X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=apps%2Fsilcd%2Fpacket_receive.c;h=fa24ff21e4f1af12ef652e0c7d49d049c7d51a82;hp=b9a0224f052f99174af426457632390cdc458960;hb=c257b555225193e54d85daf541d29578b3c93882;hpb=f658940d02cf2fd893296b6a7825b42502573668 diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index b9a0224f..fa24ff21 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2003 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 @@ -227,13 +227,16 @@ void silc_server_notify(SilcServer server, if (server->server_type != SILC_ROUTER || sock->type == SILC_SOCKET_TYPE_ROUTER) { - /* If this is the first one on the channel then it is the founder of - the channel. This is done on normal server and on router if this - notify is coming from router */ - if (!silc_hash_table_count(channel->user_list)) { - SILC_LOG_DEBUG(("Client %s is founder on channel", - silc_id_render(chl->client->id, SILC_ID_CLIENT))); - chl->mode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO); + /* If founder auth is set, first client is not automatically founder. */ + if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) { + /* If this is the first one on the channel then it is the founder of + the channel. This is done on normal server and on router if this + notify is coming from router */ + if (!silc_hash_table_count(channel->user_list)) { + SILC_LOG_DEBUG(("Client %s is founder on channel", + silc_id_render(chl->client->id, SILC_ID_CLIENT))); + chl->mode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO); + } } } @@ -361,6 +364,11 @@ void silc_server_notify(SilcServer server, SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR); silc_schedule_task_del_by_context(server->schedule, client); + /* Remove from public key hash table. */ + if (client->data.public_key) + silc_hash_table_del_by_context(server->pk_hash, client->data.public_key, + client); + /* Remove the client from all channels. */ silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, FALSE, FALSE); @@ -374,6 +382,9 @@ void silc_server_notify(SilcServer server, silc_server_del_from_watcher_list(server, client); client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; + client->mode = 0; + client->router = NULL; + client->connection = NULL; cache->expire = SILC_ID_CACHE_EXPIRE_DEF; break; @@ -623,7 +634,7 @@ void silc_server_notify(SilcServer server, mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) { SilcBuffer chpklist; SilcBuffer sidp; - unsigned char mask[4]; + unsigned char mask[4], ulimit[4]; SILC_LOG_DEBUG(("Channel public key list received from router")); tmp = silc_argument_get_arg_type(args, 7, &tmp_len); @@ -639,8 +650,10 @@ void silc_server_notify(SilcServer server, break; sidp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER); SILC_PUT32_MSB(channel->mode, mask); + if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) + SILC_PUT32_MSB(channel->user_limit, ulimit); silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE, - SILC_NOTIFY_TYPE_CMODE_CHANGE, 7, + SILC_NOTIFY_TYPE_CMODE_CHANGE, 8, sidp->data, sidp->len, mask, 4, channel->cipher, @@ -653,7 +666,13 @@ void silc_server_notify(SilcServer server, channel->passphrase ? strlen(channel->passphrase) : 0, NULL, 0, - chpklist->data, chpklist->len); + chpklist->data, chpklist->len, + (channel->mode & + SILC_CHANNEL_MODE_ULIMIT ? + ulimit : NULL), + (channel->mode & + SILC_CHANNEL_MODE_ULIMIT ? + sizeof(ulimit) : 0)); silc_buffer_free(sidp); silc_buffer_free(chpklist); goto out; @@ -762,6 +781,7 @@ void silc_server_notify(SilcServer server, if (channel->founder_key) silc_pkcs_public_key_free(channel->founder_key); channel->founder_key = NULL; + SILC_LOG_DEBUG(("Founder public key received")); if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &channel->founder_key)) { SILC_LOG_DEBUG(("Enforcing sender to change channel mode")); @@ -808,6 +828,11 @@ void silc_server_notify(SilcServer server, } } + /* Get the user limit */ + tmp = silc_argument_get_arg_type(args, 8, &tmp_len); + if (tmp && tmp_len == 4 && mode & SILC_CHANNEL_MODE_ULIMIT) + SILC_GET32_MSB(channel->user_limit, tmp); + /* Send the same notify to the channel */ silc_server_packet_send_to_channel(server, NULL, channel, packet->type, FALSE, TRUE, packet->buffer->data, @@ -975,8 +1000,9 @@ void silc_server_notify(SilcServer server, /* Get the founder of the channel and if found then this client cannot be the founder since there already is one. */ silc_hash_table_list(channel->user_list, &htl); - while (silc_hash_table_get(&htl, NULL, (void **)&chl2)) + while (silc_hash_table_get(&htl, NULL, (void *)&chl2)) if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) { + SILC_LOG_DEBUG(("Founder already on channel")); chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO; silc_server_force_cumode_change(server, sock, channel, chl, mode); @@ -987,7 +1013,7 @@ void silc_server_notify(SilcServer server, if (!(mode & SILC_CHANNEL_UMODE_CHANFO)) break; - /* Founder not found of the channel. Since the founder auth mode + /* Founder not found on the channel. Since the founder auth mode is set on the channel now check whether this is the client that originally set the mode. */ @@ -997,6 +1023,7 @@ void silc_server_notify(SilcServer server, if (!tmp || !silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key)) { chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO; + SILC_LOG_DEBUG(("Founder public key not present")); silc_server_force_cumode_change(server, sock, channel, chl, mode); notify_sent = TRUE; break; @@ -1007,6 +1034,7 @@ void silc_server_notify(SilcServer server, if (!silc_pkcs_public_key_compare(channel->founder_key, founder_key)) { chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO; + SILC_LOG_DEBUG(("Founder public key mismatch")); silc_server_force_cumode_change(server, sock, channel, chl, mode); notify_sent = TRUE; break; @@ -1015,11 +1043,13 @@ void silc_server_notify(SilcServer server, /* There cannot be anyone else as founder on the channel now. This client is definitely the founder due to this 'authentication'. - We trust the server did the actual authentication earlier. */ + We trust the server did the actual signature verification + earlier (bad, yes). */ silc_hash_table_list(channel->user_list, &htl); while (silc_hash_table_get(&htl, NULL, (void *)&chl2)) if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) { chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO; + SILC_LOG_DEBUG(("Removing old founder rights, new authenticated")); silc_server_force_cumode_change(server, NULL, channel, chl2, chl2->mode); break; @@ -1044,7 +1074,7 @@ void silc_server_notify(SilcServer server, /* Send the same notify to the channel */ if (!notify_sent) - silc_server_packet_send_to_channel(server, NULL, channel, + silc_server_packet_send_to_channel(server, sock, channel, packet->type, FALSE, TRUE, packet->buffer->data, packet->buffer->len, FALSE); @@ -1138,15 +1168,16 @@ void silc_server_notify(SilcServer server, if (!iargs) goto out; - if (action != 0x01 && !channel->invite_list) + if (!channel->invite_list) channel->invite_list = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL, silc_server_inviteban_destruct, channel, TRUE); /* Proces the invite action */ - silc_server_inviteban_process(server, channel->invite_list, action, - iargs); + if (!silc_server_inviteban_process(server, channel->invite_list, action, + iargs)) + goto out; silc_argument_payload_free(iargs); /* If we are router we must send this notify to our local servers on @@ -1360,6 +1391,12 @@ void silc_server_notify(SilcServer server, if (local) silc_server_del_from_watcher_list(server, client); + /* Remove from public key hash table. */ + if (client->data.public_key) + silc_hash_table_del_by_context(server->pk_hash, + client->data.public_key, + client); + /* Remove the client */ silc_idlist_del_data(client); silc_idlist_del_client(local ? server->local_list : @@ -1604,8 +1641,15 @@ void silc_server_notify(SilcServer server, FALSE, TRUE); /* Check if anyone is watching this nickname */ - silc_server_check_watcher_list(server, client, NULL, - SILC_NOTIFY_TYPE_KILLED); + if (server->server_type == SILC_ROUTER) + silc_server_check_watcher_list(server, client, NULL, + SILC_NOTIFY_TYPE_KILLED); + + /* Remove from public key hash table. */ + if (client->data.public_key) + silc_hash_table_del_by_context(server->pk_hash, + client->data.public_key, + client); /* Update statistics */ server->stat.clients--; @@ -1622,6 +1666,9 @@ void silc_server_notify(SilcServer server, } client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; + client->mode = 0; + client->router = NULL; + client->connection = NULL; cache->expire = SILC_ID_CACHE_EXPIRE_DEF; break; } @@ -1741,15 +1788,16 @@ void silc_server_notify(SilcServer server, if (!iargs) goto out; - if (action != 0x01 && !channel->ban_list) + if (!channel->ban_list) channel->ban_list = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL, silc_server_inviteban_destruct, channel, TRUE); /* Proces the ban action */ - silc_server_inviteban_process(server, channel->ban_list, action, - iargs); + if (!silc_server_inviteban_process(server, channel->ban_list, action, + iargs)) + goto out; silc_argument_payload_free(iargs); /* If we are router we must send this notify to our local servers on @@ -1789,6 +1837,11 @@ void silc_server_notify(SilcServer server, client = silc_idlist_find_client_by_id(server->global_list, client_id, FALSE, NULL); if (client) { + 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); @@ -2216,10 +2269,9 @@ SilcClientEntry silc_server_new_client(SilcServer server, SilcIDListData idata; char *username = NULL, *realname = NULL; SilcUInt16 username_len; - SilcUInt32 id_len; + SilcUInt32 id_len, tmp_len; int ret; - char *hostname, *nickname; - int nickfail = 0; + char *hostname, *nickname, *nicknamec; SILC_LOG_DEBUG(("Creating new client")); @@ -2282,17 +2334,30 @@ SilcClientEntry silc_server_new_client(SilcServer server, return NULL; } - if (username_len > 128) + if (username_len > 128) { username[128] = '\0'; + username_len = 128; + } - /* Check for bad characters for nickname, and modify the nickname if - it includes those. */ - if (silc_server_name_bad_chars(username, username_len)) { - nickname = silc_server_name_modify_bad(username, username_len); - } else { - nickname = strdup(username); + /* Check for valid username string */ + nicknamec = silc_identifier_check(username, username_len, + SILC_STRING_UTF8, 128, &tmp_len); + if (!nicknamec) { + silc_free(username); + silc_free(realname); + SILC_LOG_ERROR(("Client %s (%s) sent bad username string '%s', closing " + "connection", sock->hostname, sock->ip, username)); + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_INCOMPLETE_INFORMATION, + NULL); + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); + return NULL; } + /* Nickname is initially same as username */ + nickname = strdup(username); + /* Make sanity checks for the hostname of the client. If the hostname is provided in the `username' check that it is the same than the resolved hostname, or if not resolved the hostname that appears in @@ -2381,17 +2446,14 @@ SilcClientEntry silc_server_new_client(SilcServer server, } /* Create Client ID */ - while (!silc_id_create_client_id(server, server->id, server->rng, - server->md5hash, nickname, &client_id)) { - nickfail++; - if (nickfail > 9) { - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_BAD_NICKNAME, NULL); - if (sock->user_data) - silc_server_free_sock_user_data(server, sock, NULL); - return NULL; - } - snprintf(&nickname[strlen(nickname) - 1], 1, "%d", nickfail); + if (!silc_id_create_client_id(server, server->id, server->rng, + server->md5hash, nicknamec, + strlen(nicknamec), &client_id)) { + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_BAD_NICKNAME, NULL); + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); + return NULL; } /* If client marked as anonymous, scramble the username and hostname */ @@ -2422,7 +2484,7 @@ SilcClientEntry silc_server_new_client(SilcServer server, id_len = silc_id_get_len(client_id, SILC_ID_CLIENT); /* Add the client again to the ID cache */ - silc_idcache_add(server->local_list->clients, client->nickname, + silc_idcache_add(server->local_list->clients, nicknamec, client_id, client, 0, NULL); /* Notify our router about new client on the SILC network */ @@ -2468,7 +2530,7 @@ SilcServerEntry silc_server_new_server(SilcServer server, SilcServerEntry new_server, server_entry; SilcServerID *server_id; SilcIDListData idata; - unsigned char *server_name, *id_string; + unsigned char *server_name, *server_namec, *id_string; SilcUInt16 id_len, name_len; int ret; bool local = TRUE; @@ -2483,6 +2545,10 @@ SilcServerEntry silc_server_new_server(SilcServer server, new_server = (SilcServerEntry)sock->user_data; idata = (SilcIDListData)new_server; + /* Statistics */ + if (server->server_type == SILC_ROUTER) + server->stat.cell_servers++; + /* Remove the old cache entry */ if (!silc_idcache_del_by_context(server->local_list->servers, new_server)) { if (!silc_idcache_del_by_context(server->global_list->servers, @@ -2537,8 +2603,10 @@ SilcServerEntry silc_server_new_server(SilcServer server, return NULL; } - if (name_len > 256) - server_name[255] = '\0'; + if (name_len > 256) { + server_name[256] = '\0'; + name_len = 256; + } /* Get Server ID */ server_id = silc_id_str2id(id_string, id_len, SILC_ID_SERVER); @@ -2571,6 +2639,8 @@ SilcServerEntry silc_server_new_server(SilcServer server, server_id, TRUE, NULL); if (server_entry) { if (SILC_IS_LOCAL(server_entry)) { + SILC_LOG_ERROR(("Too many registrations from %s (%s)", + sock->ip, sock->hostname)); silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_OPERATION_ALLOWED, "Too many registrations"); @@ -2585,6 +2655,8 @@ SilcServerEntry silc_server_new_server(SilcServer server, server_id, TRUE, NULL); if (server_entry) { if (SILC_IS_LOCAL(server_entry)) { + SILC_LOG_ERROR(("Too many registrations from %s (%s)", + sock->ip, sock->hostname)); silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_OPERATION_ALLOWED, "Too many registrations"); @@ -2598,6 +2670,20 @@ SilcServerEntry silc_server_new_server(SilcServer server, } } + /* Check server name */ + server_namec = silc_identifier_check(server_name, strlen(server_name), + SILC_STRING_UTF8, 256, NULL); + if (!server_namec) { + SILC_LOG_ERROR(("Malformed server name from %s (%s)", + sock->ip, sock->hostname)); + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_OPERATION_ALLOWED, + "Malfromed server name"); + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); + return NULL; + } + /* Update server entry */ idata->status |= SILC_IDLIST_STATUS_REGISTERED; new_server->server_name = server_name; @@ -2608,7 +2694,7 @@ SilcServerEntry silc_server_new_server(SilcServer server, /* Add again the entry to the ID cache. */ silc_idcache_add(local ? server->local_list->servers : - server->global_list->servers, server_name, server_id, + server->global_list->servers, server_namec, server_id, new_server, 0, NULL); /* Distribute the information about new server in the SILC network @@ -2626,9 +2712,6 @@ SilcServerEntry silc_server_new_server(SilcServer server, silc_server_backup_send(server, sock->user_data, SILC_PACKET_NEW_ID, 0, idp->data, idp->len, FALSE, TRUE); silc_buffer_free(idp); - - /* Statistics */ - server->stat.cell_servers++; } /* Check whether this router connection has been replaced by an @@ -2806,6 +2889,21 @@ static void silc_server_new_id_real(SilcServer server, /* Check if anyone is watching this nickname */ if (server->server_type == SILC_ROUTER && id_list == server->local_list) silc_server_check_watcher_list(server, entry, NULL, 0); + + if (server->server_type == SILC_ROUTER) { + /* Add the client's public key to hash table or get the key with + GETKEY command. */ + if (entry->data.public_key) { + if (!silc_hash_table_find_by_context(server->pk_hash, + entry->data.public_key, + entry, NULL)) + silc_hash_table_add(server->pk_hash, entry->data.public_key, + entry); + } else + silc_server_send_command(server, router_sock, + SILC_COMMAND_GETKEY, ++server->cmd_ident, + 1, 1, buffer->data, buffer->len); + } } break; @@ -2980,7 +3078,7 @@ void silc_server_new_channel(SilcServer server, { SilcChannelPayload payload; SilcChannelID *channel_id; - char *channel_name; + char *channel_name, *channel_namec = NULL; SilcUInt32 name_len; unsigned char *id; SilcUInt32 id_len, cipher_len; @@ -3007,8 +3105,16 @@ void silc_server_new_channel(SilcServer server, } channel_name = silc_channel_get_name(payload, &name_len); - if (name_len > 256) - channel_name[255] = '\0'; + if (name_len > 256) { + channel_name[256] = '\0'; + name_len = 256; + } + + /* Check channel name */ + channel_namec = silc_channel_name_check(channel_name, strlen(channel_name), + SILC_STRING_UTF8, 256, NULL); + if (!channel_namec) + return; id = silc_channel_get_id(payload, &id_len); @@ -3020,10 +3126,10 @@ void silc_server_new_channel(SilcServer server, /* Check that we don't already have this channel */ channel = silc_idlist_find_channel_by_name(server->local_list, - channel_name, NULL); + channel_namec, NULL); if (!channel) channel = silc_idlist_find_channel_by_name(server->global_list, - channel_name, NULL); + channel_namec, NULL); if (!channel) { SILC_LOG_DEBUG(("New channel id(%s) from [Router] %s", silc_id_render(channel_id, SILC_ID_CHANNEL), @@ -3054,10 +3160,10 @@ void silc_server_new_channel(SilcServer server, /* Check that we don't already have this channel */ channel = silc_idlist_find_channel_by_name(server->local_list, - channel_name, NULL); + channel_namec, NULL); if (!channel) channel = silc_idlist_find_channel_by_name(server->global_list, - channel_name, NULL); + channel_namec, NULL); /* If the channel does not exist, then create it. This creates a new key to the channel as well that we will send to the server. */ @@ -3244,6 +3350,7 @@ void silc_server_new_channel(SilcServer server, FALSE, TRUE); } + silc_free(channel_namec); silc_channel_payload_free(payload); } @@ -3556,9 +3663,9 @@ void silc_server_resume_client(SilcServer server, SilcIDCacheEntry id_cache = NULL; SilcClientEntry detached_client; SilcClientID *client_id = NULL; - unsigned char *id_string, *auth = NULL; + unsigned char *id_string, *auth = NULL, *nicknamec = NULL; SilcUInt16 id_len, auth_len = 0; - int ret, nickfail = 0; + int ret; bool resolved, local, nick_change = FALSE, resolve = FALSE; SilcChannelEntry channel; SilcHashTableList htl; @@ -3631,6 +3738,36 @@ void silc_server_resume_client(SilcServer server, return; } + if (detached_client->data.status & SILC_IDLIST_STATUS_RESUMED) { + SILC_LOG_ERROR(("Client %s (%s) tried to attach more than once, " + "closing connection", sock->hostname, sock->ip)); + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_INCOMPLETE_INFORMATION, + "Resuming not possible"); + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); + silc_free(client_id); + + return; + } + + if (detached_client->resuming_client && + detached_client->resuming_client != client) { + SILC_LOG_ERROR(("Client %s (%s) tried to attach more than once, " + "closing connection", sock->hostname, sock->ip)); + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_INCOMPLETE_INFORMATION, + "Resuming not possible"); + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); + silc_free(client_id); + + return; + } + + if (!detached_client->resuming_client) + detached_client->resuming_client = client; + if (!(detached_client->mode & SILC_UMODE_DETACHED)) resolve = TRUE; if (!silc_hash_table_count(detached_client->channels) && @@ -3748,15 +3885,58 @@ void silc_server_resume_client(SilcServer server, return; } + /* Check nickname */ + nicknamec = silc_identifier_check(detached_client->nickname, + strlen(detached_client->nickname), + SILC_STRING_UTF8, 128, NULL); + if (!nicknamec) { + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_BAD_NICKNAME, + "Malformed nickname, cannot resume"); + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); + return; + } + + /* If the ID is not based in our ID then change it */ + if (!SILC_ID_COMPARE(detached_client->id, server->id, + server->id->ip.data_len)) { + silc_free(client_id); + if (!silc_id_create_client_id(server, server->id, server->rng, + server->md5hash, nicknamec, + strlen(nicknamec), &client_id)) { + silc_server_disconnect_remote(server, sock, + SILC_STATUS_ERR_BAD_NICKNAME, + "Resuming not possible"); + if (sock->user_data) + silc_server_free_sock_user_data(server, sock, NULL); + return; + } + nick_change = TRUE; + } + /* Now resume the client to the network */ silc_schedule_task_del_by_context(server->schedule, detached_client); sock->user_data = detached_client; detached_client->connection = sock; + if (detached_client->data.public_key) + silc_hash_table_del_by_context(server->pk_hash, + detached_client->data.public_key, + detached_client); + if (idata->public_key) + silc_hash_table_del_by_context(server->pk_hash, + idata->public_key, idata); + /* Take new keys and stuff into use in the old entry */ silc_idlist_del_data(detached_client); silc_idlist_add_data(detached_client, idata); + + if (detached_client->data.public_key) + silc_hash_table_add(server->pk_hash, + detached_client->data.public_key, detached_client); + detached_client->data.status |= SILC_IDLIST_STATUS_REGISTERED; detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED; detached_client->data.status |= SILC_IDLIST_STATUS_LOCAL; @@ -3764,6 +3944,28 @@ void silc_server_resume_client(SilcServer server, detached_client->mode &= ~SILC_UMODE_DETACHED; server->stat.my_detached--; + /* We are finished - reset resuming client */ + detached_client->resuming_client = NULL; + + /* Check if anyone is watching this client */ + if (server->server_type == SILC_ROUTER) + silc_server_check_watcher_list(server, detached_client, NULL, + SILC_NOTIFY_TYPE_UMODE_CHANGE); + + /* Delete this current client entry since we're resuming to old one. */ + server->stat.my_clients--; + server->stat.clients--; + if (server->stat.cell_clients) + server->stat.cell_clients--; + silc_server_remove_from_channels(server, NULL, client, FALSE, + NULL, FALSE, FALSE); + silc_server_del_from_watcher_list(server, client); + if (!silc_idlist_del_client(server->local_list, client)) + silc_idlist_del_client(server->global_list, client); + client = detached_client; + silc_free(client->servername); + client->servername = strdup(server->server_name); + /* Send the RESUME_CLIENT packet to our primary router so that others know this client isn't detached anymore. */ buf = silc_buffer_alloc_size(2 + id_len); @@ -3776,54 +3978,19 @@ void silc_server_resume_client(SilcServer server, silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), SILC_PACKET_RESUME_CLIENT, 0, buf->data, buf->len, TRUE); - silc_server_backup_send(server, detached_client->router, + silc_server_backup_send(server, client->router, SILC_PACKET_RESUME_CLIENT, 0, buf->data, buf->len, TRUE, TRUE); /* As router we must deliver this packet directly to the original server whom this client was earlier. */ - if (server->server_type == SILC_ROUTER && detached_client->router && - detached_client->router->server_type != SILC_ROUTER) - silc_server_packet_send(server, detached_client->router->connection, + if (server->server_type == SILC_ROUTER && client->router && + client->router->server_type != SILC_ROUTER) + silc_server_packet_send(server, client->router->connection, SILC_PACKET_RESUME_CLIENT, 0, buf->data, buf->len, TRUE); silc_buffer_free(buf); - - detached_client->router = NULL; - - /* Delete this client entry since we're resuming to old one. */ - server->stat.my_clients--; - server->stat.clients--; - if (server->stat.cell_clients) - server->stat.cell_clients--; - silc_server_remove_from_channels(server, NULL, client, FALSE, - NULL, FALSE, FALSE); - silc_server_del_from_watcher_list(server, client); - if (!silc_idlist_del_client(server->local_list, client)) - silc_idlist_del_client(server->global_list, client); - client = detached_client; - silc_free(client->servername); - client->servername = strdup(server->server_name); - - /* If the ID is not based in our ID then change it */ - if (!SILC_ID_COMPARE(client->id, server->id, server->id->ip.data_len)) { - silc_free(client_id); - while (!silc_id_create_client_id(server, server->id, server->rng, - server->md5hash, client->nickname, - &client_id)) { - nickfail++; - if (nickfail > 9) { - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_BAD_NICKNAME, NULL); - if (sock->user_data) - silc_server_free_sock_user_data(server, sock, NULL); - return; - } - snprintf(&client->nickname[strlen(client->nickname) - 1], 1, - "%d", nickfail); - } - nick_change = TRUE; - } + client->router = NULL; if (nick_change) { /* Notify about Client ID change, nickname doesn't actually change. */ @@ -3837,7 +4004,7 @@ void silc_server_resume_client(SilcServer server, haven't resolved user list yet. */ if (server->server_type == SILC_SERVER && !server->standalone) { silc_hash_table_list(client->channels, &htl); - while (silc_hash_table_get(&htl, NULL, (void **)&chl)) { + while (silc_hash_table_get(&htl, NULL, (void *)&chl)) { channel = chl->channel; SILC_LOG_DEBUG(("Resolving users for %s channel", channel->channel_name)); @@ -3877,7 +4044,7 @@ void silc_server_resume_client(SilcServer server, silc_free(client->id); client->id = client_id; client_id = NULL; - silc_idcache_add(server->local_list->clients, client->nickname, + silc_idcache_add(server->local_list->clients, nicknamec, client->id, client, 0, NULL); /* Send some nice info to the client */ @@ -3885,7 +4052,7 @@ void silc_server_resume_client(SilcServer server, /* Send all channel keys of channels the client has joined */ silc_hash_table_list(client->channels, &htl); - while (silc_hash_table_get(&htl, NULL, (void **)&chl)) { + while (silc_hash_table_get(&htl, NULL, (void *)&chl)) { bool created = FALSE; channel = chl->channel; @@ -3974,6 +4141,17 @@ void silc_server_resume_client(SilcServer server, return; } + /* Check nickname */ + if (detached_client->nickname) { + nicknamec = silc_identifier_check(detached_client->nickname, + strlen(detached_client->nickname), + SILC_STRING_UTF8, 128, NULL); + if (!nicknamec) { + silc_free(client_id); + return; + } + } + SILC_LOG_DEBUG(("Resuming detached client")); /* If the sender of this packet is server and we are router we need to @@ -3994,12 +4172,23 @@ void silc_server_resume_client(SilcServer server, /* Client is detached, and now it is resumed. Remove the detached mode and mark that it is resumed. */ + + if (detached_client->data.public_key) + silc_hash_table_del_by_context(server->pk_hash, + detached_client->data.public_key, + detached_client); + silc_idlist_del_data(detached_client); detached_client->mode &= ~SILC_UMODE_DETACHED; detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED; detached_client->data.status &= ~SILC_IDLIST_STATUS_LOCAL; id_cache->expire = 0; + /* Check if anyone is watching this client */ + if (server->server_type == SILC_ROUTER) + silc_server_check_watcher_list(server, detached_client, NULL, + SILC_NOTIFY_TYPE_UMODE_CHANGE); + silc_schedule_task_del_by_context(server->schedule, detached_client); /* Get the new owner of the resumed client */ @@ -4037,8 +4226,7 @@ void silc_server_resume_client(SilcServer server, detached_client); silc_idcache_add(local && server->server_type == SILC_ROUTER ? server->local_list->clients : - server->global_list->clients, - detached_client->nickname, + server->global_list->clients, nicknamec, detached_client->id, detached_client, FALSE, NULL); /* Change the owner of the client */ @@ -4047,7 +4235,7 @@ void silc_server_resume_client(SilcServer server, /* Update channel information regarding global clients on channel. */ if (server->server_type != SILC_ROUTER) { silc_hash_table_list(detached_client->channels, &htl); - while (silc_hash_table_get(&htl, NULL, (void **)&chl)) + while (silc_hash_table_get(&htl, NULL, (void *)&chl)) chl->channel->global_users = silc_server_channel_has_global(chl->channel); silc_hash_table_list_reset(&htl);