X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Fsilcd%2Fcommand_reply.c;h=506c7f1e79b7094791a0a9e17c834b2bdecf159e;hb=d1e71f42379e8b5cd0748a7aeae8561b02cfe53d;hp=6d427ca9e626ebb36cc782d148dc6a12790c8fe7;hpb=f57bef4b184adf4d2c1a21c1ef7403711172737c;p=silc.git diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index 6d427ca9..506c7f1e 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -4,13 +4,12 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2002 Pekka Riikonen + Copyright (C) 1997 - 2005 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -52,6 +51,8 @@ SilcServerCommandReply silc_command_reply_list[] = SILC_SERVER_CMD_REPLY(users, USERS), SILC_SERVER_CMD_REPLY(getkey, GETKEY), SILC_SERVER_CMD_REPLY(list, LIST), + SILC_SERVER_CMD_REPLY(watch, WATCH), + SILC_SERVER_CMD_REPLY(ping, PING), { NULL, 0 }, }; @@ -76,7 +77,7 @@ void silc_server_command_reply_process(SilcServer server, SILC_LOG_DEBUG(("Bad command reply packet")); return; } - + /* Allocate command reply context. This must be free'd by the command reply routine receiving it. */ ctx = silc_calloc(1, sizeof(*ctx)); @@ -93,9 +94,9 @@ void silc_server_command_reply_process(SilcServer server, silc_server_command_reply_free(ctx); return; } - + /* Check for pending commands and mark to be exeucted */ - ctx->callbacks = + ctx->callbacks = silc_server_command_pending_check(server, command, ctx->ident, &ctx->callbacks_count); @@ -125,7 +126,7 @@ void silc_server_command_reply_free(SilcServerCommandReplyContext cmd) } } -static void +static void silc_server_command_process_error(SilcServerCommandReplyContext cmd, SilcStatus error) { @@ -143,11 +144,17 @@ silc_server_command_process_error(SilcServerCommandReplyContext cmd, if (client_id) { SILC_LOG_DEBUG(("Received invalid client ID notification, deleting " "the entry from cache")); - client = silc_idlist_find_client_by_id(server->global_list, + client = silc_idlist_find_client_by_id(server->global_list, client_id, FALSE, NULL); if (client) { - silc_server_remove_from_channels(server, NULL, client, TRUE, - NULL, TRUE); + + if (client->data.public_key) + silc_hash_table_del_by_context(server->pk_hash, + client->data.public_key, + client); + + silc_server_remove_from_channels(server, NULL, client, TRUE, + NULL, TRUE, FALSE); silc_idlist_del_data(client); silc_idlist_del_client(server->global_list, client); } @@ -163,14 +170,14 @@ static char silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) { SilcServer server = cmd->server; - unsigned char *tmp, *id_data, *umodes; - char *nickname, *username, *realname, *servername = NULL; + unsigned char *id_data, *umodes; + char *nickname, *username, *realname, *tmp, *servername = NULL; unsigned char *fingerprint; SilcClientID *client_id; SilcClientEntry client; SilcIDCacheEntry cache = NULL; char global = FALSE; - char *nick; + char *nick = NULL; SilcUInt32 mode = 0, len, len2, id_len, flen; id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len); @@ -192,10 +199,10 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) /* Check if we have this client cached already. */ - client = silc_idlist_find_client_by_id(server->local_list, client_id, + client = silc_idlist_find_client_by_id(server->local_list, client_id, FALSE, NULL); if (!client) { - client = silc_idlist_find_client_by_id(server->global_list, client_id, + client = silc_idlist_find_client_by_id(server->global_list, client_id, FALSE, NULL); global = TRUE; } @@ -210,18 +217,19 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) silc_parse_userfqdn(nickname, &nick, &servername); /* We don't have that client anywhere, add it. The client is added - to global list since server didn't have it in the lists so it must be - global. */ - client = silc_idlist_add_client(server->global_list, nick, - strdup(username), - strdup(realname), client_id, + to global list since server didn't have it in the lists so it must be + global. This will check for valid nickname and username strings. */ + client = silc_idlist_add_client(server->global_list, nick, username, + strdup(realname), client_id, cmd->sock->user_data, NULL, 0); if (!client) { SILC_LOG_ERROR(("Could not add new client to the ID Cache")); + silc_free(nick); + silc_free(servername); return FALSE; } - client->data.status |= + client->data.status |= (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED); client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; client->mode = mode; @@ -231,8 +239,31 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) SILC_LOG_DEBUG(("Updating client data")); - /* Take hostname out of nick string if it includes it. */ + /* Check nickname */ silc_parse_userfqdn(nickname, &nick, &servername); + nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8, + 128, NULL); + if (!nickname) { + SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOIS reply " + "from %s", + cmd->sock->hostname ? cmd->sock->hostname : "", nick)); + silc_free(nick); + silc_free(servername); + return FALSE; + } + + /* Check username */ + silc_parse_userfqdn(username, &tmp, NULL); + if (!silc_identifier_verify(tmp, strlen(tmp), SILC_STRING_UTF8, 128)) { + silc_free(tmp); + silc_free(nick); + silc_free(servername); + SILC_LOG_ERROR(("Malformed username '%s' received in WHOIS reply " + "from %s", + cmd->sock->hostname ? cmd->sock->hostname : "", tmp)); + return FALSE; + } + silc_free(tmp); /* Remove the old cache entry */ silc_idcache_del_by_context(global ? server->global_list->clients : @@ -242,7 +273,7 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) silc_free(client->username); silc_free(client->userinfo); silc_free(client->servername); - + client->nickname = nick; client->username = strdup(username); client->userinfo = strdup(realname); @@ -253,8 +284,8 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) /* Create new cache entry */ silc_idcache_add(global ? server->global_list->clients : - server->local_list->clients, nick, client->id, - client, 0, NULL); + server->local_list->clients, nickname, client->id, + client, 0, NULL); silc_free(client_id); } @@ -292,6 +323,69 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) if (tmp) { silc_free(client->attrs); client->attrs = silc_memdup(tmp, len); + client->attrs_len = len; + + /* Try to take public key from attributes if present and we don't have + the key already. Do this only on normal server. Routers do GETKEY + for all clients anyway. */ + if (server->server_type != SILC_ROUTER && !client->data.public_key) { + SilcAttributePayload attr; + SilcAttributeObjPk pk; + unsigned char f[20]; + SilcDList attrs = silc_attribute_payload_parse(tmp, len); + + SILC_LOG_DEBUG(("Take client public key from attributes")); + + if (attrs) { + silc_dlist_start(attrs); + while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) { + if (silc_attribute_get_attribute(attr) == + SILC_ATTRIBUTE_USER_PUBLIC_KEY) { + + if (!silc_attribute_get_object(attr, &pk, sizeof(pk))) + continue; + + /* Take only SILC public keys */ + if (strcmp(pk.type, "silc-rsa")) { + silc_free(pk.type); + silc_free(pk.data); + continue; + } + + /* Verify that the server provided fingerprint matches the key */ + silc_hash_make(server->sha1hash, pk.data, pk.data_len, f); + if (memcmp(f, client->data.fingerprint, sizeof(f))) { + silc_free(pk.type); + silc_free(pk.data); + continue; + } + + /* Save the public key. */ + if (!silc_pkcs_public_key_decode(pk.data, pk.data_len, + &client->data.public_key)) { + silc_free(pk.type); + silc_free(pk.data); + continue; + } + + SILC_LOG_DEBUG(("Saved client public key from attributes")); + + /* Add to public key hash table */ + if (!silc_hash_table_find_by_context(server->pk_hash, + client->data.public_key, + client, NULL)) + silc_hash_table_add(server->pk_hash, + client->data.public_key, client); + + silc_free(pk.type); + silc_free(pk.data); + break; + } + } + + silc_attribute_payload_list_free(attrs); + } + } } return TRUE; @@ -311,8 +405,11 @@ silc_server_command_reply_whois_save_client(SilcServerCommandReplyContext cmd) if (tmp && client) { silc_free(client->attrs); client->attrs = silc_memdup(tmp, len); + client->attrs_len = len; } + client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; + return TRUE; } @@ -363,11 +460,11 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd) SilcServer server = cmd->server; SilcUInt32 len, id_len; unsigned char *id_data; - char *nickname, *username, *realname, *servername = NULL; + char *nickname, *username, *realname, *servername = NULL, *tmp; SilcClientID *client_id; SilcClientEntry client; SilcIDCacheEntry cache = NULL; - char *nick; + char *nick = NULL; int global = FALSE; id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len); @@ -387,7 +484,7 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd) client = silc_idlist_find_client_by_id(server->local_list, client_id, FALSE, &cache); if (!client) { - client = silc_idlist_find_client_by_id(server->global_list, + client = silc_idlist_find_client_by_id(server->global_list, client_id, FALSE, &cache); global = TRUE; } @@ -402,32 +499,57 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd) silc_parse_userfqdn(nickname, &nick, &servername); /* We don't have that client anywhere, add it. The client is added - to global list since server didn't have it in the lists so it must be + to global list since server didn't have it in the lists so it must be global. */ - client = silc_idlist_add_client(server->global_list, nick, - strdup(username), strdup(realname), - silc_id_dup(client_id, SILC_ID_CLIENT), + client = silc_idlist_add_client(server->global_list, nick, username, + strdup(realname), + silc_id_dup(client_id, SILC_ID_CLIENT), cmd->sock->user_data, NULL, SILC_ID_CACHE_EXPIRE_DEF); if (!client) { SILC_LOG_ERROR(("Could not add new client to the ID Cache")); + silc_free(nick); + silc_free(servername); return FALSE; } client->data.status |= SILC_IDLIST_STATUS_RESOLVED; client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; - client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; + client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; client->servername = servername; } else { /* We have the client already, update the data */ - /* Take hostname out of nick string if it includes it. */ + /* Check nickname */ silc_parse_userfqdn(nickname, &nick, &servername); + nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8, + 128, NULL); + if (!nickname) { + SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOWAS reply " + "from %s", + cmd->sock->hostname ? cmd->sock->hostname : "", nick)); + silc_free(nick); + silc_free(servername); + return FALSE; + } + + /* Check username */ + silc_parse_userfqdn(username, &tmp, NULL); + if (!silc_identifier_verify(tmp, strlen(tmp), SILC_STRING_UTF8, 128)) { + silc_free(tmp); + silc_free(nick); + silc_free(servername); + SILC_LOG_ERROR(("Malformed username '%s' received in WHOWAS reply " + "from %s", + cmd->sock->hostname ? cmd->sock->hostname : "", tmp)); + return FALSE; + } + silc_free(tmp); silc_free(client->nickname); silc_free(client->username); silc_free(client->servername); - + client->nickname = nick; client->username = strdup(username); client->servername = servername; @@ -438,7 +560,7 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd) silc_idcache_del_by_context(global ? server->global_list->clients : server->local_list->clients, client); silc_idcache_add(global ? server->global_list->clients : - server->local_list->clients, nick, client->id, + server->local_list->clients, nickname, client->id, client, 0, NULL); } @@ -530,7 +652,7 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) SILC_LOG_DEBUG(("Received client information")); - client = silc_idlist_find_client_by_id(server->local_list, + client = silc_idlist_find_client_by_id(server->local_list, client_id, FALSE, NULL); if (!client) { client = silc_idlist_find_client_by_id(server->global_list, client_id, @@ -548,36 +670,53 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) silc_parse_userfqdn(name, &nick, NULL); /* We don't have that client anywhere, add it. The client is added - to global list since server didn't have it in the lists so it must be + to global list since server didn't have it in the lists so it must be global. */ - client = silc_idlist_add_client(server->global_list, nick, - info ? strdup(info) : NULL, NULL, + client = silc_idlist_add_client(server->global_list, nick, info, NULL, client_id, cmd->sock->user_data, NULL, time(NULL) + 300); if (!client) { SILC_LOG_ERROR(("Could not add new client to the ID Cache")); + silc_free(nick); goto error; } + client->data.status |= SILC_IDLIST_STATUS_REGISTERED; client->data.status |= SILC_IDLIST_STATUS_RESOLVED; client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; } else { /* We have the client already, update the data */ - + SILC_LOG_DEBUG(("Updating client data")); - + /* Take nickname */ if (name) { silc_parse_userfqdn(name, &nick, NULL); + /* Check nickname */ + name = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8, + 128, NULL); + if (!name) { + SILC_LOG_ERROR(("Malformed nickname '%s' received in IDENTIFY reply " + "from %s", + cmd->sock->hostname ? + cmd->sock->hostname : "", nick)); + return FALSE; + } + /* Remove the old cache entry */ silc_idcache_del_by_context(global ? server->global_list->clients : server->local_list->clients, client); silc_free(client->nickname); client->nickname = nick; + + /* Add new cache entry */ + silc_idcache_add(global ? server->global_list->clients : + server->local_list->clients, name, client->id, + client, expire, NULL); } - + if (info) { silc_free(client->username); client->username = strdup(info); @@ -585,13 +724,6 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) client->data.status |= SILC_IDLIST_STATUS_RESOLVED; client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING; - - if (name) { - /* Add new cache entry */ - silc_idcache_add(global ? server->global_list->clients : - server->local_list->clients, nick, client->id, - client, expire, NULL); - } /* If client is global and is not on any channel then add that we'll expire the entry after a while. */ @@ -620,19 +752,19 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) SILC_LOG_DEBUG(("Received server information")); - server_entry = silc_idlist_find_server_by_id(server->local_list, + server_entry = silc_idlist_find_server_by_id(server->local_list, server_id, FALSE, NULL); if (!server_entry) - server_entry = silc_idlist_find_server_by_id(server->global_list, + server_entry = silc_idlist_find_server_by_id(server->global_list, server_id, FALSE, NULL); if (!server_entry) { /* If router did not find such Server ID in its lists then this must be bogus server or some router in the net is buggy. */ if (server->server_type != SILC_SERVER) goto error; - + /* We don't have that server anywhere, add it. */ - server_entry = silc_idlist_add_server(server->global_list, + server_entry = silc_idlist_add_server(server->global_list, strdup(name), 0, server_id, server->router, SILC_PRIMARY_ROUTE(server)); @@ -659,25 +791,35 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) SILC_LOG_DEBUG(("Received channel information")); - channel = silc_idlist_find_channel_by_name(server->local_list, - name, NULL); + /* Check channel name */ + info = silc_channel_name_check(name, strlen(name), SILC_STRING_UTF8, + 256, NULL); + if (!info) + goto error; + + channel = silc_idlist_find_channel_by_name(server->local_list, + info, NULL); if (!channel) - channel = silc_idlist_find_channel_by_name(server->global_list, - name, NULL); + channel = silc_idlist_find_channel_by_name(server->global_list, + info, NULL); if (!channel) { /* If router did not find such Channel ID in its lists then this must be bogus channel or some router in the net is buggy. */ - if (server->server_type != SILC_SERVER) + if (server->server_type != SILC_SERVER) { + silc_free(info); goto error; - + } + /* We don't have that channel anywhere, add it. */ channel = silc_idlist_add_channel(server->global_list, strdup(name), - SILC_CHANNEL_MODE_NONE, channel_id, + SILC_CHANNEL_MODE_NONE, channel_id, server->router, NULL, NULL, 0); if (!channel) { silc_free(channel_id); + silc_free(info); goto error; } + silc_free(info); channel_id = NULL; } @@ -750,18 +892,18 @@ SILC_SERVER_CMD_REPLY_FUNC(info) /* Get the name */ name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); - if (tmp_len > 256) + if (!name) goto out; - entry = silc_idlist_find_server_by_id(server->local_list, server_id, + entry = silc_idlist_find_server_by_id(server->local_list, server_id, FALSE, NULL); if (!entry) { - entry = silc_idlist_find_server_by_id(server->global_list, server_id, + entry = silc_idlist_find_server_by_id(server->global_list, server_id, FALSE, NULL); if (!entry) { /* Add the server to global list */ server_id = silc_id_dup(server_id, SILC_ID_SERVER); - entry = silc_idlist_add_server(server->global_list, name, 0, + entry = silc_idlist_add_server(server->global_list, strdup(name), 0, server_id, cmd->sock->user_data, cmd->sock); if (!entry) { @@ -807,13 +949,40 @@ SILC_SERVER_CMD_REPLY_FUNC(motd) if (!server_id) goto out; - entry = silc_idlist_find_server_by_id(server->local_list, server_id, + entry = silc_idlist_find_server_by_id(server->local_list, server_id, TRUE, NULL); if (!entry) { - entry = silc_idlist_find_server_by_id(server->global_list, server_id, + entry = silc_idlist_find_server_by_id(server->global_list, server_id, TRUE, NULL); - if (!entry) - goto out; + if (!entry) { + SilcBuffer buffer; + + /* If router did not find such Server ID in its lists then this must + be bogus client or some router in the net is buggy. */ + if (server->server_type != SILC_SERVER) + goto out; + + /* Statistics */ + cmd->server->stat.commands_sent++; + + /* entry isn't known so we IDENTIFY it. otherwise the + silc_server_command_motd won't know about it and tell + the client that there is no such server */ + buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, + ++server->cmd_ident, 5, + 1, NULL, 0, 2, NULL, 0, + 3, NULL, 0, 4, NULL, 0, + 5, tmp, tmp_len); + silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), + SILC_PACKET_COMMAND, 0, buffer->data, + buffer->len, TRUE); + silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, + server->cmd_ident, + silc_server_command_reply_motd, + cmd); + silc_buffer_free(buffer); + return; + } } /* Get the motd */ @@ -848,7 +1017,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join) SilcHmac hmac = NULL; SilcUInt32 id_len, len, list_count; unsigned char *id_string; - char *channel_name, *tmp; + char *channel_name, *channel_namec = NULL, *tmp; SilcUInt32 mode, created; SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL; SilcPublicKey founder_key = NULL; @@ -934,22 +1103,26 @@ SILC_SERVER_CMD_REPLY_FUNC(join) /* Get founder key */ tmp = silc_argument_get_arg_type(cmd->args, 15, &len); if (tmp) - silc_pkcs_public_key_decode(tmp, len, &founder_key); + silc_pkcs_public_key_payload_decode(tmp, len, &founder_key); /* See whether we already have the channel. */ - entry = silc_idlist_find_channel_by_name(server->local_list, - channel_name, &cache); + channel_namec = silc_channel_name_check(channel_name, strlen(channel_name), + SILC_STRING_UTF8, 256, NULL); + if (!channel_namec) + goto out; + entry = silc_idlist_find_channel_by_name(server->local_list, + channel_namec, &cache); if (!entry) { /* Add new channel */ - SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)", + SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)", (created == 0 ? "existing" : "created"), channel_name, silc_id_render(id, SILC_ID_CHANNEL))); /* If the channel is found from global list we must move it to the local list. */ entry = silc_idlist_find_channel_by_name(server->global_list, - channel_name, &cache); + channel_namec, &cache); if (entry) silc_idlist_del_channel(server->global_list, entry); @@ -961,6 +1134,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join) silc_free(id); goto out; } + hmac = NULL; server->stat.my_channels++; server->stat.channels++; } else { @@ -987,23 +1161,53 @@ SILC_SERVER_CMD_REPLY_FUNC(join) founder_key = NULL; } - if (entry->hmac_name && hmac) { + if (entry->hmac_name && (hmac || (!hmac && entry->hmac))) { silc_free(entry->hmac_name); - entry->hmac_name = strdup(silc_hmac_get_name(hmac)); + entry->hmac_name = strdup(silc_hmac_get_name(hmac ? hmac : entry->hmac)); } /* Get the ban list */ tmp = silc_argument_get_arg_type(cmd->args, 8, &len); - if (tmp) { - silc_free(entry->ban_list); - entry->ban_list = silc_memdup(tmp, len); + if (tmp && len > 2) { + SilcArgumentPayload iargs; + SilcUInt16 iargc; + SILC_GET16_MSB(iargc, tmp); + iargs = silc_argument_payload_parse(tmp + 2, len - 2, iargc); + if (iargs) { + /* Delete old ban list */ + if (entry->ban_list) + silc_hash_table_free(entry->ban_list); + entry->ban_list = + silc_hash_table_alloc(0, silc_hash_ptr, + NULL, NULL, NULL, + silc_server_inviteban_destruct, entry, TRUE); + + /* Add new ban list */ + silc_server_inviteban_process(server, entry->ban_list, 0, iargs); + silc_argument_payload_free(iargs); + } } /* Get the invite list */ tmp = silc_argument_get_arg_type(cmd->args, 9, &len); - if (tmp) { - silc_free(entry->invite_list); - entry->invite_list = silc_memdup(tmp, len); + if (tmp && len > 2) { + SilcArgumentPayload iargs; + SilcUInt16 iargc; + SILC_GET16_MSB(iargc, tmp); + iargs = silc_argument_payload_parse(tmp + 2, len - 2, iargc); + if (iargs) { + /* Delete old invite list */ + if (entry->invite_list) + silc_hash_table_free(entry->invite_list); + entry->invite_list = + silc_hash_table_alloc(0, silc_hash_ptr, + NULL, NULL, NULL, + silc_server_inviteban_destruct, entry, TRUE); + + /* Add new invite list */ + silc_server_inviteban_process(server, entry->invite_list, 0, iargs); + silc_argument_payload_free(iargs); + } } /* Get the topic */ @@ -1013,7 +1217,17 @@ SILC_SERVER_CMD_REPLY_FUNC(join) entry->topic = strdup(tmp); } - /* If channel was not created we know there is global users on the + /* Get channel public key list */ + tmp = silc_argument_get_arg_type(cmd->args, 16, &len); + if (tmp && server->server_type != SILC_ROUTER) + silc_server_set_channel_pk_list(server, NULL, entry, tmp, len); + + /* The the user limit */ + tmp = silc_argument_get_arg_type(cmd->args, 17, &len); + if (tmp && len == 4) + SILC_GET32_MSB(entry->user_limit, tmp); + + /* If channel was not created we know there is global users on the channel. */ entry->global_users = (created == 0 ? TRUE : FALSE); @@ -1035,7 +1249,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join) } /* Save the users to the channel */ - silc_server_save_users_on_channel(server, cmd->sock, entry, + silc_server_save_users_on_channel(server, cmd->sock, entry, client_id, client_id_list, client_mode_list, list_count); entry->users_resolved = TRUE; @@ -1043,6 +1257,9 @@ SILC_SERVER_CMD_REPLY_FUNC(join) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN); err: + silc_free(channel_namec); + if (hmac) + silc_hmac_free(hmac); silc_free(client_id); silc_server_command_reply_free(cmd); @@ -1068,7 +1285,7 @@ SILC_SERVER_CMD_REPLY_FUNC(stats) /* Get statistics structure */ tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); - if (server->server_type == SILC_SERVER && tmp) { + if (server->server_type != SILC_ROUTER && tmp) { silc_buffer_set(&buf, tmp, tmp_len); silc_buffer_unformat(&buf, SILC_STR_UI_INT(NULL), @@ -1119,10 +1336,10 @@ SILC_SERVER_CMD_REPLY_FUNC(users) goto out; /* Get channel entry */ - channel = silc_idlist_find_channel_by_id(server->local_list, + channel = silc_idlist_find_channel_by_id(server->local_list, channel_id, NULL); if (!channel) { - channel = silc_idlist_find_channel_by_id(server->global_list, + channel = silc_idlist_find_channel_by_id(server->global_list, channel_id, NULL); if (!channel) { SilcBuffer idp; @@ -1139,7 +1356,7 @@ SILC_SERVER_CMD_REPLY_FUNC(users) /* Register pending command callback. After we've received the channel information we will reprocess this command reply by re-calling this USERS command reply callback. */ - silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, + silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, server->cmd_ident, silc_server_command_reply_users, cmd); return; @@ -1172,7 +1389,7 @@ SILC_SERVER_CMD_REPLY_FUNC(users) /* Save the users to the channel */ silc_server_save_users_on_channel(server, cmd->sock, channel, NULL, - client_id_list, client_mode_list, + client_id_list, client_mode_list, list_count); channel->global_users = silc_server_channel_has_global(channel); @@ -1197,10 +1414,8 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) SilcServerEntry server_entry = NULL; SilcClientID *client_id = NULL; SilcServerID *server_id = NULL; - SilcSKEPKType type; - unsigned char *tmp, *pk; + unsigned char *tmp; SilcUInt32 len; - SilcUInt16 pk_len; SilcIDPayload idp = NULL; SilcIdType id_type; SilcPublicKey public_key = NULL; @@ -1219,16 +1434,8 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) if (!tmp) goto out; - /* Decode the public key */ - - SILC_GET16_MSB(pk_len, tmp); - SILC_GET16_MSB(type, tmp + 2); - pk = tmp + 4; - - if (type != SILC_SKE_PK_TYPE_SILC) - goto out; - - if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) + /* Decode the public key payload */ + if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key)) goto out; id_type = silc_id_payload_get_type(idp); @@ -1238,21 +1445,27 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) client = silc_idlist_find_client_by_id(server->local_list, client_id, TRUE, NULL); if (!client) { - client = silc_idlist_find_client_by_id(server->global_list, + client = silc_idlist_find_client_by_id(server->global_list, client_id, TRUE, NULL); if (!client) goto out; } - client->data.public_key = public_key; - public_key = NULL; + if (!client->data.public_key) { + if (!silc_hash_table_find_by_context(server->pk_hash, public_key, + client, NULL)) + silc_hash_table_add(server->pk_hash, public_key, client); + + client->data.public_key = public_key; + public_key = NULL; + } } else if (id_type == SILC_ID_SERVER) { server_id = silc_id_payload_get_id(idp); server_entry = silc_idlist_find_server_by_id(server->local_list, server_id, TRUE, NULL); if (!server_entry) { - server_entry = silc_idlist_find_server_by_id(server->global_list, + server_entry = silc_idlist_find_server_by_id(server->global_list, server_id, TRUE, NULL); if (!server_entry) goto out; @@ -1285,13 +1498,15 @@ SILC_SERVER_CMD_REPLY_FUNC(list) SilcChannelEntry channel; SilcIDCacheEntry cache; SilcUInt32 len; - unsigned char *tmp, *name, *topic; + unsigned char *tmp, *name, *namec = NULL, *topic; SilcUInt32 usercount = 0; bool global_list = FALSE; COMMAND_CHECK_STATUS; tmp = silc_argument_get_arg_type(cmd->args, 2, &len); + if (!tmp) + goto out; channel_id = silc_id_payload_parse_id(tmp, len, NULL); if (!channel_id) goto out; @@ -1302,12 +1517,17 @@ SILC_SERVER_CMD_REPLY_FUNC(list) if (tmp) SILC_GET32_MSB(usercount, tmp); + namec = silc_channel_name_check(name, strlen(name), SILC_STRING_UTF8, + 256, NULL); + if (!namec) + goto out; + /* Add the channel entry if we do not have it already */ - channel = silc_idlist_find_channel_by_name(server->local_list, - name, &cache); + channel = silc_idlist_find_channel_by_name(server->local_list, + namec, &cache); if (!channel) { - channel = silc_idlist_find_channel_by_name(server->global_list, - name, &cache); + channel = silc_idlist_find_channel_by_name(server->global_list, + namec, &cache); global_list = TRUE; } if (!channel) { @@ -1315,10 +1535,10 @@ SILC_SERVER_CMD_REPLY_FUNC(list) be bogus channel or some router in the net is buggy. */ if (server->server_type != SILC_SERVER) goto out; - + channel = silc_idlist_add_channel(server->global_list, strdup(name), - SILC_CHANNEL_MODE_NONE, channel_id, - server->router, NULL, NULL, + SILC_CHANNEL_MODE_NONE, channel_id, + server->router, NULL, NULL, time(NULL) + 60); if (!channel) goto out; @@ -1351,6 +1571,7 @@ SILC_SERVER_CMD_REPLY_FUNC(list) SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST); silc_free(channel_id); err: + silc_free(namec); silc_server_command_reply_free(cmd); } @@ -1366,3 +1587,16 @@ SILC_SERVER_CMD_REPLY_FUNC(watch) err: silc_server_command_reply_free(cmd); } + +SILC_SERVER_CMD_REPLY_FUNC(ping) +{ + SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context; + SilcStatus status, error; + + COMMAND_CHECK_STATUS; + + out: + SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_PING); + err: + silc_server_command_reply_free(cmd); +}