X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Fsilcd%2Fpacket_receive.c;fp=apps%2Fsilcd%2Fpacket_receive.c;h=0000000000000000000000000000000000000000;hb=72c2de619079457f7a68100eb13385275a424a23;hp=9b990ff8d5fb587bec5a973171ec2e7400e9fd1d;hpb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;p=runtime.git diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c deleted file mode 100644 index 9b990ff8..00000000 --- a/apps/silcd/packet_receive.c +++ /dev/null @@ -1,4003 +0,0 @@ -/* - - packet_receive.c - - Author: Pekka Riikonen - - Copyright (C) 1997 - 2007 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. - - 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 - GNU General Public License for more details. - -*/ - -#include "serverincludes.h" -#include "server_internal.h" - -/* Received notify packet. Server can receive notify packets from router. - Server then relays the notify messages to clients if needed. */ - -static void silc_server_notify_process(SilcServer server, - SilcPacketStream sock, - SilcPacket packet, - SilcBuffer buffer) -{ - SilcIDListData idata = silc_packet_get_context(sock); - SilcNotifyPayload payload; - SilcNotifyType type; - SilcArgumentPayload args; - SilcChannelID channel_id; - SilcID id, id2; - SilcChannelEntry channel = NULL; - SilcClientEntry client = NULL, client2 = NULL; - SilcServerEntry server_entry = NULL; - SilcChannelClientEntry chl; - SilcIDCacheEntry cache = NULL; - SilcHashTableList htl; - SilcUInt32 mode; - unsigned char *tmp, *tmp2; - SilcUInt32 tmp_len, tmp2_len; - SilcBool local, ret; - - if (idata->conn_type == SILC_CONN_CLIENT) { - SILC_LOG_DEBUG(("Notify received from client, drop it")); - return; - } - - if (packet->src_id_type != SILC_ID_SERVER){ - SILC_LOG_DEBUG(("Bad notify packet received")); - return; - } - - if (!packet->dst_id) { - SILC_LOG_DEBUG(("Bad notify packet received")); - return; - } - - /* If the packet is destined directly to a client then relay the packet - before processing it. */ - if (packet->dst_id_type == SILC_ID_CLIENT) { - SilcIDListData idata; - SilcPacketStream dst_sock; - - /* Get the route to the client */ - dst_sock = silc_server_get_client_route(server, packet->dst_id, - packet->dst_id_len, NULL, - &idata, NULL); - if (dst_sock) - /* Relay the packet */ - silc_server_packet_route(server, dst_sock, packet); - } - - /* Parse the Notify Payload */ - payload = silc_notify_payload_parse(buffer->data, silc_buffer_len(buffer)); - if (!payload) { - SILC_LOG_DEBUG(("Marlformed notify payload")); - return; - } - - /* If we are router and this packet is not already broadcast packet - we will broadcast it. The sending socket really cannot be router or - the router is buggy. If this packet is coming from router then it must - have the broadcast flag set already and we won't do anything. */ - if (server->server_type == SILC_ROUTER && - idata->conn_type == SILC_CONN_SERVER && - !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) { - SILC_LOG_DEBUG(("Broadcasting received Notify packet")); - if (packet->dst_id_type == SILC_ID_CHANNEL) { - /* Packet is destined to channel */ - if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, - packet->dst_id_type, &channel_id, - sizeof(channel_id))) { - SILC_LOG_DEBUG(("Malformed destination ID in notify packet")); - goto out; - } - - silc_server_packet_send_dest(server, SILC_PRIMARY_ROUTE(server), - packet->type, packet->flags | - SILC_PACKET_FLAG_BROADCAST, - &channel_id, SILC_ID_CHANNEL, - buffer->data, silc_buffer_len(buffer)); - silc_server_backup_send_dest(server, (SilcServerEntry)idata, - packet->type, packet->flags, - &channel_id, SILC_ID_CHANNEL, - buffer->data, silc_buffer_len(buffer), - FALSE, TRUE); - } else { - /* Packet is destined to client or server */ - silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), - packet->type, - packet->flags | SILC_PACKET_FLAG_BROADCAST, - buffer->data, silc_buffer_len(buffer)); - silc_server_backup_send(server, (SilcServerEntry)idata, - packet->type, packet->flags, - buffer->data, silc_buffer_len(buffer), - FALSE, TRUE); - } - } - - type = silc_notify_get_type(payload); - args = silc_notify_get_args(payload); - if (!args) { - SILC_LOG_DEBUG(("Notify doesn't have any arguments, drop it")); - goto out; - } - - switch(type) { - case SILC_NOTIFY_TYPE_JOIN: - /* - * Distribute the notify to local clients on the channel - */ - SILC_LOG_DEBUG(("JOIN notify")); - - /* Get Channel ID */ - if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* Get channel entry */ - channel = silc_idlist_find_channel_by_id(server->global_list, - SILC_ID_GET_ID(id), NULL); - if (!channel) { - channel = silc_idlist_find_channel_by_id(server->local_list, - SILC_ID_GET_ID(id), NULL); - if (!channel) { - SILC_LOG_DEBUG(("Notify for unknown channel %s", - silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL))); - goto out; - } - } - - /* Get client ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* If the the client is not in local list we check global list (ie. the - channel will be global channel) and if it does not exist then create - entry for the client. */ - client = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), - server->server_type, - &cache); - if (!client) { - client = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id), - server->server_type, - &cache); - if (!client) { - /* If router did not find the client the it is bogus */ - if (server->server_type != SILC_SERVER) - goto out; - - client = - silc_idlist_add_client(server->global_list, NULL, NULL, NULL, - silc_id_dup(SILC_ID_GET_ID(id), - SILC_ID_CLIENT), - (SilcServerEntry)idata, NULL); - if (!client) { - SILC_LOG_ERROR(("Could not add new client to the ID Cache")); - goto out; - } - - client->data.status |= SILC_IDLIST_STATUS_REGISTERED; - } - } - - /* Do not process the notify if the client is not registered */ - if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) - break; - - /* Do not add client to channel if it is there already */ - if (silc_server_client_on_channel(client, channel, NULL)) { - SILC_LOG_DEBUG(("Client already on channel %s", - channel->channel_name)); - break; - } - - /* Send to channel */ - silc_server_packet_send_to_channel(server, sock, channel, packet->type, - FALSE, TRUE, buffer->data, - silc_buffer_len(buffer)); - - if (server->server_type != SILC_ROUTER && - idata->conn_type == SILC_CONN_ROUTER) - /* The channel is global now */ - channel->global_users = TRUE; - - SILC_LOG_DEBUG(("Joining to channel %s", channel->channel_name)); - - /* JOIN the global client to the channel (local clients (if router - created the channel) is joined in the pending JOIN command). */ - chl = silc_calloc(1, sizeof(*chl)); - if (!chl) - goto out; - chl->client = client; - chl->channel = channel; - - if (server->server_type != SILC_ROUTER || - idata->conn_type == SILC_CONN_ROUTER) { - /* 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); - } - } - } - - silc_hash_table_add(channel->user_list, client, chl); - silc_hash_table_add(client->channels, channel, chl); - channel->user_count++; - channel->disabled = FALSE; - - /* Update statistics */ - if (server->server_type == SILC_ROUTER) { - if (idata->conn_type != SILC_CONN_ROUTER) - server->stat.cell_chanclients++; - server->stat.chanclients++; - } - - break; - - case SILC_NOTIFY_TYPE_LEAVE: - /* - * Distribute the notify to local clients on the channel - */ - SILC_LOG_DEBUG(("LEAVE notify")); - - if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, - packet->dst_id_type, &channel_id, - sizeof(channel_id))) - goto out; - - /* Get channel entry */ - channel = silc_idlist_find_channel_by_id(server->global_list, - &channel_id, NULL); - if (!channel) { - channel = silc_idlist_find_channel_by_id(server->local_list, - &channel_id, NULL); - if (!channel) { - SILC_LOG_DEBUG(("Notify for unknown channel %s", - silc_id_render(&channel_id, SILC_ID_CHANNEL))); - goto out; - } - } - - /* Get client ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* Get client entry */ - client = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), TRUE, NULL); - if (!client) { - client = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id), TRUE, NULL); - if (!client) - goto out; - } - - /* Check if on channel */ - if (!silc_server_client_on_channel(client, channel, NULL)) - break; - - /* Send the leave notify to channel */ - silc_server_packet_send_to_channel(server, sock, channel, packet->type, - FALSE, TRUE, buffer->data, - silc_buffer_len(buffer)); - - /* Remove the user from channel */ - silc_server_remove_from_one_channel(server, sock, channel, client, FALSE); - break; - - case SILC_NOTIFY_TYPE_SIGNOFF: - /* - * Distribute the notify to local clients on the channel - */ - SILC_LOG_DEBUG(("SIGNOFF notify")); - - /* Get client ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* Get client entry */ - client = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), TRUE, &cache); - if (!client) { - client = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id), TRUE, &cache); - if (!client) - goto out; - } - - /* Get signoff message */ - tmp = silc_argument_get_arg_type(args, 2, &tmp_len); - if (tmp_len > 128) - tmp_len = 128; - - /* Update statistics */ - server->stat.clients--; - if (server->stat.cell_clients) - server->stat.cell_clients--; - SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR); - SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR); - silc_schedule_task_del_by_context(server->schedule, client); - - /* Remove client's public key from repository, this will free it too. */ - if (client->data.public_key) { - silc_skr_del_public_key(server->repository, client->data.public_key, - client); - client->data.public_key = NULL; - } - - /* Remove the client from all channels. */ - silc_server_remove_from_channels(server, NULL, client, TRUE, - tmp, FALSE, FALSE); - - /* Check if anyone is watching this nickname */ - if (server->server_type == SILC_ROUTER) - silc_server_check_watcher_list(server, client, NULL, - SILC_NOTIFY_TYPE_SIGNOFF); - - /* Remove this client from watcher list if it is */ - silc_server_del_from_watcher_list(server, client); - - client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; - client->mode = 0; - client->router = NULL; - client->connection = NULL; - silc_dlist_add(server->expired_clients, client); - break; - - case SILC_NOTIFY_TYPE_TOPIC_SET: - /* - * Distribute the notify to local clients on the channel - */ - - SILC_LOG_DEBUG(("TOPIC SET notify")); - - /* Get client ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* Get client entry */ - if (id.type == SILC_ID_CLIENT) { - client = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), TRUE, &cache); - if (!client) { - client = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id), - TRUE, &cache); - if (!client) - goto out; - } - } - - /* Get the topic */ - tmp = silc_argument_get_arg_type(args, 2, &tmp_len); - if (!tmp) - goto out; - - if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, - packet->dst_id_type, &channel_id, - sizeof(channel_id))) - goto out; - - /* Get channel entry */ - channel = silc_idlist_find_channel_by_id(server->global_list, - &channel_id, NULL); - if (!channel) { - channel = silc_idlist_find_channel_by_id(server->local_list, - &channel_id, NULL); - if (!channel) { - SILC_LOG_DEBUG(("Notify for unknown channel %s", - silc_id_render(&channel_id, SILC_ID_CHANNEL))); - goto out; - } - } - - if (channel->topic && !strcmp(channel->topic, tmp)) { - SILC_LOG_DEBUG(("Topic is already set and same")); - goto out; - } - - if (client) { - /* Get user's channel entry and check that topic set is allowed. */ - if (!silc_server_client_on_channel(client, channel, &chl)) - goto out; - if (channel->mode & SILC_CHANNEL_MODE_TOPIC && - !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) && - !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) { - SILC_LOG_DEBUG(("Topic change is not allowed")); - goto out; - } - } - - /* Change the topic */ - silc_free(channel->topic); - channel->topic = strdup(tmp); - - /* Send the same notify to the channel */ - silc_server_packet_send_to_channel(server, NULL, channel, packet->type, - FALSE, TRUE, buffer->data, - silc_buffer_len(buffer)); - break; - - case SILC_NOTIFY_TYPE_NICK_CHANGE: - { - /* - * Distribute the notify to local clients on the channel - */ - char *nickname; - SilcUInt32 nickname_len; - - SILC_LOG_DEBUG(("NICK CHANGE notify")); - - /* Get old client ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* Get new client ID */ - if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL)) - goto out; - - SILC_LOG_DEBUG(("Old Client ID id(%s)", - silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CLIENT))); - SILC_LOG_DEBUG(("New Client ID id(%s)", - silc_id_render(SILC_ID_GET_ID(id2), SILC_ID_CLIENT))); - - /* From protocol version 1.1 we also get the new nickname */ - nickname = silc_argument_get_arg_type(args, 3, &nickname_len);; - - /* Replace the Client ID */ - client = silc_idlist_replace_client_id(server, - server->global_list, - SILC_ID_GET_ID(id), - SILC_ID_GET_ID(id2), nickname); - if (!client) - client = silc_idlist_replace_client_id(server, - server->local_list, - SILC_ID_GET_ID(id), - SILC_ID_GET_ID(id2), nickname); - - if (client) { - /* Send the NICK_CHANGE notify type to local clients on the channels - this client is joined to. */ - tmp = silc_argument_get_arg_type(args, 1, &tmp_len); - tmp2 = silc_argument_get_arg_type(args, 2, &tmp2_len); - silc_server_send_notify_on_channels(server, client, client, - SILC_NOTIFY_TYPE_NICK_CHANGE, 3, - tmp, tmp_len, tmp2, tmp2_len, - nickname, nickname ? - nickname_len : 0); - } - - break; - } - - case SILC_NOTIFY_TYPE_CMODE_CHANGE: - /* - * Distribute the notify to local clients on the channel - */ - - SILC_LOG_DEBUG(("CMODE CHANGE notify")); - - /* Get client ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* Get client entry */ - if (id.type == SILC_ID_CLIENT) { - client = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), TRUE, &cache); - if (!client) { - client = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id), - TRUE, &cache); - if (!client) - goto out; - } - } - - if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, - packet->dst_id_type, &channel_id, - sizeof(channel_id))) - goto out; - - /* Get channel entry */ - channel = silc_idlist_find_channel_by_id(server->global_list, - &channel_id, NULL); - if (!channel) { - channel = silc_idlist_find_channel_by_id(server->local_list, - &channel_id, NULL); - if (!channel) { - SILC_LOG_DEBUG(("Notify for unknown channel %s", - silc_id_render(&channel_id, SILC_ID_CHANNEL))); - goto out; - } - } - - /* Get the mode */ - tmp = silc_argument_get_arg_type(args, 2, &tmp_len); - if (!tmp) - goto out; - SILC_GET32_MSB(mode, tmp); - - /* Check if mode changed */ - if (channel->mode == mode) { - SILC_LOG_DEBUG(("Mode is changed already")); - - /* If this mode change has founder mode then we'll enforce the - change so that the server gets the real founder public key */ - if (server->server_type != SILC_SERVER && - sock != SILC_PRIMARY_ROUTE(server) && - mode & SILC_CHANNEL_MODE_FOUNDER_AUTH && channel->founder_key) { - SILC_LOG_DEBUG(("Sending founder public key to server")); - silc_server_send_notify_cmode(server, sock, FALSE, channel, - channel->mode, server->id, - SILC_ID_SERVER, channel->cipher, - channel->hmac_name, - channel->passphrase, - channel->founder_key, NULL); - } - - /* If we received same mode from our primary check whether founder - mode and key in the notify is set. We update the founder key - here since we may have wrong one */ - if (server->server_type != SILC_ROUTER && - sock == SILC_PRIMARY_ROUTE(server) && - mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) { - SILC_LOG_DEBUG(("Founder public key received from router")); - tmp = silc_argument_get_arg_type(args, 6, &tmp_len); - if (!tmp) - break; - - if (channel->founder_key) - silc_pkcs_public_key_free(channel->founder_key); - channel->founder_key = NULL; - silc_public_key_payload_decode(tmp, tmp_len, - &channel->founder_key); - } - - /* Check also for channel public key list */ - if (server->server_type == SILC_SERVER && - sock == SILC_PRIMARY_ROUTE(server) && - mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) { - SilcBuffer chpklist; - SilcBuffer sidp; - 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); - if (!tmp) - break; - - /* Set the router's list, and send the notify to channel too so that - channel gets the list */ - silc_server_set_channel_pk_list(server, sock, channel, tmp, tmp_len); - chpklist = silc_server_get_channel_pk_list(server, channel, - FALSE, FALSE); - if (!chpklist) - 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, 8, - sidp->data, silc_buffer_len(sidp), - mask, 4, - channel->cipher, - channel->cipher ? - strlen(channel->cipher) : 0, - channel->hmac_name, - channel->hmac_name ? - strlen(channel->hmac_name) : 0, - channel->passphrase, - channel->passphrase ? - strlen(channel->passphrase) : 0, - NULL, 0, - chpklist->data, - silc_buffer_len(chpklist), - (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; - } - - break; - } - - /* Get user's channel entry and check that mode change is allowed */ - if (client) { - if (!silc_server_client_on_channel(client, channel, &chl)) - goto out; - if (!silc_server_check_cmode_rights(server, channel, chl, mode)) { - SILC_LOG_DEBUG(("CMODE change is not allowed")); - silc_server_send_notify_cmode(server, sock, FALSE, channel, - channel->mode, server->id, - SILC_ID_SERVER, channel->cipher, - channel->hmac_name, - channel->passphrase, - channel->founder_key, NULL); - goto out; - } - } else { - /* Assure that server is not removing founder mode from us */ - if (server->server_type == SILC_ROUTER && - sock != SILC_PRIMARY_ROUTE(server) && - channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH && - !(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) { - SILC_LOG_DEBUG(("Enforcing sender to change channel mode")); - silc_server_send_notify_cmode(server, sock, FALSE, channel, - channel->mode, server->id, - SILC_ID_SERVER, channel->cipher, - channel->hmac_name, - channel->passphrase, - channel->founder_key, NULL); - goto out; - } - - /* If server is adding founder mode, check whether there is founder - on channel already and is not from this server */ - if (server->server_type == SILC_ROUTER && - sock != SILC_PRIMARY_ROUTE(server) && - mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) { - silc_hash_table_list(channel->user_list, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chl)) - if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && - chl->client->router != (SilcServerEntry)idata) { - SILC_LOG_DEBUG(("Enforcing sender to change channel mode")); - silc_server_send_notify_cmode(server, sock, FALSE, channel, - channel->mode, server->id, - SILC_ID_SERVER, channel->cipher, - channel->hmac_name, - channel->passphrase, - channel->founder_key, NULL); - silc_hash_table_list_reset(&htl); - goto out; - } - silc_hash_table_list_reset(&htl); - } - } - - /* If the channel had private keys set and the mode was removed then - we must re-generate and re-distribute a new channel key */ - if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY && - !(mode & SILC_CHANNEL_MODE_PRIVKEY)) { - /* Re-generate channel key */ - if (!silc_server_create_channel_key(server, channel, 0)) - goto out; - - /* Send the channel key. This sends it to our local clients and if - we are normal server to our router as well. */ - silc_server_send_channel_key(server, NULL, channel, - server->server_type == SILC_ROUTER ? - FALSE : !server->standalone); - } - - /* Get the hmac */ - tmp = silc_argument_get_arg_type(args, 4, &tmp_len); - if (tmp) { - unsigned char hash[SILC_HASH_MAXLEN]; - - if (channel->hmac) - silc_hmac_free(channel->hmac); - if (!silc_hmac_alloc(tmp, NULL, &channel->hmac)) - goto out; - - /* Set the HMAC key out of current channel key. The client must do - this locally. */ - silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, - channel->key_len / 8, hash); - silc_hmac_set_key(channel->hmac, hash, - silc_hash_len(silc_hmac_get_hash(channel->hmac))); - memset(hash, 0, sizeof(hash)); - } - - /* Get the passphrase */ - tmp = silc_argument_get_arg_type(args, 5, &tmp_len); - if (tmp) { - silc_free(channel->passphrase); - channel->passphrase = silc_memdup(tmp, tmp_len); - } - - /* Get founder public key */ - tmp = silc_argument_get_arg_type(args, 6, &tmp_len); - if (tmp && mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) { - 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_public_key_payload_decode(tmp, tmp_len, - &channel->founder_key)) { - SILC_LOG_DEBUG(("Enforcing sender to change channel mode")); - mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH; - silc_server_send_notify_cmode(server, sock, FALSE, channel, - mode, server->id, SILC_ID_SERVER, - channel->cipher, - channel->hmac_name, - channel->passphrase, NULL, NULL); - if (channel->founder_key) - silc_pkcs_public_key_free(channel->founder_key); - channel->founder_key = NULL; - } - } - - if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH && !channel->founder_key && - server->server_type == SILC_ROUTER) { - SILC_LOG_DEBUG(("Enforcing sender to change channel mode")); - mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH; - silc_server_send_notify_cmode(server, sock, FALSE, channel, - mode, server->id, SILC_ID_SERVER, - channel->cipher, - channel->hmac_name, - channel->passphrase, NULL, NULL); - } - - /* Process channel public key(s). */ - tmp = silc_argument_get_arg_type(args, 7, &tmp_len); - if (tmp && mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) { - SilcStatus ret; - SILC_LOG_DEBUG(("Channel public key list received from router")); - - ret = - silc_server_set_channel_pk_list(server, sock, channel, tmp, tmp_len); - - /* If list was set already we will enforce the same list to server. */ - if (ret == SILC_STATUS_ERR_OPERATION_ALLOWED) { - SilcBuffer chpklist = silc_server_get_channel_pk_list(server, channel, - TRUE, FALSE); - silc_server_send_notify_cmode(server, sock, FALSE, channel, - mode, server->id, SILC_ID_SERVER, - channel->cipher, - channel->hmac_name, - channel->passphrase, NULL, - chpklist); - silc_buffer_free(chpklist); - } - } - - /* 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, buffer->data, - silc_buffer_len(buffer)); - - /* Change mode */ - channel->mode = mode; - - /* Cleanup if some modes are removed */ - - if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && - channel->founder_key) { - silc_pkcs_public_key_free(channel->founder_key); - channel->founder_key = NULL; - } - - if (!(channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) && - channel->channel_pubkeys) { - silc_hash_table_free(channel->channel_pubkeys); - channel->channel_pubkeys = NULL; - } - - break; - - case SILC_NOTIFY_TYPE_CUMODE_CHANGE: - { - /* - * Distribute the notify to local clients on the channel - */ - SilcChannelClientEntry chl2 = NULL; - SilcBool notify_sent = FALSE; - - SILC_LOG_DEBUG(("CUMODE CHANGE notify")); - - /* Get client ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* Get client entry */ - if (id.type == SILC_ID_CLIENT) { - client = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), - TRUE, &cache); - if (!client) { - client = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id), - TRUE, &cache); - if (!client) - goto out; - } - } - - if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, - packet->dst_id_type, &channel_id, - sizeof(channel_id))) - goto out; - - /* Get channel entry */ - channel = silc_idlist_find_channel_by_id(server->global_list, - &channel_id, NULL); - if (!channel) { - channel = silc_idlist_find_channel_by_id(server->local_list, - &channel_id, NULL); - if (!channel) { - SILC_LOG_DEBUG(("Notify for unknown channel %s", - silc_id_render(&channel_id, SILC_ID_CHANNEL))); - goto out; - } - } - - /* Get the mode */ - tmp = silc_argument_get_arg_type(args, 2, &tmp_len); - if (!tmp) - goto out; - - SILC_GET32_MSB(mode, tmp); - - /* Get target client */ - if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* Get client entry */ - client2 = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), TRUE, NULL); - if (!client2) { - client2 = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id), - TRUE, NULL); - if (!client2) - goto out; - } - - if (client) { - /* Check that sender is on channel */ - if (!silc_server_client_on_channel(client, channel, &chl)) - goto out; - - if (client != client2 && server->server_type == SILC_ROUTER) { - /* Sender must be operator */ - if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) && - !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) { - SILC_LOG_DEBUG(("CUMODE change is not allowed")); - goto out; - } - - if (!silc_server_client_on_channel(client2, channel, &chl)) - goto out; - - /* If target is founder mode change is not allowed. */ - if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) { - SILC_LOG_DEBUG(("CUMODE change is not allowed")); - goto out; - } - } - } - - /* Get target channel user entry */ - if (!silc_server_client_on_channel(client2, channel, &chl)) - goto out; - - if (server->server_type == SILC_SERVER && chl->mode == mode) { - SILC_LOG_DEBUG(("Mode is changed already")); - break; - } - - /* Check whether to give founder rights to this user or not. The - problem here is that we get only the public key of the client, - but no authentication data. We must assume that server has - already authenticated the user (and thus we must trust the - server). */ - if (mode & SILC_CHANNEL_UMODE_CHANFO && - !(chl->mode & SILC_CHANNEL_UMODE_CHANFO) && - server->server_type == SILC_ROUTER && - sock != SILC_PRIMARY_ROUTE(server)) { - SilcPublicKey founder_key = NULL; - - /* If channel doesn't have founder auth mode then it's impossible - that someone would be getting founder rights with CUMODE command. - In that case there already either is founder or there isn't - founder at all on the channel (valid only when 'client' is - valid). */ - if (client && !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) { - /* Force the mode to not have founder mode */ - chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO; - silc_server_force_cumode_change(server, sock, channel, chl, mode); - notify_sent = TRUE; - break; - } - - /* 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)) - 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); - notify_sent = TRUE; - break; - } - silc_hash_table_list_reset(&htl); - if (!(mode & SILC_CHANNEL_UMODE_CHANFO)) - break; - - /* 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. */ - - if (channel->founder_key) { - /* Get public key that must be present in notify */ - tmp = silc_argument_get_arg_type(args, 4, &tmp_len); - if (!tmp || !silc_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; - } - - /* Now match the public key we have cached and public key sent. - They must match. */ - 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; - } - } - - /* 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 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; - } - silc_hash_table_list_reset(&htl); - - if (founder_key) - silc_pkcs_public_key_free(founder_key); - } - - if (server->server_type != SILC_SERVER && chl->mode == mode) { - SILC_LOG_DEBUG(("Mode is changed already")); - break; - } - - SILC_LOG_DEBUG(("Changing %s channel user mode", - chl->client->nickname ? chl->client->nickname : - (unsigned char *)"")); - - /* Change the mode */ - chl->mode = mode; - - /* Send the same notify to the channel */ - if (!notify_sent) - silc_server_packet_send_to_channel(server, sock, channel, - packet->type, - FALSE, TRUE, buffer->data, - silc_buffer_len(buffer)); - - break; - } - - case SILC_NOTIFY_TYPE_INVITE: - - if (packet->dst_id_type == SILC_ID_CLIENT) - goto out; - - SILC_LOG_DEBUG(("INVITE notify")); - - /* Get Channel ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* Get channel entry */ - channel = silc_idlist_find_channel_by_id(server->global_list, - SILC_ID_GET_ID(id), NULL); - if (!channel) { - channel = silc_idlist_find_channel_by_id(server->local_list, - SILC_ID_GET_ID(id), NULL); - if (!channel) { - SILC_LOG_DEBUG(("Notify for unknown channel %s", - silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL))); - goto out; - } - } - - /* Get the invite action */ - tmp = silc_argument_get_arg_type(args, 4, &tmp_len); - if (tmp && tmp_len == 1) { - SilcUInt8 action = (SilcUInt8)tmp[0]; - SilcUInt16 iargc = 0; - SilcArgumentPayload iargs; - - /* Get invite list */ - tmp = silc_argument_get_arg_type(args, 5, &tmp_len); - if (!tmp || tmp_len < 2) - 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 (!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 */ - 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 - the channel. Normal server does nothing. The notify is not - sent to clients. */ - if (server->server_type == SILC_ROUTER) - silc_server_packet_send_to_channel(server, sock, channel, - packet->type, FALSE, FALSE, - buffer->data, - silc_buffer_len(buffer)); - } - - break; - - case SILC_NOTIFY_TYPE_CHANNEL_CHANGE: - /* - * Distribute to the local clients on the channel and change the - * channel ID. - */ - - SILC_LOG_DEBUG(("CHANNEL CHANGE")); - - if (idata->conn_type != SILC_CONN_ROUTER) - break; - - /* Get the old Channel ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* Get the channel entry */ - channel = silc_idlist_find_channel_by_id(server->local_list, - SILC_ID_GET_ID(id), NULL); - if (!channel) { - channel = silc_idlist_find_channel_by_id(server->global_list, - SILC_ID_GET_ID(id), NULL); - if (!channel) { - SILC_LOG_DEBUG(("Notify for unknown channel %s", - silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL))); - goto out; - } - } - - /* Send the notify to the channel */ - silc_server_packet_send_to_channel(server, sock, channel, packet->type, - FALSE, TRUE, buffer->data, - silc_buffer_len(buffer)); - - /* Get the new Channel ID */ - if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL)) - goto out; - - SILC_LOG_DEBUG(("Old Channel ID id(%s)", - silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL))); - SILC_LOG_DEBUG(("New Channel ID id(%s)", - silc_id_render(SILC_ID_GET_ID(id2), SILC_ID_CHANNEL))); - - /* Replace the Channel ID */ - ret = TRUE; - if (!silc_idlist_replace_channel_id(server->local_list, - SILC_ID_GET_ID(id), - SILC_ID_GET_ID(id2))) - if (!silc_idlist_replace_channel_id(server->global_list, - SILC_ID_GET_ID(id), - SILC_ID_GET_ID(id2))) - ret = FALSE; - - if (ret) { - SilcBuffer modes = NULL, users = NULL, users_modes = NULL; - - /* Re-announce this channel which ID was changed. */ - silc_server_send_new_channel(server, sock, FALSE, channel->channel_name, - channel->id, - silc_id_get_len(channel->id, - SILC_ID_CHANNEL), - channel->mode); - - /* Re-announce our clients on the channel as the ID has changed now */ - silc_server_announce_get_channel_users(server, channel, &modes, &users, - &users_modes); - if (users) { - silc_buffer_push(users, users->data - users->head); - silc_server_packet_send(server, sock, - SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST, - users->data, silc_buffer_len(users)); - silc_buffer_free(users); - } - if (modes) { - silc_buffer_push(modes, modes->data - modes->head); - silc_server_packet_send_dest(server, sock, - SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST, - channel->id, SILC_ID_CHANNEL, - modes->data, silc_buffer_len(modes)); - silc_buffer_free(modes); - } - if (users_modes) { - silc_buffer_push(users_modes, users_modes->data - users_modes->head); - silc_server_packet_send_dest(server, sock, - SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST, - channel->id, SILC_ID_CHANNEL, - users_modes->data, - silc_buffer_len(users_modes)); - silc_buffer_free(users_modes); - } - - /* Re-announce channel's topic */ - if (channel->topic) { - silc_server_send_notify_topic_set(server, sock, - server->server_type == SILC_ROUTER ? - TRUE : FALSE, channel, - server->id, SILC_ID_SERVER, - channel->topic); - } - } - - break; - - case SILC_NOTIFY_TYPE_SERVER_SIGNOFF: - /* - * Remove the server entry and all clients that this server owns. - */ - - SILC_LOG_DEBUG(("SERVER SIGNOFF notify")); - - /* Backup router shouldn't accept SERVER_SIGNOFF's from normal routers - when the backup isn't acting as primary router. */ - if (idata->conn_type == SILC_CONN_SERVER && - server->backup_router && server->server_type == SILC_BACKUP_ROUTER) - return; - - /* Get Server ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* If the ID is mine, this notify is not allowed. */ - if (SILC_ID_SERVER_COMPARE(SILC_ID_GET_ID(id), server->id)) { - SILC_LOG_DEBUG(("Ignoring my own ID for SERVER_SIGNOFF")); - break; - } - - /* Get server entry */ - server_entry = silc_idlist_find_server_by_id(server->global_list, - SILC_ID_GET_ID(id), - TRUE, NULL); - local = FALSE; - if (!server_entry) { - server_entry = silc_idlist_find_server_by_id(server->local_list, - SILC_ID_GET_ID(id), - TRUE, NULL); - local = TRUE; - if (!server_entry) { - /* If we are normal server then we might not have the server. Check - whether router was kind enough to send the list of all clients - that actually was to be removed. Remove them if the list is - available. */ - if (server->server_type != SILC_ROUTER && - silc_argument_get_arg_num(args) > 1) { - int i; - - for (i = 1; i < silc_argument_get_arg_num(args); i++) { - /* Get Client ID */ - if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, - &id2, NULL)) - continue; - - /* Get client entry */ - client = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id2), - TRUE, &cache); - local = FALSE; - if (!client) { - client = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id2), - TRUE, &cache); - local = TRUE; - if (!client) - continue; - } - - /* Update statistics */ - server->stat.clients--; - if (server->stat.cell_clients) - server->stat.cell_clients--; - SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR); - SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR); - - /* Remove the client from all channels. */ - silc_server_remove_from_channels(server, NULL, client, - TRUE, NULL, FALSE, FALSE); - - /* Check if anyone is watching this nickname */ - if (server->server_type == SILC_ROUTER) - silc_server_check_watcher_list(server, client, NULL, - SILC_NOTIFY_TYPE_SERVER_SIGNOFF); - - /* Remove this client from watcher list if it is */ - if (local) - silc_server_del_from_watcher_list(server, client); - - /* Remove the client */ - silc_idlist_del_data(client); - silc_idlist_del_client(local ? server->local_list : - server->global_list, client); - } - } - - goto out; - } - } - - /* For local entrys SERVER_SIGNOFF is processed only on backup router. - It is possible that router sends server signoff for a server. If - backup router has it as local connection it will be closed. */ - if (SILC_IS_LOCAL(server_entry)) { - if (server->server_type == SILC_BACKUP_ROUTER) { - sock = server_entry->connection; - SILC_LOG_DEBUG(("Closing connection after SERVER_SIGNOFF")); - silc_server_free_sock_user_data(server, sock, NULL); - silc_server_close_connection(server, sock); - } - - break; - } - - /* Remove all servers that are originated from this server, and - remove the clients of those servers too. */ - silc_server_remove_servers_by_server(server, server_entry, TRUE); - - /* Remove the clients that this server owns as they will become - invalid now too. */ - silc_server_remove_clients_by_server(server, server_entry->router, - server_entry, TRUE); - silc_server_backup_del(server, server_entry); - - /* Remove the server entry */ - silc_idlist_del_server(local ? server->local_list : - server->global_list, server_entry); - - /* Update statistics */ - if (server->server_type == SILC_ROUTER) - server->stat.servers--; - - break; - - case SILC_NOTIFY_TYPE_KICKED: - /* - * Distribute the notify to local clients on the channel - */ - - SILC_LOG_DEBUG(("KICKED notify")); - - if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, - packet->dst_id_type, &channel_id, - sizeof(channel_id))) - goto out; - - /* Get channel entry */ - channel = silc_idlist_find_channel_by_id(server->global_list, - &channel_id, NULL); - if (!channel) { - channel = silc_idlist_find_channel_by_id(server->local_list, - &channel_id, NULL); - if (!channel) { - SILC_LOG_DEBUG(("Notify for unknown channel %s", - silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL))); - goto out; - } - } - - /* Get client ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* If the the client is not in local list we check global list */ - client = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), TRUE, NULL); - if (!client) { - client = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id), TRUE, NULL); - if (!client) - goto out; - } - - /* If target is founder they cannot be kicked */ - if (!silc_server_client_on_channel(client, channel, &chl)) - goto out; - if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) - goto out; - - /* Get the kicker's Client ID */ - if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* If the the client is not in local list we check global list */ - client2 = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), TRUE, NULL); - if (!client2) { - client2 = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id), TRUE, NULL); - if (!client2) - goto out; - } - - /* Kicker must be operator on channel */ - if (!silc_server_client_on_channel(client2, channel, &chl)) - goto out; - if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) && - !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) { - SILC_LOG_DEBUG(("Kicking is not allowed")); - goto out; - } - - /* Send to channel */ - silc_server_packet_send_to_channel(server, sock, channel, packet->type, - FALSE, TRUE, buffer->data, - silc_buffer_len(buffer)); - - /* Remove the client from channel's invite list */ - if (channel->invite_list && silc_hash_table_count(channel->invite_list)) { - SilcBuffer ab; - SilcArgumentPayload iargs; - tmp = silc_argument_get_arg_type(args, 1, &tmp_len); - ab = silc_argument_payload_encode_one(NULL, tmp, tmp_len, 3); - iargs = silc_argument_payload_parse(ab->data, silc_buffer_len(ab), 1); - silc_server_inviteban_process(server, channel->invite_list, 1, iargs); - silc_buffer_free(ab); - silc_argument_payload_free(iargs); - } - - /* Remove the client from channel */ - silc_server_remove_from_one_channel(server, sock, channel, client, FALSE); - - break; - - case SILC_NOTIFY_TYPE_KILLED: - { - /* - * Distribute the notify to local clients on channels - */ - unsigned char *comment; - SilcUInt32 comment_len; - - SILC_LOG_DEBUG(("KILLED notify")); - - /* Get client ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* If the the client is not in local list we check global list */ - client = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), TRUE, &cache); - if (!client) { - client = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id), - TRUE, &cache); - if (!client) - goto out; - } - - /* If the client is one of ours, then close the connection to the - client now. This removes the client from all channels as well. */ - if (packet->dst_id_type == SILC_ID_CLIENT && client->connection) { - sock = client->connection; - silc_server_free_client_data(server, NULL, client, FALSE, NULL); - silc_server_close_connection(server, sock); - break; - } - - /* Get comment */ - comment = silc_argument_get_arg_type(args, 2, &comment_len); - if (comment_len > 128) - comment_len = 127; - - /* Get the killer's Client ID */ - if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - if (id.type == SILC_ID_CLIENT) { - /* If the the client is not in local list we check global list */ - client2 = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), - TRUE, NULL); - if (!client2) { - client2 = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id), - TRUE, NULL); - if (!client2) - goto out; - } - - /* Killer must be router operator */ - if (server->server_type != SILC_SERVER && - !(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) { - SILC_LOG_DEBUG(("Killing is not allowed")); - goto out; - } - } - - /* Send the notify to local clients on the channels except to the - client who is killed. */ - tmp = silc_argument_get_arg_type(args, 1, &tmp_len); - tmp2 = silc_argument_get_arg_type(args, 3, &tmp2_len); - silc_server_send_notify_on_channels(server, client, client, - SILC_NOTIFY_TYPE_KILLED, 3, - tmp, tmp_len, comment, comment_len, - tmp2, tmp2_len); - - /* Remove the client from all channels */ - silc_server_remove_from_channels(server, NULL, client, FALSE, NULL, - FALSE, TRUE); - - /* Check if anyone is watching this nickname */ - if (server->server_type == SILC_ROUTER) - silc_server_check_watcher_list(server, client, NULL, - SILC_NOTIFY_TYPE_KILLED); - - /* Remove client's public key from repository, this will free it too. */ - if (client->data.public_key) { - silc_skr_del_public_key(server->repository, client->data.public_key, - client); - client->data.public_key = NULL; - } - - /* Update statistics */ - server->stat.clients--; - if (server->stat.cell_clients) - server->stat.cell_clients--; - SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR); - SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR); - - if (SILC_IS_LOCAL(client)) { - server->stat.my_clients--; - silc_schedule_task_del_by_context(server->schedule, client); - silc_idlist_del_data(client); - client->mode = 0; - } - - client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; - client->mode = 0; - client->router = NULL; - client->connection = NULL; - silc_dlist_add(server->expired_clients, client); - break; - } - - case SILC_NOTIFY_TYPE_UMODE_CHANGE: - /* - * Save the mode of the client. - */ - - SILC_LOG_DEBUG(("UMODE_CHANGE notify")); - - /* Get client ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* Get client entry */ - client = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), TRUE, NULL); - if (!client) { - client = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(id), TRUE, NULL); - if (!client) - goto out; - } - - /* Get the mode */ - tmp = silc_argument_get_arg_type(args, 2, &tmp_len); - if (!tmp) - goto out; - SILC_GET32_MSB(mode, tmp); - - /* Remove internal resumed flag if client is marked detached now */ - if (mode & SILC_UMODE_DETACHED) - client->data.status &= ~SILC_IDLIST_STATUS_RESUMED; - - /* Update statistics */ - if (server->server_type == SILC_ROUTER) { - if (mode & SILC_UMODE_GONE) { - if (!(client->mode & SILC_UMODE_GONE)) - server->stat.aways++; - } else { - if (client->mode & SILC_UMODE_GONE) - server->stat.aways--; - } - if (mode & SILC_UMODE_DETACHED) { - if (!(client->mode & SILC_UMODE_DETACHED)) - server->stat.detached++; - } else { - if (client->mode & SILC_UMODE_DETACHED) - server->stat.detached--; - } - } - SILC_UMODE_STATS_UPDATE(server, SILC_UMODE_SERVER_OPERATOR); - SILC_UMODE_STATS_UPDATE(router, SILC_UMODE_ROUTER_OPERATOR); - - /* Change the mode */ - client->mode = mode; - - /* Check if anyone is watching this nickname */ - if (server->server_type == SILC_ROUTER) - silc_server_check_watcher_list(server, client, NULL, - SILC_NOTIFY_TYPE_UMODE_CHANGE); - - break; - - case SILC_NOTIFY_TYPE_BAN: - /* - * Save the ban - */ - - SILC_LOG_DEBUG(("BAN notify")); - - /* Get Channel ID */ - if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - /* Get channel entry */ - channel = silc_idlist_find_channel_by_id(server->global_list, - SILC_ID_GET_ID(id), NULL); - if (!channel) { - channel = silc_idlist_find_channel_by_id(server->local_list, - SILC_ID_GET_ID(id), NULL); - if (!channel) { - SILC_LOG_DEBUG(("Notify for unknown channel %s", - silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL))); - goto out; - } - } - - /* Get the ban action */ - tmp = silc_argument_get_arg_type(args, 2, &tmp_len); - if (tmp && tmp_len == 1) { - SilcUInt8 action = (SilcUInt8)tmp[0]; - SilcUInt16 iargc = 0; - SilcArgumentPayload iargs; - - /* Get ban list */ - tmp = silc_argument_get_arg_type(args, 3, &tmp_len); - if (!tmp || tmp_len < 2) - 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 (!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 */ - 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 - the channel. Normal server does nothing. The notify is not - sent to clients. */ - if (server->server_type == SILC_ROUTER) - silc_server_packet_send_to_channel(server, sock, channel, - packet->type, FALSE, FALSE, - buffer->data, - silc_buffer_len(buffer)); - } - break; - - case SILC_NOTIFY_TYPE_ERROR: - { - /* - * Error notify - */ - SilcStatus error; - - tmp = silc_argument_get_arg_type(args, 1, &tmp_len); - if (!tmp && tmp_len != 1) - goto out; - error = (SilcStatus)tmp[0]; - - SILC_LOG_DEBUG(("ERROR notify (%d)", error)); - - if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID && - idata->conn_type == SILC_CONN_ROUTER) { - if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) - goto out; - - SILC_LOG_DEBUG(("Received invalid client ID notification, deleting " - "the entry from cache")); - - client = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(id), - FALSE, NULL); - if (!client) - goto out; - - 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); - } - } - break; - - /* Ignore rest of the notify types for now */ - case SILC_NOTIFY_TYPE_NONE: - case SILC_NOTIFY_TYPE_MOTD: - break; - - default: - SILC_LOG_DEBUG(("Unsupported notify %d", type)); - break; - } - - out: - silc_notify_payload_free(payload); -} - -void silc_server_notify(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - silc_server_notify_process(server, sock, packet, &packet->buffer); - silc_packet_free(packet); -} - -void silc_server_notify_list(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcIDListData idata = silc_packet_get_context(sock); - SilcUInt16 len; - SilcBuffer buffer; - - SILC_LOG_DEBUG(("Processing Notify List")); - - if (idata->conn_type == SILC_CONN_CLIENT || - packet->src_id_type != SILC_ID_SERVER) - return; - - buffer = silc_buffer_alloc(1024); - if (!buffer) - return; - - while (silc_buffer_len(&packet->buffer)) { - SILC_GET16_MSB(len, packet->buffer.data + 2); - if (len > silc_buffer_len(&packet->buffer)) - break; - - if (len > silc_buffer_truelen(buffer)) { - silc_buffer_free(buffer); - buffer = silc_buffer_alloc(1024 + len); - } - - silc_buffer_pull_tail(buffer, len); - silc_buffer_put(buffer, packet->buffer.data, len); - - /* Process the Notify */ - silc_server_notify_process(server, sock, packet, buffer); - - silc_buffer_push_tail(buffer, len); - silc_buffer_pull(&packet->buffer, len); - } - - silc_packet_free(packet); - silc_buffer_free(buffer); -} - -/* Received private message. This resolves the destination of the message - and sends the packet. This is used by both server and router. If the - destination is our locally connected client this sends the packet to - the client. This may also send the message for further routing if - the destination is not in our server (or router). */ - -void silc_server_private_message(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcPacketStream dst_sock; - SilcIDListData idata; - SilcClientEntry client; - SilcClientID client_id; - - SILC_LOG_DEBUG(("Start")); - - if (packet->src_id_type != SILC_ID_CLIENT || - packet->dst_id_type != SILC_ID_CLIENT || !packet->dst_id) - goto out; - - /* Get the route to the client */ - dst_sock = silc_server_get_client_route(server, packet->dst_id, - packet->dst_id_len, NULL, - &idata, &client); - if (!dst_sock) { - SilcBuffer idp; - unsigned char error; - - if (client && client->mode & SILC_UMODE_DETACHED) { - SILC_LOG_DEBUG(("Client is detached, discarding packet")); - goto out; - } - - /* Send SILC_NOTIFY_TYPE_ERROR to indicate that such destination ID - does not exist or is invalid. */ - idp = silc_id_payload_encode_data(packet->dst_id, - packet->dst_id_len, - packet->dst_id_type); - if (!idp) - goto out; - - error = SILC_STATUS_ERR_NO_SUCH_CLIENT_ID; - if (packet->src_id_type == SILC_ID_CLIENT) { - silc_id_str2id(packet->src_id, packet->src_id_len, - packet->src_id_type, &client_id, sizeof(client_id)); - silc_server_send_notify_dest(server, sock, FALSE, - &client_id, SILC_ID_CLIENT, - SILC_NOTIFY_TYPE_ERROR, 2, - &error, 1, - idp->data, silc_buffer_len(idp)); - } else { - silc_server_send_notify(server, sock, FALSE, - SILC_NOTIFY_TYPE_ERROR, 2, - &error, 1, - idp->data, silc_buffer_len(idp)); - } - - silc_buffer_free(idp); - goto out; - } - - /* Check whether destination client wishes to receive private messages */ - if (client && !(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) && - client->mode & SILC_UMODE_BLOCK_PRIVMSG) { - SILC_LOG_DEBUG(("Client blocks private messages, discarding packet")); - goto out; - } - - /* Send the private message */ - silc_server_packet_route(server, dst_sock, packet); - - out: - silc_packet_free(packet); -} - -/* Received private message key packet.. This packet is never for us. It is to - the client in the packet's destination ID. Sending of this sort of packet - equals sending private message, ie. it is sent point to point from - one client to another. */ - -void silc_server_private_message_key(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcPacketStream dst_sock; - SilcIDListData idata; - - SILC_LOG_DEBUG(("Start")); - - if (packet->src_id_type != SILC_ID_CLIENT || - packet->dst_id_type != SILC_ID_CLIENT || !packet->dst_id) { - silc_packet_free(packet); - return; - } - - /* Get the route to the client */ - dst_sock = silc_server_get_client_route(server, packet->dst_id, - packet->dst_id_len, NULL, - &idata, NULL); - if (!dst_sock) { - silc_packet_free(packet); - return; - } - - /* Relay the packet */ - silc_server_packet_route(server, dst_sock, packet); - - silc_packet_free(packet); -} - -/* Processes incoming command reply packet. The command reply packet may - be destined to one of our clients or it may directly for us. We will - call the command reply routine after processing the packet. */ - -void silc_server_command_reply(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcBuffer buffer = &packet->buffer; - SilcClientEntry client = NULL; - SilcClientID id; - - SILC_LOG_DEBUG(("Start")); - - if (packet->dst_id_type == SILC_ID_CHANNEL) { - silc_packet_free(packet); - return; - } - - if (packet->dst_id_type == SILC_ID_CLIENT) { - /* Destination must be one of ours */ - if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CLIENT, - &id, sizeof(id))) { - silc_packet_free(packet); - return; - } - client = silc_idlist_find_client_by_id(server->local_list, &id, - TRUE, NULL); - if (!client) { - SILC_LOG_ERROR(("Cannot process command reply to unknown client")); - silc_packet_free(packet); - return; - } - } - - if (packet->dst_id_type == SILC_ID_SERVER) { - /* For now this must be for us */ - if (memcmp(packet->dst_id, server->id_string, server->id_string_len)) { - SILC_LOG_ERROR(("Cannot process command reply to unknown server")); - silc_packet_free(packet); - return; - } - } - - /* Execute command reply locally for the command */ - silc_server_command_reply_process(server, sock, buffer); - - /* Relay the packet to the client */ - if (packet->dst_id_type == SILC_ID_CLIENT && client) - silc_server_packet_route(server, client->connection, packet); - - silc_packet_free(packet); -} - -/* Process received channel message. The message can be originated from - client or server. */ - -void silc_server_channel_message(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcChannelEntry channel = NULL; - SilcChannelID id; - SilcClientID cid; - SilcID sid; - SilcClientEntry sender_entry = NULL; - SilcIDListData idata; - SilcChannelClientEntry chl; - SilcBool local = TRUE; - - SILC_LOG_DEBUG(("Processing channel message")); - - /* Sanity checks */ - if (packet->dst_id_type != SILC_ID_CHANNEL) { - SILC_LOG_DEBUG(("Received bad message for channel, dropped")); - goto out; - } - - /* Find channel entry */ - if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL, - &id, sizeof(id))) - goto out; - channel = silc_idlist_find_channel_by_id(server->local_list, &id, NULL); - if (!channel) { - channel = silc_idlist_find_channel_by_id(server->global_list, &id, NULL); - if (!channel) { - SilcBuffer idp; - unsigned char error; - - /* Send SILC_NOTIFY_TYPE_ERROR to indicate that such destination ID - does not exist or is invalid. */ - idp = silc_id_payload_encode_data(packet->dst_id, - packet->dst_id_len, - packet->dst_id_type); - if (!idp) - goto out; - - error = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID; - if (packet->src_id_type == SILC_ID_CLIENT) { - silc_id_str2id(packet->src_id, packet->src_id_len, - packet->src_id_type, &cid, sizeof(cid)); - silc_server_send_notify_dest(server, sock, FALSE, - &cid, SILC_ID_CLIENT, - SILC_NOTIFY_TYPE_ERROR, 2, - &error, 1, idp->data, - silc_buffer_len(idp)); - } else { - silc_server_send_notify(server, sock, FALSE, - SILC_NOTIFY_TYPE_ERROR, 2, - &error, 1, idp->data, silc_buffer_len(idp)); - } - - silc_buffer_free(idp); - goto out; - } - } - - /* See that this client is on the channel. If the original sender is - not client (as it can be server as well) we don't do the check. */ - if (!silc_id_str2id2(packet->src_id, packet->src_id_len, - packet->src_id_type, &sid)) - goto out; - if (sid.type == SILC_ID_CLIENT) { - sender_entry = silc_idlist_find_client_by_id(server->local_list, - SILC_ID_GET_ID(sid), - TRUE, NULL); - if (!sender_entry) { - local = FALSE; - sender_entry = silc_idlist_find_client_by_id(server->global_list, - SILC_ID_GET_ID(sid), - TRUE, NULL); - } - if (!sender_entry || !silc_server_client_on_channel(sender_entry, - channel, &chl)) { - SILC_LOG_DEBUG(("Client not on channel")); - goto out; - } - - /* If channel is moderated check that client is allowed to send - messages. */ - if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && - !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) && - !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) { - SILC_LOG_DEBUG(("Channel is silenced from normal users")); - goto out; - } - if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS && - chl->mode & SILC_CHANNEL_UMODE_CHANOP && - !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) { - SILC_LOG_DEBUG(("Channel is silenced from operators")); - goto out; - } - if (chl->mode & SILC_CHANNEL_UMODE_QUIET) { - SILC_LOG_DEBUG(("Sender is quieted on the channel")); - goto out; - } - - /* If the packet is coming from router, but the client entry is local - entry to us then some router is rerouting this to us and it is not - allowed. When the client is local to us it means that we've routed - this packet to network, and now someone is routing it back to us. */ - idata = silc_packet_get_context(sock); - if (server->server_type == SILC_ROUTER && - idata->conn_type == SILC_CONN_ROUTER && local) { - SILC_LOG_DEBUG(("Channel message rerouted to the sender, drop it")); - goto out; - } - } - - /* Distribute the packet to our local clients. This will send the - packet for further routing as well, if needed. */ - silc_server_packet_relay_to_channel(server, sock, channel, - SILC_ID_GET_ID(sid), sid.type, - sender_entry, packet->buffer.data, - silc_buffer_len(&packet->buffer)); - - out: - silc_packet_free(packet); -} - -/* Received channel key packet. We distribute the key to all of our locally - connected clients on the channel. */ - -void silc_server_channel_key(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcBuffer buffer = &packet->buffer; - SilcIDListData idata = silc_packet_get_context(sock); - SilcChannelEntry channel; - - if (packet->src_id_type != SILC_ID_SERVER || - (server->server_type == SILC_ROUTER && !server->backup_router && - idata->conn_type == SILC_CONN_ROUTER)) { - silc_packet_free(packet); - return; - } - - /* Save the channel key */ - channel = silc_server_save_channel_key(server, buffer, NULL); - if (!channel) { - SILC_LOG_ERROR(("Bad channel key from %s", idata->sconn->remote_host)); - silc_packet_free(packet); - return; - } - - /* Distribute the key to everybody who is on the channel. If we are router - we will also send it to locally connected servers. */ - silc_server_send_channel_key(server, sock, channel, FALSE); - - if (server->server_type != SILC_BACKUP_ROUTER) - /* Distribute to local cell backup routers. */ - silc_server_backup_send(server, (SilcServerEntry)idata, - SILC_PACKET_CHANNEL_KEY, 0, - buffer->data, silc_buffer_len(buffer), - FALSE, TRUE); - - silc_packet_free(packet); -} - -/* Received New Client packet and processes it. Creates Client ID for the - client. Client becomes registered after calling this functions. */ - -SilcClientEntry silc_server_new_client(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcBuffer buffer = &packet->buffer; - SilcIDListData idata = silc_packet_get_context(sock); - SilcClientEntry client; - SilcClientID *client_id; - char *username = NULL, *realname = NULL; - SilcUInt16 username_len, nickname_len; - SilcUInt32 id_len, tmp_len; - int ret; - char *host, *nickname = NULL, *nicknamec; - const char *hostname, *ip; - - SILC_LOG_DEBUG(("Creating new client")); - - if (idata->conn_type != SILC_CONN_CLIENT) { - silc_packet_free(packet); - return NULL; - } - - /* Take client entry */ - client = (SilcClientEntry)idata; - silc_socket_stream_get_info(silc_packet_stream_get_stream(sock), - NULL, &hostname, &ip, NULL); - - SILC_LOG_DEBUG(("%s %s", ip, hostname)); - - /* Make sure this client hasn't registered already */ - if (idata->status & SILC_IDLIST_STATUS_REGISTERED) { - silc_packet_free(packet); - return NULL; - } - - /* Parse incoming packet */ - ret = silc_buffer_unformat(buffer, - SILC_STR_ADVANCE, - SILC_STR_UI16_NSTRING_ALLOC(&username, - &username_len), - SILC_STR_UI16_STRING_ALLOC(&realname), - SILC_STR_END); - if (ret == -1) { - silc_free(username); - silc_free(realname); - SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing " - "connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - NULL); - silc_server_free_sock_user_data(server, sock, NULL); - silc_packet_free(packet); - return NULL; - } - - if (!username) { - silc_free(username); - silc_free(realname); - SILC_LOG_ERROR(("Client %s (%s) did not send its username, closing " - "connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - NULL); - silc_server_free_sock_user_data(server, sock, NULL); - silc_packet_free(packet); - return NULL; - } - - if (username_len > 128) { - username_len = 128; - username[username_len - 1] = '\0'; - } - - /* Take nickname from NEW_CLIENT packet, if present */ - if (silc_buffer_unformat(buffer, - SILC_STR_UI16_NSTRING_ALLOC(&nickname, - &nickname_len), - SILC_STR_END)) { - if (nickname_len > 128) { - nickname_len = 128; - nickname[nickname_len - 1] = '\0'; - } - } - - /* Nickname is initially same as username, if not present in NEW_CLIENT */ - if (!nickname) { - nickname = strdup(username); - nickname_len = strlen(nickname); - } - - /* Check for valid username string */ - nicknamec = silc_identifier_check(nickname, nickname_len, - SILC_STRING_UTF8, 128, &tmp_len); - if (!nicknamec) { - silc_free(username); - silc_free(realname); - silc_free(nickname); - SILC_LOG_ERROR(("Client %s (%s) sent bad username string '%s', closing " - "connection", hostname, ip, username)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - NULL); - silc_server_free_sock_user_data(server, sock, NULL); - silc_packet_free(packet); - return NULL; - } - - /* 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 - the client's public key. If the hostname is not present then put - it from the resolved name or from the public key. */ - if (strchr(username, '@')) { - SilcSILCPublicKey silc_pubkey; - int tlen = strcspn(username, "@"); - char *phostname = NULL; - - host = silc_memdup(username + tlen + 1, strlen(username) - tlen - 1); - - if (strcmp(hostname, ip) && strcmp(hostname, host)) { - silc_free(nickname); - silc_free(username); - silc_free(host); - silc_free(realname); - SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing " - "connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - NULL); - silc_server_free_sock_user_data(server, sock, NULL); - silc_packet_free(packet); - return NULL; - } - - silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, - client->data.public_key); - phostname = strdup(silc_pubkey->identifier.host); - if (!strcmp(hostname, ip) && phostname && strcmp(phostname, host)) { - silc_free(nickname); - silc_free(username); - silc_free(host); - silc_free(phostname); - silc_free(realname); - SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing " - "connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - NULL); - silc_server_free_sock_user_data(server, sock, NULL); - silc_packet_free(packet); - return NULL; - } - - silc_free(phostname); - } else { - /* The hostname is not present, add it. */ - char *newusername; - newusername = silc_calloc(strlen(username) + strlen(hostname) + 2, - sizeof(*newusername)); - strncat(newusername, username, strlen(username)); - strncat(newusername, "@", 1); - strncat(newusername, hostname, strlen(hostname)); - silc_free(username); - username = newusername; - } - - SILC_LOG_DEBUG(("%s %s", ip, hostname)); - - /* Create 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, NULL); - silc_server_free_sock_user_data(server, sock, NULL); - silc_packet_free(packet); - return NULL; - } - - /* If client marked as anonymous, scramble the username and hostname */ - if (client->mode & SILC_UMODE_ANONYMOUS) { - char *scramble; - - if (strlen(username) >= 2) { - username[0] = silc_rng_get_byte_fast(server->rng); - username[1] = silc_rng_get_byte_fast(server->rng); - } - - scramble = silc_hash_babbleprint(server->sha1hash, username, - strlen(username)); - scramble[5] = '@'; - scramble[11] = '.'; - memcpy(&scramble[16], ".silc", 5); - scramble[21] = '\0'; - silc_free(username); - username = scramble; - } - - /* Update client entry */ - idata->status |= SILC_IDLIST_STATUS_REGISTERED; - client->nickname = nickname; - client->username = username; - client->userinfo = realname ? realname : strdup(username); - client->id = client_id; - id_len = silc_id_get_len(client_id, SILC_ID_CLIENT); - silc_idcache_update_by_context(server->local_list->clients, client, - client_id, nicknamec, TRUE); - - /* Notify our router about new client on the SILC network */ - silc_server_send_new_id(server, SILC_PRIMARY_ROUTE(server), - SILC_BROADCAST(server), client->id, - SILC_ID_CLIENT, id_len); - - /* Distribute to backup routers */ - if (server->server_type == SILC_ROUTER) { - SilcBuffer idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); - silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0, - idp->data, silc_buffer_len(idp), FALSE, TRUE); - silc_buffer_free(idp); - } - - /* Send the new client ID to the client. */ - silc_server_send_new_id(server, sock, FALSE, client->id, SILC_ID_CLIENT, - silc_id_get_len(client->id, SILC_ID_CLIENT)); - - /* Send some nice info to the client */ - silc_server_send_connect_notifys(server, sock, client); - - /* Check if anyone is watching this nickname */ - if (server->server_type == SILC_ROUTER) - silc_server_check_watcher_list(server, client, NULL, 0); - - silc_packet_free(packet); - return client; -} - -/* Create new server. This processes received New Server packet and - saves the received Server ID. The server is our locally connected - server thus we save all the information and save it to local list. - This funtion can be used by both normal server and router server. - If normal server uses this it means that its router has connected - to the server. If router uses this it means that one of the cell's - servers is connected to the router. */ - -SilcServerEntry silc_server_new_server(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcBuffer buffer = &packet->buffer; - SilcIDListData idata = silc_packet_get_context(sock); - SilcServerEntry new_server, server_entry; - SilcServerID server_id; - unsigned char *server_name, *server_namec, *id_string; - SilcUInt16 id_len, name_len; - int ret; - SilcBool local = TRUE; - const char *hostname, *ip; - - SILC_LOG_DEBUG(("Creating new server")); - - if (idata->conn_type != SILC_CONN_SERVER && - idata->conn_type != SILC_CONN_ROUTER) { - silc_packet_free(packet); - return NULL; - } - - /* Take server entry */ - new_server = (SilcServerEntry)idata; - silc_socket_stream_get_info(silc_packet_stream_get_stream(sock), - NULL, &hostname, &ip, NULL); - - /* 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, - NULL)) { - if (!silc_idcache_del_by_context(server->global_list->servers, - new_server, NULL)) { - SILC_LOG_INFO(("Unauthenticated %s attempted to register to " - "network", (idata->conn_type == SILC_CONN_SERVER ? - "server" : "router"))); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL); - silc_server_free_sock_user_data(server, sock, NULL); - return NULL; - } - local = FALSE; - } - - /* Make sure this server hasn't registered already */ - if (idata->status & SILC_IDLIST_STATUS_REGISTERED) { - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_OPERATION_ALLOWED, - "Too many registrations"); - silc_server_free_sock_user_data(server, sock, NULL); - return NULL; - } - - /* Parse the incoming packet */ - ret = silc_buffer_unformat(buffer, - SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len), - SILC_STR_UI16_NSTRING_ALLOC(&server_name, - &name_len), - SILC_STR_END); - if (ret == -1) { - silc_free(id_string); - silc_free(server_name); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - NULL); - silc_server_free_sock_user_data(server, sock, NULL); - return NULL; - } - - if (id_len > silc_buffer_len(buffer)) { - silc_free(id_string); - silc_free(server_name); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - NULL); - silc_server_free_sock_user_data(server, sock, NULL); - return NULL; - } - - if (name_len > 256) { - server_name[256] = '\0'; - name_len = 256; - } - - /* Get Server ID */ - if (!silc_id_str2id(id_string, id_len, SILC_ID_SERVER, &server_id, - sizeof(server_id))) { - silc_free(id_string); - silc_free(server_name); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - NULL); - silc_server_free_sock_user_data(server, sock, NULL); - return NULL; - } - silc_free(id_string); - - /* Check for valid server ID */ - if (!silc_id_is_valid_server_id(server, &server_id, sock)) { - SILC_LOG_INFO(("Invalid server ID sent by %s (%s)", - ip, hostname)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_BAD_SERVER_ID, NULL); - silc_server_free_sock_user_data(server, sock, NULL); - silc_free(server_name); - return NULL; - } - - /* Check that we do not have this ID already */ - server_entry = silc_idlist_find_server_by_id(server->local_list, - &server_id, TRUE, NULL); - if (server_entry) { - if (SILC_IS_LOCAL(server_entry)) { - SILC_LOG_ERROR(("Too many registrations from %s (%s)", - ip, hostname)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_OPERATION_ALLOWED, - "Too many registrations"); - silc_server_free_sock_user_data(server, sock, NULL); - return NULL; - } else { - silc_idcache_del_by_context(server->local_list->servers, server_entry, - NULL); - } - } else { - server_entry = silc_idlist_find_server_by_id(server->global_list, - &server_id, TRUE, NULL); - if (server_entry) { - if (SILC_IS_LOCAL(server_entry)) { - SILC_LOG_ERROR(("Too many registrations from %s (%s)", - ip, hostname)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_OPERATION_ALLOWED, - "Too many registrations"); - silc_server_free_sock_user_data(server, sock, NULL); - return NULL; - } else { - silc_idcache_del_by_context(server->global_list->servers, - server_entry, NULL); - } - } - } - - /* 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)", - ip, hostname)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_OPERATION_ALLOWED, - "Malfromed server name"); - 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; - new_server->id = silc_id_dup(&server_id, SILC_ID_SERVER); - - SILC_LOG_DEBUG(("New server id(%s)", - silc_id_render(&server_id, SILC_ID_SERVER))); - - /* Add again the entry to the ID cache. */ - silc_idcache_add(local ? server->local_list->servers : - server->global_list->servers, server_namec, - new_server->id, new_server); - - /* Distribute the information about new server in the SILC network - to our router. If we are normal server we won't send anything - since this connection must be our router connection. */ - if (server->server_type == SILC_ROUTER && !server->standalone && - SILC_PRIMARY_ROUTE(server) != sock) - silc_server_send_new_id(server, SILC_PRIMARY_ROUTE(server), - TRUE, new_server->id, SILC_ID_SERVER, - silc_id_get_len(&server_id, SILC_ID_SERVER)); - - if (server->server_type == SILC_ROUTER) { - /* Distribute to backup routers */ - SilcBuffer idp = silc_id_payload_encode(new_server->id, SILC_ID_SERVER); - silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0, idp->data, - silc_buffer_len(idp), FALSE, TRUE); - silc_buffer_free(idp); - } - - /* Check whether this router connection has been replaced by an - backup router. If it has been then we'll disable the server and will - ignore everything it will send until the backup router resuming - protocol has been completed. */ - if (idata->conn_type == SILC_CONN_ROUTER && - silc_server_backup_replaced_get(server, &server_id, NULL)) { - /* Send packet to the router indicating that it cannot use this - connection as it has been replaced by backup router. */ - SILC_LOG_DEBUG(("Remote router has been replaced by backup router, " - "disabling its connection")); - - silc_server_backup_send_replaced(server, sock); - - /* Mark the router disabled. The data sent earlier will go but nothing - after this goes to this connection. */ - idata->status |= SILC_IDLIST_STATUS_DISABLED; - } else { - /* If it is router announce our stuff to it. */ - if (idata->conn_type == SILC_CONN_ROUTER && - server->server_type == SILC_ROUTER) { - silc_server_announce_servers(server, FALSE, 0, sock); - silc_server_announce_clients(server, 0, sock); - silc_server_announce_channels(server, 0, sock); - } - - /* Announce our information to backup router */ - if (new_server->server_type == SILC_BACKUP_ROUTER && - idata->conn_type == SILC_CONN_SERVER && - server->server_type == SILC_ROUTER) { - silc_server_announce_servers(server, TRUE, 0, sock); - silc_server_announce_clients(server, 0, sock); - silc_server_announce_channels(server, 0, sock); - } - - /* If backup router, mark it as one of ours. This server is considered - to be backup router after this setting. */ - if (new_server->server_type == SILC_BACKUP_ROUTER) { - SilcServerConfigRouter *backup; - backup = silc_server_config_find_backup_conn(server, (char *)ip); - if (!backup) - backup = silc_server_config_find_backup_conn(server, (char *)hostname); - if (backup) { - /* Add as our backup router */ - silc_server_backup_add(server, new_server, backup->backup_replace_ip, - backup->backup_replace_port, - backup->backup_local); - } - } - - /* By default the servers connected to backup router are disabled - until backup router has become the primary */ - if (server->server_type == SILC_BACKUP_ROUTER && - idata->conn_type == SILC_CONN_SERVER) - idata->status |= SILC_IDLIST_STATUS_DISABLED; - } - - return new_server; -} - -/* Processes incoming New ID packet. New ID Payload is used to distribute - information about newly registered clients and servers. */ - -static void silc_server_new_id_real(SilcServer server, - SilcPacketStream sock, - SilcPacket packet, - SilcBuffer buffer, - SilcBool broadcast) -{ - SilcIDListData idata = silc_packet_get_context(sock); - SilcIDList id_list; - SilcServerEntry router, server_entry; - SilcPacketStream router_sock; - SilcIDPayload idp; - SilcIdType id_type; - SilcServerID sender_id; - const char *hostname, *ip; - - SILC_LOG_DEBUG(("Processing new ID")); - - if (idata->conn_type == SILC_CONN_CLIENT || - server->server_type == SILC_SERVER || - packet->src_id_type != SILC_ID_SERVER) - return; - - idp = silc_id_payload_parse(buffer->data, silc_buffer_len(buffer)); - if (!idp) - return; - - id_type = silc_id_payload_get_type(idp); - - silc_socket_stream_get_info(silc_packet_stream_get_stream(sock), - NULL, &hostname, &ip, NULL); - - /* Normal server cannot have other normal server connections */ - server_entry = (SilcServerEntry)idata; - if (id_type == SILC_ID_SERVER && idata->conn_type == SILC_CONN_SERVER && - server_entry->server_type == SILC_SERVER) - goto out; - - /* If the packet is coming from server then use the sender as the - origin of the the packet. If it came from router then check the real - sender of the packet and use that as the origin. */ - if (idata->conn_type == SILC_CONN_SERVER) { - id_list = server->local_list; - router_sock = sock; - router = server_entry; - - /* If the sender is backup router and ID is server (and we are not - backup router) then switch the entry to global list. */ - if (server_entry->server_type == SILC_BACKUP_ROUTER && - id_type == SILC_ID_SERVER && - server->id_entry->server_type != SILC_BACKUP_ROUTER) { - id_list = server->global_list; - router_sock = server->router ? SILC_PRIMARY_ROUTE(server) : sock; - } - } else { - silc_id_str2id(packet->src_id, packet->src_id_len, - packet->src_id_type, &sender_id, sizeof(sender_id)); - router = silc_idlist_find_server_by_id(server->global_list, - &sender_id, TRUE, NULL); - if (!router) - router = silc_idlist_find_server_by_id(server->local_list, - &sender_id, TRUE, NULL); - router_sock = sock; - id_list = server->global_list; - } - - if (!router) - goto out; - - switch(id_type) { - case SILC_ID_CLIENT: - { - SilcClientEntry entry; - SilcClientID id; - - if (!silc_id_payload_get_id(idp, &id, sizeof(id))) - goto out; - - /* Check that we do not have this client already */ - entry = silc_idlist_find_client_by_id(server->global_list, - &id, server->server_type, - NULL); - if (!entry) - entry = silc_idlist_find_client_by_id(server->local_list, - &id, server->server_type, - NULL); - if (entry) { - SILC_LOG_DEBUG(("Ignoring client that we already have")); - goto out; - } - - SILC_LOG_DEBUG(("New client id(%s) from [%s] %s", - silc_id_render(&id, SILC_ID_CLIENT), - idata->conn_type == SILC_CONN_SERVER ? - "Server" : "Router", hostname)); - - /* As a router we keep information of all global information in our - global list. Cell wide information however is kept in the local - list. */ - entry = silc_idlist_add_client(id_list, NULL, NULL, NULL, - silc_id_dup(&id, SILC_ID_CLIENT), - router, NULL); - if (!entry) { - SILC_LOG_ERROR(("Could not add new client to the ID Cache")); - - /* Inform the sender that the ID is not usable */ - silc_server_send_notify_signoff(server, sock, FALSE, &id, NULL); - goto out; - } - entry->nickname = NULL; - entry->data.status |= SILC_IDLIST_STATUS_REGISTERED; - - if (idata->conn_type == SILC_CONN_SERVER) - server->stat.cell_clients++; - server->stat.clients++; - - /* 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 repository or get the key with - GETKEY command. */ - if (entry->data.public_key) { - if (!silc_server_get_public_key_by_client(server, entry, NULL)) - silc_skr_add_public_key_simple(server->repository, - entry->data.public_key, - SILC_SKR_USAGE_IDENTIFICATION, - entry, NULL); - } else { - silc_server_send_command(server, router_sock, - SILC_COMMAND_GETKEY, ++server->cmd_ident, - 1, 1, buffer->data, - silc_buffer_len(buffer)); - } - } - } - break; - - case SILC_ID_SERVER: - { - SilcServerEntry entry; - SilcServerID id; - - if (!silc_id_payload_get_id(idp, &id, sizeof(id))) - goto out; - - /* If the ID is mine, ignore it. */ - if (SILC_ID_SERVER_COMPARE(&id, server->id)) { - SILC_LOG_DEBUG(("Ignoring my own ID as new ID")); - break; - } - - /* If the ID is the sender's ID, ignore it (we have it already) */ - if (SILC_ID_SERVER_COMPARE(&id, router->id)) { - SILC_LOG_DEBUG(("Ignoring sender's own ID")); - break; - } - - /* Check that we do not have this server already */ - entry = silc_idlist_find_server_by_id(server->global_list, - &id, server->server_type, - NULL); - if (!entry) - entry = silc_idlist_find_server_by_id(server->local_list, - &id, server->server_type, - NULL); - if (entry) { - SILC_LOG_DEBUG(("Ignoring server that we already have")); - goto out; - } - - SILC_LOG_DEBUG(("New server id(%s) from [%s] %s", - silc_id_render(&id, SILC_ID_SERVER), - idata->conn_type == SILC_CONN_SERVER ? - "Server" : "Router", hostname)); - - /* As a router we keep information of all global information in our - global list. Cell wide information however is kept in the local - list. */ - entry = silc_idlist_add_server(id_list, NULL, 0, - silc_id_dup(&id, SILC_ID_SERVER), router, - router_sock); - if (!entry) { - SILC_LOG_ERROR(("Could not add new server to the ID Cache")); - goto out; - } - entry->data.status |= SILC_IDLIST_STATUS_REGISTERED; - - if (idata->conn_type == SILC_CONN_SERVER) - server->stat.cell_servers++; - server->stat.servers++; - } - break; - - case SILC_ID_CHANNEL: - SILC_LOG_ERROR(("Channel cannot be registered with NEW_ID packet")); - goto out; - break; - - default: - goto out; - break; - } - - /* If the sender of this packet is server and we are router we need to - broadcast this packet to other routers in the network. */ - if (broadcast && server->server_type == SILC_ROUTER && - idata->conn_type == SILC_CONN_SERVER && - !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) { - SILC_LOG_DEBUG(("Broadcasting received New ID packet")); - silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), - packet->type, - packet->flags | SILC_PACKET_FLAG_BROADCAST, - buffer->data, silc_buffer_len(buffer)); - silc_server_backup_send(server, (SilcServerEntry)idata, - packet->type, packet->flags, - packet->buffer.data, - silc_buffer_len(&packet->buffer), - FALSE, TRUE); - } - - out: - silc_id_payload_free(idp); -} - - -/* Processes incoming New ID packet. New ID Payload is used to distribute - information about newly registered clients and servers. */ - -void silc_server_new_id(SilcServer server, SilcPacketStream sock, - SilcPacket packet) -{ - silc_server_new_id_real(server, sock, packet, &packet->buffer, TRUE); - silc_packet_free(packet); -} - -/* Receoved New Id List packet, list of New ID payloads inside one - packet. Process the New ID payloads one by one. */ - -void silc_server_new_id_list(SilcServer server, SilcPacketStream sock, - SilcPacket packet) -{ - SilcIDListData idata = silc_packet_get_context(sock); - SilcBuffer idp; - SilcUInt16 id_len; - - SILC_LOG_DEBUG(("Processing New ID List")); - - if (idata->conn_type == SILC_CONN_CLIENT || - packet->src_id_type != SILC_ID_SERVER) { - silc_packet_free(packet); - return; - } - - /* If the sender of this packet is server and we are router we need to - broadcast this packet to other routers in the network. Broadcast - this list packet instead of multiple New ID packets. */ - if (server->server_type == SILC_ROUTER && - idata->conn_type == SILC_CONN_SERVER && - !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) { - SILC_LOG_DEBUG(("Broadcasting received New ID List packet")); - silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), - packet->type, - packet->flags | SILC_PACKET_FLAG_BROADCAST, - packet->buffer.data, - silc_buffer_len(&packet->buffer)); - silc_server_backup_send(server, (SilcServerEntry)idata, - packet->type, packet->flags, - packet->buffer.data, - silc_buffer_len(&packet->buffer), - FALSE, TRUE); - } - - idp = silc_buffer_alloc(256); - if (!idp) { - silc_packet_free(packet); - return; - } - - while (silc_buffer_len(&packet->buffer)) { - SILC_GET16_MSB(id_len, packet->buffer.data + 2); - if ((id_len > silc_buffer_len(&packet->buffer)) || - (id_len > silc_buffer_truelen(idp))) - break; - - silc_buffer_pull_tail(idp, 4 + id_len); - silc_buffer_put(idp, packet->buffer.data, 4 + id_len); - - /* Process the New ID */ - silc_server_new_id_real(server, sock, packet, idp, FALSE); - - silc_buffer_push_tail(idp, 4 + id_len); - silc_buffer_pull(&packet->buffer, 4 + id_len); - } - - silc_buffer_free(idp); - silc_packet_free(packet); -} - -/* Received New Channel packet. Information about new channels in the - network are distributed using this packet. Save the information about - the new channel. This usually comes from router but also normal server - can send this to notify channels it has when it connects to us. */ - -static void silc_server_new_channel_process(SilcServer server, - SilcPacketStream sock, - SilcPacket packet, - SilcBuffer buffer) -{ - SilcIDListData idata = silc_packet_get_context(sock); - SilcChannelPayload payload; - SilcChannelID channel_id; - char *channel_name, *channel_namec = NULL; - SilcUInt32 name_len; - unsigned char *id, cid[32]; - SilcUInt32 id_len, cipher_len; - SilcServerEntry server_entry; - SilcChannelEntry channel; - const char *cipher; - - if (idata->conn_type == SILC_CONN_CLIENT || - packet->src_id_type != SILC_ID_SERVER || - server->server_type == SILC_SERVER) - return; - - /* Parse the channel payload */ - payload = silc_channel_payload_parse(buffer->data, silc_buffer_len(buffer)); - if (!payload) - return; - - /* Get the channel ID */ - if (!silc_channel_get_id_parse(payload, &channel_id)) { - silc_channel_payload_free(payload); - return; - } - - channel_name = silc_channel_get_name(payload, &name_len); - 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); - - server_entry = (SilcServerEntry)idata; - - if (idata->conn_type == SILC_CONN_ROUTER) { - /* Add the channel to global list as it is coming from router. It - cannot be our own channel as it is coming from router. */ - - /* Check that we don't already have this channel */ - channel = silc_idlist_find_channel_by_name(server->local_list, - channel_namec, NULL); - if (!channel) - channel = silc_idlist_find_channel_by_name(server->global_list, - channel_namec, NULL); - if (!channel) { - SILC_LOG_DEBUG(("New channel id(%s) from [Router] %s", - silc_id_render(&channel_id, SILC_ID_CHANNEL), - idata->sconn->remote_host)); - - channel = - silc_idlist_add_channel(server->global_list, strdup(channel_name), - 0, silc_id_dup(&channel_id, SILC_ID_CHANNEL), - (SilcServerEntry)idata, NULL, NULL, NULL); - if (!channel) { - silc_channel_payload_free(payload); - return; - } - channel->disabled = TRUE; /* Disabled until someone JOINs */ - - server->stat.channels++; - if (server->server_type == SILC_ROUTER) - channel->users_resolved = TRUE; - } - } else { - /* The channel is coming from our server, thus it is in our cell - we will add it to our local list. */ - SilcBuffer chk; - - SILC_LOG_DEBUG(("Channel id(%s) from [Server] %s", - silc_id_render(&channel_id, SILC_ID_CHANNEL), - idata->sconn->remote_host)); - - /* Check that we don't already have this channel */ - channel = silc_idlist_find_channel_by_name(server->local_list, - channel_namec, NULL); - if (!channel) - channel = silc_idlist_find_channel_by_name(server->global_list, - 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. */ - if (!channel) { - SILC_LOG_DEBUG(("Channel is new to us")); - - /* The protocol says that the Channel ID's IP address must be based - on the router's IP address. Check whether the ID is based in our - IP and if it is not then create a new ID and enforce the server - to switch the ID. */ - if (server_entry->server_type != SILC_BACKUP_ROUTER && - !SILC_ID_COMPARE(&channel_id, server->id, server->id->ip.data_len)) { - SilcChannelID *tmp; - SILC_LOG_DEBUG(("Forcing the server to change Channel ID")); - if (silc_id_create_channel_id(server, server->id, server->rng, &tmp)) { - silc_server_send_notify_channel_change(server, sock, FALSE, - &channel_id, tmp); - silc_channel_payload_free(payload); - silc_free(tmp); - } - - /* Wait that server re-announces this channel */ - return; - } - - /* Create the channel with the provided Channel ID */ - channel = - silc_server_create_new_channel_with_id( - server, NULL, NULL, - channel_name, - silc_id_dup(&channel_id, SILC_ID_CHANNEL), - FALSE); - if (!channel) { - silc_channel_payload_free(payload); - return; - } - channel->disabled = TRUE; /* Disabled until someone JOINs */ - -#if 0 /* We assume that CMODE_CHANGE notify is sent to us after this. */ - - /* XXX Dunno if this is supposed to be set in any server type. If set - here the CMODE_CHANGE that may follow sets mode that we already - have, and we may loose data from the CMODE_CHANGE notify. */ - if (server_entry->server_type != SILC_BACKUP_ROUTER) - channel->mode = silc_channel_get_mode(payload); -#endif - - /* Send the new channel key to the server */ - silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid), - &id_len); - cipher = silc_cipher_get_name(channel->send_key); - cipher_len = strlen(cipher); - chk = silc_channel_key_payload_encode(id_len, cid, - cipher_len, cipher, - channel->key_len / 8, - channel->key); - silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, - chk->data, silc_buffer_len(chk)); - silc_buffer_free(chk); - } else { - /* The channel exist by that name, check whether the ID's match. - If they don't then we'll force the server to use the ID we have. - We also create a new key for the channel. */ - SilcBuffer modes = NULL, users = NULL, users_modes = NULL; - - SILC_LOG_DEBUG(("Channel already exists")); - - if (!SILC_ID_CHANNEL_COMPARE(&channel_id, channel->id)) { - /* They don't match, send CHANNEL_CHANGE notify to the server to - force the ID change. */ - SILC_LOG_DEBUG(("Forcing the server to change Channel ID")); - silc_server_send_notify_channel_change(server, sock, FALSE, - &channel_id, channel->id); - silc_channel_payload_free(payload); - - /* Wait that server re-announces this channel */ - return; - } - -#if 0 /* We will announce our CMODE anyway for this channel, so no need - to check it (implicit enforce). */ - - /* If the mode is different from what we have then enforce the - mode change. */ - mode = silc_channel_get_mode(payload); - if (channel->mode != mode) { - SILC_LOG_DEBUG(("Forcing the server to change channel mode")); - silc_server_send_notify_cmode(server, sock, FALSE, channel, - channel->mode, server->id, - SILC_ID_SERVER, channel->cipher, - channel->hmac_name, - channel->passphrase, - channel->founder_key); - } -#endif - - /* Create new key for the channel and send it to the server and - everybody else possibly on the channel. */ - if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) { - - if (silc_hash_table_count(channel->user_list)) { - if (!silc_server_create_channel_key(server, channel, 0)) { - silc_channel_payload_free(payload); - return; - } - - /* Send to the channel */ - silc_server_send_channel_key(server, sock, channel, FALSE); - } - - /* Send to the server */ - silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid), - &id_len); - cipher = silc_cipher_get_name(channel->send_key); - cipher_len = strlen(cipher); - chk = silc_channel_key_payload_encode(id_len, cid, - cipher_len, cipher, - channel->key_len / 8, - channel->key); - silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, - chk->data, silc_buffer_len(chk)); - silc_buffer_free(chk); - } - - /* Since the channel is coming from server and we also know about it - then send the JOIN notify to the server so that it see's our - users on the channel "joining" the channel. */ - silc_server_announce_get_channel_users(server, channel, &modes, &users, - &users_modes); - if (users) { - silc_buffer_push(users, users->data - users->head); - silc_server_packet_send(server, sock, - SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST, - users->data, silc_buffer_len(users)); - silc_buffer_free(users); - } - if (modes) { - silc_buffer_push(modes, modes->data - modes->head); - silc_server_packet_send_dest(server, sock, - SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST, - channel->id, SILC_ID_CHANNEL, - modes->data, silc_buffer_len(modes)); - silc_buffer_free(modes); - } - if (users_modes) { - silc_buffer_push(users_modes, users_modes->data - users_modes->head); - silc_server_packet_send_dest(server, sock, - SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST, - channel->id, SILC_ID_CHANNEL, - users_modes->data, - silc_buffer_len(users_modes)); - silc_buffer_free(users_modes); - } - if (channel->topic) { - silc_server_send_notify_topic_set(server, sock, - server->server_type == SILC_ROUTER ? - TRUE : FALSE, channel, - server->id, SILC_ID_SERVER, - channel->topic); - } - } - } - - /* If the sender of this packet is server and we are router we need to - broadcast this packet to other routers in the network. Broadcast - this list packet instead of multiple New Channel packets. */ - if (server->server_type == SILC_ROUTER && - idata->conn_type == SILC_CONN_SERVER && - !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) { - SILC_LOG_DEBUG(("Broadcasting received New Channel packet")); - silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), - packet->type, - packet->flags | SILC_PACKET_FLAG_BROADCAST, - buffer->data, silc_buffer_len(buffer)); - silc_server_backup_send(server, (SilcServerEntry)idata, - packet->type, packet->flags, - buffer->data, silc_buffer_len(buffer), - FALSE, TRUE); - } - - silc_free(channel_namec); - silc_channel_payload_free(payload); -} - -/* Received New Channel packet. Information about new channels in the - network are distributed using this packet. Save the information about - the new channel. This usually comes from router but also normal server - can send this to notify channels it has when it connects to us. */ - -void silc_server_new_channel(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - silc_server_new_channel_process(server, sock, packet, &packet->buffer); - silc_packet_free(packet); -} - -/* Received New Channel List packet, list of New Channel List payloads inside - one packet. Process the New Channel payloads one by one. */ - -void silc_server_new_channel_list(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcIDListData idata = silc_packet_get_context(sock); - SilcBuffer buffer; - SilcUInt16 len1, len2; - - SILC_LOG_DEBUG(("Processing New Channel List")); - - if (idata->conn_type == SILC_CONN_CLIENT || - packet->src_id_type != SILC_ID_SERVER || - server->server_type == SILC_SERVER) { - silc_packet_free(packet); - return; - } - - buffer = silc_buffer_alloc(512); - if (!buffer) { - silc_packet_free(packet); - return; - } - - while (silc_buffer_len(&packet->buffer)) { - SILC_GET16_MSB(len1, packet->buffer.data); - if ((len1 > silc_buffer_len(&packet->buffer)) || - (len1 > silc_buffer_truelen(buffer))) - break; - - SILC_GET16_MSB(len2, packet->buffer.data + 2 + len1); - if ((len2 > silc_buffer_len(&packet->buffer)) || - (len2 > silc_buffer_truelen(buffer))) - break; - - silc_buffer_pull_tail(buffer, 8 + len1 + len2); - silc_buffer_put(buffer, packet->buffer.data, 8 + len1 + len2); - - /* Process the New Channel */ - silc_server_new_channel_process(server, sock, packet, buffer); - - silc_buffer_push_tail(buffer, 8 + len1 + len2); - silc_buffer_pull(&packet->buffer, 8 + len1 + len2); - } - - silc_buffer_free(buffer); - silc_packet_free(packet); -} - -/* Received key agreement packet. This packet is never for us. It is to - the client in the packet's destination ID. Sending of this sort of packet - equals sending private message, ie. it is sent point to point from - one client to another. */ - -void silc_server_key_agreement(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcPacketStream dst_sock; - SilcIDListData idata; - - SILC_LOG_DEBUG(("Start")); - - if (packet->src_id_type != SILC_ID_CLIENT || - packet->dst_id_type != SILC_ID_CLIENT || !packet->dst_id) { - silc_packet_free(packet); - return; - } - - /* Get the route to the client */ - dst_sock = silc_server_get_client_route(server, packet->dst_id, - packet->dst_id_len, NULL, - &idata, NULL); - if (!dst_sock) { - silc_packet_free(packet); - return; - } - - /* Relay the packet */ - silc_server_packet_route(server, dst_sock, packet); - silc_packet_free(packet); -} - -/* Received connection auth request packet that is used during connection - phase to resolve the mandatory authentication method. This packet can - actually be received at anytime but usually it is used only during - the connection authentication phase. Now, protocol says that this packet - can come from client or server, however, we support only this coming - from client and expect that server always knows what authentication - method to use. */ - -void silc_server_connection_auth_request(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcServerConfigClient *client = NULL; - SilcUInt16 conn_type; - int ret; - SilcAuthMethod auth_meth = SILC_AUTH_NONE; - const char *hostname, *ip; - - if (packet->src_id_type && packet->src_id_type != SILC_ID_CLIENT) { - SILC_LOG_DEBUG(("Request not from client")); - silc_packet_free(packet); - return; - } - - silc_socket_stream_get_info(silc_packet_stream_get_stream(sock), - NULL, &hostname, &ip, NULL); - - /* Parse the payload */ - ret = silc_buffer_unformat(&packet->buffer, - SILC_STR_UI_SHORT(&conn_type), - SILC_STR_UI_SHORT(NULL), - SILC_STR_END); - if (ret == -1 || conn_type != SILC_CONN_CLIENT) { - silc_packet_free(packet); - return; - } - - /* Get the authentication method for the client */ - auth_meth = SILC_AUTH_NONE; - client = silc_server_config_find_client(server, (char *)ip); - if (!client) - client = silc_server_config_find_client(server, (char *)hostname); - if (client) { - if (client->passphrase) { - if (client->publickeys && !server->config->prefer_passphrase_auth) - auth_meth = SILC_AUTH_PUBLIC_KEY; - else - auth_meth = SILC_AUTH_PASSWORD; - } else if (client->publickeys) - auth_meth = SILC_AUTH_PUBLIC_KEY; - } - - SILC_LOG_DEBUG(("Authentication method is [%s]", - (auth_meth == SILC_AUTH_NONE ? "None" : - auth_meth == SILC_AUTH_PASSWORD ? "Passphrase" : - "Digital signatures"))); - - /* Send it back to the client */ - silc_server_send_connection_auth_request(server, sock, conn_type, auth_meth); - silc_packet_free(packet); -} - -/* Received file transger packet. This packet is never for us. It is to - the client in the packet's destination ID. Sending of this sort of packet - equals sending private message, ie. it is sent point to point from - one client to another. */ - -void silc_server_ftp(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcPacketStream dst_sock; - SilcIDListData idata; - - SILC_LOG_DEBUG(("Start")); - - if (packet->src_id_type != SILC_ID_CLIENT || - packet->dst_id_type != SILC_ID_CLIENT || !packet->dst_id) { - silc_packet_free(packet); - return; - } - - /* Get the route to the client */ - dst_sock = silc_server_get_client_route(server, packet->dst_id, - packet->dst_id_len, NULL, - &idata, NULL); - if (!dst_sock) { - silc_packet_free(packet); - return; - } - - /* Relay the packet */ - silc_server_packet_route(server, dst_sock, packet); - silc_packet_free(packet); -} - -typedef struct { - SilcServer server; - SilcPacketStream sock; - SilcPacket packet; - SilcClientID client_id; -} *SilcServerResumeResolve; - -SILC_SERVER_CMD_FUNC(resume_resolve) -{ - SilcServerResumeResolve r = (SilcServerResumeResolve)context; - SilcServer server = r->server; - SilcPacketStream sock = r->sock; - SilcServerCommandReplyContext reply = context2; - SilcClientEntry client; - const char *hostname, *ip; - - SILC_LOG_DEBUG(("Start")); - - silc_socket_stream_get_info(silc_packet_stream_get_stream(sock), - NULL, &hostname, &ip, NULL); - - if (!reply || !silc_command_get_status(reply->payload, NULL, NULL)) { - SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, " - "closing connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } - - if (reply && silc_command_get(reply->payload) == SILC_COMMAND_WHOIS) { - /* Get entry to the client, and resolve it if we don't have it. */ - client = silc_idlist_find_client_by_id(server->local_list, - &r->client_id, TRUE, NULL); - if (!client) { - client = silc_idlist_find_client_by_id(server->global_list, - &r->client_id, TRUE, NULL); - if (!client) { - SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, " - "closing connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } - } - - if (!(client->mode & SILC_UMODE_DETACHED)) { - SILC_LOG_ERROR(("Client %s (%s) tried to resume un-detached client, " - "closing connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } - - client->data.status |= SILC_IDLIST_STATUS_RESUME_RES; - } - - /* Reprocess the packet */ - silc_server_resume_client(server, sock, r->packet); - - out: - silc_packet_stream_unref(r->sock); - silc_free(r); -} - -/* Received client resuming packet. This is used to resume detached - client session. It can be sent by the client who wishes to resume - but this is also sent by servers and routers to notify other routers - that the client is not detached anymore. */ - -void silc_server_resume_client(SilcServer server, - SilcPacketStream sock, - SilcPacket packet) -{ - SilcBuffer buffer = &packet->buffer, buf; - SilcIDListData idata = silc_packet_get_context(sock); - SilcIDCacheEntry id_cache = NULL; - SilcClientEntry detached_client; - SilcClientID client_id; - unsigned char *id_string, *auth = NULL, *nicknamec = NULL; - unsigned char cid[32]; - SilcUInt32 cid_len; - SilcUInt16 id_len, auth_len = 0; - SilcBool resolved, local, nick_change = FALSE, resolve = FALSE; - SilcChannelEntry channel; - SilcHashTableList htl; - SilcChannelClientEntry chl; - SilcServerResumeResolve r; - SilcPublicKey public_key; - const char *cipher, *hostname, *ip; - - silc_socket_stream_get_info(silc_packet_stream_get_stream(sock), - NULL, &hostname, &ip, NULL); - - if (silc_buffer_unformat(buffer, - SILC_STR_UI16_NSTRING(&id_string, &id_len), - SILC_STR_END) < 0) { - if (idata->conn_type == SILC_CONN_CLIENT) { - SILC_LOG_ERROR(("Client %s (%s) sent incomplete resume information, " - "closing connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - } - goto out; - } - - silc_id_str2id(id_string, id_len, SILC_ID_CLIENT, &client_id, - sizeof(client_id)); - - if (idata->conn_type == SILC_CONN_CLIENT) { - /* Client send this and is attempting to resume to old client session */ - SilcClientEntry client; - SilcBuffer keyp; - - silc_buffer_pull(buffer, 2 + id_len); - auth = buffer->data; - auth_len = silc_buffer_len(buffer); - silc_buffer_push(buffer, 2 + id_len); - - if (auth_len < 128) { - SILC_LOG_ERROR(("Client %s (%s) sent incomplete resume information, " - "closing connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } - - /* Take client entry of this connection */ - client = (SilcClientEntry)idata; - - /* Get entry to the client, and resolve it if we don't have it. */ - detached_client = silc_server_query_client(server, &client_id, FALSE, - &resolved); - if (!detached_client) { - if (resolved) { - /* The client info is being resolved. Reprocess this packet after - receiving the reply to the query. */ - SILC_LOG_DEBUG(("Resolving client")); - r = silc_calloc(1, sizeof(*r)); - if (!r) - goto out; - silc_packet_stream_ref(sock); - r->server = server; - r->sock = sock; - r->packet = packet; - r->client_id = client_id; - silc_server_command_pending(server, SILC_COMMAND_WHOIS, - server->cmd_ident, - silc_server_command_resume_resolve, r); - return; - } else { - SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, " - "closing connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } - } - - if (detached_client->data.status & SILC_IDLIST_STATUS_RESUMED) { - SILC_LOG_ERROR(("Client %s (%s) tried to attach more than once, " - "closing connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } - - if (detached_client->resuming_client && - detached_client->resuming_client != client) { - SILC_LOG_ERROR(("Client %s (%s) tried to attach more than once, " - "closing connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } - - 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) && - detached_client->router) - resolve = TRUE; - if (!detached_client->nickname) - resolve = TRUE; - if (detached_client->data.status & SILC_IDLIST_STATUS_RESUME_RES) - resolve = FALSE; - - if (resolve) { - if (server->server_type == SILC_SERVER && !server->standalone) { - /* The client info is being resolved. Reprocess this packet after - receiving the reply to the query. */ - SILC_LOG_DEBUG(("Resolving client info")); - silc_server_query_client(server, &client_id, TRUE, NULL); - r = silc_calloc(1, sizeof(*r)); - if (!r) - return; - silc_packet_stream_ref(sock); - r->server = server; - r->sock = sock; - r->packet = packet; - r->client_id = client_id; - silc_server_command_pending(server, SILC_COMMAND_WHOIS, - server->cmd_ident, - silc_server_command_resume_resolve, r); - return; - } - if (server->server_type == SILC_SERVER) { - SILC_LOG_ERROR(("Client %s (%s) tried to resume un-detached client, " - "closing connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } - } - - /* Check that we have the public key of the client, if not then we must - resolve it first. */ - if (!detached_client->data.public_key) { - if (server->server_type == SILC_SERVER && server->standalone) { - SILC_LOG_ERROR(("Detached client's public key not present, " - "closing connection")); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } else { - /* We must retrieve the detached client's public key by sending - GETKEY command. Reprocess this packet after receiving the key */ - SilcBuffer idp = silc_id_payload_encode(&client_id, SILC_ID_CLIENT); - SilcPacketStream dest_sock = - silc_server_get_client_route(server, NULL, 0, &client_id, - NULL, NULL); - - SILC_LOG_DEBUG(("Resolving client public key")); - - silc_server_send_command(server, dest_sock ? dest_sock : - SILC_PRIMARY_ROUTE(server), - SILC_COMMAND_GETKEY, ++server->cmd_ident, - 1, 1, idp->data, silc_buffer_len(idp)); - - r = silc_calloc(1, sizeof(*r)); - if (!r) - return; - silc_packet_stream_ref(sock); - r->server = server; - r->sock = sock; - r->packet = packet; - r->client_id = client_id; - silc_server_command_pending(server, SILC_COMMAND_GETKEY, - server->cmd_ident, - silc_server_command_resume_resolve, r); - - silc_buffer_free(idp); - return; - } - } else if (!silc_pkcs_public_key_compare(detached_client->data.public_key, - idata->public_key)) { - /* We require that the connection and resuming authentication data - must be using same key pair. */ - SILC_LOG_ERROR(("Resuming attempted with wrong public key, " - "closing connection")); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } - - /* Verify the authentication payload. This has to be successful in - order to allow the resuming */ - if (!idata->hash || - !silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY, - detached_client->data.public_key, 0, - idata->hash, detached_client->id, - SILC_ID_CLIENT)) { - SILC_LOG_ERROR(("Client %s (%s) resume authentication failed, " - "closing connection", hostname, ip)); - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_INCOMPLETE_INFORMATION, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } - - /* 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"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } - - /* 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)) { - SilcClientID *new_id; - if (!silc_id_create_client_id(server, server->id, server->rng, - server->md5hash, nicknamec, - strlen(nicknamec), &new_id)) { - silc_server_disconnect_remote(server, sock, - SILC_STATUS_ERR_BAD_NICKNAME, - "Resuming not possible"); - silc_server_free_sock_user_data(server, sock, NULL); - goto out; - } - nick_change = TRUE; - client_id = *new_id; - silc_free(new_id); - } - - /* Now resume the client to the network */ - - silc_schedule_task_del_by_context(server->schedule, detached_client); - silc_packet_set_context(sock, detached_client); - detached_client->connection = sock; - - if (detached_client->data.public_key) { - /* Delete the detached client's public key from repository */ - silc_skr_del_public_key(server->repository, - detached_client->data.public_key, - detached_client); - detached_client->data.public_key = NULL; - } - - if (idata->public_key) { - /* Delete the resuming client's public key from repository. It will - be added later again. */ - public_key = silc_pkcs_public_key_copy(idata->public_key); - silc_skr_del_public_key(server->repository, idata->public_key, idata); - idata->public_key = public_key; - } - - /* 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) { - /* Add the resumed client's public key back to repository. */ - if (!silc_server_get_public_key_by_client(server, detached_client, NULL)) - silc_skr_add_public_key_simple(server->repository, - detached_client->data.public_key, - SILC_SKR_USAGE_IDENTIFICATION, - detached_client, NULL); - } - - detached_client->data.status |= SILC_IDLIST_STATUS_REGISTERED; - detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED; - detached_client->data.status |= SILC_IDLIST_STATUS_LOCAL; - detached_client->data.status &= ~SILC_IDLIST_STATUS_RESUME_RES; - 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); - silc_buffer_format(buf, - SILC_STR_UI_SHORT(id_len), - SILC_STR_UI_XNSTRING(id_string, id_len), - SILC_STR_END); - - /* Send to primary router */ - silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), - SILC_PACKET_RESUME_CLIENT, 0, - buf->data, silc_buffer_len(buf)); - silc_server_backup_send(server, client->router, - SILC_PACKET_RESUME_CLIENT, 0, - buf->data, silc_buffer_len(buf), 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 && client->router && - client->router->server_type != SILC_ROUTER) - silc_server_packet_send(server, client->router->connection, - SILC_PACKET_RESUME_CLIENT, 0, - buf->data, silc_buffer_len(buf)); - silc_buffer_free(buf); - client->router = NULL; - - if (nick_change) { - /* Notify about Client ID change, nickname doesn't actually change. */ - silc_server_send_notify_nick_change(server, SILC_PRIMARY_ROUTE(server), - SILC_BROADCAST(server), - client->id, &client_id, - client->nickname); - } - - /* Resolve users on those channels that client has joined but we - 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)) { - channel = chl->channel; - SILC_LOG_DEBUG(("Resolving users for %s channel", - channel->channel_name)); - if (channel->disabled || !channel->users_resolved) { - silc_server_send_command(server, SILC_PRIMARY_ROUTE(server), - SILC_COMMAND_USERS, ++server->cmd_ident, - 1, 2, channel->channel_name, - strlen(channel->channel_name)); - } - } - silc_hash_table_list_reset(&htl); - } - - /* Send the new client ID to the client. After this client may start - receiving other packets, and may start sending packets too. */ - silc_server_send_new_id(server, sock, FALSE, &client_id, SILC_ID_CLIENT, - silc_id_get_len(&client_id, SILC_ID_CLIENT)); - - if (nick_change) { - /* Send NICK change notify to channels as well. */ - SilcBuffer oidp, nidp; - oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); - nidp = silc_id_payload_encode(&client_id, SILC_ID_CLIENT); - silc_server_send_notify_on_channels(server, NULL, client, - SILC_NOTIFY_TYPE_NICK_CHANGE, 3, - oidp->data, silc_buffer_len(oidp), - nidp->data, silc_buffer_len(nidp), - client->nickname, - strlen(client->nickname)); - silc_buffer_free(oidp); - silc_buffer_free(nidp); - } - - /* Add the client again to the ID cache to get it to correct list */ - if (!silc_idcache_del_by_context(server->local_list->clients, client, - NULL)) - silc_idcache_del_by_context(server->global_list->clients, client, NULL); - silc_free(client->id); - *client->id = client_id; - silc_idcache_add(server->local_list->clients, nicknamec, - client->id, client); - - /* Send some nice info to the client */ - silc_server_send_connect_notifys(server, sock, client); - - /* 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)) { - SilcBool created = FALSE; - channel = chl->channel; - - if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) - continue; - - /* If we don't have channel key, then create one */ - if (!channel->send_key) { - if (!silc_server_create_channel_key(server, channel, 0)) - continue; - created = TRUE; - } - - silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid), - &cid_len); - cipher = silc_cipher_get_name(channel->send_key); - keyp = - silc_channel_key_payload_encode(cid_len, cid, - strlen(cipher), cipher, - channel->key_len / 8, channel->key); - - /* Send the channel key to the client */ - silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, - keyp->data, silc_buffer_len(keyp)); - - /* Distribute the channel key to channel */ - if (created) { - silc_server_send_channel_key(server, NULL, channel, - server->server_type == SILC_ROUTER ? - FALSE : !server->standalone); - silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0, - keyp->data, silc_buffer_len(keyp), - FALSE, TRUE); - } - - silc_buffer_free(keyp); - } - silc_hash_table_list_reset(&htl); - - } else if (idata->conn_type != SILC_CONN_CLIENT) { - /* Server or router sent this to us to notify that that a client has - been resumed. */ - SilcServerEntry server_entry; - SilcServerID server_id; - - /* Get entry to the client, and resolve it if we don't have it. */ - detached_client = silc_idlist_find_client_by_id(server->local_list, - &client_id, TRUE, - &id_cache); - if (!detached_client) { - detached_client = silc_idlist_find_client_by_id(server->global_list, - &client_id, TRUE, - &id_cache); - if (!detached_client) { - SILC_LOG_DEBUG(("Resuming client is unknown")); - goto out; - } - } - - /* Check that the client has not been resumed already because it is - protocol error to attempt to resume more than once. The client - will be killed if this protocol error occurs. */ - if (detached_client->data.status & SILC_IDLIST_STATUS_RESUMED && - !(detached_client->mode & SILC_UMODE_DETACHED)) { - /* The client is clearly attempting to resume more than once and - perhaps playing around by resuming from several different places - at the same time. */ - SILC_LOG_DEBUG(("Attempting to re-resume client, killing both")); - silc_server_kill_client(server, detached_client, NULL, - server->id, SILC_ID_SERVER); - goto out; - } - - /* Check whether client is detached at all */ - if (!(detached_client->mode & SILC_UMODE_DETACHED)) { - SILC_LOG_DEBUG(("Client is not detached")); - goto out; - } - - /* Check nickname */ - if (detached_client->nickname) { - nicknamec = silc_identifier_check(detached_client->nickname, - strlen(detached_client->nickname), - SILC_STRING_UTF8, 128, NULL); - if (!nicknamec) - goto out; - } - - SILC_LOG_DEBUG(("Resuming detached client")); - - /* If the sender of this packet is server and we are router we need to - broadcast this packet to other routers in the network. */ - if (server->server_type == SILC_ROUTER && - idata->conn_type == SILC_CONN_SERVER && - !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) { - SILC_LOG_DEBUG(("Broadcasting received Resume Client packet")); - silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), - packet->type, - packet->flags | SILC_PACKET_FLAG_BROADCAST, - buffer->data, silc_buffer_len(buffer)); - silc_server_backup_send(server, (SilcServerEntry)idata, - packet->type, packet->flags, - packet->buffer.data, - silc_buffer_len(&packet->buffer), - FALSE, TRUE); - } - - /* Client is detached, and now it is resumed. Remove the detached - mode and mark that it is resumed. */ - - if (detached_client->data.public_key) { - /* Delete the detached client's public key from repository */ - silc_skr_del_public_key(server->repository, - detached_client->data.public_key, - detached_client); - detached_client->data.public_key = NULL; - } - - 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; - silc_dlist_del(server->expired_clients, detached_client); - - /* 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 */ - if (!silc_id_str2id(packet->src_id, packet->src_id_len, - packet->src_id_type, &server_id, sizeof(server_id))) - goto out; - - /* Get server entry */ - server_entry = silc_idlist_find_server_by_id(server->global_list, - &server_id, TRUE, NULL); - local = FALSE; - if (!server_entry) { - server_entry = silc_idlist_find_server_by_id(server->local_list, - &server_id, TRUE, NULL); - local = TRUE; - if (!server_entry) - goto out; - } - - if (server->server_type == SILC_ROUTER && - idata->conn_type == SILC_CONN_ROUTER && - server_entry->server_type == SILC_ROUTER) - local = FALSE; - - /* Change the client to correct list. */ - if (!silc_idcache_del_by_context(server->local_list->clients, - detached_client, NULL)) - silc_idcache_del_by_context(server->global_list->clients, - detached_client, NULL); - silc_idcache_add(local && server->server_type == SILC_ROUTER ? - server->local_list->clients : - server->global_list->clients, nicknamec, - detached_client->id, detached_client); - - /* Change the owner of the client */ - detached_client->router = server_entry; - - /* 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)) - chl->channel->global_users = - silc_server_channel_has_global(chl->channel); - silc_hash_table_list_reset(&htl); - } - } - - out: - silc_packet_free(packet); -}