Static analyzer bug fixes
[silc.git] / apps / silcd / command.c
index 2bd8198ebcfd0e2583b84098c1063bfe777c8cdd..213e8feed13edebec257fff173b57c81b6caf38a 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2008 Pekka Riikonen
+  Copyright (C) 1997 - 2014 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
@@ -16,7 +16,6 @@
   GNU General Public License for more details.
 
 */
-/* $Id$ */
 
 #include "serverincludes.h"
 #include "server_internal.h"
@@ -86,6 +85,27 @@ SilcServerCommand silc_command_list[] =
   { NULL, 0 },
 };
 
+/* Returns TRUE if the connection is registered. Unregistered connections
+   usually cannot send commands hence the check. */
+
+static int silc_server_is_registered(SilcServer server,
+                                    SilcPacketStream sock,
+                                    SilcServerCommandContext cmd,
+                                    SilcCommand command)
+{
+  SilcIDListData idata = silc_packet_get_context(sock);
+
+  if (!idata)
+    return FALSE;
+
+  if (idata->status & SILC_IDLIST_STATUS_REGISTERED)
+    return TRUE;
+
+  silc_server_command_send_status_reply(cmd, command,
+                                       SILC_STATUS_ERR_NOT_REGISTERED, 0);
+  return FALSE;
+}
+
 /* Performs several checks to the command. It first checks whether this
    command was called as pending command callback. If it was then it checks
    whether error occurred in the command reply where the pending command
@@ -103,6 +123,13 @@ do {                                                                            \
     return;                                                                 \
   }                                                                         \
                                                                             \
+  if (context2 &&                                                           \
+      !silc_server_is_registered(cmd->server, cmd->sock, cmd, command)) {    \
+    SILC_LOG_DEBUG(("Not registered, command not called"));                 \
+    silc_server_command_free(cmd);                                          \
+    return;                                                                 \
+  }                                                                         \
+                                                                            \
   _argc = silc_argument_get_arg_num(cmd->args);                                     \
   if (_argc < min) {                                                        \
     SILC_LOG_DEBUG(("Not enough parameters in command"));                   \
@@ -122,27 +149,6 @@ do {                                                                            \
   }                                                                         \
 } while(0)
 
-/* Returns TRUE if the connection is registered. Unregistered connections
-   usually cannot send commands hence the check. */
-
-static int silc_server_is_registered(SilcServer server,
-                                    SilcPacketStream sock,
-                                    SilcServerCommandContext cmd,
-                                    SilcCommand command)
-{
-  SilcIDListData idata = silc_packet_get_context(sock);
-
-  if (!idata)
-    return FALSE;
-
-  if (idata->status & SILC_IDLIST_STATUS_REGISTERED)
-    return TRUE;
-
-  silc_server_command_send_status_reply(cmd, command,
-                                       SILC_STATUS_ERR_NOT_REGISTERED, 0);
-  return FALSE;
-}
-
 /* Internal context to hold data when executed command with timeout. */
 typedef struct {
   SilcServerCommandContext ctx;
@@ -203,6 +209,8 @@ void silc_server_command_process(SilcServer server,
   /* Allocate command context. This must be free'd by the
      command routine receiving it. */
   ctx = silc_server_command_alloc();
+  if (!ctx)
+    return;
   ctx->server = server;
   ctx->sock = sock;
   ctx->packet = packet; /* Save original packet */
@@ -246,6 +254,15 @@ void silc_server_command_process(SilcServer server,
     int fast;
 
     timeout = silc_calloc(1, sizeof(*timeout));
+    if (!timeout) {
+      silc_server_command_send_status_reply(
+                                       ctx, command,
+                                       SILC_STATUS_ERR_OPERATION_ALLOWED, 0);
+      silc_packet_free(packet);
+      silc_packet_stream_unref(ctx->sock);
+      silc_free(ctx);
+      return;
+    }
     timeout->ctx = ctx;
     timeout->cmd = cmd;
 
@@ -294,7 +311,8 @@ void silc_server_command_process(SilcServer server,
 SilcServerCommandContext silc_server_command_alloc()
 {
   SilcServerCommandContext ctx = silc_calloc(1, sizeof(*ctx));
-  ctx->users++;
+  if (ctx)
+    ctx->users++;
   return ctx;
 }
 
@@ -339,10 +357,12 @@ SILC_TASK_CALLBACK(silc_server_command_pending_timeout)
   SilcBuffer tmpreply;
   int i;
 
-  SILC_LOG_DEBUG(("Timeout pending command"));
+  SILC_LOG_DEBUG(("Timeout pending command %p", reply));
 
   /* Allocate temporary and bogus command reply context */
   cmdr = silc_calloc(1, sizeof(*cmdr));
+  if (!cmdr)
+    return;
   cmdr->server = server;
   cmdr->ident = reply->ident;
 
@@ -350,6 +370,10 @@ SILC_TASK_CALLBACK(silc_server_command_pending_timeout)
   cmdr->callbacks =
     silc_server_command_pending_check(server, reply->reply_cmd,
                                      reply->ident, &cmdr->callbacks_count);
+  if (!cmdr->callbacks) {
+    silc_free(cmdr);
+    return;
+  }
 
   /* Create bogus command reply with an error inside */
   tmpreply =
@@ -393,11 +417,11 @@ SilcBool silc_server_command_pending(SilcServer server,
    commands.  If the `timeout' is zero default timeout is used. */
 
 SilcBool silc_server_command_pending_timed(SilcServer server,
-                                      SilcCommand reply_cmd,
-                                      SilcUInt16 ident,
-                                      SilcCommandCb callback,
-                                      void *context,
-                                      SilcUInt16 timeout)
+                                          SilcCommand reply_cmd,
+                                          SilcUInt16 ident,
+                                          SilcCommandCb callback,
+                                          void *context,
+                                          SilcUInt16 timeout)
 {
   SilcServerCommandPending *reply;
 
@@ -412,6 +436,8 @@ SilcBool silc_server_command_pending_timed(SilcServer server,
   }
 
   reply = silc_calloc(1, sizeof(*reply));
+  if (!reply)
+    return FALSE;
   reply->reply_cmd = reply_cmd;
   reply->ident = ident;
   reply->context = context;
@@ -447,7 +473,8 @@ void silc_server_command_pending_del(SilcServer server,
 }
 
 /* Checks for pending commands and marks callbacks to be called from
-   the command reply function. Returns TRUE if there were pending command. */
+   the command reply function. Returns the pending callbacks if there were
+   any or NULL if there weren't. */
 
 SilcServerCommandPendingCallbacks
 silc_server_command_pending_check(SilcServer server,
@@ -464,6 +491,8 @@ silc_server_command_pending_check(SilcServer server,
     if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
        && r->ident == ident) {
       callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
+      if (!callbacks)
+       return NULL;
       callbacks[i].context = r->context;
       callbacks[i].callback = r->callback;
       r->reply_check = TRUE;
@@ -1359,6 +1388,8 @@ SILC_SERVER_CMD_FUNC(quit)
     tmp = NULL;
 
   q = silc_calloc(1, sizeof(*q));
+  if (!q)
+    goto out;
   q->sock = sock;
   q->signoff = tmp ? strdup(tmp) : NULL;
   silc_packet_stream_ref(q->sock);
@@ -2106,6 +2137,8 @@ static void silc_server_command_join_channel(SilcServer server,
      Add also the channel to client entry's channels list for fast cross-
      referencing. */
   chl = silc_calloc(1, sizeof(*chl));
+  if (!chl)
+    goto out;
   chl->mode = umode;
   chl->client = client;
   chl->channel = channel;
@@ -2379,7 +2412,7 @@ SILC_SERVER_CMD_FUNC(join)
        channel will be global, based on our router name. */
     if (!serv[0] && !server->config->local_channels) {
       if (!server->standalone) {
-       silc_snprintf(serv, sizeof(serv), server->router->server_name);
+       silc_snprintf(serv, sizeof(serv), "%s", server->router->server_name);
       } else {
        SilcServerConfigRouter *router;
        router = silc_server_config_get_primary_router(server);
@@ -2433,7 +2466,6 @@ SILC_SERVER_CMD_FUNC(join)
                                          0);
     goto out;
   }
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
 
   /* Get cipher, hmac name and auth payload */
   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
@@ -3233,7 +3265,8 @@ SILC_SERVER_CMD_FUNC(cmode)
        silc_server_command_send_status_data(
                                        cmd, SILC_COMMAND_CMODE,
                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
-                                       2, hmac, strlen(hmac));
+                                       2, hmac ? hmac : SILC_DEFAULT_HMAC,
+                                       strlen(hmac ? hmac : SILC_DEFAULT_HMAC));
        goto out;
       }
 
@@ -4065,22 +4098,47 @@ SILC_TASK_CALLBACK(silc_server_command_detach_cb)
 {
   SilcServer server = app_context;
   QuitInternal q = (QuitInternal)context;
-  SilcClientID *client_id = (SilcClientID *)q->sock;
-  SilcClientEntry client;
-  SilcPacketStream sock;
+  SilcPacketStream sock = q->sock;
+  SilcClientEntry client = silc_packet_get_context(sock);
+  SilcIDListData idata;
 
-  client = silc_idlist_find_client_by_id(server->local_list, client_id,
-                                        TRUE, NULL);
-  if (client && client->connection) {
-    sock = client->connection;
+  if (!client) {
+    silc_packet_stream_unref(sock);
+    silc_free(q);
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Detaching client %s",
+                 silc_id_render(client->id, SILC_ID_CLIENT)));
 
-    /* Close the connection on our side */
-    client->router = NULL;
-    client->connection = NULL;
-    silc_server_close_connection(server, sock);
+  /* Stop rekey for the client. */
+  silc_server_stop_rekey(server, client);
+
+  /* Abort any active protocol */
+  idata = silc_packet_get_context(sock);
+  if (idata && idata->sconn && idata->sconn->op) {
+    SILC_LOG_DEBUG(("Abort active protocol"));
+    silc_async_abort(idata->sconn->op, NULL, NULL);
+    idata->sconn->op = NULL;
   }
 
-  silc_free(client_id);
+  silc_schedule_task_del_by_all(server->schedule, 0, silc_server_do_heartbeat,
+                               sock);
+
+  /* Close the connection on our side */
+  client->router = NULL;
+  client->connection = NULL;
+  silc_server_close_connection(server, sock);
+
+  /* Mark the client as locally detached. */
+  client->local_detached = TRUE;
+
+  /* Decrement the user count; we'll increment it if the user resumes on our
+     server. */
+  SILC_VERIFY(&server->stat.my_clients > 0);
+  server->stat.my_clients--;
+
+  silc_packet_stream_unref(sock);
   silc_free(q);
 }
 
@@ -4147,14 +4205,19 @@ SILC_SERVER_CMD_FUNC(detach)
                                   SILC_NOTIFY_TYPE_UMODE_CHANGE);
 
   q = silc_calloc(1, sizeof(*q));
-  q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
+  if (!q)
+    goto out;
+  q->sock = cmd->sock;
+  silc_packet_stream_ref(q->sock);
   silc_schedule_task_add_timeout(server->schedule,
                                 silc_server_command_detach_cb,
                                 q, 0, 200000);
 
   if (server->config->detach_timeout) {
     q = silc_calloc(1, sizeof(*q));
-    q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
+    if (!q)
+      goto out;
+    q->sock = (void *)silc_id_dup(client->id, SILC_ID_CLIENT);
     silc_schedule_task_add_timeout(server->schedule,
                                   silc_server_command_detach_timeout,
                                   q, server->config->detach_timeout * 60, 0);
@@ -5182,7 +5245,6 @@ SILC_SERVER_CMD_FUNC(service)
   SilcServer server = cmd->server;
   SilcUInt32 tmp_len, auth_len;
   unsigned char *service_name, *auth;
-  SilcBool send_list = FALSE;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SERVICE, cmd, 0, 256);
@@ -5207,8 +5269,6 @@ SILC_SERVER_CMD_FUNC(service)
   }
 
 
-  send_list = TRUE;
-
   /* Send our service list back */
   silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_SERVICE,
                                 SILC_STATUS_OK, 0, ident, 0);