From 41679a58249890f091c084b6fb34b58187618df1 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Fri, 3 Oct 2003 15:40:28 +0000 Subject: [PATCH] Channel public key support added. --- apps/silcd/idlist.c | 80 ++++---- apps/silcd/idlist.h | 71 +++---- apps/silcd/packet_send.c | 15 +- apps/silcd/packet_send.h | 47 ++--- apps/silcd/server_util.c | 408 ++++++++++++++++++++++++++++++++------- apps/silcd/server_util.h | 55 ++++-- 6 files changed, 485 insertions(+), 191 deletions(-) diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index fb457b6c..7e5e99b9 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -4,13 +4,13 @@ Author: Pekka Riikonen - 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 @@ -112,8 +112,8 @@ SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge) 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) @@ -129,7 +129,7 @@ silc_idlist_add_server(SilcIDList id_list, 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; @@ -153,13 +153,13 @@ silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id, 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; @@ -186,7 +186,7 @@ silc_idlist_find_server_by_name(SilcIDList id_list, char *name, return NULL; server = (SilcServerEntry)id_cache->context; - + if (server && registered && !(server->data.status & SILC_IDLIST_STATUS_REGISTERED)) return NULL; @@ -210,7 +210,7 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname, 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)) @@ -224,7 +224,7 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname, 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)) @@ -236,7 +236,7 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname, if (!silc_idcache_list_next(list, &id_cache)) break; } - + silc_idcache_list_free(list); if (server && registered && @@ -251,7 +251,7 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname, 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, @@ -265,7 +265,7 @@ 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; @@ -278,7 +278,7 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id, 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")); @@ -329,8 +329,8 @@ int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry) 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) { @@ -348,7 +348,7 @@ silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username, 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); @@ -394,7 +394,7 @@ int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry) 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) { @@ -406,8 +406,8 @@ int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname, 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); @@ -415,9 +415,9 @@ int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname, 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; @@ -452,8 +452,8 @@ int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname, 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); @@ -461,9 +461,9 @@ int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname, 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; @@ -481,15 +481,15 @@ silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id, 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; @@ -527,8 +527,8 @@ silc_idlist_replace_client_id(SilcServer server, 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; @@ -555,7 +555,7 @@ silc_idlist_replace_client_id(SilcServer server, 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; @@ -622,7 +622,7 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode, 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); @@ -663,7 +663,7 @@ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry) 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); @@ -692,6 +692,8 @@ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry) 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); @@ -772,7 +774,7 @@ silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id, 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; @@ -785,7 +787,7 @@ silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id, 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")); @@ -815,14 +817,14 @@ silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id, 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)) diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index ac67e10a..cfb46fea 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -4,13 +4,13 @@ Author: Pekka Riikonen - 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 @@ -111,12 +111,12 @@ typedef struct { 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: @@ -158,8 +158,8 @@ typedef struct { 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 @@ -173,7 +173,7 @@ typedef struct { 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! */ @@ -192,7 +192,7 @@ struct SilcServerEntryStruct { void *connection; }; -/* +/* SILC Channel Client entry structure. This entry used only by the SilcChannelEntry object and it holds @@ -220,11 +220,11 @@ typedef struct SilcChannelClientEntryStruct { 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: @@ -260,7 +260,7 @@ typedef struct SilcChannelClientEntryStruct { 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. @@ -268,14 +268,14 @@ typedef struct SilcChannelClientEntryStruct { 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. @@ -283,9 +283,9 @@ typedef struct SilcChannelClientEntryStruct { 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 @@ -307,8 +307,8 @@ typedef struct SilcChannelClientEntryStruct { 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; @@ -363,16 +363,16 @@ struct SilcClientEntryStruct { /* 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: @@ -401,12 +401,12 @@ struct SilcClientEntryStruct { 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. @@ -438,8 +438,8 @@ struct SilcClientEntryStruct { 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 @@ -473,6 +473,7 @@ struct SilcChannelEntryStruct { char *cipher; char *hmac_name; SilcPublicKey founder_key; + SilcHashTable channel_pubkeys; SilcUInt32 user_limit; unsigned char *passphrase; @@ -502,7 +503,7 @@ struct SilcChannelEntryStruct { unsigned int users_resolved : 1; }; -/* +/* SILC ID List object. As for remainder these lists are defined as follows: @@ -547,7 +548,7 @@ typedef struct SilcIDListStruct { /* 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. @@ -564,8 +565,8 @@ typedef struct { 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); @@ -584,13 +585,13 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id, 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, diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index 3feec835..71868184 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -49,9 +49,9 @@ int silc_server_packet_send_real(SilcServer server, sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" : "Router"))); - SILC_SET_DISCONNECTING(sock); if (sock->user_data) silc_server_free_sock_user_data(server, sock, NULL); + SILC_SET_DISCONNECTING(sock); silc_server_close_connection(server, sock); return ret; } @@ -1285,7 +1285,8 @@ void silc_server_send_notify_cmode(SilcServer server, void *id, SilcIdType id_type, const char *cipher, const char *hmac, const char *passphrase, - SilcPublicKey founder_key) + SilcPublicKey founder_key, + SilcBuffer channel_pubkeys) { SilcBuffer idp, fkey = NULL; unsigned char mode[4]; @@ -1297,14 +1298,16 @@ void silc_server_send_notify_cmode(SilcServer server, silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id, SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE, - 6, idp->data, idp->len, + 7, idp->data, idp->len, mode, 4, cipher, cipher ? strlen(cipher) : 0, hmac, hmac ? strlen(hmac) : 0, passphrase, passphrase ? strlen(passphrase) : 0, - fkey ? fkey->data : NULL, fkey ? fkey->len : 0); - silc_buffer_free(fkey), + fkey ? fkey->data : NULL, fkey ? fkey->len : 0, + channel_pubkeys ? channel_pubkeys->data : NULL, + channel_pubkeys ? channel_pubkeys->len : 0); + silc_buffer_free(fkey); silc_buffer_free(idp); } @@ -2004,7 +2007,7 @@ void silc_server_packet_queue_purge(SilcServer server, SilcSocketConnection sock) { if (sock && SILC_IS_OUTBUF_PENDING(sock) && - (SILC_IS_DISCONNECTED(sock) == FALSE)) { + !(SILC_IS_DISCONNECTING(sock)) && !(SILC_IS_DISCONNECTED(sock))) { SILC_LOG_DEBUG(("Purging outgoing queue")); server->stat.packets_sent++; silc_packet_send(sock, TRUE); diff --git a/apps/silcd/packet_send.h b/apps/silcd/packet_send.h index 2dac8012..730111ad 100644 --- a/apps/silcd/packet_send.h +++ b/apps/silcd/packet_send.h @@ -4,13 +4,13 @@ Author: Pekka Riikonen - 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 @@ -27,30 +27,30 @@ int silc_server_packet_send_real(SilcServer server, SilcSocketConnection sock, bool force_send); void silc_server_packet_send(SilcServer server, - SilcSocketConnection sock, - SilcPacketType type, + SilcSocketConnection sock, + SilcPacketType type, SilcPacketFlags flags, - unsigned char *data, + unsigned char *data, SilcUInt32 data_len, bool force_send); void silc_server_packet_send_dest(SilcServer server, - SilcSocketConnection sock, - SilcPacketType type, + SilcSocketConnection sock, + SilcPacketType type, SilcPacketFlags flags, void *dst_id, SilcIdType dst_id_type, - unsigned char *data, + unsigned char *data, SilcUInt32 data_len, bool force_send); void silc_server_packet_send_srcdest(SilcServer server, - SilcSocketConnection sock, - SilcPacketType type, + SilcSocketConnection sock, + SilcPacketType type, SilcPacketFlags flags, void *src_id, SilcIdType src_id_type, void *dst_id, SilcIdType dst_id_type, - unsigned char *data, + unsigned char *data, SilcUInt32 data_len, bool force_send); void silc_server_packet_broadcast(SilcServer server, @@ -64,7 +64,7 @@ void silc_server_packet_send_clients(SilcServer server, SilcPacketType type, SilcPacketFlags flags, bool route, - unsigned char *data, + unsigned char *data, SilcUInt32 data_len, bool force_send); void silc_server_packet_send_to_channel(SilcServer server, @@ -78,7 +78,7 @@ void silc_server_packet_send_to_channel(SilcServer server, void silc_server_packet_relay_to_channel(SilcServer server, SilcSocketConnection sender_sock, SilcChannelEntry channel, - void *sender_id, + void *sender_id, SilcIdType sender_type, SilcClientEntry sender_entry, unsigned char *data, @@ -142,7 +142,8 @@ void silc_server_send_notify_cmode(SilcServer server, void *id, SilcIdType id_type, const char *cipher, const char *hmac, const char *passphrase, - SilcPublicKey founder_key); + SilcPublicKey founder_key, + SilcBuffer channel_pubkeys); void silc_server_send_notify_cumode(SilcServer server, SilcSocketConnection sock, bool broadcast, @@ -220,36 +221,36 @@ void silc_server_send_notify_on_channels(SilcServer server, void silc_server_send_new_id(SilcServer server, SilcSocketConnection sock, bool broadcast, - void *id, SilcIdType id_type, + void *id, SilcIdType id_type, SilcUInt32 id_len); void silc_server_send_new_channel(SilcServer server, SilcSocketConnection sock, bool broadcast, char *channel_name, - void *channel_id, + void *channel_id, SilcUInt32 channel_id_len, SilcUInt32 mode); void silc_server_send_channel_key(SilcServer server, SilcSocketConnection sender, SilcChannelEntry channel, unsigned char route); -void silc_server_send_command(SilcServer server, +void silc_server_send_command(SilcServer server, SilcSocketConnection sock, - SilcCommand command, + SilcCommand command, SilcUInt16 ident, SilcUInt32 argc, ...); -void silc_server_send_command_reply(SilcServer server, +void silc_server_send_command_reply(SilcServer server, SilcSocketConnection sock, - SilcCommand command, + SilcCommand command, SilcStatus status, SilcStatus error, SilcUInt16 ident, SilcUInt32 argc, ...); -void silc_server_send_dest_command_reply(SilcServer server, +void silc_server_send_dest_command_reply(SilcServer server, SilcSocketConnection sock, void *dst_id, SilcIdType dst_id_type, - SilcCommand command, + SilcCommand command, SilcStatus status, SilcStatus error, SilcUInt16 ident, @@ -273,7 +274,7 @@ void silc_server_send_opers(SilcServer server, SilcPacketType type, SilcPacketFlags flags, bool route, bool local, - unsigned char *data, + unsigned char *data, SilcUInt32 data_len, bool force_send); void silc_server_send_opers_notify(SilcServer server, diff --git a/apps/silcd/server_util.c b/apps/silcd/server_util.c index f697323d..5815ca5a 100644 --- a/apps/silcd/server_util.c +++ b/apps/silcd/server_util.c @@ -1,10 +1,10 @@ /* - server_util.c + server_util.c Author: Pekka Riikonen - 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 @@ -42,7 +42,7 @@ silc_server_remove_clients_channels(SilcServer server, 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 *)"")); @@ -72,7 +72,7 @@ silc_server_remove_clients_channels(SilcServer server, /* 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; @@ -113,7 +113,7 @@ silc_server_remove_clients_channels(SilcServer server, } 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); @@ -123,7 +123,7 @@ silc_server_remove_clients_channels(SilcServer server, /* 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, @@ -230,7 +230,7 @@ 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)) { @@ -328,7 +328,7 @@ bool silc_server_remove_clients_by_server(SilcServer server, 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, @@ -363,8 +363,8 @@ bool silc_server_remove_clients_by_server(SilcServer server, 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); @@ -394,7 +394,7 @@ silc_server_update_clients_by_real_server(SilcServer server, 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))); @@ -442,7 +442,7 @@ silc_server_update_clients_by_real_server(SilcServer 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))); @@ -490,7 +490,7 @@ silc_server_update_clients_by_real_server(SilcServer 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) @@ -516,16 +516,16 @@ void silc_server_update_clients_by_server(SilcServer 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); @@ -545,7 +545,7 @@ void silc_server_update_clients_by_server(SilcServer server, } 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)) @@ -571,16 +571,16 @@ void silc_server_update_clients_by_server(SilcServer 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); @@ -596,7 +596,7 @@ void silc_server_update_clients_by_server(SilcServer server, } 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)) @@ -610,7 +610,7 @@ void silc_server_update_clients_by_server(SilcServer server, /* 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) { @@ -652,7 +652,7 @@ void silc_server_update_servers_by_server(SilcServer server, 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; @@ -698,7 +698,7 @@ void silc_server_update_servers_by_server(SilcServer server, 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; @@ -846,7 +846,7 @@ void silc_server_remove_servers_by_server(SilcServer server, /* 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; @@ -871,7 +871,7 @@ void silc_server_remove_channels_by_server(SilcServer server, /* 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) { @@ -995,9 +995,9 @@ bool silc_server_channel_delete(SilcServer server, 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, @@ -1007,7 +1007,7 @@ 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); } @@ -1093,7 +1093,7 @@ SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip, 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, @@ -1116,12 +1116,12 @@ SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server, 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) { @@ -1131,7 +1131,7 @@ SilcPublicKey silc_server_find_public_key(SilcServer server, 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")); @@ -1159,8 +1159,10 @@ SilcPublicKey silc_server_get_public_key(SilcServer server, 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; @@ -1170,7 +1172,7 @@ SilcPublicKey silc_server_get_public_key(SilcServer server, 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, @@ -1191,18 +1193,18 @@ bool silc_server_connection_allowed(SilcServer server, /* 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)) { @@ -1213,7 +1215,7 @@ bool silc_server_connection_allowed(SilcServer server, 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; @@ -1224,18 +1226,18 @@ bool silc_server_connection_allowed(SilcServer server, 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; @@ -1253,7 +1255,7 @@ bool silc_server_connection_allowed(SilcServer server, 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; @@ -1262,7 +1264,7 @@ bool silc_server_connection_allowed(SilcServer server, 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; @@ -1307,7 +1309,7 @@ bool silc_server_check_cmode_rights(SilcServer server, return FALSE; } } - + if (mode & SILC_CHANNEL_MODE_PASSPHRASE) { if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) { if (is_op && !is_fo) @@ -1331,7 +1333,7 @@ bool silc_server_check_cmode_rights(SilcServer server, return FALSE; } } - + if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) { if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) { if (is_op && !is_fo) @@ -1343,7 +1345,7 @@ bool silc_server_check_cmode_rights(SilcServer server, return FALSE; } } - + if (mode & SILC_CHANNEL_MODE_SILENCE_USERS) { if (!(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS)) { if (is_op && !is_fo) @@ -1355,7 +1357,7 @@ bool silc_server_check_cmode_rights(SilcServer server, return FALSE; } } - + if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS) { if (!(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS)) { if (is_op && !is_fo) @@ -1367,7 +1369,19 @@ bool silc_server_check_cmode_rights(SilcServer server, 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; } @@ -1431,14 +1445,14 @@ void silc_server_send_connect_notifys(SilcServer server, 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))); @@ -1448,12 +1462,12 @@ void silc_server_send_connect_notifys(SilcServer server, 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)); @@ -1501,7 +1515,7 @@ void silc_server_kill_client(SilcServer server, { 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 @@ -1514,7 +1528,7 @@ void silc_server_kill_client(SilcServer server, /* 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, @@ -1527,15 +1541,15 @@ void silc_server_kill_client(SilcServer server, /* 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 @@ -1564,7 +1578,7 @@ void silc_server_kill_client(SilcServer server, 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); } } @@ -1579,8 +1593,8 @@ typedef struct { 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; @@ -1600,10 +1614,10 @@ silc_server_check_watcher_list_foreach(void *key, void *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); } } @@ -1746,7 +1760,7 @@ bool silc_server_inviteban_match(SilcServer server, SilcHashTable list, 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) @@ -1758,9 +1772,11 @@ bool silc_server_inviteban_match(SilcServer server, SilcHashTable list, 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); @@ -1787,9 +1803,10 @@ bool silc_server_inviteban_match(SilcServer server, SilcHashTable list, } silc_hash_table_list_reset(&htl); - if (!idp) + if (type == 1) silc_free(tmp); silc_buffer_free(idp); + silc_buffer_free(pkp); return ret; } @@ -1951,3 +1968,244 @@ void silc_server_create_connections(SilcServer server) 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; +} diff --git a/apps/silcd/server_util.h b/apps/silcd/server_util.h index 7209c04c..32ea609f 100644 --- a/apps/silcd/server_util.h +++ b/apps/silcd/server_util.h @@ -1,10 +1,10 @@ /* - server_util.h + server_util.h Author: Pekka Riikonen - 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 @@ -22,7 +22,7 @@ /* 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, SilcServerEntry router, @@ -35,7 +35,7 @@ bool silc_server_remove_clients_by_server(SilcServer server, `from' and which are originated from a server that we have connection 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); @@ -62,11 +62,11 @@ void silc_server_remove_servers_by_server(SilcServer server, bool remove_clients); /* 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); /* 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); @@ -85,9 +85,9 @@ bool silc_server_channel_has_local(SilcChannelEntry channel); bool silc_server_channel_delete(SilcServer server, SilcChannelEntry channel); -/* 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, SilcChannelEntry channel, @@ -109,17 +109,17 @@ SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip, /* Find number of sockets by IP address indicated by remote host, indicated 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, SilcSocketType type); -/* 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); @@ -133,7 +133,7 @@ SilcPublicKey silc_server_get_public_key(SilcServer server, /* 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, +bool silc_server_connection_allowed(SilcServer server, SilcSocketConnection sock, SilcSocketType type, SilcServerConfigConnParams *global, @@ -208,7 +208,36 @@ void silc_server_inviteban_process(SilcServer server, SilcHashTable list, void silc_server_inviteban_destruct(void *key, void *context, void *user_context); -/* Creates connections accoring to configuration. */ +/* Creates connections according to configuration. */ void silc_server_create_connections(SilcServer server); + +/* 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); + +/* Returns the channel public keys as Argument List payload. */ +SilcBuffer silc_server_get_channel_pk_list(SilcServer server, + SilcChannelEntry channel, + bool announce, + bool delete); + +/* 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); + +/* 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); + #endif /* SERVER_UTIL_H */ -- 2.24.0