From bbc2071bac65ded8d5bc07831d768de254c55842 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Mon, 25 Nov 2002 20:24:13 +0000 Subject: [PATCH] Support for SILC 1.2 INVITE and BAN commands. Client supports adding/deleting string entries, but not public key or other. Server supports both command fully. --- CHANGES | 21 +++ TODO | 18 +- apps/silcd/command.c | 366 +++++++++++++++++++++++------------- apps/silcd/idlist.c | 33 +++- apps/silcd/idlist.h | 4 +- apps/silcd/packet_receive.c | 121 +++++------- apps/silcd/packet_send.c | 14 +- apps/silcd/packet_send.h | 6 +- apps/silcd/server_util.c | 205 ++++++++++++++++++++ apps/silcd/server_util.h | 8 + lib/silcclient/command.c | 57 ++++-- 11 files changed, 614 insertions(+), 239 deletions(-) diff --git a/CHANGES b/CHANGES index 04711b05..ebdab9fa 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,24 @@ +Mon Nov 25 18:21:43 EET 2002 Pekka Riikonen + + * The silc_argument_get_[first/next] now return the argument + type to caller. Added silc_argument_payload_encode_one. + + Affected files are lib/silccore/silcargument.[ch]. + + * Added support for the SILC 1.2 INVITE command and new + invite lists to server. Affected files are silcd/command.c, + silcd/server_util.[ch] and silcd/packet_[receive/send].[ch]. + + * Added support for the SILC 1.2 BAN command and new + ban lists to server. Affected files are silcd/command.c, + silcd/server_util.[ch] and silcd/packet_[receive/send].[ch]. + + * Added support to client sending new INVITE command. Affected + file is lib/silcclient/command.c. + + * Added support to client sending new BAN command. Affected + file is lib/silcclient/command.c. + Sun Nov 24 18:26:42 EET 2002 Pekka Riikonen * If iv argument to silc_cipher_[encrypt/decrypt] is NULL, use diff --git a/TODO b/TODO index 2e639ffb..e597065a 100644 --- a/TODO +++ b/TODO @@ -1,13 +1,14 @@ TODO for Irssi SILC Client 1.0 ============================== - o bugs parsing nicknames with @ in NICK_CHANGE. + o Signed message payload handling on UI - o c0ffee's MIME signal + o Support to set arbitrary pulic key in CMODE - o SILC protocol version 1.2 integration + o INVITE/BAN by public key file and Client ID, new INVITE/BAN list handling + in command reply. - o Signed message payload handling + o bugs parsing nicknames with @ in NICK_CHANGE o Testing - See test plan: http://silcnet.org/docs/silc-client-1.0-test.pdf @@ -17,19 +18,10 @@ TODO for Irssi SILC Client 1.0 TODO for SILC Server 1.0 ======================== - o New INVITE and BAN commands and notify types. - o Remove client from invite lists in KICKED and KILLED. o 1.2 backup router support - o Backup router related issues: - - o Add special handling in router and server for "connection - timed out" error. Be optimistic. - - o SILC protocol version 1.2 integration - o Testing diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 1a144382..10c54657 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -1021,10 +1021,12 @@ SILC_SERVER_CMD_FUNC(invite) SilcChannelEntry channel; SilcChannelID *channel_id = NULL; SilcIDListData idata; - SilcBuffer idp, idp2, packet; - unsigned char *tmp, *add, *del; - SilcUInt32 len; - SilcUInt16 ident = silc_command_get_ident(cmd->payload); + SilcArgumentPayload args; + SilcHashTableList htl; + SilcBuffer packet, list, tmp2; + unsigned char *tmp; + SilcUInt32 len, type; + SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload); SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4); @@ -1078,7 +1080,6 @@ SILC_SERVER_CMD_FUNC(invite) /* Get destination client ID */ tmp = silc_argument_get_arg_type(cmd->args, 2, &len); if (tmp) { - char invite[512]; bool resolve; dest_id = silc_id_payload_parse_id(tmp, len, NULL); @@ -1128,32 +1129,34 @@ SILC_SERVER_CMD_FUNC(invite) goto out; } - memset(invite, 0, sizeof(invite)); - silc_strncat(invite, sizeof(invite), - dest->nickname, strlen(dest->nickname)); - silc_strncat(invite, sizeof(invite), "!", 1); - silc_strncat(invite, sizeof(invite), - dest->username, strlen(dest->username)); - if (!strchr(dest->username, '@')) { - silc_strncat(invite, sizeof(invite), "@", 1); - silc_strncat(invite, sizeof(invite), cmd->sock->hostname, - strlen(cmd->sock->hostname)); - } + /* Add the client to the invite list */ - len = strlen(invite); + /* Allocate hash table for invite list if it doesn't exist yet */ if (!channel->invite_list) - channel->invite_list = silc_calloc(len + 2, - sizeof(*channel->invite_list)); - else - channel->invite_list = silc_realloc(channel->invite_list, - sizeof(*channel->invite_list) * - (len + - strlen(channel->invite_list) + 2)); - strncat(channel->invite_list, invite, len); - strncat(channel->invite_list, ",", 1); + channel->invite_list = silc_hash_table_alloc(0, silc_hash_ptr, + NULL, NULL, NULL, + NULL, NULL, TRUE); + + /* Check if the ID is in the list already */ + silc_hash_table_list(channel->invite_list, &htl); + while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) { + if (type == 3 && !memcmp(tmp2->data, tmp, len)) { + tmp = NULL; + break; + } + } + silc_hash_table_list_reset(&htl); + + /* Add new Client ID to invite list */ + if (tmp) { + list = silc_buffer_alloc_size(len); + silc_buffer_put(list, tmp, len); + silc_hash_table_add(channel->invite_list, (void *)3, list); + } if (!(dest->mode & SILC_UMODE_BLOCK_INVITE)) { /* Send notify to the client that is invited to the channel */ + SilcBuffer idp, idp2; idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL); idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT); silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id, @@ -1168,65 +1171,83 @@ SILC_SERVER_CMD_FUNC(invite) } } - /* Add the client to the invite list of the channel */ - add = silc_argument_get_arg_type(cmd->args, 3, &len); - if (add) { - if (!channel->invite_list) - channel->invite_list = silc_calloc(len + 2, - sizeof(*channel->invite_list)); - else - channel->invite_list = silc_realloc(channel->invite_list, - sizeof(*channel->invite_list) * - (len + - strlen(channel->invite_list) + 2)); - if (add[len - 1] == ',') - add[len - 1] = '\0'; - - strncat(channel->invite_list, add, len); - strncat(channel->invite_list, ",", 1); - } - - /* Get the invite to be removed and remove it from the list */ - del = silc_argument_get_arg_type(cmd->args, 4, &len); - if (del && channel->invite_list) { - char *start, *end, *n; + /* Get the invite information */ + tmp = silc_argument_get_arg_type(cmd->args, 4, &len); + if (tmp) { + /* Parse the arguments to see they are constructed correctly */ + SILC_GET16_MSB(argc, tmp); + args = silc_argument_payload_parse(tmp + 2, len - 2, argc); + if (!args) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, + 0); + goto out; + } - if (!strncmp(channel->invite_list, del, - strlen(channel->invite_list) - 1)) { - silc_free(channel->invite_list); - channel->invite_list = NULL; - } else { - start = strstr(channel->invite_list, del); - if (start && strlen(start) >= len) { - end = start + len; - n = silc_calloc(strlen(channel->invite_list) - len, sizeof(*n)); - strncat(n, channel->invite_list, start - channel->invite_list); - strncat(n, end + 1, ((channel->invite_list + - strlen(channel->invite_list)) - end) - 1); - silc_free(channel->invite_list); - channel->invite_list = n; + /* Get the type of action */ + tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + if (tmp && len == 1) { + if (tmp[0] == 0x00) { + /* Allocate hash table for invite list if it doesn't exist yet */ + if (!channel->invite_list) + channel->invite_list = silc_hash_table_alloc(0, silc_hash_ptr, + NULL, NULL, NULL, + NULL, NULL, TRUE); + + /* Check for resource limit */ + if (silc_hash_table_count(channel->invite_list) > 64) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE, + SILC_STATUS_ERR_RESOURCE_LIMIT, + 0); + goto out; + } } + + /* Now add or delete the information. */ + silc_server_inviteban_process(server, channel->invite_list, + (SilcUInt8)tmp[0], args); + } + silc_argument_payload_free(args); + } + + /* Encode invite list */ + list = NULL; + if (channel->invite_list) { + list = silc_buffer_alloc_size(2); + silc_buffer_format(list, + SILC_STR_UI_SHORT(silc_hash_table_count( + channel->invite_list)), + SILC_STR_END); + silc_hash_table_list(channel->invite_list, &htl); + while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) { + if (type == 1) + list = silc_argument_payload_encode_one(list, (char *)tmp2, + strlen((char *)tmp2), type); + else + list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len, + type); } + silc_hash_table_list_reset(&htl); } /* Send notify to the primary router */ - silc_server_send_notify_invite(server, SILC_PRIMARY_ROUTE(server), - SILC_BROADCAST(server), channel, - sender->id, add, del); + silc_server_send_notify_invite( + server, SILC_PRIMARY_ROUTE(server), + SILC_BROADCAST(server), channel, sender->id, + silc_argument_get_arg_type(cmd->args, 3, NULL), + list); /* Send command reply */ tmp = silc_argument_get_arg_type(cmd->args, 1, &len); - - packet = - silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE, - SILC_STATUS_OK, 0, ident, 2, - 2, tmp, len, - 3, channel->invite_list, - channel->invite_list ? - strlen(channel->invite_list) : 0); + packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE, + SILC_STATUS_OK, 0, ident, 2, + 2, tmp, len, + 3, list ? list->data : NULL, + list ? list->len : 0); silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, packet->data, packet->len, FALSE); silc_buffer_free(packet); + silc_buffer_free(list); out: silc_free(dest_id); @@ -1743,7 +1764,8 @@ static void silc_server_command_join_channel(SilcServer server, unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4]; SilcClientEntry client; SilcChannelClientEntry chl; - SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list; + SilcBuffer reply, chidp, clidp, keyp = NULL; + SilcBuffer user_list, mode_list, invite_list, ban_list; SilcUInt16 ident = silc_command_get_ident(cmd->payload); char check[512], check2[512]; bool founder = FALSE; @@ -1877,8 +1899,14 @@ static void silc_server_command_join_channel(SilcServer server, /* Check invite list if channel is invite-only channel */ if (channel->mode & SILC_CHANNEL_MODE_INVITE) { if (!channel->invite_list || - (!silc_string_match(channel->invite_list, check) && - !silc_string_match(channel->invite_list, check2))) { + (!silc_server_inviteban_match(server, channel->invite_list, + 3, client->id) && + !silc_server_inviteban_match(server, channel->invite_list, + 2, client->data.public_key) && + !silc_server_inviteban_match(server, channel->invite_list, + 1, check) && + !silc_server_inviteban_match(server, channel->invite_list, + 1, check2))) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN, SILC_STATUS_ERR_NOT_INVITED, 0); goto out; @@ -1889,8 +1917,14 @@ static void silc_server_command_join_channel(SilcServer server, username and/or hostname is in the ban list the access to the channel is denied. */ if (channel->ban_list) { - if (silc_string_match(channel->ban_list, check) || - silc_string_match(channel->ban_list, check2)) { + if (silc_server_inviteban_match(server, channel->invite_list, + 3, client->id) || + silc_server_inviteban_match(server, channel->invite_list, + 2, client->data.public_key) || + !silc_server_inviteban_match(server, channel->invite_list, + 1, check) || + !silc_server_inviteban_match(server, channel->invite_list, + 1, check2)) { silc_server_command_send_status_reply( cmd, SILC_COMMAND_JOIN, SILC_STATUS_ERR_BANNED_FROM_CHANNEL, 0); @@ -1988,6 +2022,58 @@ static void silc_server_command_join_channel(SilcServer server, if (channel->founder_key) fkey = silc_pkcs_public_key_payload_encode(channel->founder_key); + /* Encode invite list */ + invite_list = NULL; + if (channel->invite_list) { + SilcHashTableList htl; + + invite_list = silc_buffer_alloc_size(2); + silc_buffer_format(invite_list, + SILC_STR_UI_SHORT(silc_hash_table_count( + channel->invite_list)), + SILC_STR_END); + + silc_hash_table_list(channel->invite_list, &htl); + while (silc_hash_table_get(&htl, (void **)&tmp_len, (void **)&reply)) { + if (tmp_len == 1) + invite_list = silc_argument_payload_encode_one(invite_list, + (char *)reply, + strlen((char *)reply), + tmp_len); + else + invite_list = silc_argument_payload_encode_one(invite_list, + reply->data, + reply->len, tmp_len); + } + silc_hash_table_list_reset(&htl); + } + + /* Encode ban list */ + ban_list = NULL; + if (channel->ban_list) { + SilcHashTableList htl; + + ban_list = silc_buffer_alloc_size(2); + silc_buffer_format(ban_list, + SILC_STR_UI_SHORT(silc_hash_table_count( + channel->ban_list)), + SILC_STR_END); + + silc_hash_table_list(channel->ban_list, &htl); + while (silc_hash_table_get(&htl, (void **)&tmp_len, (void **)&reply)) { + if (tmp_len == 1) + ban_list = silc_argument_payload_encode_one(ban_list, + (char *)reply, + strlen((char *)reply), + tmp_len); + else + ban_list = silc_argument_payload_encode_one(ban_list, + reply->data, + reply->len, tmp_len); + } + silc_hash_table_list_reset(&htl); + } + reply = silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN, SILC_STATUS_OK, 0, ident, 14, @@ -1999,12 +2085,11 @@ static void silc_server_command_join_channel(SilcServer server, 6, tmp2, 4, 7, keyp ? keyp->data : NULL, keyp ? keyp->len : 0, - 8, channel->ban_list, - channel->ban_list ? - strlen(channel->ban_list) : 0, - 9, channel->invite_list, - channel->invite_list ? - strlen(channel->invite_list) : 0, + 8, ban_list ? ban_list->data : NULL, + ban_list ? ban_list->len : 0, + 9, invite_list ? invite_list->data : + NULL, + invite_list ? invite_list->len : 0, 10, channel->topic, channel->topic ? strlen(channel->topic) : 0, @@ -2079,6 +2164,8 @@ static void silc_server_command_join_channel(SilcServer server, silc_buffer_free(user_list); silc_buffer_free(mode_list); silc_buffer_free(fkey); + silc_buffer_free(invite_list); + silc_buffer_free(ban_list); out: silc_free(passphrase); @@ -3991,13 +4078,16 @@ SILC_SERVER_CMD_FUNC(ban) SilcServerCommandContext cmd = (SilcServerCommandContext)context; SilcServer server = cmd->server; SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; - SilcBuffer packet; + SilcBuffer packet, list, tmp2; SilcChannelEntry channel; SilcChannelClientEntry chl; SilcChannelID *channel_id = NULL; - unsigned char *id, *add, *del; - SilcUInt32 id_len, tmp_len; - SilcUInt16 ident = silc_command_get_ident(cmd->payload); + unsigned char *id, *tmp; + SilcUInt32 id_len, len; + SilcArgumentPayload args; + SilcHashTableList htl; + SilcUInt32 type; + SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload); if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client) goto out; @@ -4044,62 +4134,84 @@ SILC_SERVER_CMD_FUNC(ban) goto out; } - /* Get the new ban and add it to the ban list */ - add = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); - if (add) { - if (!channel->ban_list) - channel->ban_list = silc_calloc(tmp_len + 2, sizeof(*channel->ban_list)); - else - channel->ban_list = silc_realloc(channel->ban_list, - sizeof(*channel->ban_list) * - (tmp_len + - strlen(channel->ban_list) + 2)); - if (add[tmp_len - 1] == ',') - add[tmp_len - 1] = '\0'; - - strncat(channel->ban_list, add, tmp_len); - strncat(channel->ban_list, ",", 1); - } - - /* Get the ban to be removed and remove it from the list */ - del = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); - if (del && channel->ban_list) { - char *start, *end, *n; + /* Get the ban information */ + tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + if (tmp) { + /* Parse the arguments to see they are constructed correctly */ + SILC_GET16_MSB(argc, tmp); + args = silc_argument_payload_parse(tmp + 2, len - 2, argc); + if (!args) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, + 0); + goto out; + } - if (!strncmp(channel->ban_list, del, strlen(channel->ban_list) - 1)) { - silc_free(channel->ban_list); - channel->ban_list = NULL; - } else { - start = strstr(channel->ban_list, del); - if (start && strlen(start) >= tmp_len) { - end = start + tmp_len; - n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n)); - strncat(n, channel->ban_list, start - channel->ban_list); - strncat(n, end + 1, ((channel->ban_list + strlen(channel->ban_list)) - - end) - 1); - silc_free(channel->ban_list); - channel->ban_list = n; + /* Get the type of action */ + tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + if (tmp && len == 1) { + if (tmp[0] == 0x00) { + /* Allocate hash table for ban list if it doesn't exist yet */ + if (!channel->ban_list) + channel->ban_list = silc_hash_table_alloc(0, silc_hash_ptr, + NULL, NULL, NULL, + NULL, NULL, TRUE); + + /* Check for resource limit */ + if (silc_hash_table_count(channel->ban_list) > 64) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN, + SILC_STATUS_ERR_RESOURCE_LIMIT, + 0); + goto out; + } } + + /* Now add or delete the information. */ + silc_server_inviteban_process(server, channel->ban_list, + (SilcUInt8)tmp[0], args); + } + silc_argument_payload_free(args); + } + + /* Encode ban list */ + list = NULL; + if (channel->ban_list) { + list = silc_buffer_alloc_size(2); + silc_buffer_format(list, + SILC_STR_UI_SHORT(silc_hash_table_count( + channel->ban_list)), + SILC_STR_END); + silc_hash_table_list(channel->ban_list, &htl); + while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) { + if (type == 1) + list = silc_argument_payload_encode_one(list, (char *)tmp2, + strlen((char *)tmp2), type); + else + list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len, + type); } + silc_hash_table_list_reset(&htl); } /* Send the BAN notify type to our primary router. */ - if (add || del) + if (list) silc_server_send_notify_ban(server, SILC_PRIMARY_ROUTE(server), - SILC_BROADCAST(server), channel, add, del); + SILC_BROADCAST(server), channel, + silc_argument_get_arg_type(cmd->args, 2, NULL), + list); /* Send the reply back to the client */ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_BAN, SILC_STATUS_OK, 0, ident, 2, 2, id, id_len, - 3, channel->ban_list, - channel->ban_list ? - strlen(channel->ban_list) -1 : 0); + 3, list ? list->data : NULL, + list ? list->len : 0); silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, packet->data, packet->len, FALSE); silc_buffer_free(packet); + silc_buffer_free(list); out: silc_free(channel_id); diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index d683a0e9..6a4d5f76 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -654,6 +654,10 @@ static void silc_idlist_del_channel_foreach(void *key, void *context, int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry) { if (entry) { + SilcHashTableList htl; + SilcBuffer tmp; + SilcUInt32 type; + /* Remove from cache */ if (!silc_idcache_del_by_context(id_list->channels, entry)) return FALSE; @@ -671,8 +675,33 @@ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry) silc_free(entry->channel_name); silc_free(entry->id); silc_free(entry->topic); - silc_free(entry->invite_list); - silc_free(entry->ban_list); + + if (entry->invite_list) { + silc_hash_table_list(entry->invite_list, &htl); + while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp)) { + if (type == 1) { + silc_free((char *)tmp); + continue; + } + silc_buffer_free(tmp); + } + silc_hash_table_list_reset(&htl); + silc_hash_table_free(entry->invite_list); + } + + if (entry->ban_list) { + silc_hash_table_list(entry->ban_list, &htl); + while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp)) { + if (type == 1) { + silc_free((char *)tmp); + continue; + } + silc_buffer_free(tmp); + } + silc_hash_table_list_reset(&htl); + silc_hash_table_free(entry->ban_list); + } + if (entry->channel_key) silc_cipher_free(entry->channel_key); if (entry->key) { diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index 4e41a359..ac67e10a 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -476,8 +476,8 @@ struct SilcChannelEntryStruct { SilcUInt32 user_limit; unsigned char *passphrase; - char *invite_list; - char *ban_list; + SilcHashTable invite_list; + SilcHashTable ban_list; /* All users on this channel */ SilcHashTable user_list; diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 2e96fa3e..fbb5a9d0 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -1067,46 +1067,33 @@ void silc_server_notify(SilcServer server, goto out; } - /* Get the added invite */ + /* Get the invite action */ tmp = silc_argument_get_arg_type(args, 4, &tmp_len); - if (tmp) { - if (!channel->invite_list) - channel->invite_list = silc_calloc(tmp_len + 2, - sizeof(*channel->invite_list)); - else - channel->invite_list = silc_realloc(channel->invite_list, - sizeof(*channel->invite_list) * - (tmp_len + - strlen(channel->invite_list) + - 2)); - if (tmp[tmp_len - 1] == ',') - tmp[tmp_len - 1] = '\0'; - - strncat(channel->invite_list, tmp, tmp_len); - strncat(channel->invite_list, ",", 1); - } + if (tmp && tmp_len == 1) { + SilcUInt8 action = (SilcUInt8)tmp[0]; + SilcUInt16 iargc = 0; + SilcArgumentPayload iargs; - /* Get the deleted invite */ - tmp = silc_argument_get_arg_type(args, 5, &tmp_len); - if (tmp && channel->invite_list) { - char *start, *end, *n; - - if (!strncmp(channel->invite_list, tmp, - strlen(channel->invite_list) - 1)) { - silc_free(channel->invite_list); - channel->invite_list = NULL; - } else { - start = strstr(channel->invite_list, tmp); - if (start && strlen(start) >= tmp_len) { - end = start + tmp_len; - n = silc_calloc(strlen(channel->invite_list) - tmp_len, sizeof(*n)); - strncat(n, channel->invite_list, start - channel->invite_list); - strncat(n, end + 1, ((channel->invite_list + - strlen(channel->invite_list)) - end) - 1); - silc_free(channel->invite_list); - channel->invite_list = n; - } - } + /* Get invite list */ + tmp = silc_argument_get_arg_type(args, 5, &tmp_len); + if (!tmp) + goto out; + + /* Parse the arguments to see they are constructed correctly */ + SILC_GET16_MSB(iargc, tmp); + iargs = silc_argument_payload_parse(tmp + 2, tmp_len - 2, iargc); + if (!iargs) + goto out; + + if (action == 0 && !channel->invite_list) + channel->invite_list = silc_hash_table_alloc(0, silc_hash_ptr, + NULL, NULL, NULL, + NULL, NULL, TRUE); + + /* Proces the invite action */ + silc_server_inviteban_process(server, channel->invite_list, action, + iargs); + silc_argument_payload_free(iargs); } break; @@ -1642,41 +1629,33 @@ void silc_server_notify(SilcServer server, } silc_free(channel_id); - /* Get the new ban and add it to the ban list */ + /* Get the ban action */ tmp = silc_argument_get_arg_type(args, 2, &tmp_len); - if (tmp) { - if (!channel->ban_list) - channel->ban_list = silc_calloc(tmp_len + 2, - sizeof(*channel->ban_list)); - else - channel->ban_list = silc_realloc(channel->ban_list, - sizeof(*channel->ban_list) * - (tmp_len + - strlen(channel->ban_list) + 2)); - strncat(channel->ban_list, tmp, tmp_len); - strncat(channel->ban_list, ",", 1); - } + if (tmp && tmp_len == 1) { + SilcUInt8 action = (SilcUInt8)tmp[0]; + SilcUInt16 iargc = 0; + SilcArgumentPayload iargs; - /* Get the ban to be removed and remove it from the list */ - tmp = silc_argument_get_arg_type(args, 3, &tmp_len); - if (tmp && channel->ban_list) { - char *start, *end, *n; - - if (!strncmp(channel->ban_list, tmp, strlen(channel->ban_list) - 1)) { - silc_free(channel->ban_list); - channel->ban_list = NULL; - } else { - start = strstr(channel->ban_list, tmp); - if (start && strlen(start) >= tmp_len) { - end = start + tmp_len; - n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n)); - strncat(n, channel->ban_list, start - channel->ban_list); - strncat(n, end + 1, ((channel->ban_list + - strlen(channel->ban_list)) - end) - 1); - silc_free(channel->ban_list); - channel->ban_list = n; - } - } + /* Get ban list */ + tmp = silc_argument_get_arg_type(args, 3, &tmp_len); + if (!tmp) + goto out; + + /* Parse the arguments to see they are constructed correctly */ + SILC_GET16_MSB(iargc, tmp); + iargs = silc_argument_payload_parse(tmp + 2, tmp_len - 2, iargc); + if (!iargs) + goto out; + + if (action == 0 && !channel->ban_list) + channel->ban_list = silc_hash_table_alloc(0, silc_hash_ptr, + NULL, NULL, NULL, + NULL, NULL, TRUE); + + /* Proces the ban action */ + silc_server_inviteban_process(server, channel->ban_list, action, + iargs); + silc_argument_payload_free(iargs); } break; diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index cc0bf758..0d97aeaf 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -1454,7 +1454,8 @@ void silc_server_send_notify_ban(SilcServer server, SilcSocketConnection sock, bool broadcast, SilcChannelEntry channel, - char *add, char *del) + unsigned char *action, + SilcBuffer list) { SilcBuffer idp; @@ -1462,8 +1463,8 @@ void silc_server_send_notify_ban(SilcServer server, silc_server_send_notify(server, sock, broadcast, SILC_NOTIFY_TYPE_BAN, 3, idp->data, idp->len, - add, add ? strlen(add) : 0, - del, del ? strlen(del) : 0); + action ? action : NULL, action ? 1 : 0, + list ? list->data : NULL, list ? list->len : 0); silc_buffer_free(idp); } @@ -1477,7 +1478,8 @@ void silc_server_send_notify_invite(SilcServer server, bool broadcast, SilcChannelEntry channel, SilcClientID *client_id, - char *add, char *del) + unsigned char *action, + SilcBuffer list) { SilcBuffer idp, idp2; @@ -1488,8 +1490,8 @@ void silc_server_send_notify_invite(SilcServer server, idp->data, idp->len, channel->channel_name, strlen(channel->channel_name), idp2->data, idp2->len, - add, add ? strlen(add) : 0, - del, del ? strlen(del) : 0); + action ? action : NULL, action ? 1 : 0, + list ? list->data : NULL, list ? list->len : 0); silc_buffer_free(idp); silc_buffer_free(idp2); } diff --git a/apps/silcd/packet_send.h b/apps/silcd/packet_send.h index ec3d1f46..2dac8012 100644 --- a/apps/silcd/packet_send.h +++ b/apps/silcd/packet_send.h @@ -184,13 +184,15 @@ void silc_server_send_notify_ban(SilcServer server, SilcSocketConnection sock, bool broadcast, SilcChannelEntry channel, - char *add, char *del); + unsigned char *action, + SilcBuffer list); void silc_server_send_notify_invite(SilcServer server, SilcSocketConnection sock, bool broadcast, SilcChannelEntry channel, SilcClientID *client_id, - char *add, char *del); + unsigned char *action, + SilcBuffer list); void silc_server_send_notify_watch(SilcServer server, SilcSocketConnection sock, SilcClientEntry watcher, diff --git a/apps/silcd/server_util.c b/apps/silcd/server_util.c index 5511a3ca..790979cd 100644 --- a/apps/silcd/server_util.c +++ b/apps/silcd/server_util.c @@ -1714,3 +1714,208 @@ silc_server_find_socket_by_host(SilcServer server, return NULL; } + +/* This function can be used to match the invite and ban lists. */ + +bool silc_server_inviteban_match(SilcServer server, SilcHashTable list, + SilcUInt8 type, void *check) +{ + unsigned char *tmp = NULL; + SilcUInt32 len = 0, t; + SilcHashTableList htl; + SilcBuffer entry; + bool ret = FALSE; + + if (type < 1 || type > 3 || !check) + return FALSE; + + if (type == 1) { + tmp = strdup((char *)check); + if (!tmp) + return FALSE; + } + if (type == 2) { + tmp = silc_pkcs_public_key_encode(check, &len); + if (!tmp) + return FALSE; + } + if (type == 3) { + tmp = silc_id_id2str(check, SILC_ID_CLIENT); + if (!tmp) + return FALSE; + len = silc_id_get_len(check, SILC_ID_CLIENT); + } + + /* Compare the list */ + silc_hash_table_list(list, &htl); + while (silc_hash_table_get(&htl, (void **)&t, (void **)&entry)) { + if (type == t) { + if (type == 1) { + if (silc_string_match((char *)entry, tmp)) { + ret = TRUE; + break; + } + } else if (!memcmp(entry->data, tmp, len)) { + ret = TRUE; + break; + } + } + } + silc_hash_table_list_reset(&htl); + + silc_free(tmp); + return ret; +} + +/* Process invite or ban information */ + +void silc_server_inviteban_process(SilcServer server, SilcHashTable list, + SilcUInt8 action, SilcArgumentPayload args) +{ + unsigned char *tmp; + SilcUInt32 type, len; + SilcBuffer tmp2; + SilcHashTableList htl; + + SILC_LOG_DEBUG(("Processing invite/ban for %s action", + action == 0x00 ? "ADD" : "DEL")); + + /* Add the information to invite list */ + if (action == 0x00) { + /* Traverse all arguments and add to the hash table according to + their type. */ + tmp = silc_argument_get_first_arg(args, &type, &len); + while (tmp) { + if (type == 1) { + /* Invite string. Get the old invite string from hash table + and append this at the end of the existing one. */ + char *string = NULL; + silc_hash_table_find(list, (void *)1, + NULL, (void **)&string); + silc_hash_table_del(list, (void *)1); + if (!string) + string = silc_calloc(len + 2, sizeof(*string)); + else + string = silc_realloc(string, sizeof(*string) * + (strlen(string) + len + 2)); + memset(string + strlen(string), 0, len + 2); + if (tmp[len - 1] == ',') + tmp[len - 1] = '\0'; + strncat(string, tmp, len); + strncat(string, ",", 1); + + /* Add new invite string to invite list */ + silc_hash_table_add(list, (void *)1, string); + + } else if (type == 2) { + /* Public key. Check first if the public key is already on the + list and ignore it if it is, otherwise, add it to hash table. */ + + /* Check if the public key is in the list already */ + silc_hash_table_list(list, &htl); + while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) { + if (type == 2 && !memcmp(tmp2->data, tmp, len)) { + tmp = NULL; + break; + } + } + silc_hash_table_list_reset(&htl); + + /* Add new public key to invite list */ + if (tmp) { + tmp2 = silc_buffer_alloc_size(len); + silc_buffer_put(tmp2, tmp, len); + silc_hash_table_add(list, (void *)2, tmp2); + } + + } else if (type == 3) { + /* Client ID */ + + /* Check if the ID is in the list already */ + silc_hash_table_list(list, &htl); + while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) { + if (type == 3 && !memcmp(tmp2->data, tmp, len)) { + tmp = NULL; + break; + } + } + silc_hash_table_list_reset(&htl); + + /* Add new Client ID to invite list */ + if (tmp) { + tmp2 = silc_buffer_alloc_size(len); + silc_buffer_put(tmp2, tmp, len); + silc_hash_table_add(list, (void *)3, tmp2); + } + } + + tmp = silc_argument_get_next_arg(args, &type, &len); + } + } + + /* Delete information to invite list */ + if (action && list) { + /* Now delete the arguments from invite list */ + tmp = silc_argument_get_first_arg(args, &type, &len); + while (tmp) { + if (type == 1) { + /* Invite string. Get the old string from hash table and delete + the requested string. */ + char *string = NULL, *start, *end, *n; + + if (silc_hash_table_find(list, (void *)1, NULL, (void **)&string)) { + silc_hash_table_del(list, (void *)1); + + if (!strncmp(string, tmp, strlen(string) - 1)) { + silc_free(string); + string = NULL; + } else { + start = strstr(string, tmp); + if (start && strlen(start) >= len) { + end = start + len; + n = silc_calloc(strlen(string) - len, sizeof(*n)); + strncat(n, string, start - string); + strncat(n, end + 1, ((string + strlen(string)) - end) - 1); + silc_free(string); + string = n; + } + } + + /* Add new invite string to invite list */ + if (string) + silc_hash_table_add(list, (void *)1, string); + } + + } else if (type == 2) { + /* Public key. */ + + /* Delete from the invite list */ + silc_hash_table_list(list, &htl); + while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) { + if (type == 2 && !memcmp(tmp2->data, tmp, len)) { + silc_hash_table_del_by_context(list, (void *)2, tmp2); + silc_buffer_free(tmp2); + break; + } + } + silc_hash_table_list_reset(&htl); + + } else if (type == 3) { + /* Client ID */ + + /* Delete from the invite list */ + silc_hash_table_list(list, &htl); + while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) { + if (type == 2 && !memcmp(tmp2->data, tmp, len)) { + silc_hash_table_del_by_context(list, (void *)2, tmp2); + silc_buffer_free(tmp2); + break; + } + } + silc_hash_table_list_reset(&htl); + } + + tmp = silc_argument_get_next_arg(args, &type, &len); + } + } +} diff --git a/apps/silcd/server_util.h b/apps/silcd/server_util.h index c18b9c20..e072df44 100644 --- a/apps/silcd/server_util.h +++ b/apps/silcd/server_util.h @@ -195,4 +195,12 @@ silc_server_find_socket_by_host(SilcServer server, SilcSocketType type, const char *ip, SilcUInt16 port); +/* This function can be used to match the invite and ban lists. */ +bool silc_server_inviteban_match(SilcServer server, SilcHashTable list, + SilcUInt8 type, void *check); + +/* Process invite or ban information */ +void silc_server_inviteban_process(SilcServer server, SilcHashTable list, + SilcUInt8 action, SilcArgumentPayload args); + #endif /* SERVER_UTIL_H */ diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index ed6a49e2..ed94414d 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -624,10 +624,10 @@ SILC_CLIENT_CMD_FUNC(invite) SilcClientConnection conn = cmd->conn; SilcClientEntry client_entry = NULL; SilcChannelEntry channel; - SilcBuffer buffer, clidp, chidp; - SilcUInt32 type = 0; + SilcBuffer buffer, clidp, chidp, args = NULL; char *nickname = NULL, *name; char *invite = NULL; + unsigned char action[1]; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -690,35 +690,48 @@ SILC_CLIENT_CMD_FUNC(invite) invite = cmd->argv[2]; invite++; if (cmd->argv[2][0] == '+') - type = 3; + action[0] = 0x00; else - type = 4; + action[0] = 0x01; } } + if (invite) { + args = silc_buffer_alloc_size(2); + silc_buffer_format(args, + SILC_STR_UI_SHORT(1), + SILC_STR_END); + args = silc_argument_payload_encode_one(args, invite, strlen(invite), 1); + } + /* Send the command */ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); if (client_entry) { clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT); buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, - ++conn->cmd_ident, 3, + ++conn->cmd_ident, 4, 1, chidp->data, chidp->len, 2, clidp->data, clidp->len, - type, invite, invite ? - strlen(invite) : 0); + 3, args ? action : NULL, + args ? 1 : 0, + 4, args ? args->data : NULL, + args ? args->len : 0); silc_buffer_free(clidp); } else { buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, - ++conn->cmd_ident, 2, + ++conn->cmd_ident, 3, 1, chidp->data, chidp->len, - type, invite, invite ? - strlen(invite) : 0); + 3, args ? action : NULL, + args ? 1 : 0, + 4, args ? args->data : NULL, + args ? args->len : 0); } silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(chidp); + silc_buffer_free(args), /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1990,9 +2003,9 @@ SILC_CLIENT_CMD_FUNC(ban) SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; SilcChannelEntry channel; - SilcBuffer buffer, chidp; - int type = 0; + SilcBuffer buffer, chidp, args = NULL; char *name, *ban = NULL; + unsigned char action[1]; if (!cmd->conn) { SILC_NOT_CONNECTED(cmd->client, cmd->conn); @@ -2027,25 +2040,37 @@ SILC_CLIENT_CMD_FUNC(ban) if (cmd->argc == 3) { if (cmd->argv[2][0] == '+') - type = 2; + action[0] = 0x00; else - type = 3; + action[0] = 0x01; ban = cmd->argv[2]; ban++; } + if (ban) { + args = silc_buffer_alloc_size(2); + silc_buffer_format(args, + SILC_STR_UI_SHORT(1), + SILC_STR_END); + args = silc_argument_payload_encode_one(args, ban, strlen(ban), 1); + } + chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL); /* Send the command */ buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, - ++conn->cmd_ident, 2, + ++conn->cmd_ident, 3, 1, chidp->data, chidp->len, - type, ban, ban ? strlen(ban) : 0); + 2, args ? action : NULL, + args ? 1 : 0, + 3, args ? args->data : NULL, + args ? args->len : 0); silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); silc_buffer_free(chidp); + silc_buffer_free(args); /* Notify application */ COMMAND(SILC_STATUS_OK); -- 2.24.0