updates.
[silc.git] / apps / silcd / server.c
index d16d3f00d350f8ca05bdabff9e98bdba3b75c286..609b02df49ca39131d1c1bd73c4e2e634e71743f 100644 (file)
@@ -74,18 +74,8 @@ void silc_server_free(SilcServer server)
 {
   if (server) {
 #ifdef SILC_SIM
-    SilcSimContext *sim;
-#endif
-
-    silc_free(server->local_list);
-    silc_free(server->global_list);
-    if (server->rng)
-      silc_rng_free(server->rng);
+    SilcSim sim;
 
-    if (server->pkcs)
-      silc_pkcs_free(server->pkcs);
-
-#ifdef SILC_SIM
     while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
       silc_dlist_del(server->sim, sim);
       silc_sim_free(sim);
@@ -93,9 +83,23 @@ void silc_server_free(SilcServer server)
     silc_dlist_uninit(server->sim);
 #endif
 
+    if (server->rng)
+      silc_rng_free(server->rng);
+    if (server->pkcs)
+      silc_pkcs_free(server->pkcs);
     if (server->pending_commands)
       silc_dlist_uninit(server->pending_commands);
+    if (server->id_entry)
+      silc_idlist_del_server(server->local_list, server->id_entry);
+
+    silc_idcache_free(server->local_list->clients);
+    silc_idcache_free(server->local_list->servers);
+    silc_idcache_free(server->local_list->channels);
+    silc_idcache_free(server->global_list->clients);
+    silc_idcache_free(server->global_list->servers);
+    silc_idcache_free(server->global_list->channels);
 
+    silc_free(server->sockets);
     silc_free(server);
   }
 }
@@ -231,8 +235,7 @@ int silc_server_init(SilcServer server)
        For now, NULL is sent as router. This allocates new entry to
        the ID list. */
     id_entry =
-      silc_idlist_add_server(server->local_list,
-                            server->config->server_info->server_name,
+      silc_idlist_add_server(server->local_list, strdup(server->server_name),
                             server->server_type, server->id, NULL, NULL);
     if (!id_entry) {
       SILC_LOG_ERROR(("Could not add ourselves to cache"));
@@ -765,20 +768,18 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
     conn = sconn->conn;
 
   if (conn) {
-    /* Match found. Use the configured authentication method */
+    /* Match found. Use the configured authentication method. Take only
+       the passphrase, since for public key auth we automatically use
+       our local key pair. */
     if (conn->passphrase) {
-      if (conn->publickey && !server->config->prefer_passphrase_auth) {
-       proto_ctx->auth_data = conn->publickey;
-       proto_ctx->auth_data_len = 0;
+      if (conn->publickeys && !server->config->prefer_passphrase_auth) {
        proto_ctx->auth_meth = SILC_AUTH_PUBLIC_KEY;
       } else {
        proto_ctx->auth_data = strdup(conn->passphrase);
        proto_ctx->auth_data_len = strlen(conn->passphrase);
        proto_ctx->auth_meth = SILC_AUTH_PASSWORD;
       }
-    } else if (conn->publickey) {
-      proto_ctx->auth_data = conn->publickey;
-      proto_ctx->auth_data_len = 0;
+    } else if (conn->publickeys) {
       proto_ctx->auth_meth = SILC_AUTH_PUBLIC_KEY;
     } else {
       proto_ctx->auth_meth = SILC_AUTH_NONE;
@@ -1036,7 +1037,7 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
      later when outgoing data is available. */
   SILC_REGISTER_CONNECTION_FOR_IO(sock->sock);
 
-  SILC_LOG_INFO(("Incoming connection s (%s)", sock->hostname,
+  SILC_LOG_INFO(("Incoming connection %s (%s)", sock->hostname,
                 sock->ip));
 
   port = server->sockets[server->sock]->port; /* Listenning port */
@@ -1286,7 +1287,6 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
   void *id_entry;
   SilcUInt32 hearbeat_timeout = server->config->param.keepalive_secs;
-  SilcUInt32 num_sockets;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1311,43 +1311,22 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
 
   entry->data.last_receive = time(NULL);
 
-  num_sockets = silc_server_num_sockets_by_ip(server, sock->ip);
-
   switch (ctx->conn_type) {
   case SILC_SOCKET_TYPE_CLIENT:
     {
       SilcClientEntry client;
       SilcServerConfigClient *conn = ctx->cconfig;
-      SilcUInt32 max_per_host = server->config->param.connections_max_per_host;
-
-      /* Check for maximum connections limit */
-      if (conn->param) {
-       if (conn->param->connections_max &&
-           server->stat.my_clients >= conn->param->connections_max) {
-         SILC_LOG_INFO(("Server is full, closing %s (%s) connection",
-                        sock->hostname, sock->ip));
-         silc_server_disconnect_remote(server, sock, 
-                                       "Server closed connection: "
-                                       "Server is full, try again later");
-         server->stat.auth_failures++;
-         goto out;
-       }
-
-       max_per_host = conn->param->connections_max_per_host;
-      }
 
-      if (num_sockets > max_per_host) {
-       SILC_LOG_INFO(("Too many connections from %s (%s), closing connection",
-                      sock->hostname, sock->ip));
-       silc_server_disconnect_remote(server, sock, 
-                                     "Server closed connection: "
-                                     "Too many connections from your host");
+      /* Verify whether this connection is after all allowed to connect */
+      if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
+                                         &server->config->param,
+                                         conn->param, ctx->ske)) {
        server->stat.auth_failures++;
        goto out;
       }
 
       SILC_LOG_DEBUG(("Remote host is client"));
-      SILC_LOG_INFO(("Connection s (%s) is client", sock->hostname,
+      SILC_LOG_INFO(("Connection %s (%s) is client", sock->hostname,
                     sock->ip));
 
       /* Add the client to the client ID cache. The nickname and Client ID
@@ -1391,69 +1370,55 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       SilcUInt16 backup_replace_port = 0;
       SilcServerConfigServer *sconn = ctx->sconfig;
       SilcServerConfigRouter *rconn = ctx->rconfig;
-      SilcUInt32 max_per_host = server->config->param.connections_max_per_host;
-
-      if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && rconn) {
-       if (rconn->param) {
-         /* Check for maximum connections limit */
-         if (rconn->param->connections_max &&
-             server->stat.my_routers >= rconn->param->connections_max) {
-           silc_server_disconnect_remote(server, sock, 
-                                         "Server closed connection: "
-                                         "Server is full, try again later");
-           server->stat.auth_failures++;
-           goto out;
-         }
-         max_per_host = rconn->param->connections_max_per_host;
 
-         if (rconn->param->keepalive_secs)
-           hearbeat_timeout = rconn->param->keepalive_secs;
+      if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
+       /* Verify whether this connection is after all allowed to connect */
+       if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
+                                           &server->config->param,
+                                           rconn ? rconn->param : NULL, 
+                                           ctx->ske)) {
+         server->stat.auth_failures++;
+         goto out;
        }
 
-       initiator = rconn->initiator;
-       backup_local = rconn->backup_local;
-       backup_router = rconn->backup_router;
-       backup_replace_ip = rconn->backup_replace_ip;
-       backup_replace_port = rconn->backup_replace_port;
-      }
-
-      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER && sconn) {
-       if (sconn->param) {
-         /* Check for maximum connections limit */
-         if (sconn->param->connections_max &&
-             server->stat.my_servers >= sconn->param->connections_max) {
-           SILC_LOG_INFO(("Server is full, closing %s (%s) connection",
-                          sock->hostname, sock->ip));
-           silc_server_disconnect_remote(server, sock, 
-                                         "Server closed connection: "
-                                         "Server is full, try again later");
-           server->stat.auth_failures++;
-           goto out;
+       if (rconn) {
+         if (rconn->param) {
+           if (rconn->param->keepalive_secs)
+             hearbeat_timeout = rconn->param->keepalive_secs;
          }
-         max_per_host = sconn->param->connections_max_per_host;
 
-         if (sconn->param->keepalive_secs)
-           hearbeat_timeout = sconn->param->keepalive_secs;
+         initiator = rconn->initiator;
+         backup_local = rconn->backup_local;
+         backup_router = rconn->backup_router;
+         backup_replace_ip = rconn->backup_replace_ip;
+         backup_replace_port = rconn->backup_replace_port;
        }
-
-       backup_router = sconn->backup_router;
       }
 
-      if (num_sockets > max_per_host) {
-       SILC_LOG_INFO(("Too many connections from %s (%s), closing connection",
-                      sock->hostname, sock->ip));
-       silc_server_disconnect_remote(server, sock, 
-                                     "Server closed connection: "
-                                     "Too many connections from your host");
-       server->stat.auth_failures++;
-       goto out;
+      if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
+       /* Verify whether this connection is after all allowed to connect */
+       if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
+                                           &server->config->param,
+                                           sconn ? sconn->param : NULL, 
+                                           ctx->ske)) {
+         server->stat.auth_failures++;
+         goto out;
+       }
+       if (sconn) {
+         if (sconn->param) {
+           if (sconn->param->keepalive_secs)
+             hearbeat_timeout = sconn->param->keepalive_secs;
+         }
+
+         backup_router = sconn->backup_router;
+       }
       }
 
       SILC_LOG_DEBUG(("Remote host is %s", 
                      ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
                      "server" : (backup_router ? 
                                  "backup router" : "router")));
-      SILC_LOG_INFO(("Connection s (%s) is %s", sock->hostname,
+      SILC_LOG_INFO(("Connection %s (%s) is %s", sock->hostname,
                     sock->ip, ctx->conn_type == SILC_SOCKET_TYPE_SERVER ? 
                     "server" : (backup_router ? 
                                 "backup router" : "router")));
@@ -1588,9 +1553,6 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
 
     server->stat.packets_sent++;
 
-    if (sock->outbuf->data - sock->outbuf->head)
-     silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
-
     /* Send the packet */
     ret = silc_packet_send(sock, TRUE);
 
@@ -1877,6 +1839,12 @@ void silc_server_packet_parse_type(SilcServer server,
     SILC_LOG_DEBUG(("Disconnect packet"));
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
+    if (silc_string_is_ascii(packet->buffer->data, packet->buffer->len)) {
+      /* Duplicate to null terminate the string. */
+      char *message = silc_memdup(packet->buffer->data, packet->buffer->len);
+      SILC_LOG_ERROR(("%s", message));
+      silc_free(message);
+    }
     break;
 
   case SILC_PACKET_SUCCESS:
@@ -2390,6 +2358,7 @@ void silc_server_disconnect_remote(SilcServer server,
      is tried to be sent immediately. */
   silc_server_packet_send(server, sock, SILC_PACKET_DISCONNECT, 0,  
                          buf, strlen(buf), TRUE);
+  silc_server_packet_queue_purge(server, sock);
 
   /* Mark the connection to be disconnected */
   SILC_SET_DISCONNECTED(sock);
@@ -3831,7 +3800,7 @@ void silc_server_save_users_on_channel(SilcServer server,
     /* Client ID */
     SILC_GET16_MSB(idp_len, user_list->data + 2);
     idp_len += 4;
-    client_id = silc_id_payload_parse_id(user_list->data, idp_len);
+    client_id = silc_id_payload_parse_id(user_list->data, idp_len, NULL);
     silc_buffer_pull(user_list, idp_len);
     if (!client_id)
       continue;
@@ -3886,7 +3855,7 @@ void silc_server_save_users_on_channel(SilcServer server,
 
     silc_free(client_id);
 
-    if (!silc_server_client_on_channel(client, channel)) {
+    if (!silc_server_client_on_channel(client, channel, NULL)) {
       /* Client was not on the channel, add it. */
       SilcChannelClientEntry chl = silc_calloc(1, sizeof(*chl));
       chl->client = client;