From 4c75c8f9eb45c0a696f992c277dcc8ffb77fa3ba Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Mon, 6 Dec 2010 14:21:34 +0000 Subject: [PATCH 01/16] Add support for UserStats message. --- src/client.c | 6 ++ src/client.h | 6 +- src/messagehandler.c | 147 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 150 insertions(+), 9 deletions(-) diff --git a/src/client.c b/src/client.c index e515a45..963ec4d 100644 --- a/src/client.c +++ b/src/client.c @@ -259,6 +259,8 @@ int Client_add(int fd, struct sockaddr_in *remote) } newclient->availableBandwidth = maxBandwidth; Timer_init(&newclient->lastActivity); + Timer_init(&newclient->connectTime); + Timer_init(&newclient->idleTime); newclient->sessionId = findFreeSessionId(); if (newclient->sessionId < 0) Log_fatal("Could not find a free session ID"); @@ -317,6 +319,8 @@ void Client_free(client_t *client) free(client->release); if (client->os) free(client->os); + if (client->os_version) + free(client->os_version); if (client->username) free(client->username); if (client->context) @@ -719,6 +723,8 @@ int Client_voiceMsg(client_t *client, uint8_t *data, int len) goto out; /* Discard */ client->availableBandwidth -= packetsize; + Timer_restart(&client->idleTime); + counter = Pds_get_numval(pdi); /* step past session id */ do { counter = Pds_next8(pdi); diff --git a/src/client.h b/src/client.h index 66bf7d8..d2f935c 100644 --- a/src/client.h +++ b/src/client.h @@ -71,12 +71,12 @@ typedef struct { uint64_t key; char *username; bool_t bUDP, authenticated, deaf, mute; - char *os, *release; + char *os, *release, *os_version; uint32_t version; int codec_count; struct dlist codecs; int availableBandwidth; - etimer_t lastActivity; + etimer_t lastActivity, connectTime, idleTime; struct dlist node; struct dlist txMsgQueue; int txQueueCount; @@ -84,6 +84,8 @@ typedef struct { char *context; struct dlist chan_node; struct dlist voicetargets; + float UDPPingAvg, UDPPingVar, TCPPingAvg, TCPPingVar; + uint32_t UDPPackets, TCPPackets; } client_t; typedef struct { diff --git a/src/messagehandler.c b/src/messagehandler.c index 4111d49..640a736 100644 --- a/src/messagehandler.c +++ b/src/messagehandler.c @@ -76,7 +76,20 @@ void Mh_handle_message(client_t *client, message_t *msg) if (!client->authenticated && !(msg->messageType == Authenticate || msg->messageType == Version)) { goto out; - } + } + + switch (msg->messageType) { + case UDPTunnel: + case Ping: + case CryptSetup: + case VoiceTarget: + case UserStats: + case PermissionQuery: + break; + default: + Timer_restart(&client->idleTime); + } + switch (msg->messageType) { case Authenticate: Log_debug("Authenticate message received"); @@ -260,10 +273,18 @@ void Mh_handle_message(client_t *client, message_t *msg) sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT)); sendmsg->payload.serverSync->has_max_bandwidth = true; sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH); - sendmsg->payload.serverSync->has_allow_html = true; - sendmsg->payload.serverSync->allow_html = true; /* Support this? */ Client_send_message(client, sendmsg); - + + /* Server config message */ + sendmsg = Msg_create(ServerConfig); + sendmsg->payload.serverConfig->has_allow_html = true; + sendmsg->payload.serverConfig->allow_html = true; /* Support this? */ + sendmsg->payload.serverConfig->has_message_length = true; + sendmsg->payload.serverConfig->message_length = MAX_TEXT; /* Hardcoded */ + sendmsg->payload.serverConfig->has_image_message_length = true; + sendmsg->payload.serverConfig->image_message_length = 0; /* XXX */ + Client_send_message(client, sendmsg); + Log_info_client(client, "User %s authenticated", client->username); break; @@ -282,7 +303,12 @@ void Mh_handle_message(client_t *client, message_t *msg) client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync ); - /* Ignoring the double values since they don't seem to be used */ + client->UDPPingAvg = msg->payload.ping->udp_ping_avg; + client->UDPPingVar = msg->payload.ping->udp_ping_var; + client->TCPPingAvg = msg->payload.ping->tcp_ping_avg; + client->TCPPingVar = msg->payload.ping->tcp_ping_var; + client->UDPPackets = msg->payload.ping->udp_packets; + client->TCPPackets = msg->payload.ping->tcp_packets; sendmsg = Msg_create(Ping); @@ -358,12 +384,14 @@ void Mh_handle_message(client_t *client, message_t *msg) sendmsg->payload.channelRemove->channel_id = leave_id; } } - if (msg->payload.userState->plugin_context != NULL) { + if (msg->payload.userState->has_plugin_context) { if (client->context) free(client->context); - client->context = strdup(msg->payload.userState->plugin_context); + client->context = malloc(msg->payload.userState->plugin_context.len); if (client->context == NULL) Log_fatal("Out of memory"); + memcpy(client->context, msg->payload.userState->plugin_context.data, + msg->payload.userState->plugin_context.len); break; /* Don't inform other users about this state */ } @@ -475,6 +503,11 @@ void Mh_handle_message(client_t *client, message_t *msg) client->os = strdup(msg->payload.version->os); Log_debug("Client OS %s", client->os); } + if (msg->payload.version->os_version) { + if (client->os_version) free(client->os_version); + client->os_version = strdup(msg->payload.version->os_version); + Log_debug("Client OS version %s", client->os_version); + } break; case PermissionQuery: Msg_inc_ref(msg); /* Re-use message */ @@ -568,6 +601,106 @@ void Mh_handle_message(client_t *client, message_t *msg) } break; + case UserStats: + { + client_t *target = NULL; + codec_t *codec_itr = NULL; + int i; + bool_t details = true; + + if (msg->payload.userStats->has_stats_only) + details = !msg->payload.userStats->stats_only; + + if (!msg->payload.userStats->has_session) + sendPermissionDenied(client, "Not supported by uMurmur"); + while (Client_iterate(&target) != NULL) { + if (!IS_AUTH(target)) + continue; + if (target->sessionId == msg->payload.userStats->session) + break; + } + if (!target) /* Not found */ + break; + + /* + * Differences from Murmur: + * o Ignoring certificates intentionally + * o Ignoring channel local determining + */ + + sendmsg = Msg_create(UserStats); + sendmsg->payload.userStats->session = msg->payload.userStats->session; + sendmsg->payload.userStats->from_client->has_good = true; + sendmsg->payload.userStats->from_client->good = target->cryptState.uiGood; + sendmsg->payload.userStats->from_client->has_late = true; + sendmsg->payload.userStats->from_client->late = target->cryptState.uiLate; + sendmsg->payload.userStats->from_client->has_lost = true; + sendmsg->payload.userStats->from_client->lost = target->cryptState.uiLost; + sendmsg->payload.userStats->from_client->has_resync = true; + sendmsg->payload.userStats->from_client->resync = target->cryptState.uiResync; + + sendmsg->payload.userStats->from_server->has_good = true; + sendmsg->payload.userStats->from_server->good = target->cryptState.uiRemoteGood; + sendmsg->payload.userStats->from_server->has_late = true; + sendmsg->payload.userStats->from_server->late = target->cryptState.uiRemoteLate; + sendmsg->payload.userStats->from_server->has_lost = true; + sendmsg->payload.userStats->from_server->lost = target->cryptState.uiRemoteLost; + sendmsg->payload.userStats->from_server->has_resync = true; + sendmsg->payload.userStats->from_server->resync = target->cryptState.uiRemoteResync; + + sendmsg->payload.userStats->has_udp_packets = true; + sendmsg->payload.userStats->udp_packets = target->UDPPackets; + sendmsg->payload.userStats->has_udp_ping_avg = true; + sendmsg->payload.userStats->udp_ping_avg = target->UDPPingAvg; + sendmsg->payload.userStats->has_udp_ping_var = true; + sendmsg->payload.userStats->udp_ping_var = target->UDPPingVar; + + sendmsg->payload.userStats->has_tcp_ping_avg = true; + sendmsg->payload.userStats->tcp_ping_avg = target->TCPPingAvg; + sendmsg->payload.userStats->has_tcp_ping_var = true; + sendmsg->payload.userStats->tcp_ping_var = target->TCPPingVar; + sendmsg->payload.userStats->has_tcp_packets = true; + sendmsg->payload.userStats->tcp_packets = target->TCPPackets; + + if (details) { + + sendmsg->payload.userStats->version->has_version = true; + sendmsg->payload.userStats->version->version = target->version; + sendmsg->payload.userStats->version->release = strdup(target->release); + sendmsg->payload.userStats->version->os = strdup(target->os); + sendmsg->payload.userStats->version->os_version = strdup(target->os_version); + + sendmsg->payload.userStats->n_celt_versions = target->codec_count; + sendmsg->payload.userStats->celt_versions = malloc(sizeof(int32_t) * target->codec_count); + if (!sendmsg->payload.userStats->celt_versions) + Log_fatal("Out of memory"); + i = 0; + while (Client_codec_iterate(target, &codec_itr) != NULL) + sendmsg->payload.userStats->celt_versions[i++] = codec_itr->codec; + + /* Address */ + sendmsg->payload.userStats->has_address = true; + sendmsg->payload.userStats->address.data = malloc(sizeof(uint8_t) * 16); + if (!sendmsg->payload.userStats->address.data) + Log_fatal("Out of memory"); + memset(sendmsg->payload.userStats->address.data, 0, 16); + /* ipv4 representation as ipv6 address. Supposedly correct. */ + memcpy(&sendmsg->payload.userStats->address.data[12], &target->remote_tcp.sin_addr, 4); + sendmsg->payload.userStats->address.len = 16; + } + /* BW */ + sendmsg->payload.userStats->has_bandwidth = true; + sendmsg->payload.userStats->bandwidth = target->availableBandwidth; + + /* Onlinesecs */ + sendmsg->payload.userStats->has_onlinesecs = true; + sendmsg->payload.userStats->onlinesecs = Timer_elapsed(&target->connectTime) / 1000000LL; + /* Idlesecs */ + sendmsg->payload.userStats->has_idlesecs = true; + sendmsg->payload.userStats->idlesecs = Timer_elapsed(&target->idleTime) / 1000000LL; + Client_send_message(client, sendmsg); + } + break; /* Permission denied for all these messages. Not implemented. */ case ChannelRemove: case ContextAction: -- 2.30.2 From 082533e47427c10c255a12a962b8d8ea7ef0bdc0 Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Mon, 6 Dec 2010 20:03:03 +0000 Subject: [PATCH 02/16] Add functions for sending messages to clients with different Mumble versions. Add recording support. --- src/client.c | 32 ++++++++++++++++++++++++++++++++ src/client.h | 4 +++- src/messagehandler.c | 36 ++++++++++++++++++++++++++++++++---- src/messages.c | 8 ++++++++ 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/client.c b/src/client.c index 963ec4d..35ab266 100644 --- a/src/client.c +++ b/src/client.c @@ -505,6 +505,15 @@ int Client_write(client_t *client) return 0; } +int Client_send_message_ver(client_t *client, message_t *msg, uint32_t version) +{ + if ((version == 0) || (client->version >= version) || + ((version & 0x80000000) && (client->version < (~version)))) + return Client_send_message(client, msg); + else + Msg_free(msg); +} + int Client_send_message(client_t *client, message_t *msg) { if (!client->authenticated && msg->messageType != Version) { @@ -577,6 +586,29 @@ int Client_send_message_except(client_t *client, message_t *msg) return 0; } +int Client_send_message_except_ver(client_t *client, message_t *msg, uint32_t version) +{ + client_t *itr = NULL; + int count = 0; + + Msg_inc_ref(msg); /* Make sure a reference is held during the whole iteration. */ + while (Client_iterate(&itr) != NULL) { + if (itr != client) { + if (count++ > 0) + Msg_inc_ref(msg); /* One extra reference for each new copy */ + Log_debug("Msg %d to %s refcount %d", msg->messageType, itr->username, msg->refcount); + Client_send_message_ver(itr, msg, version); + } + } + Msg_free(msg); /* Free our reference to the message */ + + if (count == 0) + Msg_free(msg); /* If only 1 client is connected then no message is passed + * to Client_send_message(). Free it here. */ + + return 0; +} + static bool_t checkDecrypt(client_t *client, const uint8_t *encrypted, uint8_t *plain, unsigned int len) { if (CryptState_isValid(&client->cryptState) && diff --git a/src/client.h b/src/client.h index d2f935c..a74a206 100644 --- a/src/client.h +++ b/src/client.h @@ -70,7 +70,7 @@ typedef struct { int sessionId; uint64_t key; char *username; - bool_t bUDP, authenticated, deaf, mute; + bool_t bUDP, authenticated, deaf, mute, recording; char *os, *release, *os_version; uint32_t version; int codec_count; @@ -100,6 +100,8 @@ int Client_add(int fd, struct sockaddr_in *remote); int Client_read_fd(int fd); int Client_write_fd(int fd); int Client_send_message(client_t *client, message_t *msg); +int Client_send_message_ver(client_t *client, message_t *msg, uint32_t version); +int Client_send_message_except_ver(client_t *client, message_t *msg, uint32_t version); int Client_count(void); void Client_close(client_t *client); client_t *Client_iterate(client_t **client); diff --git a/src/messagehandler.c b/src/messagehandler.c index 640a736..c2aa522 100644 --- a/src/messagehandler.c +++ b/src/messagehandler.c @@ -42,6 +42,7 @@ #include "voicetarget.h" #define MAX_TEXT 512 +#define MAX_USERNAME 128 extern channel_t *defaultChan; extern int iCodecAlpha, iCodecBeta; @@ -108,7 +109,7 @@ void Mh_handle_message(client_t *client, message_t *msg) while (Client_iterate(&client_itr) != NULL) { if (!IS_AUTH(client_itr)) continue; - if (client_itr->username && strncmp(client_itr->username, msg->payload.authenticate->username, MAX_TEXT) == 0) { + if (client_itr->username && strncmp(client_itr->username, msg->payload.authenticate->username, MAX_USERNAME) == 0) { char buf[64]; sprintf(buf, "Username already in use"); Log_debug("Username already in use"); @@ -129,7 +130,7 @@ void Mh_handle_message(client_t *client, message_t *msg) } } if (strlen(msg->payload.authenticate->username) == 0 || - strlen(msg->payload.authenticate->username) >= MAX_TEXT) { /* XXX - other invalid names? */ + strlen(msg->payload.authenticate->username) >= MAX_USERNAME) { /* XXX - other invalid names? */ char buf[64]; sprintf(buf, "Invalid username"); Log_debug("Invalid username"); @@ -240,7 +241,7 @@ void Mh_handle_message(client_t *client, message_t *msg) sendmsg->payload.userState->name = strdup(client->username); sendmsg->payload.userState->has_channel_id = true; sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id; - + Client_send_message_except(client, sendmsg); client_itr = NULL; @@ -263,6 +264,10 @@ void Mh_handle_message(client_t *client, message_t *msg) sendmsg->payload.userState->has_self_mute = true; sendmsg->payload.userState->self_mute = true; } + if (client_itr->recording) { + sendmsg->payload.userState->has_recording = true; + sendmsg->payload.userState->recording = true; + } Client_send_message(client, sendmsg); } @@ -373,6 +378,30 @@ void Mh_handle_message(client_t *client, message_t *msg) client->deaf = false; } } + if (msg->payload.userState->has_recording && + msg->payload.userState->recording != client->recording) { + client->recording = msg->payload.userState->recording; + char *message; + uint32_t *tree_id; + + message = malloc(strlen(client->username) + 32); + if (!message) + Log_fatal("Out of memory"); + tree_id = malloc(sizeof(uint32_t)); + if (!tree_id) + Log_fatal("Out of memory"); + *tree_id = 0; + sendmsg = Msg_create(TextMessage); + sendmsg->payload.textMessage->message = message; + sendmsg->payload.textMessage->n_tree_id = 1; + sendmsg->payload.textMessage->tree_id = tree_id; + if (client->recording) + sprintf(message, "User %s started recording", client->username); + else + sprintf(message, "User %s stopped recording", client->username); + Client_send_message_except_ver(NULL, sendmsg, ~0x010203); + sendmsg = NULL; + } if (msg->payload.userState->has_channel_id) { int leave_id; if (!Chan_userJoin_id_test(msg->payload.userState->channel_id)) @@ -395,7 +424,6 @@ void Mh_handle_message(client_t *client, message_t *msg) break; /* Don't inform other users about this state */ } - /* Re-use message */ Msg_inc_ref(msg); diff --git a/src/messages.c b/src/messages.c index 5a61082..38d4ea9 100644 --- a/src/messages.c +++ b/src/messages.c @@ -436,6 +436,14 @@ void Msg_free(message_t *msg) if (msg->unpacked) mumble_proto__text_message__free_unpacked(msg->payload.textMessage, NULL); else { + if (msg->payload.textMessage->message) + free(msg->payload.textMessage->message); + if (msg->payload.textMessage->session) + free(msg->payload.textMessage->session); + if (msg->payload.textMessage->channel_id) + free(msg->payload.textMessage->channel_id); + if (msg->payload.textMessage->tree_id) + free(msg->payload.textMessage->tree_id); free(msg->payload.textMessage); } break; -- 2.30.2 From b026c5ad0acc4388d05fa4768b75ee8d79403ea4 Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Sat, 18 Dec 2010 21:29:22 +0000 Subject: [PATCH 03/16] libconfig.h moved to include/ in OpenWRT, so no fix is required anymore. --- src/conf.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/conf.c b/src/conf.c index 4d82e2f..a66d9ee 100644 --- a/src/conf.c +++ b/src/conf.c @@ -32,11 +32,7 @@ #include #include -#ifdef WRT_TARGET -#include -#else #include -#endif #include "types.h" #include "conf.h" -- 2.30.2 From 877434b8b0295725e2a4f8fffd139ee0985da8a3 Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Sat, 18 Dec 2010 21:31:01 +0000 Subject: [PATCH 04/16] CELT default version/bitstream version updated. --- src/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.c b/src/client.c index 35ab266..367f18d 100644 --- a/src/client.c +++ b/src/client.c @@ -200,7 +200,7 @@ void recheckCodecVersions() // it as alpha and announce it. If another codec now got the // majority set it as the opposite of the currently valid bPreferAlpha // and announce it. - if (version == (uint32_t)0x8000000a) + if (version == (uint32_t)0x8000000b) bPreferAlpha = true; else bPreferAlpha = ! bPreferAlpha; -- 2.30.2 From 1c9b1f27ae2c73853f1c493885315506923a04be Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Tue, 21 Dec 2010 21:13:43 +0000 Subject: [PATCH 05/16] Patch by J Sisson: Conditionally compile with scheduler setting support if target supports it. --- src/main.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index d1351dd..8c5febd 100644 --- a/src/main.c +++ b/src/main.c @@ -37,11 +37,12 @@ #include #include #include -#include #include #include #include - +#ifdef _POSIX_PRIORITY_SCHEDULING +#include +#endif #include "server.h" #include "ssl.h" #include "channel.h" @@ -111,6 +112,7 @@ void daemonize() } +#ifdef _POSIX_PRIORITY_SCHEDULING void setscheduler() { int rc; @@ -122,6 +124,7 @@ void setscheduler() if (rc < 0) Log_warn("Failed to set scheduler: %s", strerror(errno)); } +#endif void printhelp() { @@ -130,7 +133,9 @@ void printhelp() printf(" -d - Do not deamonize\n"); printf(" -p - Write PID to this file\n"); printf(" -c - Specify configuration file\n"); +#ifdef _POSIX_PRIORITY_SCHEDULING printf(" -r - Run with realtime priority\n"); +#endif printf(" -a
- Bind to IP address\n"); printf(" -b - Bind to port\n"); printf(" -h - Print this help\n"); @@ -140,13 +145,19 @@ void printhelp() int main(int argc, char **argv) { bool_t nodaemon = false; +#ifdef _POSIX_PRIORITY_SCHEDULING bool_t realtime = false; +#endif char *conffile = NULL, *pidfile = NULL; int c; struct utsname utsbuf; /* Arguments */ +#ifdef _POSIX_PRIORITY_SCHEDULING while ((c = getopt(argc, argv, "drp:c:a:b:h")) != EOF) { +#else + while ((c = getopt(argc, argv, "dp:c:a:b:h")) != EOF) { +#endif switch(c) { case 'c': conffile = optarg; @@ -166,9 +177,11 @@ int main(int argc, char **argv) case 'h': printhelp(); break; +#ifdef _POSIX_PRIORITY_SCHEDULING case 'r': realtime = true; break; +#endif default: fprintf(stderr, "Unrecognized option\n"); printhelp(); @@ -213,8 +226,10 @@ int main(int argc, char **argv) Chan_init(); Client_init(); +#ifdef _POSIX_PRIORITY_SCHEDULING if (realtime) setscheduler(); +#endif Server_run(); -- 2.30.2 From 9bf7a133fd2e6500976bdd7c8a8bc830f54c5c13 Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Sat, 1 Jan 2011 20:00:24 +0000 Subject: [PATCH 06/16] Patch by J Sisson: sprintf -> snprintf --- src/conf.c | 30 ++++++++++++++++-------------- src/main.c | 2 +- src/messagehandler.c | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/conf.c b/src/conf.c index a66d9ee..d85ff7c 100644 --- a/src/conf.c +++ b/src/conf.c @@ -186,30 +186,31 @@ int getIntConf(param_t param) int Conf_getNextChannel(conf_channel_t *chdesc, int index) { config_setting_t *setting = NULL; - char configstr[64]; + int maxconfig = 64, ret = 0; + char configstr[maxconfig]; - sprintf(configstr, "channels.[%d].name", index); + ret = snprintf(configstr, maxconfig, "channels.[%d].name", index); setting = config_lookup(&configuration, configstr); - if (setting == NULL) + if (ret >= maxconfig || ret < 0 || setting == NULL) return -1; /* Required */ chdesc->name = config_setting_get_string(setting); - sprintf(configstr, "channels.[%d].parent", index); + ret = snprintf(configstr, maxconfig, "channels.[%d].parent", index); setting = config_lookup(&configuration, configstr); - if (setting == NULL) + if (ret >= maxconfig || ret < 0 || setting == NULL) return -1; /* Required */ chdesc->parent = config_setting_get_string(setting); - sprintf(configstr, "channels.[%d].description", index); + ret = snprintf(configstr, maxconfig, "channels.[%d].description", index); setting = config_lookup(&configuration, configstr); - if (setting == NULL) /* Optional */ + if (ret >= maxconfig || ret < 0 || setting == NULL) /* Optional */ chdesc->description = NULL; else chdesc->description = config_setting_get_string(setting); - sprintf(configstr, "channels.[%d].noenter", index); + ret = snprintf(configstr, maxconfig, "channels.[%d].noenter", index); setting = config_lookup(&configuration, configstr); - if (setting == NULL) /* Optional */ + if (ret >= maxconfig || ret < 0 || setting == NULL) /* Optional */ chdesc->noenter = false; else chdesc->noenter = config_setting_get_bool(setting); @@ -220,17 +221,18 @@ int Conf_getNextChannel(conf_channel_t *chdesc, int index) int Conf_getNextChannelLink(conf_channel_link_t *chlink, int index) { config_setting_t *setting = NULL; - char configstr[64]; + int maxconfig = 64, ret = 0; + char configstr[maxconfig]; - sprintf(configstr, "channel_links.[%d].source", index); + ret = snprintf(configstr, maxconfig, "channel_links.[%d].source", index); setting = config_lookup(&configuration, configstr); - if (setting == NULL) + if (ret >= maxconfig || ret < 0 || setting == NULL) return -1; chlink->source = config_setting_get_string(setting); - sprintf(configstr, "channel_links.[%d].destination", index); + ret = snprintf(configstr, maxconfig, "channel_links.[%d].destination", index); setting = config_lookup(&configuration, configstr); - if (setting == NULL) + if (ret >= maxconfig || ret < 0 || setting == NULL) return -1; chlink->destination = config_setting_get_string(setting); diff --git a/src/main.c b/src/main.c index 8c5febd..863a7d4 100644 --- a/src/main.c +++ b/src/main.c @@ -64,7 +64,7 @@ void lockfile(const char *pidfile) if (lfp < 0) Log_fatal("Cannot open PID-file %s for writing", pidfile); - sprintf(str,"%d\n", getpid()); + snprintf(str,16,"%d\n", getpid()); write(lfp, str, strlen(str)); /* record pid to lockfile */ Log_info("PID-file: %s", pidfile); } diff --git a/src/messagehandler.c b/src/messagehandler.c index c2aa522..4b6c396 100644 --- a/src/messagehandler.c +++ b/src/messagehandler.c @@ -140,7 +140,7 @@ void Mh_handle_message(client_t *client, message_t *msg) if (Client_count() >= getIntConf(MAX_CLIENTS)) { char buf[64]; - sprintf(buf, "Server is full (max %d users)", getIntConf(MAX_CLIENTS)); + snprintf(buf, 64, "Server is full (max %d users)", getIntConf(MAX_CLIENTS)); sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__ServerFull); goto disconnect; } -- 2.30.2 From 0cd54c5f6e11a98a0f0a5e44fd88e4e7826fa12d Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Sat, 8 Jan 2011 21:45:31 +0000 Subject: [PATCH 07/16] Fix issue 11: Typo --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 863a7d4..70358e6 100644 --- a/src/main.c +++ b/src/main.c @@ -130,7 +130,7 @@ void printhelp() { printf("uMurmur version %s. Mumble protocol %d.%d.%d\n", UMURMUR_VERSION, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH); printf("Usage: umurmurd [-d] [-p ] [-c ] [-h]\n"); - printf(" -d - Do not deamonize\n"); + printf(" -d - Do not daemonize\n"); printf(" -p - Write PID to this file\n"); printf(" -c - Specify configuration file\n"); #ifdef _POSIX_PRIORITY_SCHEDULING -- 2.30.2 From 57ed6bb65460216b63238e4b1fe28312a39eb132 Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Thu, 20 Jan 2011 08:24:21 +0000 Subject: [PATCH 08/16] Patch from tilman2: Open PID file with O_EXCL --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 70358e6..1b92f50 100644 --- a/src/main.c +++ b/src/main.c @@ -60,7 +60,7 @@ void lockfile(const char *pidfile) int lfp; char str[16]; - lfp = open(pidfile, O_RDWR|O_CREAT, 0640); + lfp = open(pidfile, O_RDWR|O_CREAT|O_EXCL, 0640); if (lfp < 0) Log_fatal("Cannot open PID-file %s for writing", pidfile); -- 2.30.2 From 63c7b082aa8fd8f7323e25fa1337cc8de5c2d8d6 Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Thu, 20 Jan 2011 08:25:34 +0000 Subject: [PATCH 09/16] Patch from tilman2: Close PID-file --- src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.c b/src/main.c index 1b92f50..8a0573a 100644 --- a/src/main.c +++ b/src/main.c @@ -66,6 +66,7 @@ void lockfile(const char *pidfile) Log_fatal("Cannot open PID-file %s for writing", pidfile); snprintf(str,16,"%d\n", getpid()); write(lfp, str, strlen(str)); /* record pid to lockfile */ + close(lfp); Log_info("PID-file: %s", pidfile); } -- 2.30.2 From 3fbab274e9932e10d257e70fad310e00a4260d43 Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Thu, 20 Jan 2011 08:34:19 +0000 Subject: [PATCH 10/16] Patch from tilman2: Don't print null config file name --- src/conf.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/conf.c b/src/conf.c index d85ff7c..185e508 100644 --- a/src/conf.c +++ b/src/conf.c @@ -50,14 +50,10 @@ const char defaultconfig[] = DEFAULT_CONFIG; int Conf_init(const char *conffile) { - const char *conf; - config_init(&configuration); if (conffile == NULL) - conf = defaultconfig; - else - conf = conffile; - if (config_read_file(&configuration, conf) != CONFIG_TRUE) { + conffile = defaultconfig; + if (config_read_file(&configuration, conffile) != CONFIG_TRUE) { fprintf(stderr, "Error in config file %s: %s at line %d\n", conffile, config_error_text(&configuration), config_error_line(&configuration)); exit(1); -- 2.30.2 From 0fd109448ce43a6a53866614423463788c278ff6 Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Thu, 20 Jan 2011 08:45:18 +0000 Subject: [PATCH 11/16] Make configuration file errors print the error via standard logging function. Clean up interface. --- src/conf.c | 8 +++----- src/conf.h | 2 +- src/main.c | 9 +++------ 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/conf.c b/src/conf.c index 185e508..72fd8f1 100644 --- a/src/conf.c +++ b/src/conf.c @@ -48,17 +48,15 @@ static config_t configuration; const char defaultconfig[] = DEFAULT_CONFIG; -int Conf_init(const char *conffile) +void Conf_init(const char *conffile) { config_init(&configuration); if (conffile == NULL) conffile = defaultconfig; if (config_read_file(&configuration, conffile) != CONFIG_TRUE) { - fprintf(stderr, "Error in config file %s: %s at line %d\n", conffile, - config_error_text(&configuration), config_error_line(&configuration)); - exit(1); + Log_fatal("Error in config file %s line %d: %s", conffile, + config_error_line(&configuration), config_error_text(&configuration)); } - return 0; } void Conf_deinit() diff --git a/src/conf.h b/src/conf.h index 7967716..1b9b21e 100644 --- a/src/conf.h +++ b/src/conf.h @@ -57,7 +57,7 @@ typedef struct { const char *destination; } conf_channel_link_t; -int Conf_init(const char *conffile); +void Conf_init(const char *conffile); void Conf_deinit(); const char *getStrConf(param_t param); diff --git a/src/main.c b/src/main.c index 8a0573a..7bd8a0b 100644 --- a/src/main.c +++ b/src/main.c @@ -190,11 +190,6 @@ int main(int argc, char **argv) } } - if (Conf_init(conffile) != 0) { - fprintf(stderr, "Configuration error\n"); - exit(1); - } - if (!nodaemon) { Log_init(false); daemonize(); @@ -203,7 +198,9 @@ int main(int argc, char **argv) } else Log_init(true); - + + Conf_init(conffile); + signal(SIGCHLD, SIG_IGN); /* ignore child */ signal(SIGTSTP, SIG_IGN); /* ignore tty signals */ signal(SIGTTOU, SIG_IGN); -- 2.30.2 From 454ad122eb158b4391e2690fe6a7e127d24c525b Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Sun, 23 Jan 2011 11:58:12 +0000 Subject: [PATCH 12/16] Issue 15 - Patch by tilman2: Drop privileges optionally --- src/conf.c | 22 +++++++++++++ src/conf.h | 2 ++ src/main.c | 75 +++++++++++++++++++++++++++++++++++++++++--- umurmur.conf.example | 2 ++ 4 files changed, 96 insertions(+), 5 deletions(-) diff --git a/src/conf.c b/src/conf.c index 72fd8f1..3592647 100644 --- a/src/conf.c +++ b/src/conf.c @@ -136,6 +136,28 @@ const char *getStrConf(param_t param) return ""; } break; + case USERNAME: + setting = config_lookup(&configuration, "username"); + if (!setting) + return ""; + else { + if ((strsetting = config_setting_get_string(setting)) != NULL) + return strsetting; + else + return ""; + } + break; + case GROUPNAME: + setting = config_lookup(&configuration, "groupname"); + if (!setting) + return ""; + else { + if ((strsetting = config_setting_get_string(setting)) != NULL) + return strsetting; + else + return ""; + } + break; default: doAssert(false); break; diff --git a/src/conf.h b/src/conf.h index 1b9b21e..6e0a666 100644 --- a/src/conf.h +++ b/src/conf.h @@ -43,6 +43,8 @@ typedef enum param { MAX_BANDWIDTH, MAX_CLIENTS, DEFAULT_CHANNEL, + USERNAME, + GROUPNAME, } param_t; typedef struct { diff --git a/src/main.c b/src/main.c index 7bd8a0b..36c5f88 100644 --- a/src/main.c +++ b/src/main.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include #include @@ -70,6 +72,59 @@ void lockfile(const char *pidfile) Log_info("PID-file: %s", pidfile); } +/* Drops privileges (if configured to do so). */ +static void switch_user(void) +{ + struct passwd *pwd; + struct group *grp = NULL; + const char *username, *groupname; + gid_t gid; + + username = getStrConf(USERNAME); + groupname = getStrConf(GROUPNAME); + + if (!*username) { + /* It's an error to specify groupname + * but leave username empty. + */ + if (*groupname) + Log_fatal("username missing"); + + /* Nothing to do. */ + return; + } + + pwd = getpwnam(username); + if (!pwd) + Log_fatal("Unknown user '%s'", username); + + if (!*groupname) + gid = pwd->pw_gid; + else { + grp = getgrnam(groupname); + + if (!grp) + Log_fatal("Unknown group '%s'", groupname); + + gid = grp->gr_gid; + } + + if (initgroups(pwd->pw_name, gid)) + Log_fatal("initgroups() failed: %s", strerror(errno)); + + if (setgid(gid)) + Log_fatal("setgid() failed: %s", strerror(errno)); + + if (setuid(pwd->pw_uid)) + Log_fatal("setuid() failed: %s", strerror(errno)); + + if (!grp) + grp = getgrgid(gid); + if (!grp) + Log_fatal("getgrgid() failed: %s", strerror(errno)); + + Log_info("Switch to user '%s' group '%s'", pwd->pw_name, grp->gr_name); +} void signal_handler(int sig) { @@ -189,18 +244,28 @@ int main(int argc, char **argv) break; } } + + /* Logging to terminal if not daemonizing, otherwise to syslog. + * Need to initialize logging before calling Conf_init() + */ + if (!nodaemon) + Log_init(false); + else + Log_init(true); + /* Initialize the config subsystem early; + * switch_user() will need to read some config variables. + */ + Conf_init(conffile); + if (!nodaemon) { - Log_init(false); daemonize(); if (pidfile != NULL) lockfile(pidfile); + + switch_user(); } - else - Log_init(true); - Conf_init(conffile); - signal(SIGCHLD, SIG_IGN); /* ignore child */ signal(SIGTSTP, SIG_IGN); /* ignore tty signals */ signal(SIGTTOU, SIG_IGN); diff --git a/umurmur.conf.example b/umurmur.conf.example index 47c0dea..09b49c5 100644 --- a/umurmur.conf.example +++ b/umurmur.conf.example @@ -4,6 +4,8 @@ certificate = "/etc/umurmur/cert.crt"; private_key = "/etc/umurmur/key.key"; password = ""; max_users = 10; +username = ""; +groupname = ""; # Root channel must always be defined first. # If a channel has a parent, the parent must be defined before the child channel(s). -- 2.30.2 From 6014b0c3e4de295fb88dc71f779abe8bf7a5553b Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Sun, 23 Jan 2011 12:02:54 +0000 Subject: [PATCH 13/16] Issue 16 - patch by tilman2: No need to end syslog message with \n --- src/log.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/log.c b/src/log.c index 94f86a8..9392884 100644 --- a/src/log.c +++ b/src/log.c @@ -58,14 +58,13 @@ void Log_free() void logthis(const char *logstring, ...) { va_list argp; - char buf[STRSIZE + 2]; + char buf[STRSIZE + 1]; va_start(argp, logstring); vsnprintf(&buf[0], STRSIZE, logstring, argp); va_end(argp); - strcat(buf, "\n"); if (termprint) - fprintf(stderr, "%s", buf); + fprintf(stderr, "%s\n", buf); else syslog(LOG_INFO, buf); } @@ -73,16 +72,15 @@ void logthis(const char *logstring, ...) void Log_warn(const char *logstring, ...) { va_list argp; - char buf[STRSIZE + 2]; + char buf[STRSIZE + 1]; int offset = 0; va_start(argp, logstring); offset = sprintf(buf, "WARN: "); vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp); va_end(argp); - strcat(buf, "\n"); if (termprint) - fprintf(stderr, "%s", buf); + fprintf(stderr, "%s\n", buf); else syslog(LOG_WARNING, buf); } @@ -90,23 +88,22 @@ void Log_warn(const char *logstring, ...) void Log_info(const char *logstring, ...) { va_list argp; - char buf[STRSIZE + 2]; + char buf[STRSIZE + 1]; int offset = 0; va_start(argp, logstring); offset = sprintf(buf, "INFO: "); vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp); va_end(argp); - strcat(buf, "\n"); if (termprint) - fprintf(stderr, "%s", buf); + fprintf(stderr, "%s\n", buf); else syslog(LOG_INFO, buf); } void Log_info_client(client_t *client, const char *logstring, ...) { va_list argp; - char buf[STRSIZE + 2]; + char buf[STRSIZE + 1]; int offset = 0; va_start(argp, logstring); @@ -118,9 +115,8 @@ void Log_info_client(client_t *client, const char *logstring, ...) client->username == NULL ? "" : client->username, inet_ntoa(client->remote_tcp.sin_addr), ntohs(client->remote_tcp.sin_port)); - strcat(buf, "\n"); if (termprint) - fprintf(stderr, "%s", buf); + fprintf(stderr, "%s\n", buf); else syslog(LOG_INFO, buf); @@ -130,16 +126,15 @@ void Log_info_client(client_t *client, const char *logstring, ...) void Log_debug(const char *logstring, ...) { va_list argp; - char buf[STRSIZE + 2]; + char buf[STRSIZE + 1]; int offset = 0; va_start(argp, logstring); offset = sprintf(buf, "DEBUG: "); vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp); va_end(argp); - strcat(buf, "\n"); if (termprint) - fprintf(stderr, "%s", buf); + fprintf(stderr, "%s\n", buf); else syslog(LOG_DEBUG, buf); } @@ -148,15 +143,14 @@ void Log_debug(const char *logstring, ...) void Log_fatal(const char *logstring, ...) { va_list argp; - char buf[STRSIZE + 2]; + char buf[STRSIZE + 1]; int offset = 0; va_start(argp, logstring); offset = sprintf(buf, "FATAL: "); vsnprintf(&buf[offset], STRSIZE - offset, logstring, argp); va_end(argp); - strcat(buf, "\n"); if (termprint) - fprintf(stderr, "%s", buf); + fprintf(stderr, "%s\n", buf); else syslog(LOG_CRIT, buf); exit(1); -- 2.30.2 From a8ca900b2e60cc837c5e9529d7a9c778ff30c955 Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Sun, 23 Jan 2011 12:05:52 +0000 Subject: [PATCH 14/16] Issue 17 - patch by tilman2: Always pass a format string to syslog() --- src/log.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/log.c b/src/log.c index 9392884..5d2af2b 100644 --- a/src/log.c +++ b/src/log.c @@ -66,7 +66,7 @@ void logthis(const char *logstring, ...) if (termprint) fprintf(stderr, "%s\n", buf); else - syslog(LOG_INFO, buf); + syslog(LOG_INFO, "%s", buf); } void Log_warn(const char *logstring, ...) @@ -82,7 +82,7 @@ void Log_warn(const char *logstring, ...) if (termprint) fprintf(stderr, "%s\n", buf); else - syslog(LOG_WARNING, buf); + syslog(LOG_WARNING, "%s", buf); } void Log_info(const char *logstring, ...) @@ -98,7 +98,7 @@ void Log_info(const char *logstring, ...) if (termprint) fprintf(stderr, "%s\n", buf); else - syslog(LOG_INFO, buf); + syslog(LOG_INFO, "%s", buf); } void Log_info_client(client_t *client, const char *logstring, ...) { @@ -118,7 +118,7 @@ void Log_info_client(client_t *client, const char *logstring, ...) if (termprint) fprintf(stderr, "%s\n", buf); else - syslog(LOG_INFO, buf); + syslog(LOG_INFO, "%s", buf); } @@ -136,7 +136,7 @@ void Log_debug(const char *logstring, ...) if (termprint) fprintf(stderr, "%s\n", buf); else - syslog(LOG_DEBUG, buf); + syslog(LOG_DEBUG, "%s", buf); } #endif @@ -152,6 +152,6 @@ void Log_fatal(const char *logstring, ...) if (termprint) fprintf(stderr, "%s\n", buf); else - syslog(LOG_CRIT, buf); + syslog(LOG_CRIT, "%s", buf); exit(1); } -- 2.30.2 From ed9b54bd89b704e6111acbd91b6a7b50e3c30cf5 Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Sun, 23 Jan 2011 20:28:42 +0000 Subject: [PATCH 15/16] Issue 19 - patch by tilman2: Fix PID-file support again --- src/main.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/main.c b/src/main.c index 36c5f88..cef4f60 100644 --- a/src/main.c +++ b/src/main.c @@ -59,17 +59,50 @@ char *bindaddr; void lockfile(const char *pidfile) { - int lfp; + int lfp, flags; char str[16]; - - lfp = open(pidfile, O_RDWR|O_CREAT|O_EXCL, 0640); + + /* Don't use O_TRUNC here -- we want to leave the PID file + * unmodified if we cannot lock it. + */ + lfp = open(pidfile, O_WRONLY|O_CREAT, 0640); if (lfp < 0) Log_fatal("Cannot open PID-file %s for writing", pidfile); + + /* Try to lock the file. */ + if (lockf(lfp, F_TLOCK, 0) < 0) { + close(lfp); + + if (errno == EACCES || errno == EAGAIN) + Log_fatal("PID file is locked -- uMurmur already running?"); + + Log_fatal("Cannot lock PID file: %s", strerror(errno)); + } + + /* Now that we locked the file, erase its contents. */ + if (ftruncate(lfp, 0) < 0) { + close(lfp); + Log_fatal("Cannot truncate PID file: %s", strerror(errno)); + } + snprintf(str,16,"%d\n", getpid()); write(lfp, str, strlen(str)); /* record pid to lockfile */ - close(lfp); Log_info("PID-file: %s", pidfile); + + /* If uMurmur ever starts to fork()+exec(), we don't want it to + * leak the fd to the forked process though. Set the close-on-exec + * flag to prevent leakage. + */ + flags = fcntl(lfp, F_GETFD, 0); + flags |= FD_CLOEXEC; + fcntl(lfp, F_SETFD, (long) flags); + + /* Don't close(lfp) here! + * We want the fd to remain opened so the lock is held until the + * process exits. + */ + lfp = -1; } /* Drops privileges (if configured to do so). */ -- 2.30.2 From 3a9d9e4e2ec7ad528d50d920161aea272c01d35d Mon Sep 17 00:00:00 2001 From: fatbob313 Date: Tue, 8 Feb 2011 22:06:05 +0000 Subject: [PATCH 16/16] Add new parameters with some comments --- openwrt/files/umurmur.conf | 7 +++++++ umurmur.conf.example | 11 +++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/openwrt/files/umurmur.conf b/openwrt/files/umurmur.conf index 47c0dea..826746b 100644 --- a/openwrt/files/umurmur.conf +++ b/openwrt/files/umurmur.conf @@ -5,6 +5,13 @@ private_key = "/etc/umurmur/key.key"; password = ""; max_users = 10; +# Username and groupname for privilege dropping +# username = ""; +# groupname = ""; + +# bindaddr = "192.168.1.1"; +# bindport = 64738; + # Root channel must always be defined first. # If a channel has a parent, the parent must be defined before the child channel(s). channels = ( { diff --git a/umurmur.conf.example b/umurmur.conf.example index 09b49c5..fad2b80 100644 --- a/umurmur.conf.example +++ b/umurmur.conf.example @@ -4,8 +4,15 @@ certificate = "/etc/umurmur/cert.crt"; private_key = "/etc/umurmur/key.key"; password = ""; max_users = 10; -username = ""; -groupname = ""; + +# username and groupname for privilege dropping. +# Will attempt to switch user if set. +# username = ""; +# If groupname not set the user's default login group will be used +# groupname = ""; + +# bindport = 64738; +# bindaddr = "192.168.1.1"; # Root channel must always be defined first. # If a channel has a parent, the parent must be defined before the child channel(s). -- 2.30.2