Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2001 Pekka Riikonen
+ Copyright (C) 1997 - 2002 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
/* Remove the client from all channels. The client is removed from
the channels' user list. */
silc_hash_table_list(client->channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
channel = chl->channel;
/* Remove channel from client's channel list */
channel->disabled = TRUE;
silc_hash_table_list(channel->user_list, &htl2);
- while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
+ while (silc_hash_table_get(&htl2, NULL, (void **)&chl2)) {
silc_hash_table_del(chl2->client->channels, channel);
silc_hash_table_del(channel->user_list, chl2->client);
channel->user_count--;
SilcClientEntry client = NULL;
SilcBuffer idp;
SilcClientEntry *clients = NULL;
- uint32 clients_c = 0;
+ SilcUInt32 clients_c = 0;
unsigned char **argv = NULL;
- uint32 *argv_lens = NULL, *argv_types = NULL, argc = 0;
+ SilcUInt32 *argv_lens = NULL, *argv_types = NULL, argc = 0;
SilcHashTableList htl;
SilcChannelEntry channel;
SilcHashTable channels;
this server's client(s) on the channel. As they left the channel we
must re-generate the channel key. */
silc_hash_table_list(channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&channel)) {
if (!silc_server_create_channel_key(server, channel, 0)) {
silc_hash_table_list_reset(&htl);
silc_hash_table_free(channels);
SilcHashTableList htl;
silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
if (chl->client->router) {
silc_hash_table_list_reset(&htl);
return TRUE;
SilcHashTableList htl;
silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
if (!chl->client->router) {
silc_hash_table_list_reset(&htl);
return TRUE;
`client' which is faster than checking the user list from `channel'. */
bool silc_server_client_on_channel(SilcClientEntry client,
- SilcChannelEntry channel)
+ SilcChannelEntry channel,
+ SilcChannelClientEntry *chl)
{
if (!client || !channel)
return FALSE;
- return silc_hash_table_find(client->channels, channel, NULL, NULL);
+ return silc_hash_table_find(client->channels, channel, NULL,
+ (void **)chl);
}
/* Checks string for bad characters and returns TRUE if they are found. */
-bool silc_server_name_bad_chars(const char *name, uint32 name_len)
+bool silc_server_name_bad_chars(const char *name, SilcUInt32 name_len)
{
int i;
/* Modifies the `name' if it includes bad characters and returns new
allocated name that does not include bad characters. */
-char *silc_server_name_modify_bad(const char *name, uint32 name_len)
+char *silc_server_name_modify_bad(const char *name, SilcUInt32 name_len)
{
int i;
char *newname = strdup(name);
/* Find number of sockets by IP address indicated by `ip'. Returns 0 if
socket connections with the IP address does not exist. */
-uint32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip)
+SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
+ SilcSocketType type)
{
int i, count;
for (i = 0, count = 0; i < server->config->param.connections_max; i++) {
- if (server->sockets[i] && !strcmp(server->sockets[i]->ip, ip))
+ if (server->sockets[i] && !strcmp(server->sockets[i]->ip, ip) &&
+ server->sockets[i]->type == type)
count++;
}
return count;
}
+
+/* Find number of sockets by IP address indicated by remote host, indicatd
+ 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,
+ const char *ip,
+ const char *hostname,
+ SilcUInt16 port,
+ SilcSocketType type)
+{
+ int i, count;
+
+ if (!ip && !hostname)
+ return 0;
+
+ for (i = 0, count = 0; i < server->config->param.connections_max; i++) {
+ if (server->sockets[i] &&
+ ((ip && !strcmp(server->sockets[i]->ip, ip)) ||
+ (hostname && !strcmp(server->sockets[i]->hostname, hostname))) &&
+ server->sockets[i]->port == port &&
+ server->sockets[i]->type == type)
+ count++;
+ }
+
+ return count;
+}
+
+/* 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,
+ SilcHashTable local_public_keys,
+ SilcPublicKey remote_public_key)
+{
+ SilcPublicKey cached_key;
+
+ SILC_LOG_DEBUG(("Find remote public key (%d keys in local cache)",
+ silc_hash_table_count(local_public_keys)));
+
+ if (!silc_hash_table_find_ext(local_public_keys, remote_public_key,
+ (void **)&cached_key, NULL,
+ silc_hash_public_key, NULL,
+ silc_hash_public_key_compare, NULL)) {
+ SILC_LOG_ERROR(("Public key not found"));
+ return NULL;
+ }
+
+ SILC_LOG_DEBUG(("Found public key"));
+
+ return cached_key;
+}
+
+/* This returns the first public key from the table of public keys. This
+ is used only in cases where single public key exists in the table and
+ we want to get a pointer to it. For public key tables that has multiple
+ keys in it the silc_server_find_public_key must be used. */
+
+SilcPublicKey silc_server_get_public_key(SilcServer server,
+ SilcHashTable local_public_keys)
+{
+ SilcPublicKey cached_key;
+ SilcHashTableList htl;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ 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))
+ return NULL;
+ silc_hash_table_list_reset(&htl);
+
+ return cached_key;
+}
+
+/* Check whether the connection `sock' is allowed to connect to us. This
+ 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,
+ SilcSocketConnection sock,
+ SilcSocketType type,
+ SilcServerConfigConnParams *global,
+ SilcServerConfigConnParams *params,
+ SilcSKE ske)
+{
+ SilcUInt32 conn_number = (type == SILC_SOCKET_TYPE_CLIENT ?
+ server->stat.my_clients :
+ type == SILC_SOCKET_TYPE_SERVER ?
+ server->stat.my_servers :
+ server->stat.my_routers);
+ SilcUInt32 num_sockets, max_hosts, max_per_host;
+ SilcUInt32 r_protocol_version, l_protocol_version;
+ SilcUInt32 r_software_version, l_software_version;
+ char *r_vendor_version = NULL, *l_vendor_version;
+
+ /* Check version */
+
+ 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 :
+ global->version_software);
+ 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)) {
+ /* Match protocol version */
+ if (l_protocol_version && r_protocol_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,
+ "Server closed connection: "
+ "You support too old protocol version");
+ return FALSE;
+ }
+
+ /* Math software version */
+ if (l_software_version && r_software_version &&
+ 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,
+ "Server closed connection: "
+ "You support too old software version");
+ return FALSE;
+ }
+
+ /* Regex match 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,
+ "Server closed connection: "
+ "Your software is not supported");
+ return FALSE;
+ }
+ }
+ silc_free(r_vendor_version);
+
+ /* Check for maximum connections limit */
+
+ num_sockets = silc_server_num_sockets_by_ip(server, sock->ip, type);
+ max_hosts = (params ? params->connections_max : global->connections_max);
+ max_per_host = (params ? params->connections_max_per_host :
+ global->connections_max_per_host);
+
+ 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,
+ "Server closed connection: "
+ "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,
+ "Server closed connection: "
+ "Too many connections from your host");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Checks that client has rights to add or remove channel modes. If any
+ of the checks fails FALSE is returned. */
+
+bool silc_server_check_cmode_rights(SilcServer server,
+ SilcChannelEntry channel,
+ SilcChannelClientEntry client,
+ SilcUInt32 mode)
+{
+ bool is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
+ bool is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
+
+ /* Check whether has rights to change anything */
+ if (!is_op && !is_fo)
+ return FALSE;
+
+ /* Check whether has rights to change everything */
+ if (is_op && is_fo)
+ return TRUE;
+
+ /* We know that client is channel operator, check that they are not
+ changing anything that requires channel founder rights. Rest of the
+ modes are available automatically for channel operator. */
+
+ if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
+ if (is_op && !is_fo)
+ return FALSE;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
+ if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE))
+ if (is_op && !is_fo)
+ return FALSE;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
+ if (mode & SILC_CHANNEL_MODE_CIPHER) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER))
+ if (is_op && !is_fo)
+ return FALSE;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
+ 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;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Check that the client has rights to change its user mode. Returns
+ FALSE if setting some mode is not allowed. */
+
+bool silc_server_check_umode_rights(SilcServer server,
+ SilcClientEntry client,
+ SilcUInt32 mode)
+{
+ bool server_op = FALSE, router_op = FALSE;
+
+ if (mode & SILC_UMODE_SERVER_OPERATOR) {
+ /* Cannot set server operator mode (must use OPER command) */
+ if (!(client->mode & SILC_UMODE_SERVER_OPERATOR))
+ return FALSE;
+ } else {
+ /* Remove the server operator rights */
+ if (client->mode & SILC_UMODE_SERVER_OPERATOR)
+ server_op = TRUE;
+ }
+
+ if (mode & SILC_UMODE_ROUTER_OPERATOR) {
+ /* Cannot set router operator mode (must use SILCOPER command) */
+ if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR))
+ return FALSE;
+ } else {
+ /* Remove the router operator rights */
+ if (client->mode & SILC_UMODE_ROUTER_OPERATOR)
+ router_op = TRUE;
+ }
+
+ if (server_op)
+ SILC_UMODE_STATS_UPDATE(server, SILC_UMODE_SERVER_OPERATOR);
+ if (router_op)
+ SILC_UMODE_STATS_UPDATE(router, SILC_UMODE_ROUTER_OPERATOR);
+
+ return TRUE;
+}