TextMessage handling added.
[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                 /* 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                 if (msg->payload.authenticate->n_celt_versions > 0) {
151                         int i;
152                         client->codec_count = msg->payload.authenticate->n_celt_versions > MAX_CODECS ?
153                                 MAX_CODECS : msg->payload.authenticate->n_celt_versions;
154                         for (i = 0; i < client->codec_count; i++)
155                                 client->codecs[i] = msg->payload.authenticate->celt_versions[i];
156                 } else {
157                         client->codecs[0] = (int32_t)0x8000000a;
158                         client->codec_count = 1;
159                 }
160                 recheckCodecVersions();
161                         
162                 /* Iterate channels and send channel info */
163                 ch_itr = NULL;
164                 Chan_iterate(&ch_itr);
165                 do {
166                         sendmsg = Msg_create(ChannelState);
167                         sendmsg->payload.channelState->has_channel_id = true;
168                         sendmsg->payload.channelState->channel_id = ch_itr->id;
169                         if (ch_itr->id != 0) {
170                                 sendmsg->payload.channelState->has_parent = true;
171                                 sendmsg->payload.channelState->parent = ch_itr->parent->id;
172                         }
173                         sendmsg->payload.channelState->name = strdup(ch_itr->name);
174                         if (strlen(ch_itr->desc) > 0) {
175                                 sendmsg->payload.channelState->description = strdup(ch_itr->desc);
176                         }
177                         Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
178                         Client_send_message(client, sendmsg);
179                         
180                         Chan_iterate(&ch_itr);
181                 } while (ch_itr != NULL);
182
183                 /* Not supporting channel links yet */
184                 
185                 /* Send user state for connecting user to other users */
186                 sendmsg = Msg_create(UserState);
187                 sendmsg->payload.userState->has_session = true;
188                 sendmsg->payload.userState->session = client->sessionId;
189                 sendmsg->payload.userState->has_user_id = true;
190                 sendmsg->payload.userState->user_id = client->playerId;
191                 sendmsg->payload.userState->name = strdup(client->playerName);
192                 sendmsg->payload.userState->has_channel_id = true;
193                 sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
194                 
195                 Client_send_message_except(client, sendmsg);
196
197                 client_itr = NULL;
198                 while (Client_iterate(&client_itr) != NULL) {
199                         if (!IS_AUTH(client_itr))
200                                 continue;
201                         sendmsg = Msg_create(UserState);
202                         sendmsg->payload.userState->has_session = true;
203                         sendmsg->payload.userState->session = client_itr->sessionId;
204                         sendmsg->payload.userState->name = strdup(client_itr->playerName);
205                         sendmsg->payload.userState->has_channel_id = true;
206                         sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
207
208                         /* XXX - check if self_* is correct */
209                         if (client_itr->deaf) {
210                                 sendmsg->payload.userState->has_self_deaf = true;
211                                 sendmsg->payload.userState->self_deaf = true;
212                         }
213                         if (client_itr->mute) {
214                                 sendmsg->payload.userState->has_self_mute = true;
215                                 sendmsg->payload.userState->self_mute = true;
216                         }
217                         Client_send_message(client, sendmsg);
218                 }
219
220                 /* Sync message */
221                 sendmsg = Msg_create(ServerSync);
222                 sendmsg->payload.serverSync->has_session = true;
223                 sendmsg->payload.serverSync->session = client->sessionId;
224                 sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT));
225                 sendmsg->payload.serverSync->has_max_bandwidth = true;
226                 sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH);
227                 sendmsg->payload.serverSync->has_allow_html = true;
228                 sendmsg->payload.serverSync->allow_html = false; /* Support this? */
229                 Client_send_message(client, sendmsg);
230                 
231                 Log_info("User %s authenticated", client->playerName);
232                 break;
233                 
234         case Ping:
235         {
236                 uint64_t timestamp;
237                 if (msg->payload.ping->has_good)
238                         client->cryptState.uiRemoteGood = msg->payload.ping->good;
239                 if (msg->payload.ping->has_late)
240                         client->cryptState.uiRemoteLate = msg->payload.ping->late;
241                 if (msg->payload.ping->has_lost)
242                         client->cryptState.uiRemoteLost = msg->payload.ping->lost;
243                 if (msg->payload.ping->has_resync)
244                         client->cryptState.uiRemoteResync = msg->payload.ping->resync;
245
246                 Log_debug("Ping <-: %d %d %d %d",
247                                   client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
248                                   client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync
249                         );
250                 
251                 /* Ignoring the double values since they don't seem to be used */
252                 
253                 sendmsg = Msg_create(Ping);
254                 timestamp = msg->payload.ping->timestamp;
255
256                 sendmsg->payload.ping->timestamp = timestamp;
257                 
258                 sendmsg->payload.ping->good = client->cryptState.uiGood;
259                 sendmsg->payload.ping->has_good = true;
260                 sendmsg->payload.ping->late = client->cryptState.uiLate;
261                 sendmsg->payload.ping->has_late = true;
262                 sendmsg->payload.ping->lost = client->cryptState.uiLost;
263                 sendmsg->payload.ping->has_lost = true;
264                 sendmsg->payload.ping->resync = client->cryptState.uiResync;
265                 sendmsg->payload.ping->has_resync = true;
266
267                 Client_send_message(client, sendmsg);
268                 Log_debug("Ping ->: %d %d %d %d",
269                                   client->cryptState.uiGood, client->cryptState.uiLate,
270                                   client->cryptState.uiLost, client->cryptState.uiResync);
271
272                 break;
273         }
274         case CryptSetup:
275                 Log_debug("Voice channel crypt resync requested");
276                 if (!msg->payload.cryptSetup->has_client_nonce) {
277                         sendmsg = Msg_create(CryptSetup);
278                         sendmsg->payload.cryptSetup->has_server_nonce = true;
279                         sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.decrypt_iv;
280                         sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
281                         Client_send_message(client, sendmsg);
282                 } else {
283                         memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSetup->client_nonce.data, AES_BLOCK_SIZE);
284                         client->cryptState.uiResync++;
285                 }
286                 break;
287         case UserState:
288                 /* Only allow state changes for for the self user */
289                 if (msg->payload.userState->has_session &&
290                         msg->payload.userState->session != client->sessionId) {
291                         sendPermissionDenied(client, "Permission denied");
292                         break;
293                 }
294                 if (msg->payload.userState->has_user_id || msg->payload.userState->has_mute ||
295                         msg->payload.userState->has_deaf || msg->payload.userState->has_suppress ||
296                         msg->payload.userState->has_texture) {
297                         
298                         sendPermissionDenied(client, "Not supported by uMurmur");
299                         break;
300                 }
301                 if (msg->payload.userState->has_self_deaf) {
302                         client->deaf = msg->payload.userState->self_deaf;
303                 }
304                 if (msg->payload.userState->has_self_mute) {
305                         client->mute = msg->payload.userState->self_mute;                       
306                 }
307                 if (msg->payload.userState->has_channel_id) {
308                         Chan_playerJoin_id(msg->payload.userState->channel_id, client);
309                 }
310                 /* Re-use message */
311                 Msg_inc_ref(msg);
312                 msg->payload.userState->has_actor = true;
313                 msg->payload.userState->actor = client->sessionId;
314                 Client_send_message_except(NULL, msg);
315                 break;
316                 
317         case TextMessage:
318                 msg->payload.textMessage->has_actor = true;
319                 msg->payload.textMessage->actor = client->sessionId;
320
321                 /* XXX - Allow HTML stuff? */
322                 
323                 if (msg->payload.textMessage->n_tree_id > 0) {
324                         sendPermissionDenied(client, "Tree message not supported");
325                         break;
326                 }
327                         
328                 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
329                         int i;
330                         channel_t *ch_itr;
331                         for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
332                                 ch_itr = NULL;
333                                 do {
334                                         Chan_iterate(&ch_itr);
335                                 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
336                                 if (ch_itr == NULL)
337                                         Log_warn("Channel id %d not found - ignoring.", msg->payload.textMessage->channel_id[i]);
338                                 else {
339                                         struct dlist *itr;
340                                         list_iterate(itr, &ch_itr->clients) {
341                                                 client_t *c;
342                                                 c = list_get_entry(itr, client_t, chan_node);
343                                                 if (c != client && !c->deaf) {
344                                                         Msg_inc_ref(msg);
345                                                         Client_send_message(c, msg);
346                                                         Log_debug("Text message to session ID %d", c->sessionId);
347                                                 }
348                                         }
349                                 }
350                         } /* for */
351                 }
352                 if (msg->payload.textMessage->n_session > 0) { /* To user */
353                         int i;
354                         client_t *itr;
355                         for (i = 0; i < msg->payload.textMessage->n_session; i++) {
356                                 itr = NULL;
357                                 while (Client_iterate(&itr) != NULL) {
358                                         if (!IS_AUTH(itr))
359                                                 continue;
360                                         if (itr->playerId == msg->payload.textMessage->session[i]) {
361                                                 if (!itr->deaf) {
362                                                         Msg_inc_ref(msg);
363                                                         Client_send_message(itr, msg);
364                                                 }
365                                                 break;
366                                         }
367                                 }
368                                 if (itr == NULL)
369                                         Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
370                         } /* for */
371                 }
372                 break;
373
374         case VoiceTarget:
375                 /* XXX -TODO */
376                 break;
377
378         case Version:
379                 Log_debug("Version message received");
380                 if (msg->payload.version->has_version) {
381                         client->version = msg->payload.version->version;
382                         Log_debug("Client version 0x%x", client->version);
383                 }
384                 if (msg->payload.version->release) {
385                         if (client->release) free(client->release);
386                         client->release = strdup(msg->payload.version->release);
387                         Log_debug("Client release %s", client->release);
388                 }
389                 if (msg->payload.version->os) {
390                         if (client->os) free(client->os);                       
391                         client->os = strdup(msg->payload.version->os);
392                         Log_debug("Client OS %s", client->os);
393                 }
394                 break;
395         case CodecVersion:
396                 Msg_inc_ref(msg); /* Re-use message */
397
398                 /* XXX - fill in version */
399                 
400                 Client_send_message(client, msg);
401                 break;
402         case UDPTunnel:
403                 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
404             break;
405                 /* Permission denied for all these messages. Not implemented. */
406         case ChannelRemove:
407         case ChannelState:
408         case ContextAction:
409         case ContextActionAdd:
410         case ACL:
411         case BanList:
412                 sendPermissionDenied(client, "Not supported by uMurmur");
413                 break;
414                                 
415         default:
416                 Log_warn("Message %d not handled", msg->messageType);
417                 break;
418         }
419         Msg_free(msg);
420         return;
421 disconnect:
422         Msg_free(msg);
423         Client_close(client);
424 }
425