updates.
[silc.git] / apps / silcd / command.c
index ccc3cbb6a9ab8b243f2b8911b7f3c57ef4042a16..d72636f44453ef5404c368b2eebcc8f3c4230ca6 100644 (file)
@@ -62,8 +62,7 @@ SilcServerCommand silc_command_list[] =
   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG_STRICT | SILC_CF_REG),
   SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
-  SILC_SERVER_CMD(restart, RESTART, 
-                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+  SILC_SERVER_CMD(ban, BAN, SILC_CF_LAG_STRICT | SILC_CF_REG),
   SILC_SERVER_CMD(close, CLOSE,
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(shutdown, SHUTDOWN, SILC_CF_LAG | SILC_CF_REG | 
@@ -72,7 +71,6 @@ SilcServerCommand silc_command_list[] =
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
   SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
   SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
-  SILC_SERVER_CMD(ban, BAN, SILC_CF_LAG_STRICT | SILC_CF_REG),
 
   { NULL, 0 },
 };
@@ -488,7 +486,7 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
   for (i = 0; i < clients_count; i++) {
     entry = clients[i];
 
-    if (entry->data.registered == FALSE)
+    if (!entry || entry->data.registered == FALSE)
       continue;
 
     if (!entry->nickname || !entry->username || !entry->userinfo) {
@@ -717,37 +715,33 @@ silc_server_command_whois_from_client(SilcServerCommandContext cmd)
       }
     }
   } else {
-    clients = silc_idlist_get_clients_by_hash(server->local_list, 
-                                             nick, server->md5hash,
-                                             &clients_count);
-    if (!clients)
-      clients = silc_idlist_get_clients_by_nickname(server->local_list, 
-                                                   nick, server_name,
-                                                   &clients_count);
+    if (!silc_idlist_get_clients_by_hash(server->local_list, 
+                                        nick, server->md5hash,
+                                        &clients, &clients_count))
+      silc_idlist_get_clients_by_nickname(server->local_list, 
+                                         nick, server_name,
+                                         &clients, &clients_count);
   }
   
   /* Check global list as well */
-  if (!clients) {
-    if (client_id_count) {
-      /* Check all Client ID's received in the command packet */
-      for (i = 0; i < client_id_count; i++) {
-       entry = silc_idlist_find_client_by_id(server->global_list, 
-                                             client_id[i], NULL);
-       if (entry) {
-         clients = silc_realloc(clients, sizeof(*clients) * 
-                                (clients_count + 1));
-         clients[clients_count++] = entry;
-       }
+  if (client_id_count) {
+    /* Check all Client ID's received in the command packet */
+    for (i = 0; i < client_id_count; i++) {
+      entry = silc_idlist_find_client_by_id(server->global_list, 
+                                           client_id[i], NULL);
+      if (entry) {
+       clients = silc_realloc(clients, sizeof(*clients) * 
+                              (clients_count + 1));
+       clients[clients_count++] = entry;
       }
-    } else {
-      clients = silc_idlist_get_clients_by_hash(server->global_list, 
-                                               nick, server->md5hash,
-                                               &clients_count);
-      if (!clients)
-       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
-                                                     nick, server_name,
-                                                     &clients_count);
     }
+  } else {
+    if (!silc_idlist_get_clients_by_hash(server->global_list, 
+                                        nick, server->md5hash,
+                                        &clients, &clients_count))
+      silc_idlist_get_clients_by_nickname(server->global_list, 
+                                         nick, server_name,
+                                         &clients, &clients_count);
   }
   
   if (!clients) {
@@ -828,17 +822,16 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd)
       }
     }
   } else {
-    clients = silc_idlist_get_clients_by_hash(server->local_list, 
-                                             nick, server->md5hash,
-                                             &clients_count);
-    if (!clients)
-      clients = silc_idlist_get_clients_by_nickname(server->local_list, 
-                                                   nick, server_name,
-                                                   &clients_count);
+    if (!silc_idlist_get_clients_by_hash(server->local_list, 
+                                        nick, server->md5hash,
+                                        &clients, &clients_count))
+      silc_idlist_get_clients_by_nickname(server->local_list, 
+                                         nick, server_name,
+                                         &clients, &clients_count);
   }
   
   /* If we are router we will check our global list as well. */
-  if (!clients && server->server_type == SILC_ROUTER) {
+  if (server->server_type == SILC_ROUTER) {
     if (client_id_count) {
       /* Check all Client ID's received in the command packet */
       for (i = 0; i < client_id_count; i++) {
@@ -851,13 +844,12 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd)
        }
       }
     } else {
-      clients = silc_idlist_get_clients_by_hash(server->global_list, 
-                                               nick, server->md5hash,
-                                               &clients_count);
-      if (!clients)
-       clients = silc_idlist_get_clients_by_nickname(server->global_list, 
-                                                     nick, server_name,
-                                                     &clients_count);
+      if (!silc_idlist_get_clients_by_hash(server->global_list, 
+                                          nick, server->md5hash,
+                                          &clients, &clients_count))
+       silc_idlist_get_clients_by_nickname(server->global_list, 
+                                           nick, server_name,
+                                           &clients, &clients_count);
     }
   }
 
@@ -1165,24 +1157,20 @@ silc_server_command_whowas_from_client(SilcServerCommandContext cmd)
     return 0;
 
   /* Get all clients matching that nickname from local list */
-  clients = silc_idlist_get_clients_by_nickname(server->local_list, 
-                                               nick, server_name,
-                                               &clients_count);
-  if (!clients)
-    clients = silc_idlist_get_clients_by_hash(server->local_list, 
-                                             nick, server->md5hash,
-                                             &clients_count);
+  if (!silc_idlist_get_clients_by_nickname(server->local_list, 
+                                          nick, server_name,
+                                          &clients, &clients_count))
+    silc_idlist_get_clients_by_hash(server->local_list, 
+                                   nick, server->md5hash,
+                                   &clients, &clients_count);
   
   /* Check global list as well */
-  if (!clients) {
-    clients = silc_idlist_get_clients_by_nickname(server->global_list, 
-                                                 nick, server_name,
-                                                 &clients_count);
-    if (!clients)
-      clients = silc_idlist_get_clients_by_hash(server->global_list, 
-                                               nick, server->md5hash,
-                                               &clients_count);
-  }
+  if (!silc_idlist_get_clients_by_nickname(server->global_list, 
+                                          nick, server_name,
+                                          &clients, &clients_count))
+    silc_idlist_get_clients_by_hash(server->global_list, 
+                                   nick, server->md5hash,
+                                   &clients, &clients_count);
   
   if (!silc_server_command_whowas_check(cmd, clients, clients_count)) {
     ret = -1;
@@ -1219,23 +1207,21 @@ silc_server_command_whowas_from_server(SilcServerCommandContext cmd)
   /* Process the command request. Let's search for the requested client and
      send reply to the requesting server. */
 
-  clients = silc_idlist_get_clients_by_nickname(server->local_list, 
-                                               nick, server_name,
-                                               &clients_count);
-  if (!clients)
-    clients = silc_idlist_get_clients_by_hash(server->local_list, 
-                                             nick, server->md5hash,
-                                             &clients_count);
+  if (!silc_idlist_get_clients_by_nickname(server->local_list, 
+                                          nick, server_name,
+                                          &clients, &clients_count))
+    silc_idlist_get_clients_by_hash(server->local_list, 
+                                   nick, server->md5hash,
+                                   &clients, &clients_count);
   
   /* If we are router we will check our global list as well. */
-  if (!clients && server->server_type == SILC_ROUTER) {
-    clients = silc_idlist_get_clients_by_nickname(server->global_list, 
-                                                 nick, server_name,
-                                                 &clients_count);
-    if (!clients)
-      clients = silc_idlist_get_clients_by_hash(server->global_list, 
-                                               nick, server->md5hash,
-                                               &clients_count);
+  if (server->server_type == SILC_ROUTER) {
+    if (!silc_idlist_get_clients_by_nickname(server->global_list, 
+                                            nick, server_name,
+                                            &clients, &clients_count))
+      silc_idlist_get_clients_by_hash(server->global_list, 
+                                     nick, server->md5hash,
+                                     &clients, &clients_count);
   }
 
   if (!clients) {
@@ -1301,7 +1287,7 @@ silc_server_command_identify_check(SilcServerCommandContext cmd,
   for (i = 0; i < clients_count; i++) {
     entry = clients[i];
 
-    if (entry->data.registered == FALSE)
+    if (!entry || entry->data.registered == FALSE)
       continue;
 
     if (!entry->nickname) {
@@ -1508,37 +1494,33 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd)
       }
     }
   } else {
-    clients = silc_idlist_get_clients_by_nickname(server->local_list, 
-                                                 nick, server_name,
-                                                 &clients_count);
-    if (!clients)
-      clients = silc_idlist_get_clients_by_hash(server->local_list, 
-                                               nick, server->md5hash,
-                                               &clients_count);
+    if (!silc_idlist_get_clients_by_hash(server->local_list, 
+                                        nick, server->md5hash,
+                                        &clients, &clients_count))
+      silc_idlist_get_clients_by_nickname(server->local_list, 
+                                         nick, server_name,
+                                         &clients, &clients_count);
   }
   
   /* Check global list as well */
-  if (!clients) {
-    if (client_id_count) {
-      /* Check all Client ID's received in the command packet */
-      for (i = 0; i < client_id_count; i++) {
-       entry = silc_idlist_find_client_by_id(server->global_list, 
-                                             client_id[i], NULL);
-       if (entry) {
-         clients = silc_realloc(clients, sizeof(*clients) * 
-                                (clients_count + 1));
-         clients[clients_count++] = entry;
-       }
+  if (client_id_count) {
+    /* Check all Client ID's received in the command packet */
+    for (i = 0; i < client_id_count; i++) {
+      entry = silc_idlist_find_client_by_id(server->global_list, 
+                                           client_id[i], NULL);
+      if (entry) {
+       clients = silc_realloc(clients, sizeof(*clients) * 
+                              (clients_count + 1));
+       clients[clients_count++] = entry;
       }
-    } else {
-      clients = silc_idlist_get_clients_by_nickname(server->global_list, 
-                                                   nick, server_name,
-                                                   &clients_count);
-      if (!clients)
-       clients = silc_idlist_get_clients_by_hash(server->global_list, 
-                                                 nick, server->md5hash,
-                                                 &clients_count);
     }
+  } else {
+    if (!silc_idlist_get_clients_by_hash(server->global_list, 
+                                        nick, server->md5hash,
+                                        &clients, &clients_count))
+      silc_idlist_get_clients_by_nickname(server->global_list, 
+                                         nick, server_name,
+                                         &clients, &clients_count);
   }
   
   if (!clients) {
@@ -1616,17 +1598,16 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd)
       }
     }
   } else {
-    clients = silc_idlist_get_clients_by_nickname(server->local_list, 
-                                                 nick, server_name,
-                                                 &clients_count);
-    if (!clients)
-      clients = silc_idlist_get_clients_by_hash(server->local_list, 
-                                               nick, server->md5hash,
-                                               &clients_count);
+    if (!silc_idlist_get_clients_by_hash(server->local_list, 
+                                        nick, server->md5hash,
+                                        &clients, &clients_count))
+      silc_idlist_get_clients_by_nickname(server->local_list, 
+                                         nick, server_name,
+                                         &clients, &clients_count);
   }
   
   /* If we are router we will check our global list as well. */
-  if (!clients && server->server_type == SILC_ROUTER) {
+  if (server->server_type == SILC_ROUTER) {
     if (client_id_count) {
       /* Check all Client ID's received in the command packet */
       for (i = 0; i < client_id_count; i++) {
@@ -1639,13 +1620,12 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd)
        }
       }
     } else {
-      clients = silc_idlist_get_clients_by_nickname(server->global_list, 
-                                                   nick, server_name,
-                                                   &clients_count);
-      if (!clients)
-       clients = silc_idlist_get_clients_by_hash(server->global_list, 
-                                                 nick, server->md5hash,
-                                                 &clients_count);
+      if (!silc_idlist_get_clients_by_hash(server->global_list, 
+                                          nick, server->md5hash,
+                                          &clients, &clients_count))
+       silc_idlist_get_clients_by_nickname(server->global_list, 
+                                           nick, server_name,
+                                           &clients, &clients_count);
     }
   }
 
@@ -2517,21 +2497,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];
 
@@ -2547,14 +2553,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;
@@ -2605,6 +2614,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);
@@ -2614,7 +2626,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,
@@ -2964,7 +2976,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 
@@ -3254,10 +3266,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 */
@@ -3265,16 +3279,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,
@@ -3345,6 +3369,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;
 }
 
@@ -3355,28 +3389,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);
@@ -3620,6 +3643,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;
 
@@ -3628,7 +3702,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);
 
@@ -3637,7 +3711,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 */
@@ -3662,6 +3737,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;
@@ -3669,11 +3745,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);
@@ -3713,13 +3789,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;
     }
@@ -3756,18 +3825,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 
@@ -3782,10 +3861,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;
+    }
+
+    sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
+    notify = TRUE;
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
       if (target_client == client) {
@@ -3803,11 +3918,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;
@@ -3815,6 +3944,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) {
@@ -4097,6 +4227,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;
 
@@ -4210,10 +4343,139 @@ SILC_SERVER_CMD_FUNC(connect)
   silc_server_command_free(cmd);
 }
 
-SILC_SERVER_CMD_FUNC(restart)
+/* Server side of command BAN. This is used to manage the ban list of the
+   channel. To add clients and remove clients from the ban list. */
+
+SILC_SERVER_CMD_FUNC(ban)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcBuffer packet;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  SilcChannelID *channel_id = NULL;
+  unsigned char *id, *add, *del;
+  unsigned int id_len, tmp_len;
+  unsigned short ident = silc_command_get_ident(cmd->payload);
+
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+    goto out;
+
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_BAN, cmd, 0, 3);
+
+  /* Get Channel ID */
+  id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
+  if (id) {
+    channel_id = silc_id_payload_parse_id(id, id_len);
+    if (!channel_id) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
+      goto out;
+    }
+  }
 
+  /* Get channel entry. The server must know about the channel since the
+     client is expected to be on the channel. */
+  channel = silc_idlist_find_channel_by_id(server->local_list, 
+                                          channel_id, NULL);
+  if (!channel) {
+    channel = silc_idlist_find_channel_by_id(server->global_list, 
+                                            channel_id, NULL);
+    if (!channel) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+      goto out;
+    }
+  }
+
+  /* Check whether this client is on the channel */
+  if (!silc_server_client_on_channel(client, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+                                         SILC_STATUS_ERR_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 == client)
+      break;
+
+  /* The client must be at least channel operator. */
+  if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
+                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+    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;
+
+    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;
+      }
+    }
+  }
+
+  /* Send the BAN notify type to our primary router. */
+  if (!server->standalone && (add || del))
+    silc_server_send_notify_ban(server, server->router->connection,
+                               server->server_type == SILC_ROUTER ?
+                               TRUE : FALSE, channel, add, del);
+
+  /* Send the reply back to the client */
+  if (channel->ban_list)
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
+                                          SILC_STATUS_OK, ident, 2,
+                                          2, id, id_len,
+                                          3, channel->ban_list, 
+                                          strlen(channel->ban_list) - 1);
+  else
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
+                                          SILC_STATUS_OK, ident, 1,
+                                          2, id, id_len);
+
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+                         packet->data, packet->len, FALSE);
+    
+  silc_buffer_free(packet);
+
+ out:
+  if (channel_id)
+    silc_free(channel_id);
   silc_server_command_free(cmd);
 }
 
@@ -4318,7 +4580,7 @@ SILC_SERVER_CMD_FUNC(leave)
   SilcServer server = cmd->server;
   SilcSocketConnection sock = cmd->sock;
   SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
-  SilcChannelID *id;
+  SilcChannelID *id = NULL;
   SilcChannelEntry channel;
   unsigned int len;
   unsigned char *tmp;
@@ -4387,6 +4649,8 @@ SILC_SERVER_CMD_FUNC(leave)
   silc_free(id);
 
  out:
+  if (id)
+    silc_free(id);
   silc_server_command_free(cmd);
 }
 
@@ -4493,139 +4757,3 @@ SILC_SERVER_CMD_FUNC(users)
  out:
   silc_server_command_free(cmd);
 }
-
-/* Server side of command BAN. This is used to manage the ban list of the
-   channel. To add clients and remove clients from the ban list. */
-
-SILC_SERVER_CMD_FUNC(ban)
-{
-  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  SilcServer server = cmd->server;
-  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  SilcBuffer packet;
-  SilcChannelEntry channel;
-  SilcChannelClientEntry chl;
-  SilcChannelID *channel_id = NULL;
-  unsigned char *id, *add, *del;
-  unsigned int id_len, tmp_len;
-  unsigned short ident = silc_command_get_ident(cmd->payload);
-
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
-    goto out;
-
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_BAN, cmd, 0, 3);
-
-  /* Get Channel ID */
-  id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
-  if (id) {
-    channel_id = silc_id_payload_parse_id(id, id_len);
-    if (!channel_id) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
-                                           SILC_STATUS_ERR_NO_CHANNEL_ID);
-      goto out;
-    }
-  }
-
-  /* Get channel entry. The server must know about the channel since the
-     client is expected to be on the channel. */
-  channel = silc_idlist_find_channel_by_id(server->local_list, 
-                                          channel_id, NULL);
-  if (!channel) {
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
-                                            channel_id, NULL);
-    if (!channel) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
-                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL);
-      goto out;
-    }
-  }
-
-  /* Check whether this client is on the channel */
-  if (!silc_server_client_on_channel(client, channel)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
-                                         SILC_STATUS_ERR_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 == client)
-      break;
-
-  /* The client must be at least channel operator. */
-  if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
-                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
-    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;
-
-    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;
-      }
-    }
-  }
-
-  /* Send the BAN notify type to our primary router. */
-  if (!server->standalone && (add || del))
-    silc_server_send_notify_ban(server, server->router->connection,
-                               server->server_type == SILC_ROUTER ?
-                               TRUE : FALSE, channel, add, del);
-
-  /* Send the reply back to the client */
-  if (channel->ban_list)
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
-                                          SILC_STATUS_OK, ident, 2,
-                                          2, id, id_len,
-                                          3, channel->ban_list, 
-                                          strlen(channel->ban_list) - 1);
-  else
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
-                                          SILC_STATUS_OK, ident, 1,
-                                          2, id, id_len);
-
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
-                         packet->data, packet->len, FALSE);
-    
-  silc_buffer_free(packet);
-
- out:
-  if (channel_id)
-    silc_free(channel_id);
-  silc_server_command_free(cmd);
-}