From 977a33f0978bec21b3c12a8c04a40bf56afe7334 Mon Sep 17 00:00:00 2001 From: Martin Johansson Date: Fri, 7 Oct 2011 08:09:04 -0400 Subject: [PATCH] Add support for channel passwords. --- src/channel.c | 20 +++++++++++------- src/channel.h | 10 ++++++++- src/client.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ src/client.h | 9 +++++++++ src/messagehandler.c | 44 ++++++++++++++++++++++++++++++++++++---- 5 files changed, 119 insertions(+), 12 deletions(-) diff --git a/src/channel.c b/src/channel.c index 4609e4c..22d909f 100644 --- a/src/channel.c +++ b/src/channel.c @@ -161,7 +161,8 @@ void Chan_init() channel_t *ch, *ch_itr = NULL; ch = Chan_createChannel(chdesc.name, chdesc.description); ch->noenter = chdesc.noenter; - + if (chdesc.password) + ch->password = strdup(chdesc.password); if (strcmp(defaultChannelName, chdesc.name) == 0) { Log_info("Setting default channel %s", ch->name); defaultChan = ch; @@ -184,6 +185,8 @@ void Chan_init() if (defaultChan->noenter) Log_fatal("Error in channel configuration: default channel is marked as noenter"); + if (defaultChan->password) + Log_fatal("Error in channel configuration: default channel has a password"); /* Channel links */ for (i = 0; ; i++) { @@ -230,6 +233,8 @@ void Chan_free() free(ch->name); if (ch->desc) free(ch->desc); + if (ch->password) + free(ch->password); free(ch); } } @@ -303,7 +308,7 @@ int Chan_userJoin_id(int channelid, client_t *client) return Chan_userJoin(ch_itr, client); } -bool_t Chan_userJoin_id_test(int channelid) +channelJoinResult_t Chan_userJoin_id_test(int channelid, client_t *client) { channel_t *ch_itr = NULL; do { @@ -311,12 +316,13 @@ bool_t Chan_userJoin_id_test(int channelid) } while (ch_itr != NULL && ch_itr->id != channelid); if (ch_itr == NULL) { Log_warn("Channel id %d not found - ignoring.", channelid); - return false; + return CHJOIN_NOTFOUND; } - if (ch_itr->noenter) - return false; - else - return true; + else if (ch_itr->noenter) + return CHJOIN_NOENTER; + else if (ch_itr->password && !Client_token_match(client, ch_itr->password)) + return CHJOIN_WRONGPW; + else return CHJOIN_OK; } #if 0 diff --git a/src/channel.h b/src/channel.h index 887baa0..7c4a299 100644 --- a/src/channel.h +++ b/src/channel.h @@ -39,6 +39,7 @@ typedef struct channel { int id; char *name; char *desc; + char *password; struct channel *parent; bool_t temporary, noenter; struct dlist node; @@ -55,6 +56,13 @@ typedef struct { struct dlist node; } channellist_t; +typedef enum { + CHJOIN_OK, + CHJOIN_NOENTER, + CHJOIN_WRONGPW, + CHJOIN_NOTFOUND, +} channelJoinResult_t; + void Chan_init(); void Chan_free(); void Chan_addChannel(channel_t *parent, channel_t *sub); @@ -64,7 +72,7 @@ void Chan_removeClient(channel_t *c, client_t *client); int Chan_userJoin(channel_t *ch, client_t *client); int Chan_userJoin_id(int channelid, client_t *client); int Chan_userLeave(client_t *client); -bool_t Chan_userJoin_id_test(int channelid); +channelJoinResult_t Chan_userJoin_id_test(int channelid, client_t *client); channel_t *Chan_iterate(channel_t **channelpptr); channel_t *Chan_iterate_siblings(channel_t *parent, channel_t **channelpptr); channel_t *Chan_createChannel(const char *name, const char *desc); diff --git a/src/client.c b/src/client.c index 2ad53ba..e4936e2 100644 --- a/src/client.c +++ b/src/client.c @@ -146,6 +146,52 @@ codec_t *Client_codec_iterate(client_t *client, codec_t **codec_itr) return cd; } +void Client_token_add(client_t *client, char *token_string) +{ + token_t *token; + + if (client->tokencount >= MAX_TOKENS) + return; + token = malloc(sizeof(token_t)); + if (token == NULL) + Log_fatal("Out of memory"); + init_list_entry(&token->node); + token->token = strdup(token_string); + if (token->token == NULL) + Log_fatal("Out of memory"); + list_add_tail(&token->node, &client->tokens); + client->tokencount++; +} + +bool_t Client_token_match(client_t *client, char *str) +{ + token_t *token; + struct dlist *itr; + + if (list_empty(&client->tokens)) + return false; + list_iterate(itr, &client->tokens) { + token = list_get_entry(itr, token_t, node); + if (strncasecmp(token->token, str, MAX_TOKENSIZE) == 0) + return true; + } + return false; +} + +void Client_token_free(client_t *client) +{ + struct dlist *itr, *save; + token_t *token; + + list_iterate_safe(itr, save, &client->tokens) { + token = list_get_entry(itr, token_t, node); + list_del(&token->node); + free(token->token); + free(token); + } + client->tokencount = 0; +} + void recheckCodecVersions() { client_t *client_itr = NULL; @@ -270,6 +316,7 @@ int Client_add(int fd, struct sockaddr_in *remote) init_list_entry(&newclient->node); init_list_entry(&newclient->voicetargets); init_list_entry(&newclient->codecs); + init_list_entry(&newclient->tokens); list_add_tail(&newclient->node, &clients); clientcount++; @@ -309,6 +356,7 @@ void Client_free(client_t *client) } Client_codec_free(client); Voicetarget_free_all(client); + Client_token_free(client); list_del(&client->node); if (client->ssl) diff --git a/src/client.h b/src/client.h index 608c87c..0e5e135 100644 --- a/src/client.h +++ b/src/client.h @@ -53,6 +53,8 @@ #define UDP_BUFSIZE 512 #define INACTICITY_TIMEOUT 15 /* Seconds */ #define MAX_CODECS 10 +#define MAX_TOKENSIZE 64 +#define MAX_TOKENS 32 #define IS_AUTH(_a_) ((_a_)->authenticated) @@ -85,6 +87,8 @@ typedef struct { char *context; struct dlist chan_node; struct dlist voicetargets; + struct dlist tokens; + int tokencount; float UDPPingAvg, UDPPingVar, TCPPingAvg, TCPPingVar; uint32_t UDPPackets, TCPPackets; } client_t; @@ -94,6 +98,11 @@ typedef struct { struct dlist node; } codec_t; +typedef struct { + char *token; + struct dlist node; +} token_t; + void Client_init(); int Client_getfds(struct pollfd *pollfds); void Client_janitor(); diff --git a/src/messagehandler.c b/src/messagehandler.c index b0248d0..c271b78 100644 --- a/src/messagehandler.c +++ b/src/messagehandler.c @@ -68,6 +68,27 @@ static void sendPermissionDenied(client_t *client, const char *reason) Client_send_message(client, msg); } +static void addTokens(client_t *client, message_t *msg) +{ + int i; + if (client->tokencount + msg->payload.authenticate->n_tokens < MAX_TOKENS) { + /* Check lengths first */ + for (i = 0; i < msg->payload.authenticate->n_tokens; i++) { + if (strlen(msg->payload.authenticate->tokens[i]) > MAX_TOKENSIZE - 1) { + sendPermissionDenied(client, "Too long token"); + return; + } + } + + for (i = 0; i < msg->payload.authenticate->n_tokens; i++) { + Log_debug("Adding token '%s' to client '%s'", msg->payload.authenticate->tokens[i], client->username); + Client_token_add(client, msg->payload.authenticate->tokens[i]); + } + } + else + sendPermissionDenied(client, "Too many tokens"); +} + void Mh_handle_message(client_t *client, message_t *msg) { message_t *sendmsg = NULL; @@ -96,9 +117,12 @@ void Mh_handle_message(client_t *client, message_t *msg) Log_debug("Authenticate message received"); if (IS_AUTH(client) || !msg->payload.authenticate->username) { - /* Authenticate message might be sent when a token is set by the user.*/ + /* Authenticate message might be sent when a tokens are changed by the user.*/ + Client_token_free(client); /* Clear the token list */ if (msg->payload.authenticate->n_tokens > 0) { - Log_debug("Tokens in auth message from %s", client->username); + Log_debug("Tokens in auth message from '%s'. n_tokens = %d", client->username, + msg->payload.authenticate->n_tokens); + addTokens(client, msg); } break; } @@ -145,8 +169,13 @@ void Mh_handle_message(client_t *client, message_t *msg) goto disconnect; } - /* Name & password */ + /* Name */ client->username = strdup(msg->payload.authenticate->username); + + /* Tokens */ + if (msg->payload.authenticate->n_tokens > 0) + addTokens(client, msg); + /* Setup UDP encryption */ CryptState_init(&client->cryptState); @@ -404,8 +433,15 @@ void Mh_handle_message(client_t *client, message_t *msg) } if (msg->payload.userState->has_channel_id) { int leave_id; - if (!Chan_userJoin_id_test(msg->payload.userState->channel_id)) + channelJoinResult_t chjoin_rc = Chan_userJoin_id_test(msg->payload.userState->channel_id, client); + + if (chjoin_rc != CHJOIN_OK) { + if (chjoin_rc == CHJOIN_WRONGPW) { + sendPermissionDenied(client, "Wrong channel password"); + } break; + } + leave_id = Chan_userJoin_id(msg->payload.userState->channel_id, client); if (leave_id > 0) { Log_debug("Removing channel ID %d", leave_id); -- 2.30.2