Added anonymous client connections support.
[silc.git] / apps / silcd / packet_receive.c
index 4e07b0ce40502355bbca0bb2b7f7580e33ee4c71..d3f03aae0bca0667e643715008640924f39f2955 100644 (file)
@@ -43,7 +43,7 @@ void silc_server_notify(SilcServer server,
   SilcClientEntry client = NULL, client2 = NULL;
   SilcServerEntry server_entry = NULL;
   SilcChannelClientEntry chl;
-  SilcIDCacheEntry cache;
+  SilcIDCacheEntry cache = NULL;
   SilcHashTableList htl;
   SilcUInt32 mode;
   unsigned char *tmp;
@@ -100,7 +100,7 @@ void silc_server_notify(SilcServer server,
                                   channel_id, SILC_ID_CHANNEL,
                                   packet->buffer->data, 
                                   packet->buffer->len, FALSE);
-      silc_server_backup_send_dest(server, (SilcServerEntry)sock->user_data, 
+      silc_server_backup_send_dest(server, sock->user_data, 
                                   packet->type, packet->flags,
                                   channel_id, SILC_ID_CHANNEL,
                                   packet->buffer->data, packet->buffer->len, 
@@ -112,7 +112,7 @@ void silc_server_notify(SilcServer server,
                              packet->flags | SILC_PACKET_FLAG_BROADCAST, 
                              packet->buffer->data, packet->buffer->len, 
                              FALSE);
-      silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
+      silc_server_backup_send(server, sock->user_data,
                              packet->type, packet->flags,
                              packet->buffer->data, packet->buffer->len, 
                              FALSE, TRUE);
@@ -166,15 +166,17 @@ void silc_server_notify(SilcServer server,
        entry for the client. */
     client = silc_idlist_find_client_by_id(server->global_list, 
                                           client_id, server->server_type, 
-                                          NULL);
+                                          &cache);
     if (!client) {
       client = silc_idlist_find_client_by_id(server->local_list, 
                                             client_id, server->server_type,
-                                            NULL);
+                                            &cache);
       if (!client) {
        /* If router did not find the client the it is bogus */
-       if (server->server_type != SILC_SERVER)
+       if (server->server_type != SILC_SERVER) {
+         silc_free(client_id);
          goto out;
+       }
 
        client = 
          silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
@@ -189,6 +191,7 @@ void silc_server_notify(SilcServer server,
        client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
       }
     }
+    silc_free(client_id);
 
     /* Do not process the notify if the client is not registered */
     if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
@@ -196,7 +199,8 @@ void silc_server_notify(SilcServer server,
 
     /* Do not add client to channel if it is there already */
     if (silc_server_client_on_channel(client, channel, NULL)) {
-      SILC_LOG_DEBUG(("Client already on channel"));
+      SILC_LOG_DEBUG(("Client already on channel %s",
+                     channel->channel_name));
       break;
     }
 
@@ -232,10 +236,13 @@ void silc_server_notify(SilcServer server,
 
     silc_hash_table_add(channel->user_list, client, chl);
     silc_hash_table_add(client->channels, channel, chl);
-    silc_free(client_id);
     channel->user_count++;
     channel->disabled = FALSE;
 
+    /* Make sure we don't expire clients that are on channel */
+    if (cache)
+      cache->expire = 0;
+
     /* Update statistics */
     if (server->server_type == SILC_ROUTER) {
       if (sock->type != SILC_SOCKET_TYPE_ROUTER)
@@ -421,6 +428,7 @@ void silc_server_notify(SilcServer server,
        goto out;
       }
     }
+    silc_free(channel_id);
 
     if (channel->topic && !strcmp(channel->topic, tmp)) {
       SILC_LOG_DEBUG(("Topic is already set and same"));
@@ -447,7 +455,6 @@ void silc_server_notify(SilcServer server,
     silc_server_packet_send_to_channel(server, NULL, channel, packet->type, 
                                       FALSE, packet->buffer->data, 
                                       packet->buffer->len, FALSE);
-    silc_free(channel_id);
     break;
 
   case SILC_NOTIFY_TYPE_NICK_CHANGE:
@@ -474,8 +481,10 @@ void silc_server_notify(SilcServer server,
       if (!id2)
        goto out;
       client_id2 = silc_id_payload_parse_id(id2, tmp_len, NULL);
-      if (!client_id2)
+      if (!client_id2) {
+       silc_free(client_id);
        goto out;
+      }
       
       SILC_LOG_DEBUG(("Old Client ID id(%s)", 
                      silc_id_render(client_id, SILC_ID_CLIENT)));
@@ -591,7 +600,7 @@ void silc_server_notify(SilcServer server,
       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"));
+       SILC_LOG_DEBUG(("Founder public key received from router"));
        tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
        if (!tmp)
          break;
@@ -982,9 +991,9 @@ void silc_server_notify(SilcServer server,
 
       /* Send the same notify to the channel */
       if (!notify_sent)
-       silc_server_packet_send_to_channel(server, NULL, channel, 
-                                          packet->type, 
-                                          FALSE, packet->buffer->data, 
+       silc_server_packet_send_to_channel(server, NULL, channel,
+                                          packet->type,
+                                          FALSE, packet->buffer->data,
                                           packet->buffer->len, FALSE);
       
       silc_free(channel_id);
@@ -1283,6 +1292,7 @@ void silc_server_notify(SilcServer server,
              silc_server_del_from_watcher_list(server, client);
 
            /* Remove the client */
+           silc_idlist_del_data(client);
            silc_idlist_del_client(local ? server->local_list :
                                   server->global_list, client);
          }
@@ -1304,7 +1314,7 @@ void silc_server_notify(SilcServer server,
 
     /* Remove the clients that this server owns as they will become
        invalid now too. */
-    silc_server_remove_clients_by_server(server, server_entry,
+    silc_server_remove_clients_by_server(server, server_entry->router,
                                         server_entry, TRUE);
     silc_server_backup_del(server, server_entry);
 
@@ -1577,6 +1587,8 @@ void silc_server_notify(SilcServer server,
          server->stat.detached--;
       }
     }
+    SILC_UMODE_STATS_UPDATE(server, SILC_UMODE_SERVER_OPERATOR);
+    SILC_UMODE_STATS_UPDATE(router, SILC_UMODE_ROUTER_OPERATOR);
 
     /* Change the mode */
     client->mode = mode;
@@ -1683,6 +1695,7 @@ void silc_server_notify(SilcServer server,
          if (client) {
            silc_server_remove_from_channels(server, NULL, client, TRUE, 
                                             NULL, TRUE);
+           silc_idlist_del_data(client);
            silc_idlist_del_client(server->global_list, client);
          }
          silc_free(client_id);
@@ -2090,7 +2103,7 @@ void silc_server_channel_key(SilcServer server,
   
   if (server->server_type != SILC_BACKUP_ROUTER) {
     /* Distribute to local cell backup routers. */
-    silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
+    silc_server_backup_send(server, sock->user_data, 
                            SILC_PACKET_CHANNEL_KEY, 0,
                            buffer->data, buffer->len, FALSE, TRUE);
   }
@@ -2277,6 +2290,25 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     snprintf(&nickname[strlen(nickname) - 1], 1, "%d", nickfail);
   }
 
+  /* If client marked as anonymous, scramble the username and hostname */
+  if (client->mode & SILC_UMODE_ANONYMOUS) {
+    char *scramble;
+
+    if (strlen(username) >= 2) {
+      username[0] = silc_rng_get_byte_fast(server->rng);
+      username[1] = silc_rng_get_byte_fast(server->rng);
+    }
+
+    scramble = silc_hash_babbleprint(server->sha1hash, username,
+                                    strlen(username));
+    scramble[5] = '@';
+    scramble[11] = '.';
+    memcpy(&scramble[16], ".silc", 5);
+    scramble[21] = '\0';
+    silc_free(username);
+    username = scramble;
+  }
+
   /* Update client entry */
   idata->status |= SILC_IDLIST_STATUS_REGISTERED;
   client->nickname = nickname;
@@ -2297,7 +2329,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   /* Distribute to backup routers */
   if (server->server_type == SILC_ROUTER) {
     SilcBuffer idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
+    silc_server_backup_send(server, sock->user_data, SILC_PACKET_NEW_ID, 0,
                            idp->data, idp->len, FALSE, TRUE);
     silc_buffer_free(idp);
   }
@@ -2457,7 +2489,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   if (server->server_type == SILC_ROUTER) {
     /* Distribute to backup routers */
     SilcBuffer idp = silc_id_payload_encode(new_server->id, SILC_ID_SERVER);
-    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
+    silc_server_backup_send(server, sock->user_data, SILC_PACKET_NEW_ID, 0,
                            idp->data, idp->len, FALSE, TRUE);
     silc_buffer_free(idp);
 
@@ -2496,6 +2528,30 @@ SilcServerEntry silc_server_new_server(SilcServer server,
       silc_server_announce_channels(server, 0, sock);
     }
 
+    /* Announce our information to backup router */
+    if (new_server->server_type == SILC_BACKUP_ROUTER &&
+       sock->type == SILC_SOCKET_TYPE_SERVER &&
+       server->server_type == SILC_ROUTER) {
+      silc_server_announce_servers(server, TRUE, 0, sock);
+      silc_server_announce_clients(server, 0, sock);
+      silc_server_announce_channels(server, 0, sock);
+    }
+
+    /* If backup router, mark it as one of ours.  This server is considered
+       to be backup router after this setting. */
+    if (new_server->server_type == SILC_BACKUP_ROUTER) {
+      SilcServerConfigRouter *backup;
+      backup = silc_server_config_find_backup_conn(server, sock->ip);
+      if (!backup)
+       backup = silc_server_config_find_backup_conn(server, sock->hostname);
+      if (backup) {
+       /* Add as our backup router */
+       silc_server_backup_add(server, new_server, backup->backup_replace_ip,
+                              backup->backup_replace_port,
+                              backup->backup_local);
+      }
+    }
+
     /* By default the servers connected to backup router are disabled
        until backup router has become the primary */
     if (server->server_type == SILC_BACKUP_ROUTER &&
@@ -2696,7 +2752,7 @@ static void silc_server_new_id_real(SilcServer server,
                            packet->type, 
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
                            buffer->data, buffer->len, FALSE);
-    silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
+    silc_server_backup_send(server, sock->user_data, 
                            packet->type, packet->flags,
                            packet->buffer->data, packet->buffer->len, 
                            FALSE, TRUE);
@@ -2744,7 +2800,7 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
                            packet->buffer->data, 
                            packet->buffer->len, FALSE);
-    silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
+    silc_server_backup_send(server, sock->user_data, 
                            packet->type, packet->flags,
                            packet->buffer->data, packet->buffer->len, 
                            FALSE, TRUE);
@@ -2754,7 +2810,7 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
      data buffer, which we will here now fetch from the original buffer. */
   new_id = silc_packet_context_alloc();
   new_id->type = SILC_PACKET_NEW_ID;
-  new_id->flags = packet->flags;
+  new_id->flags = packet->flags & (~SILC_PACKET_FLAG_LIST);
   new_id->src_id = packet->src_id;
   new_id->src_id_len = packet->src_id_len;
   new_id->src_id_type = packet->src_id_type;
@@ -2849,7 +2905,7 @@ void silc_server_new_channel(SilcServer server,
                                0, channel_id, sock->user_data, NULL, NULL, 0);
       if (!channel)
        return;
-      channel->disabled = TRUE;
+      channel->disabled = TRUE;    /* Disabled until someone JOINs */
 
       server->stat.channels++;
       if (server->server_type == SILC_ROUTER)
@@ -2884,13 +2940,15 @@ void silc_server_new_channel(SilcServer server,
          !SILC_ID_COMPARE(channel_id, server->id, server->id->ip.data_len)) {
        SilcChannelID *tmp;
        SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
-       
        if (silc_id_create_channel_id(server, server->id, server->rng, &tmp)) {
          silc_server_send_notify_channel_change(server, sock, FALSE, 
                                                 channel_id, tmp);
          silc_free(channel_id);
-         channel_id = tmp;
+         silc_free(tmp);
        }
+
+       /* Wait that server re-announces this channel */
+       return;
       }
 
       /* Create the channel with the provided Channel ID */
@@ -2902,8 +2960,16 @@ void silc_server_new_channel(SilcServer server,
        silc_free(channel_id);
        return;
       }
-      channel->disabled = TRUE;
-      channel->mode = silc_channel_get_mode(payload);
+      channel->disabled = TRUE;    /* Disabled until someone JOINs */
+
+#if 0 /* We assume that CMODE_CHANGE notify is sent to us after this. */
+
+      /* XXX Dunno if this is supposed to be set in any server type.  If set
+        here the CMODE_CHANGE that may follow sets mode that we already
+        have, and we may loose data from the CMODE_CHANGE notify. */
+      if (server_entry->server_type != SILC_BACKUP_ROUTER)
+       channel->mode = silc_channel_get_mode(payload);
+#endif
 
       /* Send the new channel key to the server */
       id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
@@ -2956,15 +3022,18 @@ void silc_server_new_channel(SilcServer server,
       /* Create new key for the channel and send it to the server and
         everybody else possibly on the channel. */
       if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
-       if (!silc_server_create_channel_key(server, channel, 0))
-         return;
-       
-       /* Send to the channel */
-       silc_server_send_channel_key(server, sock, channel, FALSE);
-       id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-       id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+
+       if (silc_hash_table_count(channel->user_list)) {
+         if (!silc_server_create_channel_key(server, channel, 0))
+           return;
+
+         /* Send to the channel */
+         silc_server_send_channel_key(server, sock, channel, FALSE);
+       }
 
        /* Send to the server */
+       id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+       id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
        chk = silc_channel_key_payload_encode(id_len, id,
                                              strlen(channel->channel_key->
                                                     cipher->name),
@@ -3023,6 +3092,24 @@ void silc_server_new_channel(SilcServer server,
     }
   }
 
+  /* 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
+     this list packet instead of multiple New Channel packets. */
+  if (server->server_type == SILC_ROUTER &&
+      sock->type == SILC_SOCKET_TYPE_SERVER &&
+      !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+    SILC_LOG_DEBUG(("Broadcasting received New Channel packet"));
+    silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
+                           packet->type, 
+                           packet->flags | SILC_PACKET_FLAG_BROADCAST,
+                           packet->buffer->data, 
+                           packet->buffer->len, FALSE);
+    silc_server_backup_send(server, sock->user_data, 
+                           packet->type, packet->flags,
+                           packet->buffer->data, packet->buffer->len, 
+                           FALSE, TRUE);
+  }
+
   silc_channel_payload_free(payload);
 }
 
@@ -3044,29 +3131,11 @@ void silc_server_new_channel_list(SilcServer server,
       server->server_type == SILC_SERVER)
     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
-     this list packet instead of multiple New Channel packets. */
-  if (server->server_type == SILC_ROUTER &&
-      sock->type == SILC_SOCKET_TYPE_SERVER &&
-      !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
-    SILC_LOG_DEBUG(("Broadcasting received New Channel List packet"));
-    silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
-                           packet->type, 
-                           packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           packet->buffer->data, 
-                           packet->buffer->len, FALSE);
-    silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
-                           packet->type, packet->flags,
-                           packet->buffer->data, packet->buffer->len, 
-                           FALSE, TRUE);
-  }
-
   /* Make copy of the original packet context, except for the actual
      data buffer, which we will here now fetch from the original buffer. */
   new = silc_packet_context_alloc();
   new->type = SILC_PACKET_NEW_CHANNEL;
-  new->flags = packet->flags;
+  new->flags = packet->flags & (~SILC_PACKET_FLAG_LIST);
   new->src_id = packet->src_id;
   new->src_id_len = packet->src_id_len;
   new->src_id_type = packet->src_id_type;
@@ -3339,6 +3408,7 @@ void silc_server_resume_client(SilcServer server,
 {
   SilcBuffer buffer = packet->buffer, buf;
   SilcIDListData idata;
+  SilcIDCacheEntry id_cache = NULL;
   SilcClientEntry detached_client;
   SilcClientID *client_id = NULL;
   unsigned char *id_string, *auth = NULL;
@@ -3573,8 +3643,10 @@ 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_del_from_watcher_list(server, client);
-    silc_idlist_del_client(server->local_list, client);
+    if (!silc_idlist_del_client(server->local_list, client))
+      silc_idlist_del_client(server->global_list, client);
     client = detached_client;
 
     /* If the ID is not based in our ID then change it */
@@ -3708,10 +3780,12 @@ void silc_server_resume_client(SilcServer server,
 
     /* Get entry to the client, and resolve it if we don't have it. */
     detached_client = silc_idlist_find_client_by_id(server->local_list, 
-                                                   client_id, TRUE, NULL);
+                                                   client_id, TRUE,
+                                                   &id_cache);
     if (!detached_client) {
       detached_client = silc_idlist_find_client_by_id(server->global_list,
-                                                     client_id, TRUE, NULL);
+                                                     client_id, TRUE,
+                                                     &id_cache);
       if (!detached_client) {
        SILC_LOG_DEBUG(("Resuming client is unknown"));
        silc_free(client_id);
@@ -3741,10 +3815,41 @@ void silc_server_resume_client(SilcServer server,
       return;
     }
 
+    SILC_LOG_DEBUG(("Resuming 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->server_type == SILC_ROUTER &&
+       sock->type == SILC_SOCKET_TYPE_SERVER &&
+       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+      SILC_LOG_DEBUG(("Broadcasting received Resume Client packet"));
+      silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
+                             packet->type, 
+                             packet->flags | SILC_PACKET_FLAG_BROADCAST,
+                             buffer->data, buffer->len, FALSE);
+      silc_server_backup_send(server, sock->user_data, 
+                             packet->type, packet->flags,
+                             packet->buffer->data, packet->buffer->len, 
+                             FALSE, TRUE);
+    }
+
     /* Client is detached, and now it is resumed.  Remove the detached
        mode and mark that it is resumed. */
     detached_client->mode &= ~SILC_UMODE_DETACHED;
     detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED;
+    detached_client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
+    id_cache->expire = 0;
+
+    /* Update channel information regarding global clients on channel. */
+    if (server->server_type == SILC_SERVER) {
+      silc_hash_table_list(detached_client->channels, &htl);
+      while (silc_hash_table_get(&htl, NULL, (void **)&chl))
+       chl->channel->global_users = 
+         silc_server_channel_has_global(chl->channel);
+      silc_hash_table_list_reset(&htl);
+    }
+
+    silc_schedule_task_del_by_context(server->schedule, detached_client);
 
     /* Get the new owner of the resumed client */
     server_id = silc_id_str2id(packet->src_id, packet->src_id_len,
@@ -3774,8 +3879,6 @@ void silc_server_resume_client(SilcServer server,
        server_entry->server_type == SILC_ROUTER)
       local = FALSE;
 
-    SILC_LOG_DEBUG(("Resuming detached client"));
-
     /* Change the client to correct list. */
     if (!silc_idcache_del_by_context(server->local_list->clients,
                                     detached_client))
@@ -3786,38 +3889,9 @@ 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)
-      detached_client->router = server_entry;
-
-    /* Update channel information regarding global clients on channel. */
-    if (server->server_type == SILC_SERVER) {
-      silc_hash_table_list(detached_client->channels, &htl);
-      while (silc_hash_table_get(&htl, NULL, (void **)&chl))
-       chl->channel->global_users = 
-         silc_server_channel_has_global(chl->channel);
-      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->server_type == SILC_ROUTER &&
-       sock->type == SILC_SOCKET_TYPE_SERVER &&
-       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
-      SILC_LOG_DEBUG(("Broadcasting received Resume Client packet"));
-      silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
-                             packet->type, 
-                             packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                             buffer->data, buffer->len, FALSE);
-      silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
-                             packet->type, packet->flags,
-                             packet->buffer->data, packet->buffer->len, 
-                             FALSE, TRUE);
-    }
+    /* Change the owner of the client */
+    detached_client->router = server_entry;
 
     silc_free(server_id);
   }