updates.
[silc.git] / apps / silcd / server.c
index 8f58188eb09208c6ad063a129977e3f3be65435c..64c837a158d1d23d3d655931e7f259e26ecd8bfc 100644 (file)
@@ -143,7 +143,6 @@ int silc_server_init(SilcServer server)
 
   /* Set log files where log message should be saved. */
   server->config->server = server;
-  silc_server_config_setlogfiles(server->config);
  
   /* Register all configured ciphers, PKCS and hash functions. */
   if (!silc_server_config_register_ciphers(server->config))
@@ -284,7 +283,7 @@ int silc_server_init(SilcServer server)
   server->schedule = silc_schedule_init(SILC_SERVER_MAX_CONNECTIONS);
   if (!server->schedule)
     goto err0;
-  
+
   /* Add the first task to the scheduler. This is task that is executed by
      timeout. It expires as soon as the caller calls silc_server_run. This
      task performs authentication protocol and key exchange with our
@@ -305,6 +304,9 @@ int silc_server_init(SilcServer server)
                         SILC_TASK_PRI_NORMAL);
   server->listenning = TRUE;
 
+  /* Send log file configuration */
+  silc_server_config_setlogfiles(server->config, server->schedule);
+
   /* If server connections has been configured then we must be router as
      normal server cannot have server connections, only router connections. */
   if (server->config->servers) {
@@ -329,18 +331,20 @@ int silc_server_init(SilcServer server)
   purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->local_list->clients;
   purge->schedule = server->schedule;
+  purge->timeout = 600;
   silc_schedule_task_add(purge->schedule, 0, 
                         silc_idlist_purge,
-                        (void *)purge, 600, 0,
+                        (void *)purge, purge->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   /* Clients global list */
   purge = silc_calloc(1, sizeof(*purge));
   purge->cache = server->global_list->clients;
   purge->schedule = server->schedule;
+  purge->timeout = 300;
   silc_schedule_task_add(purge->schedule, 0, 
                         silc_idlist_purge,
-                        (void *)purge, 300, 0,
+                        (void *)purge, purge->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
 
   SILC_LOG_DEBUG(("Server initialized"));
@@ -355,27 +359,26 @@ int silc_server_init(SilcServer server)
   return FALSE;
 }
 
-/* Fork server to background and set gid+uid to non-root */
+/* Fork server to background */
 
 void silc_server_daemonise(SilcServer server)
 {
   int i;
 
-  i = fork ();
+  SILC_LOG_DEBUG(("Forking SILC server to background"));
 
-  if (i) {
-    if (i > 0) {
-      if (geteuid())
-        SILC_LOG_DEBUG(("Server started as user"));
-      else
-        SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
+  i = fork();
 
-      SILC_LOG_DEBUG(("Forking SILC server to background"));
-      exit(0);
-    } else {
-      SILC_LOG_DEBUG(("fork() failed, cannot proceed"));
-      exit(1);
-    }
+  if (i < 0) {
+    SILC_LOG_DEBUG(("fork() failed, cannot proceed"));
+    exit(1);
+  }
+  else if (i) {
+    if (geteuid())
+      SILC_LOG_DEBUG(("Server started as user"));
+    else
+      SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
+    exit(0);
   }
   setsid();
 }
@@ -386,7 +389,6 @@ void silc_server_drop(SilcServer server)
 {
   /* Are we executing silcd as root or a regular user? */
   if (!geteuid()) {
-
     struct passwd *pw;
     struct group *gr;
     char *user, *group;
@@ -499,8 +501,11 @@ void silc_server_stop(SilcServer server)
 {
   SILC_LOG_DEBUG(("Stopping server"));
 
-  silc_schedule_stop(server->schedule);
-  silc_schedule_uninit(server->schedule);
+  if (server->schedule) {
+    silc_schedule_stop(server->schedule);
+    silc_schedule_uninit(server->schedule);
+    server->schedule = NULL;
+  }
 
   silc_server_protocols_unregister();
 
@@ -687,6 +692,9 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
        sconn->backup_replace_port = ptr->backup_replace_port;
       }
 
+      if (!server->router_conn && !sconn->backup)
+       server->router_conn = sconn;
+
       silc_schedule_task_add(server->schedule, fd, 
                             silc_server_connect_router,
                             (void *)sconn, 0, 1, SILC_TASK_TIMEOUT, 
@@ -986,6 +994,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
     silc_free(sconn->backup_replace_ip);
     silc_free(sconn);
   }
+  if (sconn == server->router_conn)
+    server->router_conn = NULL;
 
   /* Free the protocol object */
   if (sock->protocol == protocol)
@@ -1078,6 +1088,8 @@ silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
                                                  sock->hostname, 
                                                  port);
   if (!cconfig && !sconfig && !rconfig) {
+    SILC_LOG_INFO(("Connection %s (%s) is not allowed", 
+                   sock->hostname, sock->ip));
     silc_server_disconnect_remote(server, sock, 
                                  "Server closed connection: "
                                  "Connection refused");
@@ -1319,7 +1331,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, NULL, NULL, NULL, NULL, sock);
+                                     NULL, NULL, NULL, NULL, NULL, sock, 0);
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to cache"));
        silc_free(sock->user_data);
@@ -1544,7 +1556,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
        close the connection */
     if (SILC_IS_DISCONNECTING(sock)) {
       if (sock->user_data)
-       silc_server_free_sock_user_data(server, sock);
+       silc_server_free_sock_user_data(server, sock, NULL);
       silc_server_close_connection(server, sock);
       return;
     }
@@ -1552,8 +1564,20 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
     SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
     SILC_SET_DISCONNECTING(sock);
 
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock);
+    if (sock->user_data) {
+      char tmp[128];
+      if (silc_socket_get_error(sock, tmp, sizeof(tmp) - 1))
+       silc_server_free_sock_user_data(server, sock, tmp);
+      else
+       silc_server_free_sock_user_data(server, sock, NULL);
+    } else if (server->router_conn && server->router_conn->sock == sock &&
+            !server->router && server->standalone)
+      silc_schedule_task_add(server->schedule, 0, 
+                            silc_server_connect_to_router, 
+                            server, 1, 0,
+                            SILC_TASK_TIMEOUT,
+                            SILC_TASK_PRI_NORMAL);
+
     silc_server_close_connection(server, sock);
     return;
   }
@@ -1577,9 +1601,23 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
  
   /* Process the packet. This will call the parser that will then
      decrypt and parse the packet. */
-  silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
-                             TRUE : FALSE, cipher, hmac, sequence, 
-                             silc_server_packet_parse, server);
+  ret = silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ? 
+                                   TRUE : FALSE, cipher, hmac, sequence, 
+                                   silc_server_packet_parse, server);
+
+  /* If this socket connection is not authenticated yet and the packet
+     processing failed we will drop the connection since it can be
+     a malicious flooder. */
+  if (sock->type == SILC_SOCKET_TYPE_UNKNOWN && ret == FALSE &&
+      (!sock->protocol || sock->protocol->protocol->type ==
+       SILC_PROTOCOL_SERVER_KEY_EXCHANGE)) {
+    SILC_LOG_DEBUG(("Bad data sent from unknown connection %d", sock->sock));
+    SILC_SET_DISCONNECTING(sock);
+
+    if (sock->user_data)
+      silc_server_free_sock_user_data(server, sock, NULL);
+    silc_server_close_connection(server, sock);
+  }
 }
   
 /* Parses whole packet, received earlier. */
@@ -1631,7 +1669,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 &&
-       memcmp(packet->dst_id, server->id_string, packet->dst_id_len)) {
+       memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
       
       /* Route the packet to fastest route for the destination ID */
       void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len, 
@@ -2288,7 +2326,7 @@ void silc_server_free_client_data(SilcServer server,
                                  SilcSocketConnection sock,
                                  SilcClientEntry client, 
                                  int notify,
-                                 char *signoff)
+                                 const char *signoff)
 {
   FreeClientInternal i = silc_calloc(1, sizeof(*i));
 
@@ -2308,7 +2346,7 @@ void silc_server_free_client_data(SilcServer server,
   /* Remove client from all channels */
   if (notify)
     silc_server_remove_from_channels(server, NULL, client, 
-                                    TRUE, signoff, TRUE);
+                                    TRUE, (char *)signoff, TRUE);
   else
     silc_server_remove_from_channels(server, NULL, client, 
                                     FALSE, NULL, FALSE);
@@ -2337,7 +2375,8 @@ void silc_server_free_client_data(SilcServer server,
    entities. */
 
 void silc_server_free_sock_user_data(SilcServer server, 
-                                    SilcSocketConnection sock)
+                                    SilcSocketConnection sock,
+                                    const char *signoff_message)
 {
   SILC_LOG_DEBUG(("Start"));
 
@@ -2345,7 +2384,8 @@ void silc_server_free_sock_user_data(SilcServer server,
   case SILC_SOCKET_TYPE_CLIENT:
     {
       SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
-      silc_server_free_client_data(server, sock, user_data, TRUE, NULL);
+      silc_server_free_client_data(server, sock, user_data, TRUE, 
+                                  signoff_message);
       break;
     }
   case SILC_SOCKET_TYPE_SERVER:
@@ -2363,7 +2403,7 @@ void silc_server_free_sock_user_data(SilcServer server,
        /* Check whether we have a backup router connection */
        if (!backup_router || backup_router == user_data) {
          silc_schedule_task_add(server->schedule, 0, 
-                                silc_server_connect_to_router,
+                                silc_server_connect_to_router, 
                                 server, 1, 0,
                                 SILC_TASK_TIMEOUT,
                                 SILC_TASK_PRI_NORMAL);
@@ -2715,13 +2755,15 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote)
   /* If we have protocol active we must assure that we call the protocol's
      final callback so that all the memory is freed. */
   if (sock->protocol) {
+    silc_protocol_cancel(sock->protocol, server->schedule);
     sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
     silc_protocol_execute_final(sock->protocol, server->schedule);
+    sock->protocol = NULL;
     return;
   }
 
   if (sock->user_data)
-    silc_server_free_sock_user_data(server, sock);
+    silc_server_free_sock_user_data(server, sock, NULL);
 
   silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                "Connection timeout");
@@ -2773,7 +2815,7 @@ SilcChannelEntry silc_server_create_new_channel(SilcServer server,
   }
   entry = silc_idlist_add_channel(server->local_list, channel_name, 
                                  SILC_CHANNEL_MODE_NONE, channel_id, 
-                                 NULL, key, newhmac);
+                                 NULL, key, newhmac, 0);
   if (!entry) {
     silc_free(channel_name);
     silc_cipher_free(key);
@@ -2844,7 +2886,7 @@ silc_server_create_new_channel_with_id(SilcServer server,
   /* Create the channel */
   entry = silc_idlist_add_channel(server->local_list, channel_name, 
                                  SILC_CHANNEL_MODE_NONE, channel_id, 
-                                 NULL, key, newhmac);
+                                 NULL, key, newhmac, 0);
   if (!entry) {
     silc_free(channel_name);
     return NULL;
@@ -2983,7 +3025,7 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   payload = silc_channel_key_payload_parse(key_payload->data,
                                           key_payload->len);
   if (!payload) {
-    SILC_LOG_ERROR(("Bad channel key payload, dropped"));
+    SILC_LOG_ERROR(("Bad channel key payload received, dropped"));
     channel = NULL;
     goto out;
   }
@@ -3666,13 +3708,16 @@ void silc_server_save_users_on_channel(SilcServer server,
                                       uint32 user_count)
 {
   int i;
+  uint16 idp_len;
+  uint32 mode;
+  SilcClientID *client_id;
+  SilcClientEntry client;
+  SilcIDCacheEntry cache;
+  bool global;
 
-  for (i = 0; i < user_count; i++) {
-    uint16 idp_len;
-    uint32 mode;
-    SilcClientID *client_id;
-    SilcClientEntry client;
+  SILC_LOG_DEBUG(("Start"));
 
+  for (i = 0; i < user_count; i++) {
     /* Client ID */
     SILC_GET16_MSB(idp_len, user_list->data + 2);
     idp_len += 4;
@@ -3689,14 +3734,18 @@ void silc_server_save_users_on_channel(SilcServer server,
       silc_free(client_id);
       continue;
     }
+
+    global = FALSE;
     
     /* Check if we have this client cached already. */
     client = silc_idlist_find_client_by_id(server->local_list, client_id,
-                                          server->server_type, NULL);
-    if (!client)
+                                          server->server_type, &cache);
+    if (!client) {
       client = silc_idlist_find_client_by_id(server->global_list, 
                                             client_id, server->server_type,
-                                            NULL);
+                                            &cache);
+      global = TRUE;
+    }
     if (!client) {
       /* If router did not find such Client ID in its lists then this must
         be bogus client or some router in the net is buggy. */
@@ -3710,7 +3759,7 @@ void silc_server_save_users_on_channel(SilcServer server,
         global. */
       client = silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
                                      silc_id_dup(client_id, SILC_ID_CLIENT), 
-                                     sock->user_data, NULL);
+                                     sock->user_data, NULL, 0);
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
        silc_free(client_id);
@@ -3718,6 +3767,11 @@ void silc_server_save_users_on_channel(SilcServer server,
       }
 
       client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+    } else {
+      /* Found, if it is from global list we'll assure that we won't
+        expire it now that the entry is on channel. */
+      if (global)
+       cache->expire = 0;
     }
 
     silc_free(client_id);
@@ -3868,10 +3922,14 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
    it using WHOIS command. */
 
 SilcClientEntry silc_server_get_client_resolve(SilcServer server,
-                                              SilcClientID *client_id)
+                                              SilcClientID *client_id,
+                                              bool *resolved)
 {
   SilcClientEntry client;
 
+  if (resolved)
+    *resolved = FALSE;
+
   client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                         TRUE, NULL);
   if (!client) {
@@ -3901,6 +3959,10 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server,
                            buffer->data, buffer->len, FALSE);
     silc_buffer_free(idp);
     silc_buffer_free(buffer);
+
+    if (resolved)
+      *resolved = TRUE;
+
     return NULL;
   }