updates.
[silc.git] / apps / silcd / server.c
index 4892cd065864cae453981326a1b592d73dc6438b..2eae57b86ec79e5f2f69a727d01b4df8e75fc7d9 100644 (file)
@@ -182,17 +182,17 @@ int silc_server_init(SilcServer server)
 
   /* Initialize ID caches */
   server->local_list->clients = 
-    silc_idcache_alloc(0, silc_idlist_client_destructor);
-  server->local_list->servers = silc_idcache_alloc(0, NULL);
-  server->local_list->channels = silc_idcache_alloc(0, NULL);
+    silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor);
+  server->local_list->servers = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
+  server->local_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
 
   /* These are allocated for normal server as well as these hold some 
      global information that the server has fetched from its router. For 
      router these are used as they are supposed to be used on router. */
   server->global_list->clients = 
-    silc_idcache_alloc(0, silc_idlist_client_destructor);
-  server->global_list->servers = silc_idcache_alloc(0, NULL);
-  server->global_list->channels = silc_idcache_alloc(0, NULL);
+    silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor);
+  server->global_list->servers = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
+  server->global_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
 
   /* Allocate the entire socket list that is used in server. Eventually 
      all connections will have entry in this table (it is a table of 
@@ -216,7 +216,7 @@ int silc_server_init(SilcServer server)
     
     server->id = id;
     server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
-    server->id_string_len = silc_id_get_len(SILC_ID_SERVER);
+    server->id_string_len = silc_id_get_len(id, SILC_ID_SERVER);
     server->id_type = SILC_ID_SERVER;
     server->server_name = server->config->server_info->server_name;
 
@@ -828,6 +828,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   SilcBuffer packet;
   SilcServerHBContext hb_context;
   unsigned char *id_string;
+  uint32 id_len;
   SilcIDListData idata;
 
   SILC_LOG_DEBUG(("Start"));
@@ -856,12 +857,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   /* Send NEW_SERVER packet to the router. We will become registered
      to the SILC network after sending this packet. */
   id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
-  packet = silc_buffer_alloc(2 + 2 + SILC_ID_SERVER_LEN + 
-                            strlen(server->server_name));
+  id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
+  packet = silc_buffer_alloc(2 + 2 + id_len + strlen(server->server_name));
   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
   silc_buffer_format(packet,
-                    SILC_STR_UI_SHORT(SILC_ID_SERVER_LEN),
-                    SILC_STR_UI_XNSTRING(id_string, SILC_ID_SERVER_LEN),
+                    SILC_STR_UI_SHORT(id_len),
+                    SILC_STR_UI_XNSTRING(id_string, id_len),
                     SILC_STR_UI_SHORT(strlen(server->server_name)),
                     SILC_STR_UI_XNSTRING(server->server_name,
                                          strlen(server->server_name)),
@@ -948,6 +949,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
   SilcServerKEInternalContext *proto_ctx;
   int sock, port;
   void *cconfig, *sconfig, *rconfig;
+  SilcServerConfigSectionDenyConnection *deny;
 
   SILC_LOG_DEBUG(("Accepting new connection"));
 
@@ -1003,10 +1005,26 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
      later when outgoing data is available. */
   SILC_REGISTER_CONNECTION_FOR_IO(sock);
 
+  port = server->sockets[fd]->port; /* Listenning port */
+
+  /* Check whether this connection is denied to connect to us. */
+  deny = silc_server_config_denied_conn(server->config, newsocket->ip, port);
+  if (!deny)
+    deny = silc_server_config_denied_conn(server->config, newsocket->hostname,
+                                         port);
+  if (deny) {
+    /* The connection is denied */
+    silc_server_disconnect_remote(server, newsocket, deny->comment ?
+                                 deny->comment :
+                                 "Server closed connection: "
+                                 "Connection refused");
+    server->stat.conn_failures++;
+    return;
+  }
+
   /* Check whether we have configred this sort of connection at all. We
      have to check all configurations since we don't know what type of
      connection this is. */
-  port = server->sockets[fd]->port; /* Listenning port */
   if (!(cconfig = silc_server_config_find_client_conn(server->config,
                                                      newsocket->ip, port)))
     cconfig = silc_server_config_find_client_conn(server->config,
@@ -1226,7 +1244,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
         and other information is created after we have received NEW_CLIENT
         packet from client. */
       client = silc_idlist_add_client(server->local_list, 
-                                     NULL, 0, NULL, NULL, NULL, NULL, sock);
+                                     NULL, NULL, NULL, NULL, NULL, sock);
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to cache"));
        silc_free(sock->user_data);
@@ -1521,7 +1539,7 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
     if (client && client->id) {
       void *id = silc_id_str2id(packet->src_id, packet->src_id_len,
                                packet->src_id_type);
-      if (SILC_ID_CLIENT_COMPARE(client->id, id)) {
+      if (!id || !SILC_ID_CLIENT_COMPARE(client->id, id)) {
        silc_free(id);
        goto out;
       }
@@ -1535,7 +1553,7 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
     if (!(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
        packet->dst_id_type == SILC_ID_SERVER && 
        sock->type != SILC_SOCKET_TYPE_CLIENT &&
-       SILC_ID_SERVER_COMPARE(packet->dst_id, server->id_string)) {
+       memcmp(packet->dst_id, server->id_string, packet->dst_id_len)) {
       
       /* Route the packet to fastest route for the destination ID */
       void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len, 
@@ -2162,8 +2180,7 @@ void silc_server_free_client_data(SilcServer server,
   if (notify && !server->standalone && server->router)
     silc_server_send_notify_signoff(server, server->router->connection,
                                    server->server_type == SILC_SERVER ?
-                                   FALSE : TRUE, client->id, 
-                                   SILC_ID_CLIENT_LEN, signoff);
+                                   FALSE : TRUE, client->id, signoff);
 
   /* Remove client from all channels */
   if (notify)
@@ -2280,8 +2297,7 @@ int silc_server_remove_clients_by_server(SilcServer server,
     silc_buffer_free(idp);
   }
 
-  if (silc_idcache_find_by_id(server->local_list->clients, 
-                             SILC_ID_CACHE_ANY, SILC_ID_CLIENT, &list)) {
+  if (silc_idcache_get_all(server->local_list->clients, &list)) {
 
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
@@ -2334,8 +2350,7 @@ int silc_server_remove_clients_by_server(SilcServer server,
     silc_idcache_list_free(list);
   }
   
-  if (silc_idcache_find_by_id(server->global_list->clients, 
-                             SILC_ID_CACHE_ANY, SILC_ID_CLIENT, &list)) {
+  if (silc_idcache_get_all(server->global_list->clients, &list)) {
 
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
@@ -2789,7 +2804,8 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
      to our primary route. */
   if (broadcast && server->standalone == FALSE)
     silc_server_send_new_channel(server, server->router->connection, TRUE, 
-                                channel_name, entry->id, SILC_ID_CHANNEL_LEN,
+                                channel_name, entry->id, 
+                                silc_id_get_len(entry->id, SILC_ID_CHANNEL),
                                 entry->mode);
 
   server->stat.my_channels++;
@@ -2847,7 +2863,8 @@ silc_server_create_new_channel_with_id(SilcServer server,
      to our primary route. */
   if (broadcast && server->standalone == FALSE)
     silc_server_send_new_channel(server, server->router->connection, TRUE, 
-                                channel_name, entry->id, SILC_ID_CHANNEL_LEN,
+                                channel_name, entry->id, 
+                                silc_id_get_len(entry->id, SILC_ID_CHANNEL),
                                 entry->mode);
 
   server->stat.my_channels++;
@@ -3086,8 +3103,7 @@ static void silc_server_announce_get_servers(SilcServer server,
   SilcBuffer idp;
 
   /* Go through all clients in the list */
-  if (silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY, 
-                             SILC_ID_SERVER, &list)) {
+  if (silc_idcache_get_all(id_list->servers, &list)) {
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        entry = (SilcServerEntry)id_cache->context;
@@ -3153,8 +3169,7 @@ static void silc_server_announce_get_clients(SilcServer server,
   SilcBuffer idp;
 
   /* Go through all clients in the list */
-  if (silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY, 
-                             SILC_ID_CLIENT, &list)) {
+  if (silc_idcache_get_all(id_list->clients, &list)) {
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        client = (SilcClientEntry)id_cache->context;
@@ -3211,24 +3226,26 @@ void silc_server_announce_clients(SilcServer server)
 }
 
 static SilcBuffer 
-silc_server_announce_encode_join(uint32 argc, ...)
+silc_server_announce_encode_notify(SilcNotifyType notify, uint32 argc, ...)
 {
   va_list ap;
 
   va_start(ap, argc);
-  return silc_notify_payload_encode(SILC_NOTIFY_TYPE_JOIN, argc, ap);
+  return silc_notify_payload_encode(notify, argc, ap);
 }
 
 /* Returns assembled packets for channel users of the `channel'. */
 
 void silc_server_announce_get_channel_users(SilcServer server,
                                            SilcChannelEntry channel,
-                                           SilcBuffer *channel_users)
+                                           SilcBuffer *channel_users,
+                                           SilcBuffer *channel_users_modes)
 {
   SilcChannelClientEntry chl;
   SilcBuffer chidp, clidp;
   SilcBuffer tmp;
   int len;
+  unsigned char mode[4];
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -3237,8 +3254,11 @@ void silc_server_announce_get_channel_users(SilcServer server,
   silc_list_start(channel->user_list);
   while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
     clidp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
-    tmp = silc_server_announce_encode_join(2, clidp->data, clidp->len,
-                                          chidp->data, chidp->len);
+
+    /* JOIN Notify */
+    tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_JOIN, 2, 
+                                            clidp->data, clidp->len,
+                                            chidp->data, chidp->len);
     len = tmp->len;
     *channel_users = 
       silc_buffer_realloc(*channel_users, 
@@ -3250,8 +3270,28 @@ void silc_server_announce_get_channel_users(SilcServer server,
     
     silc_buffer_put(*channel_users, tmp->data, tmp->len);
     silc_buffer_pull(*channel_users, len);
-    silc_buffer_free(clidp);
     silc_buffer_free(tmp);
+
+    /* CUMODE notify for mode change on the channel */
+    SILC_PUT32_MSB(chl->mode, mode);
+    tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CUMODE_CHANGE, 
+                                            3, clidp->data, clidp->len,
+                                            mode, 4,
+                                            clidp->data, clidp->len);
+    len = tmp->len;
+    *channel_users_modes = 
+      silc_buffer_realloc(*channel_users_modes, 
+                         (*channel_users_modes ? 
+                          (*channel_users_modes)->truelen + len : len));
+    silc_buffer_pull_tail(*channel_users_modes, 
+                         ((*channel_users_modes)->end - 
+                          (*channel_users_modes)->data));
+    
+    silc_buffer_put(*channel_users_modes, tmp->data, tmp->len);
+    silc_buffer_pull(*channel_users_modes, len);
+    silc_buffer_free(tmp);
+
+    silc_buffer_free(clidp);
   }
   silc_buffer_free(chidp);
 }
@@ -3263,28 +3303,30 @@ void silc_server_announce_get_channel_users(SilcServer server,
 void silc_server_announce_get_channels(SilcServer server,
                                       SilcIDList id_list,
                                       SilcBuffer *channels,
-                                      SilcBuffer *channel_users)
+                                      SilcBuffer *channel_users,
+                                      SilcBuffer *channel_users_modes)
 {
   SilcIDCacheList list;
   SilcIDCacheEntry id_cache;
   SilcChannelEntry channel;
   unsigned char *cid;
+  uint32 id_len;
   uint16 name_len;
   int len;
 
   SILC_LOG_DEBUG(("Start"));
 
   /* Go through all channels in the list */
-  if (silc_idcache_find_by_id(id_list->channels, SILC_ID_CACHE_ANY, 
-                             SILC_ID_CHANNEL, &list)) {
+  if (silc_idcache_get_all(id_list->channels, &list)) {
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        channel = (SilcChannelEntry)id_cache->context;
        
        cid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+       id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
        name_len = strlen(channel->channel_name);
 
-       len = 4 + name_len + SILC_ID_CHANNEL_LEN + 4;
+       len = 4 + name_len + id_len + 4;
        *channels = 
          silc_buffer_realloc(*channels, 
                              (*channels ? (*channels)->truelen + len : len));
@@ -3294,14 +3336,15 @@ void silc_server_announce_get_channels(SilcServer server,
                           SILC_STR_UI_SHORT(name_len),
                           SILC_STR_UI_XNSTRING(channel->channel_name, 
                                                name_len),
-                          SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
-                          SILC_STR_UI_XNSTRING(cid, SILC_ID_CHANNEL_LEN),
+                          SILC_STR_UI_SHORT(id_len),
+                          SILC_STR_UI_XNSTRING(cid, id_len),
                           SILC_STR_UI_INT(channel->mode),
                           SILC_STR_END);
        silc_buffer_pull(*channels, len);
 
        silc_server_announce_get_channel_users(server, channel,
-                                              channel_users);
+                                              channel_users,
+                                              channel_users_modes);
 
        silc_free(cid);
 
@@ -3320,17 +3363,19 @@ void silc_server_announce_get_channels(SilcServer server,
 
 void silc_server_announce_channels(SilcServer server)
 {
-  SilcBuffer channels = NULL, channel_users = NULL;
+  SilcBuffer channels = NULL, channel_users = NULL, channel_users_modes = NULL;
 
   SILC_LOG_DEBUG(("Announcing channels and channel users"));
 
   /* Get channels and channel users in local list */
   silc_server_announce_get_channels(server, server->local_list,
-                                   &channels, &channel_users);
+                                   &channels, &channel_users,
+                                   &channel_users_modes);
 
   /* Get channels and channel users in global list */
   silc_server_announce_get_channels(server, server->global_list,
-                                   &channels, &channel_users);
+                                   &channels, &channel_users,
+                                   &channel_users_modes);
 
   if (channels) {
     silc_buffer_push(channels, channels->data - channels->head);
@@ -3358,6 +3403,22 @@ void silc_server_announce_channels(SilcServer server)
 
     silc_buffer_free(channel_users);
   }
+
+  if (channel_users_modes) {
+    silc_buffer_push(channel_users_modes, 
+                    channel_users_modes->data - channel_users_modes->head);
+    SILC_LOG_HEXDUMP(("channel users modes"), channel_users_modes->data, 
+                    channel_users_modes->len);
+
+    /* Send the packet */
+    silc_server_packet_send(server, server->router->connection,
+                           SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                           channel_users_modes->data, 
+                           channel_users_modes->len,
+                           FALSE);
+
+    silc_buffer_free(channel_users_modes);
+  }
 }
 
 /* Failure timeout callback. If this is called then we will immediately
@@ -3394,6 +3455,8 @@ void silc_server_get_users_on_channel(SilcServer server,
   SilcBuffer idp;
   uint32 list_count = 0;
 
+  /* XXX rewrite - this does not support IPv6 based Client ID's. */
+
   client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) * 
                                     silc_list_count(channel->user_list));
   client_mode_list = silc_buffer_alloc(4 * 
@@ -3457,7 +3520,7 @@ void silc_server_save_users_on_channel(SilcServer server,
     SILC_GET32_MSB(mode, mode_list->data);
     silc_buffer_pull(mode_list, 4);
 
-    if (noadd && !SILC_ID_CLIENT_COMPARE(client_id, noadd)) {
+    if (noadd && SILC_ID_CLIENT_COMPARE(client_id, noadd)) {
       silc_free(client_id);
       continue;
     }
@@ -3479,8 +3542,7 @@ void silc_server_save_users_on_channel(SilcServer server,
       /* We don't have that client anywhere, add it. The client is added
         to global list since server didn't have it in the lists so it must be 
         global. */
-      client = silc_idlist_add_client(server->global_list, NULL, 0, NULL, 
-                                     NULL, 
+      client = silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
                                      silc_id_dup(client_id, SILC_ID_CLIENT), 
                                      sock->user_data, NULL);
       if (!client) {
@@ -3598,6 +3660,7 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   unsigned char *cid;
+  uint32 id_len;
   uint16 name_len;
   int len;
 
@@ -3609,9 +3672,10 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
       continue;
 
     cid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+    id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
     name_len = strlen(channel->channel_name);
     
-    len = 4 + name_len + SILC_ID_CHANNEL_LEN + 4;
+    len = 4 + name_len + id_len + 4;
     buffer = silc_buffer_realloc(buffer, 
                                 (buffer ? (buffer)->truelen + len : len));
     silc_buffer_pull_tail(buffer, ((buffer)->end - (buffer)->data));
@@ -3619,8 +3683,8 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
                       SILC_STR_UI_SHORT(name_len),
                       SILC_STR_UI_XNSTRING(channel->channel_name, 
                                            name_len),
-                      SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
-                      SILC_STR_UI_XNSTRING(cid, SILC_ID_CHANNEL_LEN),
+                      SILC_STR_UI_SHORT(id_len),
+                      SILC_STR_UI_XNSTRING(cid, id_len),
                       SILC_STR_UI_INT(chl->mode), /* Client's mode */
                       SILC_STR_END);
     silc_buffer_pull(buffer, len);