Code auditing weekend results and fixes committing.
[silc.git] / apps / silcd / command.c
index b7f9f680b60ad734945b42ed05a6d2c460e35744..3241d595406245020f09e3cc794c5c79f1812161 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 1997 - 2000 Pekka Riikonen
+  Copyright (C) 1997 - 2001 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -40,7 +40,8 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
 static void silc_server_command_free(SilcServerCommandContext cmd);
 void silc_server_command_send_users(SilcServer server,
                                    SilcSocketConnection sock,
-                                   SilcChannelEntry channel);
+                                   SilcChannelEntry channel,
+                                   int pending);
 
 /* Server command list. */
 SilcServerCommand silc_command_list[] =
@@ -325,7 +326,7 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
   int i, k;
 
   /* If client ID is in the command it must be used instead of nickname */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
   if (!tmp) {
     /* No ID, get the nickname@server string and parse it. */
     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
@@ -350,6 +351,10 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
 
     *client_id = silc_calloc(1, sizeof(**client_id));
     (*client_id)[0] = silc_id_payload_parse_id(tmp, len);
+    if ((*client_id)[0] == NULL) {
+      silc_free(*client_id);
+      return FALSE;
+    }
     *client_id_count = 1;
 
     /* Take all ID's from the command packet */
@@ -359,8 +364,15 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
        if (tmp) {
          *client_id = silc_realloc(*client_id, sizeof(**client_id) *
                                    (*client_id_count + 1));
-         (*client_id)[k++] = silc_id_payload_parse_id(tmp, len);
+         (*client_id)[k] = silc_id_payload_parse_id(tmp, len);
+         if ((*client_id)[k] == NULL) {
+           for (i = 0; i < k; i++)
+             silc_free((*client_id)[i]);
+           silc_free(*client_id);
+           return FALSE;
+         }
          (*client_id_count)++;
+         k++;
        }
       }
     }
@@ -393,6 +405,9 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
     if (!entry->nickname || !entry->username || !entry->userinfo) {
       SilcBuffer tmpbuf;
       unsigned short old_ident;
+
+      if (!entry->router)
+       continue;
       
       old_ident = silc_command_get_ident(cmd->payload);
       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
@@ -764,7 +779,7 @@ SILC_SERVER_CMD_FUNC(whois)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   int ret;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3);
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3328);
 
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
     ret = silc_server_command_whois_from_client(cmd);
@@ -805,6 +820,9 @@ silc_server_command_identify_check(SilcServerCommandContext cmd,
       SilcBuffer tmpbuf;
       unsigned short old_ident;
       
+      if (!entry->router)
+       continue;
+      
       old_ident = silc_command_get_ident(cmd->payload);
       silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
       silc_command_set_command(cmd->payload, SILC_COMMAND_WHOIS);
@@ -919,7 +937,7 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd)
 {
   SilcServer server = cmd->server;
   char *nick = NULL, *server_name = NULL;
-  int count = 0, clients_count; 
+  int count = 0, clients_count = 0
   SilcClientEntry *clients = NULL, entry;
   SilcClientID **client_id = NULL;
   unsigned int client_id_count = 0;
@@ -1052,7 +1070,7 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd)
 {
   SilcServer server = cmd->server;
   char *nick = NULL, *server_name = NULL;
-  int count = 0, clients_count;
+  int count = 0, clients_count = 0;
   SilcClientEntry *clients = NULL, entry;
   SilcClientID **client_id = NULL;
   unsigned int client_id_count = 0;
@@ -1114,9 +1132,17 @@ silc_server_command_identify_from_server(SilcServerCommandContext cmd)
 
   if (!clients) {
     /* Such a client really does not exist in the SILC network. */
-    silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                        SILC_STATUS_ERR_NO_SUCH_NICK,
-                                        3, nick, strlen(nick));
+    if (!client_id_count) {
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+                                          SILC_STATUS_ERR_NO_SUCH_NICK,
+                                          3, nick, strlen(nick));
+    } else {
+      SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+                                          SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+                                          2, idp->data, idp->len);
+      silc_buffer_free(idp);
+    }
     goto out;
   }
 
@@ -1152,7 +1178,7 @@ SILC_SERVER_CMD_FUNC(identify)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   int ret;
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3);
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
 
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
     ret = silc_server_command_identify_from_client(cmd);
@@ -1210,7 +1236,7 @@ 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. */
-  if (!cmd->server->standalone)
+  if (!server->standalone)
     silc_server_send_replace_id(server, server->router->connection, 
                                server->server_type == SILC_SERVER ? 
                                FALSE : TRUE, client->id,
@@ -1294,6 +1320,11 @@ SILC_SERVER_CMD_FUNC(topic)
     goto out;
   }
   channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+  if (!channel_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
 
   /* Check whether the channel exists */
   channel = silc_idlist_find_channel_by_id(server->local_list, 
@@ -1341,7 +1372,7 @@ SILC_SERVER_CMD_FUNC(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, channel, TRUE,
+    silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
                                       SILC_NOTIFY_TYPE_TOPIC_SET, 2,
                                       idp->data, idp->len,
                                       channel->topic, strlen(channel->topic));
@@ -1396,6 +1427,11 @@ SILC_SERVER_CMD_FUNC(invite)
     goto out;
   }
   dest_id = silc_id_payload_parse_id(tmp, len);
+  if (!dest_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                         SILC_STATUS_ERR_NO_CLIENT_ID);
+    goto out;
+  }
 
   /* Get Channel ID */
   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
@@ -1405,6 +1441,11 @@ SILC_SERVER_CMD_FUNC(invite)
     goto out;
   }
   channel_id = silc_id_payload_parse_id(tmp, len);
+  if (!channel_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
 
   /* Check whether the channel exists */
   channel = silc_idlist_find_channel_by_id(server->local_list, 
@@ -1595,7 +1636,7 @@ SILC_SERVER_CMD_FUNC(ping)
                                          SILC_STATUS_ERR_NO_SERVER_ID);
     goto out;
   }
-  id = silc_id_str2id(tmp, SILC_ID_SERVER);
+  id = silc_id_str2id(tmp, len, SILC_ID_SERVER);
   if (!id)
     goto out;
 
@@ -1619,63 +1660,22 @@ SILC_SERVER_CMD_FUNC(oper)
 {
 }
 
-typedef struct {
-  char *channel_name;
-  char *nickname;
-  char *username;
-  char *hostname;
-  SilcChannelEntry channel;
-  SilcServer server;
-  SilcClientEntry client;
-} JoinInternalContext;
-
-SILC_TASK_CALLBACK(silc_server_command_join_notify)
-{
-  JoinInternalContext *ctx = (JoinInternalContext *)context;
-
-  if (ctx->channel->key && ctx->channel->key_len) {
-    SilcBuffer clidp;
-
-    clidp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT);
-
-    silc_server_send_notify_to_channel(ctx->server, ctx->channel, FALSE,
-                                      SILC_NOTIFY_TYPE_JOIN, 1,
-                                      clidp->data, clidp->len);
-#if 0
-    /* Send NEW_CHANNEL_USER packet to primary route */
-    silc_server_send_new_channel_user(server, server->router->connection,
-                                     server->server_type == SILC_SERVER ?
-                                     FALSE : TRUE,
-                                     channel->id, SILC_ID_CHANNEL_LEN,
-                                     client->id, SILC_ID_CLIENT_LEN);
-#endif
-
-    /* Send USERS command reply to the joined channel so the user sees who
-       is currently on the channel. */
-    silc_server_command_send_users(ctx->server, ctx->client->connection, 
-                                  ctx->channel);
-
-    silc_buffer_free(clidp);
-    silc_free(ctx);
-  } else {
-    silc_task_register(ctx->server->timeout_queue, fd,
-                      silc_server_command_join_notify, context,
-                      0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
-  }
-}
-
 /* Assembles USERS command and executes it. This is called when client
    joins to a channel and we wan't to send USERS command reply to the 
    client. */
 
 void silc_server_command_send_users(SilcServer server,
                                    SilcSocketConnection sock,
-                                   SilcChannelEntry channel)
+                                   SilcChannelEntry channel,
+                                   int pending)
 {
   SilcServerCommandContext cmd;
   SilcBuffer buffer, idp;
   SilcPacketContext *packet = silc_packet_context_alloc();
 
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Create USERS command packet and process it. */
   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
   buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 0, 1,
                                          1, idp->data, idp->len);
@@ -1686,55 +1686,38 @@ void silc_server_command_send_users(SilcServer server,
 
   cmd = silc_calloc(1, sizeof(*cmd));
   cmd->payload = silc_command_payload_parse(buffer);
+  if (!cmd->payload) {
+    silc_free(cmd);
+    silc_buffer_free(buffer);
+    silc_buffer_free(idp);
+    silc_packet_context_free(packet);
+    return;
+  }
   cmd->args = silc_command_get_args(cmd->payload);
   cmd->server = server;
   cmd->sock = sock;
   cmd->packet = silc_packet_context_dup(packet);
   cmd->pending = FALSE;
 
-  silc_server_command_users((void *)cmd);
-
-  silc_free(buffer);
-  silc_free(idp);
-  silc_packet_context_free(packet);
-}
-
-/* Internal routine that is called after router has replied to server's
-   JOIN command it forwarded to the router. The route has joined and possibly
-   creaetd the channel. This function adds the client to the channel's user
-   list. */
-
-SILC_SERVER_CMD_FUNC(add_to_channel)
-{
-  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  SilcServer server = cmd->server;
-  SilcClientEntry client;
-  SilcChannelEntry channel;
-  SilcChannelClientEntry chl;
-  char *channel_name;
-
-  /* Get channel name */
-  channel_name = silc_argument_get_arg_type(cmd->args, 1, NULL);
-
-  /* Get client entry */
-  client = (SilcClientEntry)cmd->sock->user_data;
-
-  /* Get channel entry */
-  channel = silc_idlist_find_channel_by_name(server->local_list, 
-                                            channel_name, NULL);
-  if (channel) {
-    /* Join the client to the channel by adding it to channel's user list.
-       Add also the channel to client entry's channels list for fast cross-
-       referencing. */
-    chl = silc_calloc(1, sizeof(*chl));
-    //chl->mode = SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO;
-    chl->client = client;
-    chl->channel = channel;
-    silc_list_add(channel->user_list, chl);
-    silc_list_add(client->channels, chl);
+  if (pending) {
+    /* If this function was called from pending command then instead of
+       processing the command now, register a pending command callback which
+       will process it after we've received the automatic USERS command 
+       reply. */
+    silc_server_command_pending(server, SILC_COMMAND_USERS, 0,
+                               silc_server_command_users, (void *)cmd);
+    cmd->pending = TRUE;
+    silc_buffer_free(buffer);
+    silc_buffer_free(idp);
+    return;
   }
 
-  silc_server_command_free(cmd);
+  /* Process USERS command. */
+  silc_server_command_users((void *)cmd);
+  silc_buffer_free(buffer);
+  silc_buffer_free(idp);
+  silc_packet_context_free(packet);
 }
 
 /* Internal routine to join channel. The channel sent to this function
@@ -1842,7 +1825,7 @@ static void silc_server_command_join_channel(SilcServer server,
 
   /* Send the channel key. This is broadcasted to the channel but is not
      sent to the client who is joining to the channel. */
-  silc_server_send_channel_key(server, channel, 
+  silc_server_send_channel_key(server, NULL, channel, 
                               server->server_type == SILC_ROUTER ? 
                               FALSE : server->standalone);
 
@@ -1897,34 +1880,24 @@ static void silc_server_command_join_channel(SilcServer server,
   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          reply->data, reply->len, FALSE);
 
-  if (!cmd->pending)
+  if (!cmd->pending) {
     /* Send JOIN notify to locally connected clients on the channel */
-    silc_server_send_notify_to_channel(server, channel, FALSE,
+    silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
                                       SILC_NOTIFY_TYPE_JOIN, 1,
                                       clidp->data, clidp->len);
 
-  /* Send NEW_CHANNEL_USER packet to our primary router */
-  if (!cmd->pending && !server->standalone)
-    silc_server_send_new_channel_user(server, server->router->connection,
-                                     server->server_type == SILC_SERVER ?
-                                     FALSE : TRUE,
-                                     channel->id, SILC_ID_CHANNEL_LEN,
-                                     client->id, SILC_ID_CLIENT_LEN);
+    /* Send NEW_CHANNEL_USER packet to our primary router */
+    if (!server->standalone)
+      silc_server_send_new_channel_user(server, server->router->connection,
+                                       server->server_type == SILC_SERVER ?
+                                       FALSE : TRUE,
+                                       channel->id, SILC_ID_CHANNEL_LEN,
+                                       client->id, SILC_ID_CLIENT_LEN);
+  }
 
   /* Send USERS command reply to the joined channel so the user sees who
      is currently on the channel. */
-  silc_server_command_send_users(server, sock, channel);
-
-  /*
-
-    FAQ:
-
-   * Kuinka USERS komento händlätään serverissä kun router lähettää sen
-   serverille joka on lähettäny sille clientin puolesta JOIN komennon?
-   
-   R: Serverin pitää ymmärtää USERS comman replyjä.
-
-  */
+  silc_server_command_send_users(server, sock, channel, cmd->pending);
 
   silc_buffer_free(reply);
   silc_buffer_free(clidp);
@@ -1976,6 +1949,11 @@ SILC_SERVER_CMD_FUNC(join)
     goto out;
   }
   client_id = silc_id_payload_parse_id(tmp, tmp_len);
+  if (!client_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
 
   /* Get cipher name */
   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
@@ -2223,6 +2201,11 @@ SILC_SERVER_CMD_FUNC(cmode)
     goto out;
   }
   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
+  if (!channel_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
 
   /* Get the channel mode mask */
   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
@@ -2530,7 +2513,7 @@ SILC_SERVER_CMD_FUNC(cmode)
 
   /* Send CMODE_CHANGE notify */
   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-  silc_server_send_notify_to_channel(server, channel, TRUE,
+  silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
                                     SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
                                     cidp->data, cidp->len, 
                                     tmp_mask, tmp_len);
@@ -2577,6 +2560,11 @@ SILC_SERVER_CMD_FUNC(cumode)
     goto out;
   }
   channel_id = silc_id_payload_parse_id(tmp_id, tmp_len);
+  if (!channel_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
 
   /* Get channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list, 
@@ -2627,6 +2615,11 @@ SILC_SERVER_CMD_FUNC(cumode)
     goto out;
   }
   client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
+  if (!client_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
 
   /* Get target client's entry */
   target_client = silc_idlist_find_client_by_id(server->local_list, 
@@ -2696,7 +2689,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   /* Send notify to channel, notify only if mode was actually changed. */
   if (notify) {
     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-    silc_server_send_notify_to_channel(server, channel, TRUE,
+    silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
                                       SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
                                       idp->data, idp->len,
                                       tmp_mask, 4, tmp_id, tmp_len);
@@ -2765,6 +2758,11 @@ SILC_SERVER_CMD_FUNC(leave)
     goto out;
   }
   id = silc_id_payload_parse_id(tmp, len);
+  if (!id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
 
   /* Get channel entry */
   channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
@@ -2846,23 +2844,30 @@ SILC_SERVER_CMD_FUNC(users)
   SilcChannelClientEntry chl;
   SilcChannelID *id;
   SilcBuffer packet;
-  unsigned char *tmp;
-  unsigned int tmp_len;
+  unsigned char *channel_id;
+  unsigned int channel_id_len;
   SilcBuffer client_id_list;
   SilcBuffer client_mode_list;
   SilcBuffer idp;
+  unsigned char lc[4];
+  unsigned int list_count = 0;
   unsigned short ident = silc_command_get_ident(cmd->payload);
 
-  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 2);
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 1);
 
   /* Get Channel ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
-  if (!tmp) {
+  channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
+  if (!channel_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  id = silc_id_payload_parse_id(channel_id, channel_id_len);
+  if (!id) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
                                          SILC_STATUS_ERR_NO_CHANNEL_ID);
     goto out;
   }
-  id = silc_id_payload_parse_id(tmp, tmp_len);
 
   /* If we are server and we don't know about this channel we will send
      the command to our router. If we know about the channel then we also
@@ -2923,19 +2928,25 @@ SILC_SERVER_CMD_FUNC(users)
     /* Client's mode on channel */
     SILC_PUT32_MSB(chl->mode, client_mode_list->data);
     silc_buffer_pull(client_mode_list, 4);
+
+    list_count++;
   }
   silc_buffer_push(client_id_list, 
                   client_id_list->data - client_id_list->head);
   silc_buffer_push(client_mode_list, 
                   client_mode_list->data - client_mode_list->head);
 
+  /* List count */
+  SILC_PUT32_MSB(list_count, lc);
+
   /* Send reply */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
                                                SILC_STATUS_OK, 0, 4,
-                                               2, tmp, tmp_len,
-                                               3, client_id_list->data,
+                                               2, channel_id, channel_id_len,
+                                               3, lc, 4,
+                                               4, client_id_list->data,
                                                client_id_list->len,
-                                               4, client_mode_list->data,
+                                               5, client_mode_list->data,
                                                client_mode_list->len);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);