silc_hash_table_add(client->channels, channel, chl);
silc_free(client_id);
channel->user_count++;
+ channel->disabled = FALSE;
break;
/* 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) {
FALSE : !server->standalone);
}
- /* Change mode */
- channel->mode = mode;
-
/* Get the hmac */
tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
if (tmp) {
/* 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));
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_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
+
+ if (!channel->founder_key ||
+ (client && client->data.public_key &&
+ server->server_type == SILC_ROUTER &&
+ !silc_pkcs_public_key_compare(channel->founder_key,
+ client->data.public_key))) {
+ /* A really buggy server isn't checking public keys correctly.
+ It's not possible that the mode setter and founder wouldn't
+ have same public 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);
+ if (channel->founder_key)
+ silc_pkcs_public_key_free(channel->founder_key);
+ channel->founder_key = NULL;
+ } else if (client && !client->data.public_key) {
+ client->data.public_key =
+ silc_pkcs_public_key_copy(channel->founder_key);
+ }
+ }
+
+ 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);
+ }
+
+ /* Change mode */
+ channel->mode = mode;
+
+ if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) &&
+ channel->founder_key) {
+ silc_pkcs_public_key_free(channel->founder_key);
+ channel->founder_key = NULL;
+ }
+
break;
case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
if (!silc_server_client_on_channel(client, channel, &chl))
goto out;
- if (client != client2) {
+ if (client != client2 && server->server_type == SILC_ROUTER) {
/* 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;
}
- /* Check that target is on channel */
if (!silc_server_client_on_channel(client2, channel, &chl))
goto out;
}
}
- /* Get entry to the channel user list */
- silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
- /* If the mode is channel founder and we already find a client
- to have that mode on the channel we will enforce the sender
- to change the channel founder mode away. There can be only one
- channel founder on the channel. */
- if (server->server_type == SILC_ROUTER &&
- mode & SILC_CHANNEL_UMODE_CHANFO &&
- chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
- SilcBuffer idp;
- unsigned char cumode[4];
-
- if (chl->client == client && chl->mode == mode) {
+ /* Get target channel entry */
+ if (!silc_server_client_on_channel(client2, channel, &chl))
+ goto out;
+
+ if (mode & SILC_CHANNEL_UMODE_CHANFO &&
+ !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && !client &&
+ server->server_type == SILC_ROUTER) {
+ /* 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) {
+ 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;
+ }
+ if (client && mode & SILC_CHANNEL_UMODE_CHANFO &&
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
+ server->server_type == SILC_ROUTER) {
+ /* Check whether this client is allowed to be channel founder on
+ this channel. */
+ 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. */
+ if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
+ /* Force the mode to not have founder mode */
mode &= ~SILC_CHANNEL_UMODE_CHANFO;
- silc_server_send_notify_cumode(server, sock, FALSE, channel, mode,
- client2->id, SILC_ID_CLIENT,
- client2->id);
-
- idp = silc_id_payload_encode(client2->id, SILC_ID_CLIENT);
- SILC_PUT32_MSB(mode, cumode);
- silc_server_send_notify_to_channel(server, sock, channel, FALSE,
- SILC_NOTIFY_TYPE_CUMODE_CHANGE,
- 3, idp->data, idp->len,
- cumode, 4,
- idp->data, idp->len);
- silc_buffer_free(idp);
+ silc_server_force_cumode_change(server, sock, channel, chl, mode);
notify_sent = TRUE;
-
- /* Force the mode change if we alredy set the mode */
- if (chl2) {
- chl2->mode = mode;
- silc_free(channel_id);
- silc_hash_table_list_reset(&htl);
- goto out;
- }
+ break;
}
-
- if (chl->client == client2) {
- if (chl->mode == mode) {
+
+ /* 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) {
+ 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 of the channel. Since the founder auth mode
+ is set on the channel now check whether this is the client that
+ originally set the mode. */
+
+ /* Get public key that must be present in notify */
+ tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+ if (!tmp || !silc_pkcs_public_key_decode(tmp, tmp_len,
+ &founder_key)) {
+ mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ silc_server_force_cumode_change(server, sock, channel, chl, mode);
+ notify_sent = TRUE;
+ break;
+ }
- SILC_LOG_DEBUG(("Changing the channel user mode"));
-
- /* Change the mode */
- chl->mode = mode;
- if (!(mode & SILC_CHANNEL_UMODE_CHANFO))
- break;
-
- chl2 = chl;
+ /* Now match the public key we have cached and public key sent.
+ They must match. */
+ if (client->data.public_key &&
+ !silc_pkcs_public_key_compare(channel->founder_key,
+ client->data.public_key)) {
+ mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ silc_server_force_cumode_change(server, sock, channel, chl, mode);
+ notify_sent = TRUE;
+ break;
}
+ if (!silc_pkcs_public_key_compare(channel->founder_key,
+ founder_key)) {
+ mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ silc_server_force_cumode_change(server, sock, channel, chl, mode);
+ notify_sent = TRUE;
+ break;
+ }
+
+ if (founder_key)
+ silc_pkcs_public_key_free(founder_key);
}
- silc_hash_table_list_reset(&htl);
-
+
+ SILC_LOG_DEBUG(("Changing the channel user mode"));
+
+ /* 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,
/* 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;
}
}
if (channel_id2) {
- SilcBuffer users = NULL, users_modes = NULL;
+ 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->mode);
/* Re-announce our clients on the channel as the ID has changed now */
- silc_server_announce_get_channel_users(server, channel, &users,
+ silc_server_announce_get_channel_users(server, channel, &modes, &users,
&users_modes);
+ 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, modes->len, FALSE);
+ silc_buffer_free(modes);
+ }
if (users) {
silc_buffer_push(users, users->data - users->head);
silc_server_packet_send(server, sock,
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(("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;
}
/* 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);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, 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);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, 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);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, 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);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, 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);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
return NULL;
}
nickfail++;
if (nickfail > 9) {
silc_server_disconnect_remote(server, sock,
- "Server closed connection: Bad nickname");
+ SILC_STATUS_ERR_BAD_NICKNAME, NULL);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
return NULL;
}
snprintf(&nickname[strlen(nickname) - 1], 1, "%d", nickfail);
/* 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);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
return NULL;
}
local = FALSE;
&name_len),
SILC_STR_END);
if (ret == -1) {
- if (id_string)
- silc_free(id_string);
- if (server_name)
- silc_free(server_name);
+ silc_free(id_string);
+ silc_free(server_name);
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ NULL);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
return NULL;
}
if (id_len > buffer->len) {
silc_free(id_string);
silc_free(server_name);
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ NULL);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
return NULL;
}
if (!server_id) {
silc_free(id_string);
silc_free(server_name);
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ NULL);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
return NULL;
}
silc_free(id_string);
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);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, 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;
0, channel_id, sock->user_data, NULL, NULL, 0);
if (!channel)
return;
+ channel->disabled = TRUE;
server->stat.channels++;
if (server->server_type == SILC_ROUTER)
silc_free(channel_id);
return;
}
+ channel->disabled = TRUE;
+#if 0
+ /* CMODE change notify is expected */
/* Get the mode and set it to the channel */
channel->mode = silc_channel_get_mode(payload);
+#endif
/* Send the new channel key to the server */
id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
/* 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 users = NULL, users_modes = NULL;
+ SilcBuffer modes = NULL, users = NULL, users_modes = NULL;
if (!SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
/* They don't match, send CHANNEL_CHANGE notify to the server to
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);
+ SILC_ID_SERVER, channel->cipher,
+ channel->hmac_name,
+ channel->passphrase,
+ channel->founder_key);
}
/* 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_server_create_channel_key(server, channel, 0))
return;
/* 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, &users,
+ silc_server_announce_get_channel_users(server, channel, &modes, &users,
&users_modes);
+ 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, modes->len, FALSE);
+ silc_buffer_free(modes);
+ }
if (users) {
silc_buffer_push(users, users->data - users->head);
silc_server_packet_send(server, sock,
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 (!client) {
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 (!(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");
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ "Resuming not possible");
goto out;
}
}
unsigned char *id_string, *auth = NULL;
SilcUInt16 id_len, auth_len = 0;
int ret, nickfail = 0;
- bool resolved, local, nick_change = FALSE;
+ bool resolved, local, nick_change = FALSE, resolve = FALSE;
SilcChannelEntry channel;
SilcHashTableList htl;
SilcChannelClientEntry chl;
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;
}
} 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, 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 (!(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 (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_server_command_pending(server, SILC_COMMAND_WHOIS,
server->cmd_ident,
silc_server_command_resume_resolve, r);
- } else {
+ 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,
- "Server closed connection: "
- "Incomplete resume information");
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+ "Resuming not possible");
+ return;
}
- 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");
+ if (server->server_type == SILC_SERVER && server->standalone) {
+ 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 */
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
order to allow the resuming */
- if (!silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
+ 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", 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;
/* 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)
+ 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);
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,
}
}
+ 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. */
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 &&