Fixed memory leaks around the tree.
[silc.git] / lib / silccore / silcpacket.c
index 76c36ff886c23bf95448b85eda1dc6d9d8de568d..fa3b9cdb7131fda006c1f4b759db8f36c9c9aeae 100644 (file)
@@ -77,11 +77,11 @@ int silc_packet_send(SilcSocketConnection sock, bool force_send)
    other process of HMAC computing and encryption is needed this function
    cannot be used. */
 
-void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, uint32 sequence,
-                        SilcBuffer buffer, uint32 len)
+void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, SilcUInt32 sequence,
+                        SilcBuffer buffer, SilcUInt32 len)
 {
   unsigned char mac[32];
-  uint32 mac_len;
+  SilcUInt32 mac_len;
 
   /* Compute HMAC. This assumes that HMAC is created from the entire
      data area thus this uses the length found in buffer, not the length
@@ -110,171 +110,141 @@ void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, uint32 sequence,
     silc_buffer_pull_tail(buffer, mac_len);
 }
 
-/* Assembles a new packet to be ready for send out. The buffer sent as
-   argument must include the data to be sent and it must not be encrypted. 
-   The packet also must have enough free space so that the SILC header
-   and padding maybe added to the packet. The packet is encrypted after 
-   this function has returned.
+/* Assembles a new packet to be ready for send out. */
 
-   The buffer sent as argument should be something like following:
-
-   --------------------------------------------
-   | head             | data           | tail |
-   --------------------------------------------
-   ^                  ^
-   58 bytes           x bytes
-
-   So that the SILC header and 1 - 16 bytes of padding can fit to
-   the buffer. After assembly the buffer might look like this:
-
-   --------------------------------------------
-   | data                              |      |
-   --------------------------------------------
-   ^                                   ^
-   Start of assembled packet
-
-   Packet construct is as follows:
-
-   n bytes       SILC Header
-      2 bytes     Payload length
-      1 byte      Flags
-      1 byte      Packet type
-      1 byte      Padding length
-      1 byte      RESERVED
-      1 bytes     Source ID Length
-      1 bytes     Destination ID Length
-      1 byte      Source ID Type
-      n bytes     Source ID
-      1 byte      Destination ID Type
-      n bytes     Destination ID
-
-   1 - 16 bytes    Padding
-
-   n bytes        Data payload
-
-   All fields in the packet will be authenticated by MAC. The MAC is
-   not computed here, it must be computed separately before encrypting
-   the packet.
-
-*/
-
-void silc_packet_assemble(SilcPacketContext *ctx, SilcCipher cipher)
-{
-  unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
+bool silc_packet_assemble(SilcPacketContext *packet, SilcRng rng,
+                         SilcCipher cipher, SilcHmac hmac,
+                         SilcSocketConnection sock,
+                         const unsigned char *data, SilcUInt32 data_len,
+                         const SilcBuffer assembled_packet)
+{ 
+  unsigned char tmppad[SILC_PACKET_MAX_PADLEN];   
   int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
-  int i;
+  int i, ret;
 
   SILC_LOG_DEBUG(("Assembling outgoing packet"));
-  
+
+  /* Calculate the packet's length and padding length if upper layer
+     didn't already do it. */
+
   /* Get the true length of the packet. This is saved as payload length
      into the packet header. This does not include the length of the
      padding. */
-  if (!ctx->truelen)
-    ctx->truelen = ctx->buffer->len + SILC_PACKET_HEADER_LEN + 
-      ctx->src_id_len + ctx->dst_id_len;
+  if (!packet->truelen) {
+    data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
+                                  packet->src_id_len + packet->dst_id_len);
+    packet->truelen = data_len + SILC_PACKET_HEADER_LEN + 
+      packet->src_id_len + packet->dst_id_len;
+  }
 
   /* Calculate the length of the padding. The padding is calculated from
      the data that will be encrypted. */
-  if (!ctx->padlen) {
-    if (ctx->long_pad)
-      ctx->padlen = SILC_PACKET_PADLEN_MAX(ctx->truelen);
-    else
-      ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen, block_len);
+  if (!packet->padlen) {
+    packet->padlen = (packet->long_pad ?
+                     SILC_PACKET_PADLEN_MAX(packet->truelen) :
+                     SILC_PACKET_PADLEN(packet->truelen, block_len));
   }
 
-  /* Put the start of the data section to the right place. */
-  silc_buffer_push(ctx->buffer, SILC_PACKET_HEADER_LEN + 
-                  ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
+  /* Now prepare the outgoing data buffer for packet sending and start
+     assembling the packet. */
+
+  /* Return pointer to the assembled packet */
+  if (!silc_packet_send_prepare(sock, packet->truelen - data_len,
+                               packet->padlen, data_len, hmac,
+                               assembled_packet))
+    return FALSE;
 
   /* Get random padding */
-#if 1
-  for (i = 0; i < ctx->padlen; i++) tmppad[i] = 
-                                     silc_rng_global_get_byte_fast();
-#else
-  /* XXX: For testing - to be removed */
-  memset(tmppad, 65, sizeof(tmppad));
-#endif
-
-  /* Create the packet. This creates the SILC header and adds padding,
-     rest of the buffer remains as it is. */
-  silc_buffer_format(ctx->buffer, 
-                    SILC_STR_UI_SHORT(ctx->truelen),
-                    SILC_STR_UI_CHAR(ctx->flags),
-                    SILC_STR_UI_CHAR(ctx->type),
-                    SILC_STR_UI_CHAR(ctx->padlen),
-                    SILC_STR_UI_CHAR(0),
-                    SILC_STR_UI_CHAR(ctx->src_id_len),
-                    SILC_STR_UI_CHAR(ctx->dst_id_len),
-                    SILC_STR_UI_CHAR(ctx->src_id_type),
-                    SILC_STR_UI_XNSTRING(ctx->src_id, ctx->src_id_len),
-                    SILC_STR_UI_CHAR(ctx->dst_id_type),
-                    SILC_STR_UI_XNSTRING(ctx->dst_id, ctx->dst_id_len),
-                    SILC_STR_UI_XNSTRING(tmppad, ctx->padlen),
-                    SILC_STR_END);
-
-  SILC_LOG_HEXDUMP(("Assembled packet, len %d", ctx->buffer->len), 
-                  ctx->buffer->data, ctx->buffer->len);
+  if (rng)
+    for (i = 0; i < packet->padlen; i++) tmppad[i] =
+                                          silc_rng_get_byte_fast(rng);
+  else
+    for (i = 0; i < packet->padlen; i++) tmppad[i] =
+                                          silc_rng_global_get_byte_fast();
+
+  /* Create the packet. This creates the SILC header, adds padding, and
+     the actual packet data. */
+  ret =
+    silc_buffer_format(assembled_packet,
+                      SILC_STR_UI_SHORT(packet->truelen),
+                      SILC_STR_UI_CHAR(packet->flags),
+                      SILC_STR_UI_CHAR(packet->type),
+                      SILC_STR_UI_CHAR(packet->padlen),
+                      SILC_STR_UI_CHAR(0),
+                      SILC_STR_UI_CHAR(packet->src_id_len),
+                      SILC_STR_UI_CHAR(packet->dst_id_len),
+                      SILC_STR_UI_CHAR(packet->src_id_type),
+                      SILC_STR_UI_XNSTRING(packet->src_id,
+                                           packet->src_id_len),
+                      SILC_STR_UI_CHAR(packet->dst_id_type),
+                      SILC_STR_UI_XNSTRING(packet->dst_id,
+                                           packet->dst_id_len),
+                      SILC_STR_UI_XNSTRING(tmppad, packet->padlen),
+                      SILC_STR_UI_XNSTRING(data, data_len),
+                      SILC_STR_END);
+  if (ret < 0)
+    return FALSE;
+
+  SILC_LOG_HEXDUMP(("Assembled packet, len %d", assembled_packet->len),
+                  assembled_packet->data, assembled_packet->len);
 
-  SILC_LOG_DEBUG(("Outgoing packet assembled"));
+  return TRUE;
 }
 
 /* Prepare outgoing data buffer for packet sending. This moves the data
    area so that new packet may be added into it. If needed this allocates
    more space to the buffer. This handles directly the connection's
-   outgoing buffer in SilcSocketConnection object. */
+   outgoing buffer in SilcSocketConnection object, and returns the
+   pointer to that buffer into the `packet'. */
 
-void silc_packet_send_prepare(SilcSocketConnection sock,
-                             uint32 header_len,
-                             uint32 padlen,
-                             uint32 data_len)
-{
-  int totlen, oldlen;
+bool silc_packet_send_prepare(SilcSocketConnection sock,
+                             SilcUInt32 header_len,
+                             SilcUInt32 pad_len,
+                             SilcUInt32 data_len,
+                             SilcHmac hmac,
+                             const SilcBuffer packet)
+{ 
+  int totlen;
+  unsigned char *oldptr;
+  int mac_len = hmac ? silc_hmac_len(hmac) : 0;
 
-  totlen = header_len + padlen + data_len;
+  if (!packet)
+    return FALSE;
+
+  totlen = header_len + pad_len + data_len;
 
   /* Prepare the outgoing buffer for packet sending. */
   if (!sock->outbuf) {
     /* Allocate new buffer. This is done only once per connection. */
     SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
-    
-    if (totlen > SILC_PACKET_DEFAULT_SIZE)
-      sock->outbuf = silc_buffer_alloc(totlen);
-    else
-      sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
-    silc_buffer_pull_tail(sock->outbuf, totlen);
-    silc_buffer_pull(sock->outbuf, header_len + padlen);
-  } else {
-    if (SILC_IS_OUTBUF_PENDING(sock)) {
-      /* There is some pending data in the buffer. */
-
-      /* Allocate more space if needed */
-      if ((sock->outbuf->end - sock->outbuf->tail) < 
-         (totlen + 20)) {
-       SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
-       sock->outbuf = silc_buffer_realloc(sock->outbuf, 
-                                          sock->outbuf->truelen +
-                                          (totlen * 2));
-      }
 
-      oldlen = sock->outbuf->len;
-      silc_buffer_pull_tail(sock->outbuf, totlen);
-      silc_buffer_pull(sock->outbuf, header_len + padlen + oldlen);
-    } else {
+    sock->outbuf = silc_buffer_alloc(totlen > SILC_PACKET_DEFAULT_SIZE ?
+                                    totlen : SILC_PACKET_DEFAULT_SIZE);
+    if (!sock->outbuf)
+      return FALSE;
+  } else {
+    if (!SILC_IS_OUTBUF_PENDING(sock)) {
       /* Buffer is free for use */
       silc_buffer_clear(sock->outbuf);
-
-      /* Allocate more space if needed */
-      if ((sock->outbuf->end - sock->outbuf->tail) < (totlen + 20)) {
-       SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
-       sock->outbuf = silc_buffer_realloc(sock->outbuf, 
-                                          sock->outbuf->truelen + 
-                                          (totlen * 2));
-      }
-
-      silc_buffer_pull_tail(sock->outbuf, totlen);
-      silc_buffer_pull(sock->outbuf, header_len + padlen);
     }
   }
+
+  /* Allocate more space if needed */
+  if ((sock->outbuf->end - sock->outbuf->tail) < (totlen + mac_len)) {
+    SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
+    sock->outbuf = silc_buffer_realloc(sock->outbuf,
+                                      sock->outbuf->truelen + (totlen * 2));
+    if (!sock->outbuf)
+      return FALSE;
+  }
+
+  /* Pull data area for the new packet, and return pointer to the start of
+     the data area and save the pointer in to the `packet'. */
+  oldptr = silc_buffer_pull_tail(sock->outbuf, totlen + mac_len);
+  silc_buffer_set(packet, oldptr, totlen + mac_len);
+  silc_buffer_push_tail(packet, mac_len);
+
+  return TRUE;
 }
 
 /******************************************************************************
@@ -284,7 +254,7 @@ void silc_packet_send_prepare(SilcSocketConnection sock,
 ******************************************************************************/
 
 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, 
-                              uint32 sequence, SilcBuffer buffer, 
+                              SilcUInt32 sequence, SilcBuffer buffer, 
                               bool normal);
 
 /* Receives packet from network and reads the data into connection's
@@ -327,7 +297,7 @@ int silc_packet_receive(SilcSocketConnection sock)
 bool silc_packet_receive_process(SilcSocketConnection sock,
                                 bool local_is_router,
                                 SilcCipher cipher, SilcHmac hmac,
-                                uint32 sequence,
+                                SilcUInt32 sequence,
                                 SilcPacketParserCallback parser,
                                 void *parser_context)
 {
@@ -363,7 +333,7 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
 
     /* Sanity checks */
     if (packetlen < SILC_PACKET_MIN_LEN) {
-      SILC_LOG_DEBUG(("Received invalid packet, dropped"));
+      SILC_LOG_ERROR(("Received invalid packet, dropped"));
       silc_buffer_clear(sock->inbuf);
       return FALSE;
     }
@@ -377,6 +347,8 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
 
     SILC_UNSET_INBUF_PENDING(sock);
     parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
+    if (!parse_ctx)
+      return FALSE;
     parse_ctx->packet = silc_packet_context_alloc();
     parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len);
     parse_ctx->packet->type = sock->inbuf->data[3];
@@ -417,12 +389,16 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
       if (silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence, 
                              parse_ctx->packet->buffer, 
                              parse_ctx->normal) == -1) {
-       SILC_LOG_WARNING(("Packet decryption failed %s:%d [%s]", 
+       SILC_LOG_WARNING(("Packet decryption failed %s:%d [%s] [%s]", 
                          sock->hostname, sock->port,
+                         silc_get_packet_name(parse_ctx->packet->type),
                          (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
                           sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
                           sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
                           "Router")));
+       silc_packet_context_free(parse_ctx->packet);
+       silc_free(parse_ctx);
+       return FALSE;
       }
 
     /* Pull the packet from inbuf thus we'll get the next one
@@ -445,12 +421,12 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
    after packet has been totally decrypted and parsed. */
 
 static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer,
-                                uint32 sequence)
+                                SilcUInt32 sequence)
 {
   /* Check MAC */
   if (hmac) {
     unsigned char mac[32], psn[4];
-    uint32 mac_len;
+    SilcUInt32 mac_len;
     
     SILC_LOG_DEBUG(("Verifying MAC"));
 
@@ -491,7 +467,7 @@ static int silc_packet_decrypt_rest(SilcCipher cipher, SilcHmac hmac,
       if ((buffer->len - silc_hmac_len(hmac)) > SILC_PACKET_MIN_LEN) {
        silc_buffer_push_tail(buffer, silc_hmac_len(hmac));
       } else {
-       SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
+       SILC_LOG_ERROR(("Bad MAC length in packet, packet dropped"));
        return FALSE;
       }
     }
@@ -523,14 +499,14 @@ static int silc_packet_decrypt_rest_special(SilcCipher cipher,
 {
   /* Decrypt rest of the header plus padding */
   if (cipher) {
-    uint16 len;
+    SilcUInt16 len;
 
     /* Pull MAC from packet before decryption */
     if (hmac) {
       if ((buffer->len - silc_hmac_len(hmac)) > SILC_PACKET_MIN_LEN) {
        silc_buffer_push_tail(buffer, silc_hmac_len(hmac));
       } else {
-       SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
+       SILC_LOG_ERROR(("Bad MAC length in packet, packet dropped"));
        return FALSE;
       }
     }
@@ -539,13 +515,13 @@ static int silc_packet_decrypt_rest_special(SilcCipher cipher,
 
     /* padding length + src id len + dst id len + header length - 16
        bytes already decrypted, gives the rest of the encrypted packet */
-    len = (((uint8)buffer->data[4] + (uint8)buffer->data[6] + 
-          (uint8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
+    len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] + 
+          (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
           SILC_PACKET_MIN_HEADER_LEN);
 
     silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN);
     if (len > buffer->len) {
-      SILC_LOG_DEBUG(("Garbage in header of packet, bad packet length, "
+      SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
                      "packet dropped"));
       return FALSE;
     }
@@ -573,7 +549,7 @@ static int silc_packet_decrypt_rest_special(SilcCipher cipher,
    is special and requires special procesing. */
 
 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
-                              uint32 sequence, SilcBuffer buffer, 
+                              SilcUInt32 sequence, SilcBuffer buffer, 
                               bool normal)
 {
   /* If the packet type is not any special type lets decrypt rest
@@ -611,8 +587,9 @@ static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
 SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
 {
   SilcBuffer buffer = ctx->buffer;
-  uint8 tmp;
+  SilcUInt8 tmp;
   int len, ret;
+  SilcUInt8 src_id_len, src_id_type, dst_id_len, dst_id_type, padlen;
 
   SILC_LOG_DEBUG(("Parsing incoming packet"));
 
@@ -627,34 +604,46 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
                             SILC_STR_UI_SHORT(&ctx->truelen),
                             SILC_STR_UI_CHAR(&ctx->flags),
                             SILC_STR_UI_CHAR(&ctx->type),
-                            SILC_STR_UI_CHAR(&ctx->padlen),
+                            SILC_STR_UI_CHAR(&padlen),
                             SILC_STR_UI_CHAR(&tmp),
-                            SILC_STR_UI_CHAR(&ctx->src_id_len),
-                            SILC_STR_UI_CHAR(&ctx->dst_id_len),
-                            SILC_STR_UI_CHAR(&ctx->src_id_type),
+                            SILC_STR_UI_CHAR(&src_id_len),
+                            SILC_STR_UI_CHAR(&dst_id_len),
+                            SILC_STR_UI_CHAR(&src_id_type),
                             SILC_STR_END);
   if (len == -1 || tmp != 0)
     return SILC_PACKET_NONE;
 
-  if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
-      ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
+  if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
+      dst_id_len > SILC_PACKET_MAX_ID_LEN) {
     SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
-                   ctx->src_id_len, ctx->dst_id_len));
+                   src_id_len, dst_id_len));
     return SILC_PACKET_NONE;
   }
 
   silc_buffer_pull(buffer, len);
   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),
+                                                       src_id_len),
+                            SILC_STR_UI_CHAR(&dst_id_type),
                             SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
-                                                       ctx->dst_id_len),
-                            SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
+                                                       dst_id_len),
+                            SILC_STR_UI_XNSTRING(NULL, padlen),
                             SILC_STR_END);
   if (ret == -1)
     return SILC_PACKET_NONE;
 
+  if (src_id_type > SILC_ID_CHANNEL || dst_id_type > SILC_ID_CHANNEL) {
+    SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
+                  src_id_type, dst_id_type));
+    return SILC_PACKET_NONE;
+  }
+
+  ctx->src_id_len = src_id_len;
+  ctx->dst_id_len = dst_id_len;
+  ctx->src_id_type = src_id_type;
+  ctx->dst_id_type = dst_id_type;
+  ctx->padlen = padlen;
+
   silc_buffer_push(buffer, len);
 
   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
@@ -679,8 +668,9 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
                                         SilcCipher cipher)
 {
   SilcBuffer buffer = ctx->buffer;
-  uint8 tmp;
+  SilcUInt8 tmp;
   int len, ret;
+  SilcUInt8 src_id_len, src_id_type, dst_id_len, dst_id_type, padlen;
 
   SILC_LOG_DEBUG(("Parsing incoming packet"));
 
@@ -695,38 +685,50 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
                             SILC_STR_UI_SHORT(&ctx->truelen),
                             SILC_STR_UI_CHAR(&ctx->flags),
                             SILC_STR_UI_CHAR(&ctx->type),
-                            SILC_STR_UI_CHAR(&ctx->padlen),
+                            SILC_STR_UI_CHAR(&padlen),
                             SILC_STR_UI_CHAR(&tmp),
-                            SILC_STR_UI_CHAR(&ctx->src_id_len),
-                            SILC_STR_UI_CHAR(&ctx->dst_id_len),
-                            SILC_STR_UI_CHAR(&ctx->src_id_type),
+                            SILC_STR_UI_CHAR(&src_id_len),
+                            SILC_STR_UI_CHAR(&dst_id_len),
+                            SILC_STR_UI_CHAR(&src_id_type),
                             SILC_STR_END);
   if (len == -1 || tmp != 0) {
     SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
     return SILC_PACKET_NONE;
   }
 
-  if (ctx->src_id_len > SILC_PACKET_MAX_ID_LEN ||
-      ctx->dst_id_len > SILC_PACKET_MAX_ID_LEN) {
+  if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
+      dst_id_len > SILC_PACKET_MAX_ID_LEN) {
     SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
-                   ctx->src_id_len, ctx->dst_id_len));
+                   src_id_len, dst_id_len));
     return SILC_PACKET_NONE;
   }
 
   silc_buffer_pull(buffer, len);
   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),
+                                                       src_id_len),
+                            SILC_STR_UI_CHAR(&dst_id_type),
                             SILC_STR_UI_XNSTRING_ALLOC(&ctx->dst_id,
-                                                       ctx->dst_id_len),
-                            SILC_STR_UI_XNSTRING(NULL, ctx->padlen),
+                                                       dst_id_len),
+                            SILC_STR_UI_XNSTRING(NULL, padlen),
                             SILC_STR_END);
   if (ret == -1) {
     SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
     return SILC_PACKET_NONE;
   }
 
+  if (src_id_type > SILC_ID_CHANNEL || dst_id_type > SILC_ID_CHANNEL) {
+    SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
+                  src_id_type, dst_id_type));
+    return SILC_PACKET_NONE;
+  }
+
+  ctx->src_id_len = src_id_len;
+  ctx->dst_id_len = dst_id_len;
+  ctx->src_id_type = src_id_type;
+  ctx->dst_id_type = dst_id_type;
+  ctx->padlen = padlen;
+
   silc_buffer_push(buffer, len);
 
   SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
@@ -746,6 +748,8 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
 SilcPacketContext *silc_packet_context_alloc(void)
 {
   SilcPacketContext *ctx = silc_calloc(1, sizeof(*ctx));
+  if (!ctx)
+    return NULL;
   ctx->users++;
   return ctx;
 }