1 /* Copyright (C) 2009-2010, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2010, Thorvald Natvig <thorvald@natvig.com>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
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.
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.
32 #include <openssl/aes.h>
41 #include "voicetarget.h"
43 extern channel_t *defaultChan;
44 extern int iCodecAlpha, iCodecBeta;
45 extern bool_t bPreferAlpha;
47 static void sendServerReject(client_t *client, const char *reason, MumbleProto__Reject__RejectType type)
49 message_t *msg = Msg_create(Reject);
50 msg->payload.reject->reason = strdup(reason);
51 msg->payload.reject->type = type;
52 msg->payload.reject->has_type = true;
53 Client_send_message(client, msg);
55 Log_info("Server reject reason: %s. Disconnecting session %d - %s@%s:%d",
59 inet_ntoa(client->remote_tcp.sin_addr),
60 ntohs(client->remote_tcp.sin_port));
64 static void sendPermissionDenied(client_t *client, const char *reason)
66 message_t *msg = Msg_create(PermissionDenied);
67 msg->payload.permissionDenied->has_type = true;
68 msg->payload.permissionDenied->type = MUMBLE_PROTO__PERMISSION_DENIED__DENY_TYPE__Text;
69 msg->payload.permissionDenied->reason = strdup(reason);
70 Client_send_message(client, msg);
73 void Mh_handle_message(client_t *client, message_t *msg)
76 channel_t *ch_itr = NULL;
79 switch (msg->messageType) {
82 * 1. Check stuff, Serverreject if not ok
83 * 2. Setup UDP encryption -> MessageCryptSetup
85 * 4. MessageChannelAdd + MessageChannelDescUpdate for all channels
86 * 5. (MessageChannelLink)
87 * 6. MessageServerJoin
88 * 7. MessagePlayerMove
89 * 8. MessageServerJoin for all connected users
90 * 9. PlayerDeaf/PlayerMute/PlayerSelfMuteDeaf for all users it applies to
91 * 10. MessageServerSync
94 Log_debug("Authenticate message received");
95 Log_debug("Username: %s", msg->payload.authenticate->username);
97 client->authenticated = true;
100 while (Client_iterate(&client_itr) != NULL) {
101 if (!IS_AUTH(client_itr))
103 if (client_itr->playerName && strncmp(client_itr->playerName, msg->payload.authenticate->username, MAX_TEXT) == 0) {
105 sprintf(buf, "Username already in use");
106 Log_debug("Username already in use");
107 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__UsernameInUse);
111 if (msg->payload.authenticate->password && strncmp(getStrConf(PASSPHRASE), msg->payload.authenticate->password, MAX_TEXT) != 0) {
113 sprintf(buf, "Wrong server password");
114 Log_debug("Wrong server password: %s", msg->payload.authenticate->password);
115 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__WrongServerPW);
118 if (strlen(msg->payload.authenticate->username) == 0 ||
119 strlen(msg->payload.authenticate->username) >= MAX_TEXT) { /* XXX - other invalid names? */
121 sprintf(buf, "Invalid username");
122 Log_debug("Invalid username");
123 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__InvalidUsername);
127 if (Client_count() >= getIntConf(MAX_CLIENTS)) {
129 sprintf(buf, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
130 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__ServerFull);
134 /* Name & password */
135 client->playerName = strdup(msg->payload.authenticate->username);
137 /* Setup UDP encryption */
138 CryptState_init(&client->cryptState);
139 CryptState_genKey(&client->cryptState);
140 sendmsg = Msg_create(CryptSetup);
141 sendmsg->payload.cryptSetup->has_key = true;
142 sendmsg->payload.cryptSetup->key.data = client->cryptState.raw_key;
143 sendmsg->payload.cryptSetup->key.len = AES_BLOCK_SIZE;
144 sendmsg->payload.cryptSetup->has_server_nonce = true;
145 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.encrypt_iv;
146 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
147 sendmsg->payload.cryptSetup->has_client_nonce = true;
148 sendmsg->payload.cryptSetup->client_nonce.data = client->cryptState.decrypt_iv;
149 sendmsg->payload.cryptSetup->client_nonce.len = AES_BLOCK_SIZE;
150 Client_send_message(client, sendmsg);
153 Chan_playerJoin(defaultChan, client); /* Join default channel */
156 if (msg->payload.authenticate->n_celt_versions > MAX_CODECS)
157 Log_warn("Client has more than %d CELT codecs. Ignoring %d codecs",
158 MAX_CODECS, msg->payload.authenticate->n_celt_versions - MAX_CODECS);
160 Log_debug("Client %d has %d CELT codecs", client->sessionId, msg->payload.authenticate->n_celt_versions);
161 if (msg->payload.authenticate->n_celt_versions > 0) {
163 client->codec_count = msg->payload.authenticate->n_celt_versions > MAX_CODECS ?
164 MAX_CODECS : msg->payload.authenticate->n_celt_versions;
165 for (i = 0; i < client->codec_count; i++) {
166 client->codecs[i] = msg->payload.authenticate->celt_versions[i];
167 Log_debug("Client %d CELT codec ver 0x%x", client->sessionId, client->codecs[i]);
170 client->codecs[0] = (int32_t)0x8000000a;
171 client->codec_count = 1;
174 recheckCodecVersions();
176 sendmsg = Msg_create(CodecVersion);
177 sendmsg->payload.codecVersion->alpha = iCodecAlpha;
178 sendmsg->payload.codecVersion->beta = iCodecBeta;
179 sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha;
180 Client_send_message(client, sendmsg);
182 /* Iterate channels and send channel info */
184 Chan_iterate(&ch_itr);
186 sendmsg = Msg_create(ChannelState);
187 sendmsg->payload.channelState->has_channel_id = true;
188 sendmsg->payload.channelState->channel_id = ch_itr->id;
189 if (ch_itr->id != 0) {
190 sendmsg->payload.channelState->has_parent = true;
191 sendmsg->payload.channelState->parent = ch_itr->parent->id;
193 sendmsg->payload.channelState->name = strdup(ch_itr->name);
194 if (strlen(ch_itr->desc) > 0) {
195 sendmsg->payload.channelState->description = strdup(ch_itr->desc);
197 Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
198 Client_send_message(client, sendmsg);
200 Chan_iterate(&ch_itr);
201 } while (ch_itr != NULL);
203 /* Not supporting channel links yet */
205 /* Send user state for connecting user to other users */
206 sendmsg = Msg_create(UserState);
207 sendmsg->payload.userState->has_session = true;
208 sendmsg->payload.userState->session = client->sessionId;
209 sendmsg->payload.userState->has_user_id = true;
210 sendmsg->payload.userState->user_id = client->sessionId;
211 sendmsg->payload.userState->name = strdup(client->playerName);
212 sendmsg->payload.userState->has_channel_id = true;
213 sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
215 Client_send_message_except(client, sendmsg);
218 while (Client_iterate(&client_itr) != NULL) {
219 if (!IS_AUTH(client_itr))
221 sendmsg = Msg_create(UserState);
222 sendmsg->payload.userState->has_session = true;
223 sendmsg->payload.userState->session = client_itr->sessionId;
224 sendmsg->payload.userState->name = strdup(client_itr->playerName);
225 sendmsg->payload.userState->has_channel_id = true;
226 sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
228 /* Only self_mute/deaf supported */
229 if (client_itr->deaf) {
230 sendmsg->payload.userState->has_self_deaf = true;
231 sendmsg->payload.userState->self_deaf = true;
233 if (client_itr->mute) {
234 sendmsg->payload.userState->has_self_mute = true;
235 sendmsg->payload.userState->self_mute = true;
237 Client_send_message(client, sendmsg);
241 sendmsg = Msg_create(ServerSync);
242 sendmsg->payload.serverSync->has_session = true;
243 sendmsg->payload.serverSync->session = client->sessionId;
244 sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT));
245 sendmsg->payload.serverSync->has_max_bandwidth = true;
246 sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH);
247 sendmsg->payload.serverSync->has_allow_html = true;
248 sendmsg->payload.serverSync->allow_html = true; /* Support this? */
249 Client_send_message(client, sendmsg);
251 Log_info("User %s authenticated", client->playerName);
255 if (msg->payload.ping->has_good)
256 client->cryptState.uiRemoteGood = msg->payload.ping->good;
257 if (msg->payload.ping->has_late)
258 client->cryptState.uiRemoteLate = msg->payload.ping->late;
259 if (msg->payload.ping->has_lost)
260 client->cryptState.uiRemoteLost = msg->payload.ping->lost;
261 if (msg->payload.ping->has_resync)
262 client->cryptState.uiRemoteResync = msg->payload.ping->resync;
264 Log_debug("Ping <-: %d %d %d %d",
265 client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
266 client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync
269 /* Ignoring the double values since they don't seem to be used */
271 sendmsg = Msg_create(Ping);
273 sendmsg->payload.ping->timestamp = msg->payload.ping->timestamp;
274 sendmsg->payload.ping->has_timestamp = true;
275 sendmsg->payload.ping->good = client->cryptState.uiGood;
276 sendmsg->payload.ping->has_good = true;
277 sendmsg->payload.ping->late = client->cryptState.uiLate;
278 sendmsg->payload.ping->has_late = true;
279 sendmsg->payload.ping->lost = client->cryptState.uiLost;
280 sendmsg->payload.ping->has_lost = true;
281 sendmsg->payload.ping->resync = client->cryptState.uiResync;
282 sendmsg->payload.ping->has_resync = true;
284 Client_send_message(client, sendmsg);
285 Log_debug("Ping ->: %d %d %d %d",
286 client->cryptState.uiGood, client->cryptState.uiLate,
287 client->cryptState.uiLost, client->cryptState.uiResync);
291 Log_debug("Voice channel crypt resync requested");
292 if (!msg->payload.cryptSetup->has_client_nonce) {
293 sendmsg = Msg_create(CryptSetup);
294 sendmsg->payload.cryptSetup->has_server_nonce = true;
295 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.decrypt_iv;
296 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
297 Client_send_message(client, sendmsg);
299 memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSetup->client_nonce.data, AES_BLOCK_SIZE);
300 client->cryptState.uiResync++;
304 /* Only allow state changes for for the self user */
305 if (msg->payload.userState->has_session &&
306 msg->payload.userState->session != client->sessionId) {
307 sendPermissionDenied(client, "Permission denied");
310 if (msg->payload.userState->has_user_id || msg->payload.userState->has_mute ||
311 msg->payload.userState->has_deaf || msg->payload.userState->has_suppress ||
312 msg->payload.userState->has_texture) {
314 sendPermissionDenied(client, "Not supported by uMurmur");
317 if (msg->payload.userState->has_self_deaf) {
318 client->deaf = msg->payload.userState->self_deaf;
320 if (msg->payload.userState->has_self_mute) {
321 client->mute = msg->payload.userState->self_mute;
323 if (msg->payload.userState->has_channel_id) {
324 Chan_playerJoin_id(msg->payload.userState->channel_id, client);
326 if (msg->payload.userState->plugin_context != NULL) {
328 free(client->context);
329 client->context = strdup(msg->payload.userState->plugin_context);
330 if (client->context == NULL)
331 Log_fatal("Out of memory");
333 break; /* Don't inform other users about this state */
338 msg->payload.userState->has_actor = true;
339 msg->payload.userState->actor = client->sessionId;
340 Client_send_message_except(NULL, msg);
343 msg->payload.textMessage->has_actor = true;
344 msg->payload.textMessage->actor = client->sessionId;
346 /* XXX - Allow HTML stuff? */
348 if (msg->payload.textMessage->n_tree_id > 0) {
349 sendPermissionDenied(client, "Tree message not supported");
353 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
356 for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
359 Chan_iterate(&ch_itr);
360 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
362 Log_warn("Channel id %d not found - ignoring.", msg->payload.textMessage->channel_id[i]);
365 list_iterate(itr, &ch_itr->clients) {
367 c = list_get_entry(itr, client_t, chan_node);
368 if (c != client && !c->deaf) {
370 Client_send_message(c, msg);
371 Log_debug("Text message to session ID %d", c->sessionId);
377 if (msg->payload.textMessage->n_session > 0) { /* To user */
380 for (i = 0; i < msg->payload.textMessage->n_session; i++) {
382 while (Client_iterate(&itr) != NULL) {
385 if (itr->sessionId == msg->payload.textMessage->session[i]) {
388 Client_send_message(itr, msg);
389 Log_debug("Text message to session ID %d", itr->sessionId);
395 Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
402 int i, j, count, targetId = msg->payload.voiceTarget->id;
403 struct _MumbleProto__VoiceTarget__Target *target;
405 if (!targetId || targetId >= 0x1f)
407 Voicetarget_add_id(client, targetId);
408 count = msg->payload.voiceTarget->n_targets;
411 for (i = 0; i < count; i++) {
412 target = msg->payload.voiceTarget->targets[i];
413 for (j = 0; j < target->n_session; j++)
414 Voicetarget_add_session(client, targetId, target->session[j]);
415 if (target->has_channel_id) {
416 if (target->has_links || target->has_children)
417 Log_warn("Whisper to children or linked channels not implemented. Ignoring.");
418 Voicetarget_add_channel(client, targetId, target->channel_id);
424 Log_debug("Version message received");
425 if (msg->payload.version->has_version) {
426 client->version = msg->payload.version->version;
427 Log_debug("Client version 0x%x", client->version);
429 if (msg->payload.version->release) {
430 if (client->release) free(client->release);
431 client->release = strdup(msg->payload.version->release);
432 Log_debug("Client release %s", client->release);
434 if (msg->payload.version->os) {
435 if (client->os) free(client->os);
436 client->os = strdup(msg->payload.version->os);
437 Log_debug("Client OS %s", client->os);
440 case PermissionQuery:
441 Msg_inc_ref(msg); /* Re-use message */
442 msg->payload.permissionQuery->has_permissions = true;
443 msg->payload.permissionQuery->permissions = PERM_DEFAULT;
445 Client_send_message(client, msg);
448 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
450 /* Permission denied for all these messages. Not implemented. */
454 case ContextActionAdd:
459 sendPermissionDenied(client, "Not supported by uMurmur");
463 Log_warn("Message %d not handled", msg->messageType);
470 Client_close(client);