updates.
[silc.git] / apps / silcd / server.c
index 7a88cad30610d813ca94849c8330c06649ee582c..eaa5eaf4f7abd23e0cdcfafe8ef2c89948eae861 100644 (file)
@@ -947,7 +947,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
   SilcSocketConnection newsocket;
   SilcServerKEInternalContext *proto_ctx;
   int sock, port;
-  void *config;
+  void *cconfig, *sconfig, *rconfig;
+  SilcServerConfigSectionDenyConnection *deny;
 
   SILC_LOG_DEBUG(("Accepting new connection"));
 
@@ -1003,34 +1004,49 @@ 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 (!(config = silc_server_config_find_client_conn(server->config,
+  if (!(cconfig = silc_server_config_find_client_conn(server->config,
+                                                     newsocket->ip, port)))
+    cconfig = silc_server_config_find_client_conn(server->config,
+                                                 newsocket->hostname, 
+                                                 port);
+  if (!(sconfig = silc_server_config_find_server_conn(server->config,
+                                                    newsocket->ip, 
+                                                    port)))
+    sconfig = silc_server_config_find_server_conn(server->config,
+                                                 newsocket->hostname,
+                                                 port);
+  if (!(rconfig = silc_server_config_find_router_conn(server->config,
                                                     newsocket->ip, port)))
-    if (!(config = silc_server_config_find_client_conn(server->config,
-                                                      newsocket->hostname, 
-                                                      port)))
-      if (!(config = silc_server_config_find_server_conn(server->config,
-                                                        newsocket->ip, 
-                                                        port)))
-       if (!(config = silc_server_config_find_server_conn(server->config,
-                                                          newsocket->hostname,
-                                                          port)))
-         if (!(config = 
-               silc_server_config_find_router_conn(server->config,
-                                                   newsocket->ip, port)))
-           if (!(config = 
-                 silc_server_config_find_router_conn(server->config,
-                                                     newsocket->hostname, 
-                                                     port))) {
-             silc_server_disconnect_remote(server, newsocket, 
-                                           "Server closed connection: "
-                                           "Connection refused");
-             server->stat.conn_failures++;
-             return;
-           }
+    rconfig = silc_server_config_find_router_conn(server->config,
+                                                 newsocket->hostname, 
+                                                 port);
+  if (!cconfig && !sconfig && !rconfig) {
+    silc_server_disconnect_remote(server, newsocket, 
+                                 "Server closed connection: "
+                                 "Connection refused");
+    server->stat.conn_failures++;
+    return;
+  }
 
   /* The connection is allowed */
 
@@ -1044,7 +1060,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
   proto_ctx->sock = newsocket;
   proto_ctx->rng = server->rng;
   proto_ctx->responder = TRUE;
-  proto_ctx->config = config;
+  proto_ctx->cconfig = cconfig;
+  proto_ctx->sconfig = sconfig;
+  proto_ctx->rconfig = rconfig;
 
   /* Prepare the connection for key exchange protocol. We allocate the
      protocol but will not start it yet. The connector will be the
@@ -1143,7 +1161,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
   proto_ctx->responder = TRUE;
   proto_ctx->dest_id_type = ctx->dest_id_type;
   proto_ctx->dest_id = ctx->dest_id;
-  proto_ctx->config = ctx->config;
+  proto_ctx->cconfig = ctx->cconfig;
+  proto_ctx->sconfig = ctx->sconfig;
+  proto_ctx->rconfig = ctx->rconfig;
 
   /* Free old protocol as it is finished now */
   silc_protocol_free(protocol);
@@ -1243,7 +1263,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   case SILC_SOCKET_TYPE_ROUTER:
     {
       SilcServerEntry new_server;
-      SilcServerConfigSectionServerConnection *conn = ctx->config;
+      SilcServerConfigSectionServerConnection *conn = 
+       sock->type == SILC_SOCKET_TYPE_SERVER ? ctx->sconfig : ctx->rconfig;
 
       SILC_LOG_DEBUG(("Remote host is %s", 
                      sock->type == SILC_SOCKET_TYPE_SERVER ? 
@@ -1517,7 +1538,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;
       }
@@ -2209,7 +2230,8 @@ void silc_server_free_sock_user_data(SilcServer server,
 
       /* Free all client entries that this server owns as they will
         become invalid now as well. */
-      silc_server_remove_clients_by_server(server, user_data, TRUE);
+      if (user_data->id)
+       silc_server_remove_clients_by_server(server, user_data, TRUE);
 
       /* If this was our primary router connection then we're lost to
         the outside world. */
@@ -2534,8 +2556,6 @@ void silc_server_remove_from_channels(SilcServer server,
                                           signoff_message, signoff_message ?
                                           strlen(signoff_message) : 0);
 
-      server->stat.my_channels--;
-
       if (channel->rekey)
        silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
 
@@ -2556,6 +2576,7 @@ void silc_server_remove_from_channels(SilcServer server,
 
       if (!silc_idlist_del_channel(server->local_list, channel))
        silc_idlist_del_channel(server->global_list, channel);
+      server->stat.my_channels--;
       continue;
     }
 
@@ -2649,7 +2670,6 @@ int silc_server_remove_from_one_channel(SilcServer server,
                                           SILC_NOTIFY_TYPE_LEAVE, 1,
                                           clidp->data, clidp->len);
 
-      server->stat.my_channels--;
       silc_buffer_free(clidp);
 
       if (channel->rekey)
@@ -2672,6 +2692,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
 
       if (!silc_idlist_del_channel(server->local_list, channel))
        silc_idlist_del_channel(server->global_list, channel);
+      server->stat.my_channels--;
       return FALSE;
     }
 
@@ -3207,24 +3228,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"));
 
@@ -3233,8 +3256,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, 
@@ -3246,8 +3272,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);
 }
@@ -3259,7 +3305,8 @@ 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;
@@ -3297,7 +3344,8 @@ void silc_server_announce_get_channels(SilcServer server,
        silc_buffer_pull(*channels, len);
 
        silc_server_announce_get_channel_users(server, channel,
-                                              channel_users);
+                                              channel_users,
+                                              channel_users_modes);
 
        silc_free(cid);
 
@@ -3316,17 +3364,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);
@@ -3354,6 +3404,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