Merged silc_1_1_branch to trunk.
[silc.git] / apps / silcd / packet_receive.c
index 313004f8330efaa3b62ddddeed7e66ac77c24d9e..9b990ff8d5fb587bec5a973171ec2e7400e9fd1d 100644 (file)
@@ -46,8 +46,17 @@ static void silc_server_notify_process(SilcServer server,
   SilcUInt32 tmp_len, tmp2_len;
   SilcBool local, ret;
 
-  if (idata->conn_type == SILC_CONN_CLIENT ||
-      packet->src_id_type != SILC_ID_SERVER || !packet->dst_id) {
+  if (idata->conn_type == SILC_CONN_CLIENT) {
+    SILC_LOG_DEBUG(("Notify received from client, drop it"));
+    return;
+  }
+
+  if (packet->src_id_type != SILC_ID_SERVER){
+    SILC_LOG_DEBUG(("Bad notify packet received"));
+    return;
+  }
+
+  if (!packet->dst_id) {
     SILC_LOG_DEBUG(("Bad notify packet received"));
     return;
   }
@@ -69,8 +78,10 @@ static void silc_server_notify_process(SilcServer server,
 
   /* Parse the Notify Payload */
   payload = silc_notify_payload_parse(buffer->data, silc_buffer_len(buffer));
-  if (!payload)
+  if (!payload) {
+    SILC_LOG_DEBUG(("Marlformed notify payload"));
     return;
+  }
 
   /* If we are router and this packet is not already broadcast packet
      we will broadcast it. The sending socket really cannot be router or
@@ -84,8 +95,10 @@ static void silc_server_notify_process(SilcServer server,
       /* Packet is destined to channel */
       if (!silc_id_str2id(packet->dst_id, packet->dst_id_len,
                          packet->dst_id_type, &channel_id,
-                         sizeof(channel_id)))
+                         sizeof(channel_id))) {
+       SILC_LOG_DEBUG(("Malformed destination ID in notify packet"));
        goto out;
+      }
 
       silc_server_packet_send_dest(server, SILC_PRIMARY_ROUTE(server),
                                   packet->type, packet->flags |
@@ -112,8 +125,10 @@ static void silc_server_notify_process(SilcServer server,
 
   type = silc_notify_get_type(payload);
   args = silc_notify_get_args(payload);
-  if (!args)
+  if (!args) {
+    SILC_LOG_DEBUG(("Notify doesn't have any arguments, drop it"));
     goto out;
+  }
 
   switch(type) {
   case SILC_NOTIFY_TYPE_JOIN:
@@ -133,7 +148,8 @@ static void silc_server_notify_process(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list,
                                               SILC_ID_GET_ID(id), NULL);
       if (!channel) {
-       SILC_LOG_DEBUG(("Notify for unknown channel"));
+       SILC_LOG_DEBUG(("Notify for unknown channel %s",
+                       silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL)));
        goto out;
       }
     }
@@ -251,7 +267,8 @@ static void silc_server_notify_process(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list,
                                               &channel_id, NULL);
       if (!channel) {
-       SILC_LOG_DEBUG(("Notify for unknown channel"));
+       SILC_LOG_DEBUG(("Notify for unknown channel %s",
+                       silc_id_render(&channel_id, SILC_ID_CHANNEL)));
        goto out;
       }
     }
@@ -316,10 +333,12 @@ static void silc_server_notify_process(SilcServer server,
     SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
     silc_schedule_task_del_by_context(server->schedule, client);
 
-    /* Remove from public key hash table. */
-    if (client->data.public_key)
-      silc_hash_table_del_by_context(server->pk_hash, client->data.public_key,
-                                     client);
+    /* Remove client's public key from repository, this will free it too. */
+    if (client->data.public_key) {
+      silc_skr_del_public_key(server->repository, client->data.public_key,
+                             client);
+      client->data.public_key = NULL;
+    }
 
     /* Remove the client from all channels. */
     silc_server_remove_from_channels(server, NULL, client, TRUE,
@@ -337,6 +356,7 @@ static void silc_server_notify_process(SilcServer server,
     client->mode = 0;
     client->router = NULL;
     client->connection = NULL;
+    silc_dlist_add(server->expired_clients, client);
     break;
 
   case SILC_NOTIFY_TYPE_TOPIC_SET:
@@ -380,7 +400,8 @@ static void silc_server_notify_process(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list,
                                               &channel_id, NULL);
       if (!channel) {
-       SILC_LOG_DEBUG(("Notify for unknown channel"));
+       SILC_LOG_DEBUG(("Notify for unknown channel %s",
+                       silc_id_render(&channel_id, SILC_ID_CHANNEL)));
        goto out;
       }
     }
@@ -500,7 +521,8 @@ static void silc_server_notify_process(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list,
                                               &channel_id, NULL);
       if (!channel) {
-       SILC_LOG_DEBUG(("Notify for unknown channel"));
+       SILC_LOG_DEBUG(("Notify for unknown channel %s",
+                       silc_id_render(&channel_id, SILC_ID_CHANNEL)));
        goto out;
       }
     }
@@ -820,7 +842,8 @@ static void silc_server_notify_process(SilcServer server,
        channel = silc_idlist_find_channel_by_id(server->local_list,
                                                 &channel_id, NULL);
        if (!channel) {
-         SILC_LOG_DEBUG(("Notify for unknown channel"));
+         SILC_LOG_DEBUG(("Notify for unknown channel %s",
+                         silc_id_render(&channel_id, SILC_ID_CHANNEL)));
          goto out;
        }
       }
@@ -1007,7 +1030,8 @@ static void silc_server_notify_process(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list,
                                               SILC_ID_GET_ID(id), NULL);
       if (!channel) {
-       SILC_LOG_DEBUG(("Notify for unknown channel"));
+       SILC_LOG_DEBUG(("Notify for unknown channel %s",
+                       silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL)));
        goto out;
       }
     }
@@ -1076,7 +1100,8 @@ static void silc_server_notify_process(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->global_list,
                                               SILC_ID_GET_ID(id), NULL);
       if (!channel) {
-       SILC_LOG_DEBUG(("Notify for unknown channel"));
+       SILC_LOG_DEBUG(("Notify for unknown channel %s",
+                       silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL)));
        goto out;
       }
     }
@@ -1205,12 +1230,12 @@ static void silc_server_notify_process(SilcServer server,
 
            /* Get client entry */
            client = silc_idlist_find_client_by_id(server->global_list,
-                                                  SILC_ID_GET_ID(id),
+                                                  SILC_ID_GET_ID(id2),
                                                   TRUE, &cache);
            local = FALSE;
            if (!client) {
              client = silc_idlist_find_client_by_id(server->local_list,
-                                                    SILC_ID_GET_ID(id),
+                                                    SILC_ID_GET_ID(id2),
                                                     TRUE, &cache);
              local = TRUE;
              if (!client)
@@ -1237,12 +1262,6 @@ static void silc_server_notify_process(SilcServer server,
            if (local)
              silc_server_del_from_watcher_list(server, client);
 
-           /* Remove from public key hash table. */
-           if (client->data.public_key)
-             silc_hash_table_del_by_context(server->pk_hash,
-                                             client->data.public_key,
-                                             client);
-
            /* Remove the client */
            silc_idlist_del_data(client);
            silc_idlist_del_client(local ? server->local_list :
@@ -1307,7 +1326,8 @@ static void silc_server_notify_process(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list,
                                               &channel_id, NULL);
       if (!channel) {
-       SILC_LOG_DEBUG(("Notify for unknown channel"));
+       SILC_LOG_DEBUG(("Notify for unknown channel %s",
+                       silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL)));
        goto out;
       }
     }
@@ -1459,11 +1479,12 @@ static void silc_server_notify_process(SilcServer server,
        silc_server_check_watcher_list(server, client, NULL,
                                       SILC_NOTIFY_TYPE_KILLED);
 
-      /* Remove from public key hash table. */
-      if (client->data.public_key)
-       silc_hash_table_del_by_context(server->pk_hash,
-                                      client->data.public_key,
-                                      client);
+      /* Remove client's public key from repository, this will free it too. */
+      if (client->data.public_key) {
+       silc_skr_del_public_key(server->repository, client->data.public_key,
+                               client);
+       client->data.public_key = NULL;
+      }
 
       /* Update statistics */
       server->stat.clients--;
@@ -1483,6 +1504,7 @@ static void silc_server_notify_process(SilcServer server,
       client->mode = 0;
       client->router = NULL;
       client->connection = NULL;
+      silc_dlist_add(server->expired_clients, client);
       break;
     }
 
@@ -1565,7 +1587,8 @@ static void silc_server_notify_process(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list,
                                               SILC_ID_GET_ID(id), NULL);
       if (!channel) {
-       SILC_LOG_DEBUG(("Notify for unknown channel"));
+       SILC_LOG_DEBUG(("Notify for unknown channel %s",
+                       silc_id_render(SILC_ID_GET_ID(id), SILC_ID_CHANNEL)));
        goto out;
       }
     }
@@ -1639,11 +1662,6 @@ static void silc_server_notify_process(SilcServer server,
        if (!client)
          goto out;
 
-       if (client->data.public_key)
-         silc_hash_table_del_by_context(server->pk_hash,
-                                        client->data.public_key,
-                                        client);
-
        silc_server_remove_from_channels(server, NULL, client, TRUE,
                                         NULL, TRUE, FALSE);
        silc_idlist_del_data(client);
@@ -1658,6 +1676,7 @@ static void silc_server_notify_process(SilcServer server,
     break;
 
   default:
+    SILC_LOG_DEBUG(("Unsupported notify %d", type));
     break;
   }
 
@@ -1670,6 +1689,7 @@ void silc_server_notify(SilcServer server,
                        SilcPacket packet)
 {
   silc_server_notify_process(server, sock, packet, &packet->buffer);
+  silc_packet_free(packet);
 }
 
 void silc_server_notify_list(SilcServer server,
@@ -1710,6 +1730,7 @@ void silc_server_notify_list(SilcServer server,
     silc_buffer_pull(&packet->buffer, len);
   }
 
+  silc_packet_free(packet);
   silc_buffer_free(buffer);
 }
 
@@ -1732,7 +1753,7 @@ void silc_server_private_message(SilcServer server,
 
   if (packet->src_id_type != SILC_ID_CLIENT ||
       packet->dst_id_type != SILC_ID_CLIENT || !packet->dst_id)
-    return;
+    goto out;
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
@@ -1744,7 +1765,7 @@ void silc_server_private_message(SilcServer server,
 
     if (client && client->mode & SILC_UMODE_DETACHED) {
       SILC_LOG_DEBUG(("Client is detached, discarding packet"));
-      return;
+      goto out;
     }
 
     /* Send SILC_NOTIFY_TYPE_ERROR to indicate that such destination ID
@@ -1753,7 +1774,7 @@ void silc_server_private_message(SilcServer server,
                                      packet->dst_id_len,
                                      packet->dst_id_type);
     if (!idp)
-      return;
+      goto out;
 
     error = SILC_STATUS_ERR_NO_SUCH_CLIENT_ID;
     if (packet->src_id_type == SILC_ID_CLIENT) {
@@ -1772,18 +1793,21 @@ void silc_server_private_message(SilcServer server,
     }
 
     silc_buffer_free(idp);
-    return;
+    goto out;
   }
 
   /* Check whether destination client wishes to receive private messages */
   if (client && !(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) &&
       client->mode & SILC_UMODE_BLOCK_PRIVMSG) {
     SILC_LOG_DEBUG(("Client blocks private messages, discarding packet"));
-    return;
+    goto out;
   }
 
   /* Send the private message */
   silc_server_packet_route(server, dst_sock, packet);
+
+ out:
+  silc_packet_free(packet);
 }
 
 /* Received private message key packet.. This packet is never for us. It is to
@@ -1801,21 +1825,24 @@ void silc_server_private_message_key(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   if (packet->src_id_type != SILC_ID_CLIENT ||
-      packet->dst_id_type != SILC_ID_CLIENT)
-    return;
-
-  if (!packet->dst_id)
+      packet->dst_id_type != SILC_ID_CLIENT || !packet->dst_id) {
+    silc_packet_free(packet);
     return;
+  }
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
                                          packet->dst_id_len, NULL,
                                          &idata, NULL);
-  if (!dst_sock)
+  if (!dst_sock) {
+    silc_packet_free(packet);
     return;
+  }
 
   /* Relay the packet */
   silc_server_packet_route(server, dst_sock, packet);
+
+  silc_packet_free(packet);
 }
 
 /* Processes incoming command reply packet. The command reply packet may
@@ -1832,18 +1859,23 @@ void silc_server_command_reply(SilcServer server,
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (packet->dst_id_type == SILC_ID_CHANNEL)
+  if (packet->dst_id_type == SILC_ID_CHANNEL) {
+    silc_packet_free(packet);
     return;
+  }
 
   if (packet->dst_id_type == SILC_ID_CLIENT) {
     /* Destination must be one of ours */
     if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CLIENT,
-                       &id, sizeof(id)))
+                       &id, sizeof(id))) {
+      silc_packet_free(packet);
       return;
+    }
     client = silc_idlist_find_client_by_id(server->local_list, &id,
                                           TRUE, NULL);
     if (!client) {
       SILC_LOG_ERROR(("Cannot process command reply to unknown client"));
+      silc_packet_free(packet);
       return;
     }
   }
@@ -1852,6 +1884,7 @@ void silc_server_command_reply(SilcServer server,
     /* For now this must be for us */
     if (memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
       SILC_LOG_ERROR(("Cannot process command reply to unknown server"));
+      silc_packet_free(packet);
       return;
     }
   }
@@ -1862,6 +1895,8 @@ void silc_server_command_reply(SilcServer server,
   /* Relay the packet to the client */
   if (packet->dst_id_type == SILC_ID_CLIENT && client)
     silc_server_packet_route(server, client->connection, packet);
+
+  silc_packet_free(packet);
 }
 
 /* Process received channel message. The message can be originated from
@@ -1875,7 +1910,6 @@ void silc_server_channel_message(SilcServer server,
   SilcChannelID id;
   SilcClientID cid;
   SilcID sid;
-  void *sender_id = NULL;
   SilcClientEntry sender_entry = NULL;
   SilcIDListData idata;
   SilcChannelClientEntry chl;
@@ -1886,13 +1920,13 @@ void silc_server_channel_message(SilcServer server,
   /* Sanity checks */
   if (packet->dst_id_type != SILC_ID_CHANNEL) {
     SILC_LOG_DEBUG(("Received bad message for channel, dropped"));
-    return;
+    goto out;
   }
 
   /* Find channel entry */
   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
                      &id, sizeof(id)))
-    return;
+    goto out;
   channel = silc_idlist_find_channel_by_id(server->local_list, &id, NULL);
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list, &id, NULL);
@@ -1906,7 +1940,7 @@ void silc_server_channel_message(SilcServer server,
                                        packet->dst_id_len,
                                        packet->dst_id_type);
       if (!idp)
-       return;
+       goto out;
 
       error = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
       if (packet->src_id_type == SILC_ID_CLIENT) {
@@ -1924,7 +1958,7 @@ void silc_server_channel_message(SilcServer server,
       }
 
       silc_buffer_free(idp);
-      return;
+      goto out;
     }
   }
 
@@ -1932,7 +1966,7 @@ void silc_server_channel_message(SilcServer server,
      not client (as it can be server as well) we don't do the check. */
   if (!silc_id_str2id2(packet->src_id, packet->src_id_len,
                       packet->src_id_type, &sid))
-    return;
+    goto out;
   if (sid.type == SILC_ID_CLIENT) {
     sender_entry = silc_idlist_find_client_by_id(server->local_list,
                                                 SILC_ID_GET_ID(sid),
@@ -1946,7 +1980,7 @@ void silc_server_channel_message(SilcServer server,
     if (!sender_entry || !silc_server_client_on_channel(sender_entry,
                                                        channel, &chl)) {
       SILC_LOG_DEBUG(("Client not on channel"));
-      return;
+      goto out;
     }
 
     /* If channel is moderated check that client is allowed to send
@@ -1955,17 +1989,17 @@ void silc_server_channel_message(SilcServer server,
        !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
        !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
       SILC_LOG_DEBUG(("Channel is silenced from normal users"));
-      return;
+      goto out;
     }
     if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
        chl->mode & SILC_CHANNEL_UMODE_CHANOP &&
        !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
       SILC_LOG_DEBUG(("Channel is silenced from operators"));
-      return;
+      goto out;
     }
     if (chl->mode & SILC_CHANNEL_UMODE_QUIET) {
       SILC_LOG_DEBUG(("Sender is quieted on the channel"));
-      return;
+      goto out;
     }
 
     /* If the packet is coming from router, but the client entry is local
@@ -1976,16 +2010,19 @@ void silc_server_channel_message(SilcServer server,
     if (server->server_type == SILC_ROUTER &&
        idata->conn_type == SILC_CONN_ROUTER && local) {
       SILC_LOG_DEBUG(("Channel message rerouted to the sender, drop it"));
-      return;
+      goto out;
     }
   }
 
   /* Distribute the packet to our local clients. This will send the
      packet for further routing as well, if needed. */
-  silc_server_packet_relay_to_channel(server, sock, channel, sender_id,
-                                     packet->src_id_type, sender_entry,
-                                     packet->buffer.data,
+  silc_server_packet_relay_to_channel(server, sock, channel,
+                                     SILC_ID_GET_ID(sid), sid.type,
+                                     sender_entry, packet->buffer.data,
                                      silc_buffer_len(&packet->buffer));
+
+ out:
+  silc_packet_free(packet);
 }
 
 /* Received channel key packet. We distribute the key to all of our locally
@@ -2001,13 +2038,16 @@ void silc_server_channel_key(SilcServer server,
 
   if (packet->src_id_type != SILC_ID_SERVER ||
       (server->server_type == SILC_ROUTER && !server->backup_router &&
-       idata->conn_type == SILC_CONN_ROUTER))
+       idata->conn_type == SILC_CONN_ROUTER)) {
+    silc_packet_free(packet);
     return;
+  }
 
   /* Save the channel key */
   channel = silc_server_save_channel_key(server, buffer, NULL);
   if (!channel) {
     SILC_LOG_ERROR(("Bad channel key from %s", idata->sconn->remote_host));
+    silc_packet_free(packet);
     return;
   }
 
@@ -2015,13 +2055,14 @@ void silc_server_channel_key(SilcServer server,
      we will also send it to locally connected servers. */
   silc_server_send_channel_key(server, sock, channel, FALSE);
 
-  if (server->server_type != SILC_BACKUP_ROUTER) {
+  if (server->server_type != SILC_BACKUP_ROUTER)
     /* Distribute to local cell backup routers. */
     silc_server_backup_send(server, (SilcServerEntry)idata,
                            SILC_PACKET_CHANNEL_KEY, 0,
                            buffer->data, silc_buffer_len(buffer),
                            FALSE, TRUE);
-  }
+
+  silc_packet_free(packet);
 }
 
 /* Received New Client packet and processes it.  Creates Client ID for the
@@ -2036,42 +2077,35 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   SilcClientEntry client;
   SilcClientID *client_id;
   char *username = NULL, *realname = NULL;
-  SilcUInt16 username_len;
+  SilcUInt16 username_len, nickname_len;
   SilcUInt32 id_len, tmp_len;
   int ret;
-  char *host, *nickname, *nicknamec;
+  char *host, *nickname = NULL, *nicknamec;
   const char *hostname, *ip;
 
   SILC_LOG_DEBUG(("Creating new client"));
 
-  if (idata->conn_type != SILC_CONN_CLIENT)
+  if (idata->conn_type != SILC_CONN_CLIENT) {
+    silc_packet_free(packet);
     return NULL;
+  }
 
   /* Take client entry */
   client = (SilcClientEntry)idata;
-  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+                             NULL, &hostname, &ip, NULL);
 
-  /* Remove the old cache entry. */
-  if (!silc_idcache_del_by_context(server->local_list->clients, client,
-                                  NULL)) {
-    SILC_LOG_INFO(("Unauthenticated client attempted to register to network"));
-    silc_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
-    silc_server_free_sock_user_data(server, sock, NULL);
-    return NULL;
-  }
+  SILC_LOG_DEBUG(("%s %s", ip, hostname));
 
   /* Make sure this client hasn't registered already */
   if (idata->status & SILC_IDLIST_STATUS_REGISTERED) {
-    silc_server_disconnect_remote(server, sock,
-                                 SILC_STATUS_ERR_OPERATION_ALLOWED,
-                                 "Too many registrations");
-    silc_server_free_sock_user_data(server, sock, NULL);
+    silc_packet_free(packet);
     return NULL;
   }
 
   /* Parse incoming packet */
   ret = silc_buffer_unformat(buffer,
+                            SILC_STR_ADVANCE,
                             SILC_STR_UI16_NSTRING_ALLOC(&username,
                                                         &username_len),
                             SILC_STR_UI16_STRING_ALLOC(&realname),
@@ -2085,6 +2119,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
     silc_server_free_sock_user_data(server, sock, NULL);
+    silc_packet_free(packet);
     return NULL;
   }
 
@@ -2097,32 +2132,49 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
     silc_server_free_sock_user_data(server, sock, NULL);
+    silc_packet_free(packet);
     return NULL;
   }
 
   if (username_len > 128) {
-    username[128] = '\0';
     username_len = 128;
+    username[username_len - 1] = '\0';
+  }
+
+  /* Take nickname from NEW_CLIENT packet, if present */
+  if (silc_buffer_unformat(buffer,
+                          SILC_STR_UI16_NSTRING_ALLOC(&nickname,
+                                                      &nickname_len),
+                          SILC_STR_END)) {
+    if (nickname_len > 128) {
+      nickname_len = 128;
+      nickname[nickname_len - 1] = '\0';
+    }
+  }
+
+  /* Nickname is initially same as username, if not present in NEW_CLIENT */
+  if (!nickname) {
+    nickname = strdup(username);
+    nickname_len = strlen(nickname);
   }
 
   /* Check for valid username string */
-  nicknamec = silc_identifier_check(username, username_len,
+  nicknamec = silc_identifier_check(nickname, nickname_len,
                                    SILC_STRING_UTF8, 128, &tmp_len);
   if (!nicknamec) {
     silc_free(username);
     silc_free(realname);
+    silc_free(nickname);
     SILC_LOG_ERROR(("Client %s (%s) sent bad username string '%s', closing "
                    "connection", hostname, ip, username));
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
     silc_server_free_sock_user_data(server, sock, NULL);
+    silc_packet_free(packet);
     return NULL;
   }
 
-  /* Nickname is initially same as username */
-  nickname = strdup(username);
-
   /* Make sanity checks for the hostname of the client. If the hostname
      is provided in the `username' check that it is the same than the
      resolved hostname, or if not resolved the hostname that appears in
@@ -2136,6 +2188,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     host = silc_memdup(username + tlen + 1, strlen(username) - tlen - 1);
 
     if (strcmp(hostname, ip) && strcmp(hostname, host)) {
+      silc_free(nickname);
       silc_free(username);
       silc_free(host);
       silc_free(realname);
@@ -2145,6 +2198,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    NULL);
       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_packet_free(packet);
       return NULL;
     }
 
@@ -2152,6 +2206,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                                        client->data.public_key);
     phostname = strdup(silc_pubkey->identifier.host);
     if (!strcmp(hostname, ip) && phostname && strcmp(phostname, host)) {
+      silc_free(nickname);
       silc_free(username);
       silc_free(host);
       silc_free(phostname);
@@ -2162,6 +2217,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    NULL);
       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_packet_free(packet);
       return NULL;
     }
 
@@ -2178,6 +2234,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     username = newusername;
   }
 
+  SILC_LOG_DEBUG(("%s %s", ip, hostname));
+
   /* Create Client ID */
   if (!silc_id_create_client_id(server, server->id, server->rng,
                                server->md5hash, nicknamec,
@@ -2185,6 +2243,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_BAD_NICKNAME, NULL);
     silc_server_free_sock_user_data(server, sock, NULL);
+    silc_packet_free(packet);
     return NULL;
   }
 
@@ -2214,10 +2273,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   client->userinfo = realname ? realname : strdup(username);
   client->id = client_id;
   id_len = silc_id_get_len(client_id, SILC_ID_CLIENT);
-
-  /* Add the client again to the ID cache */
-  silc_idcache_add(server->local_list->clients, nicknamec,
-                  client_id, client);
+  silc_idcache_update_by_context(server->local_list->clients, client,
+                                client_id, nicknamec, TRUE);
 
   /* Notify our router about new client on the SILC network */
   silc_server_send_new_id(server, SILC_PRIMARY_ROUTE(server),
@@ -2243,6 +2300,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   if (server->server_type == SILC_ROUTER)
     silc_server_check_watcher_list(server, client, NULL, 0);
 
+  silc_packet_free(packet);
   return client;
 }
 
@@ -2271,12 +2329,15 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   SILC_LOG_DEBUG(("Creating new server"));
 
   if (idata->conn_type != SILC_CONN_SERVER &&
-      idata->conn_type != SILC_CONN_ROUTER)
+      idata->conn_type != SILC_CONN_ROUTER) {
+    silc_packet_free(packet);
     return NULL;
+  }
 
   /* Take server entry */
   new_server = (SilcServerEntry)idata;
-  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+                             NULL, &hostname, &ip, NULL);
 
   /* Statistics */
   if (server->server_type == SILC_ROUTER)
@@ -2530,7 +2591,8 @@ static void silc_server_new_id_real(SilcServer server,
 
   id_type = silc_id_payload_get_type(idp);
 
-  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+                             NULL, &hostname, &ip, NULL);
 
   /* Normal server cannot have other normal server connections */
   server_entry = (SilcServerEntry)idata;
@@ -2600,7 +2662,8 @@ static void silc_server_new_id_real(SilcServer server,
         global list. Cell wide information however is kept in the local
         list. */
       entry = silc_idlist_add_client(id_list, NULL, NULL, NULL,
-                                    &id, router, NULL);
+                                    silc_id_dup(&id, SILC_ID_CLIENT),
+                                    router, NULL);
       if (!entry) {
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
 
@@ -2620,19 +2683,20 @@ static void silc_server_new_id_real(SilcServer server,
        silc_server_check_watcher_list(server, entry, NULL, 0);
 
       if (server->server_type == SILC_ROUTER) {
-       /* Add the client's public key to hash table or get the key with
+       /* Add the client's public key to repository or get the key with
           GETKEY command. */
         if (entry->data.public_key) {
-         if (!silc_hash_table_find_by_context(server->pk_hash,
-                                              entry->data.public_key,
-                                              entry, NULL))
-           silc_hash_table_add(server->pk_hash, entry->data.public_key,
-                               entry);
-       } else
+         if (!silc_server_get_public_key_by_client(server, entry, NULL))
+           silc_skr_add_public_key_simple(server->repository,
+                                          entry->data.public_key,
+                                          SILC_SKR_USAGE_IDENTIFICATION,
+                                          entry, NULL);
+       } else {
          silc_server_send_command(server, router_sock,
                                   SILC_COMMAND_GETKEY, ++server->cmd_ident,
                                   1, 1, buffer->data,
                                   silc_buffer_len(buffer));
+       }
       }
     }
     break;
@@ -2678,7 +2742,8 @@ static void silc_server_new_id_real(SilcServer server,
       /* As a router we keep information of all global information in our
         global list. Cell wide information however is kept in the local
         list. */
-      entry = silc_idlist_add_server(id_list, NULL, 0, &id, router,
+      entry = silc_idlist_add_server(id_list, NULL, 0,
+                                    silc_id_dup(&id, SILC_ID_SERVER), router,
                                     router_sock);
       if (!entry) {
        SILC_LOG_ERROR(("Could not add new server to the ID Cache"));
@@ -2731,6 +2796,7 @@ void silc_server_new_id(SilcServer server, SilcPacketStream sock,
                        SilcPacket packet)
 {
   silc_server_new_id_real(server, sock, packet, &packet->buffer, TRUE);
+  silc_packet_free(packet);
 }
 
 /* Receoved New Id List packet, list of New ID payloads inside one
@@ -2746,8 +2812,10 @@ void silc_server_new_id_list(SilcServer server, SilcPacketStream sock,
   SILC_LOG_DEBUG(("Processing New ID List"));
 
   if (idata->conn_type == SILC_CONN_CLIENT ||
-      packet->src_id_type != SILC_ID_SERVER)
+      packet->src_id_type != SILC_ID_SERVER) {
+    silc_packet_free(packet);
     return;
+  }
 
   /* If the sender of this packet is server and we are router we need to
      broadcast this packet to other routers in the network. Broadcast
@@ -2769,8 +2837,10 @@ void silc_server_new_id_list(SilcServer server, SilcPacketStream sock,
   }
 
   idp = silc_buffer_alloc(256);
-  if (!idp)
+  if (!idp) {
+    silc_packet_free(packet);
     return;
+  }
 
   while (silc_buffer_len(&packet->buffer)) {
     SILC_GET16_MSB(id_len, packet->buffer.data + 2);
@@ -2789,6 +2859,7 @@ void silc_server_new_id_list(SilcServer server, SilcPacketStream sock,
   }
 
   silc_buffer_free(idp);
+  silc_packet_free(packet);
 }
 
 /* Received New Channel packet. Information about new channels in the
@@ -2914,9 +2985,12 @@ static void silc_server_new_channel_process(SilcServer server,
       }
 
       /* Create the channel with the provided Channel ID */
-      channel = silc_server_create_new_channel_with_id(server, NULL, NULL,
-                                                      channel_name,
-                                                      &channel_id, FALSE);
+      channel =
+       silc_server_create_new_channel_with_id(
+                                    server, NULL, NULL,
+                                    channel_name,
+                                    silc_id_dup(&channel_id, SILC_ID_CHANNEL),
+                                    FALSE);
       if (!channel) {
        silc_channel_payload_free(payload);
        return;
@@ -3079,6 +3153,7 @@ void silc_server_new_channel(SilcServer server,
                             SilcPacket packet)
 {
   silc_server_new_channel_process(server, sock, packet, &packet->buffer);
+  silc_packet_free(packet);
 }
 
 /* Received New Channel List packet, list of New Channel List payloads inside
@@ -3096,12 +3171,16 @@ void silc_server_new_channel_list(SilcServer server,
 
   if (idata->conn_type == SILC_CONN_CLIENT ||
       packet->src_id_type != SILC_ID_SERVER ||
-      server->server_type == SILC_SERVER)
+      server->server_type == SILC_SERVER) {
+    silc_packet_free(packet);
     return;
+  }
 
   buffer = silc_buffer_alloc(512);
-  if (!buffer)
+  if (!buffer) {
+    silc_packet_free(packet);
     return;
+  }
 
   while (silc_buffer_len(&packet->buffer)) {
     SILC_GET16_MSB(len1, packet->buffer.data);
@@ -3125,6 +3204,7 @@ void silc_server_new_channel_list(SilcServer server,
   }
 
   silc_buffer_free(buffer);
+  silc_packet_free(packet);
 }
 
 /* Received key agreement packet. This packet is never for us. It is to
@@ -3142,21 +3222,23 @@ void silc_server_key_agreement(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   if (packet->src_id_type != SILC_ID_CLIENT ||
-      packet->dst_id_type != SILC_ID_CLIENT)
-    return;
-
-  if (!packet->dst_id)
+      packet->dst_id_type != SILC_ID_CLIENT || !packet->dst_id) {
+    silc_packet_free(packet);
     return;
+  }
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
                                          packet->dst_id_len, NULL,
                                          &idata, NULL);
-  if (!dst_sock)
+  if (!dst_sock) {
+    silc_packet_free(packet);
     return;
+  }
 
   /* Relay the packet */
   silc_server_packet_route(server, dst_sock, packet);
+  silc_packet_free(packet);
 }
 
 /* Received connection auth request packet that is used during connection
@@ -3179,21 +3261,22 @@ void silc_server_connection_auth_request(SilcServer server,
 
   if (packet->src_id_type && packet->src_id_type != SILC_ID_CLIENT) {
     SILC_LOG_DEBUG(("Request not from client"));
+    silc_packet_free(packet);
     return;
   }
 
-  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+                             NULL, &hostname, &ip, NULL);
 
   /* Parse the payload */
   ret = silc_buffer_unformat(&packet->buffer,
                             SILC_STR_UI_SHORT(&conn_type),
                             SILC_STR_UI_SHORT(NULL),
                             SILC_STR_END);
-  if (ret == -1)
-    return;
-
-  if (conn_type != SILC_CONN_CLIENT)
+  if (ret == -1 || conn_type != SILC_CONN_CLIENT) {
+    silc_packet_free(packet);
     return;
+  }
 
   /* Get the authentication method for the client */
   auth_meth = SILC_AUTH_NONE;
@@ -3217,6 +3300,7 @@ void silc_server_connection_auth_request(SilcServer server,
 
   /* Send it back to the client */
   silc_server_send_connection_auth_request(server, sock, conn_type, auth_meth);
+  silc_packet_free(packet);
 }
 
 /* Received file transger packet. This packet is never for us. It is to
@@ -3234,21 +3318,23 @@ void silc_server_ftp(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   if (packet->src_id_type != SILC_ID_CLIENT ||
-      packet->dst_id_type != SILC_ID_CLIENT)
-    return;
-
-  if (!packet->dst_id)
+      packet->dst_id_type != SILC_ID_CLIENT || !packet->dst_id) {
+    silc_packet_free(packet);
     return;
+  }
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
                                          packet->dst_id_len, NULL,
                                          &idata, NULL);
-  if (!dst_sock)
+  if (!dst_sock) {
+    silc_packet_free(packet);
     return;
+  }
 
   /* Relay the packet */
   silc_server_packet_route(server, dst_sock, packet);
+  silc_packet_free(packet);
 }
 
 typedef struct {
@@ -3269,7 +3355,8 @@ SILC_SERVER_CMD_FUNC(resume_resolve)
 
   SILC_LOG_DEBUG(("Start"));
 
-  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+                             NULL, &hostname, &ip, NULL);
 
   if (!reply || !silc_command_get_status(reply->payload, NULL, NULL)) {
     SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
@@ -3343,9 +3430,11 @@ void silc_server_resume_client(SilcServer server,
   SilcHashTableList htl;
   SilcChannelClientEntry chl;
   SilcServerResumeResolve r;
+  SilcPublicKey public_key;
   const char *cipher, *hostname, *ip;
 
-  silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL);
+  silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+                             NULL, &hostname, &ip, NULL);
 
   if (silc_buffer_unformat(buffer,
                           SILC_STR_UI16_NSTRING(&id_string, &id_len),
@@ -3588,21 +3677,34 @@ void silc_server_resume_client(SilcServer server,
     silc_packet_set_context(sock, detached_client);
     detached_client->connection = sock;
 
-    if (detached_client->data.public_key)
-      silc_hash_table_del_by_context(server->pk_hash,
-                                    detached_client->data.public_key,
-                                    detached_client);
-    if (idata->public_key)
-      silc_hash_table_del_by_context(server->pk_hash,
-                                    idata->public_key, idata);
+    if (detached_client->data.public_key) {
+      /* Delete the detached client's public key from repository */
+      silc_skr_del_public_key(server->repository,
+                             detached_client->data.public_key,
+                             detached_client);
+      detached_client->data.public_key = NULL;
+    }
+
+    if (idata->public_key) {
+      /* Delete the resuming client's public key from repository.  It will
+        be added later again. */
+      public_key = silc_pkcs_public_key_copy(idata->public_key);
+      silc_skr_del_public_key(server->repository, idata->public_key, idata);
+      idata->public_key = public_key;
+    }
 
     /* Take new keys and stuff into use in the old entry */
     silc_idlist_del_data(detached_client);
     silc_idlist_add_data(detached_client, idata);
 
-    if (detached_client->data.public_key)
-      silc_hash_table_add(server->pk_hash,
-                         detached_client->data.public_key, detached_client);
+    if (detached_client->data.public_key) {
+      /* Add the resumed client's public key back to repository. */
+      if (!silc_server_get_public_key_by_client(server, detached_client, NULL))
+       silc_skr_add_public_key_simple(server->repository,
+                                      detached_client->data.public_key,
+                                      SILC_SKR_USAGE_IDENTIFICATION,
+                                      detached_client, NULL);
+    }
 
     detached_client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED;
@@ -3830,15 +3932,19 @@ void silc_server_resume_client(SilcServer server,
     /* Client is detached, and now it is resumed.  Remove the detached
        mode and mark that it is resumed. */
 
-    if (detached_client->data.public_key)
-      silc_hash_table_del_by_context(server->pk_hash,
-                                    detached_client->data.public_key,
-                                    detached_client);
+    if (detached_client->data.public_key) {
+      /* Delete the detached client's public key from repository */
+      silc_skr_del_public_key(server->repository,
+                             detached_client->data.public_key,
+                             detached_client);
+      detached_client->data.public_key = NULL;
+    }
 
     silc_idlist_del_data(detached_client);
     detached_client->mode &= ~SILC_UMODE_DETACHED;
     detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED;
     detached_client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
+    silc_dlist_del(server->expired_clients, detached_client);
 
     /* Check if anyone is watching this client */
     if (server->server_type == SILC_ROUTER)