Merged from silc_1_0_branch (second merge).
[silc.git] / apps / silcd / command.c
index 10c546573d8cd19e03e08425f6b60d1f4416a498..f5fcb1b4846bf6d5dc3e1bcb6741268decb8ace7 100644 (file)
@@ -160,6 +160,7 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout)
     SILC_LOG_DEBUG(("Client entry is invalid"));
     silc_server_command_free(timeout->ctx);
     silc_free(timeout);
+    return;
   }
 
   /* Update access time */
@@ -239,6 +240,7 @@ void silc_server_command_process(SilcServer server,
     if (!client) {
       SILC_LOG_DEBUG(("Client entry is invalid"));
       silc_server_command_free(ctx);
+      return;
     }
 
     timeout = silc_calloc(1, sizeof(*timeout));
@@ -1106,8 +1108,6 @@ SILC_SERVER_CMD_FUNC(invite)
                                  silc_server_command_invite, 
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
-      silc_free(channel_id);
-      silc_free(dest_id);
       goto out;
     }
 
@@ -1133,9 +1133,10 @@ SILC_SERVER_CMD_FUNC(invite)
 
     /* Allocate hash table for invite list if it doesn't exist yet */
     if (!channel->invite_list)
-      channel->invite_list = silc_hash_table_alloc(0, silc_hash_ptr,
-                                                  NULL, NULL, NULL,
-                                                  NULL, NULL, TRUE);
+      channel->invite_list =
+       silc_hash_table_alloc(0, silc_hash_ptr,
+                             NULL, NULL, NULL,
+                             silc_server_inviteban_destruct, channel, TRUE);
 
     /* Check if the ID is in the list already */
     silc_hash_table_list(channel->invite_list, &htl);
@@ -1173,7 +1174,7 @@ SILC_SERVER_CMD_FUNC(invite)
 
   /* Get the invite information */
   tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
-  if (tmp) {
+  if (tmp && len > 2) {
     /* Parse the arguments to see they are constructed correctly */
     SILC_GET16_MSB(argc, tmp);
     args = silc_argument_payload_parse(tmp + 2, len - 2, argc);
@@ -1190,9 +1191,11 @@ SILC_SERVER_CMD_FUNC(invite)
       if (tmp[0] == 0x00) {
        /* Allocate hash table for invite list if it doesn't exist yet */
        if (!channel->invite_list)
-         channel->invite_list = silc_hash_table_alloc(0, silc_hash_ptr,
-                                                      NULL, NULL, NULL,
-                                                      NULL, NULL, TRUE);
+         channel->invite_list =
+           silc_hash_table_alloc(0, silc_hash_ptr,
+                                 NULL, NULL, NULL,
+                                 silc_server_inviteban_destruct, channel,
+                                 TRUE);
     
        /* Check for resource limit */
        if (silc_hash_table_count(channel->invite_list) > 64) {
@@ -1212,21 +1215,16 @@ SILC_SERVER_CMD_FUNC(invite)
 
   /* Encode invite list */
   list = NULL;
-  if (channel->invite_list) {
+  if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
     list = silc_buffer_alloc_size(2);
     silc_buffer_format(list,
                       SILC_STR_UI_SHORT(silc_hash_table_count(
                                          channel->invite_list)),
                       SILC_STR_END);
     silc_hash_table_list(channel->invite_list, &htl);
-    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) {
-      if (type == 1)
-       list = silc_argument_payload_encode_one(list, (char *)tmp2,
-                                               strlen((char *)tmp2), type);
-      else
-       list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
-                                               type);
-    }
+    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2))
+      list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
+                                             type);
     silc_hash_table_list_reset(&htl);
   }
 
@@ -1237,13 +1235,23 @@ SILC_SERVER_CMD_FUNC(invite)
                         silc_argument_get_arg_type(cmd->args, 3, NULL),
                         list);
 
+  /* Send invite list back only if the list was modified, or now arguments
+     was given. */
+  type = 0;
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc == 1)
+    type = 1;
+  if (silc_argument_get_arg_type(cmd->args, 3, &len))
+    type = 1;
+
   /* Send command reply */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
                                                SILC_STATUS_OK, 0, ident, 2,
                                                2, tmp, len,
-                                               3, list ? list->data : NULL,
-                                               list ? list->len : 0);
+                                               3, type && list ? 
+                                               list->data : NULL,
+                                               type && list ? list->len : 0);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
@@ -1421,6 +1429,8 @@ SILC_SERVER_CMD_FUNC(kill)
 
     /* Do normal signoff for the destination client */
     sock = remote_client->connection;
+    silc_server_remove_from_channels(server, NULL, remote_client,
+                                    TRUE, (char *)"Killed", TRUE, TRUE);
     silc_server_free_client_data(server, NULL, remote_client, TRUE,
                                 comment ? comment :
                                 (unsigned char *)"Killed");
@@ -1899,6 +1909,7 @@ static void silc_server_command_join_channel(SilcServer server,
     /* Check invite list if channel is invite-only channel */
     if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
       if (!channel->invite_list ||
+         !silc_hash_table_count(channel->invite_list) ||
          (!silc_server_inviteban_match(server, channel->invite_list,
                                        3, client->id) &&
           !silc_server_inviteban_match(server, channel->invite_list,
@@ -1916,15 +1927,15 @@ static void silc_server_command_join_channel(SilcServer server,
     /* Check ban list if it exists. If the client's nickname, server,
        username and/or hostname is in the ban list the access to the
        channel is denied. */
-    if (channel->ban_list) {
-      if (silc_server_inviteban_match(server, channel->invite_list,
+    if (channel->ban_list && silc_hash_table_count(channel->ban_list)) {
+      if (silc_server_inviteban_match(server, channel->ban_list,
                                      3, client->id) ||
-         silc_server_inviteban_match(server, channel->invite_list,
+         silc_server_inviteban_match(server, channel->ban_list,
                                      2, client->data.public_key) ||
-         !silc_server_inviteban_match(server, channel->invite_list,
-                                      1, check) ||
-         !silc_server_inviteban_match(server, channel->invite_list,
-                                      1, check2)) {
+         silc_server_inviteban_match(server, channel->ban_list,
+                                     1, check) ||
+         silc_server_inviteban_match(server, channel->ban_list,
+                                     1, check2)) {
        silc_server_command_send_status_reply(
                                      cmd, SILC_COMMAND_JOIN,
                                      SILC_STATUS_ERR_BANNED_FROM_CHANNEL, 0);
@@ -2024,7 +2035,7 @@ static void silc_server_command_join_channel(SilcServer server,
 
   /* Encode invite list */
   invite_list = NULL;
-  if (channel->invite_list) {
+  if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
     SilcHashTableList htl;
 
     invite_list = silc_buffer_alloc_size(2);
@@ -2034,23 +2045,16 @@ static void silc_server_command_join_channel(SilcServer server,
                       SILC_STR_END);
 
     silc_hash_table_list(channel->invite_list, &htl);
-    while (silc_hash_table_get(&htl, (void **)&tmp_len, (void **)&reply)) {
-      if (tmp_len == 1)
-       invite_list = silc_argument_payload_encode_one(invite_list,
-                                                      (char *)reply,
-                                                      strlen((char *)reply),
-                                                      tmp_len);
-      else
-       invite_list = silc_argument_payload_encode_one(invite_list,
-                                                      reply->data,
-                                                      reply->len, tmp_len);
-    }
+    while (silc_hash_table_get(&htl, (void **)&tmp_len, (void **)&reply))
+      invite_list = silc_argument_payload_encode_one(invite_list,
+                                                    reply->data,
+                                                    reply->len, tmp_len);
     silc_hash_table_list_reset(&htl);
   }
 
   /* Encode ban list */
   ban_list = NULL;
-  if (channel->ban_list) {
+  if (channel->ban_list && silc_hash_table_count(channel->ban_list)) {
     SilcHashTableList htl;
 
     ban_list = silc_buffer_alloc_size(2);
@@ -2060,17 +2064,10 @@ static void silc_server_command_join_channel(SilcServer server,
                       SILC_STR_END);
 
     silc_hash_table_list(channel->ban_list, &htl);
-    while (silc_hash_table_get(&htl, (void **)&tmp_len, (void **)&reply)) {
-      if (tmp_len == 1)
-       ban_list = silc_argument_payload_encode_one(ban_list,
-                                                   (char *)reply,
-                                                   strlen((char *)reply),
-                                                   tmp_len);
-      else
-       ban_list = silc_argument_payload_encode_one(ban_list,
-                                                   reply->data,
-                                                   reply->len, tmp_len);
-    }
+    while (silc_hash_table_get(&htl, (void **)&tmp_len, (void **)&reply))
+      ban_list = silc_argument_payload_encode_one(ban_list,
+                                                 reply->data,
+                                                 reply->len, tmp_len);
     silc_hash_table_list_reset(&htl);
   }
 
@@ -2168,6 +2165,8 @@ static void silc_server_command_join_channel(SilcServer server,
   silc_buffer_free(ban_list);
 
  out:
+  if (passphrase)
+    memset(passphrase, 0, strlen(passphrase));
   silc_free(passphrase);
 }
 
@@ -2923,7 +2922,6 @@ SILC_SERVER_CMD_FUNC(cmode)
       hmac = channel->hmac_name;
 
       /* Delete old hmac and allocate default one */
-      silc_hmac_free(channel->hmac);
       if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL, &newhmac)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
@@ -2956,6 +2954,11 @@ SILC_SERVER_CMD_FUNC(cmode)
                                                0);
          goto out;
        }
+      } else {
+       /* If key was not sent and the channel mode has already founder
+          then the key was not to be changed. */
+       if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
+         goto has_founder;
       }
 
       /* Set the founder authentication */
@@ -3000,6 +3003,7 @@ SILC_SERVER_CMD_FUNC(cmode)
        channel->founder_key = NULL;
        goto out;
       }
+    has_founder:
     }
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
@@ -3060,7 +3064,6 @@ 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 = NULL;
   SilcClientID *client_id = NULL;
   SilcChannelEntry channel;
@@ -3192,9 +3195,7 @@ SILC_SERVER_CMD_FUNC(cumode)
       SilcHashTableList htl;
 
       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
-         !channel->founder_key || !idata->public_key ||
-         !silc_pkcs_public_key_compare(channel->founder_key, 
-                                       idata->public_key)) {
+         !channel->founder_key) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                              SILC_STATUS_ERR_AUTH_FAILED, 0);
        goto out;
@@ -3543,6 +3544,17 @@ SILC_SERVER_CMD_FUNC(kick)
                                 SILC_BROADCAST(server), channel,
                                 target_client->id, client->id, comment);
 
+  /* Remove the client from channel's invite list */
+  if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
+    SilcBuffer ab =
+      silc_argument_payload_encode_one(NULL, target_idp, target_idp_len, 3);
+    SilcArgumentPayload args =
+      silc_argument_payload_parse(ab->data, ab->len, 1);
+    silc_server_inviteban_process(server, channel->invite_list, 1, args);
+    silc_buffer_free(ab);
+    silc_argument_payload_free(args);
+  }
+
   /* 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. */
@@ -4136,7 +4148,7 @@ SILC_SERVER_CMD_FUNC(ban)
 
   /* Get the ban information */
   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
-  if (tmp) {
+  if (tmp && len > 2) {
     /* Parse the arguments to see they are constructed correctly */
     SILC_GET16_MSB(argc, tmp);
     args = silc_argument_payload_parse(tmp + 2, len - 2, argc);
@@ -4148,14 +4160,16 @@ SILC_SERVER_CMD_FUNC(ban)
     }
 
     /* Get the type of action */
-    tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+    tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
     if (tmp && len == 1) {
       if (tmp[0] == 0x00) {
        /* Allocate hash table for ban list if it doesn't exist yet */
        if (!channel->ban_list)
-         channel->ban_list = silc_hash_table_alloc(0, silc_hash_ptr,
-                                                   NULL, NULL, NULL,
-                                                   NULL, NULL, TRUE);
+         channel->ban_list =
+           silc_hash_table_alloc(0, silc_hash_ptr,
+                                 NULL, NULL, NULL,
+                                 silc_server_inviteban_destruct, channel,
+                                 TRUE);
     
        /* Check for resource limit */
        if (silc_hash_table_count(channel->ban_list) > 64) {
@@ -4175,21 +4189,16 @@ SILC_SERVER_CMD_FUNC(ban)
 
   /* Encode ban list */
   list = NULL;
-  if (channel->ban_list) {
+  if (channel->ban_list && silc_hash_table_count(channel->ban_list)) {
     list = silc_buffer_alloc_size(2);
     silc_buffer_format(list,
                       SILC_STR_UI_SHORT(silc_hash_table_count(
                                          channel->ban_list)),
                       SILC_STR_END);
     silc_hash_table_list(channel->ban_list, &htl);
-    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) {
-      if (type == 1)
-       list = silc_argument_payload_encode_one(list, (char *)tmp2,
-                                               strlen((char *)tmp2), type);
-      else
-       list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
-                                               type);
-    }
+    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2))
+      list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
+                                             type);
     silc_hash_table_list_reset(&htl);
   }
 
@@ -4738,17 +4747,19 @@ SILC_SERVER_CMD_FUNC(close)
   /* Close the connection to the server */
   sock = (SilcSocketConnection)server_entry->connection;
 
-  /* If we shutdown primary router connection manually then don't trigger
-     any reconnect or backup router connections, by setting the router
-     to NULL here. */
+  server->backup_noswitch = TRUE;
   if (server->router == server_entry) {
     server->id_entry->router = NULL;
     server->router = NULL;
     server->standalone = TRUE;
   }
-  silc_server_free_sock_user_data(server, sock, NULL);
-  silc_server_close_connection(server, sock);
-  
+  silc_server_disconnect_remote(server, sock,
+                               SILC_STATUS_ERR_BANNED_FROM_SERVER,
+                               "Closed by administrator");
+  if (sock->user_data)
+    silc_server_free_sock_user_data(server, sock, NULL);
+  server->backup_noswitch = FALSE;
+
  out:
   silc_server_command_free(cmd);
 }