updates.
[silc.git] / apps / silcd / command.c
index d60bf2c65553fe572b17e0007257b260b9f075b1..f3eab682ae4f142dc51827ce5c2976726b25ccf0 100644 (file)
@@ -675,6 +675,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   uint16 ident = silc_command_get_ident(cmd->payload);
   char nh[256], uh[256];
   unsigned char idle[4], mode[4];
+  unsigned char *fingerprint;
   SilcSocketConnection hsock;
 
   len = 0;
@@ -772,6 +773,11 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
     }
 
     channels = silc_server_get_client_channel_list(server, entry);
+
+    if (entry->data.fingerprint[0] != 0 && entry->data.fingerprint[1] != 0)
+      fingerprint = entry->data.fingerprint;
+    else
+      fingerprint = NULL;
       
     SILC_PUT32_MSB(entry->mode, mode);
 
@@ -779,29 +785,21 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
       SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
     }
 
-    if (channels)
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
-                                                   status, ident, 7, 
-                                                   2, idp->data, idp->len,
-                                                   3, nh, strlen(nh),
-                                                   4, uh, strlen(uh),
-                                                   5, entry->userinfo, 
-                                                   strlen(entry->userinfo),
-                                                   6, channels->data,
-                                                   channels->len,
-                                                   7, mode, 4,
-                                                   8, idle, 4);
-    else
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
-                                                   status, ident, 6, 
-                                                   2, idp->data, idp->len,
-                                                   3, nh, strlen(nh),
-                                                   4, uh, strlen(uh),
-                                                   5, entry->userinfo, 
-                                                   strlen(entry->userinfo),
-                                                   7, mode, 4,
-                                                   8, idle, 4);
-    
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+                                          status, ident, 8, 
+                                          2, idp->data, idp->len,
+                                          3, nh, strlen(nh),
+                                          4, uh, strlen(uh),
+                                          5, entry->userinfo, 
+                                          strlen(entry->userinfo),
+                                          6, channels ? channels->data : NULL,
+                                          channels ? channels->len : 0,
+                                          7, mode, 4,
+                                          8, idle, 4,
+                                          9, fingerprint,
+                                          fingerprint ? 20 : 0);
+
     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                            0, packet->data, packet->len, FALSE);
     
@@ -837,7 +835,7 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
     uint16 old_ident;
 
     old_ident = silc_command_get_ident(cmd->payload);
-    silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+    silc_command_set_ident(cmd->payload, ++server->cmd_ident);
     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
     /* Send WHOIS command to our router */
@@ -1021,7 +1019,7 @@ silc_server_command_whowas_check(SilcServerCommandContext cmd,
        continue;
       
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       /* Send WHOWAS command */
@@ -1172,7 +1170,7 @@ silc_server_command_whowas_process(SilcServerCommandContext cmd)
     uint16 old_ident;
 
     old_ident = silc_command_get_ident(cmd->payload);
-    silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+    silc_command_set_ident(cmd->payload, ++server->cmd_ident);
     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
     /* Send WHOWAS command to our router */
@@ -1341,7 +1339,7 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       entry = silc_idlist_find_server_by_name(server->local_list,
                                              tmp, TRUE, NULL);
       if (!entry && check_global)
-       entry = silc_idlist_find_server_by_name(server->local_list,
+       entry = silc_idlist_find_server_by_name(server->global_list,
                                                tmp, TRUE, NULL);
       if (entry) {
        *servers = silc_realloc(*servers, sizeof(**servers) * 
@@ -1363,7 +1361,7 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       entry = silc_idlist_find_channel_by_name(server->local_list,
                                               tmp, NULL);
       if (!entry && check_global)
-       entry = silc_idlist_find_channel_by_name(server->local_list,
+       entry = silc_idlist_find_channel_by_name(server->global_list,
                                                 tmp, NULL);
       if (entry) {
        *channels = silc_realloc(*channels, sizeof(**channels) * 
@@ -1857,7 +1855,7 @@ silc_server_command_identify_process(SilcServerCommandContext cmd)
     uint16 old_ident;
 
     old_ident = silc_command_get_ident(cmd->payload);
-    silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+    silc_command_set_ident(cmd->payload, ++server->cmd_ident);
     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
     /* Send IDENTIFY command to our router */
@@ -1937,6 +1935,7 @@ static int silc_server_command_bad_chars(char *nick)
   for (i = 0; i < strlen(nick); i++) {
     if (!isascii(nick[i]))
       return TRUE;
+    if (nick[i] <= 32) return TRUE;
     if (nick[i] == ' ') return TRUE;
     if (nick[i] == '\\') return TRUE;
     if (nick[i] == '\"') return TRUE;
@@ -1944,6 +1943,16 @@ static int silc_server_command_bad_chars(char *nick)
     if (nick[i] == '?') return TRUE;
     if (nick[i] == ',') return TRUE;
     if (nick[i] == '@') return TRUE;
+    if (nick[i] == ':') return TRUE;
+    if (nick[i] == '/') return TRUE;
+    if (nick[i] == '[') return TRUE;
+    if (nick[i] == '[') return TRUE;
+    if (nick[i] == '(') return TRUE;
+    if (nick[i] == ')') return TRUE;
+    if (nick[i] == '{') return TRUE;
+    if (nick[i] == '}') return TRUE;
+    if (nick[i] == '<') return TRUE;
+    if (nick[i] == '>') return TRUE;
   }
 
   return FALSE;
@@ -1958,7 +1967,7 @@ SILC_SERVER_CMD_FUNC(nick)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   SilcServer server = cmd->server;
-  SilcBuffer packet, nidp, oidp;
+  SilcBuffer packet, nidp, oidp = NULL;
   SilcClientID *new_id;
   char *nick;
   uint16 ident = silc_command_get_ident(cmd->payload);
@@ -1980,6 +1989,12 @@ SILC_SERVER_CMD_FUNC(nick)
   if (strlen(nick) > 128)
     nick[128] = '\0';
 
+  /* Check for same nickname */
+  if (!strcmp(client->nickname, nick)) {
+    nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+    goto send_reply;
+  }
+
   /* Create new Client ID */
   while (!silc_id_create_client_id(cmd->server, cmd->server->id, 
                                   cmd->server->rng, 
@@ -2024,6 +2039,7 @@ SILC_SERVER_CMD_FUNC(nick)
                                      oidp->data, oidp->len, 
                                      nidp->data, nidp->len);
 
+ send_reply:
   /* Send the new Client ID as reply command back to client */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
                                                SILC_STATUS_OK, ident, 1, 
@@ -2033,7 +2049,8 @@ SILC_SERVER_CMD_FUNC(nick)
 
   silc_buffer_free(packet);
   silc_buffer_free(nidp);
-  silc_buffer_free(oidp);
+  if (oidp)
+    silc_buffer_free(oidp);
   
  out:
   silc_server_command_free(cmd);
@@ -2078,9 +2095,7 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     if (i >= 1)
       status = SILC_STATUS_LIST_ITEM;
 
-    if (i == lch_count - 1 && gch_count)
-      break;
-    if (lch_count > 1 && i == lch_count - 1)
+    if (lch_count > 1 && i == lch_count - 1 && !gch_count)
       status = SILC_STATUS_LIST_END;
 
     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
@@ -2184,7 +2199,33 @@ SILC_SERVER_CMD_FUNC(list)
   SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
   uint32 lch_count = 0, gch_count = 0;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 1);
+
+  /* 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 && 
+      !server->standalone) {
+    SilcBuffer tmpbuf;
+    uint16 old_ident;
+    
+    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);
+    silc_server_packet_send(server, server->router->connection,
+                           SILC_PACKET_COMMAND, cmd->packet->flags,
+                           tmpbuf->data, tmpbuf->len, TRUE);
+
+    /* Reprocess this packet after received reply from router */
+    silc_server_command_pending(server, SILC_COMMAND_LIST, 
+                               silc_command_get_ident(cmd->payload),
+                               silc_server_command_destructor,
+                               silc_server_command_list, 
+                               silc_server_command_dup(cmd));
+    cmd->pending = TRUE;
+    silc_command_set_ident(cmd->payload, old_ident);
+    silc_buffer_free(tmpbuf);
+    return;
+  }
 
   /* Get Channel ID */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
@@ -2201,10 +2242,9 @@ SILC_SERVER_CMD_FUNC(list)
   lchannels = silc_idlist_get_channels(server->local_list, channel_id,
                                       &lch_count);
   
-  /* Get the channels from global list if we are router */
-  if (server->server_type != SILC_SERVER) 
-    gchannels = silc_idlist_get_channels(server->global_list, channel_id,
-                                        &gch_count);
+  /* Get the channels from global list */
+  gchannels = silc_idlist_get_channels(server->global_list, channel_id,
+                                      &gch_count);
 
   /* Send the reply */
   silc_server_command_list_send_reply(cmd, lchannels, lch_count, 
@@ -2822,7 +2862,7 @@ SILC_SERVER_CMD_FUNC(info)
       uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       silc_server_packet_send(server, entry->connection,
@@ -2847,7 +2887,7 @@ SILC_SERVER_CMD_FUNC(info)
       uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       silc_server_packet_send(server, server->router->connection,
@@ -2952,7 +2992,8 @@ static void silc_server_command_join_channel(SilcServer server,
                                             SilcServerCommandContext cmd,
                                             SilcChannelEntry channel,
                                             SilcClientID *client_id,
-                                            int created,
+                                            bool created,
+                                            bool create_key,
                                             uint32 umode)
 {
   SilcSocketConnection sock = cmd->sock;
@@ -3033,7 +3074,8 @@ static void silc_server_command_join_channel(SilcServer 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) ||
+    if (!channel->ban_list ||
+        silc_string_match(channel->ban_list, check) ||
        silc_string_match(channel->ban_list, check2)) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                              SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
@@ -3050,8 +3092,9 @@ static void silc_server_command_join_channel(SilcServer server,
   
   /* Check the channel passphrase if set. */
   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
-    if (!passphrase || memcmp(channel->passphrase, passphrase,
-                             strlen(channel->passphrase))) {
+    if (!passphrase || !channel->passphrase ||
+        memcmp(channel->passphrase, passphrase,
+               strlen(channel->passphrase))) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                            SILC_STATUS_ERR_BAD_PASSWORD);
       goto out;
@@ -3080,17 +3123,17 @@ static void silc_server_command_join_channel(SilcServer server,
   }
 
   /* Generate new channel key as protocol dictates */
-  if ((!created && silc_hash_table_count(channel->user_list) > 0) || 
-      !channel->channel_key)
+  if (create_key) {
     if (!silc_server_create_channel_key(server, channel, 0))
       goto out;
 
-  /* Send the channel key. This is broadcasted to the channel but is not
-     sent to the client who is joining to the channel. */
-  if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
-    silc_server_send_channel_key(server, NULL, channel, 
-                                server->server_type == SILC_ROUTER ? 
-                                FALSE : !server->standalone);
+    /* Send the channel key. This is broadcasted to the channel but is not
+       sent to the client who is joining to the channel. */
+    if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
+      silc_server_send_channel_key(server, NULL, channel, 
+                                  server->server_type == SILC_ROUTER ? 
+                                  FALSE : !server->standalone);
+  }
 
   /* Join the client to the channel by adding it to channel's user list.
      Add also the channel to client entry's channels list for fast cross-
@@ -3145,8 +3188,9 @@ static void silc_server_command_join_channel(SilcServer server,
                                         10, channel->topic,
                                         channel->topic ?
                                         strlen(channel->topic) : 0,
-                                        11, channel->hmac->hmac->name,
-                                        strlen(channel->hmac->hmac->name),
+                                        11, silc_hmac_get_name(channel->hmac),
+                                        strlen(silc_hmac_get_name(channel->
+                                                                  hmac)),
                                         12, tmp3, 4,
                                         13, user_list->data, user_list->len,
                                         14, mode_list->data, 
@@ -3202,7 +3246,7 @@ SILC_SERVER_CMD_FUNC(join)
   char *tmp, *channel_name = NULL, *cipher, *hmac;
   SilcChannelEntry channel;
   uint32 umode = 0;
-  int created = FALSE;
+  bool created = FALSE, create_key = TRUE;
   SilcClientID *client_id;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 1, 4);
@@ -3259,7 +3303,7 @@ SILC_SERVER_CMD_FUNC(join)
       }
     }
 
-    if (!channel || !channel->id) {
+    if (!channel || channel->disabled) {
       /* Channel not found */
 
       /* If we are standalone server we don't have a router, we just create 
@@ -3269,13 +3313,14 @@ SILC_SERVER_CMD_FUNC(join)
                                                 hmac, channel_name, TRUE);
        if (!channel) {
          silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                    SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
          goto out;
        }
-
+       
        umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
        created = TRUE;
-
+       create_key = FALSE;
+       
       } else {
 
        /* The channel does not exist on our server. If we are normal server 
@@ -3293,7 +3338,7 @@ SILC_SERVER_CMD_FUNC(join)
            goto out;
          
          old_ident = silc_command_get_ident(cmd->payload);
-         silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+         silc_command_set_ident(cmd->payload, ++server->cmd_ident);
          tmpbuf = silc_command_payload_encode_payload(cmd->payload);
          
          /* Send JOIN command to our router */
@@ -3328,6 +3373,7 @@ SILC_SERVER_CMD_FUNC(join)
 
          umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
          created = TRUE;
+         create_key = FALSE;
        }
       }
     }
@@ -3358,21 +3404,30 @@ SILC_SERVER_CMD_FUNC(join)
 
        umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
        created = TRUE;
+       create_key = FALSE;
       }
     }
   }
 
-  /* If the channel does not have global users and is also empty it means the
-     channel was created globally (by our router) and the client will be the
-     channel founder and operator. */
-  if (!channel->global_users && !silc_hash_table_count(channel->user_list)) {
-    umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
-    created = TRUE;            /* Created globally by our router */
+  /* Check whether the channel was created by our router */
+  if (cmd->pending && context2) {
+    SilcServerCommandReplyContext reply = 
+      (SilcServerCommandReplyContext)context2;
+    if (silc_command_get(reply->payload) == SILC_COMMAND_JOIN) {
+      tmp = silc_argument_get_arg_type(reply->args, 6, NULL);
+      SILC_GET32_MSB(created, tmp);
+      create_key = FALSE;      /* Router returned the key already */
+    }
   }
 
+  /* If the channel does not have global users and is also empty the client
+     will be the channel founder and operator. */
+  if (!channel->global_users && !silc_hash_table_count(channel->user_list))
+    umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+
   /* Join to the channel */
   silc_server_command_join_channel(server, cmd, channel, client_id,
-                                  created, umode);
+                                  created, create_key, umode);
 
   silc_free(client_id);
 
@@ -3410,7 +3465,7 @@ SILC_SERVER_CMD_FUNC(motd)
     if (server->config && server->config->motd && 
        server->config->motd->motd_file) {
       /* Send motd */
-      motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+      motd = silc_file_readfile(server->config->motd->motd_file, &motd_len);
       if (!motd)
        goto out;
       
@@ -3449,7 +3504,7 @@ SILC_SERVER_CMD_FUNC(motd)
       uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       silc_server_packet_send(server, entry->connection,
@@ -3474,7 +3529,7 @@ SILC_SERVER_CMD_FUNC(motd)
       uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       silc_server_packet_send(server, server->router->connection,
@@ -3628,8 +3683,9 @@ int silc_server_check_cmode_rights(SilcChannelEntry channel,
      modes are available automatically for channel operator. */
 
   if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
-    if (is_op && !is_fo)
-      return FALSE;
+    if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
+      if (is_op && !is_fo)
+       return FALSE;
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
       if (is_op && !is_fo)
@@ -3638,8 +3694,9 @@ int silc_server_check_cmode_rights(SilcChannelEntry channel,
   }
   
   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
-    if (is_op && !is_fo)
-      return FALSE;
+    if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE))
+      if (is_op && !is_fo)
+       return FALSE;
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
       if (is_op && !is_fo)
@@ -3648,8 +3705,9 @@ int silc_server_check_cmode_rights(SilcChannelEntry channel,
   }
 
   if (mode & SILC_CHANNEL_MODE_CIPHER) {
-    if (is_op && !is_fo)
-      return FALSE;
+    if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER))
+      if (is_op && !is_fo)
+       return FALSE;
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
       if (is_op && !is_fo)
@@ -3658,8 +3716,9 @@ int silc_server_check_cmode_rights(SilcChannelEntry channel,
   }
   
   if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
-    if (is_op && !is_fo)
-      return FALSE;
+    if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH))
+      if (is_op && !is_fo)
+       return FALSE;
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
       if (is_op && !is_fo)
@@ -3768,7 +3827,7 @@ SILC_SERVER_CMD_FUNC(cmode)
                                   FALSE : !server->standalone);
 
       cipher = channel->channel_key->cipher->name;
-      hmac = channel->hmac->hmac->name;
+      hmac = (char *)silc_hmac_get_name(channel->hmac);
     }
   }
   
@@ -3822,6 +3881,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
       /* Cipher to use protect the traffic */
+      SilcCipher newkey, oldkey;
 
       /* Get cipher */
       cipher = silc_argument_get_arg_type(cmd->args, 5, NULL);
@@ -3832,17 +3892,25 @@ SILC_SERVER_CMD_FUNC(cmode)
       }
 
       /* Delete old cipher and allocate the new one */
-      silc_cipher_free(channel->channel_key);
-      if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
+      if (!silc_cipher_alloc(cipher, &newkey)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
        goto out;
       }
 
+      oldkey = channel->channel_key;
+      channel->channel_key = newkey;
+
       /* Re-generate channel key */
-      if (!silc_server_create_channel_key(server, channel, 0))
+      if (!silc_server_create_channel_key(server, channel, 0)) {
+       /* We don't have new key, revert to old one */
+       channel->channel_key = oldkey;
        goto out;
-    
+      }
+
+      /* Remove old channel key for good */
+      silc_cipher_free(oldkey);
+
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
       silc_server_send_channel_key(server, NULL, channel, 
@@ -3853,21 +3921,29 @@ SILC_SERVER_CMD_FUNC(cmode)
     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
       /* Cipher mode is unset. Remove the cipher and revert back to 
         default cipher */
+      SilcCipher newkey, oldkey;
       cipher = channel->cipher;
 
       /* Delete old cipher and allocate default one */
-      silc_cipher_free(channel->channel_key);
-      if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER, 
-                            &channel->channel_key)) {
+      if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER, &newkey)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                   SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
        goto out;
       }
 
+      oldkey = channel->channel_key;
+      channel->channel_key = newkey;
+
       /* Re-generate channel key */
-      if (!silc_server_create_channel_key(server, channel, 0))
+      if (!silc_server_create_channel_key(server, channel, 0)) {
+       /* We don't have new key, revert to old one */
+       channel->channel_key = oldkey;
        goto out;
+      }
       
+      /* Remove old channel key for good */
+      silc_cipher_free(oldkey);
+
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
       silc_server_send_channel_key(server, NULL, channel, 
@@ -3880,6 +3956,7 @@ SILC_SERVER_CMD_FUNC(cmode)
     if (!(channel->mode & SILC_CHANNEL_MODE_HMAC)) {
       /* HMAC to use protect the traffic */
       unsigned char hash[32];
+      SilcHmac newhmac;
 
       /* Get hmac */
       hmac = silc_argument_get_arg_type(cmd->args, 6, NULL);
@@ -3890,43 +3967,49 @@ SILC_SERVER_CMD_FUNC(cmode)
       }
 
       /* Delete old hmac and allocate the new one */
-      silc_hmac_free(channel->hmac);
-      if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
+      if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
        goto out;
       }
 
+      silc_hmac_free(channel->hmac);
+      channel->hmac = newhmac;
+
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
-      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8
-                    hash);
+      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(channel->hmac->hash));
+                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_HMAC) {
       /* Hmac mode is unset. Remove the hmac and revert back to 
         default hmac */
+      SilcHmac newhmac;
       unsigned char hash[32];
       hmac = channel->hmac_name;
 
       /* Delete old hmac and allocate default one */
       silc_hmac_free(channel->hmac);
-      if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL, 
-                          &channel->hmac)) {
+      if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL, &newhmac)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
        goto out;
       }
 
+      silc_hmac_free(channel->hmac);
+      channel->hmac = newhmac;
+
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
-      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, 
+      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(channel->hmac->hash));
+                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
   }
@@ -4164,7 +4247,9 @@ SILC_SERVER_CMD_FUNC(cumode)
       }
 
       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
-         !channel->founder_key) {
+         !channel->founder_key || !idata->public_key ||
+         !silc_pkcs_public_key_compare(channel->founder_key, 
+                                       idata->public_key)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                              SILC_STATUS_ERR_NOT_YOU);
        goto out;
@@ -4176,7 +4261,7 @@ SILC_SERVER_CMD_FUNC(cumode)
                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
        goto out;
       }
-      
+
       auth = (channel->founder_method == SILC_AUTH_PASSWORD ?
              (void *)channel->founder_passwd : (void *)channel->founder_key);
       auth_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
@@ -4799,6 +4884,9 @@ SILC_SERVER_CMD_FUNC(close)
 
   server_entry = silc_idlist_find_server_by_conn(server->local_list,
                                                 name, port, FALSE, NULL);
+  if (!server_entry)
+    server_entry = silc_idlist_find_server_by_conn(server->global_list,
+                                                  name, port, FALSE, NULL);
   if (!server_entry) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
                                          SILC_STATUS_ERR_NO_SERVER_ID);
@@ -4991,12 +5079,12 @@ SILC_SERVER_CMD_FUNC(users)
     channel = silc_idlist_find_channel_by_name(server->local_list, 
                                               channel_name, NULL);
 
-  if (!channel) {
+  if (!channel || channel->disabled) {
     if (server->server_type != SILC_ROUTER && !server->standalone &&
        !cmd->pending) {
       SilcBuffer tmpbuf;
       
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
       
       /* Send USERS command */
@@ -5139,7 +5227,7 @@ SILC_SERVER_CMD_FUNC(getkey)
        goto out;
       
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
       
       silc_server_packet_send(server, dest_sock,
@@ -5205,7 +5293,7 @@ SILC_SERVER_CMD_FUNC(getkey)
       uint16 old_ident;
       
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
       
       silc_server_packet_send(server, server->router->connection,