When disabled channel is found on normal server in JOIN, do
[silc.git] / apps / silcd / command.c
index 1a5c7c5faebe1ff6b555adc9cd8f5b3f19209b5e..086836c5645b65fc17cd9b6e1a8574d3d001f671 100644 (file)
@@ -234,9 +234,15 @@ void silc_server_command_process(SilcServer server,
      seconds. */
   if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
     SilcClientEntry client = (SilcClientEntry)sock->user_data;
-    SilcServerCommandTimeout timeout = silc_calloc(1, sizeof(*timeout));
+    SilcServerCommandTimeout timeout;
     int fast;
 
+    if (!client) {
+      SILC_LOG_DEBUG(("Client entry is invalid"));
+      silc_server_command_free(ctx);
+    }
+
+    timeout = silc_calloc(1, sizeof(*timeout));
     timeout->ctx = ctx;
     timeout->cmd = cmd;
 
@@ -366,9 +372,11 @@ void silc_server_command_pending_del(SilcServer server,
 
   silc_dlist_start(server->pending_commands);
   while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
-    if (r->reply_cmd == reply_cmd && r->ident == ident) {
+    if ((r->reply_cmd == reply_cmd || (r->reply_cmd == SILC_COMMAND_NONE &&
+                                       r->reply_check))
+        && r->ident == ident) {
       silc_dlist_del(server->pending_commands, r);
-      break;
+      silc_free(r);
     }
   }
 }
@@ -394,6 +402,7 @@ silc_server_command_pending_check(SilcServer server,
       callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
       callbacks[i].context = r->context;
       callbacks[i].callback = r->callback;
+      r->reply_check = TRUE;
       ctx->ident = ident;
       i++;
     }
@@ -733,7 +742,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   char nh[256], uh[256];
   unsigned char idle[4], mode[4];
-  unsigned char *fingerprint;
+  unsigned char *fingerprint, fempty[20];
   SilcSocketConnection hsock;
 
   if (nickname) {
@@ -755,6 +764,8 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
     }
   }
 
+  memset(fempty, 0, sizeof(fempty));
+
   /* Start processing found clients. */
   status = SILC_STATUS_OK;
   if (valid_count > 1)
@@ -808,7 +819,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
       channels = silc_server_get_client_channel_list(server, entry, TRUE, 
                                                     TRUE, &umode_list);
 
-    if (entry->data.fingerprint[0] != 0 && entry->data.fingerprint[1] != 0)
+    if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
       fingerprint = entry->data.fingerprint;
     else
       fingerprint = NULL;
@@ -902,7 +913,7 @@ silc_server_command_whois_send_router(SilcServerCommandContext cmd)
 
   /* Send WHOIS command to our router */
   silc_server_packet_send(server, (SilcSocketConnection)
-                         server->router->connection,
+                         SILC_PRIMARY_ROUTE(server),
                          SILC_PACKET_COMMAND, cmd->packet->flags,
                          tmpbuf->data, tmpbuf->len, TRUE);
 
@@ -1266,8 +1277,7 @@ silc_server_command_whowas_process(SilcServerCommandContext cmd)
     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
     /* Send WHOWAS command to our router */
-    silc_server_packet_send(server, (SilcSocketConnection)
-                           server->router->connection,
+    silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            SILC_PACKET_COMMAND, cmd->packet->flags,
                            tmpbuf->data, tmpbuf->len, TRUE);
 
@@ -1369,7 +1379,7 @@ silc_server_command_identify_send_router(SilcServerCommandContext cmd)
 
   /* Send IDENTIFY command to our router */
   silc_server_packet_send(server, (SilcSocketConnection)
-                         server->router->connection,
+                         SILC_PRIMARY_ROUTE(server),
                          SILC_PACKET_COMMAND, cmd->packet->flags,
                          tmpbuf->data, tmpbuf->len, TRUE);
 
@@ -1618,6 +1628,7 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
        break;
       }
 
+      silc_id_payload_free(idp);
       silc_free(id);
     }
   }
@@ -2079,7 +2090,7 @@ SILC_SERVER_CMD_FUNC(nick)
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   int nickfail = 0;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_NICK, cmd, 1, 1);
@@ -2117,11 +2128,9 @@ SILC_SERVER_CMD_FUNC(nick)
   /* Send notify about nickname change to our router. We send the new
      ID and ask to replace it with the old one. If we are router the
      packet is broadcasted. Send NICK_CHANGE notify. */
-  if (!server->standalone)
-    silc_server_send_notify_nick_change(server, server->router->connection, 
-                                       server->server_type == SILC_SERVER ? 
-                                       FALSE : TRUE, client->id,
-                                       new_id, nick);
+  silc_server_send_notify_nick_change(server, SILC_PRIMARY_ROUTE(server),
+                                     SILC_BROADCAST(server), client->id,
+                                     new_id, nick);
 
   /* Check if anyone is watching the old nickname */
   if (server->server_type == SILC_ROUTER)
@@ -2316,7 +2325,7 @@ SILC_SERVER_CMD_FUNC(list)
     old_ident = silc_command_get_ident(cmd->payload);
     silc_command_set_ident(cmd->payload, ++server->cmd_ident);
     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-    silc_server_packet_send(server, server->router->connection,
+    silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            SILC_PACKET_COMMAND, cmd->packet->flags,
                            tmpbuf->data, tmpbuf->len, TRUE);
 
@@ -2377,6 +2386,9 @@ SILC_SERVER_CMD_FUNC(topic)
   SilcUInt32 argc, tmp_len;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
 
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
+    goto out;
+
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_TOPIC, cmd, 1, 2);
 
   argc = silc_argument_get_arg_num(cmd->args);
@@ -2443,26 +2455,26 @@ SILC_SERVER_CMD_FUNC(topic)
       goto out;
     }
 
-    /* Set the topic for channel */
-    silc_free(channel->topic);
-    channel->topic = strdup(tmp);
+    if (!channel->topic || strcmp(channel->topic, tmp)) {
+      /* Set the topic for channel */
+      silc_free(channel->topic);
+      channel->topic = strdup(tmp);
 
-    /* Send TOPIC_SET notify type to the network */
-    if (!server->standalone)
-      silc_server_send_notify_topic_set(server, server->router->connection,
-                                       server->server_type == SILC_ROUTER ?
-                                       TRUE : FALSE, channel, 
+      /* Send TOPIC_SET notify type to the network */
+      silc_server_send_notify_topic_set(server, SILC_PRIMARY_ROUTE(server),
+                                       SILC_BROADCAST(server), channel,
                                        client->id, SILC_ID_CLIENT,
                                        channel->topic);
 
-    idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
-    /* Send notify about topic change to all clients on the channel */
-    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
-                                      SILC_NOTIFY_TYPE_TOPIC_SET, 2,
-                                      idp->data, idp->len,
-                                      channel->topic, strlen(channel->topic));
-    silc_buffer_free(idp);
+      /* Send notify about topic change to all clients on the channel */
+      idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
+                                        SILC_NOTIFY_TYPE_TOPIC_SET, 2,
+                                        idp->data, idp->len,
+                                        channel->topic,
+                                        strlen(channel->topic));
+      silc_buffer_free(idp);
+    }
   }
 
   /* Send the topic to client as reply packet */
@@ -2535,7 +2547,7 @@ SILC_SERVER_CMD_FUNC(invite)
 
   /* Check whether the sender of this command is on the channel. */
   sender = (SilcClientEntry)sock->user_data;
-  if (!silc_server_client_on_channel(sender, channel, &chl)) {
+  if (!sender || !silc_server_client_on_channel(sender, channel, &chl)) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
                                          SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
     goto out;
@@ -2684,11 +2696,9 @@ SILC_SERVER_CMD_FUNC(invite)
   }
 
   /* Send notify to the primary router */
-  if (!server->standalone)
-    silc_server_send_notify_invite(server, server->router->connection,
-                                  server->server_type == SILC_ROUTER ?
-                                  TRUE : FALSE, channel,
-                                  sender->id, add, del);
+  silc_server_send_notify_invite(server, SILC_PRIMARY_ROUTE(server),
+                                SILC_BROADCAST(server), channel,
+                                sender->id, add, del);
 
   /* Send command reply */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
@@ -2793,7 +2803,7 @@ SILC_SERVER_CMD_FUNC(kill)
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2);
 
-  if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
 
   /* KILL command works only on router */
@@ -2978,7 +2988,7 @@ SILC_SERVER_CMD_FUNC(info)
       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
-      silc_server_packet_send(server, server->router->connection,
+      silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
                              tmpbuf->data, tmpbuf->len, TRUE);
 
@@ -3111,7 +3121,7 @@ SILC_SERVER_CMD_FUNC(stats)
     packet = silc_command_payload_encode_va(SILC_COMMAND_STATS, 
                                            ++server->cmd_ident, 1,
                                            1, idp->data, idp->len);
-    silc_server_packet_send(server, server->router->connection,
+    silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            SILC_PACKET_COMMAND, 0, packet->data,
                            packet->len, FALSE);
 
@@ -3197,6 +3207,8 @@ static void silc_server_command_join_channel(SilcServer server,
   /* Get the client entry */
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
     client = (SilcClientEntry)sock->user_data;
+    if (!client)
+      return;
   } else {
     client = silc_server_get_client_resolve(server, client_id, FALSE, 
                                            &resolve);
@@ -3456,10 +3468,8 @@ static void silc_server_command_join_channel(SilcServer server,
 
   if (!cmd->pending) {
     /* Send JOIN notify packet to our primary router */
-    if (!server->standalone)
-      silc_server_send_notify_join(server, server->router->connection,
-                                  server->server_type == SILC_ROUTER ?
-                                  TRUE : FALSE, channel, client->id);
+    silc_server_send_notify_join(server, SILC_PRIMARY_ROUTE(server),
+                                SILC_BROADCAST(server), channel, client->id);
 
     if (keyp)
       /* Distribute the channel key to all backup routers. */
@@ -3480,10 +3490,9 @@ static void silc_server_command_join_channel(SilcServer server,
   }
 
   /* Set CUMODE notify type to network */
-  if (founder && !server->standalone)
-    silc_server_send_notify_cumode(server, server->router->connection,
-                                  server->server_type == SILC_ROUTER ?
-                                  TRUE : FALSE, channel,
+  if (founder)
+    silc_server_send_notify_cumode(server, SILC_PRIMARY_ROUTE(server),
+                                  SILC_BROADCAST(server), channel,
                                   chl->mode, client->id, SILC_ID_CLIENT,
                                   client->id, channel->founder_key);
 
@@ -3562,31 +3571,39 @@ SILC_SERVER_CMD_FUNC(join)
 
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
     SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
+    if (!entry) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                           0);
+      goto out;
+    }
+
     silc_free(client_id);
     client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
 
     if (!channel || 
        (channel->disabled && server->server_type != SILC_ROUTER)) {
-      /* Channel not found */
+      /* Channel not found or not valid */
 
       /* If we are standalone server we don't have a router, we just create 
-        the channel by ourselves. */
+        the channel by ourselves (unless it existed). */
       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,
-                                        0);
-         silc_free(client_id);
-         goto out;
-       }
-       
-       umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
-       created = TRUE;
-       create_key = FALSE;
+         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,
+                                 0);
+           silc_free(client_id);
+           goto out;
+         }
        
+         umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+         created = TRUE;
+         create_key = FALSE;
+       }
       } else {
 
        /* The channel does not exist on our server. If we are normal server 
@@ -3611,7 +3628,7 @@ SILC_SERVER_CMD_FUNC(join)
          
          /* Send JOIN command to our router */
          silc_server_packet_send(server, (SilcSocketConnection)
-                                 server->router->connection,
+                                 SILC_PRIMARY_ROUTE(server),
                                  SILC_PACKET_COMMAND, cmd->packet->flags,
                                  tmpbuf->data, tmpbuf->len, TRUE);
          
@@ -3700,7 +3717,7 @@ SILC_SERVER_CMD_FUNC(join)
        /* Save channel passphrase, if user provided it successfully */
        unsigned char *pa;
        SilcUInt32 pa_len;
-       pa = silc_argument_get_arg_type(reply->args, 3, &pa_len);
+       pa = silc_argument_get_arg_type(cmd->args, 3, &pa_len);
        if (pa) {
          silc_free(channel->passphrase);
          channel->passphrase = silc_memdup(pa, pa_len);
@@ -3828,7 +3845,7 @@ SILC_SERVER_CMD_FUNC(motd)
       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
-      silc_server_packet_send(server, server->router->connection,
+      silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
                              tmpbuf->data, tmpbuf->len, TRUE);
 
@@ -3881,7 +3898,7 @@ SILC_SERVER_CMD_FUNC(umode)
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   bool set_mask = FALSE;
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_UMODE, cmd, 1, 2);
@@ -3929,9 +3946,9 @@ SILC_SERVER_CMD_FUNC(umode)
     client->mode = mask;
 
     /* Send UMODE change to primary router */
-    if (!server->standalone)
-      silc_server_send_notify_umode(server, server->router->connection, TRUE,
-                                   client->id, client->mode);
+    silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),
+                                 SILC_BROADCAST(server), client->id,
+                                 client->mode);
 
     /* Check if anyone is watching this nickname */
     if (server->server_type == SILC_ROUTER)
@@ -3966,13 +3983,18 @@ SILC_SERVER_CMD_FUNC(cmode)
   SilcBuffer packet, cidp;
   unsigned char *tmp, *tmp_id, *tmp_mask;
   char *cipher = NULL, *hmac = NULL, *passphrase = NULL;
-  SilcUInt32 mode_mask = 0, tmp_len, tmp_len2;
+  SilcUInt32 mode_mask = 0, old_mask = 0, tmp_len, tmp_len2;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   bool set_mask = FALSE;
   SilcPublicKey founder_key = NULL;
   unsigned char *fkey = NULL;
   SilcUInt32 fkey_len = 0;
 
+  if (!client) {
+    silc_server_command_free(cmd);
+    return;
+  }
+
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 1, 7);
 
   /* Get Channel ID */
@@ -3980,20 +4002,15 @@ SILC_SERVER_CMD_FUNC(cmode)
   if (!tmp_id) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-    goto out;
+    silc_server_command_free(cmd);
+    return;
   }
   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2, NULL);
   if (!channel_id) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
-    goto out;
-  }
-
-  /* Get the channel mode mask */
-  tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (tmp_mask) {
-    SILC_GET32_MSB(mode_mask, tmp_mask);
-    set_mask = TRUE;
+    silc_server_command_free(cmd);
+    return;
   }
 
   /* Get channel entry */
@@ -4006,9 +4023,19 @@ SILC_SERVER_CMD_FUNC(cmode)
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                            SILC_STATUS_ERR_NO_SUCH_CHANNEL,
                                            0);
-      goto out;
+      silc_free(channel_id);
+      silc_server_command_free(cmd);
+      return;
     }
   }
+  old_mask = channel->mode;
+
+  /* Get the channel mode mask */
+  tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+  if (tmp_mask) {
+    SILC_GET32_MSB(mode_mask, tmp_mask);
+    set_mask = TRUE;
+  }
 
   /* Check whether this client is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
@@ -4020,6 +4047,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   /* Check that client has rights to change any requested channel modes */
   if (set_mask && !silc_server_check_cmode_rights(server, channel, chl, 
                                                  mode_mask)) {
+    SILC_LOG_DEBUG(("Client does not have rights to change mode"));
     silc_server_command_send_status_reply(
                             cmd, SILC_COMMAND_CMODE,
                             (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) ? 
@@ -4291,6 +4319,8 @@ SILC_SERVER_CMD_FUNC(cmode)
          silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                                SILC_STATUS_ERR_AUTH_FAILED,
                                                0);
+         silc_pkcs_public_key_free(channel->founder_key);
+         channel->founder_key = NULL;
          goto out;
         }
       }
@@ -4306,7 +4336,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   }
 
   /* Finally, set the mode */
-  channel->mode = mode_mask;
+  old_mask = channel->mode = mode_mask;
 
   /* Send CMODE_CHANGE notify. */
   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
@@ -4321,12 +4351,10 @@ SILC_SERVER_CMD_FUNC(cmode)
                                     fkey, fkey_len);
 
   /* Set CMODE notify type to network */
-  if (!server->standalone)
-    silc_server_send_notify_cmode(server, server->router->connection,
-                                 server->server_type == SILC_ROUTER ? 
-                                 TRUE : FALSE, channel,
-                                 mode_mask, client->id, SILC_ID_CLIENT,
-                                 cipher, hmac, passphrase, founder_key);
+  silc_server_send_notify_cmode(server, SILC_PRIMARY_ROUTE(server),
+                               SILC_BROADCAST(server), channel,
+                               mode_mask, client->id, SILC_ID_CLIENT,
+                               cipher, hmac, passphrase, founder_key);
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
@@ -4335,11 +4363,12 @@ SILC_SERVER_CMD_FUNC(cmode)
                                                3, tmp_mask, 4);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
-    
+
   silc_buffer_free(packet);
   silc_buffer_free(cidp);
 
  out:
+  channel->mode = old_mask;
   silc_free(fkey);
   silc_free(channel_id);
   silc_server_command_free(cmd);
@@ -4367,6 +4396,9 @@ SILC_SERVER_CMD_FUNC(cumode)
   unsigned char *fkey = NULL;
   SilcUInt32 fkey_len = 0;
 
+  if (!client)
+    goto out;
+
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CUMODE, cmd, 3, 4);
 
   /* Get Channel ID */
@@ -4680,13 +4712,10 @@ SILC_SERVER_CMD_FUNC(cumode)
                                       fkey, fkey_len);
 
     /* Set CUMODE notify type to network */
-    if (!server->standalone)
-      silc_server_send_notify_cumode(server, server->router->connection,
-                                    server->server_type == SILC_ROUTER ? 
-                                    TRUE : FALSE, channel,
-                                    target_mask, client->id, 
-                                    SILC_ID_CLIENT,
-                                    target_client->id, founder_key);
+    silc_server_send_notify_cumode(server, SILC_PRIMARY_ROUTE(server),
+                                  SILC_BROADCAST(server), channel,
+                                  target_mask, client->id, SILC_ID_CLIENT,
+                                  target_client->id, founder_key);
   }
 
   /* Send command reply to sender */
@@ -4724,6 +4753,9 @@ SILC_SERVER_CMD_FUNC(kick)
   SilcUInt32 tmp_len, target_idp_len;
   unsigned char *tmp, *comment, *target_idp;
 
+  if (!client)
+    goto out;
+
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 3);
 
   /* Get Channel ID */
@@ -4827,6 +4859,11 @@ SILC_SERVER_CMD_FUNC(kick)
                                     idp->data, idp->len);
   silc_buffer_free(idp);
 
+  /* Send KICKED notify to primary route */
+  silc_server_send_notify_kicked(server, SILC_PRIMARY_ROUTE(server),
+                                SILC_BROADCAST(server), channel,
+                                target_client->id, client->id, comment);
+
   /* Remove the client from the channel. If the channel does not exist
      after removing the client then the client kicked itself off the channel
      and we don't have to send anything after that. */
@@ -4834,13 +4871,6 @@ SILC_SERVER_CMD_FUNC(kick)
                                           target_client, FALSE))
     goto out;
 
-  /* Send KICKED notify to primary route */
-  if (!server->standalone)
-    silc_server_send_notify_kicked(server, server->router->connection,
-                                  server->server_type == SILC_ROUTER ?
-                                  TRUE : FALSE, channel,
-                                  target_client->id, client->id, comment);
-
   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
     /* Re-generate channel key */
     if (!silc_server_create_channel_key(server, channel, 0))
@@ -4872,11 +4902,11 @@ SILC_SERVER_CMD_FUNC(oper)
   bool result = FALSE;
   SilcPublicKey cached_key;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
-
-  if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
 
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
+
   /* Get the username */
   username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   if (!username) {
@@ -4935,15 +4965,15 @@ SILC_SERVER_CMD_FUNC(oper)
   client->mode |= SILC_UMODE_SERVER_OPERATOR;
 
   /* Update statistics */
-  if (client->connection)
+  if (SILC_IS_LOCAL(client))
     server->stat.my_server_ops++;
   if (server->server_type == SILC_ROUTER)
     server->stat.server_ops++;
 
   /* Send UMODE change to primary router */
-  if (!server->standalone)
-    silc_server_send_notify_umode(server, server->router->connection, TRUE,
-                                 client->id, client->mode);
+  silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),
+                               SILC_BROADCAST(server), client->id,
+                               client->mode);
 
   /* Check if anyone is watching this nickname */
   if (server->server_type == SILC_ROUTER)
@@ -4961,18 +4991,27 @@ SILC_SERVER_CMD_FUNC(oper)
 SILC_TASK_CALLBACK(silc_server_command_detach_cb)
 {
   QuitInternal q = (QuitInternal)context;
-  SilcClientEntry client = (SilcClientEntry)q->sock->user_data;
+  SilcClientID *client_id = (SilcClientID *)q->sock;
+  SilcClientEntry client;
+  SilcSocketConnection sock;
 
-  /* If there is pending outgoing data for the client then purge it
-     to the network before closing connection. */
-  silc_server_packet_queue_purge(q->server, q->sock);
+  client = silc_idlist_find_client_by_id(q->server->local_list, client_id,
+                                        TRUE, NULL);
+  if (client && client->connection) {
+    sock = client->connection;
 
-  /* Close the connection on our side */
-  client->router = NULL;
-  client->connection = NULL;
-  q->sock->user_data = NULL;
-  silc_server_close_connection(q->server, q->sock);
+    /* If there is pending outgoing data for the client then purge it
+       to the network before closing connection. */
+    silc_server_packet_queue_purge(q->server, sock);
+
+    /* Close the connection on our side */
+    client->router = NULL;
+    client->connection = NULL;
+    sock->user_data = NULL;
+    silc_server_close_connection(q->server, sock);
+  }
 
+  silc_free(client_id);
   silc_free(q);
 }
 
@@ -4983,11 +5022,12 @@ SILC_TASK_CALLBACK(silc_server_command_detach_timeout)
   SilcClientEntry client;
 
   client = silc_idlist_find_client_by_id(q->server->local_list, client_id,
-                                        FALSE, NULL);
-
-  if (client && client->mode & SILC_UMODE_DETACHED)
+                                        TRUE, NULL);
+  if (client && client->mode & SILC_UMODE_DETACHED) {
+    SILC_LOG_DEBUG(("Detach timeout"));
     silc_server_free_client_data(q->server, NULL, client, TRUE,
                                 "Detach timeout");
+  }
 
   silc_free(client_id);
   silc_free(q);
@@ -5009,20 +5049,24 @@ SILC_SERVER_CMD_FUNC(detach)
     goto out;
   }
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_DETACH, cmd, 0, 0);
 
+  /* Remove operator privileges, since the client may resume in some
+     other server which to it does not have operator privileges. */
+  SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+  SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
   /* Send the user mode notify to notify that client is detached */
   client->mode |= SILC_UMODE_DETACHED;
   client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
   client->last_command = 0;
   client->fast_command = 0;
-  if (!server->standalone)
-    silc_server_send_notify_umode(server, server->router->connection,
-                                 server->server_type == SILC_SERVER ?
-                                 FALSE : TRUE, client->id, client->mode);
+  silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),
+                               SILC_BROADCAST(server), client->id,
+                               client->mode);
   server->stat.my_detached++;
 
   /* Check if anyone is watching this nickname */
@@ -5032,7 +5076,7 @@ SILC_SERVER_CMD_FUNC(detach)
 
   q = silc_calloc(1, sizeof(*q));
   q->server = server;
-  q->sock = cmd->sock;
+  q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
   silc_schedule_task_add(server->schedule, 0, silc_server_command_detach_cb,
                         q, 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
@@ -5079,7 +5123,7 @@ SILC_SERVER_CMD_FUNC(watch)
       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
-      silc_server_packet_send(server, server->router->connection,
+      silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
                              tmpbuf->data, tmpbuf->len, TRUE);
 
@@ -5245,11 +5289,11 @@ SILC_SERVER_CMD_FUNC(silcoper)
   bool result = FALSE;
   SilcPublicKey cached_key;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
-
-  if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
 
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
+
   if (server->server_type != SILC_ROUTER) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
                                          SILC_STATUS_ERR_AUTH_FAILED, 0);
@@ -5312,15 +5356,15 @@ SILC_SERVER_CMD_FUNC(silcoper)
   client->mode |= SILC_UMODE_ROUTER_OPERATOR;
 
   /* Update statistics */
-  if (client->connection)
+  if (SILC_IS_LOCAL(client))
     server->stat.my_router_ops++;
   if (server->server_type == SILC_ROUTER)
     server->stat.router_ops++;
 
   /* Send UMODE change to primary router */
-  if (!server->standalone)
-    silc_server_send_notify_umode(server, server->router->connection, TRUE,
-                                 client->id, client->mode);
+  silc_server_send_notify_umode(server, SILC_PRIMARY_ROUTE(server),
+                               SILC_BROADCAST(server), client->id,
+                               client->mode);
 
   /* Check if anyone is watching this nickname */
   if (server->server_type == SILC_ROUTER)
@@ -5351,7 +5395,7 @@ SILC_SERVER_CMD_FUNC(ban)
   SilcUInt32 id_len, tmp_len;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
 
-  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_BAN, cmd, 0, 3);
@@ -5436,10 +5480,9 @@ SILC_SERVER_CMD_FUNC(ban)
   }
 
   /* 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);
+  if (add || del)
+    silc_server_send_notify_ban(server, SILC_PRIMARY_ROUTE(server),
+                               SILC_BROADCAST(server), channel, add, del);
 
   /* Send the reply back to the client */
   packet = 
@@ -5472,6 +5515,9 @@ SILC_SERVER_CMD_FUNC(leave)
   SilcUInt32 len;
   unsigned char *tmp;
 
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !id_entry)
+    goto out;
+
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 2);
 
   /* Get Channel ID */
@@ -5509,10 +5555,8 @@ SILC_SERVER_CMD_FUNC(leave)
 
   /* Notify routers that they should remove this client from their list
      of clients on the channel. Send LEAVE notify type. */
-  if (!server->standalone)
-    silc_server_send_notify_leave(server, server->router->connection,
-                                 server->server_type == SILC_ROUTER ?
-                                 TRUE : FALSE, channel, id_entry->id);
+  silc_server_send_notify_leave(server, SILC_PRIMARY_ROUTE(server),
+                               SILC_BROADCAST(server), channel, id_entry->id);
 
   silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
                                       SILC_STATUS_OK, 0, 2, tmp, len);
@@ -5601,7 +5645,7 @@ SILC_SERVER_CMD_FUNC(users)
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
       
       /* Send USERS command */
-      silc_server_packet_send(server, server->router->connection,
+      silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
                              tmpbuf->data, tmpbuf->len, TRUE);
       
@@ -5639,7 +5683,8 @@ SILC_SERVER_CMD_FUNC(users)
        && !silc_server_client_on_channel(cmd->sock->user_data, channel, 
                                          NULL)) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
-                                           SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
+                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL,
+                                           0);
       goto out;
     }
   }
@@ -5814,7 +5859,7 @@ SILC_SERVER_CMD_FUNC(getkey)
       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
       
-      silc_server_packet_send(server, server->router->connection,
+      silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
                              tmpbuf->data, tmpbuf->len, TRUE);
       
@@ -5896,11 +5941,11 @@ SILC_SERVER_CMD_FUNC(connect)
   SilcUInt32 tmp_len;
   SilcUInt32 port = SILC_PORT;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CONNECT, cmd, 1, 2);
-
-  if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
 
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CONNECT, cmd, 1, 2);
+
   /* Check whether client has the permissions. */
   if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
       !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
@@ -5955,11 +6000,11 @@ SILC_SERVER_CMD_FUNC(close)
   unsigned char *name;
   SilcUInt32 port = SILC_PORT;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CLOSE, cmd, 1, 2);
-
-  if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
 
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CLOSE, cmd, 1, 2);
+
   /* Check whether client has the permissions. */
   if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
       !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
@@ -5994,6 +6039,12 @@ SILC_SERVER_CMD_FUNC(close)
     goto out;
   }
 
+  if (server_entry == server->id_entry) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
+                                         SILC_STATUS_ERR_NO_SERVER_ID, 0);
+    goto out;
+  }
+
   /* Send reply to the sender */
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
                                        SILC_STATUS_OK, 0);
@@ -6025,11 +6076,11 @@ SILC_SERVER_CMD_FUNC(shutdown)
   SilcServer server = cmd->server;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_SHUTDOWN, cmd, 0, 0);
-
-  if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+  if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
 
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_SHUTDOWN, cmd, 0, 0);
+
   /* Check whether client has the permission. */
   if (!(client->mode & SILC_UMODE_SERVER_OPERATOR) &&
       !(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {