Channel public key support added.
authorPekka Riikonen <priikone@silcnet.org>
Fri, 3 Oct 2003 15:40:28 +0000 (15:40 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Fri, 3 Oct 2003 15:40:28 +0000 (15:40 +0000)
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/packet_send.c
apps/silcd/packet_send.h
apps/silcd/server_util.c
apps/silcd/server_util.h

index fb457b6c44335fe596b732bccd50aed9d8f0b605..7e5e99b9d3643e3f55380f8595ec3400b58ab8d0 100644 (file)
@@ -4,13 +4,13 @@
 
   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
@@ -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))
index ac67e10ad5a06cc950476c76f706d1d185828a78..cfb46feaddf2847f56cea06e3aba6296646dfbd1 100644 (file)
@@ -4,13 +4,13 @@
 
   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
@@ -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,
index 3feec835c08c65a5058d3964f522db032104e3ca..71868184b9c61e27e0c0d1d41426b56e9cac121b 100644 (file)
@@ -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);
index 2dac801278ab9638f91c8df138fd1d1c291e9cba..730111adeb2f2a341258d968c713fcf9b43bedf2 100644 (file)
@@ -4,13 +4,13 @@
 
   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
@@ -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,
index f697323d1ca3675f732f8c0fe8af0846e8eaa375..5815ca5ae14ae0551dccda8a9a86f1472cf270e1 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  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
@@ -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;
+}
index 7209c04cbde706dfe5c390263c19b83876f95119..32ea609f16e9f12de22ece815f2d45b5af49b86b 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  server_util.h 
+  server_util.h
 
   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
@@ -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 */