Merged from silc_1_0_branch.
[silc.git] / apps / silcd / packet_receive.c
index fbb5a9d0badb8c9c2740340781030b1223050572..e49fafb59e7fb9a6d34595eff5748831a191b5a3 100644 (file)
@@ -362,7 +362,8 @@ void silc_server_notify(SilcServer server,
     silc_schedule_task_del_by_context(server->schedule, client);
 
     /* Remove the client from all channels. */
-    silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, FALSE);
+    silc_server_remove_from_channels(server, NULL, client, TRUE,
+                                    tmp, FALSE, FALSE);
 
     /* Check if anyone is watching this nickname */
     if (server->server_type == SILC_ROUTER)
@@ -1076,7 +1077,7 @@ void silc_server_notify(SilcServer server,
 
       /* Get invite list */
       tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
-      if (!tmp)
+      if (!tmp || tmp_len < 2)
        goto out;
 
       /* Parse the arguments to see they are constructed correctly */
@@ -1086,9 +1087,10 @@ void silc_server_notify(SilcServer server,
        goto out;
 
       if (action == 0 && !channel->invite_list)
-       channel->invite_list = silc_hash_table_alloc(0, silc_hash_ptr,
-                                                    NULL, NULL, NULL,
-                                                    NULL, NULL, TRUE);
+       channel->invite_list =
+         silc_hash_table_alloc(0, silc_hash_ptr,
+                               NULL, NULL, NULL,
+                               silc_server_inviteban_destruct, channel, TRUE);
 
       /* Proces the invite action */
       silc_server_inviteban_process(server, channel->invite_list, action,
@@ -1280,7 +1282,7 @@ void silc_server_notify(SilcServer server,
 
            /* Remove the client from all channels. */
            silc_server_remove_from_channels(server, NULL, client, 
-                                            TRUE, NULL, FALSE);
+                                            TRUE, NULL, FALSE, FALSE);
 
            /* Check if anyone is watching this nickname */
            if (server->server_type == SILC_ROUTER)
@@ -1304,9 +1306,22 @@ void silc_server_notify(SilcServer server,
     }
     silc_free(server_id);
 
-    /* Sending SERVER_SIGNOFF is not right way to signoff local connection */
-    if (SILC_IS_LOCAL(server_entry))
+    /* For local entrys SERVER_SIGNOFF is processed only on backup router.
+       It is possible that router sends server signoff for a server.  If
+       backup router has it as local connection it will be closed. */
+    if (SILC_IS_LOCAL(server_entry)) {
+      if (server->server_type == SILC_BACKUP_ROUTER) {
+       sock = server_entry->connection;
+       SILC_LOG_DEBUG(("Closing connection %s after SERVER_SIGNOFF",
+                      sock->hostname));
+       SILC_SET_DISCONNECTING(sock);
+       if (sock->user_data)
+         silc_server_free_sock_user_data(server, sock, NULL);
+       silc_server_close_connection(server, sock);
+      }
+
       break;
+    }
 
     /* Remove all servers that are originated from this server, and
        remove the clients of those servers too. */
@@ -1383,41 +1398,53 @@ void silc_server_notify(SilcServer server,
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO)
       goto out;
     
-    /* From protocol version 1.1 we get the kicker's ID as well. */
+    /* Get the kicker's Client ID */
     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
-    if (tmp) {
-      client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-      if (!client_id)
-       goto out;
+    if (!tmp)
+      goto out;
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+    if (!client_id)
+      goto out;
 
-      /* If the the client is not in local list we check global list */
-      client2 = silc_idlist_find_client_by_id(server->global_list, 
+    /* If the the client is not in local list we check global list */
+    client2 = silc_idlist_find_client_by_id(server->global_list, 
+                                           client_id, TRUE, NULL);
+    if (!client2) {
+      client2 = silc_idlist_find_client_by_id(server->local_list, 
                                              client_id, TRUE, NULL);
       if (!client2) {
-       client2 = silc_idlist_find_client_by_id(server->local_list, 
-                                               client_id, TRUE, NULL);
-       if (!client2) {
-         silc_free(client_id);
-         goto out;
-       }
-      }
-      silc_free(client_id);
-
-      /* Kicker must be operator on channel */
-      if (!silc_server_client_on_channel(client2, channel, &chl))
-       goto out;
-      if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
-         !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
-       SILC_LOG_DEBUG(("Kicking is not allowed"));
+       silc_free(client_id);
        goto out;
       }
     }
+    silc_free(client_id);
+
+    /* Kicker must be operator on channel */
+    if (!silc_server_client_on_channel(client2, channel, &chl))
+      goto out;
+    if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+      SILC_LOG_DEBUG(("Kicking is not allowed"));
+      goto out;
+    }
 
     /* Send to channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
                                       FALSE, packet->buffer->data, 
                                       packet->buffer->len, FALSE);
 
+    /* Remove the client from channel's invite list */
+    if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
+      SilcBuffer ab;
+      SilcArgumentPayload iargs;
+      tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+      ab = silc_argument_payload_encode_one(NULL, tmp, tmp_len, 3);
+      iargs = silc_argument_payload_parse(ab->data, ab->len, 1);
+      silc_server_inviteban_process(server, channel->invite_list, 1, iargs);
+      silc_buffer_free(ab);
+      silc_argument_payload_free(iargs);
+    }
+
     /* Remove the client from channel */
     silc_server_remove_from_one_channel(server, sock, channel, client, FALSE);
 
@@ -1468,34 +1495,34 @@ void silc_server_notify(SilcServer server,
       if (comment_len > 128)
        comment_len = 127;
 
-      /* From protocol version 1.1 we get the killer's ID as well. */
+      /* Get the killer's Client ID */
       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
-      if (tmp) {
-       client_id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
-       if (!client_id)
-         goto out;
+      if (!tmp)
+       goto out;
+      client_id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
+      if (!client_id)
+       goto out;
 
-       if (id_type == SILC_ID_CLIENT) {
-         /* If the the client is not in local list we check global list */
-         client2 = silc_idlist_find_client_by_id(server->global_list, 
+      if (id_type == SILC_ID_CLIENT) {
+       /* If the the client is not in local list we check global list */
+       client2 = silc_idlist_find_client_by_id(server->global_list, 
+                                               client_id, TRUE, NULL);
+       if (!client2) {
+         client2 = silc_idlist_find_client_by_id(server->local_list, 
                                                  client_id, TRUE, NULL);
          if (!client2) {
-           client2 = silc_idlist_find_client_by_id(server->local_list, 
-                                                   client_id, TRUE, NULL);
-           if (!client2) {
-             silc_free(client_id);
-             goto out;
-           }
-         }
-         silc_free(client_id);
-
-         /* Killer must be router operator */
-         if (server->server_type != SILC_SERVER &&
-             !(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
-           SILC_LOG_DEBUG(("Killing is not allowed"));
+           silc_free(client_id);
            goto out;
          }
        }
+       silc_free(client_id);
+
+       /* Killer must be router operator */
+       if (server->server_type != SILC_SERVER &&
+           !(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+         SILC_LOG_DEBUG(("Killing is not allowed"));
+         goto out;
+       }
       }
 
       /* Send the notify to local clients on the channels except to the
@@ -1507,7 +1534,7 @@ void silc_server_notify(SilcServer server,
 
       /* Remove the client from all channels */
       silc_server_remove_from_channels(server, NULL, client, FALSE, NULL, 
-                                      FALSE);
+                                      FALSE, TRUE);
 
       /* Check if anyone is watching this nickname */
       silc_server_check_watcher_list(server, client, NULL,
@@ -1638,7 +1665,7 @@ void silc_server_notify(SilcServer server,
 
       /* Get ban list */
       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
-      if (!tmp)
+      if (!tmp || tmp_len < 2)
        goto out;
 
       /* Parse the arguments to see they are constructed correctly */
@@ -1648,9 +1675,10 @@ void silc_server_notify(SilcServer server,
        goto out;
 
       if (action == 0 && !channel->ban_list)
-       channel->ban_list = silc_hash_table_alloc(0, silc_hash_ptr,
-                                                 NULL, NULL, NULL,
-                                                 NULL, NULL, TRUE);
+       channel->ban_list =
+         silc_hash_table_alloc(0, silc_hash_ptr,
+                               NULL, NULL, NULL,
+                               silc_server_inviteban_destruct, channel, TRUE);
 
       /* Proces the ban action */
       silc_server_inviteban_process(server, channel->ban_list, action,
@@ -1686,7 +1714,7 @@ void silc_server_notify(SilcServer server,
                                                 client_id, FALSE, NULL);
          if (client) {
            silc_server_remove_from_channels(server, NULL, client, TRUE, 
-                                            NULL, TRUE);
+                                            NULL, TRUE, FALSE);
            silc_idlist_del_data(client);
            silc_idlist_del_client(server->global_list, client);
          }
@@ -2081,9 +2109,12 @@ void silc_server_channel_key(SilcServer server,
 
   /* Save the channel key */
   channel = silc_server_save_channel_key(server, buffer, NULL);
-  if (!channel)
+  if (!channel) {
+    SILC_LOG_ERROR(("Bad channel key from %s (%s)",
+                   sock->hostname, sock->ip));
     return;
-
+  }
+    
   /* Distribute the key to everybody who is on the channel. If we are router
      we will also send it to locally connected servers. */
   silc_server_send_channel_key(server, sock, channel, FALSE);
@@ -3646,7 +3677,8 @@ void silc_server_resume_client(SilcServer server,
     server->stat.clients--;
     if (server->stat.cell_clients)
       server->stat.cell_clients--;
-    silc_server_remove_from_channels(server, NULL, client, FALSE, NULL, FALSE);
+    silc_server_remove_from_channels(server, NULL, client, FALSE,
+                                    NULL, FALSE, FALSE);
     silc_server_del_from_watcher_list(server, client);
     if (!silc_idlist_del_client(server->local_list, client))
       silc_idlist_del_client(server->global_list, client);
@@ -3906,5 +3938,4 @@ void silc_server_resume_client(SilcServer server,
   }
 
   silc_free(client_id);
-    silc_idlist_del_data(detached_client);
 }