updates.
[silc.git] / apps / silcd / command.c
index 0f712ea04bcee725ef4f60d754defaff0ff78287..c317a5462a2d40c22556cde3dccfad2bcffc3970 100644 (file)
@@ -528,11 +528,12 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
 static void
 silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
                                     SilcClientEntry *clients,
-                                    unsigned int clients_count)
+                                    unsigned int clients_count,
+                                    int count)
 {
   SilcServer server = cmd->server;
   char *tmp;
-  int i, count = 0, len;
+  int i, k, len;
   SilcBuffer packet, idp, channels;
   SilcClientEntry entry;
   SilcCommandStatus status;
@@ -541,11 +542,16 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   unsigned char idle[4], mode[4];
   SilcSocketConnection hsock;
 
+  len = 0;
+  for (i = 0; i < clients_count; i++)
+    if (clients[i]->data.registered)
+      len++;
+
   status = SILC_STATUS_OK;
-  if (clients_count > 1)
+  if (len > 1)
     status = SILC_STATUS_LIST_START;
 
-  for (i = 0; i < clients_count; i++) {
+  for (i = 0, k = 0; i < clients_count; i++) {
     entry = clients[i];
 
     if (entry->data.registered == FALSE) {
@@ -559,15 +565,18 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
       continue;
     }
 
-    if (count && i - 1 == count)
-      break;
-
-    if (i >= 1)
+    if (k >= 1)
       status = SILC_STATUS_LIST_ITEM;
 
-    if (clients_count > 1 && i == clients_count - 1)
+    if (clients_count > 1 && k == clients_count - 1)
+      status = SILC_STATUS_LIST_END;
+
+    if (count && k - 1 == count)
       status = SILC_STATUS_LIST_END;
 
+    if (count && k - 1 > count)
+      break;
+
     /* Sanity check, however these should never fail. However, as
        this sanity check has been added here they have failed. */
     if (!entry->nickname || !entry->username || !entry->userinfo)
@@ -636,6 +645,8 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
     silc_buffer_free(idp);
     if (channels)
       silc_buffer_free(channels);
+
+    k++;
   }
 }
 
@@ -766,7 +777,8 @@ silc_server_command_whois_from_client(SilcServerCommandContext cmd)
   }
 
   /* Send the command reply to the client */
-  silc_server_command_whois_send_reply(cmd, clients, clients_count);
+  silc_server_command_whois_send_reply(cmd, clients, clients_count,
+                                      count);
 
  out:
   if (client_id_count) {
@@ -876,7 +888,8 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd)
   }
 
   /* Send the command reply to the client */
-  silc_server_command_whois_send_reply(cmd, clients, clients_count);
+  silc_server_command_whois_send_reply(cmd, clients, clients_count,
+                                      count);
 
  out:
   if (client_id_count) {
@@ -1333,11 +1346,12 @@ silc_server_command_identify_check(SilcServerCommandContext cmd,
 static void
 silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
                                        SilcClientEntry *clients,
-                                       unsigned int clients_count)
+                                       unsigned int clients_count,
+                                       int count)
 {
   SilcServer server = cmd->server;
   char *tmp;
-  int i, count = 0, len;
+  int i, k, len;
   SilcBuffer packet, idp;
   SilcClientEntry entry;
   SilcCommandStatus status;
@@ -1345,11 +1359,16 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
   char nh[256], uh[256];
   SilcSocketConnection hsock;
 
+  len = 0;
+  for (i = 0; i < clients_count; i++)
+    if (clients[i]->data.registered)
+      len++;
+
   status = SILC_STATUS_OK;
-  if (clients_count > 1)
+  if (len > 1)
     status = SILC_STATUS_LIST_START;
 
-  for (i = 0; i < clients_count; i++) {
+  for (i = 0, k = 0; i < clients_count; i++) {
     entry = clients[i];
 
     if (entry->data.registered == FALSE) {
@@ -1363,15 +1382,18 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       continue;
     }
 
-    if (count && i - 1 == count)
-      break;
-
-    if (i >= 1)
+    if (k >= 1)
       status = SILC_STATUS_LIST_ITEM;
 
-    if (clients_count > 1 && i == clients_count - 1)
+    if (clients_count > 1 && k == clients_count - 1)
+      status = SILC_STATUS_LIST_END;
+
+    if (count && k - 1 == count)
       status = SILC_STATUS_LIST_END;
 
+    if (count && k - 1 > count)
+      break;
+
     /* Send IDENTIFY reply */
     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
     tmp = silc_argument_get_first_arg(cmd->args, NULL);
@@ -1414,6 +1436,8 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
     
     silc_buffer_free(packet);
     silc_buffer_free(idp);
+
+    k++;
   }
 }
 
@@ -1484,13 +1508,13 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd)
       }
     }
   } else {
-    clients = silc_idlist_get_clients_by_nickname(server->local_list, 
-                                                 nick, server_name,
-                                                 &clients_count);
+    clients = silc_idlist_get_clients_by_hash(server->local_list, 
+                                             nick, server->md5hash,
+                                             &clients_count);
     if (!clients)
-      clients = silc_idlist_get_clients_by_hash(server->local_list, 
-                                               nick, server->md5hash,
-                                               &clients_count);
+      clients = silc_idlist_get_clients_by_nickname(server->local_list, 
+                                                   nick, server_name,
+                                                   &clients_count);
   }
   
   /* Check global list as well */
@@ -1507,13 +1531,13 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd)
        }
       }
     } else {
-      clients = silc_idlist_get_clients_by_nickname(server->global_list, 
-                                                   nick, server_name,
-                                                   &clients_count);
+      clients = silc_idlist_get_clients_by_hash(server->global_list, 
+                                               nick, server->md5hash,
+                                               &clients_count);
       if (!clients)
-       clients = silc_idlist_get_clients_by_hash(server->global_list, 
-                                                 nick, server->md5hash,
-                                                 &clients_count);
+       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
+                                                     nick, server_name,
+                                                     &clients_count);
     }
   }
   
@@ -1541,7 +1565,8 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd)
   }
 
   /* Send the command reply to the client */
-  silc_server_command_identify_send_reply(cmd, clients, clients_count);
+  silc_server_command_identify_send_reply(cmd, clients, clients_count,
+                                         count);
 
  out:
   if (client_id_count) {
@@ -1591,13 +1616,13 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd)
       }
     }
   } else {
-    clients = silc_idlist_get_clients_by_nickname(server->local_list, 
-                                                 nick, server_name,
-                                                 &clients_count);
+    clients = silc_idlist_get_clients_by_hash(server->local_list, 
+                                             nick, server->md5hash,
+                                             &clients_count);
     if (!clients)
-      clients = silc_idlist_get_clients_by_hash(server->local_list, 
-                                               nick, server->md5hash,
-                                               &clients_count);
+      clients = silc_idlist_get_clients_by_nickname(server->local_list, 
+                                                   nick, server_name,
+                                                   &clients_count);
   }
   
   /* If we are router we will check our global list as well. */
@@ -1614,13 +1639,13 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd)
        }
       }
     } else {
-      clients = silc_idlist_get_clients_by_nickname(server->global_list, 
-                                                   nick, server_name,
-                                                   &clients_count);
+      clients = silc_idlist_get_clients_by_hash(server->global_list, 
+                                               nick, server->md5hash,
+                                               &clients_count);
       if (!clients)
-       clients = silc_idlist_get_clients_by_hash(server->global_list, 
-                                                 nick, server->md5hash,
-                                                 &clients_count);
+       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
+                                                     nick, server_name,
+                                                     &clients_count);
     }
   }
 
@@ -1648,7 +1673,7 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd)
   }
 
   /* Send the command reply */
-  silc_server_command_identify_send_reply(cmd, clients, clients_count);
+  silc_server_command_identify_send_reply(cmd, clients, clients_count, count);
 
  out:
   if (client_id_count) {
@@ -2492,21 +2517,47 @@ SILC_SERVER_CMD_FUNC(info)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcBuffer packet, idp;
+  unsigned char *tmp;
+  unsigned int tmp_len;
   char *dest_server, *server_info = NULL, *server_name;
   unsigned short ident = silc_command_get_ident(cmd->payload);
   SilcServerEntry entry = NULL;
+  SilcServerID *server_id = NULL;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 1);
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 0, 2);
 
   /* Get server name */
   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
-  if (!dest_server) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
-                                         SILC_STATUS_ERR_NO_SUCH_SERVER);
-    goto out;
+
+  /* Get Server ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+  if (tmp) {
+    server_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!server_id) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+                                           SILC_STATUS_ERR_NO_SERVER_ID);
+      goto out;
+    }
   }
 
-  if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
+  if (server_id) {
+    /* Check whether we have this server cached */
+    entry = silc_idlist_find_server_by_id(server->local_list,
+                                         server_id, NULL);
+    if (!entry) {
+      entry = silc_idlist_find_server_by_id(server->global_list,
+                                           server_id, NULL);
+      if (!entry && server->server_type == SILC_ROUTER) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+                                             SILC_STATUS_ERR_NO_SUCH_SERVER);
+       goto out;
+      }
+    }
+  }
+
+  if ((!dest_server && !server_id) || 
+      (dest_server && !cmd->pending && 
+       !strncasecmp(dest_server, server->server_name, strlen(dest_server)))) {
     /* Send our reply */
     char info_string[256];
 
@@ -2522,14 +2573,17 @@ SILC_SERVER_CMD_FUNC(info)
     entry = server->id_entry;
   } else {
     /* Check whether we have this server cached */
-    entry = silc_idlist_find_server_by_name(server->global_list,
-                                           dest_server, NULL);
-    if (!entry) {
-      entry = silc_idlist_find_server_by_name(server->local_list,
+    if (!entry && dest_server) {
+      entry = silc_idlist_find_server_by_name(server->global_list,
                                              dest_server, NULL);
+      if (!entry) {
+       entry = silc_idlist_find_server_by_name(server->local_list,
+                                               dest_server, NULL);
+      }
     }
 
-    if (server->server_type == SILC_ROUTER && entry && !entry->server_info) {
+    if (!cmd->pending &&
+       server->server_type == SILC_ROUTER && entry && !entry->server_info) {
       /* Send to the server */
       SilcBuffer tmpbuf;
       unsigned short old_ident;
@@ -2580,6 +2634,9 @@ SILC_SERVER_CMD_FUNC(info)
     }
   }
 
+  if (server_id)
+    silc_free(server_id);
+
   if (!entry) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
                                          SILC_STATUS_ERR_NO_SUCH_SERVER);
@@ -2589,7 +2646,7 @@ SILC_SERVER_CMD_FUNC(info)
   idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
   if (!server_info)
     server_info = entry->server_info;
-  server_name = dest_server;
+  server_name = entry->server_name;
 
   /* Send the reply */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
@@ -2939,7 +2996,7 @@ SILC_SERVER_CMD_FUNC(join)
       }
     }
 
-    if (!channel) {
+    if (!channel || !channel->id) {
       /* Channel not found */
 
       /* If we are standalone server we don't have a router, we just create 
@@ -2947,6 +3004,12 @@ SILC_SERVER_CMD_FUNC(join)
       if (server->standalone) {
        channel = silc_server_create_new_channel(server, server->id, cipher, 
                                                 hmac, channel_name, TRUE);
+       if (!channel) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                    SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+         goto out;
+       }
+
        umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
        created = TRUE;
 
@@ -2988,6 +3051,12 @@ SILC_SERVER_CMD_FUNC(join)
          /* Channel really does not exist, create it */
          channel = silc_server_create_new_channel(server, server->id, cipher, 
                                                   hmac, channel_name, TRUE);
+         if (!channel) {
+           silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+           goto out;
+         }
+
          umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
          created = TRUE;
        }
@@ -3012,6 +3081,12 @@ SILC_SERVER_CMD_FUNC(join)
        /* Channel really does not exist, create it */
        channel = silc_server_create_new_channel(server, server->id, cipher, 
                                                 hmac, channel_name, TRUE);
+       if (!channel) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+         goto out;
+       }
+
        umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
        created = TRUE;
       }
@@ -3211,10 +3286,12 @@ SILC_SERVER_CMD_FUNC(umode)
    */
 
   if (mask & SILC_UMODE_SERVER_OPERATOR) {
-    /* Cannot operator mode */
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
-                                         SILC_STATUS_ERR_PERM_DENIED);
-    goto out;
+    if (!(client->mode & SILC_UMODE_SERVER_OPERATOR)) {
+      /* Cannot operator mode */
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+                                           SILC_STATUS_ERR_PERM_DENIED);
+      goto out;
+    }
   } else {
     if (client->mode & SILC_UMODE_SERVER_OPERATOR)
       /* Remove the server operator rights */
@@ -3222,16 +3299,26 @@ SILC_SERVER_CMD_FUNC(umode)
   }
 
   if (mask & SILC_UMODE_ROUTER_OPERATOR) {
-    /* Cannot operator mode */
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
-                                         SILC_STATUS_ERR_PERM_DENIED);
-    goto out;
+    if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+      /* Cannot operator mode */
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+                                           SILC_STATUS_ERR_PERM_DENIED);
+      goto out;
+    }
   } else {
     if (client->mode & SILC_UMODE_ROUTER_OPERATOR)
       /* Remove the router operator rights */
       client->mode &= ~SILC_UMODE_ROUTER_OPERATOR;
   }
 
+  if (mask & SILC_UMODE_GONE) {
+    client->mode |= SILC_UMODE_GONE;
+  } else {
+    if (client->mode & SILC_UMODE_GONE)
+      /* Remove the gone status */
+      client->mode &= ~SILC_UMODE_GONE;
+  }
+
   /* Send UMODE change to primary router */
   if (!server->standalone)
     silc_server_send_notify_umode(server, server->router->connection, TRUE,
@@ -3302,6 +3389,16 @@ int silc_server_check_cmode_rights(SilcChannelEntry channel,
     }
   }
   
+  if (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)
+       return FALSE;
+    }
+  }
+  
   return TRUE;
 }
 
@@ -3312,28 +3409,17 @@ SILC_SERVER_CMD_FUNC(cmode)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcIDListData idata = (SilcIDListData)client;
   SilcChannelID *channel_id;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcBuffer packet, cidp;
   unsigned char *tmp, *tmp_id, *tmp_mask;
   char *cipher = NULL, *hmac = NULL;
-  unsigned int argc, mode_mask, tmp_len, tmp_len2;
+  unsigned int mode_mask, tmp_len, tmp_len2;
   unsigned short ident = silc_command_get_ident(cmd->payload);
 
-  SILC_LOG_DEBUG(("Start"));
-
-  argc = silc_argument_get_arg_num(cmd->args);
-  if (argc < 2) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
-  }
-  if (argc > 8) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
-    goto out;
-  }
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CMODE, cmd, 2, 7);
 
   /* Get Channel ID */
   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
@@ -3577,6 +3663,57 @@ 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 */
+       SilcAuthPayload auth;
+       
+       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);
+         goto out;
+       }
+
+       auth = silc_auth_payload_parse(tmp, tmp_len);
+       if (!auth) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+         goto out;
+       }
+
+       /* Save the public key */
+       tmp = silc_pkcs_public_key_encode(idata->public_key, &tmp_len);
+       silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
+       silc_free(tmp);
+       
+       channel->founder_method = silc_auth_get_method(auth);
+
+       if (channel->founder_method == SILC_AUTH_PASSWORD) {
+         tmp = silc_auth_get_data(auth, &tmp_len);
+         channel->founder_passwd = 
+           silc_calloc(tmp_len + 1, sizeof(*channel->founder_passwd));
+         memcpy(channel->founder_passwd, tmp, tmp_len);
+         channel->founder_passwd_len = tmp_len;
+       }
+
+       silc_auth_payload_free(auth);
+      }
+    }
+  } else {
+    if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+      if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+       if (channel->founder_key)
+         silc_pkcs_public_key_free(channel->founder_key);
+       if (channel->founder_passwd) {
+         silc_free(channel->founder_passwd);
+         channel->founder_passwd = NULL;
+       }
+      }
+    }
+  }
+
   /* Finally, set the mode */
   channel->mode = mode_mask;
 
@@ -3585,7 +3722,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
                                     SILC_NOTIFY_TYPE_CMODE_CHANGE, 4,
                                     cidp->data, cidp->len, 
-                                    tmp_mask, tmp_len,
+                                    tmp_mask, 4,
                                     cipher, cipher ? strlen(cipher) : 0,
                                     hmac, hmac ? strlen(hmac) : 0);
 
@@ -3594,7 +3731,8 @@ SILC_SERVER_CMD_FUNC(cmode)
     silc_server_send_notify_cmode(server, server->router->connection,
                                  server->server_type == SILC_ROUTER ? 
                                  TRUE : FALSE, channel,
-                                 mode_mask, client->id, SILC_ID_CLIENT_LEN,
+                                 mode_mask, client->id, SILC_ID_CLIENT,
+                                 SILC_ID_CLIENT_LEN,
                                  cipher, hmac);
 
   /* Send command reply to sender */
@@ -3619,6 +3757,7 @@ 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;
   SilcChannelEntry channel;
@@ -3626,11 +3765,11 @@ SILC_SERVER_CMD_FUNC(cumode)
   SilcChannelClientEntry chl;
   SilcBuffer packet, idp;
   unsigned char *tmp_id, *tmp_ch_id, *tmp_mask;
-  unsigned int target_mask, sender_mask, tmp_len, tmp_ch_len;
+  unsigned int target_mask, sender_mask = 0, tmp_len, tmp_ch_len;
   int notify = FALSE;
   unsigned short ident = silc_command_get_ident(cmd->payload);
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3);
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 4);
 
   /* Get Channel ID */
   tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
@@ -3670,13 +3809,6 @@ SILC_SERVER_CMD_FUNC(cumode)
   silc_list_start(channel->user_list);
   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
     if (chl->client == client) {
-      if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
-         !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
-       goto out;
-      }
-
       sender_mask = chl->mode;
       break;
     }
@@ -3713,18 +3845,28 @@ SILC_SERVER_CMD_FUNC(cumode)
                                                  client_id, NULL);
   }
 
-  /* Check whether target client is on the channel */
-  if (!silc_server_client_on_channel(target_client, channel)) {
+  if (target_client != client &&
+      !(sender_mask & SILC_CHANNEL_UMODE_CHANFO) &&
+      !(sender_mask & SILC_CHANNEL_UMODE_CHANOP)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
+                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
     goto out;
   }
 
-  /* Get entry to the channel user list */
-  silc_list_start(channel->user_list);
-  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
-    if (chl->client == target_client)
-      break;
+  /* Check whether target client is on the channel */
+  if (target_client != client) {
+    if (!silc_server_client_on_channel(target_client, channel)) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
+      goto out;
+    }
+
+    /* Get entry to the channel user list */
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+      if (chl->client == target_client)
+       break;
+  }
 
   /* 
    * Change the mode 
@@ -3739,10 +3881,46 @@ SILC_SERVER_CMD_FUNC(cumode)
   }
 
   if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
-    /* Cannot promote anyone to channel founder */
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NOT_YOU);
-    goto out;
+    /* The client tries to claim the founder rights. */
+    unsigned char *tmp_auth;
+    unsigned int tmp_auth_len, auth_len;
+    void *auth;
+    
+    if (target_client != client) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                           SILC_STATUS_ERR_NOT_YOU);
+      goto out;
+    }
+
+    if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
+       !channel->founder_key) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                           SILC_STATUS_ERR_NOT_YOU);
+      goto out;
+    }
+
+    tmp_auth = silc_argument_get_arg_type(cmd->args, 4, &tmp_auth_len);
+    if (!tmp_auth) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_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 ?
+               channel->founder_passwd_len : 0);
+    
+    if (!silc_auth_verify_data(tmp_auth, tmp_auth_len,
+                              channel->founder_method, auth, auth_len,
+                              idata->hash, client->id, SILC_ID_CLIENT)) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                           SILC_STATUS_ERR_AUTH_FAILED);
+      goto out;
+    }
+
+    chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
+    notify = TRUE;
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
       if (target_client == client) {
@@ -3760,11 +3938,25 @@ SILC_SERVER_CMD_FUNC(cumode)
   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
     /* Promote to operator */
     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+      if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
+         !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+       goto out;
+      }
+
       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
       notify = TRUE;
     }
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
+      if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
+         !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+       goto out;
+      }
+
       /* Demote to normal user */
       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
       notify = TRUE;
@@ -3772,6 +3964,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   }
 
   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+  tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
 
   /* Send notify to channel, notify only if mode was actually changed. */
   if (notify) {
@@ -4054,6 +4247,9 @@ SILC_SERVER_CMD_FUNC(silcoper)
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SILCOPER, cmd, 1, 2);
 
+  if (server->server_type == SILC_SERVER)
+    goto out;
+
   if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
     goto out;
 
@@ -4169,6 +4365,9 @@ SILC_SERVER_CMD_FUNC(connect)
 
 SILC_SERVER_CMD_FUNC(restart)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+
+  silc_server_command_free(cmd);
 }
 
 /* Server side command of CLOSE. Closes connection to a specified server. */
@@ -4274,8 +4473,7 @@ SILC_SERVER_CMD_FUNC(leave)
   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
   SilcChannelID *id;
   SilcChannelEntry channel;
-  SilcBuffer packet;
-  unsigned int i, len;
+  unsigned int len;
   unsigned char *tmp;
 
   SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
@@ -4320,47 +4518,23 @@ SILC_SERVER_CMD_FUNC(leave)
                                  TRUE : FALSE, channel, id_entry->id,
                                  SILC_ID_CLIENT_LEN);
 
-  /* Remove client from channel */
-  i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
-                                         TRUE);
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
                                        SILC_STATUS_OK);
 
-  /* If the channel does not exist anymore we won't send anything */
-  if (!i)
+  /* Remove client from channel */
+  if (!silc_server_remove_from_one_channel(server, sock, channel, id_entry,
+                                          TRUE))
+    /* If the channel does not exist anymore we won't send anything */
     goto out;
 
   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
     /* Re-generate channel key */
     silc_server_create_channel_key(server, channel, 0);
 
-    /* Encode channel key payload to be distributed on the channel */
-    packet = 
-      silc_channel_key_payload_encode(len, tmp,
-                                     strlen(channel->channel_key->
-                                            cipher->name),
-                                     channel->channel_key->cipher->name,
-                                     channel->key_len / 8, channel->key);
-
-    /* If we are normal server then we will send it to our router.  If we
-       are router we will send it to all local servers that has clients on
-       the channel */
-    if (server->server_type == SILC_SERVER) {
-      if (!server->standalone)
-       silc_server_packet_send(server, 
-                               cmd->server->router->connection,
-                               SILC_PACKET_CHANNEL_KEY, 0, packet->data,
-                               packet->len, FALSE);
-    } else {
-      
-    }
-
-    /* Send to locally connected clients on the channel */
-    silc_server_packet_send_local_channel(server, channel, 
-                                         SILC_PACKET_CHANNEL_KEY, 0,
-                                         packet->data, packet->len, FALSE);
-
-    silc_buffer_free(packet);
+    /* Send the channel key */
+    silc_server_send_channel_key(server, NULL, channel, 
+                                server->server_type == SILC_ROUTER ? 
+                                FALSE : !server->standalone);
   }
 
   silc_free(id);