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>
42 extern channel_t *defaultChan;
43 extern int iCodecAlpha, iCodecBeta;
44 extern bool_t bPreferAlpha;
46 static void sendServerReject(client_t *client, const char *reason, MumbleProto__Reject__RejectType type)
48 message_t *msg = Msg_create(Reject);
49 msg->payload.reject->reason = strdup(reason);
50 msg->payload.reject->type = type;
51 msg->payload.reject->has_type = true;
52 Client_send_message(client, msg);
55 static void sendPermissionDenied(client_t *client, const char *reason)
57 message_t *msg = Msg_create(PermissionDenied);
58 msg->payload.permissionDenied->has_type = true;
59 msg->payload.permissionDenied->type = MUMBLE_PROTO__PERMISSION_DENIED__DENY_TYPE__Text;
60 msg->payload.permissionDenied->reason = strdup(reason);
61 Client_send_message(client, msg);
64 void Mh_handle_message(client_t *client, message_t *msg)
67 channel_t *ch_itr = NULL;
70 switch (msg->messageType) {
73 * 1. Check stuff, Serverreject if not ok
74 * 2. Setup UDP encryption -> MessageCryptSetup
76 * 4. MessageChannelAdd + MessageChannelDescUpdate for all channels
77 * 5. (MessageChannelLink)
78 * 6. MessageServerJoin
79 * 7. MessagePlayerMove
80 * 8. MessageServerJoin for all connected users
81 * 9. PlayerDeaf/PlayerMute/PlayerSelfMuteDeaf for all users it applies to
82 * 10. MessageServerSync
85 Log_debug("Authenticate message received");
86 Log_debug("Username: %s", msg->payload.authenticate->username);
88 client->authenticated = true;
91 while (Client_iterate(&client_itr) != NULL) {
92 if (!IS_AUTH(client_itr))
94 if (client_itr->playerName && strncmp(client_itr->playerName, msg->payload.authenticate->username, MAX_TEXT) == 0) {
96 sprintf(buf, "Username already in use");
97 Log_debug("Username already in use");
98 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__UsernameInUse);
102 if (msg->payload.authenticate->password && strncmp(getStrConf(PASSPHRASE), msg->payload.authenticate->password, MAX_TEXT) != 0) {
104 sprintf(buf, "Wrong server password");
105 Log_debug("Wrong server password: %s", msg->payload.authenticate->password);
106 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__WrongServerPW);
109 if (strlen(msg->payload.authenticate->username) == 0 ||
110 strlen(msg->payload.authenticate->username) >= MAX_TEXT) { /* XXX - other invalid names? */
112 sprintf(buf, "Invalid username");
113 Log_debug("Invalid username");
114 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__InvalidUsername);
118 if (Client_count() >= getIntConf(MAX_CLIENTS)) {
120 sprintf(buf, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
121 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__ServerFull);
125 /* Name & password */
126 client->playerName = strdup(msg->payload.authenticate->username);
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);
144 Chan_playerJoin(defaultChan, client); /* Join default channel */
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);
151 Log_debug("Client %d has %d CELT codecs", client->sessionId, msg->payload.authenticate->n_celt_versions);
152 if (msg->payload.authenticate->n_celt_versions > 0) {
154 client->codec_count = msg->payload.authenticate->n_celt_versions > MAX_CODECS ?
155 MAX_CODECS : msg->payload.authenticate->n_celt_versions;
156 for (i = 0; i < client->codec_count; i++) {
157 client->codecs[i] = msg->payload.authenticate->celt_versions[i];
158 Log_debug("Client %d CELT codec ver 0x%x", client->sessionId, client->codecs[i]);
161 client->codecs[0] = (int32_t)0x8000000a;
162 client->codec_count = 1;
165 recheckCodecVersions();
167 sendmsg = Msg_create(CodecVersion);
168 sendmsg->payload.codecVersion->alpha = iCodecAlpha;
169 sendmsg->payload.codecVersion->beta = iCodecBeta;
170 sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha;
171 Client_send_message(client, sendmsg);
173 /* Iterate channels and send channel info */
175 Chan_iterate(&ch_itr);
177 sendmsg = Msg_create(ChannelState);
178 sendmsg->payload.channelState->has_channel_id = true;
179 sendmsg->payload.channelState->channel_id = ch_itr->id;
180 if (ch_itr->id != 0) {
181 sendmsg->payload.channelState->has_parent = true;
182 sendmsg->payload.channelState->parent = ch_itr->parent->id;
184 sendmsg->payload.channelState->name = strdup(ch_itr->name);
185 if (strlen(ch_itr->desc) > 0) {
186 sendmsg->payload.channelState->description = strdup(ch_itr->desc);
188 Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
189 Client_send_message(client, sendmsg);
191 Chan_iterate(&ch_itr);
192 } while (ch_itr != NULL);
194 /* Not supporting channel links yet */
196 /* Send user state for connecting user to other users */
197 sendmsg = Msg_create(UserState);
198 sendmsg->payload.userState->has_session = true;
199 sendmsg->payload.userState->session = client->sessionId;
200 sendmsg->payload.userState->has_user_id = true;
201 sendmsg->payload.userState->user_id = client->sessionId;
202 sendmsg->payload.userState->name = strdup(client->playerName);
203 sendmsg->payload.userState->has_channel_id = true;
204 sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
206 Client_send_message_except(client, sendmsg);
209 while (Client_iterate(&client_itr) != NULL) {
210 if (!IS_AUTH(client_itr))
212 sendmsg = Msg_create(UserState);
213 sendmsg->payload.userState->has_session = true;
214 sendmsg->payload.userState->session = client_itr->sessionId;
215 sendmsg->payload.userState->name = strdup(client_itr->playerName);
216 sendmsg->payload.userState->has_channel_id = true;
217 sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
219 /* XXX - check if self_* is correct */
220 if (client_itr->deaf) {
221 sendmsg->payload.userState->has_self_deaf = true;
222 sendmsg->payload.userState->self_deaf = true;
224 if (client_itr->mute) {
225 sendmsg->payload.userState->has_self_mute = true;
226 sendmsg->payload.userState->self_mute = true;
228 Client_send_message(client, sendmsg);
232 sendmsg = Msg_create(ServerSync);
233 sendmsg->payload.serverSync->has_session = true;
234 sendmsg->payload.serverSync->session = client->sessionId;
235 sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT));
236 sendmsg->payload.serverSync->has_max_bandwidth = true;
237 sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH);
238 sendmsg->payload.serverSync->has_allow_html = true;
239 sendmsg->payload.serverSync->allow_html = true; /* Support this? */
240 Client_send_message(client, sendmsg);
242 Log_info("User %s authenticated", client->playerName);
246 if (msg->payload.ping->has_good)
247 client->cryptState.uiRemoteGood = msg->payload.ping->good;
248 if (msg->payload.ping->has_late)
249 client->cryptState.uiRemoteLate = msg->payload.ping->late;
250 if (msg->payload.ping->has_lost)
251 client->cryptState.uiRemoteLost = msg->payload.ping->lost;
252 if (msg->payload.ping->has_resync)
253 client->cryptState.uiRemoteResync = msg->payload.ping->resync;
255 Log_debug("Ping <-: %d %d %d %d",
256 client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
257 client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync
260 /* Ignoring the double values since they don't seem to be used */
262 sendmsg = Msg_create(Ping);
264 sendmsg->payload.ping->timestamp = msg->payload.ping->timestamp;
265 sendmsg->payload.ping->has_timestamp = true;
266 sendmsg->payload.ping->good = client->cryptState.uiGood;
267 sendmsg->payload.ping->has_good = true;
268 sendmsg->payload.ping->late = client->cryptState.uiLate;
269 sendmsg->payload.ping->has_late = true;
270 sendmsg->payload.ping->lost = client->cryptState.uiLost;
271 sendmsg->payload.ping->has_lost = true;
272 sendmsg->payload.ping->resync = client->cryptState.uiResync;
273 sendmsg->payload.ping->has_resync = true;
275 Client_send_message(client, sendmsg);
276 Log_debug("Ping ->: %d %d %d %d",
277 client->cryptState.uiGood, client->cryptState.uiLate,
278 client->cryptState.uiLost, client->cryptState.uiResync);
282 Log_debug("Voice channel crypt resync requested");
283 if (!msg->payload.cryptSetup->has_client_nonce) {
284 sendmsg = Msg_create(CryptSetup);
285 sendmsg->payload.cryptSetup->has_server_nonce = true;
286 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.decrypt_iv;
287 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
288 Client_send_message(client, sendmsg);
290 memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSetup->client_nonce.data, AES_BLOCK_SIZE);
291 client->cryptState.uiResync++;
295 /* Only allow state changes for for the self user */
296 if (msg->payload.userState->has_session &&
297 msg->payload.userState->session != client->sessionId) {
298 sendPermissionDenied(client, "Permission denied");
301 if (msg->payload.userState->has_user_id || msg->payload.userState->has_mute ||
302 msg->payload.userState->has_deaf || msg->payload.userState->has_suppress ||
303 msg->payload.userState->has_texture) {
305 sendPermissionDenied(client, "Not supported by uMurmur");
308 if (msg->payload.userState->has_self_deaf) {
309 client->deaf = msg->payload.userState->self_deaf;
311 if (msg->payload.userState->has_self_mute) {
312 client->mute = msg->payload.userState->self_mute;
314 if (msg->payload.userState->has_channel_id) {
315 Chan_playerJoin_id(msg->payload.userState->channel_id, client);
319 msg->payload.userState->has_actor = true;
320 msg->payload.userState->actor = client->sessionId;
321 Client_send_message_except(NULL, msg);
325 msg->payload.textMessage->has_actor = true;
326 msg->payload.textMessage->actor = client->sessionId;
328 /* XXX - Allow HTML stuff? */
330 if (msg->payload.textMessage->n_tree_id > 0) {
331 sendPermissionDenied(client, "Tree message not supported");
335 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
338 for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
341 Chan_iterate(&ch_itr);
342 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
344 Log_warn("Channel id %d not found - ignoring.", msg->payload.textMessage->channel_id[i]);
347 list_iterate(itr, &ch_itr->clients) {
349 c = list_get_entry(itr, client_t, chan_node);
350 if (c != client && !c->deaf) {
352 Client_send_message(c, msg);
353 Log_debug("Text message to session ID %d", c->sessionId);
359 if (msg->payload.textMessage->n_session > 0) { /* To user */
362 for (i = 0; i < msg->payload.textMessage->n_session; i++) {
364 while (Client_iterate(&itr) != NULL) {
367 if (itr->sessionId == msg->payload.textMessage->session[i]) {
370 Client_send_message(itr, msg);
371 Log_debug("Text message to session ID %d", itr->sessionId);
377 Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
387 Log_debug("Version message received");
388 if (msg->payload.version->has_version) {
389 client->version = msg->payload.version->version;
390 Log_debug("Client version 0x%x", client->version);
392 if (msg->payload.version->release) {
393 if (client->release) free(client->release);
394 client->release = strdup(msg->payload.version->release);
395 Log_debug("Client release %s", client->release);
397 if (msg->payload.version->os) {
398 if (client->os) free(client->os);
399 client->os = strdup(msg->payload.version->os);
400 Log_debug("Client OS %s", client->os);
403 case PermissionQuery:
404 Msg_inc_ref(msg); /* Re-use message */
405 msg->payload.permissionQuery->has_permissions = true;
406 msg->payload.permissionQuery->permissions = PERM_DEFAULT;
408 Client_send_message(client, msg);
411 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
413 /* Permission denied for all these messages. Not implemented. */
417 case ContextActionAdd:
420 sendPermissionDenied(client, "Not supported by uMurmur");
424 Log_warn("Message %d not handled", msg->messageType);
431 Client_close(client);