Code auditing weekend results and fixes committing.
[silc.git] / lib / silccore / silcpacket.c
index 8cb2799552e401223dacd42547815fb18708b6be..9c5ed4759534ca76f5923128a826b81e34beab8c 100644 (file)
 /*
  * Created: Fri Jul 25 18:52:14 1997
  */
-/*
- * $Id$
- * $Log$
- * Revision 1.4  2000/07/18 06:51:58  priikone
- *     Debug version bug fixes.
- *
- * Revision 1.3  2000/07/14 06:10:15  priikone
- *     Moved all the generic packet sending, enryption, reception,
- *     decryption and processing function from client and server to
- *     here as they were duplicated code in the applications. Now they
- *     are generic code over generic API. Some functions were rewritter;
- *     packet reception and HMAC computation and checking is now more
- *     optimized.
- *
- * Revision 1.2  2000/07/05 06:06:35  priikone
- *     Global cosmetic change.
- *
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "silcincludes.h"
 
@@ -225,8 +204,7 @@ void silc_packet_assemble(SilcPacketContext *ctx)
 
   /* Get random padding */
 #if 1
-  for (i = 0; i < ctx->padlen; i++)
-    tmppad[i] = silc_rng_get_byte(ctx->rng);
+  for (i = 0; i < ctx->padlen; i++) tmppad[i] = silc_rng_get_byte(ctx->rng);
 #else
   /* XXX: For testing - to be removed */
   memset(tmppad, 65, sizeof(tmppad));
@@ -328,7 +306,7 @@ int silc_packet_read(int sock, SilcBuffer dest)
   /* Read the data from the socket. */
   len = read(sock, buf, sizeof(buf));
   if (len < 0) {
-    if (errno == EAGAIN) {
+    if (errno == EAGAIN || errno == EINTR) {
       SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
       return -2;
     }
@@ -379,97 +357,71 @@ int silc_packet_read(int sock, SilcBuffer dest)
    and parsing. If more than one packet was received this calls the
    parser multiple times. The parser callback will get context
    SilcPacketParserContext that includes the packet and the `context'
-   sent to this function. Returns TRUE on success and FALSE on error. */
+   sent to this function. */
 
-int silc_packet_receive_process(SilcSocketConnection sock, 
-                               SilcCipher cipher, SilcHmac hmac,
-                               SilcPacketParserCallback parser, 
-                               void *context)
+void silc_packet_receive_process(SilcSocketConnection sock,
+                                SilcCipher cipher, SilcHmac hmac,
+                                SilcPacketParserCallback parser,
+                                void *context)
 {
   SilcPacketParserContext *parse_ctx;
-  int packetlen, paddedlen, mac_len = 0;
-
-  /* Check whether we received a whole packet. If reading went without
-     errors we either read a whole packet or the read packet is 
-     incorrect and will be dropped. */
-  SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
-  if (sock->inbuf->len < paddedlen || (packetlen < SILC_PACKET_MIN_LEN)) {
-    SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
-    silc_buffer_clear(sock->inbuf);
-    return FALSE;
-  }
+  int packetlen, paddedlen, count, mac_len = 0;
 
-  /* Parse the packets from the data */
-  if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
-    /* Received possibly many packets at once */
-
-    if (hmac)
-      mac_len = hmac->hash->hash->hash_len;
+  /* We need at least 2 bytes of data to be able to start processing
+     the packet. */
+  if (sock->inbuf->len < 2)
+    return;
 
-    while(sock->inbuf->len > 0) {
-      SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
-
-      if (sock->inbuf->len < paddedlen) {
-       SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
-       return FALSE;
-      }
+  if (hmac)
+    mac_len = hmac->hash->hash->hash_len;
 
-      paddedlen += 2;
-      parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
-      parse_ctx->packet = silc_calloc(1, sizeof(*parse_ctx->packet));
-      parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len);
-      parse_ctx->sock = sock;
-      parse_ctx->cipher = cipher;
-      parse_ctx->hmac = hmac;
-      parse_ctx->context = context;
-
-      silc_buffer_pull_tail(parse_ctx->packet->buffer, 
-                           SILC_BUFFER_END(parse_ctx->packet->buffer));
-      silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data, 
-                     paddedlen + mac_len);
-
-      SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
-                       parse_ctx->packet->buffer->len),
-                      parse_ctx->packet->buffer->data, 
-                      parse_ctx->packet->buffer->len);
-
-      /* Call the parser */
-      if (parser)
-       (*parser)(parse_ctx);
-
-      /* Pull the packet from inbuf thus we'll get the next one
-        in the inbuf. */
-      silc_buffer_pull(sock->inbuf, paddedlen);
-      if (hmac)
-       silc_buffer_pull(sock->inbuf, mac_len);
+  /* Parse the packets from the data */
+  count = 0;
+  while (sock->inbuf->len > 0) {
+    SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+    paddedlen += 2;
+    count++;
+
+    if (packetlen < SILC_PACKET_MIN_LEN) {
+      SILC_LOG_DEBUG(("Received invalid packet, dropped"));
+      return;
     }
 
-    /* All packets are processed, return successfully. */
-    silc_buffer_clear(sock->inbuf);
-    return TRUE;
-
-  } else {
-    /* Received one packet */
-    
-    SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
-                    sock->inbuf->data, sock->inbuf->len);
+    if (sock->inbuf->len < paddedlen + mac_len) {
+      SILC_LOG_DEBUG(("Received partial packet, waiting for the rest"));
+      return;
+    }
 
     parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
-    parse_ctx->packet = silc_calloc(1, sizeof(*parse_ctx->packet));
-    parse_ctx->packet->buffer = silc_buffer_copy(sock->inbuf);
+    parse_ctx->packet = silc_packet_context_alloc();
+    parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len);
     parse_ctx->sock = sock;
     parse_ctx->cipher = cipher;
     parse_ctx->hmac = hmac;
     parse_ctx->context = context;
-    silc_buffer_clear(sock->inbuf);
+
+    silc_buffer_pull_tail(parse_ctx->packet->buffer, 
+                         SILC_BUFFER_END(parse_ctx->packet->buffer));
+    silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data, 
+                   paddedlen + mac_len);
+
+    SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
+                     parse_ctx->packet->buffer->len),
+                    parse_ctx->packet->buffer->data, 
+                    parse_ctx->packet->buffer->len);
 
     /* Call the parser */
     if (parser)
       (*parser)(parse_ctx);
 
-    /* Return successfully */
-    return TRUE;
+    /* Pull the packet from inbuf thus we'll get the next one
+       in the inbuf. */
+    silc_buffer_pull(sock->inbuf, paddedlen);
+    if (hmac)
+      silc_buffer_pull(sock->inbuf, mac_len);
   }
+
+  silc_buffer_clear(sock->inbuf);
 }
 
 /* Receives packet from network and reads the data into connection's
@@ -616,10 +568,6 @@ static int silc_packet_decrypt_rest_special(SilcCipher cipher,
 int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
                        SilcBuffer buffer, SilcPacketContext *packet)
 {
-#if 0
-  SILC_LOG_DEBUG(("Decrypting packet, cipher %s, len %d (%d)", 
-                 cipher->cipher->name, len, len - 2));
-#endif
 
   /* Decrypt start of the packet header */
   if (cipher)
@@ -645,7 +593,8 @@ int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
   } else {
     /* Packet requires special handling, decrypt rest of the header.
        This only decrypts. */
-    silc_packet_decrypt_rest_special(cipher, hmac, buffer);
+    if (!silc_packet_decrypt_rest_special(cipher, hmac, buffer))
+      return -1;
 
     /* Check MAC */
     if (!silc_packet_check_mac(hmac, buffer))
@@ -664,7 +613,7 @@ int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
 SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
 {
   SilcBuffer buffer = ctx->buffer;
-  int len;
+  int len, ret;
 
   SILC_LOG_DEBUG(("Parsing incoming packet"));
 
@@ -683,6 +632,8 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
                             SILC_STR_UI_SHORT(&ctx->dst_id_len),
                             SILC_STR_UI_CHAR(&ctx->src_id_type),
                             SILC_STR_END);
+  if (len == -1)
+    return SILC_PACKET_NONE;
 
   if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
       ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
@@ -694,14 +645,17 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
   ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
 
   silc_buffer_pull(buffer, len);
-  silc_buffer_unformat(buffer, 
-                      SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
-                                                 ctx->src_id_len),
-                      SILC_STR_UI_CHAR(&ctx->dst_id_type),
-                      SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
-                                                 ctx->dst_id_len),
-                      SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
-                      SILC_STR_END);
+  ret = silc_buffer_unformat(buffer, 
+                            SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
+                                                       ctx->src_id_len),
+                            SILC_STR_UI_CHAR(&ctx->dst_id_type),
+                            SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
+                                                       ctx->dst_id_len),
+                            SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
+                            SILC_STR_END);
+  if (ret == -1)
+    return SILC_PACKET_NONE;
+
   silc_buffer_push(buffer, len);
 
   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
@@ -725,7 +679,7 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx)
 SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
 {
   SilcBuffer buffer = ctx->buffer;
-  int len, tmplen;
+  int len, tmplen, ret;
 
   SILC_LOG_DEBUG(("Parsing incoming packet"));
 
@@ -744,6 +698,8 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
                             SILC_STR_UI_SHORT(&ctx->dst_id_len),
                             SILC_STR_UI_CHAR(&ctx->src_id_type),
                             SILC_STR_END);
+  if (len == -1)
+    return SILC_PACKET_NONE;
 
   if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
       ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
@@ -758,14 +714,17 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
   ctx->padlen = SILC_PACKET_PADLEN(tmplen);
 
   silc_buffer_pull(buffer, len);
-  silc_buffer_unformat(buffer, 
-                      SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
-                                                 ctx->src_id_len),
-                      SILC_STR_UI_CHAR(&ctx->dst_id_type),
-                      SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
-                                                 ctx->dst_id_len),
-                      SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
-                      SILC_STR_END);
+  ret = silc_buffer_unformat(buffer, 
+                            SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
+                                                       ctx->src_id_len),
+                            SILC_STR_UI_CHAR(&ctx->dst_id_type),
+                            SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
+                                                       ctx->dst_id_len),
+                            SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
+                            SILC_STR_END);
+  if (ret == -1)
+    return SILC_PACKET_NONE;
+
   silc_buffer_push(buffer, len);
 
   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
@@ -779,3 +738,42 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
 
   return ctx->type;
 }
+
+/* Allocate packet context */
+
+SilcPacketContext *silc_packet_context_alloc()
+{
+  SilcPacketContext *ctx = silc_calloc(1, sizeof(*ctx));
+  ctx->users++;
+  return ctx;
+}
+
+/* Increse the reference count of the packet context. */
+
+SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx)
+{
+  ctx->users++;
+  SILC_LOG_DEBUG(("Packet context %p rfcnt %d->%d", ctx, ctx->users - 1,
+                 ctx->users));
+  return ctx;
+}
+
+/* Decrese the reference count of the packet context and free it only if
+   it is zero. */
+
+void silc_packet_context_free(SilcPacketContext *ctx)
+{
+  ctx->users--;
+  SILC_LOG_DEBUG(("Packet context %p rfcnt %d->%d", ctx, ctx->users + 1,
+                 ctx->users));
+  if (ctx->users < 1)
+    {
+      if (ctx->buffer)
+       silc_buffer_free(ctx->buffer);
+      if (ctx->src_id)
+       silc_free(ctx->src_id);
+      if (ctx->dst_id)
+       silc_free(ctx->dst_id);
+      silc_free(ctx);
+    }
+}