Add support for channel passwords.
authorMartin Johansson <martin@fatbob.nu>
Fri, 7 Oct 2011 12:09:04 +0000 (08:09 -0400)
committerMartin Johansson <martin@fatbob.nu>
Fri, 7 Oct 2011 12:09:04 +0000 (08:09 -0400)
src/channel.c
src/channel.h
src/client.c
src/client.h
src/messagehandler.c

index 4609e4cb786a94fb47b22171396c0b23a203fa59..22d909f0e14efccdcfec7d13ac7f7df087be58c2 100644 (file)
@@ -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
index 887baa0a4bd6d0efd70942eb02cfbfb037bbf0f7..7c4a2995fe7d8226d7add8cec6cf3362ecfb6f5e 100644 (file)
@@ -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);
index 2ad53ba983273dbee7256d925a9b210829cb7826..e4936e2419ef15f6091ceaa6bddd73ab25e5e9d6 100644 (file)
@@ -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)
index 608c87c036f81d453f133ace43342af1ef3c3c0f..0e5e1353300fdb2e1fdd3e48fab9151f7b536b0c 100644 (file)
@@ -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();
index b0248d007547e9d6d2f57b1c732613c62227cdf7..c271b78b6dee8c4ccec45948173e7b4c43b7580a 100644 (file)
@@ -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);