Fixed KILLED notify handling in normal server.
[silc.git] / apps / silcd / packet_receive.c
index 2ca1e630546f20a8d3ce8267f77d9673595f80b4..95486d8f61832a0ccc7b447806fa789847729785 100644 (file)
@@ -437,7 +437,7 @@ void silc_server_notify(SilcServer server,
     channel->topic = strdup(tmp);
 
     /* Send the same notify to the channel */
-    silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
+    silc_server_packet_send_to_channel(server, NULL, channel, packet->type, 
                                       FALSE, packet->buffer->data, 
                                       packet->buffer->len, FALSE);
     silc_free(channel_id);
@@ -563,6 +563,38 @@ void silc_server_notify(SilcServer server,
     /* Check if mode changed */
     if (channel->mode == mode) {
       SILC_LOG_DEBUG(("Mode is changed already"));
+
+      /* If this mode change has founder mode then we'll enforce the
+        change so that the server gets the real founder public key */
+      if (server->server_type != SILC_SERVER &&
+         sock != SILC_PRIMARY_ROUTE(server) &&
+         mode & SILC_CHANNEL_MODE_FOUNDER_AUTH && channel->founder_key) {
+       SILC_LOG_DEBUG(("Sending founder public key to server"));
+       silc_server_send_notify_cmode(server, sock, FALSE, channel,
+                                     channel->mode, server->id,
+                                     SILC_ID_SERVER, channel->cipher,
+                                     channel->hmac_name,
+                                     channel->passphrase,
+                                     channel->founder_key);
+      }
+
+      /* If we received same mode from our primary check whether founder
+        mode and key in the notify is set.  We update the founder key
+        here since we may have wrong one */
+      if (server->server_type == SILC_SERVER &&
+         sock == SILC_PRIMARY_ROUTE(server) &&
+         mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+       SILC_LOG_DEBUG(("Founder public key received from primary router"));
+       tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
+       if (!tmp)
+         break;
+
+       if (channel->founder_key)
+         silc_pkcs_public_key_free(channel->founder_key);
+       channel->founder_key = NULL;
+       silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
+      }
+
       break;
     }
 
@@ -848,7 +880,7 @@ void silc_server_notify(SilcServer server,
           founder at all on the channel. */
        if (client && !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
          /* Force the mode to not have founder mode */
-         mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+         chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
          silc_server_force_cumode_change(server, sock, channel, chl, mode);
          notify_sent = TRUE;
          break;
@@ -868,7 +900,7 @@ void silc_server_notify(SilcServer server,
                 silc_pkcs_public_key_compare(
                                        channel->founder_key,
                                        chl2->client->data.public_key))) {
-             mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+             chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
              silc_server_force_cumode_change(server, sock, channel,
                                              chl, mode);
              notify_sent = TRUE;
@@ -887,7 +919,7 @@ void silc_server_notify(SilcServer server,
        tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
        if (!tmp || !silc_pkcs_public_key_decode(tmp, tmp_len,
                                                 &founder_key)) {
-         mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+         chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
          silc_server_force_cumode_change(server, sock, channel, chl, mode);
          notify_sent = TRUE;
          break;
@@ -899,14 +931,14 @@ void silc_server_notify(SilcServer server,
          if (client && client->data.public_key && 
              !silc_pkcs_public_key_compare(channel->founder_key,
                                            client->data.public_key)) {
-           mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+           chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
            silc_server_force_cumode_change(server, sock, channel, chl, mode);
            notify_sent = TRUE;
            break;
          }
          if (!silc_pkcs_public_key_compare(channel->founder_key,
                                            founder_key)) {
-           mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+           chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
            silc_server_force_cumode_change(server, sock, channel, chl, mode);
            notify_sent = TRUE;
            break;
@@ -934,7 +966,9 @@ void silc_server_notify(SilcServer server,
        break;
       }
 
-      SILC_LOG_DEBUG(("Changing the channel user mode"));
+      SILC_LOG_DEBUG(("Changing %s channel user mode",
+                     chl->client->nickname ? chl->client->nickname :
+                     (unsigned char *)""));
 
       /* Change the mode */
       chl->mode = mode;
@@ -1126,6 +1160,13 @@ void silc_server_notify(SilcServer server,
       /* Re-announce our clients on the channel as the ID has changed now */
       silc_server_announce_get_channel_users(server, channel, &modes, &users,
                                             &users_modes);
+      if (users) {
+       silc_buffer_push(users, users->data - users->head);
+       silc_server_packet_send(server, sock,
+                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                               users->data, users->len, FALSE);
+       silc_buffer_free(users);
+      }
       if (modes) {
        silc_buffer_push(modes, modes->data - modes->head);
        silc_server_packet_send_dest(server, sock,
@@ -1134,13 +1175,6 @@ void silc_server_notify(SilcServer server,
                                     modes->data, modes->len, FALSE);
        silc_buffer_free(modes);
       }
-      if (users) {
-       silc_buffer_push(users, users->data - users->head);
-       silc_server_packet_send(server, sock,
-                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
-                               users->data, users->len, FALSE);
-       silc_buffer_free(users);
-      }
       if (users_modes) {
        silc_buffer_push(users_modes, users_modes->data - users_modes->head);
        silc_server_packet_send_dest(server, sock,
@@ -1382,10 +1416,10 @@ void silc_server_notify(SilcServer server,
 
       /* If the the client is not in local list we check global list */
       client = silc_idlist_find_client_by_id(server->global_list, 
-                                            client_id, TRUE, NULL);
+                                            client_id, TRUE, &cache);
       if (!client) {
        client = silc_idlist_find_client_by_id(server->local_list, 
-                                              client_id, TRUE, NULL);
+                                              client_id, TRUE, &cache);
        if (!client) {
          silc_free(client_id);
          goto out;
@@ -1429,7 +1463,8 @@ void silc_server_notify(SilcServer server,
          silc_free(client_id);
 
          /* Killer must be router operator */
-         if (!(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+         if (server->server_type != SILC_SERVER &&
+             !(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
            SILC_LOG_DEBUG(("Killing is not allowed"));
            goto out;
          }
@@ -1448,10 +1483,25 @@ void silc_server_notify(SilcServer server,
                                       FALSE);
 
       /* Check if anyone is watching this nickname */
-      if (server->server_type == SILC_ROUTER)
-       silc_server_check_watcher_list(server, client, NULL,
-                                      SILC_NOTIFY_TYPE_KILLED);
+      silc_server_check_watcher_list(server, client, NULL,
+                                    SILC_NOTIFY_TYPE_KILLED);
+
+      /* Update statistics */
+      server->stat.clients--;
+      if (server->stat.cell_clients)
+       server->stat.cell_clients--;
+      SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+      SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
+      if (SILC_IS_LOCAL(client)) {
+       server->stat.my_clients--;
+       silc_schedule_task_del_by_context(server->schedule, client);
+       silc_idlist_del_data(client);
+       client->mode = 0;
+      }
 
+      client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+      cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
       break;
     }
 
@@ -2922,6 +2972,13 @@ void silc_server_new_channel(SilcServer server,
         users on the channel "joining" the channel. */
       silc_server_announce_get_channel_users(server, channel, &modes, &users,
                                             &users_modes);
+      if (users) {
+       silc_buffer_push(users, users->data - users->head);
+       silc_server_packet_send(server, sock,
+                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                               users->data, users->len, FALSE);
+       silc_buffer_free(users);
+      }
       if (modes) {
        silc_buffer_push(modes, modes->data - modes->head);
        silc_server_packet_send_dest(server, sock,
@@ -2930,13 +2987,6 @@ void silc_server_new_channel(SilcServer server,
                                     modes->data, modes->len, FALSE);
        silc_buffer_free(modes);
       }
-      if (users) {
-       silc_buffer_push(users, users->data - users->head);
-       silc_server_packet_send(server, sock,
-                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
-                               users->data, users->len, FALSE);
-       silc_buffer_free(users);
-      }
       if (users_modes) {
        silc_buffer_push(users_modes, users_modes->data - users_modes->head);
        silc_server_packet_send_dest(server, sock,
@@ -3719,6 +3769,7 @@ void silc_server_resume_client(SilcServer server,
                     server->global_list->clients, 
                     detached_client->nickname,
                     detached_client->id, detached_client, FALSE, NULL);
+    detached_client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
 
     /* Change the owner of the client if needed */
     if (detached_client->router != server_entry)