Merged from silc_1_0_branch.
[silc.git] / apps / silcd / command.c
index d42af0780c340fe46f36aced184e9e851a3e4fa0..78beef6f58c38c90c71ae045894c8c16000351e1 100644 (file)
@@ -603,6 +603,11 @@ SILC_SERVER_CMD_FUNC(nick)
 
   /* Check nickname */
   nick = silc_argument_get_arg_type(cmd->args, 1, &nick_len);
+  if (!nick) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
+                                         SILC_STATUS_ERR_BAD_NICKNAME, 0);
+    goto out;
+  }
   if (nick_len > 128)
     nick[128] = '\0';
   if (silc_server_name_bad_chars(nick, nick_len) == TRUE) {
@@ -823,7 +828,7 @@ SILC_SERVER_CMD_FUNC(list)
 
   /* If we are normal server, send the command to router, since we
      want to know all channels in the network. */
-  if (!cmd->pending && server->server_type == SILC_SERVER && 
+  if (!cmd->pending && server->server_type != SILC_ROUTER && 
       !server->standalone) {
     SilcBuffer tmpbuf;
     SilcUInt16 old_ident;
@@ -1016,10 +1021,12 @@ SILC_SERVER_CMD_FUNC(invite)
   SilcChannelEntry channel;
   SilcChannelID *channel_id = NULL;
   SilcIDListData idata;
-  SilcBuffer idp, idp2, packet;
-  unsigned char *tmp, *add, *del;
-  SilcUInt32 len;
-  SilcUInt16 ident = silc_command_get_ident(cmd->payload);
+  SilcArgumentPayload args;
+  SilcHashTableList htl;
+  SilcBuffer packet, list, tmp2;
+  unsigned char *tmp;
+  SilcUInt32 len, type;
+  SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload);
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4);
 
@@ -1073,7 +1080,6 @@ SILC_SERVER_CMD_FUNC(invite)
   /* Get destination client ID */
   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
   if (tmp) {
-    char invite[512];
     bool resolve;
 
     dest_id = silc_id_payload_parse_id(tmp, len, NULL);
@@ -1086,7 +1092,7 @@ SILC_SERVER_CMD_FUNC(invite)
     /* Get the client entry */
     dest = silc_server_query_client(server, dest_id, FALSE, &resolve);
     if (!dest) {
-      if (server->server_type != SILC_SERVER || !resolve) {
+      if (server->server_type != SILC_SERVER || !resolve || cmd->pending) {
        silc_server_command_send_status_reply(
                                        cmd, SILC_COMMAND_INVITE,
                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0);
@@ -1123,32 +1129,35 @@ SILC_SERVER_CMD_FUNC(invite)
       goto out;
     }
 
-    memset(invite, 0, sizeof(invite));
-    silc_strncat(invite, sizeof(invite),
-                dest->nickname, strlen(dest->nickname));
-    silc_strncat(invite, sizeof(invite), "!", 1);
-    silc_strncat(invite, sizeof(invite),
-                dest->username, strlen(dest->username));
-    if (!strchr(dest->username, '@')) {
-      silc_strncat(invite, sizeof(invite), "@", 1);
-      silc_strncat(invite, sizeof(invite), cmd->sock->hostname,
-                  strlen(cmd->sock->hostname));
-    }
+    /* Add the client to the invite list */
 
-    len = strlen(invite);
+    /* Allocate hash table for invite list if it doesn't exist yet */
     if (!channel->invite_list)
-      channel->invite_list = silc_calloc(len + 2, 
-                                        sizeof(*channel->invite_list));
-    else
-      channel->invite_list = silc_realloc(channel->invite_list, 
-                                         sizeof(*channel->invite_list) * 
-                                         (len + 
-                                          strlen(channel->invite_list) + 2));
-    strncat(channel->invite_list, invite, len);
-    strncat(channel->invite_list, ",", 1);
+      channel->invite_list =
+       silc_hash_table_alloc(0, silc_hash_ptr,
+                             NULL, NULL, NULL,
+                             silc_server_inviteban_destruct, channel, TRUE);
+
+    /* Check if the ID is in the list already */
+    silc_hash_table_list(channel->invite_list, &htl);
+    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) {
+      if (type == 3 && !memcmp(tmp2->data, tmp, len)) {
+       tmp = NULL;
+       break;
+      }
+    }
+    silc_hash_table_list_reset(&htl);
+
+    /* Add new Client ID to invite list */
+    if (tmp) {
+      list = silc_buffer_alloc_size(len);
+      silc_buffer_put(list, tmp, len);
+      silc_hash_table_add(channel->invite_list, (void *)3, list);
+    }
 
     if (!(dest->mode & SILC_UMODE_BLOCK_INVITE)) {
       /* Send notify to the client that is invited to the channel */
+      SilcBuffer idp, idp2;
       idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
       idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
       silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id, 
@@ -1163,71 +1172,95 @@ SILC_SERVER_CMD_FUNC(invite)
     }
   }
 
-  /* Add the client to the invite list of the channel */
-  add = silc_argument_get_arg_type(cmd->args, 3, &len);
-  if (add) {
-    if (!channel->invite_list)
-      channel->invite_list = silc_calloc(len + 2, 
-                                        sizeof(*channel->invite_list));
-    else
-      channel->invite_list = silc_realloc(channel->invite_list, 
-                                         sizeof(*channel->invite_list) * 
-                                         (len + 
-                                          strlen(channel->invite_list) + 2));
-    if (add[len - 1] == ',')
-      add[len - 1] = '\0';
-    
-    strncat(channel->invite_list, add, len);
-    strncat(channel->invite_list, ",", 1);
-  }
-
-  /* Get the invite to be removed and remove it from the list */
-  del = silc_argument_get_arg_type(cmd->args, 4, &len);
-  if (del && channel->invite_list) {
-    char *start, *end, *n;
+  /* Get the invite information */
+  tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
+  if (tmp && len > 2) {
+    /* Parse the arguments to see they are constructed correctly */
+    SILC_GET16_MSB(argc, tmp);
+    args = silc_argument_payload_parse(tmp + 2, len - 2, argc);
+    if (!args) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                           0);
+      goto out;
+    }
 
-    if (!strncmp(channel->invite_list, del, 
-                strlen(channel->invite_list) - 1)) {
-      silc_free(channel->invite_list);
-      channel->invite_list = NULL;
-    } else {
-      start = strstr(channel->invite_list, del);
-      if (start && strlen(start) >= len) {
-       end = start + len;
-       n = silc_calloc(strlen(channel->invite_list) - len, sizeof(*n));
-       strncat(n, channel->invite_list, start - channel->invite_list);
-       strncat(n, end + 1, ((channel->invite_list + 
-                             strlen(channel->invite_list)) - end) - 1);
-       silc_free(channel->invite_list);
-       channel->invite_list = n;
+    /* Get the type of action */
+    tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+    if (tmp && len == 1) {
+      if (tmp[0] == 0x00) {
+       /* Allocate hash table for invite list if it doesn't exist yet */
+       if (!channel->invite_list)
+         channel->invite_list =
+           silc_hash_table_alloc(0, silc_hash_ptr,
+                                 NULL, NULL, NULL,
+                                 silc_server_inviteban_destruct, channel,
+                                 TRUE);
+    
+       /* Check for resource limit */
+       if (silc_hash_table_count(channel->invite_list) > 64) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                               SILC_STATUS_ERR_RESOURCE_LIMIT,
+                                               0);
+         goto out;
+       }
       }
+
+      /* Now add or delete the information. */
+      silc_server_inviteban_process(server, channel->invite_list,
+                                   (SilcUInt8)tmp[0], args);
     }
+    silc_argument_payload_free(args);
+  }
+
+  /* Encode invite list */
+  list = NULL;
+  if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
+    list = silc_buffer_alloc_size(2);
+    silc_buffer_format(list,
+                      SILC_STR_UI_SHORT(silc_hash_table_count(
+                                         channel->invite_list)),
+                      SILC_STR_END);
+    silc_hash_table_list(channel->invite_list, &htl);
+    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) {
+      if (type == 1)
+       list = silc_argument_payload_encode_one(list, (char *)tmp2,
+                                               strlen((char *)tmp2), type);
+      else
+       list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
+                                               type);
+    }
+    silc_hash_table_list_reset(&htl);
   }
 
   /* Send notify to the primary router */
-  silc_server_send_notify_invite(server, SILC_PRIMARY_ROUTE(server),
-                                SILC_BROADCAST(server), channel,
-                                sender->id, add, del);
+  silc_server_send_notify_invite(
+                        server, SILC_PRIMARY_ROUTE(server),
+                        SILC_BROADCAST(server), channel, sender->id,
+                        silc_argument_get_arg_type(cmd->args, 3, NULL),
+                        list);
+
+  /* Send invite list back only if the list was modified, or now arguments
+     was given. */
+  type = 0;
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc == 1)
+    type = 1;
+  if (silc_argument_get_arg_type(cmd->args, 3, &len))
+    type = 1;
 
   /* Send command reply */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
-
-  if (add || del)
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
-                                          SILC_STATUS_OK, 0, ident, 2,
-                                          2, tmp, len,
-                                          3, channel->invite_list,
-                                          channel->invite_list ?
-                                          strlen(channel->invite_list) : 0);
-  else
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
-                                          SILC_STATUS_OK, 0, ident, 1,
-                                          2, tmp, len);
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
+                                               SILC_STATUS_OK, 0, ident, 2,
+                                               2, tmp, len,
+                                               3, type && list ? 
+                                               list->data : NULL,
+                                               type && list ? list->len : 0);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
+  silc_buffer_free(list);
 
  out:
   silc_free(dest_id);
@@ -1305,28 +1338,34 @@ SILC_SERVER_CMD_FUNC(kill)
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   SilcClientEntry remote_client;
-  SilcClientID *client_id;
-  unsigned char *tmp, *comment;
-  SilcUInt32 tmp_len, tmp_len2;
-  bool local;
+  SilcClientID *client_id = NULL;
+  unsigned char *tmp, *comment, *auth;
+  SilcUInt32 tmp_len, tmp_len2, auth_len;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 3);
 
   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
 
-  /* KILL command works only on router */
-  if (server->server_type != SILC_ROUTER) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
-                                         SILC_STATUS_ERR_NO_ROUTER_PRIV, 0);
-    goto out;
-  }
+  /* Get authentication payload if present */
+  auth = silc_argument_get_arg_type(cmd->args, 3, &auth_len);
 
-  /* Check whether client has the permissions. */
-  if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
-                                         SILC_STATUS_ERR_NO_ROUTER_PRIV, 0);
-    goto out;
+  if (!auth) {
+    /* Router operator killing */
+
+    /* KILL command works only on router */
+    if (server->server_type != SILC_ROUTER) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                           SILC_STATUS_ERR_NO_ROUTER_PRIV, 0);
+      goto out;
+    }
+
+    /* Check whether client has the permissions. */
+    if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                           SILC_STATUS_ERR_NO_ROUTER_PRIV, 0);
+      goto out;
+    }
   }
 
   /* Get the client ID */
@@ -1348,11 +1387,9 @@ SILC_SERVER_CMD_FUNC(kill)
   /* Get the client entry */
   remote_client = silc_idlist_find_client_by_id(server->local_list, 
                                                client_id, TRUE, NULL);
-  local = TRUE;
   if (!remote_client) {
     remote_client = silc_idlist_find_client_by_id(server->global_list, 
                                                  client_id, TRUE, NULL);
-    local = FALSE;
     if (!remote_client) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
@@ -1363,23 +1400,66 @@ SILC_SERVER_CMD_FUNC(kill)
 
   /* Get comment */
   comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
-  if (tmp_len2 > 128)
+  if (comment && tmp_len2 > 128) {
     tmp_len2 = 128;
+    comment[127] = '\0';
+  }
 
-  /* Send reply to the sender */
-  silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
-                                       SILC_STATUS_OK, 0);
+  /* If authentication data is provided then verify that killing is
+     actually allowed */
+  if (auth && auth_len) {
+    SilcSocketConnection sock;
 
-  /* Check if anyone is watching this nickname */
-  if (server->server_type == SILC_ROUTER)
-    silc_server_check_watcher_list(server, client, NULL,
-                                  SILC_NOTIFY_TYPE_KILLED);
+    if (!SILC_IS_LOCAL(remote_client) || !remote_client->data.public_key) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                           SILC_STATUS_ERR_OPERATION_ALLOWED,
+                                           0);
+      goto out;
+    }
+
+    /* Verify the signature */
+    if (!silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
+                              remote_client->data.public_key, 0,
+                              server->sha1hash, remote_client->id,
+                              SILC_ID_CLIENT)) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                           SILC_STATUS_ERR_AUTH_FAILED,
+                                           0);
+      goto out;
+    }
+
+    /* Send reply to the sender */
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                         SILC_STATUS_OK, 0);
+
+    /* Do normal signoff for the destination client */
+    sock = remote_client->connection;
+    silc_server_remove_from_channels(server, NULL, remote_client,
+                                    TRUE, (char *)"Killed", TRUE, TRUE);
+    silc_server_free_client_data(server, NULL, remote_client, TRUE,
+                                comment ? comment :
+                                (unsigned char *)"Killed");
+    if (sock)
+      silc_server_close_connection(server, sock);
+  } else {
+    /* Router operator killing */
+
+    /* Send reply to the sender */
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                         SILC_STATUS_OK, 0);
 
-  /* Now do the killing */
-  silc_server_kill_client(server, remote_client, comment, client->id,
-                         SILC_ID_CLIENT);
+    /* Check if anyone is watching this nickname */
+    if (server->server_type == SILC_ROUTER)
+      silc_server_check_watcher_list(server, client, NULL,
+                                    SILC_NOTIFY_TYPE_KILLED);
+
+    /* Now do the killing */
+    silc_server_kill_client(server, remote_client, comment, client->id,
+                           SILC_ID_CLIENT);
+  }
 
  out:
+  silc_free(client_id);
   silc_server_command_free(cmd);
 }
 
@@ -1551,24 +1631,24 @@ SILC_SERVER_CMD_FUNC(ping)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  SilcServerID *id;
-  SilcUInt32 len;
+  SilcUInt32 tmp_len;
   unsigned char *tmp;
+  SilcServerID *server_id = NULL;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PING, cmd, 1, 1);
 
   /* Get Server ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   if (!tmp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
                                          SILC_STATUS_ERR_NO_SERVER_ID, 0);
     goto out;
   }
-  id = silc_id_str2id(tmp, len, SILC_ID_SERVER);
-  if (!id)
+  server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+  if (!server_id)
     goto out;
 
-  if (SILC_ID_SERVER_COMPARE(id, server->id)) {
+  if (SILC_ID_SERVER_COMPARE(server_id, server->id)) {
     /* Send our reply */
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
                                          SILC_STATUS_OK, 0);
@@ -1578,9 +1658,8 @@ SILC_SERVER_CMD_FUNC(ping)
     goto out;
   }
 
-  silc_free(id);
-
  out:
+  silc_free(server_id);
   silc_server_command_free(cmd);
 }
 
@@ -1602,7 +1681,7 @@ SILC_SERVER_CMD_FUNC(stats)
   /* Get Server ID */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   if (!tmp) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
                                          SILC_STATUS_ERR_NO_SERVER_ID, 0);
     goto out;
   }
@@ -1612,7 +1691,7 @@ SILC_SERVER_CMD_FUNC(stats)
 
   /* The ID must be ours */
   if (!SILC_ID_SERVER_COMPARE(server->id, server_id)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
                                          SILC_STATUS_ERR_NO_SUCH_SERVER, 0);
     silc_free(server_id);
     goto out;
@@ -1700,13 +1779,14 @@ static void silc_server_command_join_channel(SilcServer server,
   unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4];
   SilcClientEntry client;
   SilcChannelClientEntry chl;
-  SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
+  SilcBuffer reply, chidp, clidp, keyp = NULL;
+  SilcBuffer user_list, mode_list, invite_list, ban_list;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   char check[512], check2[512];
   bool founder = FALSE;
   bool resolve;
-  unsigned char *fkey = NULL;
-  SilcUInt32 fkey_len = 0;
+  SilcBuffer fkey = NULL;
+  const char *cipher;
 
   SILC_LOG_DEBUG(("Joining client to channel"));
 
@@ -1722,10 +1802,7 @@ static void silc_server_command_join_channel(SilcServer server,
     client = silc_server_query_client(server, client_id, FALSE, 
                                      &resolve);
     if (!client) {
-      if (cmd->pending)
-       goto out;
-
-      if (!resolve) {
+      if (!resolve || cmd->pending) {
        silc_server_command_send_status_reply(
                                         cmd, SILC_COMMAND_JOIN,
                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
@@ -1742,6 +1819,25 @@ static void silc_server_command_join_channel(SilcServer server,
       goto out;
     }
 
+    if (auth && auth_len && !client->data.public_key) {
+      if (cmd->pending == 2)
+       goto out;
+
+      /* We must retrieve the detached client's public key by sending
+        GETKEY command. Reprocess this packet after receiving the key */
+      clidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+      silc_server_send_command(server, cmd->sock,
+                              SILC_COMMAND_GETKEY, ++server->cmd_ident,
+                              1, 1, clidp->data, clidp->len);
+      silc_buffer_free(clidp);
+      silc_server_command_pending(server, SILC_COMMAND_GETKEY,
+                                 server->cmd_ident,
+                                 silc_server_command_join, 
+                                 silc_server_command_dup(cmd));
+      cmd->pending = 2;
+      goto out;
+    }
+
     cmd->pending = FALSE;
   }
 
@@ -1818,8 +1914,15 @@ static void silc_server_command_join_channel(SilcServer server,
     /* Check invite list if channel is invite-only channel */
     if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
       if (!channel->invite_list ||
-         (!silc_string_match(channel->invite_list, check) &&
-          !silc_string_match(channel->invite_list, check2))) {
+         !silc_hash_table_count(channel->invite_list) ||
+         (!silc_server_inviteban_match(server, channel->invite_list,
+                                       3, client->id) &&
+          !silc_server_inviteban_match(server, channel->invite_list,
+                                       2, client->data.public_key) &&
+          !silc_server_inviteban_match(server, channel->invite_list,
+                                       1, check) &&
+          !silc_server_inviteban_match(server, channel->invite_list,
+                                       1, check2))) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                              SILC_STATUS_ERR_NOT_INVITED, 0);
        goto out;
@@ -1829,9 +1932,15 @@ static void silc_server_command_join_channel(SilcServer server,
     /* Check ban list if it exists. If the client's nickname, server,
        username and/or hostname is in the ban list the access to the
        channel is denied. */
-    if (channel->ban_list) {
-      if (silc_string_match(channel->ban_list, check) ||
-         silc_string_match(channel->ban_list, check2)) {
+    if (channel->ban_list && silc_hash_table_count(channel->ban_list)) {
+      if (silc_server_inviteban_match(server, channel->ban_list,
+                                     3, client->id) ||
+         silc_server_inviteban_match(server, channel->ban_list,
+                                     2, client->data.public_key) ||
+         silc_server_inviteban_match(server, channel->ban_list,
+                                     1, check) ||
+         silc_server_inviteban_match(server, channel->ban_list,
+                                     1, check2)) {
        silc_server_command_send_status_reply(
                                      cmd, SILC_COMMAND_JOIN,
                                      SILC_STATUS_ERR_BANNED_FROM_CHANNEL, 0);
@@ -1917,18 +2026,69 @@ static void silc_server_command_join_channel(SilcServer server,
 
   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
     tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+    cipher = silc_cipher_get_name(channel->channel_key);
     keyp = silc_channel_key_payload_encode(silc_id_get_len(channel->id,
                                                           SILC_ID_CHANNEL), 
                                           tmp,
-                                          strlen(channel->channel_key->
-                                                 cipher->name),
-                                          channel->channel_key->cipher->name,
+                                          strlen(cipher), cipher,
                                           channel->key_len / 8, channel->key);
     silc_free(tmp);
   }
 
   if (channel->founder_key)
-    fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len);
+    fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+
+  /* Encode invite list */
+  invite_list = NULL;
+  if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
+    SilcHashTableList htl;
+
+    invite_list = silc_buffer_alloc_size(2);
+    silc_buffer_format(invite_list,
+                      SILC_STR_UI_SHORT(silc_hash_table_count(
+                                         channel->invite_list)),
+                      SILC_STR_END);
+
+    silc_hash_table_list(channel->invite_list, &htl);
+    while (silc_hash_table_get(&htl, (void **)&tmp_len, (void **)&reply)) {
+      if (tmp_len == 1)
+       invite_list = silc_argument_payload_encode_one(invite_list,
+                                                      (char *)reply,
+                                                      strlen((char *)reply),
+                                                      tmp_len);
+      else
+       invite_list = silc_argument_payload_encode_one(invite_list,
+                                                      reply->data,
+                                                      reply->len, tmp_len);
+    }
+    silc_hash_table_list_reset(&htl);
+  }
+
+  /* Encode ban list */
+  ban_list = NULL;
+  if (channel->ban_list && silc_hash_table_count(channel->ban_list)) {
+    SilcHashTableList htl;
+
+    ban_list = silc_buffer_alloc_size(2);
+    silc_buffer_format(ban_list,
+                      SILC_STR_UI_SHORT(silc_hash_table_count(
+                                         channel->ban_list)),
+                      SILC_STR_END);
+
+    silc_hash_table_list(channel->ban_list, &htl);
+    while (silc_hash_table_get(&htl, (void **)&tmp_len, (void **)&reply)) {
+      if (tmp_len == 1)
+       ban_list = silc_argument_payload_encode_one(ban_list,
+                                                   (char *)reply,
+                                                   strlen((char *)reply),
+                                                   tmp_len);
+      else
+       ban_list = silc_argument_payload_encode_one(ban_list,
+                                                   reply->data,
+                                                   reply->len, tmp_len);
+    }
+    silc_hash_table_list_reset(&htl);
+  }
 
   reply = 
     silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
@@ -1941,12 +2101,11 @@ static void silc_server_command_join_channel(SilcServer server,
                                         6, tmp2, 4,
                                         7, keyp ? keyp->data : NULL, 
                                         keyp ? keyp->len : 0,
-                                        8, channel->ban_list, 
-                                        channel->ban_list ?
-                                        strlen(channel->ban_list) : 0,
-                                        9, channel->invite_list,
-                                        channel->invite_list ?
-                                        strlen(channel->invite_list) : 0,
+                                        8, ban_list ? ban_list->data : NULL,
+                                        ban_list ? ban_list->len : 0,
+                                        9, invite_list ? invite_list->data :
+                                        NULL,
+                                        invite_list ? invite_list->len : 0,
                                         10, channel->topic,
                                         channel->topic ?
                                         strlen(channel->topic) : 0,
@@ -1957,7 +2116,8 @@ static void silc_server_command_join_channel(SilcServer server,
                                         13, user_list->data, user_list->len,
                                         14, mode_list->data, 
                                         mode_list->len,
-                                        15, fkey, fkey_len);
+                                        15, fkey ? fkey->data : NULL,
+                                        fkey ? fkey->len : 0);
 
   /* Send command reply */
   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
@@ -2001,7 +2161,8 @@ static void silc_server_command_join_channel(SilcServer server,
                                         SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
                                         clidp->data, clidp->len,
                                         mode, 4, clidp->data, clidp->len,
-                                        fkey, fkey_len);
+                                        fkey ? fkey->data : NULL,
+                                        fkey ? fkey->len : 0);
     }
   }
 
@@ -2018,7 +2179,9 @@ static void silc_server_command_join_channel(SilcServer server,
   silc_buffer_free(keyp);
   silc_buffer_free(user_list);
   silc_buffer_free(mode_list);
-  silc_free(fkey);
+  silc_buffer_free(fkey);
+  silc_buffer_free(invite_list);
+  silc_buffer_free(ban_list);
 
  out:
   silc_free(passphrase);
@@ -2377,7 +2540,7 @@ SILC_SERVER_CMD_FUNC(motd)
     }
 
     if (!entry) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
                                            SILC_STATUS_ERR_NO_SUCH_SERVER, 0);
       goto out;
     }
@@ -2503,15 +2666,14 @@ SILC_SERVER_CMD_FUNC(cmode)
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   bool set_mask = FALSE;
   SilcPublicKey founder_key = NULL;
-  unsigned char *fkey = NULL;
-  SilcUInt32 fkey_len = 0;
+  SilcBuffer fkey = NULL;
 
   if (!client) {
     silc_server_command_free(cmd);
     return;
   }
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 1, 7);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 1, 8);
 
   /* Get Channel ID */
   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
@@ -2611,8 +2773,8 @@ SILC_SERVER_CMD_FUNC(cmode)
       silc_server_send_channel_key(server, NULL, channel, 
                                   server->server_type == SILC_ROUTER ? 
                                   FALSE : !server->standalone);
-       
-      cipher = channel->channel_key->cipher->name;
+
+      cipher = (char *)silc_cipher_get_name(channel->channel_key);
       hmac = (char *)silc_hmac_get_name(channel->hmac);
     }
   }
@@ -2800,46 +2962,66 @@ SILC_SERVER_CMD_FUNC(cmode)
 
   if (mode_mask & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
-      if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
-       /* Set the founder authentication */
-       tmp = silc_argument_get_arg_type(cmd->args, 7, &tmp_len);
-       if (!tmp) {
-         silc_server_command_send_status_reply(
-                                    cmd, SILC_COMMAND_CMODE,
-                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
-         goto out;
-       }
-
-       /* Verify the payload before setting the mode */
-       if (!silc_auth_verify_data(tmp, tmp_len, SILC_AUTH_PUBLIC_KEY, 
-                                  idata->public_key, 0, server->sha1hash,
-                                  client->id, SILC_ID_CLIENT)) {
+      /* Check if the founder public key was received */
+      founder_key = idata->public_key;
+      tmp = silc_argument_get_arg_type(cmd->args, 8, &tmp_len);
+      if (tmp) {
+       if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
          silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                                SILC_STATUS_ERR_AUTH_FAILED,
                                                0);
          goto out;
        }
+      } else {
+       /* If key was not sent and the channel mode has already founder
+          then the key was not to be changed. */
+       if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
+         goto has_founder;
+      }
 
-       /* Save the public key */
-       channel->founder_key = silc_pkcs_public_key_copy(idata->public_key);
-        if (!channel->founder_key) {
-         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                               SILC_STATUS_ERR_AUTH_FAILED,
-                                               0);
-         goto out;
-        }
+      /* Set the founder authentication */
+      tmp = silc_argument_get_arg_type(cmd->args, 7, &tmp_len);
+      if (!tmp) {
+       silc_server_command_send_status_reply(
+                                    cmd, SILC_COMMAND_CMODE,
+                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+       goto out;
+      }
 
-       founder_key = channel->founder_key;
-       fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len);
-        if (!fkey) {
-         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                               SILC_STATUS_ERR_AUTH_FAILED,
-                                               0);
-         silc_pkcs_public_key_free(channel->founder_key);
-         channel->founder_key = NULL;
-         goto out;
-        }
+      /* Verify the payload before setting the mode */
+      if (!silc_auth_verify_data(tmp, tmp_len, SILC_AUTH_PUBLIC_KEY, 
+                                founder_key, 0, server->sha1hash,
+                                client->id, SILC_ID_CLIENT)) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_AUTH_FAILED,
+                                             0);
+       goto out;
+      }
+
+      /* Save the public key */
+      if (channel->founder_key)
+       silc_pkcs_public_key_free(channel->founder_key);
+      if (silc_argument_get_arg_type(cmd->args, 8, NULL))
+       channel->founder_key = founder_key;
+      else
+       channel->founder_key = silc_pkcs_public_key_copy(founder_key);
+      if (!channel->founder_key) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_AUTH_FAILED,
+                                             0);
+       goto out;
+      }
+
+      fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+      if (!fkey) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_AUTH_FAILED,
+                                             0);
+       silc_pkcs_public_key_free(channel->founder_key);
+       channel->founder_key = NULL;
+       goto out;
       }
+    has_founder:
     }
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
@@ -2864,7 +3046,8 @@ SILC_SERVER_CMD_FUNC(cmode)
                                     hmac, hmac ? strlen(hmac) : 0,
                                     passphrase, passphrase ? 
                                     strlen(passphrase) : 0,
-                                    fkey, fkey_len);
+                                    fkey ? fkey->data : NULL,
+                                    fkey ? fkey->len : 0);
 
   /* Set CMODE notify type to network */
   silc_server_send_notify_cmode(server, SILC_PRIMARY_ROUTE(server),
@@ -2874,9 +3057,11 @@ SILC_SERVER_CMD_FUNC(cmode)
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
-                                               SILC_STATUS_OK, 0, ident, 2,
+                                               SILC_STATUS_OK, 0, ident, 3,
                                                2, tmp_id, tmp_len2,
-                                               3, tmp_mask, 4);
+                                               3, tmp_mask, 4,
+                                               4, fkey ? fkey->data : NULL,
+                                               fkey ? fkey->len : 0);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
 
@@ -2885,7 +3070,7 @@ SILC_SERVER_CMD_FUNC(cmode)
 
  out:
   channel->mode = old_mask;
-  silc_free(fkey);
+  silc_buffer_free(fkey);
   silc_free(channel_id);
   silc_server_command_free(cmd);
 }
@@ -2897,9 +3082,8 @@ SILC_SERVER_CMD_FUNC(cumode)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  SilcIDListData idata = (SilcIDListData)client;
-  SilcChannelID *channel_id;
-  SilcClientID *client_id;
+  SilcChannelID *channel_id = NULL;
+  SilcClientID *client_id = NULL;
   SilcChannelEntry channel;
   SilcClientEntry target_client;
   SilcChannelClientEntry chl;
@@ -2909,8 +3093,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   int notify = FALSE;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   SilcPublicKey founder_key = NULL;
-  unsigned char *fkey = NULL;
-  SilcUInt32 fkey_len = 0;
+  SilcBuffer fkey = NULL;
 
   if (!client)
     goto out;
@@ -3030,9 +3213,7 @@ SILC_SERVER_CMD_FUNC(cumode)
       SilcHashTableList htl;
 
       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
-         !channel->founder_key || !idata->public_key ||
-         !silc_pkcs_public_key_compare(channel->founder_key, 
-                                       idata->public_key)) {
+         !channel->founder_key) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                              SILC_STATUS_ERR_AUTH_FAILED, 0);
        goto out;
@@ -3056,7 +3237,7 @@ SILC_SERVER_CMD_FUNC(cumode)
 
       notify = TRUE;
       founder_key = channel->founder_key;
-      fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len);
+      fkey = silc_pkcs_public_key_payload_encode(founder_key);
       if (!fkey) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                              SILC_STATUS_ERR_AUTH_FAILED, 0);
@@ -3225,7 +3406,8 @@ SILC_SERVER_CMD_FUNC(cumode)
                                       idp->data, idp->len,
                                       tmp_mask, 4, 
                                       tmp_id, tmp_len,
-                                      fkey, fkey_len);
+                                      fkey ? fkey->data : NULL,
+                                      fkey ? fkey->len : 0);
 
     /* Set CUMODE notify type to network */
     silc_server_send_notify_cumode(server, SILC_PRIMARY_ROUTE(server),
@@ -3244,12 +3426,12 @@ SILC_SERVER_CMD_FUNC(cumode)
                          packet->data, packet->len, FALSE);
     
   silc_buffer_free(packet);
-  silc_free(channel_id);
-  silc_free(client_id);
   silc_buffer_free(idp);
 
  out:
-  silc_free(fkey);
+  silc_free(channel_id);
+  silc_free(client_id);
+  silc_buffer_free(fkey);
   silc_server_command_free(cmd);
 }
 
@@ -3380,6 +3562,17 @@ SILC_SERVER_CMD_FUNC(kick)
                                 SILC_BROADCAST(server), channel,
                                 target_client->id, client->id, comment);
 
+  /* Remove the client from channel's invite list */
+  if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
+    SilcBuffer ab =
+      silc_argument_payload_encode_one(NULL, target_idp, target_idp_len, 3);
+    SilcArgumentPayload args =
+      silc_argument_payload_parse(ab->data, ab->len, 1);
+    silc_server_inviteban_process(server, channel->invite_list, 1, args);
+    silc_buffer_free(ab);
+    silc_argument_payload_free(args);
+  }
+
   /* Remove the client from the channel. If the channel does not exist
      after removing the client then the client kicked itself off the channel
      and we don't have to send anything after that. */
@@ -3442,6 +3635,9 @@ SILC_SERVER_CMD_FUNC(oper)
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
                                            SILC_STATUS_ERR_AUTH_FAILED,
                                            0);
+      SILC_LOG_INFO(("OPER authentication failed for username '%s' by "
+                    "nickname '%s' from %s", username,
+                    client->nickname, cmd->sock->hostname));
       goto out;
     }
   }
@@ -3563,7 +3759,8 @@ SILC_SERVER_CMD_FUNC(detach)
 
   if (server->config->detach_disabled) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_DETACH,
-                                         SILC_STATUS_ERR_UNKNOWN_COMMAND, 0);
+                                         SILC_STATUS_ERR_OPERATION_ALLOWED,
+                                         0);
     goto out;
   }
 
@@ -3630,12 +3827,14 @@ SILC_SERVER_CMD_FUNC(watch)
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WATCH, cmd, 1, 3);
 
-  if (server->server_type == SILC_SERVER && !server->standalone) {
+  if (server->server_type != SILC_ROUTER && !server->standalone) {
     if (!cmd->pending) {
       /* Send the command to router */
       SilcBuffer tmpbuf;
       SilcUInt16 old_ident;
 
+      SILC_LOG_DEBUG(("Forwarding WATCH to router"));
+
       old_ident = silc_command_get_ident(cmd->payload);
       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
@@ -3656,6 +3855,8 @@ SILC_SERVER_CMD_FUNC(watch)
       /* Received reply from router, just send same data to the client. */
       SilcServerCommandReplyContext reply = context2;
       SilcStatus status;
+
+      SILC_LOG_DEBUG(("Received reply to WATCH from router"));
       silc_command_get_status(reply->payload, &status, NULL);
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, status,
                                            0);
@@ -3835,6 +4036,9 @@ SILC_SERVER_CMD_FUNC(silcoper)
     if (!admin) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
                                            SILC_STATUS_ERR_AUTH_FAILED, 0);
+      SILC_LOG_INFO(("SILCOPER authentication failed for username '%s' by "
+                    "nickname '%s' from %s", username,
+                    client->nickname, cmd->sock->hostname));
       goto out;
     }
   }
@@ -3904,13 +4108,16 @@ SILC_SERVER_CMD_FUNC(ban)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  SilcBuffer packet;
+  SilcBuffer packet, list, tmp2;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcChannelID *channel_id = NULL;
-  unsigned char *id, *add, *del;
-  SilcUInt32 id_len, tmp_len;
-  SilcUInt16 ident = silc_command_get_ident(cmd->payload);
+  unsigned char *id, *tmp;
+  SilcUInt32 id_len, len;
+  SilcArgumentPayload args;
+  SilcHashTableList htl;
+  SilcUInt32 type;
+  SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload);
 
   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
@@ -3957,62 +4164,86 @@ SILC_SERVER_CMD_FUNC(ban)
     goto out;
   }
 
-  /* Get the new ban and add it to the ban list */
-  add = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (add) {
-    if (!channel->ban_list)
-      channel->ban_list = silc_calloc(tmp_len + 2, sizeof(*channel->ban_list));
-    else
-      channel->ban_list = silc_realloc(channel->ban_list, 
-                                      sizeof(*channel->ban_list) * 
-                                      (tmp_len + 
-                                       strlen(channel->ban_list) + 2));
-    if (add[tmp_len - 1] == ',')
-      add[tmp_len - 1] = '\0';
-
-    strncat(channel->ban_list, add, tmp_len);
-    strncat(channel->ban_list, ",", 1);
-  }
-
-  /* Get the ban to be removed and remove it from the list */
-  del = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
-  if (del && channel->ban_list) {
-    char *start, *end, *n;
+  /* Get the ban information */
+  tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+  if (tmp && len > 2) {
+    /* Parse the arguments to see they are constructed correctly */
+    SILC_GET16_MSB(argc, tmp);
+    args = silc_argument_payload_parse(tmp + 2, len - 2, argc);
+    if (!args) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                           0);
+      goto out;
+    }
 
-    if (!strncmp(channel->ban_list, del, strlen(channel->ban_list) - 1)) {
-      silc_free(channel->ban_list);
-      channel->ban_list = NULL;
-    } else {
-      start = strstr(channel->ban_list, del);
-      if (start && strlen(start) >= tmp_len) {
-       end = start + tmp_len;
-       n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n));
-       strncat(n, channel->ban_list, start - channel->ban_list);
-       strncat(n, end + 1, ((channel->ban_list + strlen(channel->ban_list)) - 
-                            end) - 1);
-       silc_free(channel->ban_list);
-       channel->ban_list = n;
+    /* Get the type of action */
+    tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+    if (tmp && len == 1) {
+      if (tmp[0] == 0x00) {
+       /* Allocate hash table for ban list if it doesn't exist yet */
+       if (!channel->ban_list)
+         channel->ban_list =
+           silc_hash_table_alloc(0, silc_hash_ptr,
+                                 NULL, NULL, NULL,
+                                 silc_server_inviteban_destruct, channel,
+                                 TRUE);
+    
+       /* Check for resource limit */
+       if (silc_hash_table_count(channel->ban_list) > 64) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+                                               SILC_STATUS_ERR_RESOURCE_LIMIT,
+                                               0);
+         goto out;
+       }
       }
+
+      /* Now add or delete the information. */
+      silc_server_inviteban_process(server, channel->ban_list,
+                                   (SilcUInt8)tmp[0], args);
     }
+    silc_argument_payload_free(args);
+  }
+
+  /* Encode ban list */
+  list = NULL;
+  if (channel->ban_list && silc_hash_table_count(channel->ban_list)) {
+    list = silc_buffer_alloc_size(2);
+    silc_buffer_format(list,
+                      SILC_STR_UI_SHORT(silc_hash_table_count(
+                                         channel->ban_list)),
+                      SILC_STR_END);
+    silc_hash_table_list(channel->ban_list, &htl);
+    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) {
+      if (type == 1)
+       list = silc_argument_payload_encode_one(list, (char *)tmp2,
+                                               strlen((char *)tmp2), type);
+      else
+       list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
+                                               type);
+    }
+    silc_hash_table_list_reset(&htl);
   }
 
   /* Send the BAN notify type to our primary router. */
-  if (add || del)
+  if (list)
     silc_server_send_notify_ban(server, SILC_PRIMARY_ROUTE(server),
-                               SILC_BROADCAST(server), channel, add, del);
+                               SILC_BROADCAST(server), channel,
+                               silc_argument_get_arg_type(cmd->args, 2, NULL),
+                               list);
 
   /* Send the reply back to the client */
   packet = 
     silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
                                         SILC_STATUS_OK, 0, ident, 2,
                                         2, id, id_len,
-                                        3, channel->ban_list, 
-                                        channel->ban_list ? 
-                                        strlen(channel->ban_list) -1 : 0);
+                                        3, list ? list->data : NULL,
+                                        list ? list->len : 0);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
   silc_buffer_free(packet);
+  silc_buffer_free(list);
 
  out:
   silc_free(channel_id);
@@ -4138,7 +4369,7 @@ SILC_SERVER_CMD_FUNC(users)
     id = silc_id_payload_parse_id(channel_id, channel_id_len, NULL);
     if (!id) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
-                                           SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
+                                           SILC_STATUS_ERR_BAD_CHANNEL_ID, 0);
       goto out;
     }
   }
@@ -4260,8 +4491,8 @@ SILC_SERVER_CMD_FUNC(getkey)
   SilcServerID *server_id = NULL;
   SilcIDPayload idp = NULL;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-  unsigned char *tmp, *pkdata;
-  SilcUInt32 tmp_len, pklen;
+  unsigned char *tmp;
+  SilcUInt32 tmp_len;
   SilcBuffer pk = NULL;
   SilcIdType id_type;
   SilcPublicKey public_key;
@@ -4336,22 +4567,8 @@ SILC_SERVER_CMD_FUNC(getkey)
        send it back. If they key does not exist then do not send it, 
        send just OK reply */
     public_key = client->data.public_key;
-    if (!public_key) {
-      pkdata = NULL;
-      pklen = 0;
-    } else {
-      tmp = silc_pkcs_public_key_encode(public_key, &tmp_len);
-      pk = silc_buffer_alloc(4 + tmp_len);
-      silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
-      silc_buffer_format(pk,
-                        SILC_STR_UI_SHORT(tmp_len),
-                        SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
-                        SILC_STR_UI_XNSTRING(tmp, tmp_len),
-                        SILC_STR_END);
-      silc_free(tmp);
-      pkdata = pk->data;
-      pklen = pk->len;
-    }
+    if (public_key)
+      pk = silc_pkcs_public_key_payload_encode(public_key);
   } else if (id_type == SILC_ID_SERVER) {
     server_id = silc_id_payload_get_id(idp);
 
@@ -4402,42 +4619,26 @@ SILC_SERVER_CMD_FUNC(getkey)
     public_key = (!server_entry->data.public_key ? 
                  (server_entry == server->id_entry ? server->public_key :
                   NULL) : server_entry->data.public_key);
-    if (!public_key) {
-      pkdata = NULL;
-      pklen = 0;
-    } else {
-      tmp = silc_pkcs_public_key_encode(public_key, &tmp_len);
-      pk = silc_buffer_alloc(4 + tmp_len);
-      silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
-      silc_buffer_format(pk,
-                        SILC_STR_UI_SHORT(tmp_len),
-                        SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
-                        SILC_STR_UI_XNSTRING(tmp, tmp_len),
-                        SILC_STR_END);
-      silc_free(tmp);
-      pkdata = pk->data;
-      pklen = pk->len;
-    }
+    if (public_key)
+      pk = silc_pkcs_public_key_payload_encode(public_key);
   } else {
     goto out;
   }
 
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_GETKEY,
-                                               SILC_STATUS_OK, 0, ident, 
-                                               pkdata ? 2 : 1,
+                                               SILC_STATUS_OK, 0, ident, 2,
                                                2, tmp, tmp_len,
-                                               3, pkdata, pklen);
+                                               3, pk ? pk->data : NULL,
+                                               pk ? pk->len : 0);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
 
-  if (pk)
-    silc_buffer_free(pk);
-
  out:
   if (idp)
     silc_id_payload_free(idp);
+  silc_buffer_free(pk);
   silc_free(client_id);
   silc_free(server_id);
   silc_server_command_free(cmd);
@@ -4471,7 +4672,7 @@ SILC_SERVER_CMD_FUNC(connect)
     goto out;
   }
 
-  if (server->server_type == SILC_ROUTER && 
+  if (server->server_type == SILC_ROUTER && !server->backup_router &&
       client->mode & SILC_UMODE_SERVER_OPERATOR) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
                                          SILC_STATUS_ERR_NO_ROUTER_PRIV, 0);