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