Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2002 Pekka Riikonen
+ Copyright (C) 1997 - 2003 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
when new server connects to us. We also add ourselves to cache with
this function. */
-SilcServerEntry
-silc_idlist_add_server(SilcIDList id_list,
+SilcServerEntry
+silc_idlist_add_server(SilcIDList id_list,
char *server_name, int server_type,
SilcServerID *id, SilcServerEntry router,
void *connection)
server->router = router;
server->connection = connection;
- if (!silc_idcache_add(id_list->servers, server->server_name,
+ if (!silc_idcache_add(id_list->servers, server->server_name,
(void *)server->id, (void *)server, 0, NULL)) {
silc_free(server);
return NULL;
SILC_LOG_DEBUG(("Server ID (%s)",
silc_id_render(id, SILC_ID_SERVER)));
- if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
+ if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
&id_cache))
return NULL;
server = (SilcServerEntry)id_cache->context;
- if (server && registered &&
+ if (server && registered &&
!(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
return NULL;
return NULL;
server = (SilcServerEntry)id_cache->context;
-
+
if (server && registered &&
!(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
return NULL;
SilcIDCacheEntry id_cache = NULL;
SilcServerEntry server = NULL;
SilcSocketConnection sock;
-
+
SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
if (!silc_idcache_get_all(id_list->servers, &list))
while (id_cache) {
server = (SilcServerEntry)id_cache->context;
sock = (SilcSocketConnection)server->connection;
-
+
if (sock && ((sock->hostname && !strcasecmp(sock->hostname, hostname)) ||
(sock->ip && !strcasecmp(sock->ip, hostname)))
&& server->id->port == SILC_SWAB_16(port))
if (!silc_idcache_list_next(list, &id_cache))
break;
}
-
+
silc_idcache_list_free(list);
if (server && registered &&
return server;
}
-/* Replaces old Server ID with new one */
+/* Replaces old Server ID with new one */
SilcServerEntry
silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
SILC_LOG_DEBUG(("Replacing Server ID"));
- if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
+ if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
&id_cache))
return NULL;
silc_free(server->id);
server->id = new_id;
- silc_idcache_add(id_list->servers, server->server_name, server->id,
+ silc_idcache_add(id_list->servers, server->server_name, server->id,
server, 0, NULL);
SILC_LOG_DEBUG(("Found"));
to be directly connected local client and `router' must be NULL. */
SilcClientEntry
-silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
- char *userinfo, SilcClientID *id,
+silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
+ char *userinfo, SilcClientID *id,
SilcServerEntry router, void *connection,
int expire)
{
client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
NULL, NULL, NULL, NULL, TRUE);
- if (!silc_idcache_add(id_list->clients, nickname, (void *)client->id,
+ if (!silc_idcache_add(id_list->clients, nickname, (void *)client->id,
(void *)client, expire, NULL)) {
silc_hash_table_free(client->channels);
silc_free(client);
returned to `clients_count'. Caller must free the returned table. */
int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
- char *server,
+ char *server,
SilcClientEntry **clients,
SilcUInt32 *clients_count)
{
if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
return FALSE;
- *clients = silc_realloc(*clients,
- (silc_idcache_list_count(list) + *clients_count) *
+ *clients = silc_realloc(*clients,
+ (silc_idcache_list_count(list) + *clients_count) *
sizeof(**clients));
silc_idcache_list_first(list, &id_cache);
while (silc_idcache_list_next(list, &id_cache))
(*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
-
+
silc_idcache_list_free(list);
-
+
SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
return TRUE;
if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
return FALSE;
- *clients = silc_realloc(*clients,
- (silc_idcache_list_count(list) + *clients_count) *
+ *clients = silc_realloc(*clients,
+ (silc_idcache_list_count(list) + *clients_count) *
sizeof(**clients));
silc_idcache_list_first(list, &id_cache);
while (silc_idcache_list_next(list, &id_cache))
(*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
-
+
silc_idcache_list_free(list);
-
+
SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
return TRUE;
if (!id)
return NULL;
- SILC_LOG_DEBUG(("Client ID (%s)",
+ SILC_LOG_DEBUG(("Client ID (%s)",
silc_id_render(id, SILC_ID_CLIENT)));
/* Do extended search since the normal ID comparison function for
Client ID's compares only the hash from the Client ID and not the
entire ID. The silc_hash_client_id_compare compares the entire
Client ID as we want to find one specific Client ID. */
- if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
- NULL, NULL,
+ if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
+ NULL, NULL,
silc_hash_client_id_compare, NULL,
&id_cache))
return NULL;
Client ID's compares only the hash from the Client ID and not the
entire ID. The silc_hash_client_id_compare compares the entire
Client ID as we want to find one specific Client ID. */
- if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id,
- NULL, NULL,
+ if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id,
+ NULL, NULL,
silc_hash_client_id_compare, NULL,
&id_cache))
return NULL;
silc_server_check_watcher_list(server, client, nickname,
SILC_NOTIFY_TYPE_NICK_CHANGE);
- if (!silc_idcache_add(id_list->clients, client->nickname, client->id,
+ if (!silc_idcache_add(id_list->clients, client->nickname, client->id,
client, 0, NULL))
return NULL;
channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
NULL, NULL, NULL, TRUE);
- if (!silc_idcache_add(id_list->channels, channel->channel_name,
+ if (!silc_idcache_add(id_list->channels, channel->channel_name,
(void *)channel->id, (void *)channel, expire, NULL)) {
silc_hmac_free(channel->hmac);
silc_hash_table_free(channel->user_list);
SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
/* Free all client entrys from the users list. The silc_hash_table_free
- will free all the entries so they are not freed at the foreach
+ will free all the entries so they are not freed at the foreach
callback. */
silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
NULL);
silc_free(entry->rekey);
if (entry->founder_key)
silc_pkcs_public_key_free(entry->founder_key);
+ if (entry->channel_pubkeys)
+ silc_hash_table_free(entry->channel_pubkeys);
memset(entry, 'F', sizeof(*entry));
silc_free(entry);
SILC_LOG_DEBUG(("Replacing Channel ID"));
- if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
+ if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
&id_cache))
return NULL;
silc_free(channel->id);
channel->id = new_id;
- silc_idcache_add(id_list->channels, channel->channel_name, channel->id,
+ silc_idcache_add(id_list->channels, channel->channel_name, channel->id,
channel, 0, NULL);
SILC_LOG_DEBUG(("Replaced"));
return NULL;
channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
-
+
i = 0;
silc_idcache_list_first(list, &id_cache);
channels[i++] = (SilcChannelEntry)id_cache->context;
-
+
while (silc_idcache_list_next(list, &id_cache))
channels[i++] = (SilcChannelEntry)id_cache->context;
-
+
silc_idcache_list_free(list);
} else {
if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2002 Pekka Riikonen
+ Copyright (C) 1997 - 2003 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
SilcIDListStatus status; /* Status mask of the entry */
} *SilcIDListData, SilcIDListDataStruct;
-/*
+/*
SILC Server entry object.
- This entry holds information about servers in SILC network. However,
- contents of this entry is highly dependent of what kind of server we are
- (normal server or router server) and whether the entry is used as a local
+ This entry holds information about servers in SILC network. However,
+ contents of this entry is highly dependent of what kind of server we are
+ (normal server or router server) and whether the entry is used as a local
list or a global list. These factors dictates the contents of this entry.
This entry is defined as follows:
SilcServerEntry router
- This is a pointer back to the server list. This is the router server
- where this server is connected to. If this is the router itself and
+ This is a pointer back to the server list. This is the router server
+ where this server is connected to. If this is the router itself and
it doesn't have a route this is NULL.
SilcCipher send_key
the data used in connection with this server. This may be anything
but as just said, this is usually pointer to the socket connection
list.
-
+
*/
struct SilcServerEntryStruct {
/* Generic data structure. DO NOT add anything before this! */
void *connection;
};
-/*
+/*
SILC Channel Client entry structure.
This entry used only by the SilcChannelEntry object and it holds
SilcChannelEntry channel;
} *SilcChannelClientEntry;
-/*
+/*
SILC Client entry object.
This entry holds information about connected clients ie. users in the SILC
- network. The contents of this entrt is depended on whether we are normal
+ network. The contents of this entrt is depended on whether we are normal
server or router server and whether the list is a local or global list.
This entry is defined as follows:
router local list NULL
router global list NULL
- Router doesn't hold this information since it is not vital data
+ Router doesn't hold this information since it is not vital data
for the router. If this information is needed by the client it is
fetched when it is needed.
Information about user. This is free information and can be virtually
anything. This is defined in following manner:
-
+
Server type List type Contents
====================================================
server local list User's information
router local list NULL
router global list NULL
- Router doesn't hold this information since it is not vital data
+ Router doesn't hold this information since it is not vital data
for the router. If this information is needed by the client it is
fetched when it is needed.
ID of the client. This includes all the information SILC will ever
need. Notice that no nickname of the user is saved anywhere. This is
- beacuse of SilcClientID includes 88 bit hash value of the user's
- nickname which can be used to track down specific user by their
- nickname. Nickname is not relevant information that would need to be
+ beacuse of SilcClientID includes 88 bit hash value of the user's
+ nickname which can be used to track down specific user by their
+ nickname. Nickname is not relevant information that would need to be
saved as plain.
SilcUInt32 mode
SilcServerEntry router
- This is a pointer to the server list. This is the router server whose
- cell this client is coming from. This is used to route messages to
+ This is a pointer to the server list. This is the router server whose
+ cell this client is coming from. This is used to route messages to
this client.
SilcHashTable channels;
/* Last time updated/accessed */
unsigned long updated;
- /* data.status is RESOLVING and this includes the resolving command
+ /* data.status is RESOLVING and this includes the resolving command
reply identifier. */
SilcUInt16 resolve_cmd_ident;
};
-/*
+/*
SILC Channel entry object.
- This entry holds information about channels in SILC network. The contents
- of this entry is depended on whether we are normal server or router server
+ This entry holds information about channels in SILC network. The contents
+ of this entry is depended on whether we are normal server or router server
and whether the list is a local or global list.
This entry is defined as follows:
need.
bool global_users
-
+
Boolean value to tell whether there are users outside this server
on this channel. This is set to TRUE if router sends message to
the server that there are users outside your server on your
channel as well. This way server knows that messages needs to be
- sent to the router for further routing. If this is a normal
+ sent to the router for further routing. If this is a normal
server and this channel is not created on this server this field
is always TRUE. If this server is a router this field is ignored.
SilcServerEntry router
- This is a pointer to the server list. This is the router server
- whose cell this channel belongs to. This is used to route messages
+ This is a pointer to the server list. This is the router server
+ whose cell this channel belongs to. This is used to route messages
to this channel.
SilcCipher channel_key
char *cipher;
char *hmac_name;
SilcPublicKey founder_key;
+ SilcHashTable channel_pubkeys;
SilcUInt32 user_limit;
unsigned char *passphrase;
unsigned int users_resolved : 1;
};
-/*
+/*
SILC ID List object.
As for remainder these lists are defined as follows:
/*
ID Entry for Unknown connections.
- This is used during authentication phases where we still don't know
+ This is used during authentication phases where we still don't know
what kind of connection remote connection is, hence, we will use this
structure instead until we know what type of connection remote end is.
void silc_idlist_add_data(void *entry, SilcIDListData idata);
void silc_idlist_del_data(void *entry);
SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge);
-SilcServerEntry
-silc_idlist_add_server(SilcIDList id_list,
+SilcServerEntry
+silc_idlist_add_server(SilcIDList id_list,
char *server_name, int server_type,
SilcServerID *id, SilcServerEntry router,
void *connection);
SilcServerID *new_id);
int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry);
SilcClientEntry
-silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
- char *userinfo, SilcClientID *id,
+silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
+ char *userinfo, SilcClientID *id,
SilcServerEntry router, void *connection,
int expire);
int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry);
int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
- char *server,
+ char *server,
SilcClientEntry **clients,
SilcUInt32 *clients_count);
int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
/*
- server_util.c
+ server_util.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2002 Pekka Riikonen
+ Copyright (C) 1997 - 2003 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
if (!client)
return;
- SILC_LOG_DEBUG(("Remove client %s from all channels",
+ SILC_LOG_DEBUG(("Remove client %s from all channels",
client->nickname ? client->nickname :
(unsigned char *)""));
/* If there is no global users on the channel anymore mark the channel
as local channel. Do not check if the removed client is local client. */
- if (server->server_type != SILC_ROUTER && channel->global_users &&
+ if (server->server_type != SILC_ROUTER && channel->global_users &&
chl->client->router && !silc_server_channel_has_global(channel))
channel->global_users = FALSE;
}
silc_hash_table_list_reset(&htl2);
- /* Add the channel to the the channels list to regenerate the
+ /* Add the channel to the the channels list to regenerate the
channel key */
if (!silc_hash_table_find(channels, channel, NULL, NULL))
silc_hash_table_add(channels, channel, channel);
/* This function removes all client entries that are originated from
`router' and are owned by `entry'. `router' and `entry' can be same
- too. If `server_signoff' is TRUE then SERVER_SIGNOFF notify is
+ too. If `server_signoff' is TRUE then SERVER_SIGNOFF notify is
distributed to our local clients. */
bool silc_server_remove_clients_by_server(SilcServer server,
}
silc_idcache_list_free(list);
}
-
+
if (silc_idcache_get_all(server->global_list->clients, &list)) {
if (silc_idcache_list_first(list, &id_cache)) {
is to be removed for those servers that would like to use that list. */
args = silc_argument_payload_encode(argc, argv, argv_lens,
argv_types);
- not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
+ not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
argc, args);
silc_server_packet_send_clients(server, clients,
SILC_PACKET_NOTIFY, 0, FALSE,
if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY || !channel->channel_key)
continue;
- silc_server_send_channel_key(server, NULL, channel,
- server->server_type == SILC_ROUTER ?
+ silc_server_send_channel_key(server, NULL, channel,
+ server->server_type == SILC_ROUTER ?
FALSE : !server->standalone);
}
silc_hash_table_list_reset(&htl);
server_entry = (SilcServerEntry)id_cache->context;
if (server_entry != from &&
(tolocal || server_entry != server->id_entry) &&
- SILC_ID_COMPARE(server_entry->id, client->id,
+ SILC_ID_COMPARE(server_entry->id, client->id,
client->id->ip.data_len)) {
SILC_LOG_DEBUG(("Found (local) %s",
silc_id_render(server_entry->id, SILC_ID_SERVER)));
server_entry = (SilcServerEntry)id_cache->context;
if (server_entry != from && server_entry != server->id_entry &&
(tolocal || server_entry != server->id_entry) &&
- SILC_ID_COMPARE(server_entry->id, client->id,
+ SILC_ID_COMPARE(server_entry->id, client->id,
client->id->ip.data_len)) {
SILC_LOG_DEBUG(("Found (global) %s",
silc_id_render(server_entry->id, SILC_ID_SERVER)));
to, when we've acting as backup router. If it is FALSE the `to' will
be the new source. */
-void silc_server_update_clients_by_server(SilcServer server,
+void silc_server_update_clients_by_server(SilcServer server,
SilcServerEntry from,
SilcServerEntry to,
bool resolve_real_server)
continue;
}
- SILC_LOG_DEBUG(("Client %s",
+ SILC_LOG_DEBUG(("Client %s",
silc_id_render(client->id, SILC_ID_CLIENT)));
if (client->router)
- SILC_LOG_DEBUG(("Client->router %s",
+ SILC_LOG_DEBUG(("Client->router %s",
silc_id_render(client->router->id, SILC_ID_SERVER)));
if (from) {
if (client->router == from) {
if (resolve_real_server) {
- client->router =
+ client->router =
silc_server_update_clients_by_real_server(server, from, to,
client, local,
id_cache);
}
if (client->router)
- SILC_LOG_DEBUG(("Client changed to %s",
+ SILC_LOG_DEBUG(("Client changed to %s",
silc_id_render(client->router->id, SILC_ID_SERVER)));
if (!silc_idcache_list_next(list, &id_cache))
continue;
}
- SILC_LOG_DEBUG(("Client %s",
+ SILC_LOG_DEBUG(("Client %s",
silc_id_render(client->id, SILC_ID_CLIENT)));
if (client->router)
- SILC_LOG_DEBUG(("Client->router %s",
+ SILC_LOG_DEBUG(("Client->router %s",
silc_id_render(client->router->id, SILC_ID_SERVER)));
if (from) {
if (client->router == from) {
if (resolve_real_server) {
- client->router =
+ client->router =
silc_server_update_clients_by_real_server(server, from, to,
client, local,
id_cache);
}
if (client->router)
- SILC_LOG_DEBUG(("Client changed to %s",
+ SILC_LOG_DEBUG(("Client changed to %s",
silc_id_render(client->router->id, SILC_ID_SERVER)));
if (!silc_idcache_list_next(list, &id_cache))
/* Updates servers that are from `from' to be originated from `to'. This
will also update the server's connection to `to's connection. */
-void silc_server_update_servers_by_server(SilcServer server,
+void silc_server_update_servers_by_server(SilcServer server,
SilcServerEntry from,
SilcServerEntry to)
{
if (server_entry->router == from) {
SILC_LOG_DEBUG(("Updating server (local) %s",
- server_entry->server_name ?
+ server_entry->server_name ?
server_entry->server_name : ""));
server_entry->router = to;
server_entry->connection = to->connection;
if (server_entry->router == from) {
SILC_LOG_DEBUG(("Updating server (global) %s",
- server_entry->server_name ?
+ server_entry->server_name ?
server_entry->server_name : ""));
server_entry->router = to;
server_entry->connection = to->connection;
/* Removes channels that are from `from. */
-void silc_server_remove_channels_by_server(SilcServer server,
+void silc_server_remove_channels_by_server(SilcServer server,
SilcServerEntry from)
{
SilcIDCacheList list = NULL;
/* Updates channels that are from `from' to be originated from `to'. */
-void silc_server_update_channels_by_server(SilcServer server,
+void silc_server_update_channels_by_server(SilcServer server,
SilcServerEntry from,
SilcServerEntry to)
{
return TRUE;
}
-/* Returns TRUE if the given client is on the channel. FALSE if not.
+/* Returns TRUE if the given client is on the channel. FALSE if not.
This works because we assure that the user list on the channel is
- always in up to date thus we can only check the channel list from
+ always in up to date thus we can only check the channel list from
`client' which is faster than checking the user list from `channel'. */
bool silc_server_client_on_channel(SilcClientEntry client,
if (!client || !channel)
return FALSE;
- return silc_hash_table_find(client->channels, channel, NULL,
+ return silc_hash_table_find(client->channels, channel, NULL,
(void **)chl);
}
by `ip' or `hostname', `port', and `type'. Returns 0 if socket connections
does not exist. If `ip' is provided then `hostname' is ignored. */
-SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server,
+SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server,
const char *ip,
const char *hostname,
SilcUInt16 port,
return count;
}
-/* Finds locally cached public key by the public key received in the SKE.
+/* Finds locally cached public key by the public key received in the SKE.
If we have it locally cached then we trust it and will use it in the
authentication protocol. Returns the locally cached public key or NULL
if we do not find the public key. */
-SilcPublicKey silc_server_find_public_key(SilcServer server,
+SilcPublicKey silc_server_find_public_key(SilcServer server,
SilcHashTable local_public_keys,
SilcPublicKey remote_public_key)
{
silc_hash_table_count(local_public_keys)));
if (!silc_hash_table_find_ext(local_public_keys, remote_public_key,
- (void **)&cached_key, NULL,
+ (void **)&cached_key, NULL,
silc_hash_public_key, NULL,
silc_hash_public_key_compare, NULL)) {
SILC_LOG_ERROR(("Public key not found"));
assert(silc_hash_table_count(local_public_keys) < 2);
silc_hash_table_list(local_public_keys, &htl);
- if (!silc_hash_table_get(&htl, NULL, (void **)&cached_key))
+ if (!silc_hash_table_get(&htl, NULL, (void **)&cached_key)) {
+ silc_hash_table_list_reset(&htl);
return NULL;
+ }
silc_hash_table_list_reset(&htl);
return cached_key;
checks for example whether there is too much connections for this host,
and required version for the host etc. */
-bool silc_server_connection_allowed(SilcServer server,
+bool silc_server_connection_allowed(SilcServer server,
SilcSocketConnection sock,
SilcSocketType type,
SilcServerConfigConnParams *global,
/* Check version */
- l_protocol_version =
- silc_version_to_num(params && params->version_protocol ?
- params->version_protocol :
+ l_protocol_version =
+ silc_version_to_num(params && params->version_protocol ?
+ params->version_protocol :
global->version_protocol);
- l_software_version =
- silc_version_to_num(params && params->version_software ?
- params->version_software :
+ l_software_version =
+ silc_version_to_num(params && params->version_software ?
+ params->version_software :
global->version_software);
- l_vendor_version = (params && params->version_software_vendor ?
- params->version_software_vendor :
+ l_vendor_version = (params && params->version_software_vendor ?
+ params->version_software_vendor :
global->version_software_vendor);
-
+
if (ske && silc_ske_parse_version(ske, &r_protocol_version, NULL,
&r_software_version, NULL,
&r_vendor_version)) {
r_protocol_version < l_protocol_version) {
SILC_LOG_INFO(("Connection %s (%s) is too old version",
sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_BAD_VERSION,
"You support too old protocol version");
return FALSE;
r_software_version < l_software_version) {
SILC_LOG_INFO(("Connection %s (%s) is too old version",
sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_BAD_VERSION,
"You support too old software version");
return FALSE;
}
/* Regex match vendor version */
- if (l_vendor_version && r_vendor_version &&
+ if (l_vendor_version && r_vendor_version &&
!silc_string_match(l_vendor_version, r_vendor_version)) {
SILC_LOG_INFO(("Connection %s (%s) is unsupported version",
sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_BAD_VERSION,
"Your software is not supported");
return FALSE;
if (max_hosts && conn_number >= max_hosts) {
SILC_LOG_INFO(("Server is full, closing %s (%s) connection",
sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_RESOURCE_LIMIT,
"Server is full, try again later");
return FALSE;
if (num_sockets >= max_per_host) {
SILC_LOG_INFO(("Too many connections from %s (%s), closing connection",
sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_RESOURCE_LIMIT,
"Too many connections from your host");
return FALSE;
return FALSE;
}
}
-
+
if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
if (is_op && !is_fo)
return FALSE;
}
}
-
+
if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
if (is_op && !is_fo)
return FALSE;
}
}
-
+
if (mode & SILC_CHANNEL_MODE_SILENCE_USERS) {
if (!(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS)) {
if (is_op && !is_fo)
return FALSE;
}
}
-
+
if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS) {
if (!(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS)) {
if (is_op && !is_fo)
return FALSE;
}
}
-
+
+ if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
return TRUE;
}
SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
("There are %d clients, %d servers and %d "
"routers in SILC Network",
- server->stat.clients, server->stat.servers + 1,
+ server->stat.clients, server->stat.servers,
server->stat.routers));
} else {
if (server->stat.clients && server->stat.servers + 1)
SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
("There are %d clients, %d servers and %d "
"routers in SILC Network",
- server->stat.clients, server->stat.servers + 1,
+ server->stat.clients, server->stat.servers,
(server->standalone ? 0 :
!server->stat.routers ? 1 :
server->stat.routers)));
SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
("There are %d clients on %d server in our cell",
server->stat.cell_clients,
- server->stat.cell_servers + 1));
+ server->stat.cell_servers));
if (server->server_type == SILC_ROUTER) {
SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
("I have %d clients, %d channels, %d servers and "
"%d routers",
- server->stat.my_clients,
+ server->stat.my_clients,
server->stat.my_channels,
server->stat.my_servers,
server->stat.my_routers));
{
SilcBuffer killed, killer;
- SILC_LOG_DEBUG(("Killing client %s",
+ SILC_LOG_DEBUG(("Killing client %s",
silc_id_render(remote_client->id, SILC_ID_CLIENT)));
/* Send the KILL notify packets. First send it to the channel, then
/* Send KILLED notify to the channels. It is not sent to the client
as it will be sent differently destined directly to the client and not
to the channel. */
- silc_server_send_notify_on_channels(server, remote_client,
+ silc_server_send_notify_on_channels(server, remote_client,
remote_client, SILC_NOTIFY_TYPE_KILLED,
3, killed->data, killed->len,
comment, comment ? strlen(comment) : 0,
/* Send KILLED notify to the client directly */
if (remote_client->connection || remote_client->router)
- silc_server_send_notify_killed(server, remote_client->connection ?
- remote_client->connection :
+ silc_server_send_notify_killed(server, remote_client->connection ?
+ remote_client->connection :
remote_client->router->connection, FALSE,
- remote_client->id, comment,
+ remote_client->id, comment,
killer_id, killer_id_type);
/* Remove the client from all channels. This generates new keys to the
channels as well. */
- silc_server_remove_from_channels(server, NULL, remote_client, FALSE,
+ silc_server_remove_from_channels(server, NULL, remote_client, FALSE,
NULL, TRUE, TRUE);
/* Remove the client entry, If it is locally connected then we will also
if (!silc_idlist_del_client(server->global_list, remote_client)) {
/* Remove this client from watcher list if it is */
silc_server_del_from_watcher_list(server, remote_client);
- silc_idlist_del_client(server->local_list, remote_client);
+ silc_idlist_del_client(server->local_list, remote_client);
}
}
const char *new_nick;
} WatcherNotifyContext;
-static void
-silc_server_check_watcher_list_foreach(void *key, void *context,
+static void
+silc_server_check_watcher_list_foreach(void *key, void *context,
void *user_context)
{
WatcherNotifyContext *notify = user_context;
silc_id_render(entry->id, SILC_ID_CLIENT)));
/* Send the WATCH notify */
- silc_server_send_notify_watch(notify->server, sock, entry,
- notify->client,
+ silc_server_send_notify_watch(notify->server, sock, entry,
+ notify->client,
notify->new_nick ? notify->new_nick :
- (const char *)notify->client->nickname,
+ (const char *)notify->client->nickname,
notify->notify);
}
}
unsigned char *tmp = NULL;
SilcUInt32 len = 0, t;
SilcHashTableList htl;
- SilcBuffer entry, idp = NULL;
+ SilcBuffer entry, idp = NULL, pkp = NULL;
bool ret = FALSE;
if (type < 1 || type > 3 || !check)
return FALSE;
}
if (type == 2) {
- tmp = silc_pkcs_public_key_encode(check, &len);
- if (!tmp)
+ pkp = silc_pkcs_public_key_payload_encode(check);
+ if (!pkp)
return FALSE;
+ tmp = pkp->data;
+ len = pkp->len;
}
if (type == 3) {
idp = silc_id_payload_encode(check, SILC_ID_CLIENT);
}
silc_hash_table_list_reset(&htl);
- if (!idp)
+ if (type == 1)
silc_free(tmp);
silc_buffer_free(idp);
+ silc_buffer_free(pkp);
return ret;
}
silc_server_connect_to_router, server, 0, 1,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
+
+static void
+silc_server_process_channel_pk_destruct(void *key, void *context,
+ void *user_context)
+{
+ silc_free(key);
+ silc_pkcs_public_key_free(context);
+}
+
+/* Processes a channel public key, either adds or removes it. */
+
+SilcStatus
+silc_server_process_channel_pk(SilcServer server,
+ SilcChannelEntry channel,
+ SilcUInt32 type, const unsigned char *pk,
+ SilcUInt32 pk_len)
+{
+ unsigned char pkhash[20];
+ SilcPublicKey chpk;
+
+ SILC_LOG_DEBUG(("Processing channel public key"));
+
+ if (!pk || !pk_len)
+ return SILC_STATUS_ERR_NOT_ENOUGH_PARAMS;
+
+ /* Decode the public key */
+ if (!silc_pkcs_public_key_payload_decode((unsigned char *)pk, pk_len, &chpk))
+ return SILC_STATUS_ERR_UNSUPPORTED_PUBLIC_KEY;
+
+ /* Create channel public key list (hash table) if needed */
+ if (!channel->channel_pubkeys) {
+ channel->channel_pubkeys =
+ silc_hash_table_alloc(0, silc_hash_data, (void *)20,
+ silc_hash_data_compare, (void *)20,
+ silc_server_process_channel_pk_destruct, channel,
+ TRUE);
+ }
+
+ /* Create SHA-1 digest of the public key data */
+ silc_hash_make(server->sha1hash, pk + 4, pk_len - 4, pkhash);
+
+ if (type == 0x00) {
+ /* Add new public key to channel public key list */
+ SILC_LOG_DEBUG(("Add new channel public key to channel %s",
+ channel->channel_name));
+
+ /* Check for resource limit */
+ if (silc_hash_table_count(channel->channel_pubkeys) > 64) {
+ silc_pkcs_public_key_free(chpk);
+ return SILC_STATUS_ERR_RESOURCE_LIMIT;
+ }
+
+ /* Add if doesn't exist already */
+ if (!silc_hash_table_find(channel->channel_pubkeys, pkhash,
+ NULL, NULL))
+ silc_hash_table_add(channel->channel_pubkeys, silc_memdup(pkhash, 20),
+ chpk);
+ } else if (type == 0x01) {
+ /* Delete public key from channel public key list */
+ SILC_LOG_DEBUG(("Delete a channel public key from channel %s",
+ channel->channel_name));
+ if (!silc_hash_table_del(channel->channel_pubkeys, pkhash))
+ silc_pkcs_public_key_free(chpk);
+ } else {
+ silc_pkcs_public_key_free(chpk);
+ return SILC_STATUS_ERR_NOT_ENOUGH_PARAMS;
+ }
+
+ return SILC_STATUS_OK;
+}
+
+/* Returns the channel public keys as Argument List payload. */
+
+SilcBuffer silc_server_get_channel_pk_list(SilcServer server,
+ SilcChannelEntry channel,
+ bool announce,
+ bool delete)
+{
+ SilcHashTableList htl;
+ SilcBuffer list, pkp;
+ SilcPublicKey pk;
+
+ SILC_LOG_DEBUG(("Encoding channel public keys list"));
+
+ if (!channel->channel_pubkeys ||
+ !silc_hash_table_count(channel->channel_pubkeys))
+ return NULL;
+
+ /* Encode the list */
+ list = silc_buffer_alloc_size(2);
+ silc_buffer_format(list,
+ SILC_STR_UI_SHORT(silc_hash_table_count(
+ channel->channel_pubkeys)),
+ SILC_STR_END);
+
+ silc_hash_table_list(channel->channel_pubkeys, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void **)&pk)) {
+ pkp = silc_pkcs_public_key_payload_encode(pk);
+ list = silc_argument_payload_encode_one(list, pkp->data, pkp->len,
+ announce ? 0x03 :
+ delete ? 0x01 : 0x00);
+ silc_buffer_free(pkp);
+ }
+ silc_hash_table_list_reset(&htl);
+
+ return list;
+}
+
+/* Sets the channel public keys into channel from the list of public keys. */
+
+SilcStatus silc_server_set_channel_pk_list(SilcServer server,
+ SilcSocketConnection sender,
+ SilcChannelEntry channel,
+ const unsigned char *pklist,
+ SilcUInt32 pklist_len)
+{
+ SilcUInt16 argc;
+ SilcArgumentPayload args;
+ unsigned char *chpk;
+ SilcUInt32 chpklen, type;
+ SilcStatus ret = SILC_STATUS_OK;
+
+ SILC_LOG_DEBUG(("Setting channel public keys list"));
+
+ if (!pklist || pklist_len < 2)
+ return SILC_STATUS_ERR_NOT_ENOUGH_PARAMS;
+
+ /* Get the argument from the Argument List Payload */
+ SILC_GET16_MSB(argc, pklist);
+ args = silc_argument_payload_parse(pklist + 2, pklist_len - 2, argc);
+ if (!args)
+ return SILC_STATUS_ERR_NOT_ENOUGH_PARAMS;
+
+ /* Process the public keys one by one */
+ chpk = silc_argument_get_first_arg(args, &type, &chpklen);
+
+ /* If announcing keys and we have them set already, do not allow this */
+ if (chpk && type == 0x03 && channel->channel_pubkeys &&
+ server->server_type == SILC_ROUTER &&
+ sender != SILC_PRIMARY_ROUTE(server)) {
+ SILC_LOG_DEBUG(("Channel public key list set already, enforce our list"));
+ silc_argument_payload_free(args);
+ return SILC_STATUS_ERR_OPERATION_ALLOWED;
+ }
+
+ /* If we are normal server and receive announcement list and we already
+ have keys set, we replace the old list with the announced one. */
+ if (chpk && type == 0x03 && channel->channel_pubkeys &&
+ server->server_type != SILC_ROUTER) {
+ SilcBuffer sidp;
+ unsigned char mask[4];
+
+ SILC_LOG_DEBUG(("Router enforces its list, remove old list"));
+ silc_hash_table_free(channel->channel_pubkeys);
+ channel->channel_pubkeys = NULL;
+
+ /* Send notify that removes the old list */
+ sidp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
+ SILC_PUT32_MSB((channel->mode & (~SILC_CHANNEL_MODE_CHANNEL_AUTH)), mask);
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+ SILC_NOTIFY_TYPE_CMODE_CHANGE, 7,
+ sidp->data, sidp->len,
+ mask, 4,
+ channel->cipher,
+ channel->cipher ?
+ strlen(channel->cipher) : 0,
+ channel->hmac_name,
+ channel->hmac_name ?
+ strlen(channel->hmac_name) : 0,
+ channel->passphrase,
+ channel->passphrase ?
+ strlen(channel->passphrase) : 0,
+ NULL, 0, NULL, 0);
+ silc_buffer_free(sidp);
+ }
+
+ while (chpk) {
+ if (type == 0x03)
+ type = 0x00;
+ ret = silc_server_process_channel_pk(server, channel, type,
+ chpk, chpklen);
+ if (ret != SILC_STATUS_OK)
+ break;
+ chpk = silc_argument_get_next_arg(args, &type, &chpklen);
+ }
+
+ silc_argument_payload_free(args);
+ return ret;
+}
+
+/* Verifies the Authentication Payload `auth' with one of the public keys
+ on the `channel' public key list. */
+
+bool silc_server_verify_channel_auth(SilcServer server,
+ SilcChannelEntry channel,
+ SilcClientID *client_id,
+ const unsigned char *auth,
+ SilcUInt32 auth_len)
+{
+ SilcAuthPayload ap;
+ SilcPublicKey chpk;
+ unsigned char *pkhash;
+ SilcUInt32 pkhash_len;
+ bool ret = FALSE;
+
+ SILC_LOG_DEBUG(("Verifying channel authentication"));
+
+ if (!auth || !auth_len || !channel->channel_pubkeys)
+ return FALSE;
+
+ /* Get the hash from the auth data which tells us what public key we
+ must use in verification. */
+
+ ap = silc_auth_payload_parse(auth, auth_len);
+ if (!ap)
+ return FALSE;
+
+ pkhash = silc_auth_get_public_data(ap, &pkhash_len);
+ if (pkhash_len < 128)
+ goto out;
+
+ /* Find the public key with the hash */
+ if (!silc_hash_table_find(channel->channel_pubkeys, pkhash,
+ NULL, (void **)&chpk)) {
+ SILC_LOG_DEBUG(("Public key not found in channel public key list"));
+ goto out;
+ }
+
+ /* Verify the signature */
+ if (!silc_auth_verify(ap, SILC_AUTH_PUBLIC_KEY, (void *)chpk, 0,
+ server->sha1hash, client_id, SILC_ID_CLIENT)) {
+ SILC_LOG_DEBUG(("Authentication failed"));
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ silc_auth_payload_free(ap);
+ return ret;
+}