1 /* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2009, 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);
56 static void sendPermissionDenied(client_t *client, const char *reason)
58 message_t *msg = Msg_create(PermissionDenied);
59 msg->payload.permissionDenied->has_type = true;
60 msg->payload.permissionDenied->type = MUMBLE_PROTO__PERMISSION_DENIED__DENY_TYPE__Text;
61 msg->payload.permissionDenied->reason = strdup(reason);
62 Client_send_message(client, msg);
65 void Mh_handle_message(client_t *client, message_t *msg)
68 channel_t *ch_itr = NULL;
71 switch (msg->messageType) {
74 * 1. Check stuff, Serverreject if not ok
75 * 2. Setup UDP encryption -> MessageCryptSetup
77 * 4. MessageChannelAdd + MessageChannelDescUpdate for all channels
78 * 5. (MessageChannelLink)
79 * 6. MessageServerJoin
80 * 7. MessagePlayerMove
81 * 8. MessageServerJoin for all connected users
82 * 9. PlayerDeaf/PlayerMute/PlayerSelfMuteDeaf for all users it applies to
83 * 10. MessageServerSync
86 Log_debug("Authenticate message received");
87 Log_debug("Username: %s", msg->payload.authenticate->username);
89 client->authenticated = true;
92 while (Client_iterate(&client_itr) != NULL) {
93 if (!IS_AUTH(client_itr))
95 if (client_itr->playerName && strncmp(client_itr->playerName, msg->payload.authenticate->username, MAX_TEXT) == 0) {
97 sprintf(buf, "Username already in use");
98 Log_debug("Username already in use");
99 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__UsernameInUse);
103 if (msg->payload.authenticate->password && strncmp(getStrConf(PASSPHRASE), msg->payload.authenticate->password, MAX_TEXT) != 0) {
105 sprintf(buf, "Wrong server password");
106 Log_debug("Wrong server password: %s", msg->payload.authenticate->password);
107 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__WrongServerPW);
110 if (strlen(msg->payload.authenticate->username) == 0 ||
111 strlen(msg->payload.authenticate->username) >= MAX_TEXT) { /* XXX - other invalid names? */
113 sprintf(buf, "Invalid username");
114 Log_debug("Invalid username");
115 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__InvalidUsername);
119 if (Client_count() >= getIntConf(MAX_CLIENTS)) {
121 sprintf(buf, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
122 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__ServerFull);
126 /* Name & password */
127 client->playerName = strdup(msg->payload.authenticate->username);
129 /* Setup UDP encryption */
130 CryptState_init(&client->cryptState);
131 CryptState_genKey(&client->cryptState);
132 sendmsg = Msg_create(CryptSetup);
133 sendmsg->payload.cryptSetup->has_key = true;
134 sendmsg->payload.cryptSetup->key.data = client->cryptState.raw_key;
135 sendmsg->payload.cryptSetup->key.len = AES_BLOCK_SIZE;
136 sendmsg->payload.cryptSetup->has_server_nonce = true;
137 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.encrypt_iv;
138 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
139 sendmsg->payload.cryptSetup->has_client_nonce = true;
140 sendmsg->payload.cryptSetup->client_nonce.data = client->cryptState.decrypt_iv;
141 sendmsg->payload.cryptSetup->client_nonce.len = AES_BLOCK_SIZE;
142 Client_send_message(client, sendmsg);
145 Chan_playerJoin(defaultChan, client); /* Join default channel */
148 if (msg->payload.authenticate->n_celt_versions > MAX_CODECS)
149 Log_warn("Client has more than %d CELT codecs. Ignoring %d codecs",
150 MAX_CODECS, msg->payload.authenticate->n_celt_versions - MAX_CODECS);
152 Log_debug("Client %d has %d CELT codecs", client->sessionId, msg->payload.authenticate->n_celt_versions);
153 if (msg->payload.authenticate->n_celt_versions > 0) {
155 client->codec_count = msg->payload.authenticate->n_celt_versions > MAX_CODECS ?
156 MAX_CODECS : msg->payload.authenticate->n_celt_versions;
157 for (i = 0; i < client->codec_count; i++) {
158 client->codecs[i] = msg->payload.authenticate->celt_versions[i];
159 Log_debug("Client %d CELT codec ver 0x%x", client->sessionId, client->codecs[i]);
162 client->codecs[0] = (int32_t)0x8000000a;
163 client->codec_count = 1;
166 recheckCodecVersions();
168 sendmsg = Msg_create(CodecVersion);
169 sendmsg->payload.codecVersion->alpha = iCodecAlpha;
170 sendmsg->payload.codecVersion->beta = iCodecBeta;
171 sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha;
172 Client_send_message(client, sendmsg);
174 /* Iterate channels and send channel info */
176 Chan_iterate(&ch_itr);
178 sendmsg = Msg_create(ChannelState);
179 sendmsg->payload.channelState->has_channel_id = true;
180 sendmsg->payload.channelState->channel_id = ch_itr->id;
181 if (ch_itr->id != 0) {
182 sendmsg->payload.channelState->has_parent = true;
183 sendmsg->payload.channelState->parent = ch_itr->parent->id;
185 sendmsg->payload.channelState->name = strdup(ch_itr->name);
186 if (strlen(ch_itr->desc) > 0) {
187 sendmsg->payload.channelState->description = strdup(ch_itr->desc);
189 Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
190 Client_send_message(client, sendmsg);
192 Chan_iterate(&ch_itr);
193 } while (ch_itr != NULL);
195 /* Not supporting channel links yet */
197 /* Send user state for connecting user to other users */
198 sendmsg = Msg_create(UserState);
199 sendmsg->payload.userState->has_session = true;
200 sendmsg->payload.userState->session = client->sessionId;
201 sendmsg->payload.userState->has_user_id = true;
202 sendmsg->payload.userState->user_id = client->sessionId;
203 sendmsg->payload.userState->name = strdup(client->playerName);
204 sendmsg->payload.userState->has_channel_id = true;
205 sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
207 Client_send_message_except(client, sendmsg);
210 while (Client_iterate(&client_itr) != NULL) {
211 if (!IS_AUTH(client_itr))
213 sendmsg = Msg_create(UserState);
214 sendmsg->payload.userState->has_session = true;
215 sendmsg->payload.userState->session = client_itr->sessionId;
216 sendmsg->payload.userState->name = strdup(client_itr->playerName);
217 sendmsg->payload.userState->has_channel_id = true;
218 sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
220 /* XXX - check if self_* is correct */
221 if (client_itr->deaf) {
222 sendmsg->payload.userState->has_self_deaf = true;
223 sendmsg->payload.userState->self_deaf = true;
225 if (client_itr->mute) {
226 sendmsg->payload.userState->has_self_mute = true;
227 sendmsg->payload.userState->self_mute = true;
229 Client_send_message(client, sendmsg);
233 sendmsg = Msg_create(ServerSync);
234 sendmsg->payload.serverSync->has_session = true;
235 sendmsg->payload.serverSync->session = client->sessionId;
236 sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT));
237 sendmsg->payload.serverSync->has_max_bandwidth = true;
238 sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH);
239 sendmsg->payload.serverSync->has_allow_html = true;
240 sendmsg->payload.serverSync->allow_html = true; /* Support this? */
241 Client_send_message(client, sendmsg);
243 Log_info("User %s authenticated", client->playerName);
247 if (msg->payload.ping->has_good)
248 client->cryptState.uiRemoteGood = msg->payload.ping->good;
249 if (msg->payload.ping->has_late)
250 client->cryptState.uiRemoteLate = msg->payload.ping->late;
251 if (msg->payload.ping->has_lost)
252 client->cryptState.uiRemoteLost = msg->payload.ping->lost;
253 if (msg->payload.ping->has_resync)
254 client->cryptState.uiRemoteResync = msg->payload.ping->resync;
256 Log_debug("Ping <-: %d %d %d %d",
257 client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
258 client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync
261 /* Ignoring the double values since they don't seem to be used */
263 sendmsg = Msg_create(Ping);
265 sendmsg->payload.ping->timestamp = msg->payload.ping->timestamp;
266 sendmsg->payload.ping->has_timestamp = true;
267 sendmsg->payload.ping->good = client->cryptState.uiGood;
268 sendmsg->payload.ping->has_good = true;
269 sendmsg->payload.ping->late = client->cryptState.uiLate;
270 sendmsg->payload.ping->has_late = true;
271 sendmsg->payload.ping->lost = client->cryptState.uiLost;
272 sendmsg->payload.ping->has_lost = true;
273 sendmsg->payload.ping->resync = client->cryptState.uiResync;
274 sendmsg->payload.ping->has_resync = true;
276 Client_send_message(client, sendmsg);
277 Log_debug("Ping ->: %d %d %d %d",
278 client->cryptState.uiGood, client->cryptState.uiLate,
279 client->cryptState.uiLost, client->cryptState.uiResync);
283 Log_debug("Voice channel crypt resync requested");
284 if (!msg->payload.cryptSetup->has_client_nonce) {
285 sendmsg = Msg_create(CryptSetup);
286 sendmsg->payload.cryptSetup->has_server_nonce = true;
287 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.decrypt_iv;
288 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
289 Client_send_message(client, sendmsg);
291 memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSetup->client_nonce.data, AES_BLOCK_SIZE);
292 client->cryptState.uiResync++;
296 /* Only allow state changes for for the self user */
297 if (msg->payload.userState->has_session &&
298 msg->payload.userState->session != client->sessionId) {
299 sendPermissionDenied(client, "Permission denied");
302 if (msg->payload.userState->has_user_id || msg->payload.userState->has_mute ||
303 msg->payload.userState->has_deaf || msg->payload.userState->has_suppress ||
304 msg->payload.userState->has_texture) {
306 sendPermissionDenied(client, "Not supported by uMurmur");
309 if (msg->payload.userState->has_self_deaf) {
310 client->deaf = msg->payload.userState->self_deaf;
312 if (msg->payload.userState->has_self_mute) {
313 client->mute = msg->payload.userState->self_mute;
315 if (msg->payload.userState->has_channel_id) {
316 Chan_playerJoin_id(msg->payload.userState->channel_id, client);
320 msg->payload.userState->has_actor = true;
321 msg->payload.userState->actor = client->sessionId;
322 Client_send_message_except(NULL, msg);
326 msg->payload.textMessage->has_actor = true;
327 msg->payload.textMessage->actor = client->sessionId;
329 /* XXX - Allow HTML stuff? */
331 if (msg->payload.textMessage->n_tree_id > 0) {
332 sendPermissionDenied(client, "Tree message not supported");
336 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
339 for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
342 Chan_iterate(&ch_itr);
343 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
345 Log_warn("Channel id %d not found - ignoring.", msg->payload.textMessage->channel_id[i]);
348 list_iterate(itr, &ch_itr->clients) {
350 c = list_get_entry(itr, client_t, chan_node);
351 if (c != client && !c->deaf) {
353 Client_send_message(c, msg);
354 Log_debug("Text message to session ID %d", c->sessionId);
360 if (msg->payload.textMessage->n_session > 0) { /* To user */
363 for (i = 0; i < msg->payload.textMessage->n_session; i++) {
365 while (Client_iterate(&itr) != NULL) {
368 if (itr->sessionId == msg->payload.textMessage->session[i]) {
371 Client_send_message(itr, msg);
372 Log_debug("Text message to session ID %d", itr->sessionId);
378 Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
385 int i, j, count, targetId = msg->payload.voiceTarget->id;
386 struct _MumbleProto__VoiceTarget__Target *target;
388 if (!targetId || targetId >= 0x1f)
390 Voicetarget_add_id(client, targetId);
391 count = msg->payload.voiceTarget->n_targets;
394 for (i = 0; i < count; i++) {
395 target = msg->payload.voiceTarget->targets[i];
396 for (j = 0; j < target->n_session; j++)
397 Voicetarget_add_session(client, targetId, target->session[j]);
398 if (target->has_channel_id) {
399 if (target->has_links || target->has_children)
400 Log_warn("Whisper to children or linked channels not implemented. Ignoring.");
401 Voicetarget_add_channel(client, targetId, target->channel_id);
407 Log_debug("Version message received");
408 if (msg->payload.version->has_version) {
409 client->version = msg->payload.version->version;
410 Log_debug("Client version 0x%x", client->version);
412 if (msg->payload.version->release) {
413 if (client->release) free(client->release);
414 client->release = strdup(msg->payload.version->release);
415 Log_debug("Client release %s", client->release);
417 if (msg->payload.version->os) {
418 if (client->os) free(client->os);
419 client->os = strdup(msg->payload.version->os);
420 Log_debug("Client OS %s", client->os);
423 case PermissionQuery:
424 Msg_inc_ref(msg); /* Re-use message */
425 msg->payload.permissionQuery->has_permissions = true;
426 msg->payload.permissionQuery->permissions = PERM_DEFAULT;
428 Client_send_message(client, msg);
431 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
433 /* Permission denied for all these messages. Not implemented. */
437 case ContextActionAdd:
442 sendPermissionDenied(client, "Not supported by uMurmur");
446 Log_warn("Message %d not handled", msg->messageType);
453 Client_close(client);