Added [Identity] config entry and forking support to server.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 11 Feb 2001 16:13:01 +0000 (16:13 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 11 Feb 2001 16:13:01 +0000 (16:13 +0000)
A patch from Bostik.

CHANGES
apps/silcd/server.c
apps/silcd/server.h
apps/silcd/serverconfig.c
apps/silcd/serverconfig.h
apps/silcd/silcd.c
doc/example_silcd.conf
includes/clientincludes.h
includes/silcincludes.h

diff --git a/CHANGES b/CHANGES
index c61205c7f785ac2b10861a325bfa9e8da73ce6b0..7de0d269fe5fa10ab750c0f14a4c58ee6282539e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,8 @@
+Sun Feb 11 18:19:51 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added new config entry [Identity] to fork the server and run
+         it as specific user and group.  A patch from Bostik.
+
 Sat Feb 10 21:13:45 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * A big code auditing weekend happening.  Auditing code for 
index 26b214fd3aef7adf1900caa2cd8f0204d25d7be6..34cf7d977d659d9d2902bba671477c9823dc5174 100644 (file)
@@ -349,6 +349,95 @@ 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. */
+
+void silc_server_daemonise(SilcServer server)
+{
+  /* Are we executing silcd as root or a regular user? */
+  if (geteuid()==0) {
+
+     struct passwd *pw;
+     struct group *gr;
+     char *user, *group;
+
+     if (!server->config->identity->user || 
+         !server->config->identity->group) {
+       SILC_LOG_DEBUG(("User and/or group not set"));
+       fprintf(stderr, "User and/or group not set, exiting\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"));
+       SILC_LOG_DEBUG(("User and/or group given as number"));
+       fprintf(stderr, "Invalid user and/or group information\n");
+       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);
+
+    /* 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) {
+      SILC_LOG_DEBUG(("FATAL: silcd will not run at root privileges"));
+      fprintf(stderr, "User and/or group not set. Please set them\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) {
+        SILC_LOG_DEBUG(("Setgid to %s", group));
+      } else {
+        SILC_LOG_DEBUG(("Setgid to %s failed", group));
+        fprintf(stderr, "Tried to setgid %s but no such group. Exiting\n",
+                group);
+        exit(1);
+      }
+      SILC_LOG_DEBUG(("Changing to user nobody"));
+      if(setuid(pw->pw_uid)==0) {
+        SILC_LOG_DEBUG(("Setuid to %s", user));
+      } else {
+        SILC_LOG_DEBUG(("Setuid to %s failed", user));
+        fprintf(stderr, "Tried to setuid %s but no such user. Exiting\n",
+                user);
+        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();
+  }
+}
+
+
 /* Stops the SILC server. This function is used to shutdown the server. 
    This is usually called after the scheduler has returned. After stopping 
    the server one should call silc_server_free. */
index 719c2728b361a541f19c61f29e35b452f3e0d789..24cb37c64352b231d7be87cfa3c402c75b50406e 100644 (file)
@@ -79,6 +79,7 @@ do {                                                                      \
 int silc_server_alloc(SilcServer *new_server);
 void silc_server_free(SilcServer server);
 int silc_server_init(SilcServer server);
+void silc_server_daemonise(SilcServer server);
 void silc_server_run(SilcServer server);
 void silc_server_stop(SilcServer server);
 void silc_server_packet_parse(SilcPacketParserContext *parser_context);
index ffc7e118ab474d1ccc88a71b3d4f033d67eaf081..4e42c44557d3305c07e706303080e4965a17731e 100644 (file)
 
        +<Local IP/UNIX socket path>:<Remote IP>:<Port>
 
+   <Identity>
+
+       This section is used to set both the user and group which silcd
+       sets itself upon starting.
+
+       Format:
+
+       <user>:<group>
+
    <Logging>
 
        This section is used to set various logging files, their paths
@@ -161,6 +170,8 @@ SilcConfigServerSection silc_config_server_sections[] = {
     SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO, 4 },
   { "[ListenPort]", 
     SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT, 3 },
+  { "[Identity]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY, 2 },
   { "[Logging]", 
     SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING, 3 },
   { "[ConnectionClass]", 
@@ -232,6 +243,7 @@ void silc_config_server_free(SilcConfigServer config)
     silc_free(config->server_info);
     silc_free(config->admin_info);
     silc_free(config->listen_port);
+    silc_free(config->identity);
     silc_free(config->conn_class);
     silc_free(config->clients);
     silc_free(config->admins);
@@ -627,6 +639,23 @@ int silc_config_server_parse_lines(SilcConfigServer config,
       checkmask |= (1L << pc->section->type);
       break;
 
+    case SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY:
+
+      if (!config->identity)
+        config->identity = silc_calloc(1, sizeof(*config->identity));
+
+      /* Get user */
+      ret = silc_config_get_token(line, &config->identity->user);
+      if (ret < 0)
+        break;
+      /* Get group */
+      ret = silc_config_get_token(line, &config->identity->group);
+      if (ret < 0)
+        break;
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+
     case SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS:
 
       SILC_SERVER_CONFIG_LIST_ALLOC(config->conn_class);
index e4c76d66f812b785d25c99c46dd074bafc584ec3..0b045fa182bccfe6430b60c8bf9523c530721f9d 100644 (file)
@@ -57,6 +57,13 @@ typedef struct SilcConfigServerSectionListenPortStruct {
   struct SilcConfigServerSectionListenPortStruct *prev;
 } SilcConfigServerSectionListenPort;
 
+/* Holds server's execution identity, or the user and group which
+   to change from root when server starts */
+typedef struct {
+ char *user;
+ char *group;
+} SilcConfigServerSectionIdentity;
+
 /* Holds all the configured log files. */
 typedef struct SilcConfigServerSectionLoggingStruct {
   char *logtype;
@@ -160,6 +167,7 @@ typedef struct {
   SilcConfigServerSectionServerInfo *server_info;
   SilcConfigServerSectionAdminInfo *admin_info;
   SilcConfigServerSectionListenPort *listen_port;
+  SilcConfigServerSectionIdentity *identity;
   SilcConfigServerSectionLogging *logging;
   SilcConfigServerSectionConnectionClass *conn_class;
   SilcConfigServerSectionClientConnection *clients;
@@ -182,6 +190,7 @@ typedef enum {
   SILC_CONFIG_SERVER_SECTION_TYPE_SERVER_INFO,
   SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_INFO,
   SILC_CONFIG_SERVER_SECTION_TYPE_LISTEN_PORT,
+  SILC_CONFIG_SERVER_SECTION_TYPE_IDENTITY,
   SILC_CONFIG_SERVER_SECTION_TYPE_LOGGING,
   SILC_CONFIG_SERVER_SECTION_TYPE_CONNECTION_CLASS,
   SILC_CONFIG_SERVER_SECTION_TYPE_CLIENT_CONNECTION,
index 3732bb14524281f30e3912d1b86aeb5019ce0f21..214fa344eb8b508c0bbf2eb1b35ee05362456af6 100644 (file)
@@ -34,6 +34,7 @@ static struct option long_opts[] =
 {
   { "config-file", 1, NULL, 'f' },
   { "generate-config-file", 0, NULL, 'c' },
+  { "debug", 0, NULL, 'd' },
   { "help", 0, NULL, 'h' },
   { "version", 0, NULL,'V' },
   { NULL, 0, NULL, 0 }
@@ -48,6 +49,7 @@ void silc_usage()
   printf("  -f  --config-file=FILE        Alternate configuration file\n");
   printf("  -c  --generate-config-file    Generate example configuration "
         "file\n");
+  printf("  -d  --debug                   Enable debugging (no daemon)\n");
   printf("  -h  --help                    Display this message\n");
   printf("  -V  --version                 Display version\n");
   exit(0);
@@ -60,11 +62,11 @@ int main(int argc, char **argv)
   char *config_file = NULL;
   SilcServer silcd;
 
-  silc_debug = TRUE;
+  silc_debug = FALSE;
 
   /* Parse command line arguments */
   if (argc > 1) {
-    while ((opt = getopt_long(argc, argv, "cf:hV",
+    while ((opt = getopt_long(argc, argv, "cf:dhV",
                              long_opts, &option_index)) != EOF) {
       switch(opt) 
        {
@@ -83,6 +85,8 @@ int main(int argc, char **argv)
          silc_config_server_print();
          exit(0);
          break;
+       case 'd':
+         silc_debug = TRUE;
        case 'f':
          config_file = strdup(optarg);
          break;
@@ -111,6 +115,11 @@ int main(int argc, char **argv)
   ret = silc_server_init(silcd);
   if (ret == FALSE)
     goto fail;
+
+  if (silc_debug == FALSE)
+    /* Before running the server, fork to background and set
+       both user and group no non-root */    
+    silc_server_daemonise(silcd);
   
   /* Run the server. When this returns the server has been stopped
      and we will exit. */
index b08f05636003a63d3f7d9885ff70896878fe645c..53d05e1c5d51bb20a15a858208af546a213e8b2e 100644 (file)
@@ -33,6 +33,15 @@ sha1::64:20
 #rsa::1024
 #dss::1024
 
+#
+# Run SILC server as specific user and group. The server must be initially
+# run as root.
+#
+# Format: <user>:<group>
+#
+[Identity]
+nobody:nobody
+
 #
 # Server's administrative information.
 #
index d579b1276c8d304ad96dc2566454b10626802567..b1dd3acabab4e7f6b138b4f4fb367a8e789987c7 100644 (file)
@@ -25,7 +25,6 @@
 
 #include <curses.h>
 #include <sys/param.h>
-#include <pwd.h>
 
 #ifdef HAVE_PATHS_H
 #include <paths.h>
index b3c3fc70e52b4226baf276bf2db300e39768526b..80f27486a11174e47fffdae0094fb1641430b0d0 100644 (file)
@@ -34,6 +34,8 @@
 #include <unistd.h>
 #include <string.h>
 #include <stdarg.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include <ctype.h>
 #include <sys/types.h>