updates.
[silc.git] / apps / silcd / command.c
index b1c7260a262f343b44444b6ee92127e012fc44ef..4133e7ce0517a4e380f9353dc1d2bf2e7e970532 100644 (file)
@@ -45,23 +45,23 @@ SilcServerCommand silc_command_list[] =
   SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
-  SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
-  SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
+  SILC_SERVER_CMD(list, LIST, SILC_CF_LAG_STRICT | SILC_CF_REG),
   SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
-  SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+  SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG_STRICT | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(connect, CONNECT, 
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
-  SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG_STRICT | SILC_CF_REG),
   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
-  SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
+  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 | 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(close, CLOSE,
@@ -70,7 +70,7 @@ SilcServerCommand silc_command_list[] =
                  SILC_CF_OPER),
   SILC_SERVER_CMD(silcoper, SILCOPER,
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
-  SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
   SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
 
   { NULL, 0 },
@@ -116,9 +116,8 @@ static int silc_server_is_registered(SilcServer server,
 
 /* Internal context to hold data when executed command with timeout. */
 typedef struct {
-  SilcServer server;
-  SilcSocketConnection sock;
-  SilcPacketContext *packet;
+  SilcServerCommandContext ctx;
+  SilcServerCommand *cmd;
 } *SilcServerCommandTimeout;
 
 /* Timeout callback to process commands with timeout for client. Client's
@@ -127,67 +126,61 @@ typedef struct {
 SILC_TASK_CALLBACK(silc_server_command_process_timeout)
 {
   SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
-  SilcServerCommandContext ctx;
-  SilcServerCommand *cmd;
-  SilcClientEntry client = (SilcClientEntry)timeout->sock->user_data;
+  SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data;
 
   /* Update access time */
   client->last_command = time(NULL);
 
+  if (!(timeout->cmd->flags & SILC_CF_REG))
+    timeout->cmd->cb(timeout->ctx);
+  else if (silc_server_is_registered(timeout->ctx->server, 
+                                    timeout->ctx->sock, 
+                                    timeout->ctx, 
+                                    timeout->cmd->cmd))
+    timeout->cmd->cb(timeout->ctx);
+
+  silc_free(timeout);
+}
+
+/* Processes received command packet. */
+
+void silc_server_command_process(SilcServer server,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet)
+{
+  SilcServerCommandContext ctx;
+  SilcServerCommand *cmd;
+
   /* Allocate command context. This must be free'd by the
      command routine receiving it. */
   ctx = silc_server_command_alloc();
-  ctx->server = timeout->server;
-  ctx->sock = timeout->sock;
-  ctx->packet = timeout->packet;
-
+  ctx->server = server;
+  ctx->sock = silc_socket_dup(sock);
+  ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
+  
   /* Parse the command payload in the packet */
-  ctx->payload = silc_command_payload_parse(ctx->packet->buffer);
+  ctx->payload = silc_command_payload_parse(packet->buffer);
   if (!ctx->payload) {
     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
-    silc_buffer_free(ctx->packet->buffer);
+    silc_buffer_free(packet->buffer);
+    silc_packet_context_free(packet);
     silc_socket_free(ctx->sock);
-    silc_packet_context_free(ctx->packet);
     silc_free(ctx);
-    silc_free(timeout);
     return;
   }
   ctx->args = silc_command_get_args(ctx->payload);
   
-  /* Execute command. If this fails the packet is dropped. */
+  /* Get the command */
   for (cmd = silc_command_list; cmd->cb; cmd++)
-    if (cmd->cmd == silc_command_get(ctx->payload)) {
-
-      if (!(cmd->flags & SILC_CF_REG)) {
-       cmd->cb(ctx);
-       break;
-      }
-      
-      if (silc_server_is_registered(ctx->server, ctx->sock, ctx, cmd->cmd)) {
-       cmd->cb(ctx);
-       break;
-      }
-    }
+    if (cmd->cmd == silc_command_get(ctx->payload))
+      break;
 
   if (cmd == NULL) {
     SILC_LOG_ERROR(("Unknown command, packet dropped"));
     silc_server_command_free(ctx);
-    silc_free(timeout);
     return;
   }
 
-  silc_free(timeout);
-}
-
-/* Processes received command packet. */
-
-void silc_server_command_process(SilcServer server,
-                                SilcSocketConnection sock,
-                                SilcPacketContext *packet)
-{
-  SilcServerCommandContext ctx;
-  SilcServerCommand *cmd;
-
   /* Execute client's commands always with timeout.  Normally they are
      executed with zero (0) timeout but if client is sending command more
      frequently than once in 2 seconds, then the timeout may be 0 to 2
@@ -195,12 +188,22 @@ void silc_server_command_process(SilcServer server,
   if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
     SilcClientEntry client = (SilcClientEntry)sock->user_data;
     SilcServerCommandTimeout timeout = silc_calloc(1, sizeof(*timeout));
+    int fast;
 
-    timeout->server = server;
-    timeout->sock = silc_socket_dup(sock);
-    timeout->packet = silc_packet_context_dup(packet);
+    timeout->ctx = ctx;
+    timeout->cmd = cmd;
 
-    if (client->last_command && (time(NULL) - client->last_command) < 2)
+    if (client->last_command && (time(NULL) - client->last_command) < 2) {
+      client->fast_command++;
+      fast = FALSE;
+    } else {
+      client->fast_command = ((client->fast_command - 1) <= 0 ? 0 : 
+                             client->fast_command--);
+      fast = TRUE;
+    }
+
+    if (!fast && ((cmd->flags & SILC_CF_LAG_STRICT) ||
+                 (client->fast_command > 5 && cmd->flags & SILC_CF_LAG)))
       silc_task_register(server->timeout_queue, sock->sock, 
                         silc_server_command_process_timeout,
                         (void *)timeout, 
@@ -217,45 +220,12 @@ void silc_server_command_process(SilcServer server,
     return;
   }
 
-  /* Allocate command context. This must be free'd by the
-     command routine receiving it. */
-  ctx = silc_server_command_alloc();
-  ctx->server = server;
-  ctx->sock = silc_socket_dup(sock);
-  ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
-  
-  /* Parse the command payload in the packet */
-  ctx->payload = silc_command_payload_parse(packet->buffer);
-  if (!ctx->payload) {
-    SILC_LOG_ERROR(("Bad command payload, packet dropped"));
-    silc_buffer_free(packet->buffer);
-    silc_packet_context_free(packet);
-    silc_socket_free(ctx->sock);
-    silc_free(ctx);
-    return;
-  }
-  ctx->args = silc_command_get_args(ctx->payload);
-  
-  /* Execute command. If this fails the packet is dropped. */
-  for (cmd = silc_command_list; cmd->cb; cmd++)
-    if (cmd->cmd == silc_command_get(ctx->payload)) {
+  /* Execute for server */
 
-      if (!(cmd->flags & SILC_CF_REG)) {
-       cmd->cb(ctx);
-       break;
-      }
-      
-      if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
-       cmd->cb(ctx);
-       break;
-      }
-    }
-
-  if (cmd == NULL) {
-    SILC_LOG_ERROR(("Unknown command, packet dropped"));
-    silc_server_command_free(ctx);
-    return;
-  }
+  if (!(cmd->flags & SILC_CF_REG))
+    cmd->cb(ctx);
+  else if (silc_server_is_registered(server, sock, ctx, cmd->cmd))
+    cmd->cb(ctx);
 }
 
 /* Allocate Command Context */
@@ -563,7 +533,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   for (i = 0; i < clients_count; i++) {
     entry = clients[i];
 
-    if (entry->data.registered == FALSE) {
+    if (entry->connection && entry->data.registered == FALSE) {
       if (clients_count == 1)
        silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
                                             SILC_STATUS_ERR_NO_SUCH_NICK,
@@ -1296,7 +1266,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
   for (i = 0; i < clients_count; i++) {
     entry = clients[i];
 
-    if (entry->data.registered == FALSE) {
+    if (entry->connection && entry->data.registered == FALSE) {
       if (clients_count == 1)
        silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
                                             SILC_STATUS_ERR_NO_SUCH_NICK,
@@ -1716,7 +1686,7 @@ SILC_SERVER_CMD_FUNC(nick)
   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
   /* Send NICK_CHANGE notify to the client's channels */
-  silc_server_send_notify_on_channels(server, client, 
+  silc_server_send_notify_on_channels(server, NULL, client, 
                                      SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
                                      oidp->data, oidp->len, 
                                      nidp->data, nidp->len);
@@ -2040,8 +2010,102 @@ SILC_SERVER_CMD_FUNC(quit)
   silc_server_command_free(cmd);
 }
 
+/* Server side of command KILL. This command is used by router operator
+   to remove an client from the SILC Network temporarily. */
+
 SILC_SERVER_CMD_FUNC(kill)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry remote_client;
+  SilcClientID *client_id;
+  unsigned char *tmp, *comment;
+  unsigned int tmp_len;
+  SilcBuffer idp;
+
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_KILL, cmd, 1, 2);
+
+  if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+    goto out;
+
+  if (server->server_type != SILC_ROUTER)
+    goto out;
+
+  /* Check whether client has the permissions. */
+  if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                         SILC_STATUS_ERR_NO_ROUTER_PRIV);
+    goto out;
+  }
+
+  /* Get the client ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  client_id = silc_id_payload_parse_id(tmp, tmp_len);
+  if (!client_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                         SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+    goto out;
+  }
+
+  /* Get the client entry */
+  remote_client = silc_idlist_find_client_by_id(server->local_list, 
+                                               client_id, NULL);
+  if (!remote_client) {
+    remote_client = silc_idlist_find_client_by_id(server->global_list, 
+                                                 client_id, NULL);
+    if (!remote_client) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+      goto out;
+    }
+  }
+
+  /* Get comment */
+  comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+
+  /* Send reply to the sender */
+  silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
+                                       SILC_STATUS_OK);
+
+  /* Send KILLED notify to the channels. It is not sent to the client
+     as it will be sent differently destined directly to the client and not
+     to the channel. */
+  idp = silc_id_payload_encode(remote_client->id, SILC_ID_CLIENT);
+  silc_server_send_notify_on_channels(server, remote_client->connection, 
+                                     remote_client, SILC_NOTIFY_TYPE_KILLED,
+                                     comment ? 2 : 1,
+                                     idp->data, idp->len,
+                                     comment, comment ? strlen(comment) : 0);
+  silc_buffer_free(idp);
+
+  /* Remove the client from all channels. This generates new keys to the
+     channels as well. */
+  silc_server_remove_from_channels(server, NULL, remote_client, FALSE, 
+                                  NULL, TRUE);
+
+  /* Send KILLED notify to the client directly */
+  silc_server_send_notify_killed(server, remote_client->connection ? 
+                                remote_client->connection : 
+                                remote_client->router->connection, FALSE,
+                                remote_client->id, SILC_ID_CLIENT_LEN,
+                                comment);
+
+  /* Send KILLED notify to primary route */
+  if (!server->standalone)
+    silc_server_send_notify_killed(server, server->router->connection,
+                                  server->server_type == SILC_ROUTER ?
+                                  TRUE : FALSE,
+                                  remote_client->id, SILC_ID_CLIENT_LEN,
+                                  comment);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
 /* Server side of command INFO. This sends information about us to 
@@ -3310,7 +3374,7 @@ SILC_SERVER_CMD_FUNC(kick)
   silc_buffer_free(idp);
 
   /* Remove the client from the channel. If the channel does not exist
-     after removing the client then the client kicked itself of the channel
+     after removing the client then the client kicked itself off the channel
      and we don't have to send anything after that. */
   if (!silc_server_remove_from_one_channel(server, NULL, channel, 
                                           target_client, FALSE))
@@ -3328,7 +3392,7 @@ SILC_SERVER_CMD_FUNC(kick)
   silc_server_create_channel_key(server, channel, 0);
 
   /* Send the channel key to the channel. The key of course is not sent
-     to the client who joined the channel. */
+     to the client who was kicked off the channel. */
   silc_server_send_channel_key(server, target_client->connection, channel, 
                               server->server_type == SILC_ROUTER ? 
                               FALSE : !server->standalone);
@@ -3337,12 +3401,138 @@ SILC_SERVER_CMD_FUNC(kick)
   silc_server_command_free(cmd);
 }
 
+/* Server side of OPER command. Client uses this comand to obtain server
+   operator privileges to this server/router. */
+
 SILC_SERVER_CMD_FUNC(oper)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  unsigned char *username, *auth;
+  unsigned int tmp_len;
+  SilcServerConfigSectionAdminConnection *admin;
+  SilcIDListData idata = (SilcIDListData)client;
+
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_OPER, cmd, 1, 2);
+
+  if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+    goto out;
+
+  /* Get the username */
+  username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!username) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+
+  /* Get the admin configuration */
+  admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
+                                       username, client->nickname);
+  if (!admin) {
+    admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
+                                         username, client->nickname);
+    if (!admin) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+                                           SILC_STATUS_ERR_AUTH_FAILED);
+      goto out;
+    }
+  }
+
+  /* Get the authentication payload */
+  auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+  if (!auth) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+
+  /* Verify the authentication data */
+  if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, 
+                            admin->auth_data, admin->auth_data_len,
+                            idata->hash, client->id, SILC_ID_CLIENT)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+                                         SILC_STATUS_ERR_AUTH_FAILED);
+    goto out;
+  }
+
+  /* Client is now server operator */
+  client->mode |= SILC_UMODE_SERVER_OPERATOR;
+
+  /* Send reply to the sender */
+  silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+                                       SILC_STATUS_OK);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
+/* Server side of SILCOPER command. Client uses this comand to obtain router
+   operator privileges to this router. */
+
 SILC_SERVER_CMD_FUNC(silcoper)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  unsigned char *username, *auth;
+  unsigned int tmp_len;
+  SilcServerConfigSectionAdminConnection *admin;
+  SilcIDListData idata = (SilcIDListData)client;
+
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SILCOPER, cmd, 1, 2);
+
+  if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+    goto out;
+
+  /* Get the username */
+  username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!username) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+
+  /* Get the admin configuration */
+  admin = silc_server_config_find_admin(server->config, cmd->sock->ip,
+                                       username, client->nickname);
+  if (!admin) {
+    admin = silc_server_config_find_admin(server->config, cmd->sock->hostname,
+                                         username, client->nickname);
+    if (!admin) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+                                           SILC_STATUS_ERR_AUTH_FAILED);
+      goto out;
+    }
+  }
+
+  /* Get the authentication payload */
+  auth = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+  if (!auth) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+
+  /* Verify the authentication data */
+  if (!silc_auth_verify_data(auth, tmp_len, admin->auth_meth, 
+                            admin->auth_data, admin->auth_data_len,
+                            idata->hash, client->id, SILC_ID_CLIENT)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+                                         SILC_STATUS_ERR_AUTH_FAILED);
+    goto out;
+  }
+
+  /* Client is now router operator */
+  client->mode |= SILC_UMODE_ROUTER_OPERATOR;
+
+  /* Send reply to the sender */
+  silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+                                       SILC_STATUS_OK);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
 /* Server side command of CONNECT. Connects us to the specified remote
@@ -3353,7 +3543,7 @@ SILC_SERVER_CMD_FUNC(connect)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-  unsigned char *tmp;
+  unsigned char *tmp, *host;
   unsigned int tmp_len;
   unsigned int port = SILC_PORT;
 
@@ -3377,8 +3567,8 @@ SILC_SERVER_CMD_FUNC(connect)
   }
 
   /* Get the remote server */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  host = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!host) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -3390,7 +3580,7 @@ SILC_SERVER_CMD_FUNC(connect)
     SILC_GET32_MSB(port, tmp);
 
   /* Create the connection. It is done with timeout and is async. */
-  silc_server_create_connection(server, tmp, port);
+  silc_server_create_connection(server, host, port);
 
   /* Send reply to the sender */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
@@ -3412,6 +3602,7 @@ SILC_SERVER_CMD_FUNC(close)
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   SilcServerEntry server_entry;
+  SilcSocketConnection sock;
   unsigned char *tmp;
   unsigned int tmp_len;
   unsigned char *name;
@@ -3450,16 +3641,15 @@ SILC_SERVER_CMD_FUNC(close)
     goto out;
   }
 
-  /* Close the connection to the server */
-  silc_server_free_sock_user_data(server, server_entry->connection);
-  silc_server_disconnect_remote(server, server_entry->connection,
-                               "Server closed connection: "
-                               "Closed by operator");
-  
   /* Send reply to the sender */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
                                        SILC_STATUS_OK);
 
+  /* Close the connection to the server */
+  sock = (SilcSocketConnection)server_entry->connection;
+  silc_server_free_sock_user_data(server, sock);
+  silc_server_close_connection(server, sock);
+  
  out:
   silc_server_command_free(cmd);
 }
@@ -3485,13 +3675,14 @@ SILC_SERVER_CMD_FUNC(shutdown)
     goto out;
   }
 
-  /* Then, gracefully, or not, bring the server down. */
-  silc_server_stop(server);
-
   /* Send reply to the sender */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
                                        SILC_STATUS_OK);
 
+  /* Then, gracefully, or not, bring the server down. */
+  silc_server_stop(server);
+  exit(0);
+
  out:
   silc_server_command_free(cmd);
 }