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