Added support for channel public keys in Irssi SILC client.
authorPekka Riikonen <priikone@silcnet.org>
Fri, 8 Aug 2003 14:14:19 +0000 (14:14 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Fri, 8 Aug 2003 14:14:19 +0000 (14:14 +0000)
17 files changed:
apps/irssi/docs/help/in/cmode.in
apps/irssi/docs/help/in/join.in
apps/irssi/src/fe-common/silc/module-formats.c
apps/irssi/src/fe-common/silc/module-formats.h
apps/irssi/src/silc/core/client_ops.c
apps/irssi/src/silc/core/silc-servers.c
lib/doc/command_reply_args.html
lib/doc/notifyargs.html
lib/silcclient/client_notify.c
lib/silcclient/command.c
lib/silcclient/command_reply.c
lib/silcclient/silcclient.h
lib/silccore/silcauth.c
lib/silccore/silcauth.h
lib/silccrypt/silcpkcs.c
lib/silcutil/silcconfig.h
lib/silcutil/silcutil.c

index e4cf6b4cddf93df9b84ef12a1d8d41a09205a664..ccf77840552b338b7688f20e2f99bba65acdffcc 100644 (file)
@@ -14,7 +14,7 @@ The following modes are available:
     s               Set/unset channel as secret channel
     k               Enable/disable channel private key usage (*)
     i               Set/unset channel as invite only channel
-    t               Set/unset that only channel operator or 
+    t               Set/unset that only channel operator or
                     founder may set channel topic
     m               Set/unset user silencing.  Normal users
                     are not able to talk on channel. (*)
@@ -41,6 +41,29 @@ The following modes are available:
                     server.  If these are omitted then the default
                     SILC keypair is used.  Normally you do not need
                     to provide these arguments.
+    C [{[+|-]<pubkeyfile> }]                                (*)
+                    Set/unset channel public key mode, and add/remove
+                    channel publics key from the channel public key
+                    list.  When this mode is set only those users
+                    whose public keys has been added to the list are
+                    able to join the channel.  Channel founder may set
+                    this mode and operate on the channel public key
+                    list.
+
+                    To add public key to the list give command:
+                    CMODE +C +/path/to/the/public_key_file.pub
+
+                    To remove one public key from the list give
+                    command:
+                    CMODE +C -/path/to/the/public_key_file.pub
+
+                    To add or remove more than one public keys add as
+                    many public key file paths as necessary.
+
+                    When this mode is unset (-C), all public keys are
+                    removed from the list.  If +C is given without
+                    arguments the current channel public key list is
+                    displayed.
 
 Multiple modes can be set/unset at once if the modes does not
 require any arguments.  If mode requires an argument then only
index bd95134542b70bd610b752ff9ca680a07b0dd1c1..3812019b0bccbb19c02d8d19e3d1d6ce8cdd22b7 100644 (file)
@@ -1,8 +1,9 @@
 
 @SYNTAX:join@
 
-Joins a specified channel. Channel names usually begin with #-sign,
-but note that the #-sign is not mandatory in channel names.
+Joins a specified channel.  Note that, in SILC the #-sign is NOT
+mandatory part of the channel names, and names "#foo" and "foo" will
+join to two different channels.
 
 If -cipher is provided and the channel does not exist the cipher to
 secure the channel messages on the channel will be set to <cipher>.  If
@@ -16,9 +17,17 @@ or is invite-only channel the founder can override these conditions
 and join the channel.  Only the client who set the founder mode on the
 channel is able to use -founder option.
 
+If the channel has the +C (channel public key authentication,
+see /HELP CMODE) mode set then the user joining the channel must
+provide the -auth option to JOIN command.  This option will attempt to
+authenticate the user on the channel.  If the user's public key has
+not been added to the channel's public key list, user will not be
+able to join.  User may optionally provide the <pubkeyfile>,
+<privkeyfile> and <privkey passphrase> to authenticate with some other
+key pair than with the user's default key pair.
+
 JOIN is aliased to J by default.
 
 Description
 
 See also: LEAVE, WINDOW CLOSE, CMODE, CUMODE
-
index 09440ca5c9c5c4606944c3566f705fe22c73785f..367702286edf0a26d78673a2eb526c0402b0c40a 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  modules-formats.c
+  module-formats.c
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 Pekka Riikonen
+  Copyright (C) 2001 - 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.
-  
+  the Free Software Foundation; version 2 of the License.
+
   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
@@ -80,6 +79,9 @@ FORMAT_REC fecommon_silc_formats[] = {
        { "no_msgs_sent", "You have not sent a message to anyone yet", 0 },
        { "own_msg_private_signed", "{ownprivmsg_signed msg $0}$1", 2, { 0, 0 } },
        { "own_msg_private_query_signed", "{ownprivmsgnick_signed {ownprivnick $2}}$1", 3, { 0, 0, 0 } },
+       { "channel_pk_list", "Channel {channel $0} Public Key List:", 1, { 0 } },
+       { "channel_pk_list_entry", "$0 - {channel $1}: $2 $3: Fingerprint (SHA1) {ban $4} (Babbleprint (SHA1) {ban $5})", 6, { 1, 0, 0, 0, 0, 0 } },
+       { "channel_pk_no_list", "No Channel Public Key List for {channel $0}", 1, { 0 } },
 
        /* WHOIS, WHOWAS and USERS (alias WHO) messages */
        { NULL, "Who Queries", 0 },
index 7df09206b9ec5be9a67ed4a584c2eb715e912e71..f46e6ea2862d7b8e4edbdfc35be8b452de825b22 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  modules-formats.h
+  module-formats.h
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 Pekka Riikonen
+  Copyright (C) 2001 - 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.
-  
+  the Free Software Foundation; version 2 of the License.
+
   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
@@ -22,9 +21,9 @@
 
 enum {
   SILCTXT_MODULE_NAME,
-  
+
   SILCTXT_FILL_1,
-  
+
   SILCTXT_CHANNEL_FOUNDER_YOU,
   SILCTXT_CHANNEL_FOUNDER,
   SILCTXT_CHANNEL_TOPIC,
@@ -77,6 +76,9 @@ enum {
   SILCTXT_NO_MSGS_SENT,
   SILCTXT_OWN_MSG_PRIVATE_SIGNED,
   SILCTXT_OWN_MSG_PRIVATE_QUERY_SIGNED,
+  SILCTXT_CHANNEL_PK_LIST,
+  SILCTXT_CHANNEL_PK_LIST_ENTRY,
+  SILCTXT_CHANNEL_PK_NO_LIST,
 
   SILCTXT_FILL_2,
 
index 0c10a69a385c4834ecef63692517bc06383c0c9d..a087f47ad4d918eba0c5ee069cc8ff66ca17636c 100644 (file)
@@ -124,6 +124,53 @@ silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
   g_slist_free(windows);
 }
 
+static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
+                                          SilcChannelEntry channel_entry,
+                                          SilcBuffer channel_pubkeys)
+{
+  SilcUInt16 argc;
+  SilcArgumentPayload chpks;
+  unsigned char *pk;
+  SilcUInt32 pk_len, type;
+  int c = 1;
+  char *fingerprint, *babbleprint;
+  SilcPublicKey pubkey;
+  SilcPublicKeyIdentifier ident;
+
+  printformat_module("fe-common/silc", server, NULL,
+                    MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
+                    channel_entry->channel_name);
+
+  SILC_GET16_MSB(argc, channel_pubkeys->data);
+  chpks = silc_argument_payload_parse(channel_pubkeys->data + 2,
+                                     channel_pubkeys->len - 2, argc);
+  if (!chpks)
+    return;
+
+  pk = silc_argument_get_first_arg(chpks, &type, &pk_len);
+  while (pk) {
+    fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4);
+    babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4);
+    silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey);
+    ident = silc_pkcs_decode_identifier(pubkey->identifier);
+
+    printformat_module("fe-common/silc", server, NULL,
+                      MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
+                      c++, channel_entry->channel_name,
+                      type == 0x00 ? "Added" : "Removed",
+                      ident->realname ? ident->realname : "",
+                      fingerprint, babbleprint);
+
+    silc_free(fingerprint);
+    silc_free(babbleprint);
+    silc_pkcs_public_key_free(pubkey);
+    silc_pkcs_free_identifier(ident);
+    pk = silc_argument_get_next_arg(chpks, &type, &pk_len);
+  }
+
+  silc_argument_payload_free(chpks);
+}
+
 void silc_say(SilcClient client, SilcClientConnection conn,
              SilcClientMessageType type, char *msg, ...)
 {
@@ -479,6 +526,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
   char buf[512];
   char *name, *tmp;
   GSList *list1, *list_tmp;
+  SilcBuffer buffer;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -692,8 +740,11 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     idtype = va_arg(va, int);
     entry = va_arg(va, void *);
     mode = va_arg(va, SilcUInt32);
-    (void)va_arg(va, char *);
-    (void)va_arg(va, char *);
+    (void)va_arg(va, char *);                 /* cipher */
+    (void)va_arg(va, char *);                 /* hmac */
+    (void)va_arg(va, char *);                 /* passphrase */
+    (void)va_arg(va, SilcPublicKey);          /* founder key */
+    buffer = va_arg(va, SilcBuffer);          /* channel public keys */
     channel = va_arg(va, SilcChannelEntry);
 
     tmp = silc_client_chmode(mode,
@@ -729,6 +780,10 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
                         channel2->channel_name);
     }
 
+    /* Print the channel public key list */
+    if (buffer)
+      silc_parse_channel_public_keys(server, channel, buffer);
+
     silc_free(tmp);
     break;
 
@@ -1126,6 +1181,8 @@ void silc_disconnect(SilcClient client, SilcClientConnection conn,
    after application has called the command. Just to tell application
    that the command really was processed. */
 
+static bool cmode_list_chpks = FALSE;
+
 void silc_command(SilcClient client, SilcClientConnection conn,
                  SilcClientCommandContext cmd_context, bool success,
                  SilcCommand command, SilcStatus status)
@@ -1155,6 +1212,14 @@ void silc_command(SilcClient client, SilcClientConnection conn,
     server->no_reconnect = TRUE;
     break;
 
+  case SILC_COMMAND_CMODE:
+    if (cmd_context->argc == 3 &&
+       !strcmp(cmd_context->argv[2], "+C"))
+      cmode_list_chpks = TRUE;
+    else
+      cmode_list_chpks = FALSE;
+    break;
+
   default:
     break;
   }
@@ -1263,12 +1328,12 @@ void silc_getkey_cb(bool success, void *context)
 }
 
 /* Parse an invite or ban list */
-void  silc_parse_inviteban_list(SilcClient client,
-                               SilcClientConnection conn,
-                               SILC_SERVER_REC *server,
-                               SilcChannelEntry channel,
-                               const char *list_type,
-                               SilcArgumentPayload list)
+void silc_parse_inviteban_list(SilcClient client,
+                              SilcClientConnection conn,
+                              SILC_SERVER_REC *server,
+                              SilcChannelEntry channel,
+                              const char *list_type,
+                              SilcArgumentPayload list)
 {
   unsigned char *tmp;
   SilcUInt32 type, len;
@@ -1601,7 +1666,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       SilcChannelEntry channel;
       SilcBuffer payload;
       SilcArgumentPayload invite_list;
-      SilcUInt32 argc;
+      SilcUInt16 argc;
 
       if (!success)
        return;
@@ -1902,7 +1967,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       SilcChannelEntry channel;
       SilcBuffer payload;
       SilcArgumentPayload ban_list;
-      SilcUInt32 argc;
+      SilcUInt16 argc;
 
       if (!success)
        return;
@@ -2165,6 +2230,30 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     }
     break;
 
+  case SILC_COMMAND_CMODE:
+    {
+      SilcChannelEntry channel_entry;
+      SilcBuffer channel_pubkeys;
+
+      channel_entry = va_arg(vp, SilcChannelEntry);
+      (void)va_arg(vp, SilcUInt32);
+      (void)va_arg(vp, SilcPublicKey);
+      channel_pubkeys = va_arg(vp, SilcBuffer);
+
+      if (!success || !cmode_list_chpks ||
+         !channel_entry || !channel_entry->channel_name)
+       return;
+
+      /* Print the channel public key list */
+      if (channel_pubkeys)
+       silc_parse_channel_public_keys(server, channel_entry, channel_pubkeys);
+      else
+       printformat_module("fe-common/silc", server, NULL,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
+                          channel_entry->channel_name);
+    }
+    break;
+
   }
 
   va_end(vp);
index c6cbdb4889ce46b0bc7fb4a4cd4715fee43f8dd1..bf091268d2f2b3dc9a73acc61fed9e367caa84e1 100644 (file)
@@ -1,14 +1,14 @@
 /*
   silc-server.c : irssi
 
-  Copyright (C) 2000 - 2001 Timo Sirainen
-                            Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Copyright (C) 2000 - 2003 Timo Sirainen
+                            Pekka Riikonen <priikone@silcnet.org>
 
   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
@@ -55,13 +55,13 @@ static int silc_send_channel(SILC_SERVER_REC *server,
                              SilcMessageFlags flags)
 {
   SILC_CHANNEL_REC *rec;
-  
+
   rec = silc_channel_find(server, channel);
   if (rec == NULL || rec->entry == NULL) {
     cmd_return_error_value(CMDERR_NOT_JOINED, FALSE);
   }
 
-  silc_client_send_channel_message(silc_client, server->conn, rec->entry, 
+  silc_client_send_channel_message(silc_client, server->conn, rec->entry,
                                   NULL, flags, msg, strlen(msg), TRUE);
   return TRUE;
 }
@@ -89,7 +89,7 @@ static void silc_send_msg_clients(SilcClient client,
   char *nickname = NULL;
 
   if (!clients_count) {
-    printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, 
+    printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
              "%s: There is no such client", rec->nick);
   } else {
     if (clients_count > 1) {
@@ -97,11 +97,11 @@ static void silc_send_msg_clients(SilcClient client,
 
       /* Find the correct one. The rec->nick might be a formatted nick
         so this will find the correct one. */
-      clients = silc_client_get_clients_local(silc_client, server->conn, 
-                                             nickname, rec->nick, 
+      clients = silc_client_get_clients_local(silc_client, server->conn,
+                                             nickname, rec->nick,
                                              &clients_count);
       if (!clients) {
-       printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, 
+       printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
                  "%s: There is no such client", rec->nick);
        silc_free(nickname);
        goto out;
@@ -113,21 +113,21 @@ static void silc_send_msg_clients(SilcClient client,
 
     /* Still check for exact math for nickname, this compares the
        real (formatted) nickname and the nick (maybe formatted) that
-       use gave. This is to assure that `nick' does not match 
+       use gave. This is to assure that `nick' does not match
        `nick@host'. */
     if (strcasecmp(rec->nick, clients[0]->nickname)) {
-      printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, 
+      printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
                "%s: There is no such client", rec->nick);
       goto out;
     }
 
     /* Send the private message */
-    silc_client_send_private_message(client, conn, target, 
+    silc_client_send_private_message(client, conn, target,
                                     rec->flags,
                                     rec->msg, rec->len,
                                     TRUE);
   }
-  
+
  out:
   g_free(rec->nick);
   g_free(rec->msg);
@@ -149,7 +149,7 @@ static int silc_send_msg(SILC_SERVER_REC *server, char *nick, char *msg,
   }
 
   /* Find client entry */
-  clients = silc_client_get_clients_local(silc_client, server->conn, 
+  clients = silc_client_get_clients_local(silc_client, server->conn,
                                          nickname, nick, &clients_count);
   if (!clients) {
     rec = g_new0(PRIVMSG_REC, 1);
@@ -168,7 +168,7 @@ static int silc_send_msg(SILC_SERVER_REC *server, char *nick, char *msg,
 
   /* Send the private message directly */
   silc_free(nickname);
-  silc_client_send_private_message(silc_client, server->conn, 
+  silc_client_send_private_message(silc_client, server->conn,
                                   clients[0], flags,
                                   msg, msg_len, TRUE);
   return TRUE;
@@ -182,11 +182,11 @@ void silc_send_mime(SILC_SERVER_REC *server, WI_ITEM_REC *to,
   QUERY_REC *query;
   char *mime_data;
   int mime_data_len;
-  
-  if (!(IS_SILC_SERVER(server)) || (data == NULL) || (to == NULL) || 
+
+  if (!(IS_SILC_SERVER(server)) || (data == NULL) || (to == NULL) ||
       (enc == NULL) || (type == NULL))
     return;
-           
+
 #define SILC_MIME_HEADER "MIME-Version: 1.0\r\nContent-Type: %s\r\nContent-Transfer-Encoding: %s\r\n\r\n"
 
   mime_data_len = data_len + strlen(SILC_MIME_HEADER) - 4
@@ -204,14 +204,14 @@ void silc_send_mime(SILC_SERVER_REC *server, WI_ITEM_REC *to,
 
   if (IS_SILC_CHANNEL(to)) {
     channel = SILC_CHANNEL(to);
-    silc_client_send_channel_message(silc_client, server->conn, channel->entry, 
+    silc_client_send_channel_message(silc_client, server->conn, channel->entry,
                                     NULL, SILC_MESSAGE_FLAG_DATA,
                                     mime_data, mime_data_len, TRUE);
   } else if (IS_SILC_QUERY(to)) {
     query = SILC_QUERY(to);
     silc_send_msg(server, query->name, mime_data, mime_data_len,
                  SILC_MESSAGE_FLAG_DATA);
-    
+
   }
 
   silc_free(mime_data);
@@ -260,7 +260,7 @@ static void send_message(SILC_SERVER_REC *server, char *target,
   silc_free(message);
 }
 
-void silc_send_heartbeat(SilcSocketConnection sock, 
+void silc_send_heartbeat(SilcSocketConnection sock,
                         void *hb_context)
 {
   SILC_SERVER_REC *server = SILC_SERVER(hb_context);
@@ -349,7 +349,7 @@ SERVER_REC *silc_server_init_connect(SERVER_CONNECT_REC *conn)
   SILC_SERVER_REC *server;
 
   g_return_val_if_fail(IS_SILC_SERVER_CONNECT(conn), NULL);
-  if (conn->address == NULL || *conn->address == '\0') 
+  if (conn->address == NULL || *conn->address == '\0')
     return NULL;
   if (conn->nick == NULL || *conn->nick == '\0') {
     silc_say_error("Cannot connect: nickname is not set");
@@ -361,7 +361,7 @@ SERVER_REC *silc_server_init_connect(SERVER_CONNECT_REC *conn)
   server->connrec = (SILC_SERVER_CONNECT_REC *)conn;
   server_connect_ref(conn);
 
-  if (server->connrec->port <= 0) 
+  if (server->connrec->port <= 0)
     server->connrec->port = 706;
 
   server_connect_init((SERVER_REC *)server);
@@ -377,7 +377,7 @@ void silc_server_connect(SERVER_REC *server)
   }
 }
 
-/* Return a string of all channels in server in server->channels_join() 
+/* Return a string of all channels in server in server->channels_join()
    format */
 
 char *silc_server_get_channels(SILC_SERVER_REC *server)
@@ -391,7 +391,7 @@ char *silc_server_get_channels(SILC_SERVER_REC *server)
   chans = g_string_new(NULL);
   for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
     CHANNEL_REC *channel = tmp->data;
-    
+
     g_string_sprintfa(chans, "%s,", channel->name);
   }
 
@@ -400,7 +400,7 @@ char *silc_server_get_channels(SILC_SERVER_REC *server)
 
   ret = chans->str;
   g_string_free(chans, FALSE);
-  
+
   return ret;
 }
 
@@ -441,7 +441,7 @@ char *silc_server_get_channels(SILC_SERVER_REC *server)
 /* SYNTAX: FILE ACCEPT [<nickname>] */
 /* SYNTAX: FILE CLOSE [<nickname>] */
 /* SYNTAX: FILE */
-/* SYNTAX: JOIN <channel> [<passphrase>] [-cipher <cipher>] [-hmac <hmac>] [-founder] */
+/* SYNTAX: JOIN <channel> [<passphrase>] [-cipher <cipher>] [-hmac <hmac>] [-founder] [-auth [<pubkeyfile> <privkeyfile> [<privkey passphrase>]]]*/
 /* SYNTAX: DETACH */
 /* SYNTAX: WATCH [<-add | -del> <nickname>] */
 /* SYNTAX: STATS */
@@ -507,7 +507,7 @@ static void command_smsg(const char *data, SILC_SERVER_REC *server,
   char *target, *origtarget, *msg;
   void *free_arg;
   int free_ret, target_type;
-  
+
   g_return_if_fail(data != NULL);
   if (server == NULL || !server->connected)
     cmd_param_error(CMDERR_NOT_CONNECTED);
@@ -614,12 +614,12 @@ static void silc_client_file_monitor(SilcClient client,
   if (status == SILC_CLIENT_FILE_MONITOR_ERROR) {
     if (error == SILC_CLIENT_FILE_NO_SUCH_FILE)
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_FILE_ERROR_NO_SUCH_FILE, 
-                        client_entry->nickname, 
+                        SILCTXT_FILE_ERROR_NO_SUCH_FILE,
+                        client_entry->nickname,
                         filepath ? filepath : "[N/A]");
     else if (error == SILC_CLIENT_FILE_PERMISSION_DENIED)
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_FILE_ERROR_PERMISSION_DENIED, 
+                        SILCTXT_FILE_ERROR_PERMISSION_DENIED,
                         client_entry->nickname);
     else
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
@@ -708,7 +708,7 @@ static void silc_client_command_file_get_clients(SilcClient client,
   FileGetClients internal = (FileGetClients)context;
 
   if (!clients) {
-    printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s", 
+    printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
              internal->nick);
     silc_free(internal->data);
     silc_free(internal->nick);
@@ -764,7 +764,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
     if (!strcasecmp(argv[1], "close"))
       type = 3;
   }
-  
+
   if (type == 0)
     cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
 
@@ -779,7 +779,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                         MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[3]);
       goto out;
     }
-    
+
     /* Find client entry */
     entrys = silc_client_get_clients_local(silc_client, conn, nickname,
                                           argv[3], &entry_count);
@@ -813,8 +813,8 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
        do_not_bind = TRUE;
     }
 
-    ret = 
-      silc_client_file_send(silc_client, conn, silc_client_file_monitor, 
+    ret =
+      silc_client_file_send(silc_client, conn, silc_client_file_monitor,
                            server, local_ip, local_port, do_not_bind,
                            client_entry, argv[2], &session_id);
     if (ret == SILC_CLIENT_FILE_OK) {
@@ -838,7 +838,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                           client_entry->nickname);
       if (ret == SILC_CLIENT_FILE_NO_SUCH_FILE)
        printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                          SILCTXT_FILE_ERROR_NO_SUCH_FILE, 
+                          SILCTXT_FILE_ERROR_NO_SUCH_FILE,
                           client_entry->nickname, argv[2]);
     }
 
@@ -852,7 +852,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                           MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
        goto out;
       }
-    
+
       /* Find client entry */
       entrys = silc_client_get_clients_local(silc_client, conn, nickname,
                                             argv[2], &entry_count);
@@ -875,7 +875,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
        goto out;
       }
 
-      ret = silc_client_file_receive(silc_client, conn, 
+      ret = silc_client_file_receive(silc_client, conn,
                                     silc_client_file_monitor, server, NULL,
                                     server->current_session->session_id);
       if (ret != SILC_CLIENT_FILE_OK) {
@@ -895,7 +895,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
     silc_dlist_start(server->ftp_sessions);
     while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
       if (ftp->client_entry == client_entry && !ftp->filepath) {
-       ret = silc_client_file_receive(silc_client, conn, 
+       ret = silc_client_file_receive(silc_client, conn,
                                       silc_client_file_monitor, server,
                                       NULL, ftp->session_id);
        if (ret != SILC_CLIENT_FILE_OK) {
@@ -928,7 +928,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                           MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
        goto out;
       }
-    
+
       /* Find client entry */
       entrys = silc_client_get_clients_local(silc_client, conn, nickname,
                                             argv[2], &entry_count);
@@ -950,8 +950,8 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                           MSGLEVEL_CRAP, SILCTXT_FILE_NA);
        goto out;
       }
-      silc_client_file_close(silc_client, conn, 
+
+      silc_client_file_close(silc_client, conn,
                             server->current_session->session_id);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_FILE_CLOSED,
@@ -1005,7 +1005,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
     while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_FILE_SHOW_LINE,
-                        ftp->client_entry->nickname, 
+                        ftp->client_entry->nickname,
                         ftp->send ? "send" : "receive",
                         (SilcUInt32)(ftp->offset + 1023) / 1024,
                         (SilcUInt32)(ftp->filesize + 1023) / 1024,
index 5a964271658f52abaac40a08af5e8579ef4e0b0a..e030614d70c5210c46ef85ce5e3dccc0d7491888 100644 (file)
@@ -28,7 +28,7 @@ SilcStatus status, ...);
 </tt>
 
 <br />&nbsp;<br />
-The first argument 'client' is the SILC Client Library context, the 'conn' 
+The first argument 'client' is the SILC Client Library context, the 'conn'
 is the context for the connection to the remote server, the 'cmd_payload'
 is the raw SilcCommandPayload and application usually ignores it, the
 'success' boolean value indicates whether the earlier command was a success
@@ -39,7 +39,7 @@ indicates the status of the command reply.  If 'success' is FALSE then
 <br />&nbsp;<br />
 Rest of the arguments are 'command' specific and implementation should
 handle them by the SilcCommand for example in a <tt>switch</tt> statement.
-The commands are defined in lib/silccore/silccomand.h header file.  A short 
+The commands are defined in lib/silccore/silccomand.h header file.  A short
 example:
 
 <br />&nbsp;<br />
@@ -64,10 +64,10 @@ example:
 
 <br />&nbsp;<br />
 The following table describes all commands and arguments that the client
-library sends in the 'command_reply' client operation to the application.  
-By default all arguments that the library sends to application are valid 
-pointers.  However, it is possible that some pointers may be NULL.  If 
-this is the case it is separately mentioned that the argument may be NULL.  
+library sends in the 'command_reply' client operation to the application.
+By default all arguments that the library sends to application are valid
+pointers.  However, it is possible that some pointers may be NULL.  If
+this is the case it is separately mentioned that the argument may be NULL.
 In this case application must ignore that argument.  The 'command_reply'
 arguments per SilcCommand is as follows:
 
@@ -265,9 +265,15 @@ Returns the user mode after changing it.
 <tr>
 <td><small>SILC_COMMAND_CMODE</td>
 <td><small>
-Returns channel's mode after changing it.
+Returns channel's mode after changing it.  Optionally may also return
+founder's public key when it was set.  It may also return the channel
+public key list when the list was altered.  The 'founder_key' and
+'channel_pubkeys' arguments may be NULL.  The 'channel_pubkeys' is an
+Argument List Payload where each argument includes one Public Key
+Payload.
 </td>
-<td width="50%"><small>SilcChannelEntry channel, SilcUInt32 mode
+<td width="50%"><small>SilcChannelEntry channel, SilcUInt32 mode,
+SilcPublicKey founder_key, SilcBuffer channel_pubkeys
 </td>
 </tr>
 
@@ -357,7 +363,7 @@ SilcBuffer client_id_list, SilcBuffer client_mode_list
 <td><small>SILC_COMMAND_GETKEY</td>
 <td><small>
 Returns public key of client or server.  The 'public_key' may be NULL.
-The 'entry_type' is used to check what type of pointer the entry' is.  For 
+The 'entry_type' is used to check what type of pointer the entry' is.  For
 SILC_ID_CLIENT SilcClientEntry and for SILC_ID_SERVER SilcServerEntry.
 </td>
 <td width="50%"><small>SilcIdType entry_type, void *entry,
@@ -368,6 +374,6 @@ SilcPublicKey public_key
 </table>
 
 <br />&nbsp;<br />
-SILC protocol defines some additional commands but command replies to 
+SILC protocol defines some additional commands but command replies to
 those commands are not delivered to the application.  Only the command
 replies listed above are delivered to application.
index ebe124acf2458f8e2a8b1dc377f5cc710d462c88..bcbf0a8496ce5f799ca3a563c3a201ad50ff779f 100644 (file)
@@ -23,12 +23,12 @@ SilcNotifyType type, ...);
 </tt>
 
 <br />&nbsp;<br />
-The first argument 'client' is the SILC Client Library context, the `conn' 
-is the context for the connection to the remote server, and the `type' is 
-the notify type enumeration sent by the server.  Rest of the arguments are 
-`type' specific and implementation should handle them by the 
-SilcNotifyType for example in a <tt>switch</tt> statement.  The notify 
-types are defined in lib/silccore/silcnotify.h header file.  A short 
+The first argument 'client' is the SILC Client Library context, the `conn'
+is the context for the connection to the remote server, and the `type' is
+the notify type enumeration sent by the server.  Rest of the arguments are
+`type' specific and implementation should handle them by the
+SilcNotifyType for example in a <tt>switch</tt> statement.  The notify
+types are defined in lib/silccore/silcnotify.h header file.  A short
 example:
 
 <br />&nbsp;<br />
@@ -52,12 +52,12 @@ example:
 <b>Arguments</b>
 
 <br />&nbsp;<br />
-The following table describes all notify types and arguments that the 
-client library sends in the 'notify' client operation to the application.  
-By default all arguments that the library sends to application are valid 
-pointers.  However, it is possible that some pointers may be NULL.  If 
-this is the case it is separately mentioned that the argument may be NULL.  
-In this case application must ignore that argument.  The SilcNotifyType 
+The following table describes all notify types and arguments that the
+client library sends in the 'notify' client operation to the application.
+By default all arguments that the library sends to application are valid
+pointers.  However, it is possible that some pointers may be NULL.  If
+this is the case it is separately mentioned that the argument may be NULL.
+In this case application must ignore that argument.  The SilcNotifyType
 arguments per notify type is as follows:
 
 <br />&nbsp;<br />
@@ -82,7 +82,7 @@ The 'message' argument may be NULL.
 <tr>
 <td><small>SILC_NOTIFY_TYPE_INVITE</td>
 <td><small>
-Sent to the client if the user is invited on a channel. The 'channel_name' 
+Sent to the client if the user is invited on a channel. The 'channel_name'
 argument may be NULL.
 </td>
 <td width="50%"><small>SilcClientChannel channel, char *channel_name,
@@ -111,9 +111,9 @@ Sent when someone leaves (parts) the channel.
 <tr>
 <td><small>SILC_NOTIFY_TYPE_SIGNOFF</td>
 <td><small>
-Sent when someone signoff the SILC network.  The 'signoff_message' may be 
-NULL.  The 'leaving_client' SilcClientEntry may be incomplete and contain 
-NULL pointers, application must check it's pointers before attempting to 
+Sent when someone signoff the SILC network.  The 'signoff_message' may be
+NULL.  The 'leaving_client' SilcClientEntry may be incomplete and contain
+NULL pointers, application must check it's pointers before attempting to
 display for example nickname information.
 </td>
 <td width="50%"><small>SilcClientEntry signoff_client, char *signoff_message
@@ -124,8 +124,8 @@ display for example nickname information.
 <td><small>SILC_NOTIFY_TYPE_TOPIC_SET</td>
 <td><small>
 Sent when the topic of a channel is set/changed.  The 'setter_id_type'
-is used to check what type of pointer the 'setter_entry' is.  For 
-SILC_ID_CLIENT SilcClientEntry, for SILC_ID_SERVER SilcServerEntry and for 
+is used to check what type of pointer the 'setter_entry' is.  For
+SILC_ID_CLIENT SilcClientEntry, for SILC_ID_SERVER SilcServerEntry and for
 SILC_ID_CHANNEL SilcChannelEntry.
 </td>
 <td width="50%"><small>SilcIdType setter_id_type, void *setter_entry,
@@ -136,9 +136,9 @@ char *topic, SilcChannelEntry channel
 <tr>
 <td><small>SILC_NOTIFY_TYPE_NICK_CHANGE</td>
 <td><small>
-Sent when someone changes their nickname.  The 'old_client_entry' includes 
-the old nickname and the 'new_client_entry' includes the new nickname.  
-Application must understand that the 'old_client_entry' pointer becomes 
+Sent when someone changes their nickname.  The 'old_client_entry' includes
+the old nickname and the 'new_client_entry' includes the new nickname.
+Application must understand that the 'old_client_entry' pointer becomes
 invalid after returning from the function.
 </td>
 <td width="50%"><small>SilcClientEntry old_client_entry,
@@ -150,13 +150,20 @@ SilcClientEntry new_client_entry
 <td><small>SILC_NOTIFY_TYPE_CMODE_CHANGE</td>
 <td><small>
 Sent when channel's mode has changed. The 'changer_id_type'
-is used to check what type of pointer the 'changer_entry' is.  For 
-SILC_ID_CLIENT SilcClientEntry, for SILC_ID_SERVER SilcServerEntry and for 
-SILC_ID_CHANNEL SilcChannelEntry.  The 'mode' is the mode mask after the 
-change.  The 'hmac_name' argument may be NULL.
+is used to check what type of pointer the 'changer_entry' is.  For
+SILC_ID_CLIENT SilcClientEntry, for SILC_ID_SERVER SilcServerEntry and for
+SILC_ID_CHANNEL SilcChannelEntry.  The 'mode' is the mode mask after the
+change.  The `cipher_name' is the cipher set for the channel.
+The `hmac_name' is the HMAC set for the channel.  The `passphrase'
+is the passphrase that was set for the channel.  The `founder_key' is the
+founder's public key when it was set for the channel.  The `channel_pubkeys'
+is an Argument List Payload where each argument is Public Key Payload
+containing one channel public key.  The arguments 'cipher_name', 'hmac_name',
+'passphrase', 'founder_key' and 'channel_pubkeys' may be NULL.
 </td>
 <td width="50%"><small>SilcIdType changer_id_type, void *changer_entry,
-SilcUInt32 mode, NULL, char *hmac_name, SilcChannelEntry channel
+SilcUInt32 mode, char *cipher_name, char *hmac_name, char *passphrase,
+SilcPublicKey founder_key, SilcBuffer channel_pubkeys, SilcChannelEntry channel
 </td>
 </tr>
 
@@ -164,8 +171,8 @@ SilcUInt32 mode, NULL, char *hmac_name, SilcChannelEntry channel
 <td><small>SILC_NOTIFY_TYPE_CUMODE_CHANGE</td>
 <td><small>
 Sent when a users mode on a channel has changed. The 'changer_id_type'
-is used to check what type of pointer the 'changer_entry' is.  For 
-SILC_ID_CLIENT SilcClientEntry, for SILC_ID_SERVER SilcServerEntry and for 
+is used to check what type of pointer the 'changer_entry' is.  For
+SILC_ID_CLIENT SilcClientEntry, for SILC_ID_SERVER SilcServerEntry and for
 SILC_ID_CHANNEL SilcChannelEntry.  The 'mode' is the mode mask after the
 change.  The 'target_client' is the client whose mode was changed.
 </td>
@@ -186,9 +193,9 @@ Message of the Day from the server.
 <tr>
 <td><small>SILC_NOTIFY_TYPE_CHANNEL_CHANGE</td>
 <td><small>
-Sent when a channel's Channel ID changes.  It is possible that channel's 
-ID changes and this notify is sent by the server when this happens.  
-Usually application does not need to handle this notify type and may 
+Sent when a channel's Channel ID changes.  It is possible that channel's
+ID changes and this notify is sent by the server when this happens.
+Usually application does not need to handle this notify type and may
 safely ignore it when received.
 </td>
 <td width="50%"><small>SilcChannelEntry channel
@@ -198,8 +205,8 @@ safely ignore it when received.
 <tr>
 <td><small>SILC_NOTIFY_TYPE_SERVER_SIGNOFF</td>
 <td><small>
-Sent when a server quits the network.  The 'clients' is an array 
-SilcClientEntry pointers of size of 'clients_count'.  Each client in the 
+Sent when a server quits the network.  The 'clients' is an array
+SilcClientEntry pointers of size of 'clients_count'.  Each client in the
 entry is one client signing off from the SILC network.
 </td>
 <td width="50%"><small>NULL, SilcClientEntry *clients, SilcUInt32 clients_count
@@ -209,8 +216,8 @@ entry is one client signing off from the SILC network.
 <tr>
 <td><small>SILC_NOTIFY_TYPE_KICKED</td>
 <td><small>
-Sent when a client (possibly our client) is kicked from a channel.  The 
-'kick_message' may be NULL.  If our client was kicked then 'kicked' is our 
+Sent when a client (possibly our client) is kicked from a channel.  The
+'kick_message' may be NULL.  If our client was kicked then 'kicked' is our
 local SilcClientEntry pointer.
 </td>
 <td width="50%"><small>SilcClientEntry kicked, char *kick_message,
@@ -221,10 +228,10 @@ SilcClientEntry kicker, SilcChannelEntry channel
 <tr>
 <td><small>SILC_NOTIFY_TYPE_KILLED</td>
 <td><small>
-Sent when a client (possibly our client) is killed from the network.  The 
-'kill_message' may be NULL.  If our client was killed then 'killed' is our 
-local SilcClientEntry pointer.  The 'killer_type' is used to check what 
-type of pointer the 'killer' is.  For SILC_ID_CLIENT SilcClientEntry, for 
+Sent when a client (possibly our client) is killed from the network.  The
+'kill_message' may be NULL.  If our client was killed then 'killed' is our
+local SilcClientEntry pointer.  The 'killer_type' is used to check what
+type of pointer the 'killer' is.  For SILC_ID_CLIENT SilcClientEntry, for
 SILC_ID_SERVER SilcServerEntry and for SILC_ID_CHANNEL SilcChannelEntry.
 </td>
 <td width="50%"><small>SilcClientEntry killed, char *kill_message,
@@ -236,7 +243,7 @@ SilcIdType killer_type, void *killer, SilcChannelEntry channel
 <td><small>SILC_NOTIFY_TYPE_ERROR</td>
 <td><small>
 Sent when an error occurs while handling some operation (except command)
-from the client.  Application usually cannot handle this notify type and 
+from the client.  Application usually cannot handle this notify type and
 may safely ignore it.
 </td>
 <td width="50%"><small>SilcStatus error
@@ -246,13 +253,13 @@ may safely ignore it.
 <tr>
 <td><small>SILC_NOTIFY_TYPE_WATCH</td>
 <td><small>
-Sent to notify some status change of a client we are wathing.  The 
-SILC_COMMAND_WATCH is used to manage clients we are wathing and this 
-notify type is used to deliver information about that client.  If the 
-client just changed nickname the 'new_nickname' includes the new nickname.  
-Otherwise this pointer is NULL.  The 'user_mode' is the client's mode in 
-the SILC network.  The 'notification' contains the notify type that 
-happened for the 'watched_client' (for example 
+Sent to notify some status change of a client we are wathing.  The
+SILC_COMMAND_WATCH is used to manage clients we are wathing and this
+notify type is used to deliver information about that client.  If the
+client just changed nickname the 'new_nickname' includes the new nickname.
+Otherwise this pointer is NULL.  The 'user_mode' is the client's mode in
+the SILC network.  The 'notification' contains the notify type that
+happened for the 'watched_client' (for example
 SILC_NOTIFY_TYPE_NICK_CHANGE if the client changed their nickname).
 </td>
 <td width="50%"><small>SilcClientEntry watched_client, char *new_nickname,
@@ -263,7 +270,7 @@ SilcUInt32 user_mode, SilcNotifyType notification
 </table>
 
 <br />&nbsp;<br />
-SILC protocol defines some additional notify types but those notify types 
-are not delivered to the application.  Some of those notify types are only 
-delivered between servers and routers and clients never receive them.  
+SILC protocol defines some additional notify types but those notify types
+are not delivered to the application.  Some of those notify types are only
+delivered between servers and routers and clients never receive them.
 Only the notify types listed above are delivered to application.
index 311dbdd1d13b0f613d2e867d6d1498f5d7993322..8b98b2ffb59d29b2e530f192b12635cb028adbe9 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  client_notify.c 
+  client_notify.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
@@ -33,7 +33,7 @@ typedef struct {
 } *SilcClientNotifyResolve;
 
 SILC_TASK_CALLBACK(silc_client_notify_check_client)
-{ 
+{
   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
   SilcClient client = res->context;
   SilcClientConnection conn = res->sock->user_data;
@@ -67,7 +67,7 @@ SILC_TASK_CALLBACK(silc_client_notify_del_client_cb)
 static void silc_client_notify_by_server_pending(void *context, void *context2)
 {
   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
-  SilcClientCommandReplyContext reply = 
+  SilcClientCommandReplyContext reply =
     (SilcClientCommandReplyContext)context2;
 
   SILC_LOG_DEBUG(("Start"));
@@ -122,7 +122,7 @@ static void silc_client_channel_set_wait(SilcClient client,
   }
 }
 
-/* Attaches to the channel's resolving cmd ident and calls the 
+/* Attaches to the channel's resolving cmd ident and calls the
    notify handling with `packet' after it's received. */
 
 static void silc_client_channel_wait(SilcClient client,
@@ -173,7 +173,7 @@ static void silc_client_notify_by_server_resolve(SilcClient client,
     silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
                                 silc_client_command_reply_identify_i, 0,
                                 ++conn->cmd_ident);
-    silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, 
+    silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
                             conn->cmd_ident, 1, 5, idp->data, idp->len);
     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
                                silc_client_notify_by_server_pending, res);
@@ -220,16 +220,16 @@ void silc_client_notify_by_server(SilcClient client,
   switch(type) {
   case SILC_NOTIFY_TYPE_NONE:
     /* Notify application */
-    client->internal->ops->notify(client, conn, type, 
+    client->internal->ops->notify(client, conn, type,
                                  silc_argument_get_arg_type(args, 1, NULL));
     break;
 
   case SILC_NOTIFY_TYPE_INVITE:
-    /* 
+    /*
      * Someone invited me to a channel. Find Client and Channel entries
      * for the application.
      */
-    
+
     SILC_LOG_DEBUG(("Notify: INVITE"));
 
     /* Get Channel ID */
@@ -256,7 +256,7 @@ void silc_client_notify_by_server(SilcClient client,
     /* Find Client entry and if not found query it */
     client_entry = silc_client_get_client_by_id(client, conn, client_id);
     if (!client_entry) {
-      silc_client_notify_by_server_resolve(client, conn, packet, 
+      silc_client_notify_by_server_resolve(client, conn, packet,
                                           SILC_ID_CLIENT, client_id);
       goto out;
     }
@@ -267,7 +267,7 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Notify application */
-    client->internal->ops->notify(client, conn, type, channel, tmp, 
+    client->internal->ops->notify(client, conn, type, channel, tmp,
                                  client_entry);
     break;
 
@@ -307,7 +307,7 @@ void silc_client_notify_by_server(SilcClient client,
     if (!client_entry) {
       silc_client_channel_set_wait(client, conn, channel,
                                   conn->cmd_ident + 1);
-      silc_client_notify_by_server_resolve(client, conn, packet, 
+      silc_client_notify_by_server_resolve(client, conn, packet,
                                           SILC_ID_CLIENT, client_id);
       goto out;
     }
@@ -320,7 +320,7 @@ void silc_client_notify_by_server(SilcClient client,
        res->packet = silc_packet_context_dup(packet);
        res->context = client;
        res->sock = silc_socket_dup(conn->sock);
-       silc_client_command_pending(conn, SILC_COMMAND_NONE, 
+       silc_client_command_pending(conn, SILC_COMMAND_NONE,
                                    client_entry->resolve_cmd_ident,
                                    silc_client_notify_by_server_pending,
                                    res);
@@ -330,7 +330,7 @@ void silc_client_notify_by_server(SilcClient client,
       /* Do new resolving */
       silc_client_channel_set_wait(client, conn, channel,
                                   conn->cmd_ident + 1);
-      silc_client_notify_by_server_resolve(client, conn, packet, 
+      silc_client_notify_by_server_resolve(client, conn, packet,
                                           SILC_ID_CLIENT, client_id);
       client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
       client_entry->resolve_cmd_ident = conn->cmd_ident;
@@ -366,7 +366,7 @@ void silc_client_notify_by_server(SilcClient client,
      * Someone has left a channel. We will remove it from the channel but
      * we'll keep it in the cache in case we'll need it later.
      */
-    
+
     SILC_LOG_DEBUG(("Notify: LEAVE"));
 
     /* Get Client ID */
@@ -379,7 +379,7 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Find Client entry */
-    client_entry = 
+    client_entry =
       silc_client_get_client_by_id(client, conn, client_id);
     if (!client_entry)
       goto out;
@@ -402,7 +402,7 @@ void silc_client_notify_by_server(SilcClient client,
     }
 
     /* Some client implementations actually quit network by first doing
-       LEAVE and then immediately SIGNOFF.  We'll check for this by doing 
+       LEAVE and then immediately SIGNOFF.  We'll check for this by doing
        check for the client after 5 - 34 seconds.  If it is not valid after
        that we'll remove the client from cache. */
     if (!silc_hash_table_count(client_entry->channels)) {
@@ -439,7 +439,7 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Find Client entry */
-    client_entry = 
+    client_entry =
       silc_client_get_client_by_id(client, conn, client_id);
     if (!client_entry)
       goto out;
@@ -494,7 +494,7 @@ void silc_client_notify_by_server(SilcClient client,
       if (!client_entry) {
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CLIENT, client_id);
        goto out;
       }
@@ -505,7 +505,7 @@ void silc_client_notify_by_server(SilcClient client,
       if (!server) {
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_SERVER, server_id);
        server = silc_client_add_server(client, conn, NULL, NULL, server_id);
        if (!server)
@@ -522,12 +522,12 @@ void silc_client_notify_by_server(SilcClient client,
        res->packet = silc_packet_context_dup(packet);
        res->context = client;
        res->sock = silc_socket_dup(conn->sock);
-       silc_client_command_pending(conn, SILC_COMMAND_NONE, 
+       silc_client_command_pending(conn, SILC_COMMAND_NONE,
                                    server->resolve_cmd_ident,
                                    silc_client_notify_by_server_pending, res);
        goto out;
       }
-      
+
       /* Save the pointer to the client_entry pointer */
       client_entry = (SilcClientEntry)server;
     } else {
@@ -539,7 +539,7 @@ void silc_client_notify_by_server(SilcClient client,
       if (!client_entry) {
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CHANNEL, channel_id);
        goto out;
       }
@@ -568,7 +568,7 @@ void silc_client_notify_by_server(SilcClient client,
     /*
      * Someone changed their nickname. If we don't have entry for the new
      * ID we will query it and return here after it's done. After we've
-     * returned we fetch the old entry and free it and notify the 
+     * returned we fetch the old entry and free it and notify the
      * application.
      */
 
@@ -600,7 +600,7 @@ void silc_client_notify_by_server(SilcClient client,
       res->packet = silc_packet_context_dup(packet);
       res->context = client;
       res->sock = silc_socket_dup(conn->sock);
-      silc_client_command_pending(conn, SILC_COMMAND_NONE, 
+      silc_client_command_pending(conn, SILC_COMMAND_NONE,
                                  client_entry->resolve_cmd_ident,
                                  silc_client_notify_by_server_pending, res);
       goto out;
@@ -636,16 +636,16 @@ void silc_client_notify_by_server(SilcClient client,
                       client_entry->id, client_entry, 0, NULL);
 
       /* Notify application */
-      client->internal->ops->notify(client, conn, type, 
+      client->internal->ops->notify(client, conn, type,
                                    client_entry, client_entry);
       break;
     }
 
     /* Create new client entry, and save all old information with the
        new nickname and client ID */
-    client_entry2 = silc_client_add_client(client, conn, NULL, NULL, 
+    client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
                                           client_entry->realname,
-                                          silc_id_dup(client_id, 
+                                          silc_id_dup(client_id,
                                                       SILC_ID_CLIENT), 0);
     if (!client_entry2)
       goto out;
@@ -665,166 +665,195 @@ void silc_client_notify_by_server(SilcClient client,
 
     /* Remove the old from cache */
     silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
-    
+
     /* Replace old ID entry with new one on all channels. */
     silc_client_replace_from_channels(client, conn, client_entry,
                                      client_entry2);
 
     /* Notify application */
-    client->internal->ops->notify(client, conn, type, 
+    client->internal->ops->notify(client, conn, type,
                                  client_entry, client_entry2);
-    
+
     /* Free old client entry */
     silc_client_del_client_entry(client, conn, client_entry);
 
     break;
 
   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
-    /*
-     * Someone changed a channel mode
-     */
+    {
+      /*
+       * Someone changed a channel mode
+       */
+      char *passphrase, *cipher, *hmac;
+      SilcPublicKey founder_key = NULL;
+      SilcBufferStruct chpks;
 
-    SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
+      SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
 
-    /* Get channel entry */
-    channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
-                               SILC_ID_CHANNEL);
-    if (!channel_id)
-      goto out;
-    channel = silc_client_get_channel_by_id(client, conn, channel_id);
-    if (!channel)
-      goto out;
+      /* Get channel entry */
+      channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                                 SILC_ID_CHANNEL);
+      if (!channel_id)
+       goto out;
+      channel = silc_client_get_channel_by_id(client, conn, channel_id);
+      if (!channel)
+       goto out;
 
-    /* Get ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp)
-      goto out;
-    id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
-    if (!id)
-      goto out;
+      /* Get ID */
+      tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+      if (!tmp)
+       goto out;
+      id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
+      if (!id)
+       goto out;
 
-    /* Find Client entry */
-    if (id_type == SILC_ID_CLIENT) {
       /* Find Client entry */
-      client_id = id;
-      client_entry = silc_client_get_client_by_id(client, conn, client_id);
-      if (!client_entry) {
-       silc_client_channel_set_wait(client, conn, channel,
-                                    conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
-                                            SILC_ID_CLIENT, client_id);
-       goto out;
-      }
+      if (id_type == SILC_ID_CLIENT) {
+       /* Find Client entry */
+       client_id = id;
+       client_entry = silc_client_get_client_by_id(client, conn, client_id);
+       if (!client_entry) {
+         silc_client_channel_set_wait(client, conn, channel,
+                                      conn->cmd_ident + 1);
+         silc_client_notify_by_server_resolve(client, conn, packet,
+                                              SILC_ID_CLIENT, client_id);
+         goto out;
+       }
 
-      if (!client_entry->nickname) {
-       if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
-         /* Attach to existing resolving */
+       if (!client_entry->nickname) {
+         if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+           /* Attach to existing resolving */
+           SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+           res->packet = silc_packet_context_dup(packet);
+           res->context = client;
+           res->sock = silc_socket_dup(conn->sock);
+           silc_client_command_pending(conn, SILC_COMMAND_NONE,
+                                       client_entry->resolve_cmd_ident,
+                                       silc_client_notify_by_server_pending,
+                                       res);
+           goto out;
+         }
+
+         /* Do new resolving */
+         silc_client_channel_set_wait(client, conn, channel,
+                                      conn->cmd_ident + 1);
+         silc_client_notify_by_server_resolve(client, conn, packet,
+                                              SILC_ID_CLIENT, client_id);
+         client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+         client_entry->resolve_cmd_ident = conn->cmd_ident;
+         goto out;
+       }
+      } else if (id_type == SILC_ID_SERVER) {
+       /* Find Server entry */
+       server_id = id;
+       server = silc_client_get_server_by_id(client, conn, server_id);
+       if (!server) {
+         silc_client_channel_set_wait(client, conn, channel,
+                                      conn->cmd_ident + 1);
+         silc_client_notify_by_server_resolve(client, conn, packet,
+                                              SILC_ID_SERVER, server_id);
+         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
+         if (!server)
+           goto out;
+
+         server->resolve_cmd_ident = conn->cmd_ident;
+         server_id = NULL;
+         goto out;
+       }
+
+       /* If entry being resoled, wait for it before processing this notify */
+       if (server->resolve_cmd_ident) {
          SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
          res->packet = silc_packet_context_dup(packet);
          res->context = client;
          res->sock = silc_socket_dup(conn->sock);
-         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
-                                     client_entry->resolve_cmd_ident,
+         silc_client_command_pending(conn, SILC_COMMAND_NONE,
+                                     server->resolve_cmd_ident,
                                      silc_client_notify_by_server_pending,
                                      res);
          goto out;
        }
 
-       /* Do new resolving */
-       silc_client_channel_set_wait(client, conn, channel,
-                                    conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
-                                            SILC_ID_CLIENT, client_id);
-        client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
-        client_entry->resolve_cmd_ident = conn->cmd_ident;
-       goto out;
-      }
-    } else if (id_type == SILC_ID_SERVER) {
-      /* Find Server entry */
-      server_id = id;
-      server = silc_client_get_server_by_id(client, conn, server_id);
-      if (!server) {
-       silc_client_channel_set_wait(client, conn, channel,
-                                    conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
-                                            SILC_ID_SERVER, server_id);
-       server = silc_client_add_server(client, conn, NULL, NULL, server_id);
-       if (!server)
+       /* Save the pointer to the client_entry pointer */
+       client_entry = (SilcClientEntry)server;
+      } else {
+       /* Find Channel entry */
+       silc_free(channel_id);
+       channel_id = id;
+       client_entry = (SilcClientEntry)
+         silc_client_get_channel_by_id(client, conn, channel_id);
+       if (!client_entry) {
+         silc_client_channel_set_wait(client, conn, channel,
+                                      conn->cmd_ident + 1);
+         silc_client_notify_by_server_resolve(client, conn, packet,
+                                              SILC_ID_CHANNEL, channel_id);
          goto out;
-
-       server->resolve_cmd_ident = conn->cmd_ident;
-       server_id = NULL;
-       goto out;
+       }
       }
 
-      /* If entry being resoled, wait for it before processing this notify */
-      if (server->resolve_cmd_ident) {
-       SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
-       res->packet = silc_packet_context_dup(packet);
-       res->context = client;
-       res->sock = silc_socket_dup(conn->sock);
-       silc_client_command_pending(conn, SILC_COMMAND_NONE, 
-                                   server->resolve_cmd_ident,
-                                   silc_client_notify_by_server_pending, res);
+      /* Get the mode */
+      tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+      if (!tmp)
        goto out;
-      }
-      
-      /* Save the pointer to the client_entry pointer */
-      client_entry = (SilcClientEntry)server;
-    } else {
-      /* Find Channel entry */
-      silc_free(channel_id);
-      channel_id = id;
-      client_entry = (SilcClientEntry)
-       silc_client_get_channel_by_id(client, conn, channel_id);
-      if (!client_entry) {
-       silc_client_channel_set_wait(client, conn, channel,
-                                    conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
-                                            SILC_ID_CHANNEL, channel_id);
+
+      SILC_GET32_MSB(mode, tmp);
+
+      /* If information is being resolved for this channel, wait for it */
+      if (channel->resolve_cmd_ident) {
+       silc_client_channel_wait(client, conn, channel, packet);
        goto out;
       }
-    }
 
-    /* Get the mode */
-    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-    if (!tmp)
-      goto out;
+      /* Save the new mode */
+      channel->mode = mode;
 
-    SILC_GET32_MSB(mode, tmp);
+      /* Get the cipher */
+      cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
 
-    /* If information is being resolved for this channel, wait for it */
-    if (channel->resolve_cmd_ident) {
-      silc_client_channel_wait(client, conn, channel, packet);
-      goto out;
-    }
+      /* Get the hmac */
+      hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
+      if (hmac) {
+       unsigned char hash[32];
+
+       if (channel->hmac)
+         silc_hmac_free(channel->hmac);
+       if (!silc_hmac_alloc(hmac, NULL, &channel->hmac))
+         goto out;
 
-    /* Save the new mode */
-    channel->mode = mode;
+       silc_hash_make(silc_hmac_get_hash(channel->hmac),
+                      channel->key, channel->key_len / 8,
+                      hash);
+       silc_hmac_set_key(channel->hmac, hash,
+                         silc_hash_len(silc_hmac_get_hash(channel->hmac)));
+       memset(hash, 0, sizeof(hash));
+      }
 
-    /* Get the hmac */
-    tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
-    if (tmp) {
-      unsigned char hash[32];
+      /* Get the passphrase if it was set */
+      passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
 
-      if (channel->hmac)
-       silc_hmac_free(channel->hmac);
-      if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
-       goto out;
+      /* Get the channel founder key if it was set */
+      tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
+      if (tmp) {
+       if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key))
+         founder_key = NULL;
+      }
 
-      silc_hash_make(silc_hmac_get_hash(channel->hmac), 
-                    channel->key, channel->key_len / 8,
-                    hash);
-      silc_hmac_set_key(channel->hmac, hash, 
-                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
-      memset(hash, 0, sizeof(hash));
+      /* Get the channel public key that was added or removed */
+      tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
+      if (tmp)
+       silc_buffer_set(&chpks, tmp, tmp_len);
+
+      /* Notify application. The channel entry is sent last as this notify
+        is for channel but application don't know it from the arguments
+        sent by server. */
+      client->internal->ops->notify(client, conn, type, id_type,
+                                   client_entry, mode, cipher, hmac,
+                                   passphrase, founder_key,
+                                   tmp ? &chpks : NULL, channel);
+
+      if (founder_key)
+       silc_pkcs_public_key_free(founder_key);
     }
-
-    /* Notify application. The channel entry is sent last as this notify
-       is for channel but application don't know it from the arguments
-       sent by server. */
-    client->internal->ops->notify(client, conn, type, id_type,
-                                 client_entry, mode, NULL, tmp, channel);
     break;
 
   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
@@ -859,7 +888,7 @@ void silc_client_notify_by_server(SilcClient client,
       if (!client_entry) {
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CLIENT, client_id);
        goto out;
       }
@@ -871,7 +900,7 @@ void silc_client_notify_by_server(SilcClient client,
          res->packet = silc_packet_context_dup(packet);
          res->context = client;
          res->sock = silc_socket_dup(conn->sock);
-         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
+         silc_client_command_pending(conn, SILC_COMMAND_NONE,
                                      client_entry->resolve_cmd_ident,
                                      silc_client_notify_by_server_pending,
                                      res);
@@ -881,7 +910,7 @@ void silc_client_notify_by_server(SilcClient client,
        /* Do new resolving */
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CLIENT, client_id);
         client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
         client_entry->resolve_cmd_ident = conn->cmd_ident;
@@ -894,7 +923,7 @@ void silc_client_notify_by_server(SilcClient client,
       if (!server) {
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_SERVER, server_id);
        server = silc_client_add_server(client, conn, NULL, NULL, server_id);
        if (!server)
@@ -911,7 +940,7 @@ void silc_client_notify_by_server(SilcClient client,
        res->packet = silc_packet_context_dup(packet);
        res->context = client;
        res->sock = silc_socket_dup(conn->sock);
-       silc_client_command_pending(conn, SILC_COMMAND_NONE, 
+       silc_client_command_pending(conn, SILC_COMMAND_NONE,
                                    server->resolve_cmd_ident,
                                    silc_client_notify_by_server_pending, res);
        goto out;
@@ -928,7 +957,7 @@ void silc_client_notify_by_server(SilcClient client,
       if (!client_entry) {
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CHANNEL, channel_id);
        goto out;
       }
@@ -958,10 +987,10 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Find target Client entry */
-    client_entry2 = 
+    client_entry2 =
       silc_client_get_client_by_id(client, conn, client_id);
     if (!client_entry2) {
-      silc_client_notify_by_server_resolve(client, conn, packet, 
+      silc_client_notify_by_server_resolve(client, conn, packet,
                                           SILC_ID_CLIENT, client_id);
       goto out;
     }
@@ -975,7 +1004,7 @@ void silc_client_notify_by_server(SilcClient client,
        is for channel but application don't know it from the arguments
        sent by server. */
     client->internal->ops->notify(client, conn, type,
-                                 id_type, client_entry, mode, 
+                                 id_type, client_entry, mode,
                                  client_entry2, channel);
     break;
 
@@ -990,7 +1019,7 @@ void silc_client_notify_by_server(SilcClient client,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    
+
     /* Notify application */
     client->internal->ops->notify(client, conn, type, tmp);
     break;
@@ -1076,7 +1105,7 @@ void silc_client_notify_by_server(SilcClient client,
       /* Find kicker's client entry and if not found resolve it */
       client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
       if (!client_entry2) {
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CLIENT, client_id);
        goto out;
       } else {
@@ -1091,7 +1120,7 @@ void silc_client_notify_by_server(SilcClient client,
     /* Notify application. The channel entry is sent last as this notify
        is for channel but application don't know it from the arguments
        sent by server. */
-    client->internal->ops->notify(client, conn, type, client_entry, tmp, 
+    client->internal->ops->notify(client, conn, type, client_entry, tmp,
                                  client_entry2, channel);
 
     /* Remove kicked client from channel */
@@ -1161,10 +1190,10 @@ void silc_client_notify_by_server(SilcClient client,
        if (id_type == SILC_ID_CLIENT) {
          /* Find Client entry */
          client_id = id;
-         client_entry2 = silc_client_get_client_by_id(client, conn, 
+         client_entry2 = silc_client_get_client_by_id(client, conn,
                                                       client_id);
          if (!client_entry) {
-           silc_client_notify_by_server_resolve(client, conn, packet, 
+           silc_client_notify_by_server_resolve(client, conn, packet,
                                                 SILC_ID_CLIENT, client_id);
            goto out;
          }
@@ -1173,7 +1202,7 @@ void silc_client_notify_by_server(SilcClient client,
          server_id = id;
          server = silc_client_get_server_by_id(client, conn, server_id);
          if (!server) {
-           silc_client_notify_by_server_resolve(client, conn, packet, 
+           silc_client_notify_by_server_resolve(client, conn, packet,
                                                 SILC_ID_SERVER, server_id);
            server = silc_client_add_server(client, conn, NULL, NULL,
                                            server_id);
@@ -1190,13 +1219,13 @@ void silc_client_notify_by_server(SilcClient client,
            res->packet = silc_packet_context_dup(packet);
            res->context = client;
            res->sock = silc_socket_dup(conn->sock);
-           silc_client_command_pending(conn, SILC_COMMAND_NONE, 
+           silc_client_command_pending(conn, SILC_COMMAND_NONE,
                                        server->resolve_cmd_ident,
                                        silc_client_notify_by_server_pending,
                                        res);
            goto out;
          }
-      
+
          /* Save the pointer to the client_entry pointer */
          client_entry2 = (SilcClientEntry)server;
        } else {
@@ -1204,11 +1233,11 @@ void silc_client_notify_by_server(SilcClient client,
          channel_id = id;
          channel = silc_client_get_channel_by_id(client, conn, channel_id);
          if (!channel) {
-           silc_client_notify_by_server_resolve(client, conn, packet, 
+           silc_client_notify_by_server_resolve(client, conn, packet,
                                                 SILC_ID_CHANNEL, channel_id);
            goto out;
          }
-         
+
          /* Save the pointer to the client_entry pointer */
          client_entry2 = (SilcClientEntry)channel;
          silc_free(channel_id);
@@ -1217,7 +1246,7 @@ void silc_client_notify_by_server(SilcClient client,
       }
 
       /* Notify application. */
-      client->internal->ops->notify(client, conn, type, client_entry, 
+      client->internal->ops->notify(client, conn, type, client_entry,
                                    comment, id_type, client_entry2);
 
       if (client_entry != conn->local_entry)
@@ -1225,7 +1254,7 @@ void silc_client_notify_by_server(SilcClient client,
        silc_client_del_client(client, conn, client_entry);
     }
     break;
-    
+
   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
     {
       /*
@@ -1245,11 +1274,11 @@ void silc_client_notify_by_server(SilcClient client,
          client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
          if (!client_id)
            goto out;
-         
+
          /* Get the client entry */
          client_entry = silc_client_get_client_by_id(client, conn, client_id);
          if (client_entry) {
-           clients = silc_realloc(clients, sizeof(*clients) * 
+           clients = silc_realloc(clients, sizeof(*clients) *
                                   (clients_count + 1));
            clients[clients_count] = client_entry;
            clients_count++;
@@ -1262,7 +1291,7 @@ void silc_client_notify_by_server(SilcClient client,
       /* Notify application. We don't keep server entries so the server
         entry is returned as NULL. The client's are returned as array
         of SilcClientEntry pointers. */
-      client->internal->ops->notify(client, conn, type, NULL, 
+      client->internal->ops->notify(client, conn, type, NULL,
                                    clients, clients_count);
 
       for (i = 0; i < clients_count; i++) {
@@ -1332,7 +1361,7 @@ void silc_client_notify_by_server(SilcClient client,
       /* Find Client entry and if not found query it */
       client_entry = silc_client_get_client_by_id(client, conn, client_id);
       if (!client_entry) {
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CLIENT, client_id);
        goto out;
       }
index 40e1d2566f0eb7c3dbbc510ee7d56e026a5e1e00..4796c3bce389a51e59309cf72cd63c05b4a306c9 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  command.c 
+  command.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
@@ -26,7 +26,7 @@
   x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
           "You are not connected to a server, use /SERVER to connect");
 
-/* Command operation that is called at the end of all commands. 
+/* Command operation that is called at the end of all commands.
    Usage: COMMAND(status); */
 #define COMMAND(status) cmd->client->internal->ops->command(cmd->client, \
   cmd->conn, cmd, TRUE, cmd->command->cmd, (status))
@@ -53,8 +53,8 @@ void silc_client_command_send(SilcClient client, SilcClientConnection conn,
   va_start(ap, argc);
 
   packet = silc_command_payload_encode_vap(command, ident, argc, ap);
-  silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, 
-                         NULL, 0, NULL, NULL, packet->data, 
+  silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
+                         NULL, 0, NULL, NULL, packet->data,
                          packet->len, TRUE);
   silc_buffer_free(packet);
 }
@@ -147,7 +147,7 @@ bool silc_client_command_call(SilcClient client,
   ctx->argv = argv;
   ctx->argv_lens = argv_lens;
   ctx->argv_types = argv_types;
-  
+
   /* Call the command */
   cmd->command(ctx, NULL);
 
@@ -211,7 +211,7 @@ void silc_client_command_pending_del(SilcClientConnection conn,
 SilcClientCommandPendingCallbacks
 silc_client_command_pending_check(SilcClientConnection conn,
                                  SilcClientCommandReplyContext ctx,
-                                 SilcCommand command, 
+                                 SilcCommand command,
                                  SilcUInt16 ident,
                                  SilcUInt32 *callbacks_count)
 {
@@ -276,7 +276,7 @@ SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
   return ctx;
 }
 
-/* Command WHOIS. This command is used to query information about 
+/* Command WHOIS. This command is used to query information about
    specific user. */
 
 SILC_CLIENT_CMD_FUNC(whois)
@@ -295,7 +295,7 @@ SILC_CLIENT_CMD_FUNC(whois)
   /* Given without arguments fetches client's own information */
   if (cmd->argc < 2) {
     buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
-    silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS, 
+    silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
                             ++conn->cmd_ident,
                             1, 4, buffer->data, buffer->len);
     silc_buffer_free(buffer);
@@ -305,7 +305,7 @@ SILC_CLIENT_CMD_FUNC(whois)
   if (cmd->argc == 2) {
     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
                                            ++conn->cmd_ident, 1,
-                                           1, cmd->argv[1], 
+                                           1, cmd->argv[1],
                                            cmd->argv_lens[1]);
   } else {
     if (!strcasecmp(cmd->argv[2], "-details"))
@@ -353,7 +353,7 @@ SILC_CLIENT_CMD_FUNC(whowas)
   }
 
   if (cmd->argc < 2 || cmd->argc > 3) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
     COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
                   SILC_STATUS_ERR_TOO_MANY_PARAMS));
@@ -363,7 +363,7 @@ SILC_CLIENT_CMD_FUNC(whowas)
   if (cmd->argc == 2) {
     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
                                            ++conn->cmd_ident, 1,
-                                           1, cmd->argv[1], 
+                                           1, cmd->argv[1],
                                            cmd->argv_lens[1]);
   } else {
     int c = atoi(cmd->argv[2]);
@@ -386,8 +386,8 @@ SILC_CLIENT_CMD_FUNC(whowas)
   silc_client_command_free(cmd);
 }
 
-/* Command IDENTIFY. This command is used to query information about 
-   specific user, especially ID's. 
+/* Command IDENTIFY. This command is used to query information about
+   specific user, especially ID's.
 
    NOTE: This command is used only internally by the client library
    and application MUST NOT call this command directly. */
@@ -409,7 +409,7 @@ SILC_CLIENT_CMD_FUNC(identify)
     goto out;
 
   if (cmd->argc == 2) {
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
                                            ++conn->cmd_ident, 1,
                                            1, cmd->argv[1],
                                            cmd->argv_lens[1]);
@@ -417,7 +417,7 @@ SILC_CLIENT_CMD_FUNC(identify)
     int c = atoi(cmd->argv[2]);
     memset(count, 0, sizeof(count));
     SILC_PUT32_MSB(c, count);
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
                                            ++conn->cmd_ident, 2,
                                            1, cmd->argv[1],
                                            cmd->argv_lens[1],
@@ -449,7 +449,7 @@ SILC_CLIENT_CMD_FUNC(nick)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /NICK <nickname>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -461,11 +461,11 @@ SILC_CLIENT_CMD_FUNC(nick)
   /* Show current nickname */
   if (cmd->argc < 2) {
     if (cmd->conn) {
-      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
-         "Your nickname is %s on server %s", 
+      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+         "Your nickname is %s on server %s",
          conn->nickname, conn->remote_host);
     } else {
-      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
          "Your nickname is %s", conn->nickname);
     }
 
@@ -479,7 +479,7 @@ SILC_CLIENT_CMD_FUNC(nick)
   /* Send the NICK command */
   buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
                                       &cmd->argv[1],
-                                      &cmd->argv_lens[1], 
+                                      &cmd->argv_lens[1],
                                       &cmd->argv_types[1],
                                       ++cmd->conn->cmd_ident);
   silc_client_packet_send(cmd->client, cmd->conn->sock,
@@ -520,10 +520,10 @@ SILC_CLIENT_CMD_FUNC(list)
   }
 
   if (!idp)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
                                            ++conn->cmd_ident, 0);
   else
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
                                            ++conn->cmd_ident, 1,
                                            1, idp->data, idp->len);
 
@@ -593,16 +593,16 @@ SILC_CLIENT_CMD_FUNC(topic)
   /* Send TOPIC command to the server */
   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
   if (cmd->argc > 2)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 
-                                           ++conn->cmd_ident, 2, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
+                                           ++conn->cmd_ident, 2,
                                            1, idp->data, idp->len,
-                                           2, cmd->argv[2], 
+                                           2, cmd->argv[2],
                                            strlen(cmd->argv[2]));
   else
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
                                            ++conn->cmd_ident, 1,
                                            1, idp->data, idp->len);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
@@ -670,19 +670,19 @@ SILC_CLIENT_CMD_FUNC(invite)
        nickname = strdup(cmd->argv[2]);
 
       /* Find client entry */
-      client_entry = silc_idlist_get_client(client, conn, nickname, 
+      client_entry = silc_idlist_get_client(client, conn, nickname,
                                            cmd->argv[2], TRUE);
       if (!client_entry) {
        if (cmd->pending) {
          COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
          goto out;
        }
-      
+
        /* Client entry not found, it was requested thus mark this to be
           pending command. */
-       silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
+       silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
                                    conn->cmd_ident,
-                                   silc_client_command_invite, 
+                                   silc_client_command_invite,
                                    silc_client_command_dup(cmd));
        cmd->pending = 1;
        goto out;
@@ -724,7 +724,7 @@ SILC_CLIENT_CMD_FUNC(invite)
   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
   if (client_entry) {
     clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
                                            ++conn->cmd_ident, 4,
                                            1, chidp->data, chidp->len,
                                            2, clidp->data, clidp->len,
@@ -734,7 +734,7 @@ SILC_CLIENT_CMD_FUNC(invite)
                                            args ? args->len : 0);
     silc_buffer_free(clidp);
   } else {
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
                                            ++conn->cmd_ident, 3,
                                            1, chidp->data, chidp->len,
                                            3, args ? action : NULL,
@@ -743,7 +743,7 @@ SILC_CLIENT_CMD_FUNC(invite)
                                            args ? args->len : 0);
   }
 
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
@@ -774,7 +774,7 @@ SILC_TASK_CALLBACK(silc_client_command_quit_cb)
 }
 
 /* Command QUIT. Closes connection with current server. */
+
 SILC_CLIENT_CMD_FUNC(quit)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
@@ -788,14 +788,14 @@ SILC_CLIENT_CMD_FUNC(quit)
   }
 
   if (cmd->argc > 1)
-    buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1, 
+    buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
                                         &cmd->argv[1], &cmd->argv_lens[1],
                                         &cmd->argv_types[1], 0);
   else
     buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
                                         NULL, NULL, NULL, 0);
-  silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND, 
-                         NULL, 0, NULL, NULL, 
+  silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
+                         NULL, 0, NULL, NULL,
                          buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
 
@@ -827,7 +827,7 @@ SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
   SilcClientConnection conn = cmd->conn;
   SilcClientEntry target;
   char *nickname = NULL;
-  
+
   /* Parse the typed nickname. */
   if (client->internal->params->nickname_parse)
     client->internal->params->nickname_parse(cmd->argv[1], &nickname);
@@ -835,7 +835,7 @@ SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
     nickname = strdup(cmd->argv[1]);
 
   /* Get the target client */
-  target = silc_idlist_get_client(cmd->client, conn, nickname, 
+  target = silc_idlist_get_client(cmd->client, conn, nickname,
                                  cmd->argv[1], FALSE);
   if (target)
     /* Remove the client from all channels and free it */
@@ -851,7 +851,7 @@ SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
 SILC_CLIENT_CMD_FUNC(kill_remove)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
-  SilcClientCommandReplyContext reply = 
+  SilcClientCommandReplyContext reply =
     (SilcClientCommandReplyContext)context2;
   SilcStatus status;
 
@@ -886,7 +886,7 @@ SILC_CLIENT_CMD_FUNC(kill)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /KILL <nickname> [<comment>] [-pubkey]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -899,7 +899,7 @@ SILC_CLIENT_CMD_FUNC(kill)
     nickname = strdup(cmd->argv[1]);
 
   /* Get the target client */
-  target = silc_idlist_get_client(cmd->client, conn, nickname, 
+  target = silc_idlist_get_client(cmd->client, conn, nickname,
                                  cmd->argv[1], TRUE);
   if (!target) {
     if (cmd->pending) {
@@ -909,9 +909,9 @@ SILC_CLIENT_CMD_FUNC(kill)
 
     /* Client entry not found, it was requested thus mark this to be
        pending command. */
-    silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
-                               conn->cmd_ident,  
-                               silc_client_command_kill, 
+    silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+                               conn->cmd_ident,
+                               silc_client_command_kill,
                                silc_client_command_dup(cmd));
     cmd->pending = 1;
     goto out;
@@ -935,8 +935,8 @@ SILC_CLIENT_CMD_FUNC(kill)
   /* Send the KILL command to the server */
   idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
   buffer =
-    silc_command_payload_encode_va(SILC_COMMAND_KILL, 
-                                  ++conn->cmd_ident, 3, 
+    silc_command_payload_encode_va(SILC_COMMAND_KILL,
+                                  ++conn->cmd_ident, 3,
                                   1, idp->data, idp->len,
                                   2, comment, comment ? strlen(comment) : 0,
                                   3, auth ? auth->data : NULL,
@@ -982,12 +982,12 @@ SILC_CLIENT_CMD_FUNC(info)
 
   /* Send the command */
   if (name)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
                                            1, name, strlen(name));
   else
     buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
                                         NULL, NULL, NULL, 0);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   if (name)
@@ -1014,13 +1014,13 @@ SILC_CLIENT_CMD_FUNC(stats)
     goto out;
   }
 
-  idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER); 
-  
+  idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+
   /* Send the command */
   buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
                                          ++conn->cmd_ident, 1,
                                          SILC_ID_SERVER, idp->data, idp->len);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
@@ -1032,7 +1032,7 @@ SILC_CLIENT_CMD_FUNC(stats)
   silc_client_command_free(cmd);
 }
 
-/* Command PING. Sends ping to server. This is used to test the 
+/* Command PING. Sends ping to server. This is used to test the
    communication channel. */
 
 SILC_CLIENT_CMD_FUNC(ping)
@@ -1049,12 +1049,12 @@ SILC_CLIENT_CMD_FUNC(ping)
     goto out;
   }
 
-  idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER); 
+  idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
 
   /* Send the command */
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
                                          1, idp->data, idp->len);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
@@ -1086,7 +1086,7 @@ SILC_CLIENT_CMD_FUNC(ping)
     conn->internal->ping[i].dest_name = strdup(conn->remote_host);
     conn->internal->ping_count++;
   }
-  
+
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
@@ -1101,7 +1101,7 @@ SILC_CLIENT_CMD_FUNC(join)
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
   SilcChannelEntry channel;
-  SilcBuffer buffer, idp, auth = NULL;
+  SilcBuffer buffer, idp, auth = NULL, cauth = NULL;
   char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
   int i, passphrase_len = 0;
 
@@ -1115,7 +1115,7 @@ SILC_CLIENT_CMD_FUNC(join)
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  
+
   /* See if we have joined to the requested channel already */
   channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
   if (channel && silc_client_on_channel(channel, conn->local_entry))
@@ -1138,15 +1138,50 @@ SILC_CLIENT_CMD_FUNC(join)
     } else if (!strcasecmp(cmd->argv[i], "-founder")) {
       auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
                                                cmd->client->private_key,
-                                               cmd->client->rng, 
+                                               cmd->client->rng,
                                                cmd->client->sha1hash,
                                                conn->local_id,
                                                SILC_ID_CLIENT);
       i++;
+    } else if (!strcasecmp(cmd->argv[i], "-auth")) {
+      SilcPublicKey pubkey = cmd->client->public_key;
+      SilcPrivateKey privkey = cmd->client->private_key;
+      unsigned char *pk, pkhash[20], *pubdata;
+      SilcUInt32 pk_len;
+
+      if (cmd->argc >= i + 3) {
+       char *pass = "";
+       if (cmd->argc >= i + 4) {
+         pass = cmd->argv[i + 3];
+         i++;
+       }
+       if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
+                               NULL, &pubkey, &privkey)) {
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+             "Could not load key pair, check your arguments");
+         COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+         goto out;
+       }
+       i += 2;
+      }
+
+      pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
+      silc_hash_make(cmd->client->sha1hash, pk, pk_len, pkhash);
+      silc_free(pk);
+      pubdata = silc_rng_get_rn_data(cmd->client->rng, 128);
+      memcpy(pubdata, pkhash, 20);
+      cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
+                                                     pubdata, 128,
+                                                     cmd->client->sha1hash,
+                                                     conn->local_id,
+                                                     SILC_ID_CLIENT);
+      memset(pubdata, 0, 128);
+      silc_free(pubdata);
+      i++;
     } else {
       /* Passphrases must be UTF-8 encoded, so encode if it is not */
       if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
-       passphrase_len = silc_utf8_encoded_len(cmd->argv[i], 
+       passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
                                               cmd->argv_lens[i], 0);
        pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
        passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
@@ -1161,20 +1196,22 @@ SILC_CLIENT_CMD_FUNC(join)
 
   /* Send JOIN command to the server */
   buffer =
-    silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
+    silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 7,
                                   1, name, strlen(name),
                                   2, idp->data, idp->len,
                                   3, passphrase, passphrase_len,
                                   4, cipher, cipher ? strlen(cipher) : 0,
                                   5, hmac, hmac ? strlen(hmac) : 0,
                                   6, auth ? auth->data : NULL,
-                                  auth ? auth->len : 0);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+                                  auth ? auth->len : 0,
+                                  7, cauth ? cauth->data : NULL,
+                                  cauth ? cauth->len : 0);
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
-  if (auth)
-    silc_buffer_free(auth);
+  silc_buffer_free(auth);
+  silc_buffer_free(cauth);
   if (passphrase)
     memset(passphrase, 0, strlen(passphrase));
   silc_free(passphrase);
@@ -1210,14 +1247,14 @@ SILC_CLIENT_CMD_FUNC(motd)
 
   /* Send TOPIC command to the server */
   if (cmd->argc == 1)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, 
-                                           1, conn->remote_host, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
+                                           1, conn->remote_host,
                                            strlen(conn->remote_host));
   else
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, 
-                                           1, cmd->argv[1], 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
+                                           1, cmd->argv[1],
                                            cmd->argv_lens[1]);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
 
@@ -1247,7 +1284,7 @@ SILC_CLIENT_CMD_FUNC(umode)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /UMODE +|-<modes>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -1361,11 +1398,11 @@ SILC_CLIENT_CMD_FUNC(umode)
 
   /* Send the command packet. We support sending only one mode at once
      that requires an argument. */
-  buffer = 
-    silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2, 
-                                  1, idp->data, idp->len, 
+  buffer =
+    silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
+                                  1, idp->data, idp->len,
                                   2, modebuf, sizeof(modebuf));
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
@@ -1398,7 +1435,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
   }
 
   if (cmd->argc < 3) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -1485,7 +1522,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode |= SILC_CHANNEL_MODE_ULIMIT;
        type = 3;
        if (cmd->argc < 4) {
-         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
          COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
          goto out;
@@ -1503,7 +1540,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode |= SILC_CHANNEL_MODE_PASSPHRASE;
        type = 4;
        if (cmd->argc < 4) {
-         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
          COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
          goto out;
@@ -1519,7 +1556,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode |= SILC_CHANNEL_MODE_CIPHER;
        type = 5;
        if (cmd->argc < 4) {
-         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
          COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
          goto out;
@@ -1535,7 +1572,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode |= SILC_CHANNEL_MODE_HMAC;
        type = 6;
        if (cmd->argc < 4) {
-         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
          COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
          goto out;
@@ -1569,7 +1606,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
 
        pk = silc_pkcs_public_key_payload_encode(pubkey);
        auth = silc_auth_public_key_auth_generate(pubkey, privkey,
-                                                 cmd->client->rng, 
+                                                 cmd->client->rng,
                                                  cmd->client->sha1hash,
                                                  conn->local_id,
                                                  SILC_ID_CLIENT);
@@ -1579,6 +1616,65 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
       }
       break;
+    case 'C':
+      if (add) {
+       int k;
+       bool chadd = FALSE;
+       SilcPublicKey chpk = NULL;
+
+       mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
+       type = 9;
+
+       if (cmd->argc == 3) {
+         /* Send empty command to receive the public key list. */
+         chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+         silc_client_command_send(cmd->client, conn, SILC_COMMAND_CMODE,
+                                  0, 1, 1, chidp->data, chidp->len);
+         silc_buffer_free(chidp);
+
+         /* Notify application */
+         COMMAND(SILC_STATUS_OK);
+         goto out;
+       }
+
+       if (cmd->argc >= 4) {
+         auth = silc_buffer_alloc_size(2);
+         silc_buffer_format(auth,
+                            SILC_STR_UI_SHORT(cmd->argc - 3),
+                            SILC_STR_END);
+       }
+
+       for (k = 3; k < cmd->argc; k++) {
+         if (cmd->argv[k][0] == '+')
+           chadd = TRUE;
+         if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
+                                        SILC_PKCS_FILE_PEM))
+           if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
+                                          SILC_PKCS_FILE_BIN)) {
+             SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+                 "Could not load public key %s, check the filename",
+                 cmd->argv[k]);
+             COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+             silc_buffer_free(auth);
+             goto out;
+           }
+
+         if (chpk) {
+           pk = silc_pkcs_public_key_payload_encode(chpk);
+           auth = silc_argument_payload_encode_one(auth, pk->data, pk->len,
+                                                   chadd ? 0x00 : 0x01);
+           silc_pkcs_public_key_free(chpk);
+           silc_buffer_free(pk);
+           pk = NULL;
+         }
+       }
+
+       arg = auth->data;
+       arg_len = auth->len;
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
+      }
+      break;
     default:
       COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
       goto out;
@@ -1592,21 +1688,21 @@ SILC_CLIENT_CMD_FUNC(cmode)
   /* Send the command packet. We support sending only one mode at once
      that requires an argument. */
   if (type && arg) {
-    buffer = 
+    buffer =
       silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 4,
-                                    1, chidp->data, chidp->len, 
+                                    1, chidp->data, chidp->len,
                                     2, modebuf, sizeof(modebuf),
                                     type, arg, arg_len,
                                     8, pk ? pk->data : NULL,
                                     pk ? pk->len : 0);
   } else {
-    buffer = 
+    buffer =
       silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
-                                    1, chidp->data, chidp->len, 
+                                    1, chidp->data, chidp->len,
                                     2, modebuf, sizeof(modebuf));
   }
 
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
@@ -1643,7 +1739,7 @@ SILC_CLIENT_CMD_FUNC(cumode)
   }
 
   if (cmd->argc < 4) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -1683,14 +1779,14 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
     /* Client entry not found, it was requested thus mark this to be
        pending command. */
-    silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
-                               conn->cmd_ident,  
-                               silc_client_command_cumode, 
+    silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+                               conn->cmd_ident,
+                               silc_client_command_cumode,
                                silc_client_command_dup(cmd));
     cmd->pending = 1;
     goto out;
   }
-  
+
   /* Get the current mode */
   chu = silc_client_on_channel(channel, client_entry);
   if (chu)
@@ -1789,22 +1885,22 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
   /* Send the command packet. We support sending only one mode at once
      that requires an argument. */
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 
-                                         auth ? 4 : 3, 
-                                         1, chidp->data, chidp->len, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
+                                         auth ? 4 : 3,
+                                         1, chidp->data, chidp->len,
                                          2, modebuf, 4,
                                          3, clidp->data, clidp->len,
-                                         4, auth ? auth->data : NULL, 
+                                         4, auth ? auth->data : NULL,
                                          auth ? auth->len : 0);
-  
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
   silc_buffer_free(clidp);
   if (auth)
     silc_buffer_free(auth);
-  
+
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
@@ -1834,7 +1930,7 @@ SILC_CLIENT_CMD_FUNC(kick)
   }
 
   if (cmd->argc < 3) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /KICK <channel> <nickname> [<comment>]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -1871,10 +1967,10 @@ SILC_CLIENT_CMD_FUNC(kick)
     nickname = strdup(cmd->argv[2]);
 
   /* Get the target client */
-  target = silc_idlist_get_client(cmd->client, conn, nickname, 
+  target = silc_idlist_get_client(cmd->client, conn, nickname,
                                  cmd->argv[2], FALSE);
   if (!target) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "No such client: %s", cmd->argv[2]);
     COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
     goto out;
@@ -1884,14 +1980,14 @@ SILC_CLIENT_CMD_FUNC(kick)
   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
   idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
   if (cmd->argc == 3)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
                                            1, idp->data, idp->len,
                                            2, idp2->data, idp2->len);
   else
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
                                            1, idp->data, idp->len,
                                            2, idp2->data, idp2->len,
-                                           3, cmd->argv[3], 
+                                           3, cmd->argv[3],
                                            strlen(cmd->argv[3]));
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
@@ -1928,8 +2024,8 @@ static void silc_client_command_oper_send(unsigned char *data,
                                    data, data_len);
   }
 
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2, 
-                                         1, cmd->argv[1], 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
+                                         1, cmd->argv[1],
                                          strlen(cmd->argv[1]),
                                          2, auth ? auth->data : NULL,
                                          auth ? auth->len : 0);
@@ -1958,7 +2054,7 @@ SILC_CLIENT_CMD_FUNC(oper)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /OPER <username> [-pubkey]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -1979,7 +2075,7 @@ SILC_CLIENT_CMD_FUNC(oper)
 }
 
 static void silc_client_command_silcoper_send(unsigned char *data,
-                                             SilcUInt32 data_len, 
+                                             SilcUInt32 data_len,
                                              void *context)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
@@ -2000,8 +2096,8 @@ static void silc_client_command_silcoper_send(unsigned char *data,
                                    data, data_len);
   }
 
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2, 
-                                         1, cmd->argv[1], 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
+                                         1, cmd->argv[1],
                                          strlen(cmd->argv[1]),
                                          2, auth ? auth->data : NULL,
                                          auth ? auth->len : 0);
@@ -2030,7 +2126,7 @@ SILC_CLIENT_CMD_FUNC(silcoper)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /SILCOPER <username> [-pubkey]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -2061,7 +2157,7 @@ SILC_CLIENT_CMD_FUNC(ban)
   char *name, *ban = NULL;
   unsigned char action[1];
   SilcPublicKey pubkey = NULL;
-  
+
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
@@ -2069,7 +2165,7 @@ SILC_CLIENT_CMD_FUNC(ban)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /BAN <channel> "
        "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -2128,14 +2224,14 @@ SILC_CLIENT_CMD_FUNC(ban)
   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
 
   /* Send the command */
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
                                          ++conn->cmd_ident, 3,
                                          1, chidp->data, chidp->len,
                                          2, args ? action : NULL,
                                          args ? 1 : 0,
                                          3, args ? args->data : NULL,
                                          args ? args->len : 0);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
@@ -2164,7 +2260,7 @@ SILC_CLIENT_CMD_FUNC(detach)
 
   buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
                                          ++conn->cmd_ident, 0);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
 
@@ -2206,12 +2302,12 @@ SILC_CLIENT_CMD_FUNC(watch)
     goto out;
   }
 
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
                                          ++conn->cmd_ident, 2,
                                          1, idp->data, idp->len,
                                          type, cmd->argv[2],
                                          cmd->argv_lens[2]);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
 
@@ -2242,7 +2338,7 @@ SILC_CLIENT_CMD_FUNC(leave)
   }
 
   if (cmd->argc != 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /LEAVE <channel>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -2275,9 +2371,9 @@ SILC_CLIENT_CMD_FUNC(leave)
 
   /* Send LEAVE command to the server */
   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
                                          1, idp->data, idp->len);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
@@ -2311,7 +2407,7 @@ SILC_CLIENT_CMD_FUNC(users)
   }
 
   if (cmd->argc != 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /USERS <channel>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -2328,11 +2424,11 @@ SILC_CLIENT_CMD_FUNC(users)
   }
 
   /* Send USERS command to the server */
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 
-                                         ++conn->cmd_ident, 1, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
+                                         ++conn->cmd_ident, 1,
                                          2, name, strlen(name));
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, 
-                         NULL, 0, NULL, NULL, buffer->data, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
+                         NULL, 0, NULL, NULL, buffer->data,
                          buffer->len, TRUE);
   silc_buffer_free(buffer);
 
@@ -2364,7 +2460,7 @@ SILC_CLIENT_CMD_FUNC(getkey)
   }
 
   if (cmd->argc < 2) {
-    client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
                     "Usage: /GETKEY <nickname or server name>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -2391,14 +2487,14 @@ SILC_CLIENT_CMD_FUNC(getkey)
       if (!cmd->pending) {
        /* This will send the IDENTIFY command for nickname */
        silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
-       silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
-                                   conn->cmd_ident,  
-                                   silc_client_command_getkey, 
+       silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+                                   conn->cmd_ident,
+                                   silc_client_command_getkey,
                                    silc_client_command_dup(cmd));
        cmd->pending = 1;
        goto out;
       } else {
-       SilcClientCommandReplyContext reply = 
+       SilcClientCommandReplyContext reply =
          (SilcClientCommandReplyContext)context2;
        SilcStatus error;
 
@@ -2406,16 +2502,16 @@ SILC_CLIENT_CMD_FUNC(getkey)
        silc_command_get_status(reply->payload, NULL, &error);
        if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
          /* This sends the IDENTIFY command to resolve the server. */
-         silc_client_command_register(client, SILC_COMMAND_IDENTIFY, 
+         silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
                                       NULL, NULL,
                                       silc_client_command_reply_identify_i, 0,
                                       ++conn->cmd_ident);
          silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
-                                  conn->cmd_ident, 1, 
+                                  conn->cmd_ident, 1,
                                   2, cmd->argv[1], cmd->argv_lens[1]);
-         silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
-                                     conn->cmd_ident, 
-                                     silc_client_command_getkey, 
+         silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+                                     conn->cmd_ident,
+                                     silc_client_command_getkey,
                                      silc_client_command_dup(cmd));
          goto out;
        }
@@ -2423,9 +2519,9 @@ SILC_CLIENT_CMD_FUNC(getkey)
        /* If server was not found, then we've resolved both nickname and
           server and did not find anybody. */
        if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
-         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", 
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
             silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
-         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", 
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
            silc_get_status_message(error));
          COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
          goto out;
@@ -2441,9 +2537,9 @@ SILC_CLIENT_CMD_FUNC(getkey)
     idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
   }
 
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
                                          1, idp->data, idp->len);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
@@ -2461,11 +2557,11 @@ SILC_CLIENT_CMD_FUNC(getkey)
    searched using the silc_client_command_find by that name.  The
    `command_function' is the function to be called when the command is
    executed, and the `command_reply_function' is the function to be
-   called after the server has sent reply back to the command. 
+   called after the server has sent reply back to the command.
 
    The `ident' is optional identifier for the command.  If non-zero
    the `command_reply_function' for the command type `command' will be
-   called only if the command reply sent by server includes the 
+   called only if the command reply sent by server includes the
    command identifier `ident'. Application usually does not need it
    and set it to zero value. */
 
@@ -2538,7 +2634,7 @@ SILC_CLIENT_CMD_FUNC(connect)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /CONNECT <server> [<port>]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -2550,13 +2646,13 @@ SILC_CLIENT_CMD_FUNC(connect)
   }
 
   if (cmd->argc == 3)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2, 
-                                           1, cmd->argv[1], 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
+                                           1, cmd->argv[1],
                                            strlen(cmd->argv[1]),
                                            2, port, 4);
   else
     buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
-                                           1, cmd->argv[1], 
+                                           1, cmd->argv[1],
                                            strlen(cmd->argv[1]));
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
@@ -2571,7 +2667,7 @@ SILC_CLIENT_CMD_FUNC(connect)
 
 
 /* CLOSE command. Close server connection to the remote server */
+
 SILC_CLIENT_CMD_FUNC(close)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
@@ -2587,7 +2683,7 @@ SILC_CLIENT_CMD_FUNC(close)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /CLOSE <server> [<port>]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -2599,13 +2695,13 @@ SILC_CLIENT_CMD_FUNC(close)
   }
 
   if (cmd->argc == 3)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2, 
-                                           1, cmd->argv[1], 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
+                                           1, cmd->argv[1],
                                            strlen(cmd->argv[1]),
                                            2, port, 4);
   else
     buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
-                                           1, cmd->argv[1], 
+                                           1, cmd->argv[1],
                                            strlen(cmd->argv[1]));
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
@@ -2617,7 +2713,7 @@ SILC_CLIENT_CMD_FUNC(close)
  out:
   silc_client_command_free(cmd);
 }
+
 /* SHUTDOWN command. Shutdowns the server. */
 
 SILC_CLIENT_CMD_FUNC(shutdown)
@@ -2631,7 +2727,7 @@ SILC_CLIENT_CMD_FUNC(shutdown)
   }
 
   /* Send the command */
-  silc_client_command_send(cmd->client, cmd->conn, 
+  silc_client_command_send(cmd->client, cmd->conn,
                           SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
 
   /* Notify application */
@@ -2646,7 +2742,7 @@ SILC_CLIENT_CMD_FUNC(shutdown)
 
 void silc_client_commands_register(SilcClient client)
 {
-  silc_list_init(client->internal->commands, struct SilcClientCommandStruct, 
+  silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
                 next);
 
   SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
@@ -2750,7 +2846,7 @@ void silc_client_command_process(SilcClient client,
 
   /* Get arguments */
   args = silc_command_get_args(payload);
-  
+
   /* Get the command */
   command = silc_command_get(payload);
   switch (command) {
@@ -2805,7 +2901,7 @@ void silc_client_command_process_whois(SilcClient client,
                                         silc_command_get_ident(payload),
                                         1, 11, buffer->data, buffer->len);
   silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
-                         NULL, 0, NULL, NULL, packet->data, 
+                         NULL, 0, NULL, NULL, packet->data,
                          packet->len, TRUE);
   silc_buffer_free(packet);
   silc_buffer_free(buffer);
index 202841ddf36d971d7e1a9456e504f034d01dde13..7d24d9fa051fcf56d8cdbb84d1bf8caa2c3afda0 100644 (file)
@@ -1217,6 +1217,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode)
   SilcChannelID *channel_id;
   SilcChannelEntry channel;
   SilcUInt32 len;
+  SilcPublicKey public_key = NULL;
+  SilcBufferStruct channel_pubkeys;
 
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
@@ -1253,12 +1255,27 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode)
   SILC_GET32_MSB(mode, tmp);
   channel->mode = mode;
 
+  /* Get founder public key */
+  tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
+  if (tmp) {
+    if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
+      public_key = NULL;
+  }
+
+  /* Get channel public key(s) */
+  tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
+  if (tmp)
+    silc_buffer_set(&channel_pubkeys, tmp, len);
+
   /* Notify application */
-  COMMAND_REPLY((SILC_ARGS, channel, mode));
+  COMMAND_REPLY((SILC_ARGS, channel, mode, public_key,
+                tmp ? &channel_pubkeys : NULL));
 
   silc_free(channel_id);
 
  out:
+  if (public_key)
+    silc_pkcs_public_key_free(public_key);
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
   silc_client_command_reply_free(cmd);
 }
index c6fc299096a16e8afea8db822fb3edec943aecf0..27d84f8a7a4705935b7919c684b5e5ba5bf504ec 100644 (file)
@@ -253,7 +253,8 @@ struct SilcChannelEntryStruct {
   SilcChannelID *id;                        /* Channel ID */
   SilcUInt32 mode;                          /* Channel mode */
 
-  /* All clients that has joined this channel */
+  /* All clients that has joined this channel.  The key to the table is the
+     SilcClientEntry and the context is SilcChannelUser context. */
   SilcHashTable user_list;
 
   /* Channel keys */
index d42dd66fb0ba747268f7a25cc28e46e11b541f2f..9c603df4f2ac30c418fc8509456bb45616f46d24 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcauth.c 
+  silcauth.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2002 Pekka Riikonen
+  Copyright (C) 2001 - 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
@@ -67,7 +67,7 @@ SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
     return NULL;
   }
 
-  if (newp->len != buffer.len || 
+  if (newp->len != buffer.len ||
       newp->random_len + newp->auth_len > buffer.len - 8) {
     silc_auth_payload_free(newp);
     return NULL;
@@ -163,13 +163,24 @@ SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
   return payload->auth_method;
 }
 
+/* Get the public data from the auth payload. */
+
+unsigned char *silc_auth_get_public_data(SilcAuthPayload payload,
+                                        SilcUInt32 *pubdata_len)
+{
+  if (pubdata_len)
+    *pubdata_len = (SilcUInt32)payload->random_len;
+
+  return payload->random_data;
+}
+
 /* Get the authentication data. If this is passphrase it is UTF-8 encoded. */
 
 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
                                  SilcUInt32 *auth_len)
 {
   if (auth_len)
-    *auth_len = payload->auth_len;
+    *auth_len = (SilcUInt32)payload->auth_len;
 
   return payload->auth_data;
 }
@@ -235,14 +246,7 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
                                              const void *id, SilcIdType type)
 {
   unsigned char *randomdata;
-  unsigned char auth_data[2048 + 1];
-  SilcUInt32 auth_len;
-  unsigned char *tmp;
-  SilcUInt32 tmp_len;
   SilcBuffer buf;
-  SilcPKCS pkcs;
-
-  SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
 
   /* Get 256 bytes of random data */
   if (rng)
@@ -252,8 +256,39 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
   if (!randomdata)
     return NULL;
 
+  buf = silc_auth_public_key_auth_generate_wpub(public_key, private_key,
+                                               randomdata, 256, hash,
+                                               id, type);
+
+  memset(randomdata, 0, 256);
+  silc_free(randomdata);
+
+  return buf;
+}
+
+/* Generates Authentication Payload with authentication data. This is used
+   to do public key based authentication. This generates the random data
+   and the actual authentication data. Returns NULL on error. */
+
+SilcBuffer
+silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
+                                       SilcPrivateKey private_key,
+                                       const unsigned char *pubdata,
+                                       SilcUInt32 pubdata_len,
+                                       SilcHash hash,
+                                       const void *id, SilcIdType type)
+{
+  unsigned char auth_data[2048 + 1];
+  SilcUInt32 auth_len;
+  unsigned char *tmp;
+  SilcUInt32 tmp_len;
+  SilcBuffer buf;
+  SilcPKCS pkcs;
+
+  SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
+
   /* Encode the auth data */
-  tmp = silc_auth_public_key_encode_data(public_key, randomdata, 256, id, 
+  tmp = silc_auth_public_key_encode_data(public_key, pubdata, pubdata_len, id,
                                         type, &tmp_len);
   if (!tmp)
     return NULL;
@@ -271,23 +306,19 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
   if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
       !silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
                                &auth_len)) {
-    memset(randomdata, 0, 256);
     memset(tmp, 0, tmp_len);
     silc_free(tmp);
-    silc_free(randomdata);
     silc_pkcs_free(pkcs);
     return NULL;
   }
 
   /* Encode Authentication Payload */
-  buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, randomdata, 256,
+  buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, pubdata, pubdata_len,
                                 auth_data, auth_len);
 
   memset(tmp, 0, tmp_len);
   memset(auth_data, 0, sizeof(auth_data));
-  memset(randomdata, 0, 256);
   silc_free(tmp);
-  silc_free(randomdata);
   silc_pkcs_free(pkcs);
 
   return buf;
index 6f874d959873f13ea2e394bb23cb9123e595a8eb..29101966d7ce6208f7b79055477b6ca1a66cd64d 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcauth.h 
+  silcauth.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2002 Pekka Riikonen
+  Copyright (C) 2001 - 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,8 +22,8 @@
  * DESCRIPTION
  *
  * Implementations of the SILC Authentication Payload and authentication
- * routines.  The SILC Authentication Payload is used to deliver 
- * authentication data usually from client to server in purpose of 
+ * routines.  The SILC Authentication Payload is used to deliver
+ * authentication data usually from client to server in purpose of
  * gaining access to some service.  The Payload and the authentication
  * routines supports both passphrase and public key (signature) based
  * authentication.
@@ -40,7 +40,7 @@
 /****d* silccore/SilcAuthAPI/SilcAuthMethod
  *
  * NAME
- * 
+ *
  *    typedef SilcUInt16 SilcAuthMethod;
  *
  * DESCRIPTION
@@ -66,8 +66,8 @@ typedef SilcUInt16 SilcAuthMethod;
 /****s* silccore/SilcAuthAPI/SilcAuthPayload
  *
  * NAME
- * 
- *    typedef struct SilcAuthPayloadStruct *SilcAuthPayload; 
+ *
+ *    typedef struct SilcAuthPayloadStruct *SilcAuthPayload;
  *
  *
  * DESCRIPTION
@@ -148,6 +148,22 @@ void silc_auth_payload_free(SilcAuthPayload payload);
  ***/
 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload);
 
+/****f* silccore/SilcAuthAPI/silc_auth_get_public_data
+ *
+ * SYNOPSIS
+ *
+ *    unsigned char *silc_auth_get_public_data(SilcAuthPayload payload,
+ *                                             SilcUInt32 *pubdata_len);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the public data (usually random data) from the payload.
+ *    Caller must not free the returned data.
+ *
+ ***/
+unsigned char *silc_auth_get_public_data(SilcAuthPayload payload,
+                                        SilcUInt32 *pubdata_len);
+
 /****f* silccore/SilcAuthAPI/silc_auth_get_data
  *
  * SYNOPSIS
@@ -173,7 +189,7 @@ unsigned char *silc_auth_get_data(SilcAuthPayload payload,
  *                                                  SilcPrivateKey private_key,
  *                                                  SilcRng rng,
  *                                                  SilcHash hash,
- *                                                  const void *id, 
+ *                                                  const void *id,
  *                                                  SilcIdType type);
  *
  * DESCRIPTION
@@ -195,12 +211,41 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
                                              SilcRng rng, SilcHash hash,
                                              const void *id, SilcIdType type);
 
+/****f* silccore/SilcAuthAPI/silc_auth_public_key_auth_generate_wpub
+ *
+ * SYNOPSIS
+ *
+ *    SilcBuffer
+ *    silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
+ *                                            SilcPrivateKey private_key,
+ *                                            const unsigned char *pubdata,
+ *                                            SilcUInt32 pubdata_len,
+ *                                            SilcHash hash,
+ *                                            const void *id,
+ *                                            SilcIdType type);
+ *
+ * DESCRIPTION
+ *
+ *    Same as silc_auth_public_key_auth_generate but takes the public data
+ *    (usually random data) as argument.  This function can be used when
+ *    the public data must be something else than purely random or its
+ *    structure mut be set before signing.
+ *
+ ***/
+SilcBuffer
+silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
+                                       SilcPrivateKey private_key,
+                                       const unsigned char *pubdata,
+                                       SilcUInt32 pubdata_len,
+                                       SilcHash hash,
+                                       const void *id, SilcIdType type);
+
 /****f* silccore/SilcAuthAPI/silc_auth_public_key_auth_verify
  *
  * SYNOPSIS
  *
  *    bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
- *                                          SilcPublicKey public_key, 
+ *                                          SilcPublicKey public_key,
  *                                          SilcHash hash,
  *                                          const void *id, SilcIdType type);
  *
@@ -220,9 +265,9 @@ bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
  *
  *    bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
  *                                               SilcUInt32 payload_len,
- *                                               SilcPublicKey public_key, 
+ *                                               SilcPublicKey public_key,
  *                                               SilcHash hash,
- *                                               const void *id, 
+ *                                               const void *id,
  *                                               SilcIdType type);
  *
  * DESCRIPTION
@@ -234,7 +279,7 @@ bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
  ***/
 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
                                           SilcUInt32 payload_len,
-                                          SilcPublicKey public_key, 
+                                          SilcPublicKey public_key,
                                           SilcHash hash,
                                           const void *id, SilcIdType type);
 
@@ -242,14 +287,14 @@ bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
  *
  * SYNOPSIS
  *
- *    bool silc_auth_verify(SilcAuthPayload payload, 
+ *    bool silc_auth_verify(SilcAuthPayload payload,
  *                          SilcAuthMethod auth_method,
- *                          const void *auth_data, SilcUInt32 auth_data_len, 
+ *                          const void *auth_data, SilcUInt32 auth_data_len,
  *                          SilcHash hash, const void *id, SilcIdType type);
  *
  * DESCRIPTION
  *
- *    Verifies the authentication data directly from the Authentication 
+ *    Verifies the authentication data directly from the Authentication
  *    Payload. Supports all authentication methods. If the authentication
  *    method is passphrase based then the `auth_data' and `auth_data_len'
  *    are the passphrase and its length.  The passphrase MUST be UTF-8
@@ -258,24 +303,24 @@ bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
  *
  ***/
 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
-                     const void *auth_data, SilcUInt32 auth_data_len, 
+                     const void *auth_data, SilcUInt32 auth_data_len,
                      SilcHash hash, const void *id, SilcIdType type);
 
 /****f* silccore/SilcAuthAPI/silc_auth_verify_data
  *
  * SYNOPSIS
  *
- *    bool silc_auth_verify_data(const unsigned char *payload, 
+ *    bool silc_auth_verify_data(const unsigned char *payload,
  *                               SilcUInt32 payload_len,
- *                               SilcAuthMethod auth_method, 
+ *                               SilcAuthMethod auth_method,
  *                               const void *auth_data,
- *                               SilcUInt32 auth_data_len, SilcHash hash, 
+ *                               SilcUInt32 auth_data_len, SilcHash hash,
  *                               const void *id, SilcIdType type);
- * 
+ *
  * DESCRIPTION
  *
  *    Same as silc_auth_verify but the payload has not been parsed yet.
- *    Verifies the authentication data directly from the Authentication 
+ *    Verifies the authentication data directly from the Authentication
  *    Payload. Supports all authentication methods. If the authentication
  *    method is passphrase based then the `auth_data' and `auth_data_len'
  *    are the passphrase and its length.  The passphrase MUST be UTF-8
@@ -283,16 +328,16 @@ bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
  *    `auth_data' is the SilcPublicKey and the `auth_data_len' is ignored.
  *
  ***/
-bool silc_auth_verify_data(const unsigned char *payload, 
+bool silc_auth_verify_data(const unsigned char *payload,
                           SilcUInt32 payload_len,
                           SilcAuthMethod auth_method, const void *auth_data,
-                          SilcUInt32 auth_data_len, SilcHash hash, 
+                          SilcUInt32 auth_data_len, SilcHash hash,
                           const void *id, SilcIdType type);
 
 /****s* silccore/SilcAuthAPI/SilcKeyAgreementPayload
  *
  * NAME
- * 
+ *
  *    typedef struct SilcKeyAgreementPayloadStruct *SilcKeyAgreementPayload;
  *
  * DESCRIPTION
@@ -309,7 +354,7 @@ typedef struct SilcKeyAgreementPayloadStruct *SilcKeyAgreementPayload;
  *
  * SYNOPSIS
  *
- *    SilcKeyAgreementPayload 
+ *    SilcKeyAgreementPayload
  *    silc_key_agreement_payload_parse(const unsigned char *payload,
  *                                     SilcUInt32 payload_len);
  *
@@ -318,7 +363,7 @@ typedef struct SilcKeyAgreementPayloadStruct *SilcKeyAgreementPayload;
  *    Parses and returns an allocated Key Agreement payload.
  *
  ***/
-SilcKeyAgreementPayload 
+SilcKeyAgreementPayload
 silc_key_agreement_payload_parse(const unsigned char *payload,
                                 SilcUInt32 payload_len);
 
index 83a16d005e4bb6073164dfbc77d171d21c95e274..1f662dd70fbbda819f5a4dc5669bf25f9fcd6e1e 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcpkcs.c 
+  silcpkcs.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 @@ SilcDList silc_pkcs_list = NULL;
 const SilcPKCSObject silc_default_pkcs[] =
 {
   /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
-  { "rsa", 
+  { "rsa",
     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
     silc_rsa_get_private_key, silc_rsa_set_public_key,
     silc_rsa_set_private_key, silc_rsa_context_len,
@@ -50,7 +50,7 @@ const SilcPKCSObject silc_default_pkcs[] =
     silc_pkcs1_sign, silc_pkcs1_verify },
 
   /* Raw RSA operations */
-  { "rsa-raw", 
+  { "rsa-raw",
     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
     silc_rsa_get_private_key, silc_rsa_set_public_key,
     silc_rsa_set_private_key, silc_rsa_context_len,
@@ -136,7 +136,7 @@ bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
   return FALSE;
 }
 
-/* Function that registers all the default PKCS (all builtin PKCS). 
+/* Function that registers all the default PKCS (all builtin PKCS).
    The application may use this to register the default PKCS if specific
    PKCS in any specific order is not wanted. */
 
@@ -260,8 +260,8 @@ char *silc_pkcs_get_supported(void)
     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
       len += strlen(entry->name);
       list = silc_realloc(list, len + 1);
-      
-      memcpy(list + (len - strlen(entry->name)), 
+
+      memcpy(list + (len - strlen(entry->name)),
             entry->name, strlen(entry->name));
       memcpy(list + len, ",", 1);
       len++;
@@ -274,8 +274,8 @@ char *silc_pkcs_get_supported(void)
       entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
       len += strlen(entry->name);
       list = silc_realloc(list, len + 1);
-      
-      memcpy(list + (len - strlen(entry->name)), 
+
+      memcpy(list + (len - strlen(entry->name)),
             entry->name, strlen(entry->name));
       memcpy(list + len, ",", 1);
       len++;
@@ -326,7 +326,7 @@ unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
 
 SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
 {
-  pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, 
+  pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
                                             public_key->pk_len);
   return pkcs->key_len;
 }
@@ -345,7 +345,7 @@ SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
 SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
 {
   SilcUInt32 key_len;
-  key_len = pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
+  key_len = pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
                                        private_key->prv_len);
   if (!pkcs->key_len)
     pkcs->key_len = key_len;
@@ -390,11 +390,11 @@ bool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
 
 /* Verifies signature */
 
-bool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, 
-                     SilcUInt32 signature_len, unsigned char *data, 
+bool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
+                     SilcUInt32 signature_len, unsigned char *data,
                      SilcUInt32 data_len)
 {
-  return pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
+  return pkcs->pkcs->verify(pkcs->context, signature, signature_len,
                            data, data_len);
 }
 
@@ -422,10 +422,10 @@ bool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
 /* Verifies signature with hash. The `data' is hashed and verified against
    the `signature'. */
 
-bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, 
-                               unsigned char *signature, 
-                               SilcUInt32 signature_len, 
-                               unsigned char *data, 
+bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
+                               unsigned char *signature,
+                               SilcUInt32 signature_len,
+                               unsigned char *data,
                                SilcUInt32 data_len)
 {
   unsigned char hashr[32];
@@ -437,14 +437,14 @@ bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
 
   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
 
-  ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
+  ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len,
                           hashr, hash_len);
   memset(hashr, 0, sizeof(hashr));
 
   return ret;
 }
 
-/* Encodes and returns SILC public key identifier. If some of the 
+/* Encodes and returns SILC public key identifier. If some of the
    arguments is NULL those are not encoded into the identifier string.
    Protocol says that at least username and host must be provided. */
 
@@ -464,7 +464,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
        (email    ? strlen(email)    : 0) +
        (org      ? strlen(org)      : 0) +
        (country  ? strlen(country)  : 0);
-  
+
   if (len < 3)
     return NULL;
 
@@ -478,9 +478,9 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
                       SILC_STR_UI32_STRING(username),
                       SILC_STR_END);
     silc_buffer_pull(buf, 3 + strlen(username));
-    tlen = 3 + strlen(username); 
+    tlen = 3 + strlen(username);
   }
-    
+
   if (host) {
     silc_buffer_format(buf,
                       SILC_STR_UI32_STRING(", "),
@@ -488,7 +488,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
                       SILC_STR_UI32_STRING(host),
                       SILC_STR_END);
     silc_buffer_pull(buf, 5 + strlen(host));
-    tlen += 5 + strlen(host); 
+    tlen += 5 + strlen(host);
   }
 
   if (realname) {
@@ -498,7 +498,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
                       SILC_STR_UI32_STRING(realname),
                       SILC_STR_END);
     silc_buffer_pull(buf, 5 + strlen(realname));
-    tlen += 5 + strlen(realname); 
+    tlen += 5 + strlen(realname);
   }
 
   if (email) {
@@ -508,7 +508,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
                       SILC_STR_UI32_STRING(email),
                       SILC_STR_END);
     silc_buffer_pull(buf, 4 + strlen(email));
-    tlen += 4 + strlen(email); 
+    tlen += 4 + strlen(email);
   }
 
   if (org) {
@@ -518,7 +518,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
                       SILC_STR_UI32_STRING(org),
                       SILC_STR_END);
     silc_buffer_pull(buf, 4 + strlen(org));
-    tlen += 4 + strlen(org); 
+    tlen += 4 + strlen(org);
   }
 
   if (country) {
@@ -528,7 +528,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
                       SILC_STR_UI32_STRING(country),
                       SILC_STR_END);
     silc_buffer_pull(buf, 4 + strlen(country));
-    tlen += 4 + strlen(country); 
+    tlen += 4 + strlen(country);
   }
 
   silc_buffer_push(buf, buf->data - buf->head);
@@ -577,13 +577,13 @@ SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
       ident->org = strdup(item + strcspn(cp, "=") + 1);
     else if (strstr(item, "C="))
       ident->country = strdup(item + strcspn(cp, "=") + 1);
-    
+
     cp += len;
     if (strlen(cp) == 0)
       cp = NULL;
     else
       cp += 1;
-    
+
     if (item)
       silc_free(item);
   }
@@ -608,9 +608,9 @@ void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
 /* Allocates SILC style public key formed from sent arguments. All data
    is duplicated. */
 
-SilcPublicKey silc_pkcs_public_key_alloc(const char *name, 
+SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
                                         const char *identifier,
-                                        const unsigned char *pk, 
+                                        const unsigned char *pk,
                                         SilcUInt32 pk_len)
 {
   SilcPublicKey public_key;
@@ -697,7 +697,7 @@ silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
                     SILC_STR_UI32_STRING(public_key->name),
                     SILC_STR_UI_SHORT(strlen(public_key->identifier)),
                     SILC_STR_UI32_STRING(public_key->identifier),
-                    SILC_STR_UI_XNSTRING(public_key->pk, 
+                    SILC_STR_UI_XNSTRING(public_key->pk,
                                          public_key->pk_len),
                     SILC_STR_END);
 
@@ -710,7 +710,7 @@ silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
 
 unsigned char *
 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
-                                char *pkcs, char *identifier, 
+                                char *pkcs, char *identifier,
                                 SilcUInt32 *len)
 {
   SilcBuffer buf;
@@ -776,7 +776,7 @@ bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
   if (ret == -1)
     goto err;
 
-  if (pkcs_len < 1 || identifier_len < 3 || 
+  if (pkcs_len < 1 || identifier_len < 3 ||
       pkcs_len + identifier_len > totlen)
     goto err;
 
@@ -804,7 +804,7 @@ bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
     goto err;
 
   /* Try to set the key. If this fails the key must be malformed. This
-     code assumes that the PKCS routine checks the format of the key. 
+     code assumes that the PKCS routine checks the format of the key.
      (check only if PKCS are registered) */
   if (SILC_PKCS_LIST) {
     silc_pkcs_alloc(pkcs_name, &alg);
@@ -812,7 +812,7 @@ bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
       goto err;
     silc_pkcs_free(alg);
   }
-  
+
   if (public_key) {
     *public_key = silc_calloc(1, sizeof(**public_key));
     (*public_key)->len = totlen;
@@ -961,7 +961,7 @@ silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
   silc_buffer_format(buf,
                     SILC_STR_UI_SHORT(strlen(private_key->name)),
                     SILC_STR_UI32_STRING(private_key->name),
-                    SILC_STR_UI_XNSTRING(private_key->prv, 
+                    SILC_STR_UI_XNSTRING(private_key->prv,
                                          private_key->prv_len),
                     SILC_STR_END);
 
@@ -1012,7 +1012,7 @@ bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
   silc_buffer_set(&buf, data, data_len);
 
   /* Get algorithm name and identifier */
-  ret = 
+  ret =
     silc_buffer_unformat(&buf,
                         SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
                         SILC_STR_END);
@@ -1042,7 +1042,7 @@ bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
     goto err;
 
   /* Try to set the key. If this fails the key must be malformed. This
-     code assumes that the PKCS routine checks the format of the key. 
+     code assumes that the PKCS routine checks the format of the key.
      (check only if PKCS are registered) */
   if (SILC_PKCS_LIST) {
     silc_pkcs_alloc(pkcs_name, &alg);
@@ -1052,7 +1052,7 @@ bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
     }
     silc_pkcs_free(alg);
   }
-  
+
   if (private_key) {
     *private_key = silc_calloc(1, sizeof(**private_key));
     (*private_key)->name = pkcs_name;
@@ -1186,7 +1186,7 @@ static bool silc_pkcs_save_private_key_internal(const char *filename,
   }
 
   /* Derive the encryption key from the provided key material.  The key
-     is 256 bits length, and derived by taking hash of the data, then 
+     is 256 bits length, and derived by taking hash of the data, then
      re-hashing the data and the previous digest, and using the first and
      second digest as the key. */
   silc_hash_init(sha1);
@@ -1322,7 +1322,7 @@ bool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key,
   SILC_LOG_DEBUG(("Loading public key `%s' with %s encoding", filename,
                  encoding == SILC_PKCS_FILE_PEM ? "Base64" :
                  encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
-  
+
   old = data = silc_file_readfile(filename, &data_len);
   if (!data)
     return FALSE;
@@ -1353,7 +1353,7 @@ bool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key,
       data = silc_pem_decode(data, len, &len);
       memset(old, 0, data_len);
       silc_free(old);
-      old = data; 
+      old = data;
       data_len = len;
       break;
     }
@@ -1390,7 +1390,7 @@ bool silc_pkcs_load_private_key(const char *filename,
   SILC_LOG_DEBUG(("Loading private key `%s' with %s encoding", filename,
                  encoding == SILC_PKCS_FILE_PEM ? "Base64" :
                  encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
-  
+
   old = data = silc_file_readfile(filename, &data_len);
   if (!data)
     return FALSE;
@@ -1481,7 +1481,7 @@ bool silc_pkcs_load_private_key(const char *filename,
   }
 
   /* Derive the decryption key from the provided key material.  The key
-     is 256 bits length, and derived by taking hash of the data, then 
+     is 256 bits length, and derived by taking hash of the data, then
      re-hashing the data and the previous digest, and using the first and
      second digest as the key. */
   silc_hash_init(sha1);
index 4d45aa86f1e2f2f37bde8231dd3bbd24dd724715..b7f4dfeb3c7e74b5c8568b74e78abe79d2fefdcc 100644 (file)
@@ -397,9 +397,11 @@ char *silc_config_read_current_line(SilcConfigFile *file);
  *    Register option `name' in the entity `ent'. If `cb' is not NULL, it
  *    will be called with the *val pointer pointing to an internally
  *    allocated storage of type described by `type'.
+ *
  *    If `type' is SILC_CONFIG_ARG_BLOCK, then `subtable' must be a valid
  *    pointer to a SilcConfigTable array specifying the options in the
  *    sub-block.
+ *
  *    If the option `name' was already registered in this sub-block or it
  *    matches the reserved word "Include", then this function returns FALSE,
  *    otherwise it returns TRUE.
@@ -425,8 +427,10 @@ bool silc_config_register(SilcConfigEntity ent, const char *name,
  *    Register the tableset of options `table' automatically in the entity
  *    `ent'.  If defined in the table, the callback functions will be called
  *    all with the same context `context'.
+ *
  *    The `table' array must be terminated with an entry with the name field
  *    set to NULL.
+ *
  *    If the table contains invalid data this function returns FALSE, otherwise
  *    it returns TRUE.  If a calling to this function failed, you must destroy
  *    and recreate the entity before retrying, as it's impossible to detect
@@ -449,6 +453,7 @@ bool silc_config_register_table(SilcConfigEntity ent,
  *
  *    Enter the main parsing loop. When this function returns the parsing
  *    is finished in the current block (and sub-blocks).
+ *
  *    When this function exits, the entity is already destroyed, because
  *    of this you should set it to NULL right after the function call.
  *
index 8c9064891527f6199d346681f9d3a38cf3cb0d53..f665344eee27d456d5e019a8044e12fe92704213 100644 (file)
@@ -4,7 +4,7 @@
 
   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
@@ -652,15 +652,18 @@ char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
   if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
     strncat(string, "f", 1);
 
+  if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
+    strncat(string, "C", 1);
+
   if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
     strncat(string, "m", 1);
 
   if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
     strncat(string, "M", 1);
-  
+
   if (mode & SILC_CHANNEL_MODE_CIPHER)
     strncat(string, "c", 1);
-  
+
   if (mode & SILC_CHANNEL_MODE_HMAC)
     strncat(string, "h", 1);
 
@@ -1155,7 +1158,7 @@ const char *silc_get_command_name(unsigned char command)
 
 /* Return TRUE if `smaller' is smaller than `bigger'. */
 
-bool silc_compare_timeval(struct timeval *smaller, 
+bool silc_compare_timeval(struct timeval *smaller,
                          struct timeval *bigger)
 {
   if ((smaller->tv_sec < bigger->tv_sec) ||