Issue 15 - Patch by tilman2: Drop privileges optionally
[umurmur.git] / src / main.c
index 1b92f50797e931a0807de2ed5f91548844ec9304..36c5f88db63232928ba607e91518c4292a21aacc 100644 (file)
@@ -36,6 +36,8 @@
 #include <sys/stat.h>
 #include <sys/utsname.h>
 #include <fcntl.h>
+#include <pwd.h>
+#include <grp.h>
 #include <signal.h>
 #include <errno.h>
 #include <string.h>
@@ -66,9 +68,63 @@ void lockfile(const char *pidfile)
                Log_fatal("Cannot open PID-file %s for writing", pidfile);
        snprintf(str,16,"%d\n", getpid());
        write(lfp, str, strlen(str)); /* record pid to lockfile */
+       close(lfp);
        Log_info("PID-file: %s", pidfile);
 }
 
+/* Drops privileges (if configured to do so). */
+static void switch_user(void)
+{
+       struct passwd *pwd;
+       struct group *grp = NULL;
+       const char *username, *groupname;
+       gid_t gid;
+
+       username = getStrConf(USERNAME);
+       groupname = getStrConf(GROUPNAME);
+
+       if (!*username) {
+               /* It's an error to specify groupname
+                * but leave username empty.
+                */
+               if (*groupname)
+                       Log_fatal("username missing");
+
+               /* Nothing to do. */
+               return;
+       }
+
+       pwd = getpwnam(username);
+       if (!pwd)
+               Log_fatal("Unknown user '%s'", username);
+
+       if (!*groupname)
+               gid = pwd->pw_gid;
+       else {
+               grp = getgrnam(groupname);
+
+               if (!grp)
+                       Log_fatal("Unknown group '%s'", groupname);
+
+               gid = grp->gr_gid;
+       }
+
+       if (initgroups(pwd->pw_name, gid))
+               Log_fatal("initgroups() failed: %s", strerror(errno));
+
+       if (setgid(gid))
+               Log_fatal("setgid() failed: %s", strerror(errno));
+
+       if (setuid(pwd->pw_uid))
+               Log_fatal("setuid() failed: %s", strerror(errno));
+       
+       if (!grp)
+               grp = getgrgid(gid);
+       if (!grp)
+               Log_fatal("getgrgid() failed: %s", strerror(errno));
+       
+       Log_info("Switch to user '%s' group '%s'", pwd->pw_name, grp->gr_name);
+}
 
 void signal_handler(int sig)
 {
@@ -188,21 +244,28 @@ int main(int argc, char **argv)
                        break;
                }
        }
+
+       /* Logging to terminal if not daemonizing, otherwise to syslog.
+        * Need to initialize logging before calling Conf_init()
+        */
+       if (!nodaemon)
+               Log_init(false);
+       else
+               Log_init(true);
        
-       if (Conf_init(conffile) != 0) {
-               fprintf(stderr, "Configuration error\n");
-               exit(1);
-       }
-               
+       /* Initialize the config subsystem early;
+        * switch_user() will need to read some config variables.
+        */
+       Conf_init(conffile);
+
        if (!nodaemon) {
-               Log_init(false);
                daemonize();
                if (pidfile != NULL)
                        lockfile(pidfile);
+
+               switch_user();
        }
-       else
-               Log_init(true);
-       
+
        signal(SIGCHLD, SIG_IGN); /* ignore child */
        signal(SIGTSTP, SIG_IGN); /* ignore tty signals */
        signal(SIGTTOU, SIG_IGN);