Code auditing weekend results and fixes committing.
[silc.git] / lib / silcclient / client.c
index 4ba45528d9ecf1980317823d3c1fa7d3d794f3a6..1cd84f2f6b9d34cdce3173a63226e475a107a46f 100644 (file)
@@ -141,6 +141,7 @@ SilcClientConnection silc_client_add_connection(SilcClient client,
   conn->remote_host = strdup(hostname);
   conn->remote_port = port;
   conn->context = context;
+  conn->pending_commands = silc_dlist_init();
 
   /* Add the connection to connections table */
   for (i = 0; i < client->conns_count; i++)
@@ -165,6 +166,8 @@ void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
 
   for (i = 0; i < client->conns_count; i++)
     if (client->conns[i] == conn) {
+      if (conn->pending_commands)
+       silc_dlist_uninit(conn->pending_commands);
       silc_free(conn);
       client->conns[i] = NULL;
     }
@@ -376,7 +379,8 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+      protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
     SILC_LOG_DEBUG(("Error during KE protocol"));
     silc_protocol_free(protocol);
@@ -414,7 +418,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
   /* Free old protocol as it is finished now */
   silc_protocol_free(protocol);
   if (ctx->packet)
-    silc_buffer_free(ctx->packet);
+    silc_packet_context_free(ctx->packet);
   silc_free(ctx);
   /* silc_free(ctx->keymat....); */
   sock->protocol = NULL;
@@ -447,7 +451,8 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+      protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
     SILC_LOG_DEBUG(("Error during authentication protocol"));
     silc_protocol_free(protocol);
@@ -499,8 +504,6 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
     silc_free(ctx->auth_data);
   if (ctx->ske)
     silc_ske_free(ctx->ske);
-  if (ctx->dest_id)
-    silc_free(ctx->dest_id);
   silc_free(ctx);
   conn->sock->protocol = NULL;
 }
@@ -648,12 +651,8 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real)
   silc_client_packet_parse_type(client, sock, packet);
 
  out:
-  silc_buffer_clear(buffer);
-  if (packet->src_id)
-    silc_free(packet->src_id);
-  if (packet->dst_id)
-    silc_free(packet->dst_id);
-  silc_free(packet);
+  silc_buffer_clear(sock->inbuf);
+  silc_packet_context_free(packet);
   silc_free(parse_ctx);
 }
 
@@ -780,9 +779,12 @@ void silc_client_packet_parse_type(SilcClient client,
       SilcClientKEInternalContext *proto_ctx = 
        (SilcClientKEInternalContext *)sock->protocol->context;
 
-      proto_ctx->packet = buffer;
+      proto_ctx->packet = silc_packet_context_dup(packet);
       proto_ctx->dest_id_type = packet->src_id_type;
-      proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
+      proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+                                         packet->src_id_type);
+      if (!proto_ctx->dest_id)
+       break;
 
       /* Let the protocol handle the packet */
       sock->protocol->execute(client->timeout_queue, 0,
@@ -809,11 +811,14 @@ void silc_client_packet_parse_type(SilcClient client,
        (SilcClientKEInternalContext *)sock->protocol->context;
 
       if (proto_ctx->packet)
-       silc_buffer_free(proto_ctx->packet);
+       silc_packet_context_free(proto_ctx->packet);
 
-      proto_ctx->packet = buffer;
+      proto_ctx->packet = silc_packet_context_dup(packet);
       proto_ctx->dest_id_type = packet->src_id_type;
-      proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
+      proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+                                         packet->src_id_type);
+      if (!proto_ctx->dest_id)
+       break;
 
       /* Let the protocol handle the packet */
       sock->protocol->execute(client->timeout_queue, 0,
@@ -835,6 +840,8 @@ void silc_client_packet_parse_type(SilcClient client,
       SilcIDPayload idp;
 
       idp = silc_id_payload_parse(buffer);
+      if (!idp)
+       break;
       if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
        break;
 
@@ -968,8 +975,7 @@ void silc_client_packet_send_to_channel(SilcClient client,
 
   /* Generate IV */
   if (!channel->iv)
-    for (i = 0; i < 16; i++)
-      channel->iv[i] = silc_rng_get_byte(client->rng);
+    for (i = 0; i < 16; i++) channel->iv[i] = silc_rng_get_byte(client->rng);
   else
     silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
 
@@ -1200,6 +1206,8 @@ void silc_client_close_connection(SilcClient client,
       memset(conn->hmac_key, 0, conn->hmac_key_len);
       silc_free(conn->hmac_key);
     }
+    if (conn->pending_commands)
+      silc_dlist_uninit(conn->pending_commands);
 
     conn->sock = NULL;
     conn->remote_port = 0;
@@ -1213,6 +1221,7 @@ void silc_client_close_connection(SilcClient client,
     conn->local_id_data = NULL;
     conn->remote_host = NULL;
     conn->current_channel = NULL;
+    conn->pending_commands = NULL;
 
     silc_client_del_connection(client, conn);
   }
@@ -1268,12 +1277,7 @@ static void silc_client_notify_by_server_pending(void *context)
 {
   SilcPacketContext *p = (SilcPacketContext *)context;
   silc_client_notify_by_server(p->context, p->sock, p);
-  if (p->src_id)
-    silc_free(p->src_id);
-  if (p->dst_id)
-    silc_free(p->dst_id);
-  silc_buffer_free(p->buffer);
-  silc_free(p);
+  silc_packet_context_free(p);
 }
 
 /* Received notify message from server */
@@ -1287,7 +1291,6 @@ void silc_client_notify_by_server(SilcClient client,
   SilcNotifyPayload payload;
   SilcNotifyType type;
   SilcArgumentPayload args;
-  int i;
 
   SilcClientID *client_id = NULL;
   SilcChannelID *channel_id = NULL;
@@ -1300,6 +1303,9 @@ void silc_client_notify_by_server(SilcClient client,
   unsigned int tmp_len, mode;
 
   payload = silc_notify_payload_parse(buffer);
+  if (!payload)
+    goto out;
+
   type = silc_notify_get_type(payload);
   args = silc_notify_get_args(payload);
   if (!args)
@@ -1324,6 +1330,8 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
 
     /* Find Client entry and if not found query it */
     client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
@@ -1331,7 +1339,7 @@ void silc_client_notify_by_server(SilcClient client,
       SilcPacketContext *p = silc_packet_context_dup(packet);
       p->context = (void *)client;
       p->sock = sock;
-      silc_client_command_pending(SILC_COMMAND_WHOIS, 
+      silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
                                  silc_client_notify_by_server_pending, p);
       goto out;
     }
@@ -1342,6 +1350,8 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!channel_id)
+      goto out;
 
     /* XXX Will ALWAYS fail because currently we don't have way to resolve
        channel information for channel that we're not joined to. */
@@ -1370,6 +1380,8 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
 
     /* Find Client entry and if not found query it */
     client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
@@ -1377,13 +1389,16 @@ void silc_client_notify_by_server(SilcClient client,
       SilcPacketContext *p = silc_packet_context_dup(packet);
       p->context = (void *)client;
       p->sock = sock;
-      silc_client_command_pending(SILC_COMMAND_WHOIS
+      silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT
                                  silc_client_notify_by_server_pending, p);
       goto out;
     }
 
     /* Get channel entry */
-    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+    channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                               SILC_ID_CHANNEL);
+    if (!channel_id)
+      goto out;
     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
                                     SILC_ID_CHANNEL, &id_cache))
       break;
@@ -1416,6 +1431,8 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
 
     /* Find Client entry */
     client_entry = 
@@ -1424,7 +1441,10 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Get channel entry */
-    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+    channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                               SILC_ID_CHANNEL);
+    if (!channel_id)
+      goto out;
     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
                                     SILC_ID_CHANNEL, &id_cache))
       break;
@@ -1458,6 +1478,8 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
 
     /* Find Client entry */
     client_entry = 
@@ -1499,6 +1521,8 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
 
     /* Find Client entry */
     client_entry = 
@@ -1512,7 +1536,10 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Get channel entry */
-    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+    channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                               SILC_ID_CHANNEL);
+    if (!channel_id)
+      goto out;
     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
                                     SILC_ID_CHANNEL, &id_cache))
       break;
@@ -1539,6 +1566,8 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
 
     /* Ignore my ID */
     if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
@@ -1551,7 +1580,7 @@ void silc_client_notify_by_server(SilcClient client,
       SilcPacketContext *p = silc_packet_context_dup(packet);
       p->context = (void *)client;
       p->sock = sock;
-      silc_client_command_pending(SILC_COMMAND_WHOIS, 
+      silc_client_command_pending(conn, SILC_COMMAND_WHOIS, SILC_IDLIST_IDENT,
                                  silc_client_notify_by_server_pending, p);
       goto out;
     }
@@ -1562,6 +1591,8 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
 
     /* Find old Client entry */
     client_entry = 
@@ -1604,6 +1635,8 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
 
     /* Find Client entry */
     client_entry = 
@@ -1619,7 +1652,10 @@ void silc_client_notify_by_server(SilcClient client,
     SILC_GET32_MSB(mode, tmp);
 
     /* Get channel entry */
-    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+    channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                               SILC_ID_CHANNEL);
+    if (!channel_id)
+      goto out;
     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
                                     SILC_ID_CHANNEL, &id_cache))
       break;
@@ -1646,6 +1682,8 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
 
     /* Find Client entry */
     client_entry = 
@@ -1667,6 +1705,8 @@ void silc_client_notify_by_server(SilcClient client,
 
     silc_free(client_id);
     client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
 
     /* Find target Client entry */
     client_entry2 = 
@@ -1675,7 +1715,10 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Get channel entry */
-    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+    channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                               SILC_ID_CHANNEL);
+    if (!channel_id)
+      goto out;
     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
                                     SILC_ID_CHANNEL, &id_cache))
       break;
@@ -1791,27 +1834,21 @@ void silc_client_new_channel_id(SilcClient client,
                   (void *)channel->id, (void *)channel, TRUE);
 }
 
-/* Processes received key for channel. The received key will be used
-   to protect the traffic on the channel for now on. Client must receive
-   the key to the channel before talking on the channel is possible. 
-   This is the key that server has generated, this is not the channel
-   private key, it is entirely local setting. */
+/* Saves channel key from encoded `key_payload'. This is used when we
+   receive Channel Key Payload and when we are processing JOIN command 
+   reply. */
 
-void silc_client_receive_channel_key(SilcClient client,
-                                    SilcSocketConnection sock,
-                                    SilcBuffer packet)
+void silc_client_save_channel_key(SilcClientConnection conn,
+                                 SilcBuffer key_payload, 
+                                 SilcChannelEntry channel)
 {
   unsigned char *id_string, *key, *cipher;
   unsigned int tmp_len;
-  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
   SilcChannelID *id;
   SilcIDCacheEntry id_cache = NULL;
-  SilcChannelEntry channel;
   SilcChannelKeyPayload payload;
 
-  SILC_LOG_DEBUG(("Received key for channel"));
-  
-  payload = silc_channel_key_payload_parse(packet);
+  payload = silc_channel_key_payload_parse(key_payload);
   if (!payload)
     return;
 
@@ -1820,24 +1857,32 @@ void silc_client_receive_channel_key(SilcClient client,
     silc_channel_key_payload_free(payload);
     return;
   }
-  id = silc_id_payload_parse_id(id_string, tmp_len);
+
+  id = silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL);
+  if (!id) {
+    silc_channel_key_payload_free(payload);
+    return;
+  }
 
   /* Find channel. */
-  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
-                                  SILC_ID_CHANNEL, &id_cache))
-    goto out;
+  if (!channel) {
+    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
+                                    SILC_ID_CHANNEL, &id_cache))
+      goto out;
     
+    /* Get channel entry */
+    channel = (SilcChannelEntry)id_cache->context;
+  }
+
   /* Save the key */
   key = silc_channel_key_get_key(payload, &tmp_len);
   cipher = silc_channel_key_get_cipher(payload, NULL);
-
-  channel = (SilcChannelEntry)id_cache->context;
   channel->key_len = tmp_len;
   channel->key = silc_calloc(tmp_len, sizeof(*channel->key));
   memcpy(channel->key, key, tmp_len);
 
   if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
-    client->ops->say(client, conn,
+    conn->client->ops->say(conn->client, conn,
                     "Cannot talk to channel: unsupported cipher %s", cipher);
     goto out;
   }
@@ -1852,6 +1897,22 @@ void silc_client_receive_channel_key(SilcClient client,
   silc_channel_key_payload_free(payload);
 }
 
+/* Processes received key for channel. The received key will be used
+   to protect the traffic on the channel for now on. Client must receive
+   the key to the channel before talking on the channel is possible. 
+   This is the key that server has generated, this is not the channel
+   private key, it is entirely local setting. */
+
+void silc_client_receive_channel_key(SilcClient client,
+                                    SilcSocketConnection sock,
+                                    SilcBuffer packet)
+{
+  SILC_LOG_DEBUG(("Received key for channel"));
+
+  /* Save the key */
+  silc_client_save_channel_key(sock->user_data, packet, NULL);
+}
+
 /* Process received message to a channel (or from a channel, really). This
    decrypts the channel message with channel specific key and parses the
    channel payload. Finally it displays the message on the screen. */
@@ -1868,15 +1929,19 @@ void silc_client_channel_message(SilcClient client,
   SilcChannelUser chu;
   SilcIDCacheEntry id_cache = NULL;
   SilcClientID *client_id = NULL;
-  int i;
   char *nickname;
 
   /* Sanity checks */
   if (packet->dst_id_type != SILC_ID_CHANNEL)
     goto out;
 
-  client_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
-  id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+  client_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+                            SILC_ID_CLIENT);
+  if (!client_id)
+    goto out;
+  id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL);
+  if (!id)
+    goto out;
 
   /* Find the channel entry from channels on this connection */
   if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
@@ -1933,13 +1998,17 @@ void silc_client_private_message(SilcClient client,
   SilcBuffer buffer = packet->buffer;
   unsigned short nick_len;
   unsigned char *nickname, *message;
+  int ret;
 
   /* Get nickname */
-  silc_buffer_unformat(buffer, 
-                      SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
-                      SILC_STR_END);
+  ret = silc_buffer_unformat(buffer, 
+                            SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
+                            SILC_STR_END);
+  if (ret == -1)
+    return;
+
   silc_buffer_pull(buffer, 2 + nick_len);
-     
+
   message = silc_calloc(buffer->len + 1, sizeof(char));
   memcpy(message, buffer->data, buffer->len);
 
@@ -1956,7 +2025,8 @@ void silc_client_private_message(SilcClient client,
     if (packet->src_id_type != SILC_ID_CLIENT)
       goto out;
 
-    remote_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
+    remote_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
+                              SILC_ID_CLIENT);
     if (!remote_id)
       goto out;
 
@@ -2007,7 +2077,6 @@ void silc_client_remove_from_channels(SilcClient client,
   SilcIDCacheList list;
   SilcChannelEntry channel;
   SilcChannelUser chu;
-  int i;
 
   if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
                               SILC_ID_CHANNEL, &list))
@@ -2051,7 +2120,6 @@ void silc_client_replace_from_channels(SilcClient client,
   SilcIDCacheList list;
   SilcChannelEntry channel;
   SilcChannelUser chu;
-  int i;
 
   if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
                               SILC_ID_CHANNEL, &list))