More work toward 1.2.0:
[umurmur.git] / src / messagehandler.c
1 /* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2009, 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
42 extern channel_t *defaultChan;
43 extern int iCodecAlpha, iCodecBeta;
44 extern bool_t bPreferAlpha;
45
46 static void sendServerReject(client_t *client, const char *reason, MumbleProto__Reject__RejectType type)
47 {
48         message_t *msg = Msg_create(Reject);
49         msg->payload.reject->reason = strdup(reason);
50         msg->payload.reject->type = type;
51         msg->payload.reject->has_type = true;
52         Client_send_message(client, msg);
53 }
54
55 static void sendPermissionDenied(client_t *client, const char *reason)
56 {
57         message_t *msg = Msg_create(PermissionDenied);
58         msg->payload.permissionDenied->has_type = true;
59         msg->payload.permissionDenied->type = MUMBLE_PROTO__PERMISSION_DENIED__DENY_TYPE__Text;
60         msg->payload.permissionDenied->reason = strdup(reason);
61         Client_send_message(client, msg);
62 }
63
64 void Mh_handle_message(client_t *client, message_t *msg)
65 {
66         message_t *sendmsg;
67         channel_t *ch_itr = NULL;
68         client_t *client_itr;
69         
70         switch (msg->messageType) {
71         case Authenticate:
72                 /*
73                  * 1. Check stuff, Serverreject if not ok
74                  * 2. Setup UDP encryption -> MessageCryptSetup
75                  * 3. (Enter channel)
76                  * 4. MessageChannelAdd + MessageChannelDescUpdate for all channels
77                  * 5. (MessageChannelLink)
78                  * 6. MessageServerJoin
79                  * 7. MessagePlayerMove
80                  * 8. MessageServerJoin for all connected users
81                  * 9. PlayerDeaf/PlayerMute/PlayerSelfMuteDeaf for all users it applies to
82                  * 10. MessageServerSync
83                  */
84                                 
85                 Log_debug("Authenticate message received");
86                 Log_debug("Username: %s", msg->payload.authenticate->username);
87                 
88                 client->authenticated = true;
89                 
90                 client_itr = NULL;
91                 while (Client_iterate(&client_itr) != NULL) {
92                         if (!IS_AUTH(client_itr))
93                                 continue;
94                         if (client_itr->playerName && strncmp(client_itr->playerName, msg->payload.authenticate->username, MAX_TEXT) == 0) {
95                                 char buf[64];
96                                 sprintf(buf, "Username already in use");
97                                 Log_debug("Username already in use");
98                                 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__UsernameInUse);
99                                 goto disconnect;
100                         }                               
101                 }
102                 if (msg->payload.authenticate->password && strncmp(getStrConf(PASSPHRASE), msg->payload.authenticate->password, MAX_TEXT) != 0) {
103                         char buf[64];
104                         sprintf(buf, "Wrong server password");
105                         Log_debug("Wrong server password: %s", msg->payload.authenticate->password);
106                         sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__WrongServerPW);
107                         goto disconnect;
108                 }                               
109                 if (strlen(msg->payload.authenticate->username) == 0 ||
110                         strlen(msg->payload.authenticate->username) >= MAX_TEXT) { /* XXX - other invalid names? */
111                         char buf[64];
112                         sprintf(buf, "Invalid username");
113                         Log_debug("Invalid username");
114                         sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__InvalidUsername);
115                         goto disconnect;
116                 }                               
117
118                 if (Client_count() >= getIntConf(MAX_CLIENTS)) {
119                         char buf[64];
120                         sprintf(buf, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
121                         sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__ServerFull);
122                         goto disconnect;
123                 }
124                 
125                 /* Name & password */
126                 client->playerName = strdup(msg->payload.authenticate->username);                               
127                 
128                 /* Setup UDP encryption */
129                 CryptState_init(&client->cryptState);
130                 CryptState_genKey(&client->cryptState);
131                 sendmsg = Msg_create(CryptSetup);
132                 sendmsg->payload.cryptSetup->has_key = true;
133                 sendmsg->payload.cryptSetup->key.data = client->cryptState.raw_key;
134                 sendmsg->payload.cryptSetup->key.len = AES_BLOCK_SIZE;
135                 sendmsg->payload.cryptSetup->has_server_nonce = true;
136                 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.encrypt_iv;
137                 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
138                 sendmsg->payload.cryptSetup->has_client_nonce = true;
139                 sendmsg->payload.cryptSetup->client_nonce.data = client->cryptState.decrypt_iv;
140                 sendmsg->payload.cryptSetup->client_nonce.len = AES_BLOCK_SIZE;
141                 Client_send_message(client, sendmsg);
142
143                 /* Channel stuff */
144                 Chan_playerJoin(defaultChan, client); /* Join default channel */
145
146                 /* Codec version */
147                 if (msg->payload.authenticate->n_celt_versions > MAX_CODECS)
148                         Log_warn("Client has more than %d CELT codecs. Ignoring %d codecs",
149                                          MAX_CODECS, msg->payload.authenticate->n_celt_versions - MAX_CODECS);
150                 
151                 Log_debug("Client %d has %d CELT codecs", client->sessionId, msg->payload.authenticate->n_celt_versions);
152                 if (msg->payload.authenticate->n_celt_versions > 0) {
153                         int i;
154                         client->codec_count = msg->payload.authenticate->n_celt_versions > MAX_CODECS ?
155                                 MAX_CODECS : msg->payload.authenticate->n_celt_versions;
156                         for (i = 0; i < client->codec_count; i++) {
157                                 client->codecs[i] = msg->payload.authenticate->celt_versions[i];
158                                 Log_debug("Client %d CELT codec ver 0x%x", client->sessionId, client->codecs[i]);
159                         }
160                 } else {
161                         client->codecs[0] = (int32_t)0x8000000a;
162                         client->codec_count = 1;
163                 }
164                 
165                 recheckCodecVersions();
166                 
167                 sendmsg = Msg_create(CodecVersion);
168                 sendmsg->payload.codecVersion->alpha = iCodecAlpha;
169                 sendmsg->payload.codecVersion->beta = iCodecBeta;
170                 sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha;
171                 Client_send_message(client, sendmsg);
172                 
173                 /* Iterate channels and send channel info */
174                 ch_itr = NULL;
175                 Chan_iterate(&ch_itr);
176                 do {
177                         sendmsg = Msg_create(ChannelState);
178                         sendmsg->payload.channelState->has_channel_id = true;
179                         sendmsg->payload.channelState->channel_id = ch_itr->id;
180                         if (ch_itr->id != 0) {
181                                 sendmsg->payload.channelState->has_parent = true;
182                                 sendmsg->payload.channelState->parent = ch_itr->parent->id;
183                         }
184                         sendmsg->payload.channelState->name = strdup(ch_itr->name);
185                         if (strlen(ch_itr->desc) > 0) {
186                                 sendmsg->payload.channelState->description = strdup(ch_itr->desc);
187                         }
188                         Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
189                         Client_send_message(client, sendmsg);
190                         
191                         Chan_iterate(&ch_itr);
192                 } while (ch_itr != NULL);
193
194                 /* Not supporting channel links yet */
195                 
196                 /* Send user state for connecting user to other users */
197                 sendmsg = Msg_create(UserState);
198                 sendmsg->payload.userState->has_session = true;
199                 sendmsg->payload.userState->session = client->sessionId;
200                 sendmsg->payload.userState->has_user_id = true;
201                 sendmsg->payload.userState->user_id = client->sessionId;
202                 sendmsg->payload.userState->name = strdup(client->playerName);
203                 sendmsg->payload.userState->has_channel_id = true;
204                 sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
205                 
206                 Client_send_message_except(client, sendmsg);
207
208                 client_itr = NULL;
209                 while (Client_iterate(&client_itr) != NULL) {
210                         if (!IS_AUTH(client_itr))
211                                 continue;
212                         sendmsg = Msg_create(UserState);
213                         sendmsg->payload.userState->has_session = true;
214                         sendmsg->payload.userState->session = client_itr->sessionId;
215                         sendmsg->payload.userState->name = strdup(client_itr->playerName);
216                         sendmsg->payload.userState->has_channel_id = true;
217                         sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
218
219                         /* XXX - check if self_* is correct */
220                         if (client_itr->deaf) {
221                                 sendmsg->payload.userState->has_self_deaf = true;
222                                 sendmsg->payload.userState->self_deaf = true;
223                         }
224                         if (client_itr->mute) {
225                                 sendmsg->payload.userState->has_self_mute = true;
226                                 sendmsg->payload.userState->self_mute = true;
227                         }
228                         Client_send_message(client, sendmsg);
229                 }
230
231                 /* Sync message */
232                 sendmsg = Msg_create(ServerSync);
233                 sendmsg->payload.serverSync->has_session = true;
234                 sendmsg->payload.serverSync->session = client->sessionId;
235                 sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT));
236                 sendmsg->payload.serverSync->has_max_bandwidth = true;
237                 sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH);
238                 sendmsg->payload.serverSync->has_allow_html = true;
239                 sendmsg->payload.serverSync->allow_html = true; /* Support this? */
240                 Client_send_message(client, sendmsg);
241                 
242                 Log_info("User %s authenticated", client->playerName);
243                 break;
244                 
245         case Ping:
246                 if (msg->payload.ping->has_good)
247                         client->cryptState.uiRemoteGood = msg->payload.ping->good;
248                 if (msg->payload.ping->has_late)
249                         client->cryptState.uiRemoteLate = msg->payload.ping->late;
250                 if (msg->payload.ping->has_lost)
251                         client->cryptState.uiRemoteLost = msg->payload.ping->lost;
252                 if (msg->payload.ping->has_resync)
253                         client->cryptState.uiRemoteResync = msg->payload.ping->resync;
254
255                 Log_debug("Ping <-: %d %d %d %d",
256                                   client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
257                                   client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync
258                         );
259                 
260                 /* Ignoring the double values since they don't seem to be used */
261                 
262                 sendmsg = Msg_create(Ping);
263
264                 sendmsg->payload.ping->timestamp = msg->payload.ping->timestamp;
265                 sendmsg->payload.ping->has_timestamp = true;
266                 sendmsg->payload.ping->good = client->cryptState.uiGood;
267                 sendmsg->payload.ping->has_good = true;
268                 sendmsg->payload.ping->late = client->cryptState.uiLate;
269                 sendmsg->payload.ping->has_late = true;
270                 sendmsg->payload.ping->lost = client->cryptState.uiLost;
271                 sendmsg->payload.ping->has_lost = true;
272                 sendmsg->payload.ping->resync = client->cryptState.uiResync;
273                 sendmsg->payload.ping->has_resync = true;
274
275                 Client_send_message(client, sendmsg);
276                 Log_debug("Ping ->: %d %d %d %d",
277                                   client->cryptState.uiGood, client->cryptState.uiLate,
278                                   client->cryptState.uiLost, client->cryptState.uiResync);
279
280                 break;
281         case CryptSetup:
282                 Log_debug("Voice channel crypt resync requested");
283                 if (!msg->payload.cryptSetup->has_client_nonce) {
284                         sendmsg = Msg_create(CryptSetup);
285                         sendmsg->payload.cryptSetup->has_server_nonce = true;
286                         sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.decrypt_iv;
287                         sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
288                         Client_send_message(client, sendmsg);
289                 } else {
290                         memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSetup->client_nonce.data, AES_BLOCK_SIZE);
291                         client->cryptState.uiResync++;
292                 }
293                 break;
294         case UserState:
295                 /* Only allow state changes for for the self user */
296                 if (msg->payload.userState->has_session &&
297                         msg->payload.userState->session != client->sessionId) {
298                         sendPermissionDenied(client, "Permission denied");
299                         break;
300                 }
301                 if (msg->payload.userState->has_user_id || msg->payload.userState->has_mute ||
302                         msg->payload.userState->has_deaf || msg->payload.userState->has_suppress ||
303                         msg->payload.userState->has_texture) {
304                         
305                         sendPermissionDenied(client, "Not supported by uMurmur");
306                         break;
307                 }
308                 if (msg->payload.userState->has_self_deaf) {
309                         client->deaf = msg->payload.userState->self_deaf;
310                 }
311                 if (msg->payload.userState->has_self_mute) {
312                         client->mute = msg->payload.userState->self_mute;                       
313                 }
314                 if (msg->payload.userState->has_channel_id) {
315                         Chan_playerJoin_id(msg->payload.userState->channel_id, client);
316                 }
317                 /* Re-use message */
318                 Msg_inc_ref(msg);
319                 msg->payload.userState->has_actor = true;
320                 msg->payload.userState->actor = client->sessionId;
321                 Client_send_message_except(NULL, msg);
322                 break;
323                 
324         case TextMessage:
325                 msg->payload.textMessage->has_actor = true;
326                 msg->payload.textMessage->actor = client->sessionId;
327
328                 /* XXX - Allow HTML stuff? */
329                 
330                 if (msg->payload.textMessage->n_tree_id > 0) {
331                         sendPermissionDenied(client, "Tree message not supported");
332                         break;
333                 }
334                         
335                 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
336                         int i;
337                         channel_t *ch_itr;
338                         for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
339                                 ch_itr = NULL;
340                                 do {
341                                         Chan_iterate(&ch_itr);
342                                 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
343                                 if (ch_itr == NULL)
344                                         Log_warn("Channel id %d not found - ignoring.", msg->payload.textMessage->channel_id[i]);
345                                 else {
346                                         struct dlist *itr;
347                                         list_iterate(itr, &ch_itr->clients) {
348                                                 client_t *c;
349                                                 c = list_get_entry(itr, client_t, chan_node);
350                                                 if (c != client && !c->deaf) {
351                                                         Msg_inc_ref(msg);
352                                                         Client_send_message(c, msg);
353                                                         Log_debug("Text message to session ID %d", c->sessionId);
354                                                 }
355                                         }
356                                 }
357                         } /* for */
358                 }
359                 if (msg->payload.textMessage->n_session > 0) { /* To user */
360                         int i;
361                         client_t *itr;
362                         for (i = 0; i < msg->payload.textMessage->n_session; i++) {
363                                 itr = NULL;
364                                 while (Client_iterate(&itr) != NULL) {
365                                         if (!IS_AUTH(itr))
366                                                 continue;
367                                         if (itr->sessionId == msg->payload.textMessage->session[i]) {
368                                                 if (!itr->deaf) {
369                                                         Msg_inc_ref(msg);
370                                                         Client_send_message(itr, msg);
371                                                         Log_debug("Text message to session ID %d", itr->sessionId);
372                                                 }
373                                                 break;
374                                         }
375                                 }
376                                 if (itr == NULL)
377                                         Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
378                         } /* for */
379                 }
380                 break;
381
382         case VoiceTarget:
383                 /* XXX -TODO */
384                 break;
385
386         case Version:
387                 Log_debug("Version message received");
388                 if (msg->payload.version->has_version) {
389                         client->version = msg->payload.version->version;
390                         Log_debug("Client version 0x%x", client->version);
391                 }
392                 if (msg->payload.version->release) {
393                         if (client->release) free(client->release);
394                         client->release = strdup(msg->payload.version->release);
395                         Log_debug("Client release %s", client->release);
396                 }
397                 if (msg->payload.version->os) {
398                         if (client->os) free(client->os);                       
399                         client->os = strdup(msg->payload.version->os);
400                         Log_debug("Client OS %s", client->os);
401                 }
402                 break;
403         case PermissionQuery:
404                 Msg_inc_ref(msg); /* Re-use message */
405                 msg->payload.permissionQuery->has_permissions = true;
406                 msg->payload.permissionQuery->permissions = PERM_DEFAULT;
407                 
408                 Client_send_message(client, msg);
409                 break;
410         case UDPTunnel:
411                 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
412             break;
413                 /* Permission denied for all these messages. Not implemented. */
414         case ChannelRemove:
415         case ChannelState:
416         case ContextAction:
417         case ContextActionAdd:
418         case ACL:
419         case BanList:
420                 sendPermissionDenied(client, "Not supported by uMurmur");
421                 break;
422                                 
423         default:
424                 Log_warn("Message %d not handled", msg->messageType);
425                 break;
426         }
427         Msg_free(msg);
428         return;
429 disconnect:
430         Msg_free(msg);
431         Client_close(client);
432 }
433