updates.
[silc.git] / apps / silcd / packet_receive.c
index 42085c6f54386e543886cd501b15246d3b1cf374..d124a91c68012b12a34fecf04572fcba09dbb97d 100644 (file)
@@ -1367,6 +1367,42 @@ void silc_server_notify(SilcServer server,
     }
     break;
 
+  case SILC_NOTIFY_TYPE_ERROR:
+    {
+      /*
+       * Error notify
+       */
+      SilcStatus error;
+
+      tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+      if (!tmp && tmp_len != 1)
+       goto out;
+      error = (SilcStatus)tmp[0];
+
+      SILC_LOG_DEBUG(("ERROR notify (%d)", error));
+
+      if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
+         sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+       if (tmp) {
+         SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
+                         "the entry from cache"));
+         client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+         if (!client_id)
+           goto out;
+         client = silc_idlist_find_client_by_id(server->global_list, 
+                                                client_id, FALSE, NULL);
+         if (client) {
+           silc_server_remove_from_channels(server, NULL, client, TRUE, 
+                                            NULL, TRUE);
+           silc_idlist_del_client(server->global_list, client);
+         }
+         silc_free(client_id);
+       }
+      }
+    }
+    break;
+
     /* Ignore rest of the notify types for now */
   case SILC_NOTIFY_TYPE_NONE:
   case SILC_NOTIFY_TYPE_MOTD:
@@ -1458,34 +1494,37 @@ void silc_server_private_message(SilcServer server,
                                          &idata, &client);
   if (!dst_sock) {
     SilcBuffer idp;
+    unsigned char error;
 
     if (client && client->mode & SILC_UMODE_DETACHED) {
       SILC_LOG_DEBUG(("Client is detached, discarding packet"));
       return;
     }
 
-    /* Send IDENTIFY command reply with error status to indicate that
-       such destination ID does not exist or is invalid */
+    /* Send SILC_NOTIFY_TYPE_ERROR to indicate that such destination ID
+       does not exist or is invalid. */
     idp = silc_id_payload_encode_data(packet->dst_id,
                                      packet->dst_id_len,
                                      packet->dst_id_type);
     if (!idp)
       return;
 
+    error = SILC_STATUS_ERR_NO_SUCH_CLIENT_ID;
     if (packet->src_id_type == SILC_ID_CLIENT) {
       SilcClientID *client_id = silc_id_str2id(packet->src_id,
                                               packet->src_id_len,
                                               packet->src_id_type);
-      silc_server_send_dest_command_reply(server, sock, 
-                                         client_id, SILC_ID_CLIENT,
-                                         SILC_COMMAND_IDENTIFY,
-                                         SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 
-                                         0, 0, 1, 2, idp->data, idp->len);
+      silc_server_send_notify_dest(server, sock, FALSE,
+                                  client_id, SILC_ID_CLIENT,
+                                  SILC_NOTIFY_TYPE_ERROR, 2,
+                                  &error, 1,
+                                  idp->data, idp->len);
       silc_free(client_id);
     } else {
-      silc_server_send_command_reply(server, sock, SILC_COMMAND_IDENTIFY,
-                                    SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
-                                    0, 1, 2, idp->data, idp->len);
+      silc_server_send_notify(server, sock, FALSE,
+                             SILC_NOTIFY_TYPE_ERROR, 2,
+                             &error, 1,
+                             idp->data, idp->len);
     }
 
     silc_buffer_free(idp);
@@ -2971,14 +3010,16 @@ void silc_server_resume_client(SilcServer server,
        silc_server_command_pending(server, SILC_COMMAND_WHOIS,
                                    server->cmd_ident,
                                    silc_server_command_resume_resolve, r);
-      } else {
+       return;
+      }
+      if (server->server_type == SILC_SERVER) {
        SILC_LOG_ERROR(("Client %s (%s) tried to resume un-detached client, "
                        "closing connection", sock->hostname, sock->ip));
        silc_server_disconnect_remote(server, sock, 
                                      "Server closed connection: "
                                      "Incomplete resume information");
+       return;
       }
-      return;
     }
 
     /* Check that we have the public key of the client, if not then we must
@@ -3016,6 +3057,14 @@ void silc_server_resume_client(SilcServer server,
        silc_buffer_free(idp);
       }
       return;
+    } else if (!silc_pkcs_public_key_compare(detached_client->data.public_key,
+                                            idata->public_key)) {
+      /* We require that the connection and resuming authentication data
+        must be using same key pair. */
+      silc_server_disconnect_remote(server, sock, 
+                                   "Server closed connection: "
+                                   "Incomplete resume information");
+      return;
     }
 
     /* Verify the authentication payload.  This has to be successful in
@@ -3033,6 +3082,7 @@ void silc_server_resume_client(SilcServer server,
 
     /* Now resume the client to the network */
 
+    silc_schedule_task_del_by_context(server->schedule, detached_client);
     sock->user_data = detached_client;
     detached_client->connection = sock;
 
@@ -3059,7 +3109,8 @@ void silc_server_resume_client(SilcServer server,
 
     /* As router we must deliver this packet directly to the original
        server whom this client was earlier. */
-    if (server->server_type == SILC_ROUTER && detached_client->router)
+    if (server->server_type == SILC_ROUTER && detached_client->router &&
+       detached_client->router->server_type != SILC_ROUTER)
       silc_server_packet_send(server, detached_client->router->connection,
                              SILC_PACKET_RESUME_CLIENT, 0, 
                              buf->data, buf->len, TRUE);
@@ -3253,6 +3304,11 @@ void silc_server_resume_client(SilcServer server,
       }
     }
 
+    if (server->server_type == SILC_ROUTER &&
+       sock->type == SILC_SOCKET_TYPE_ROUTER && 
+       server_entry->server_type == SILC_ROUTER)
+      local = FALSE;
+
     SILC_LOG_DEBUG(("Resuming detached client"));
 
     /* Change the client to correct list. */
@@ -3279,6 +3335,8 @@ void silc_server_resume_client(SilcServer server,
       silc_hash_table_list_reset(&htl);
     }
 
+    silc_schedule_task_del_by_context(server->schedule, detached_client);
+
     /* If the sender of this packet is server and we are router we need to
        broadcast this packet to other routers in the network. */
     if (!server->standalone && server->server_type == SILC_ROUTER &&