/* Remove the client from all channels. */
silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, 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);
+
client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
break;
/* Get user's channel entry and check that topic set is allowed. */
if (!silc_server_client_on_channel(client, channel, &chl))
goto out;
- if (chl->mode == SILC_CHANNEL_UMODE_NONE &&
- channel->mode & SILC_CHANNEL_MODE_TOPIC) {
+ 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;
}
nickname = silc_argument_get_arg_type(args, 3, &nickname_len);;
/* Replace the Client ID */
- client = silc_idlist_replace_client_id(server->global_list, client_id,
+ client = silc_idlist_replace_client_id(server,
+ server->global_list, client_id,
client_id2, nickname);
if (!client)
- client = silc_idlist_replace_client_id(server->local_list, client_id,
+ client = silc_idlist_replace_client_id(server,
+ server->local_list, client_id,
client_id2, nickname);
if (client) {
/* Send the NICK_CHANGE notify type to local clients on the channels
this client is joined to. */
- silc_server_send_notify_on_channels(server, NULL, client,
+ silc_server_send_notify_on_channels(server, client, client,
SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
id, tmp_len, id2, tmp_len,
nickname, nickname ?
/* 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);
+ 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));
if (client != client2) {
/* Sender must be operator */
- if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+ if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
SILC_LOG_DEBUG(("CUMODE change is not allowed"));
goto out;
}
/* Get user's channel entry and check that inviting is allowed. */
if (!silc_server_client_on_channel(client, channel, &chl))
goto out;
- if (chl->mode == SILC_CHANNEL_UMODE_NONE &&
- channel->mode & SILC_CHANNEL_MODE_INVITE) {
+ if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
SILC_LOG_DEBUG(("Inviting is not allowed"));
goto out;
}
silc_server_remove_from_channels(server, NULL, client,
TRUE, NULL, 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_client(local ? server->local_list :
server->global_list, client);
/* Kicker must be operator on channel */
if (!silc_server_client_on_channel(client2, channel, &chl))
goto out;
- if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+ if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
SILC_LOG_DEBUG(("Kicking is not allowed"));
goto out;
}
silc_server_remove_from_channels(server, NULL, client, FALSE, NULL,
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_KILLED);
+
break;
}
/* 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:
}
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 &&
+ sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp) {
+ SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
+ "the entry from cache"));
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, FALSE, NULL);
+ if (client) {
+ silc_server_remove_from_channels(server, NULL, client, TRUE,
+ NULL, TRUE);
+ silc_idlist_del_client(server->global_list, client);
+ }
+ silc_free(client_id);
+ }
+ }
+ }
+ break;
+
/* Ignore rest of the notify types for now */
case SILC_NOTIFY_TYPE_NONE:
case SILC_NOTIFY_TYPE_MOTD:
&idata, &client);
if (!dst_sock) {
SilcBuffer idp;
+ unsigned char error;
if (client && client->mode & SILC_UMODE_DETACHED) {
- SILC_LOG_DEBUG(("Locally connected client is detached, "
- "discarding packet"));
+ SILC_LOG_DEBUG(("Client is detached, discarding packet"));
return;
}
- /* Send IDENTIFY command reply with error status to indicate that
- such destination ID does not exist or is invalid */
+ /* 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)
return;
+ error = SILC_STATUS_ERR_NO_SUCH_CLIENT_ID;
if (packet->src_id_type == SILC_ID_CLIENT) {
SilcClientID *client_id = silc_id_str2id(packet->src_id,
packet->src_id_len,
packet->src_id_type);
- silc_server_send_dest_command_reply(server, sock,
- client_id, SILC_ID_CLIENT,
- SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
- 0, 0, 1, 2, idp->data, idp->len);
+ silc_server_send_notify_dest(server, sock, FALSE,
+ client_id, SILC_ID_CLIENT,
+ SILC_NOTIFY_TYPE_ERROR, 2,
+ &error, 1,
+ idp->data, idp->len);
silc_free(client_id);
} else {
- silc_server_send_command_reply(server, sock, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
- 0, 1, 2, idp->data, idp->len);
+ silc_server_send_notify(server, sock, FALSE,
+ SILC_NOTIFY_TYPE_ERROR, 2,
+ &error, 1,
+ idp->data, idp->len);
}
silc_buffer_free(idp);
if (!channel) {
channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
if (!channel) {
- SILC_LOG_DEBUG(("Could not find 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) {
+ SilcClientID *client_id = silc_id_str2id(packet->src_id,
+ packet->src_id_len,
+ packet->src_id_type);
+ silc_server_send_notify_dest(server, sock, FALSE,
+ client_id, SILC_ID_CLIENT,
+ SILC_NOTIFY_TYPE_ERROR, 2,
+ &error, 1, idp->data, idp->len);
+ silc_free(client_id);
+ } else {
+ silc_server_send_notify(server, sock, FALSE,
+ SILC_NOTIFY_TYPE_ERROR, 2,
+ &error, 1, idp->data, idp->len);
+ }
+
+ silc_buffer_free(idp);
goto out;
}
}
/* If channel is moderated check that client is allowed to send
messages. */
- if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chl->mode) {
+ 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;
}
SilcBuffer buffer = packet->buffer;
SilcClientEntry client;
SilcClientID *client_id;
- SilcBuffer reply;
SilcIDListData idata;
- char *username = NULL, *realname = NULL, *id_string;
+ char *username = NULL, *realname = NULL;
SilcUInt16 username_len;
SilcUInt32 id_len;
int ret;
/* Remove the old cache entry. */
if (!silc_idcache_del_by_context(server->local_list->clients, client)) {
SILC_LOG_INFO(("Unauthenticated client attempted to register to network"));
- silc_server_disconnect_remote(server, sock, "Server closed connection: "
- "You have not been authenticated");
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
return NULL;
}
silc_free(realname);
SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
"connection", sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock, "Server closed connection: "
- "Incomplete client information");
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ NULL);
return NULL;
}
silc_free(realname);
SILC_LOG_ERROR(("Client %s (%s) did not send its username, closing "
"connection", sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock, "Server closed connection: "
- "Incomplete client information");
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ NULL);
return NULL;
}
SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
"connection", sock->hostname, sock->ip));
silc_server_disconnect_remote(server, sock,
- "Server closed connection: "
- "Incomplete client information");
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ NULL);
return NULL;
}
SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
"connection", sock->hostname, sock->ip));
silc_server_disconnect_remote(server, sock,
- "Server closed connection: "
- "Incomplete client information");
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ NULL);
return NULL;
}
nickfail++;
if (nickfail > 9) {
silc_server_disconnect_remote(server, sock,
- "Server closed connection: Bad nickname");
+ SILC_STATUS_ERR_BAD_NICKNAME, NULL);
return NULL;
}
snprintf(&nickname[strlen(nickname) - 1], 1, "%d", nickfail);
client->id, SILC_ID_CLIENT, id_len);
/* Send the new client ID to the client. */
- id_string = silc_id_id2str(client->id, SILC_ID_CLIENT);
- reply = silc_buffer_alloc_size(2 + 2 + id_len);
- silc_buffer_format(reply,
- SILC_STR_UI_SHORT(SILC_ID_CLIENT),
- SILC_STR_UI_SHORT(id_len),
- SILC_STR_UI_XNSTRING(id_string, id_len),
- SILC_STR_END);
- silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0,
- reply->data, reply->len, FALSE);
- silc_free(id_string);
- silc_buffer_free(reply);
+ 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);
+
return client;
}
SILC_LOG_INFO(("Unauthenticated %s attempted to register to "
"network", (sock->type == SILC_SOCKET_TYPE_SERVER ?
"server" : "router")));
- silc_server_disconnect_remote(server, sock, "Server closed connection: "
- "You have not been authenticated");
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
return NULL;
}
local = FALSE;
if (!silc_id_is_valid_server_id(server, server_id, sock)) {
SILC_LOG_INFO(("Invalid server ID sent by %s (%s)",
sock->ip, sock->hostname));
- silc_server_disconnect_remote(server, sock, "Server closed connection: "
- "Your Server ID is not valid");
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_BAD_SERVER_ID, NULL);
silc_free(server_name);
return NULL;
}
if (sock->type == SILC_SOCKET_TYPE_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);
}
break;
silc_id_render(channel_id, SILC_ID_CHANNEL),
sock->hostname));
- silc_idlist_add_channel(server->global_list, strdup(channel_name),
- 0, channel_id, sock->user_data, NULL, NULL, 0);
+ channel =
+ silc_idlist_add_channel(server->global_list, strdup(channel_name),
+ 0, channel_id, sock->user_data, NULL, NULL, 0);
+ if (!channel)
+ return;
+
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
SilcServer server;
SilcSocketConnection sock;
SilcPacketContext *packet;
+ void *data;
} *SilcServerResumeResolve;
SILC_SERVER_CMD_FUNC(resume_resolve)
SilcServer server = r->server;
SilcSocketConnection sock = r->sock;
SilcServerCommandReplyContext reply = context2;
+ SilcClientEntry client;
+
+ SILC_LOG_DEBUG(("Start"));
- if (!context2 || !silc_command_get_status(reply->payload, NULL, NULL)) {
+ if (!reply || !silc_command_get_status(reply->payload, NULL, NULL)) {
SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
"closing connection", sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock,
- "Server closed connection: "
- "Incomplete resume information");
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ "Resuming not possible");
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->data, TRUE, NULL);
+ if (!client) {
+ client = silc_idlist_find_client_by_id(server->global_list,
+ r->data, TRUE, NULL);
+ if (!client) {
+ SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
+ "closing connection", sock->hostname, sock->ip));
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ "Resuming not possible");
+ goto out;
+ }
+ }
+
+ if (!(client->mode & SILC_UMODE_DETACHED)) {
+ SILC_LOG_ERROR(("Client %s (%s) tried to resume un-detached client, "
+ "closing connection", sock->hostname, sock->ip));
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ "Resuming not possible");
+ goto out;
+ }
+ }
+
/* Reprocess the packet */
silc_server_resume_client(server, sock, r->packet);
out:
silc_socket_free(r->sock);
silc_packet_context_free(r->packet);
+ silc_free(r->data);
silc_free(r);
}
unsigned char *id_string, *auth = NULL;
SilcUInt16 id_len, auth_len = 0;
int ret, nickfail = 0;
- bool resolved, local;
+ bool resolved, local, nick_change = FALSE;
+ SilcChannelEntry channel;
+ SilcHashTableList htl;
+ SilcChannelClientEntry chl;
SilcServerResumeResolve r;
+ SILC_LOG_DEBUG(("Start"));
+
ret = silc_buffer_unformat(buffer,
SILC_STR_UI16_NSTRING(&id_string, &id_len),
SILC_STR_END);
if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
/* Client send this and is attempting to resume to old client session */
SilcClientEntry client;
- SilcChannelEntry channel;
- SilcHashTableList htl;
- SilcChannelClientEntry chl;
SilcBuffer keyp;
if (ret != -1) {
if (!client_id || auth_len < 128) {
SILC_LOG_ERROR(("Client %s (%s) sent incomplete resume information, "
"closing connection", sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock, "Server closed connection: "
- "Incomplete resume information");
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ "Resuming not possible");
return;
}
idata = (SilcIDListData)client;
/* Get entry to the client, and resolve it if we don't have it. */
- detached_client = silc_server_get_client_resolve(server, client_id,
+ detached_client = silc_server_get_client_resolve(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)
return;
-
r->server = server;
r->sock = silc_socket_dup(sock);
r->packet = silc_packet_context_dup(packet);
+ r->data = silc_id_dup(client_id, SILC_ID_CLIENT);
silc_server_command_pending(server, SILC_COMMAND_WHOIS,
server->cmd_ident,
silc_server_command_resume_resolve, r);
} else {
SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
"closing connection", sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock,
- "Server closed connection: "
- "Incomplete resume information");
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ "Resuming not possible");
}
return;
}
- /* Check that the client is detached */
- if (!(detached_client->mode & SILC_UMODE_DETACHED)) {
- SILC_LOG_ERROR(("Client %s (%s) tried to resume un-detached client, "
- "closing connection", sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock, "Server closed connection: "
- "Incomplete resume information");
- return;
+ /* Check that the client is detached, and that we have other info too */
+ if (!(detached_client->mode & SILC_UMODE_DETACHED) ||
+ !silc_hash_table_count(detached_client->channels) ||
+ !detached_client->nickname) {
+ 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_get_client_resolve(server, client_id, TRUE, NULL);
+ r = silc_calloc(1, sizeof(*r));
+ if (!r)
+ return;
+ r->server = server;
+ r->sock = silc_socket_dup(sock);
+ r->packet = silc_packet_context_dup(packet);
+ r->data = silc_id_dup(client_id, SILC_ID_CLIENT);
+ 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", sock->hostname, sock->ip));
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ "Resuming not possible");
+ return;
+ }
}
/* 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->standalone) {
- silc_server_disconnect_remote(server, sock,
- "Server closed connection: "
- "Incomplete resume information");
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ "Resuming not possible");
} else {
/* We must retrieve the detached client's public key by sending
GETKEY command. Reprocess this packet after receiving the key */
SilcSocketConnection 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 :
server->router->connection,
SILC_COMMAND_GETKEY, ++server->cmd_ident,
- 1, idp->data, idp->len);
+ 1, 1, idp->data, idp->len);
r = silc_calloc(1, sizeof(*r));
if (!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_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ "Resuming not possible");
+ return;
}
/* Verify the authentication payload. This has to be successful in
SILC_ID_CLIENT)) {
SILC_LOG_ERROR(("Client %s (%s) resume authentication failed, "
"closing connection", sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock, "Server closed connection: "
- "Incomplete resume information");
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ "Resuming not possible");
return;
}
/* Now resume the client to the network */
+ silc_schedule_task_del_by_context(server->schedule, detached_client);
sock->user_data = detached_client;
detached_client->connection = sock;
/* Send the RESUME_CLIENT packet to our primary router so that others
know this client isn't detached anymore. */
- if (!server->standalone) {
- 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);
+ 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 */
+ if (!server->standalone)
silc_server_packet_send(server, server->router->connection,
SILC_PACKET_RESUME_CLIENT, 0,
buf->data, buf->len, TRUE);
- silc_buffer_free(buf);
- }
+
+ /* As router we must deliver this packet directly to the original
+ server whom this client was earlier. */
+ if (server->server_type == SILC_ROUTER && detached_client->router &&
+ detached_client->router->server_type != SILC_ROUTER)
+ silc_server_packet_send(server, detached_client->router->connection,
+ SILC_PACKET_RESUME_CLIENT, 0,
+ buf->data, buf->len, TRUE);
+ silc_buffer_free(buf);
+
+ detached_client->router = NULL;
/* Delete this client entry since we're resuming to old one. */
server->stat.my_clients--;
nickfail++;
if (nickfail > 9) {
silc_server_disconnect_remote(server, sock,
- "Server closed connection: "
- "Bad nickname");
+ SILC_STATUS_ERR_BAD_NICKNAME, NULL);
return;
}
snprintf(&client->nickname[strlen(client->nickname) - 1], 1,
"%d", nickfail);
}
+ nick_change = TRUE;
+ }
+ if (nick_change) {
/* Notify about Client ID change, nickname doesn't actually change. */
if (!server->standalone)
silc_server_send_notify_nick_change(server, server->router->connection,
FALSE, client->id, client_id,
client->nickname);
-
- silc_free(client->id);
- client->id = client_id;
+ }
+
+ /* 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, server->router->connection,
+ 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, oidp->len,
+ nidp->data, nidp->len,
+ 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))
silc_idcache_del_by_context(server->global_list->clients, client);
+ silc_free(client->id);
+ client->id = client_id;
+ client_id = NULL;
silc_idcache_add(server->local_list->clients, client->nickname,
- client->id, client, client->mode, NULL);
-
- /* Send the new client ID to the client. */
- id_string = silc_id_id2str(client->id, SILC_ID_CLIENT);
- buf = silc_buffer_alloc_size(2 + 2 + id_len);
- silc_buffer_format(buf,
- SILC_STR_UI_SHORT(SILC_ID_CLIENT),
- SILC_STR_UI_SHORT(id_len),
- SILC_STR_UI_XNSTRING(id_string, id_len),
- SILC_STR_END);
- silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0,
- buf->data, buf->len, FALSE);
- silc_free(id_string);
- silc_buffer_free(buf);
+ client->id, client, 0, NULL);
/* 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)) {
+ bool 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->channel_key) {
+ if (!silc_server_create_channel_key(server, channel, 0))
+ continue;
+ created = TRUE;
+ }
+
id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
keyp =
silc_channel_key_payload_encode(silc_id_get_len(channel->id,
/* Send the key packet to client */
silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
keyp->data, keyp->len, FALSE);
+
+ if (created && server->server_type == SILC_SERVER &&
+ !server->standalone)
+ silc_server_packet_send(server, server->router->connection,
+ SILC_PACKET_CHANNEL_KEY, 0,
+ keyp->data, keyp->len, FALSE);
+
+ silc_buffer_free(keyp);
}
silc_hash_table_list_reset(&htl);
- SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
- ("Your session is successfully resumed"));
-
} else if (sock->type != SILC_SOCKET_TYPE_CLIENT) {
/* Server or router sent this to us to notify that that a client has
been resumed. */
}
}
+ if (server->server_type == SILC_ROUTER &&
+ sock->type == SILC_SOCKET_TYPE_ROUTER &&
+ server_entry->server_type == SILC_ROUTER)
+ local = FALSE;
+
+ SILC_LOG_DEBUG(("Resuming detached client"));
+
/* Change the client to correct list. */
if (!silc_idcache_del_by_context(server->local_list->clients,
detached_client))
silc_idcache_del_by_context(server->global_list->clients,
detached_client);
- silc_idcache_add(local ? server->local_list->clients :
- server->global_list->clients, detached_client->nickname,
+ silc_idcache_add(local && server->server_type == SILC_ROUTER ?
+ server->local_list->clients :
+ server->global_list->clients,
+ detached_client->nickname,
detached_client->id, detached_client, FALSE, NULL);
/* Change the owner of the client if needed */
if (detached_client->router != server_entry)
detached_client->router = server_entry;
+ /* Update channel information regarding global clients on channel. */
+ if (server->server_type == SILC_SERVER) {
+ 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);
+ }
+
+ silc_schedule_task_del_by_context(server->schedule, 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->standalone && server->server_type == SILC_ROUTER &&