SilcServerEntry server_entry;
SilcChannelClientEntry chl;
SilcIDCacheEntry cache;
+ SilcHashTableList htl;
uint32 mode;
unsigned char *tmp;
uint32 tmp_len;
goto out;
client =
- silc_idlist_add_client(server->global_list, NULL, 0, NULL, NULL,
+ silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
silc_id_dup(client_id, SILC_ID_CLIENT),
sock->user_data, NULL);
if (!client) {
chl = silc_calloc(1, sizeof(*chl));
chl->client = client;
chl->channel = channel;
- silc_list_add(channel->user_list, chl);
- silc_list_add(client->channels, chl);
+ silc_hash_table_add(channel->user_list, client, chl);
+ silc_hash_table_add(client->channels, channel, chl);
silc_free(client_id);
break;
client->data.registered = FALSE;
cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+ server->stat.clients--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.cell_clients--;
break;
case SILC_NOTIFY_TYPE_TOPIC_SET:
if (channel->topic)
silc_free(channel->topic);
- channel->topic = silc_calloc(tmp_len, sizeof(*channel->topic));
+ channel->topic = silc_calloc(tmp_len + 1, sizeof(*channel->topic));
memcpy(channel->topic, tmp, tmp_len);
/* Send the same notify to the channel */
silc_free(client_id);
/* Get entry to the channel user list */
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
SilcChannelClientEntry chl2 = NULL;
/* If the mode is channel founder and we already find a client
silc_server_send_notify_cumode(server, sock, FALSE, channel,
(mode & (~SILC_CHANNEL_UMODE_CHANFO)),
server->id, SILC_ID_SERVER,
- SILC_ID_SERVER_LEN,
- client->id, SILC_ID_CLIENT_LEN);
+ client->id);
silc_free(channel_id);
/* Change the mode back if we changed it */
}
if (users_modes) {
silc_buffer_push(users_modes, users_modes->data - users_modes->head);
- silc_server_packet_send(server, sock,
- SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
- users_modes->data, users_modes->len, FALSE);
+ silc_server_packet_send_dest(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ channel->id, SILC_ID_CHANNEL,
+ users_modes->data,
+ users_modes->len, FALSE);
silc_buffer_free(users_modes);
}
}
if (packet->dst_id_type == SILC_ID_SERVER) {
/* For now this must be for us */
- if (SILC_ID_SERVER_COMPARE(packet->dst_id, server->id_string)) {
+ if (memcmp(packet->dst_id, server->id_string, packet->dst_id_len)) {
SILC_LOG_ERROR(("Cannot process command reply to unknown server"));
return;
}
SilcPacketContext *packet)
{
SilcChannelEntry channel = NULL;
- SilcChannelClientEntry chl;
SilcChannelID *id = NULL;
void *sender = NULL;
void *sender_entry = NULL;
}
}
- /* See that this client is on the channel. If the message is coming
- from router we won't do the check as the message is from client that
- we don't know about. Also, if the original sender is not client
- (as it can be server as well) we don't do the check. */
+ /* See that this client is on the channel. If the original sender is
+ not client (as it can be server as well) we don't do the check. */
sender = silc_id_str2id(packet->src_id, packet->src_id_len,
packet->src_id_type);
if (!sender)
goto out;
if (packet->src_id_type == SILC_ID_CLIENT) {
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
- if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender)) {
- sender_entry = chl->client;
- break;
- }
- }
- if (chl == SILC_LIST_END) {
+ sender_entry = silc_idlist_find_client_by_id(server->local_list,
+ sender, NULL);
+ if (!sender_entry)
+ sender_entry = silc_idlist_find_client_by_id(server->global_list,
+ sender, NULL);
+ if (!sender_entry || !silc_server_client_on_channel(sender_entry,
+ channel)) {
SILC_LOG_DEBUG(("Client not on channel"));
goto out;
}
{
SilcBuffer buffer = packet->buffer;
SilcClientEntry client;
- SilcIDCacheEntry cache;
SilcClientID *client_id;
SilcBuffer reply;
SilcIDListData idata;
char *username = NULL, *realname = NULL, *id_string;
+ uint32 id_len;
int ret;
+ char *hostname, *nickname;
SILC_LOG_DEBUG(("Creating new client"));
client = (SilcClientEntry)sock->user_data;
idata = (SilcIDListData)client;
- /* Fetch the old client cache entry so that we can update it. */
- if (!silc_idcache_find_by_context(server->local_list->clients,
- sock->user_data, &cache)) {
+ /* Remove the old cache entry */
+ if (!silc_idcache_del_by_context(server->local_list->clients, client)) {
SILC_LOG_ERROR(("Lost client's cache entry - bad thing"));
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Unknown client");
return NULL;
}
+ if (strlen(username) > 128)
+ username[127] = '\0';
+
+ nickname = strdup(username);
+
+ /* Make sanity checks for the hostname of the client. If the hostname
+ is provided in the `username' check that it is the same than the
+ resolved hostname, or if not resolved the hostname that appears in
+ the client's public key. If the hostname is not present then put
+ it from the resolved name or from the public key. */
+ if (strchr(username, '@')) {
+ SilcPublicKeyIdentifier pident;
+ int tlen = strcspn(username, "@");
+ char *phostname = NULL;
+
+ hostname = silc_calloc((strlen(username) - tlen) + 1, sizeof(char));
+ memcpy(hostname, username + tlen + 1, strlen(username) - tlen - 1);
+
+ if (strcmp(sock->hostname, sock->ip) &&
+ strcmp(sock->hostname, hostname)) {
+ silc_free(username);
+ silc_free(hostname);
+ if (realname)
+ silc_free(realname);
+ silc_server_disconnect_remote(server, sock,
+ "Server closed connection: "
+ "Incomplete client information");
+ return NULL;
+ }
+
+ pident = silc_pkcs_decode_identifier(client->data.public_key->identifier);
+ if (pident) {
+ phostname = strdup(pident->host);
+ silc_pkcs_free_identifier(pident);
+ }
+
+ if (!strcmp(sock->hostname, sock->ip) &&
+ phostname && strcmp(phostname, hostname)) {
+ silc_free(username);
+ silc_free(hostname);
+ if (phostname)
+ silc_free(phostname);
+ if (realname)
+ silc_free(realname);
+ silc_server_disconnect_remote(server, sock,
+ "Server closed connection: "
+ "Incomplete client information");
+ return NULL;
+ }
+
+ if (phostname)
+ silc_free(phostname);
+ } else {
+ /* The hostname is not present, add it. */
+ char *newusername;
+ /* XXX For now we cannot take the host name from the public key since
+ they are not trusted or we cannot verify them as trusted. Just take
+ what the resolved name or address is. */
+#if 0
+ if (strcmp(sock->hostname, sock->ip)) {
+#endif
+ newusername = silc_calloc(strlen(username) +
+ strlen(sock->hostname) + 2,
+ sizeof(*newusername));
+ strncat(newusername, username, strlen(username));
+ strncat(newusername, "@", 1);
+ strncat(newusername, sock->hostname, strlen(sock->hostname));
+ silc_free(username);
+ username = newusername;
+#if 0
+ } else {
+ SilcPublicKeyIdentifier pident =
+ silc_pkcs_decode_identifier(client->data.public_key->identifier);
+
+ if (pident) {
+ newusername = silc_calloc(strlen(username) +
+ strlen(pident->host) + 2,
+ sizeof(*newusername));
+ strncat(newusername, username, strlen(username));
+ strncat(newusername, "@", 1);
+ strncat(newusername, pident->host, strlen(pident->host));
+ silc_free(username);
+ username = newusername;
+ silc_pkcs_free_identifier(pident);
+ }
+ }
+#endif
+ }
+
/* Create Client ID */
silc_id_create_client_id(server->id, server->rng, server->md5hash,
username, &client_id);
- if (strlen(username) > 128)
- username[127] = '\0';
-
/* Update client entry */
idata->registered = TRUE;
- client->nickname = strdup(username);
+ client->nickname = nickname;
client->username = username;
client->userinfo = realname ? realname : strdup(" ");
client->id = client_id;
+ id_len = silc_id_get_len(client_id, SILC_ID_CLIENT);
- /* Update the cache entry */
- cache->id = (void *)client_id;
- cache->type = SILC_ID_CLIENT;
- cache->data = username;
- cache->data_len = strlen(username);
- silc_idcache_sort_by_data(server->local_list->clients);
+ /* Add the client again to the ID cache */
+ silc_idcache_add(server->local_list->clients, client->nickname,
+ client_id, client, FALSE);
/* Notify our router about new client on the SILC network */
if (!server->standalone)
silc_server_send_new_id(server, (SilcSocketConnection)
server->router->connection,
server->server_type == SILC_ROUTER ? TRUE : FALSE,
- client->id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+ 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(2 + 2 + SILC_ID_CLIENT_LEN);
+ reply = silc_buffer_alloc(2 + 2 + id_len);
silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply));
silc_buffer_format(reply,
SILC_STR_UI_SHORT(SILC_ID_CLIENT),
- SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
- SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
+ 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);
/* Send some nice info to the client */
SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
- ("Welcome to the SILC Network %s@%s",
- username, sock->hostname));
+ ("Welcome to the SILC Network %s",
+ username));
SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
("Your host is %s, running version %s",
server->config->server_info->server_name,
{
SilcBuffer buffer = packet->buffer;
SilcServerEntry new_server;
- SilcIDCacheEntry cache;
SilcServerID *server_id;
SilcIDListData idata;
unsigned char *server_name, *id_string;
new_server = (SilcServerEntry)sock->user_data;
idata = (SilcIDListData)new_server;
- /* Fetch the old server cache entry so that we can update it. */
- if (!silc_idcache_find_by_context(server->local_list->servers,
- sock->user_data, &cache)) {
- SILC_LOG_ERROR(("Lost server's cache entry - bad thing"));
- return NULL;
- }
+ /* Remove the old cache entry */
+ silc_idcache_del_by_context(server->local_list->servers, new_server);
/* Parse the incoming packet */
ret = silc_buffer_unformat(buffer,
}
silc_free(id_string);
- /* Update client entry */
+ /* Update server entry */
idata->registered = TRUE;
new_server->server_name = server_name;
new_server->id = server_id;
- /* Update the cache entry */
- cache->id = (void *)server_id;
- cache->type = SILC_ID_SERVER;
- cache->data = server_name;
- cache->data_len = strlen(server_name);
- silc_idcache_sort_by_data(server->local_list->servers);
+ /* Add again the entry to the ID cache. */
+ silc_idcache_add(server->local_list->servers, server_name, server_id,
+ server, FALSE);
/* Distribute the information about new server in the SILC network
to our router. If we are normal server we won't send anything
server->router->connection != sock)
silc_server_send_new_id(server, server->router->connection,
TRUE, new_server->id, SILC_ID_SERVER,
- SILC_ID_SERVER_LEN);
+ silc_id_get_len(server_id, SILC_ID_SERVER));
if (server->server_type == SILC_ROUTER)
server->stat.cell_servers++;
SilcSocketConnection router_sock;
SilcIDPayload idp;
SilcIdType id_type;
- unsigned char *hash = NULL;
void *id;
SILC_LOG_DEBUG(("Processing new ID"));
/* As a router we keep information of all global information in our
global list. Cell wide information however is kept in the local
- list. The client is put to global list and we will take the hash
- value of the Client ID and save it to the ID Cache system for fast
- searching in the future. */
- hash = silc_calloc(sizeof(((SilcClientID *)id)->hash),
- sizeof(unsigned char));
- memcpy(hash, ((SilcClientID *)id)->hash,
- sizeof(((SilcClientID *)id)->hash));
- entry = silc_idlist_add_client(id_list, hash,
- sizeof(((SilcClientID *)id)->hash),
- NULL, NULL, id, router, NULL);
+ list. */
+ entry = silc_idlist_add_client(id_list, NULL, NULL, NULL,
+ id, router, NULL);
entry->nickname = NULL;
entry->data.registered = TRUE;
case SILC_ID_SERVER:
/* If the ID is mine, ignore it. */
- if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
+ if (SILC_ID_SERVER_COMPARE(id, server->id)) {
SILC_LOG_DEBUG(("Ignoring my own ID as new ID"));
break;
}
return;
}
+ /* Get the mode and set it to the channel */
+ channel->mode = silc_channel_get_mode(payload);
+
/* Send the new channel key to the server */
chk = silc_channel_key_payload_encode(id_len, id,
strlen(channel->channel_key->
if (!channel->id)
channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
- if (SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
+ if (!SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
/* They don't match, send CHANNEL_CHANGE notify to the server to
force the ID change. */
SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
silc_server_send_notify_channel_change(server, sock, FALSE,
- channel_id,
- channel->id,
- SILC_ID_CHANNEL_LEN);
+ channel_id, channel->id);
}
/* If the mode is different from what we have then enforce the
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, SILC_ID_SERVER_LEN,
+ SILC_ID_SERVER,
channel->cipher, channel->hmac_name);
}
}
if (users_modes) {
silc_buffer_push(users_modes, users_modes->data - users_modes->head);
- silc_server_packet_send(server, sock,
- SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
- users_modes->data, users_modes->len, FALSE);
+ silc_server_packet_send_dest(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ channel->id, SILC_ID_CHANNEL,
+ users_modes->data,
+ users_modes->len, FALSE);
silc_buffer_free(users_modes);
}
}
if (proto_ctx->pfs == FALSE)
/* Run the protocol */
- protocol->execute(server->timeout_queue, 0, protocol, sock->sock, 0, 0);
+ silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
}