Add support for plugin contexts and strip positional data from voice messages when...
[umurmur.git] / src / messagehandler.c
1 /* Copyright (C) 2010, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2010, Thorvald Natvig <thorvald@natvig.com>
3
4    All rights reserved.
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9
10    - Redistributions of source code must retain the above copyright notice,
11      this list of conditions and the following disclaimer.
12    - Redistributions in binary form must reproduce the above copyright notice,
13      this list of conditions and the following disclaimer in the documentation
14      and/or other materials provided with the distribution.
15    - Neither the name of the Developers nor the names of its contributors may
16      be used to endorse or promote products derived from this software without
17      specific prior written permission.
18
19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <string.h>
32 #include <openssl/aes.h>
33
34 #include "log.h"
35 #include "list.h"
36 #include "client.h"
37 #include "messages.h"
38 #include "crypt.h"
39 #include "channel.h"
40 #include "conf.h"
41 #include "voicetarget.h"
42
43 extern channel_t *defaultChan;
44 extern int iCodecAlpha, iCodecBeta;
45 extern bool_t bPreferAlpha;
46
47 static void sendServerReject(client_t *client, const char *reason, MumbleProto__Reject__RejectType type)
48 {
49         message_t *msg = Msg_create(Reject);
50         msg->payload.reject->reason = strdup(reason);
51         msg->payload.reject->type = type;
52         msg->payload.reject->has_type = true;
53         Client_send_message(client, msg);
54 }
55
56 static void sendPermissionDenied(client_t *client, const char *reason)
57 {
58         message_t *msg = Msg_create(PermissionDenied);
59         msg->payload.permissionDenied->has_type = true;
60         msg->payload.permissionDenied->type = MUMBLE_PROTO__PERMISSION_DENIED__DENY_TYPE__Text;
61         msg->payload.permissionDenied->reason = strdup(reason);
62         Client_send_message(client, msg);
63 }
64
65 void Mh_handle_message(client_t *client, message_t *msg)
66 {
67         message_t *sendmsg;
68         channel_t *ch_itr = NULL;
69         client_t *client_itr;
70         
71         switch (msg->messageType) {
72         case Authenticate:
73                 /*
74                  * 1. Check stuff, Serverreject if not ok
75                  * 2. Setup UDP encryption -> MessageCryptSetup
76                  * 3. (Enter channel)
77                  * 4. MessageChannelAdd + MessageChannelDescUpdate for all channels
78                  * 5. (MessageChannelLink)
79                  * 6. MessageServerJoin
80                  * 7. MessagePlayerMove
81                  * 8. MessageServerJoin for all connected users
82                  * 9. PlayerDeaf/PlayerMute/PlayerSelfMuteDeaf for all users it applies to
83                  * 10. MessageServerSync
84                  */
85                                 
86                 Log_debug("Authenticate message received");
87                 Log_debug("Username: %s", msg->payload.authenticate->username);
88                 
89                 client->authenticated = true;
90                 
91                 client_itr = NULL;
92                 while (Client_iterate(&client_itr) != NULL) {
93                         if (!IS_AUTH(client_itr))
94                                 continue;
95                         if (client_itr->playerName && strncmp(client_itr->playerName, msg->payload.authenticate->username, MAX_TEXT) == 0) {
96                                 char buf[64];
97                                 sprintf(buf, "Username already in use");
98                                 Log_debug("Username already in use");
99                                 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__UsernameInUse);
100                                 goto disconnect;
101                         }                               
102                 }
103                 if (msg->payload.authenticate->password && strncmp(getStrConf(PASSPHRASE), msg->payload.authenticate->password, MAX_TEXT) != 0) {
104                         char buf[64];
105                         sprintf(buf, "Wrong server password");
106                         Log_debug("Wrong server password: %s", msg->payload.authenticate->password);
107                         sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__WrongServerPW);
108                         goto disconnect;
109                 }                               
110                 if (strlen(msg->payload.authenticate->username) == 0 ||
111                         strlen(msg->payload.authenticate->username) >= MAX_TEXT) { /* XXX - other invalid names? */
112                         char buf[64];
113                         sprintf(buf, "Invalid username");
114                         Log_debug("Invalid username");
115                         sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__InvalidUsername);
116                         goto disconnect;
117                 }                               
118
119                 if (Client_count() >= getIntConf(MAX_CLIENTS)) {
120                         char buf[64];
121                         sprintf(buf, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
122                         sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__ServerFull);
123                         goto disconnect;
124                 }
125                 
126                 /* Name & password */
127                 client->playerName = strdup(msg->payload.authenticate->username);                               
128                 
129                 /* Setup UDP encryption */
130                 CryptState_init(&client->cryptState);
131                 CryptState_genKey(&client->cryptState);
132                 sendmsg = Msg_create(CryptSetup);
133                 sendmsg->payload.cryptSetup->has_key = true;
134                 sendmsg->payload.cryptSetup->key.data = client->cryptState.raw_key;
135                 sendmsg->payload.cryptSetup->key.len = AES_BLOCK_SIZE;
136                 sendmsg->payload.cryptSetup->has_server_nonce = true;
137                 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.encrypt_iv;
138                 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
139                 sendmsg->payload.cryptSetup->has_client_nonce = true;
140                 sendmsg->payload.cryptSetup->client_nonce.data = client->cryptState.decrypt_iv;
141                 sendmsg->payload.cryptSetup->client_nonce.len = AES_BLOCK_SIZE;
142                 Client_send_message(client, sendmsg);
143
144                 /* Channel stuff */
145                 Chan_playerJoin(defaultChan, client); /* Join default channel */
146
147                 /* Codec version */
148                 if (msg->payload.authenticate->n_celt_versions > MAX_CODECS)
149                         Log_warn("Client has more than %d CELT codecs. Ignoring %d codecs",
150                                          MAX_CODECS, msg->payload.authenticate->n_celt_versions - MAX_CODECS);
151                 
152                 Log_debug("Client %d has %d CELT codecs", client->sessionId, msg->payload.authenticate->n_celt_versions);
153                 if (msg->payload.authenticate->n_celt_versions > 0) {
154                         int i;
155                         client->codec_count = msg->payload.authenticate->n_celt_versions > MAX_CODECS ?
156                                 MAX_CODECS : msg->payload.authenticate->n_celt_versions;
157                         for (i = 0; i < client->codec_count; i++) {
158                                 client->codecs[i] = msg->payload.authenticate->celt_versions[i];
159                                 Log_debug("Client %d CELT codec ver 0x%x", client->sessionId, client->codecs[i]);
160                         }
161                 } else {
162                         client->codecs[0] = (int32_t)0x8000000a;
163                         client->codec_count = 1;
164                 }
165                 
166                 recheckCodecVersions();
167                 
168                 sendmsg = Msg_create(CodecVersion);
169                 sendmsg->payload.codecVersion->alpha = iCodecAlpha;
170                 sendmsg->payload.codecVersion->beta = iCodecBeta;
171                 sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha;
172                 Client_send_message(client, sendmsg);
173                 
174                 /* Iterate channels and send channel info */
175                 ch_itr = NULL;
176                 Chan_iterate(&ch_itr);
177                 do {
178                         sendmsg = Msg_create(ChannelState);
179                         sendmsg->payload.channelState->has_channel_id = true;
180                         sendmsg->payload.channelState->channel_id = ch_itr->id;
181                         if (ch_itr->id != 0) {
182                                 sendmsg->payload.channelState->has_parent = true;
183                                 sendmsg->payload.channelState->parent = ch_itr->parent->id;
184                         }
185                         sendmsg->payload.channelState->name = strdup(ch_itr->name);
186                         if (strlen(ch_itr->desc) > 0) {
187                                 sendmsg->payload.channelState->description = strdup(ch_itr->desc);
188                         }
189                         Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
190                         Client_send_message(client, sendmsg);
191                         
192                         Chan_iterate(&ch_itr);
193                 } while (ch_itr != NULL);
194
195                 /* Not supporting channel links yet */
196                 
197                 /* Send user state for connecting user to other users */
198                 sendmsg = Msg_create(UserState);
199                 sendmsg->payload.userState->has_session = true;
200                 sendmsg->payload.userState->session = client->sessionId;
201                 sendmsg->payload.userState->has_user_id = true;
202                 sendmsg->payload.userState->user_id = client->sessionId;
203                 sendmsg->payload.userState->name = strdup(client->playerName);
204                 sendmsg->payload.userState->has_channel_id = true;
205                 sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
206                 
207                 Client_send_message_except(client, sendmsg);
208
209                 client_itr = NULL;
210                 while (Client_iterate(&client_itr) != NULL) {
211                         if (!IS_AUTH(client_itr))
212                                 continue;
213                         sendmsg = Msg_create(UserState);
214                         sendmsg->payload.userState->has_session = true;
215                         sendmsg->payload.userState->session = client_itr->sessionId;
216                         sendmsg->payload.userState->name = strdup(client_itr->playerName);
217                         sendmsg->payload.userState->has_channel_id = true;
218                         sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
219
220                         /* XXX - check if self_* is correct */
221                         if (client_itr->deaf) {
222                                 sendmsg->payload.userState->has_self_deaf = true;
223                                 sendmsg->payload.userState->self_deaf = true;
224                         }
225                         if (client_itr->mute) {
226                                 sendmsg->payload.userState->has_self_mute = true;
227                                 sendmsg->payload.userState->self_mute = true;
228                         }
229                         Client_send_message(client, sendmsg);
230                 }
231
232                 /* Sync message */
233                 sendmsg = Msg_create(ServerSync);
234                 sendmsg->payload.serverSync->has_session = true;
235                 sendmsg->payload.serverSync->session = client->sessionId;
236                 sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT));
237                 sendmsg->payload.serverSync->has_max_bandwidth = true;
238                 sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH);
239                 sendmsg->payload.serverSync->has_allow_html = true;
240                 sendmsg->payload.serverSync->allow_html = true; /* Support this? */
241                 Client_send_message(client, sendmsg);
242                 
243                 Log_info("User %s authenticated", client->playerName);
244                 break;
245                 
246         case Ping:
247                 if (msg->payload.ping->has_good)
248                         client->cryptState.uiRemoteGood = msg->payload.ping->good;
249                 if (msg->payload.ping->has_late)
250                         client->cryptState.uiRemoteLate = msg->payload.ping->late;
251                 if (msg->payload.ping->has_lost)
252                         client->cryptState.uiRemoteLost = msg->payload.ping->lost;
253                 if (msg->payload.ping->has_resync)
254                         client->cryptState.uiRemoteResync = msg->payload.ping->resync;
255
256                 Log_debug("Ping <-: %d %d %d %d",
257                                   client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
258                                   client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync
259                         );
260                 
261                 /* Ignoring the double values since they don't seem to be used */
262                 
263                 sendmsg = Msg_create(Ping);
264
265                 sendmsg->payload.ping->timestamp = msg->payload.ping->timestamp;
266                 sendmsg->payload.ping->has_timestamp = true;
267                 sendmsg->payload.ping->good = client->cryptState.uiGood;
268                 sendmsg->payload.ping->has_good = true;
269                 sendmsg->payload.ping->late = client->cryptState.uiLate;
270                 sendmsg->payload.ping->has_late = true;
271                 sendmsg->payload.ping->lost = client->cryptState.uiLost;
272                 sendmsg->payload.ping->has_lost = true;
273                 sendmsg->payload.ping->resync = client->cryptState.uiResync;
274                 sendmsg->payload.ping->has_resync = true;
275
276                 Client_send_message(client, sendmsg);
277                 Log_debug("Ping ->: %d %d %d %d",
278                                   client->cryptState.uiGood, client->cryptState.uiLate,
279                                   client->cryptState.uiLost, client->cryptState.uiResync);
280
281                 break;
282         case CryptSetup:
283                 Log_debug("Voice channel crypt resync requested");
284                 if (!msg->payload.cryptSetup->has_client_nonce) {
285                         sendmsg = Msg_create(CryptSetup);
286                         sendmsg->payload.cryptSetup->has_server_nonce = true;
287                         sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.decrypt_iv;
288                         sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
289                         Client_send_message(client, sendmsg);
290                 } else {
291                         memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSetup->client_nonce.data, AES_BLOCK_SIZE);
292                         client->cryptState.uiResync++;
293                 }
294                 break;
295         case UserState:
296                 /* Only allow state changes for for the self user */
297                 if (msg->payload.userState->has_session &&
298                         msg->payload.userState->session != client->sessionId) {
299                         sendPermissionDenied(client, "Permission denied");
300                         break;
301                 }
302                 if (msg->payload.userState->has_user_id || msg->payload.userState->has_mute ||
303                         msg->payload.userState->has_deaf || msg->payload.userState->has_suppress ||
304                         msg->payload.userState->has_texture) {
305                         
306                         sendPermissionDenied(client, "Not supported by uMurmur");
307                         break;
308                 }
309                 if (msg->payload.userState->has_self_deaf) {
310                         client->deaf = msg->payload.userState->self_deaf;
311                 }
312                 if (msg->payload.userState->has_self_mute) {
313                         client->mute = msg->payload.userState->self_mute;                       
314                 }
315                 if (msg->payload.userState->has_channel_id) {
316                         Chan_playerJoin_id(msg->payload.userState->channel_id, client);
317                 }
318                 if (msg->payload.userState->plugin_context != NULL) {
319                         if (client->context)
320                                 free(client->context);
321                         client->context = strdup(msg->payload.userState->plugin_context);
322                         if (client->context == NULL)
323                                 Log_fatal("Out of memory");
324                         
325                         break; /* Don't inform other users about this state */
326                 }
327                 
328                 /* Re-use message */
329                 Msg_inc_ref(msg);
330                 msg->payload.userState->has_actor = true;
331                 msg->payload.userState->actor = client->sessionId;
332                 Client_send_message_except(NULL, msg);
333                 break;
334         case TextMessage:
335                 msg->payload.textMessage->has_actor = true;
336                 msg->payload.textMessage->actor = client->sessionId;
337
338                 /* XXX - Allow HTML stuff? */
339                 
340                 if (msg->payload.textMessage->n_tree_id > 0) {
341                         sendPermissionDenied(client, "Tree message not supported");
342                         break;
343                 }
344                         
345                 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
346                         int i;
347                         channel_t *ch_itr;
348                         for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
349                                 ch_itr = NULL;
350                                 do {
351                                         Chan_iterate(&ch_itr);
352                                 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
353                                 if (ch_itr == NULL)
354                                         Log_warn("Channel id %d not found - ignoring.", msg->payload.textMessage->channel_id[i]);
355                                 else {
356                                         struct dlist *itr;
357                                         list_iterate(itr, &ch_itr->clients) {
358                                                 client_t *c;
359                                                 c = list_get_entry(itr, client_t, chan_node);
360                                                 if (c != client && !c->deaf) {
361                                                         Msg_inc_ref(msg);
362                                                         Client_send_message(c, msg);
363                                                         Log_debug("Text message to session ID %d", c->sessionId);
364                                                 }
365                                         }
366                                 }
367                         } /* for */
368                 }
369                 if (msg->payload.textMessage->n_session > 0) { /* To user */
370                         int i;
371                         client_t *itr;
372                         for (i = 0; i < msg->payload.textMessage->n_session; i++) {
373                                 itr = NULL;
374                                 while (Client_iterate(&itr) != NULL) {
375                                         if (!IS_AUTH(itr))
376                                                 continue;
377                                         if (itr->sessionId == msg->payload.textMessage->session[i]) {
378                                                 if (!itr->deaf) {
379                                                         Msg_inc_ref(msg);
380                                                         Client_send_message(itr, msg);
381                                                         Log_debug("Text message to session ID %d", itr->sessionId);
382                                                 }
383                                                 break;
384                                         }
385                                 }
386                                 if (itr == NULL)
387                                         Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
388                         } /* for */
389                 }
390                 break;
391
392         case VoiceTarget:
393         {
394                 int i, j, count, targetId = msg->payload.voiceTarget->id;
395                 struct _MumbleProto__VoiceTarget__Target *target;
396
397                 if (!targetId || targetId >= 0x1f)
398                         break;
399                 Voicetarget_add_id(client, targetId);
400                 count = msg->payload.voiceTarget->n_targets;
401                 if (!count)
402                         break;
403                 for (i = 0; i < count; i++) {
404                         target = msg->payload.voiceTarget->targets[i];
405                         for (j = 0; j < target->n_session; j++)
406                                 Voicetarget_add_session(client, targetId, target->session[j]);
407                         if (target->has_channel_id) {
408                                 if (target->has_links || target->has_children)
409                                         Log_warn("Whisper to children or linked channels not implemented. Ignoring.");
410                                 Voicetarget_add_channel(client, targetId, target->channel_id);
411                         }
412                 }
413                 break;
414         }
415         case Version:
416                 Log_debug("Version message received");
417                 if (msg->payload.version->has_version) {
418                         client->version = msg->payload.version->version;
419                         Log_debug("Client version 0x%x", client->version);
420                 }
421                 if (msg->payload.version->release) {
422                         if (client->release) free(client->release);
423                         client->release = strdup(msg->payload.version->release);
424                         Log_debug("Client release %s", client->release);
425                 }
426                 if (msg->payload.version->os) {
427                         if (client->os) free(client->os);                       
428                         client->os = strdup(msg->payload.version->os);
429                         Log_debug("Client OS %s", client->os);
430                 }
431                 break;
432         case PermissionQuery:
433                 Msg_inc_ref(msg); /* Re-use message */
434                 msg->payload.permissionQuery->has_permissions = true;
435                 msg->payload.permissionQuery->permissions = PERM_DEFAULT;
436                 
437                 Client_send_message(client, msg);
438                 break;
439         case UDPTunnel:
440                 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
441             break;
442                 /* Permission denied for all these messages. Not implemented. */
443         case ChannelRemove:
444         case ChannelState:
445         case ContextAction:
446         case ContextActionAdd:
447         case ACL:
448         case BanList:
449         case UserList:
450         case QueryUsers:
451                 sendPermissionDenied(client, "Not supported by uMurmur");
452                 break;
453                                 
454         default:
455                 Log_warn("Message %d not handled", msg->messageType);
456                 break;
457         }
458         Msg_free(msg);
459         return;
460 disconnect:
461         Msg_free(msg);
462         Client_close(client);
463 }
464