updates.
[silc.git] / apps / silcd / server.c
index 2d76a24a55601af18f326db26893ab2c1f70899c..c831c1586bcede4b0cbd29d08c0e300e8054fa98 100644 (file)
@@ -222,11 +222,32 @@ int silc_server_init(SilcServer server)
     silc_net_set_socket_nonblock(sock[i]);
     server->sock = sock[i];
     
+    /* Add ourselves also to the socket table. The entry allocated above
+       is sent as argument for fast referencing in the future. */
+    silc_socket_alloc(sock[i], SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
+    server->sockets[sock[i]] = newsocket;
+    
+    /* Perform name and address lookups to resolve the listenning address
+       and port. */
+    if (!silc_net_check_local_by_sock(sock[i], &newsocket->hostname, 
+                                     &newsocket->ip)) {
+      if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
+         !newsocket->ip) {
+       SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
+                       newsocket->hostname ? newsocket->hostname :
+                       newsocket->ip ? newsocket->ip : ""));
+       server->stat.conn_failures++;
+       goto err0;
+      }
+      if (!newsocket->hostname)
+       newsocket->hostname = strdup(newsocket->ip);
+    }
+    newsocket->port = silc_net_get_local_port(sock[i]);
+
     /* Create a Server ID for the server. */
-    silc_id_create_server_id(sock[i], server->rng, &id);
-    if (!id) {
+    silc_id_create_server_id(newsocket->ip, newsocket->port, server->rng, &id);
+    if (!id)
       goto err0;
-    }
     
     server->id = id;
     server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
@@ -248,33 +269,10 @@ int silc_server_init(SilcServer server)
     }
     id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     
-    /* Add ourselves also to the socket table. The entry allocated above
-       is sent as argument for fast referencing in the future. */
-    silc_socket_alloc(sock[i], SILC_SOCKET_TYPE_SERVER, id_entry, 
-                     &newsocket);
-
-    server->sockets[sock[i]] = newsocket;
-    
-    /* Perform name and address lookups to resolve the listenning address
-       and port. */
-    if (!silc_net_check_local_by_sock(sock[i], &newsocket->hostname, 
-                                    &newsocket->ip)) {
-      if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
-         !newsocket->ip) {
-       SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
-                       newsocket->hostname ? newsocket->hostname :
-                       newsocket->ip ? newsocket->ip : ""));
-       server->stat.conn_failures++;
-       goto err0;
-      }
-      if (!newsocket->hostname)
-       newsocket->hostname = strdup(newsocket->ip);
-    }
-    newsocket->port = silc_net_get_local_port(sock[i]);
-
     /* Put the allocated socket pointer also to the entry allocated above 
        for fast back-referencing to the socket list. */
-    id_entry->connection = (void *)server->sockets[sock[i]];
+    newsocket->user_data = (void *)id_entry;
+    id_entry->connection = (void *)newsocket;
     server->id_entry = id_entry;
   }
 
@@ -356,19 +354,42 @@ int silc_server_init(SilcServer server)
   return FALSE;
 }
 
-/* Fork server to background and set gid+uid to non-root.
-   Silcd will not run as root, so trying to set either user or group to
-   root will cause silcd to exit. */
+/* Fork server to background and set gid+uid to non-root */
 
 void silc_server_daemonise(SilcServer server)
+{
+  int i;
+
+  i = fork ();
+
+  if (i) {
+    if (i > 0) {
+      if (geteuid())
+        SILC_LOG_DEBUG(("Server started as user"));
+      else
+        SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
+
+      SILC_LOG_DEBUG(("Forking SILC server to background"));
+      exit(0);
+    } else {
+      SILC_LOG_DEBUG(("fork() failed, cannot proceed"));
+      exit(1);
+    }
+  }
+  setsid();
+}
+
+/* Drop root privligies. If this cannot be done, die. */
+
+void silc_server_drop(SilcServer server)
 {
   /* Are we executing silcd as root or a regular user? */
-  if (geteuid()==0) {
-    
+  if (!geteuid()) {
+
     struct passwd *pw;
     struct group *gr;
     char *user, *group;
-    
+
     if (!server->config->identity || !server->config->identity->user || 
        !server->config->identity->group) {
       fprintf(stderr, "Error:"
@@ -378,11 +399,11 @@ void silc_server_daemonise(SilcServer server)
        "\tthe server as non-root user.\n");
       exit(1);
     }
-    
+
     /* Get the values given for user and group in configuration file */
     user=server->config->identity->user;
     group=server->config->identity->group;
-    
+
     /* Check whether the user/group information is text */ 
     if (atoi(user)!=0 || atoi(group)!=0) {
       SILC_LOG_DEBUG(("Invalid user and/or group information"));
@@ -391,27 +412,24 @@ void silc_server_daemonise(SilcServer server)
       fprintf(stderr, "Please assign them as names, not numbers\n");
       exit(1);
     }
-    
+
     /* Catch the nasty incident of string "0" returning 0 from atoi */
     if (strcmp("0", user)==0 || strcmp("0", group)==0) {
       SILC_LOG_DEBUG(("User and/or group configured to 0. Unacceptable"));
       fprintf(stderr, "User and/or group configured to 0. Exiting\n");
       exit(1);
     }
-    
-    pw=getpwnam(user);
-    gr=getgrnam(group);
 
-    if (!pw) {
+    if (!(pw=getpwnam(user))) {
       fprintf(stderr, "No such user %s found\n", user);
       exit(1);
     }
 
-    if (!gr) {
+    if (!(gr=getgrnam(group))) {
       fprintf(stderr, "No such group %s found\n", group);
       exit(1);
     }
-    
+
     /* Check whether user and/or group is set to root. If yes, exit
        immediately. Otherwise, setgid and setuid server to user.group */
     if (gr->gr_gid==0 || pw->pw_uid==0) {
@@ -422,16 +440,8 @@ void silc_server_daemonise(SilcServer server)
        "\tthe server as non-root user.\n");
       exit(1);
     } else {
-      /* Fork server to background, making it a daemon */
-      if (fork()) {
-        SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
-        SILC_LOG_DEBUG(("Forking SILC server to background"));
-        exit(0);
-      } 
-      setsid();
-      
       SILC_LOG_DEBUG(("Changing to group %s", group));
-      if(setgid(gr->gr_gid)==0) {
+      if (setgid(gr->gr_gid)==0) {
         SILC_LOG_DEBUG(("Setgid to %s", group));
       } else {
         SILC_LOG_DEBUG(("Setgid to %s failed", group));
@@ -439,8 +449,21 @@ void silc_server_daemonise(SilcServer server)
                 group);
         exit(1);
       }
-      SILC_LOG_DEBUG(("Changing to user nobody"));
-      if(setuid(pw->pw_uid)==0) {
+#if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS
+      if (setgroups(0, NULL)!=0) {
+        SILC_LOG_DEBUG(("Setgroups to NULL failed"));
+        fprintf(stderr, "Tried to setgroups NULL but failed. Exiting\n");
+        exit(1);
+      }
+      if (initgroups(user, gr->gr_gid)!=0) {
+        SILC_LOG_DEBUG(("Initgroups to user %s (gid=%d) failed", user, gr->gr_gid));
+        fprintf(stderr, "Tried to initgroups %s (gid=%d) but no such user. Exiting\n",
+                user, gr->gr_gid);
+        exit(1);
+      }
+#endif
+      SILC_LOG_DEBUG(("Changing to user %s", user));
+      if (setuid(pw->pw_uid)==0) {
         SILC_LOG_DEBUG(("Setuid to %s", user));
       } else {
         SILC_LOG_DEBUG(("Setuid to %s failed", user));
@@ -449,14 +472,6 @@ void silc_server_daemonise(SilcServer server)
         exit(1);
       }
     }
-  } else {
-    /* Fork server to background, making it a daemon */
-    if (fork()) {
-      SILC_LOG_DEBUG(("Server started as user")); 
-      SILC_LOG_DEBUG(("Forking SILC server to background"));
-      exit(0);
-    }
-    setsid();
   }
 }
 
@@ -2961,7 +2976,8 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   SILC_LOG_DEBUG(("Start"));
 
   /* Decode channel key payload */
-  payload = silc_channel_key_payload_parse(key_payload);
+  payload = silc_channel_key_payload_parse(key_payload->data,
+                                          key_payload->len);
   if (!payload) {
     SILC_LOG_ERROR(("Bad channel key payload, dropped"));
     channel = NULL;