8cca053e55a281f0b5326398ff7bac7e431dfef5
[umurmur.git] / 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, rejectType_t type)
45 {
46         message_t *msg = Msg_create(ServerReject);
47         msg->sessionId = client->sessionId;
48         strcpy(msg->payload.serverReject.reason, reason);
49         msg->payload.serverReject.type = type;
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->sessionId = client->sessionId;
57         strncpy(msg->payload.permissionDenied.reason, reason, MAX_TEXT);
58         Client_send_message(client, msg);
59 }
60
61 void Mh_handle_message(client_t *client, message_t *msg)
62 {
63         message_t *sendmsg;
64         channel_t *ch_itr = NULL;
65         client_t *client_itr;
66         
67         switch (msg->messageType) {
68         case ServerAuthenticate:
69                 /*
70                  * 1. Check stuff, Serverreject if not ok
71                  * 2. Setup UDP encryption -> MessageCryptSetup
72                  * 3. (Enter channel)
73                  * 4. MessageChannelAdd + MessageChannelDescUpdate for all channels
74                  * 5. (MessageChannelLink)
75                  * 6. MessageServerJoin
76                  * 7. MessagePlayerMove
77                  * 8. MessageServerJoin for all connected users
78                  * 9. PlayerDeaf/PlayerMute/PlayerSelfMuteDeaf for all users it applies to
79                  * 10. MessageServerSync
80                  */
81                 if (msg->payload.serverAuthenticate.version != MESSAGE_STREAM_VERSION) {
82                         char buf[64];
83                         sprintf(buf, "Wrong version of mumble protocol (client: %d, server: %d)",
84                                         msg->payload.serverAuthenticate.version, MESSAGE_STREAM_VERSION);
85                         sendServerReject(client, buf, WrongVersion);
86                         goto disconnect;
87                 }
88                                 
89                 client_itr = NULL;
90                 while (Client_iterate(&client_itr) != NULL) {
91                         if (!IS_AUTH(client_itr))
92                                 continue;
93                         if (strncmp(client_itr->playerName, msg->payload.serverAuthenticate.userName, MAX_TEXT) == 0) {
94                                 char buf[64];
95                                 sprintf(buf, "Username already in use");
96                                 sendServerReject(client, buf, UsernameInUse);
97                                 goto disconnect;
98                         }                               
99                 }
100                 
101                 if (strncmp(getStrConf(PASSPHRASE), msg->payload.serverAuthenticate.password, MAX_TEXT) != 0) {
102                         char buf[64];
103                         sprintf(buf, "Wrong server password");
104                         sendServerReject(client, buf, WrongServerPW);
105                         goto disconnect;
106                 }                               
107
108                 if (strlen(msg->payload.serverAuthenticate.userName) == 0) { /* XXX - other invalid names? */
109                         char buf[64];
110                         sprintf(buf, "Invalid username");
111                         sendServerReject(client, buf, InvalidUsername);
112                         goto disconnect;
113                 }                               
114
115                 if (Client_count() >= getIntConf(MAX_CLIENTS)) {
116                         char buf[64];
117                         sprintf(buf, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
118                         sendServerReject(client, buf, ServerFull);
119                         goto disconnect;
120                 }
121                 
122                 /* Name & password */
123                 strncpy(client->playerName, msg->payload.serverAuthenticate.userName, MAX_TEXT);
124                 client->playerId = client->sessionId;
125
126                 client->authenticated = true;
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->sessionId = client->sessionId;
135                 memcpy(sendmsg->payload.cryptSetup.key, client->cryptState.raw_key, AES_BLOCK_SIZE);
136                 memcpy(sendmsg->payload.cryptSetup.serverNonce, client->cryptState.encrypt_iv, AES_BLOCK_SIZE);
137                 memcpy(sendmsg->payload.cryptSetup.clientNonce, client->cryptState.decrypt_iv, AES_BLOCK_SIZE);
138                 Client_send_message(client, sendmsg);
139
140                 /* Channel stuff */
141                 Chan_playerJoin(defaultChan, client); /* Join default channel */
142
143                 /* Iterate channels and send channel info */
144                 ch_itr = NULL;
145                 Chan_iterate(&ch_itr);
146                 do {
147                         sendmsg = Msg_create(ChannelAdd);
148                         sendmsg->sessionId = 0;
149                         sendmsg->payload.channelAdd.id = ch_itr->id;
150                         if (ch_itr->id == 0)
151                                 sendmsg->payload.channelAdd.parentId = -1;
152                         else
153                                 sendmsg->payload.channelAdd.parentId = ch_itr->parent->id;
154                         strcpy(sendmsg->payload.channelAdd.name, ch_itr->name);
155                         Client_send_message(client, sendmsg);
156                         
157                         sendmsg = Msg_create(ChannelDescUpdate);
158                         sendmsg->sessionId = 0;
159                         sendmsg->payload.channelDescUpdate.id = ch_itr->id;
160                         strcpy(sendmsg->payload.channelDescUpdate.desc, ch_itr->desc);
161                         Client_send_message(client, sendmsg);
162                         
163                         Chan_iterate(&ch_itr);
164                 } while (ch_itr != NULL);
165
166                 /* Not supporting channel link for now */
167
168                 /* Server join for connecting user */
169                 sendmsg = Msg_create(ServerJoin);
170                 sendmsg->sessionId = client->sessionId;
171                 sendmsg->payload.serverJoin.id = client->playerId;
172                 strcpy(sendmsg->payload.serverJoin.playerName, client->playerName);
173                 Client_send_message_except(client, sendmsg);
174
175                 /* Player move for connecting user */
176                 if (((channel_t *)client->channel)->id != 0) {
177                         sendmsg = Msg_create(PlayerMove);
178                         sendmsg->sessionId = client->sessionId;
179                         sendmsg->payload.playerMove.victim = client->playerId;
180                         sendmsg->payload.playerMove.channel = ((channel_t *)client->channel)->id;
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(ServerJoin);
188                         sendmsg->sessionId = client_itr->sessionId;
189                         sendmsg->payload.serverJoin.id = client_itr->playerId;
190                         strncpy(sendmsg->payload.serverJoin.playerName, client_itr->playerName, MAX_TEXT);
191                         Client_send_message(client, sendmsg);
192                         
193                         sendmsg = Msg_create(PlayerMove);
194                         sendmsg->sessionId = client_itr->sessionId;
195                         sendmsg->payload.playerMove.victim = client_itr->playerId;
196                         sendmsg->payload.playerMove.channel = ((channel_t *)client_itr->channel)->id;
197                         Client_send_message(client, sendmsg);
198                 }
199                 
200                 sendmsg = Msg_create(ServerSync);
201                 sendmsg->sessionId = client->sessionId;
202                 strcpy(sendmsg->payload.serverSync.welcomeText, getStrConf(WELCOMETEXT));
203                 sendmsg->payload.serverSync.maxBandwidth = getIntConf(MAX_BANDWIDTH);
204                 Client_send_message(client, sendmsg);
205                 
206                 Log_info("Player %s authenticated", client->playerName);
207                 
208                 break;
209                 
210         case PingStats:
211                 client->cryptState.uiRemoteGood = msg->payload.pingStats.good;
212                 client->cryptState.uiRemoteLate = msg->payload.pingStats.late;
213                 client->cryptState.uiRemoteLost = msg->payload.pingStats.lost;
214                 client->cryptState.uiRemoteResync = msg->payload.pingStats.resync;
215
216                 Log_debug("Pingstats <-: %d %d %d %d",
217                                   client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
218                                   client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync);
219                 
220                 /* Ignoring the double values since they don't seem to be used */
221                 sendmsg = Msg_create(PingStats);
222                 sendmsg->sessionId = client->sessionId;
223                 sendmsg->payload.pingStats.timestamp = msg->payload.pingStats.timestamp;
224                 
225                 sendmsg->payload.pingStats.good = client->cryptState.uiGood;
226                 sendmsg->payload.pingStats.late = client->cryptState.uiLate;
227                 sendmsg->payload.pingStats.lost = client->cryptState.uiLost;
228                 sendmsg->payload.pingStats.resync = client->cryptState.uiResync;
229                 
230                 Client_send_message(client, sendmsg);
231                 Log_debug("Pingstats ->: %d %d %d %d",
232                                   client->cryptState.uiGood, client->cryptState.uiLate,
233                                   client->cryptState.uiLost, client->cryptState.uiResync);
234
235                 break;
236         case Ping:
237                 sendmsg = Msg_create(Ping);
238                 sendmsg->sessionId = client->sessionId;
239                 sendmsg->payload.ping.timestamp = msg->payload.ping.timestamp;
240                 Client_send_message(client, sendmsg);
241                 break;
242         case CryptSync:
243                 Log_debug("Voice channel crypt resync requested");
244                 if (msg->payload.cryptSync.empty) {
245                         sendmsg = Msg_create(CryptSync);
246                         sendmsg->sessionId = msg->sessionId;
247                         sendmsg->payload.cryptSync.empty = false;
248                         memcpy(sendmsg->payload.cryptSync.nonce, client->cryptState.decrypt_iv, AES_BLOCK_SIZE);
249                         Client_send_message(client, sendmsg);
250                 } else {
251                         memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSync.nonce, AES_BLOCK_SIZE);
252                         client->cryptState.uiResync++;
253                 }
254                 break;
255         case PlayerMute:
256                 if (msg->payload.playerMute.victim != client->playerId) {
257                         sendPermissionDenied(client, "Permission denied");
258                 } else {
259                         Log_debug("Player ID %d muted", msg->payload.playerMute.victim);
260                         client->mute = msg->payload.playerMute.bMute;                   
261                 }
262                 break;
263         case PlayerDeaf:
264                 if (msg->payload.playerDeaf.victim != client->playerId) {
265                         sendPermissionDenied(client, "Permission denied");
266                 } else {
267                         Log_debug("Player ID %d deaf", msg->payload.playerDeaf.victim);
268                         client->deaf = msg->payload.playerDeaf.bDeaf;
269                 }
270                 break;
271         case TextMessage:
272                 if (msg->payload.textMessage.bTree)
273                         sendPermissionDenied(client, "Tree message not supported");
274                 else if (msg->payload.textMessage.channel != -1) { /* To channel */
275                         channel_t *ch_itr = NULL;
276                         do {
277                                 Chan_iterate(&ch_itr);
278                         } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage.channel);
279                         if (ch_itr == NULL)
280                                 Log_warn("Channel id %d not found - ignoring.", msg->payload.textMessage.channel);
281                         else {
282                                 struct dlist *itr;
283                                 list_iterate(itr, &ch_itr->clients) {
284                                         client_t *c;
285                                         c = list_get_entry(itr, client_t, chan_node);
286                                         if (c != client && !c->deaf) {
287                                                 Msg_inc_ref(msg);
288                                                 Client_send_message(c, msg);
289                                                 Log_debug("Text message to player ID %d", c->playerId);
290                                         }
291                                 }
292                         }
293                 } else { /* To player */
294                         client_t *itr = NULL;
295                         while (Client_iterate(&itr) != NULL) {
296                                 if (!IS_AUTH(itr))
297                                         continue;
298                                 if (itr->playerId == msg->payload.textMessage.victim) {
299                                         if (!itr->deaf) {
300                                                 Msg_inc_ref(msg);
301                                                 Client_send_message(itr, msg);
302                                         }
303                                         break;
304                                 }
305                         }
306                         if (itr == NULL)
307                                 Log_warn("TextMessage: Player ID %d not found", msg->payload.textMessage.victim);
308                 }
309                 break;
310         case PlayerSelfMuteDeaf:
311                 client->deaf = msg->payload.playerSelfMuteDeaf.bDeaf;
312                 client->mute = msg->payload.playerSelfMuteDeaf.bMute;
313                 Log_debug("Player ID %d %s and %s", client->playerId, client->deaf ? "deaf": "not deaf",
314                                   client->mute ? "mute" : "not mute");
315                 break;
316         case PlayerMove:
317                 Msg_inc_ref(msg); /* Re-use message */
318                 Client_send_message_except(NULL, msg);
319                 Chan_playerJoin_id(msg->payload.playerMove.channel, client);            
320                 break;
321
322                 /* Permission denied for all these messages. Not implemented. */
323         case PlayerRename:
324         case ChannelAdd:
325         case ChannelDescUpdate:
326         case ContextAction:
327         case ContextAddAction:
328         case ServerBanList:
329         case PlayerKick:
330         case PlayerBan:
331         case ChannelRemove:
332         case ChannelMove:
333         case ChannelLink:
334         case ChannelRename:
335         case EditACL:
336                 sendPermissionDenied(client, "Not supported by uMurmur");
337                 break;
338                 
339         case PlayerTexture: /* Ignore */
340                 break;
341                 
342         default:
343                 Log_warn("Message %d not handled", msg->messageType);
344                 break;
345         }
346         Msg_free(msg);
347         return;
348 disconnect:
349         Msg_free(msg);
350         Client_close(client);
351 }