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->standalone && server->server_type == SILC_ROUTER &&
+ if (server->server_type == SILC_ROUTER &&
sock->type == SILC_SOCKET_TYPE_SERVER &&
!(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
SILC_LOG_DEBUG(("Broadcasting received Notify packet"));
if (!channel_id)
goto out;
- silc_server_packet_send_dest(server, server->router->connection,
- packet->type,
- packet->flags | SILC_PACKET_FLAG_BROADCAST,
- channel_id, SILC_ID_CHANNEL,
- packet->buffer->data, packet->buffer->len,
- FALSE);
+ if (!server->standalone)
+ silc_server_packet_send_dest(server, server->router->connection,
+ packet->type, packet->flags |
+ SILC_PACKET_FLAG_BROADCAST,
+ channel_id, SILC_ID_CHANNEL,
+ packet->buffer->data,
+ packet->buffer->len, FALSE);
silc_server_backup_send_dest(server, (SilcServerEntry)sock->user_data,
packet->type, packet->flags,
channel_id, SILC_ID_CHANNEL,
FALSE, TRUE);
} else {
/* Packet is destined to client or server */
- silc_server_packet_send(server, server->router->connection,
- packet->type,
- packet->flags | SILC_PACKET_FLAG_BROADCAST,
- packet->buffer->data, packet->buffer->len,
- FALSE);
+ if (!server->standalone)
+ silc_server_packet_send(server, server->router->connection,
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ packet->buffer->data, packet->buffer->len,
+ FALSE);
silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
packet->type, packet->flags,
packet->buffer->data, packet->buffer->len,
silc_hash_table_add(client->channels, channel, chl);
silc_free(client_id);
channel->user_count++;
+ channel->disabled = FALSE;
+
+ /* Update statistics */
+ if (server->server_type == SILC_ROUTER) {
+ if (sock->type != SILC_SOCKET_TYPE_ROUTER)
+ server->stat.cell_chanclients++;
+ server->stat.chanclients++;
+ }
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) {
SILC_LOG_DEBUG(("CMODE change is not allowed"));
goto out;
}
+ } else {
+ if (server->server_type == SILC_ROUTER &&
+ 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);
+ goto out;
+ }
}
/* Send the same notify to the channel */
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);
silc_idlist_del_server(local ? server->local_list :
server->global_list, server_entry);
- /* XXX update statistics */
+ /* Update statistics */
+ if (server->server_type == SILC_ROUTER)
+ server->stat.servers--;
break;
/* 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;
}
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--;
+ }
+ }
+
/* 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;
}
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
/* 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);
server->router->connection,
server->server_type == SILC_ROUTER ? TRUE : FALSE,
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, idp->len, 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);
+
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;
}
TRUE, new_server->id, SILC_ID_SERVER,
silc_id_get_len(server_id, SILC_ID_SERVER));
- if (server->server_type == SILC_ROUTER)
+ 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, idp->len, FALSE, TRUE);
+ silc_buffer_free(idp);
+
+ /* Statistics */
server->stat.cell_servers++;
+ }
/* Check whether this router connection has been replaced by an
backup router. If it has been then we'll disable the server and will
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;
/* 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->standalone && server->server_type == SILC_ROUTER &&
+ if (broadcast && server->server_type == SILC_ROUTER &&
sock->type == SILC_SOCKET_TYPE_SERVER &&
!(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
SILC_LOG_DEBUG(("Broadcasting received New ID packet"));
- silc_server_packet_send(server, server->router->connection,
- packet->type,
- packet->flags | SILC_PACKET_FLAG_BROADCAST,
- buffer->data, buffer->len, FALSE);
+ if (!server->standalone)
+ silc_server_packet_send(server, server->router->connection,
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ buffer->data, buffer->len, FALSE);
silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
packet->type, packet->flags,
packet->buffer->data, packet->buffer->len,
/* 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->standalone && server->server_type == SILC_ROUTER &&
+ if (server->server_type == SILC_ROUTER &&
sock->type == SILC_SOCKET_TYPE_SERVER &&
!(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
SILC_LOG_DEBUG(("Broadcasting received New ID List packet"));
- silc_server_packet_send(server, server->router->connection,
- packet->type,
- packet->flags | SILC_PACKET_FLAG_BROADCAST,
- packet->buffer->data, packet->buffer->len, FALSE);
+ if (!server->standalone)
+ silc_server_packet_send(server, server->router->connection,
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ packet->buffer->data,
+ packet->buffer->len, FALSE);
silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
packet->type, packet->flags,
packet->buffer->data, packet->buffer->len,
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;
}
-
- /* Get the mode and set it to the channel */
- channel->mode = silc_channel_get_mode(payload);
+ channel->disabled = TRUE;
/* Send the new channel key to the server */
id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
chk->data, chk->len, FALSE);
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 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;
silc_free(channel_id);
+ /* Update statistics */
+ server->stat.channels++;
+ server->stat.cell_channels++;
+
/* 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 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->standalone && server->server_type == SILC_ROUTER &&
+ if (server->server_type == SILC_ROUTER &&
sock->type == SILC_SOCKET_TYPE_SERVER &&
!(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
SILC_LOG_DEBUG(("Broadcasting received New Channel List packet"));
- silc_server_packet_send(server, server->router->connection,
- packet->type,
- packet->flags | SILC_PACKET_FLAG_BROADCAST,
- packet->buffer->data, packet->buffer->len, FALSE);
+ if (!server->standalone)
+ silc_server_packet_send(server, server->router->connection,
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ packet->buffer->data,
+ packet->buffer->len, FALSE);
silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
packet->type, packet->flags,
packet->buffer->data, packet->buffer->len,
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;
server->stat.clients--;
if (server->stat.cell_clients)
server->stat.cell_clients--;
+ silc_server_del_from_watcher_list(server, client);
silc_idlist_del_client(server->local_list, client);
client = detached_client;
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,
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 &&
+ if (server->server_type == SILC_ROUTER &&
sock->type == SILC_SOCKET_TYPE_SERVER &&
!(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
SILC_LOG_DEBUG(("Broadcasting received Resume Client packet"));
- silc_server_packet_send(server, server->router->connection,
- packet->type,
- packet->flags | SILC_PACKET_FLAG_BROADCAST,
- buffer->data, buffer->len, FALSE);
+ if (!server->standalone)
+ silc_server_packet_send(server, server->router->connection,
+ packet->type,
+ packet->flags | SILC_PACKET_FLAG_BROADCAST,
+ buffer->data, buffer->len, FALSE);
silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
packet->type, packet->flags,
packet->buffer->data, packet->buffer->len,