Merge commit 'origin/silc.1.1.branch'
[silc.git] / apps / silcd / packet_receive.c
index c6ec4501980cc43f3b725f9b72b6bc7777343d44..73424a68988fe7b2016030d9c8de39bb8f33b7a9 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,9 @@ static void silc_server_notify_process(SilcServer server,
     client->mode = 0;
     client->router = NULL;
     client->connection = NULL;
+    client->data.created = silc_time();
+    silc_dlist_del(server->expired_clients, client);
+    silc_dlist_add(server->expired_clients, client);
     break;
 
   case SILC_NOTIFY_TYPE_TOPIC_SET:
@@ -380,7 +402,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 +523,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 +844,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 +1032,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 +1102,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 +1232,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,13 +1264,8 @@ 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_dlist_del(server->expired_clients, client);
            silc_idlist_del_data(client);
            silc_idlist_del_client(local ? server->local_list :
                                   server->global_list, client);
@@ -1307,7 +1329,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 +1482,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 +1507,9 @@ static void silc_server_notify_process(SilcServer server,
       client->mode = 0;
       client->router = NULL;
       client->connection = NULL;
+      client->data.created = silc_time();
+      silc_dlist_del(server->expired_clients, client);
+      silc_dlist_add(server->expired_clients, client);
       break;
     }
 
@@ -1565,7 +1592,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,13 +1667,9 @@ 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_dlist_del(server->expired_clients, client);
        silc_idlist_del_data(client);
        silc_idlist_del_client(server->global_list, client);
       }
@@ -1658,6 +1682,7 @@ static void silc_server_notify_process(SilcServer server,
     break;
 
   default:
+    SILC_LOG_DEBUG(("Unsupported notify %d", type));
     break;
   }
 
@@ -1891,7 +1916,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;
@@ -1998,9 +2022,9 @@ void silc_server_channel_message(SilcServer server,
 
   /* 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:
@@ -2123,12 +2147,30 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     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) >= 0) {
+    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,
@@ -2139,21 +2181,6 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     return NULL;
   }
 
-  /* 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);
-
   /* 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
@@ -2167,6 +2194,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);
@@ -2184,6 +2212,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);
@@ -2639,7 +2668,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"));
 
@@ -2659,19 +2689,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;
@@ -2717,7 +2748,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"));
@@ -2959,9 +2991,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;
@@ -3401,8 +3436,11 @@ void silc_server_resume_client(SilcServer server,
   SilcHashTableList htl;
   SilcChannelClientEntry chl;
   SilcServerResumeResolve r;
+  SilcPublicKey public_key;
   const char *cipher, *hostname, *ip;
 
+  SILC_LOG_DEBUG(("Resuming client"));
+
   silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
                              NULL, &hostname, &ip, NULL);
 
@@ -3647,21 +3685,35 @@ 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);
+    idata->public_key = NULL;
 
-    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;
@@ -3669,6 +3721,7 @@ void silc_server_resume_client(SilcServer server,
     detached_client->data.status &= ~SILC_IDLIST_STATUS_RESUME_RES;
     detached_client->mode &= ~SILC_UMODE_DETACHED;
     server->stat.my_detached--;
+    silc_dlist_del(server->expired_clients, detached_client);
 
     /* We are finished - reset resuming client */
     detached_client->resuming_client = NULL;
@@ -3686,6 +3739,7 @@ void silc_server_resume_client(SilcServer server,
     silc_server_remove_from_channels(server, NULL, client, FALSE,
                                     NULL, FALSE, FALSE);
     silc_server_del_from_watcher_list(server, client);
+    silc_dlist_del(server->expired_clients, client);
     if (!silc_idlist_del_client(server->local_list, client))
       silc_idlist_del_client(server->global_list, client);
     client = detached_client;
@@ -3764,14 +3818,17 @@ void silc_server_resume_client(SilcServer server,
       silc_buffer_free(nidp);
     }
 
-    /* Add the client again to the ID cache to get it to correct list */
-    if (!silc_idcache_del_by_context(server->local_list->clients, client,
-                                    NULL))
-      silc_idcache_del_by_context(server->global_list->clients, client, NULL);
-    silc_free(client->id);
-    *client->id = client_id;
-    silc_idcache_add(server->local_list->clients, nicknamec,
-                    client->id, client);
+    /* Update entry */
+    if (!silc_idcache_update_by_context(server->local_list->clients, client,
+                                       &client_id, NULL, FALSE))
+      silc_idcache_update_by_context(server->global_list->clients, client,
+                                    &client_id, NULL, FALSE);
+
+    /* Move entry to local list if it is in global list */
+    if (silc_idcache_find_by_context(server->global_list->clients, client,
+                                    &id_cache))
+      silc_idcache_move(server->global_list->clients,
+                       server->local_list->clients, id_cache);
 
     /* Send some nice info to the client */
     silc_server_send_connect_notifys(server, sock, client);
@@ -3889,15 +3946,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)
@@ -3928,15 +3989,18 @@ void silc_server_resume_client(SilcServer server,
        server_entry->server_type == SILC_ROUTER)
       local = FALSE;
 
-    /* Change the client to correct list. */
-    if (!silc_idcache_del_by_context(server->local_list->clients,
-                                    detached_client, NULL))
-      silc_idcache_del_by_context(server->global_list->clients,
-                                 detached_client, NULL);
-    silc_idcache_add(local && server->server_type == SILC_ROUTER ?
-                    server->local_list->clients :
-                    server->global_list->clients, nicknamec,
-                    detached_client->id, detached_client);
+    /* Move entry to correct list */
+    if (local && server->server_type == SILC_ROUTER) {
+      if (silc_idcache_find_by_context(server->global_list->clients,
+                                      detached_client, &id_cache))
+       silc_idcache_move(server->global_list->clients,
+                         server->local_list->clients, id_cache);
+    } else {
+      if (silc_idcache_find_by_context(server->local_list->clients,
+                                      detached_client, &id_cache))
+       silc_idcache_move(server->local_list->clients,
+                         server->global_list->clients, id_cache);
+    }
 
     /* Change the owner of the client */
     detached_client->router = server_entry;