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;
44 static void sendServerReject(client_t *client, const char *reason, MumbleProto__Reject__RejectType type)
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);
53 static void sendPermissionDenied(client_t *client, const char *reason)
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);
62 void Mh_handle_message(client_t *client, message_t *msg)
65 channel_t *ch_itr = NULL;
68 switch (msg->messageType) {
71 * 1. Check stuff, Serverreject if not ok
72 * 2. Setup UDP encryption -> MessageCryptSetup
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
83 Log_debug("Authenticate message received");
84 Log_debug("Username: %s", msg->payload.authenticate->username);
86 client->authenticated = true;
89 while (Client_iterate(&client_itr) != NULL) {
90 if (!IS_AUTH(client_itr))
92 if (strncmp(client_itr->playerName, msg->payload.authenticate->username, MAX_TEXT) == 0) {
94 sprintf(buf, "Username already in use");
95 Log_debug("Username already in use");
96 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__UsernameInUse);
100 if (msg->payload.authenticate->password && strncmp(getStrConf(PASSPHRASE), msg->payload.authenticate->password, MAX_TEXT) != 0) {
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);
107 if (strlen(msg->payload.authenticate->username) == 0 ||
108 strlen(msg->payload.authenticate->username) >= MAX_TEXT) { /* XXX - other invalid names? */
110 sprintf(buf, "Invalid username");
111 Log_debug("Invalid username");
112 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__InvalidUsername);
116 if (Client_count() >= getIntConf(MAX_CLIENTS)) {
118 sprintf(buf, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
119 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__ServerFull);
123 /* Name & password */
124 strncpy(client->playerName, msg->payload.authenticate->username, MAX_TEXT);
125 client->playerId = client->sessionId;
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);
150 if (msg->payload.authenticate->n_celt_versions > 0) {
152 client->codec_count = msg->payload.authenticate->n_celt_versions > MAX_CODECS ?
153 MAX_CODECS : msg->payload.authenticate->n_celt_versions;
154 for (i = 0; i < client->codec_count; i++)
155 client->codecs[i] = msg->payload.authenticate->celt_versions[i];
157 client->codecs[0] = (int32_t)0x8000000a;
158 client->codec_count = 1;
160 recheckCodecVersions();
162 /* Iterate channels and send channel info */
164 Chan_iterate(&ch_itr);
166 sendmsg = Msg_create(ChannelState);
167 sendmsg->payload.channelState->has_channel_id = true;
168 sendmsg->payload.channelState->channel_id = ch_itr->id;
169 if (ch_itr->id != 0) {
170 sendmsg->payload.channelState->has_parent = true;
171 sendmsg->payload.channelState->parent = ch_itr->parent->id;
173 sendmsg->payload.channelState->name = strdup(ch_itr->name);
174 if (strlen(ch_itr->desc) > 0) {
175 sendmsg->payload.channelState->description = strdup(ch_itr->desc);
177 Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
178 Client_send_message(client, sendmsg);
180 Chan_iterate(&ch_itr);
181 } while (ch_itr != NULL);
183 /* Not supporting channel links yet */
185 /* Send user state for connecting user to other users */
186 sendmsg = Msg_create(UserState);
187 sendmsg->payload.userState->has_session = true;
188 sendmsg->payload.userState->session = client->sessionId;
189 sendmsg->payload.userState->has_user_id = true;
190 sendmsg->payload.userState->user_id = client->playerId;
191 sendmsg->payload.userState->name = strdup(client->playerName);
192 sendmsg->payload.userState->has_channel_id = true;
193 sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
195 Client_send_message_except(client, sendmsg);
198 while (Client_iterate(&client_itr) != NULL) {
199 if (!IS_AUTH(client_itr))
201 sendmsg = Msg_create(UserState);
202 sendmsg->payload.userState->has_session = true;
203 sendmsg->payload.userState->session = client_itr->sessionId;
204 sendmsg->payload.userState->name = strdup(client_itr->playerName);
205 sendmsg->payload.userState->has_channel_id = true;
206 sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
208 /* XXX - check if self_* is correct */
209 if (client_itr->deaf) {
210 sendmsg->payload.userState->has_self_deaf = true;
211 sendmsg->payload.userState->self_deaf = true;
213 if (client_itr->mute) {
214 sendmsg->payload.userState->has_self_mute = true;
215 sendmsg->payload.userState->self_mute = true;
217 Client_send_message(client, sendmsg);
221 sendmsg = Msg_create(ServerSync);
222 sendmsg->payload.serverSync->has_session = true;
223 sendmsg->payload.serverSync->session = client->sessionId;
224 sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT));
225 sendmsg->payload.serverSync->has_max_bandwidth = true;
226 sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH);
227 sendmsg->payload.serverSync->has_allow_html = true;
228 sendmsg->payload.serverSync->allow_html = false; /* Support this? */
229 Client_send_message(client, sendmsg);
231 Log_info("User %s authenticated", client->playerName);
237 if (msg->payload.ping->has_good)
238 client->cryptState.uiRemoteGood = msg->payload.ping->good;
239 if (msg->payload.ping->has_late)
240 client->cryptState.uiRemoteLate = msg->payload.ping->late;
241 if (msg->payload.ping->has_lost)
242 client->cryptState.uiRemoteLost = msg->payload.ping->lost;
243 if (msg->payload.ping->has_resync)
244 client->cryptState.uiRemoteResync = msg->payload.ping->resync;
246 Log_debug("Ping <-: %d %d %d %d",
247 client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
248 client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync
251 /* Ignoring the double values since they don't seem to be used */
253 sendmsg = Msg_create(Ping);
254 timestamp = msg->payload.ping->timestamp;
256 sendmsg->payload.ping->timestamp = timestamp;
258 sendmsg->payload.ping->good = client->cryptState.uiGood;
259 sendmsg->payload.ping->has_good = true;
260 sendmsg->payload.ping->late = client->cryptState.uiLate;
261 sendmsg->payload.ping->has_late = true;
262 sendmsg->payload.ping->lost = client->cryptState.uiLost;
263 sendmsg->payload.ping->has_lost = true;
264 sendmsg->payload.ping->resync = client->cryptState.uiResync;
265 sendmsg->payload.ping->has_resync = true;
267 Client_send_message(client, sendmsg);
268 Log_debug("Ping ->: %d %d %d %d",
269 client->cryptState.uiGood, client->cryptState.uiLate,
270 client->cryptState.uiLost, client->cryptState.uiResync);
275 Log_debug("Voice channel crypt resync requested");
276 if (!msg->payload.cryptSetup->has_client_nonce) {
277 sendmsg = Msg_create(CryptSetup);
278 sendmsg->payload.cryptSetup->has_server_nonce = true;
279 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.decrypt_iv;
280 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
281 Client_send_message(client, sendmsg);
283 memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSetup->client_nonce.data, AES_BLOCK_SIZE);
284 client->cryptState.uiResync++;
288 /* Only allow state changes for for the self user */
289 if (msg->payload.userState->has_session &&
290 msg->payload.userState->session != client->sessionId) {
291 sendPermissionDenied(client, "Permission denied");
294 if (msg->payload.userState->has_user_id || msg->payload.userState->has_mute ||
295 msg->payload.userState->has_deaf || msg->payload.userState->has_suppress ||
296 msg->payload.userState->has_texture) {
298 sendPermissionDenied(client, "Not supported by uMurmur");
301 if (msg->payload.userState->has_self_deaf) {
302 client->deaf = msg->payload.userState->self_deaf;
304 if (msg->payload.userState->has_self_mute) {
305 client->mute = msg->payload.userState->self_mute;
307 if (msg->payload.userState->has_channel_id) {
308 Chan_playerJoin_id(msg->payload.userState->channel_id, client);
312 msg->payload.userState->has_actor = true;
313 msg->payload.userState->actor = client->sessionId;
314 Client_send_message_except(NULL, msg);
318 msg->payload.textMessage->has_actor = true;
319 msg->payload.textMessage->actor = client->sessionId;
321 /* XXX - Allow HTML stuff? */
323 if (msg->payload.textMessage->n_tree_id > 0) {
324 sendPermissionDenied(client, "Tree message not supported");
328 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
331 for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
334 Chan_iterate(&ch_itr);
335 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
337 Log_warn("Channel id %d not found - ignoring.", msg->payload.textMessage->channel_id[i]);
340 list_iterate(itr, &ch_itr->clients) {
342 c = list_get_entry(itr, client_t, chan_node);
343 if (c != client && !c->deaf) {
345 Client_send_message(c, msg);
346 Log_debug("Text message to session ID %d", c->sessionId);
352 if (msg->payload.textMessage->n_session > 0) { /* To user */
355 for (i = 0; i < msg->payload.textMessage->n_session; i++) {
357 while (Client_iterate(&itr) != NULL) {
360 if (itr->playerId == msg->payload.textMessage->session[i]) {
363 Client_send_message(itr, msg);
369 Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
379 Log_debug("Version message received");
380 if (msg->payload.version->has_version) {
381 client->version = msg->payload.version->version;
382 Log_debug("Client version 0x%x", client->version);
384 if (msg->payload.version->release) {
385 if (client->release) free(client->release);
386 client->release = strdup(msg->payload.version->release);
387 Log_debug("Client release %s", client->release);
389 if (msg->payload.version->os) {
390 if (client->os) free(client->os);
391 client->os = strdup(msg->payload.version->os);
392 Log_debug("Client OS %s", client->os);
396 Msg_inc_ref(msg); /* Re-use message */
398 /* XXX - fill in version */
400 Client_send_message(client, msg);
403 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
405 /* Permission denied for all these messages. Not implemented. */
409 case ContextActionAdd:
412 sendPermissionDenied(client, "Not supported by uMurmur");
416 Log_warn("Message %d not handled", msg->messageType);
423 Client_close(client);