chiark / gitweb /
Set group ID and group list.
[secnet.git] / secnet.c
index 274d35a5bc9ff8a5b7860e9f29da1469e42e5a72..775983432821477912ab2e7ff9b878bc935cc354 100644 (file)
--- a/secnet.c
+++ b/secnet.c
@@ -9,17 +9,24 @@
 #include <sys/socket.h>
 #include <arpa/inet.h>
 #include <pwd.h>
+#include <grp.h>
 
 #include "util.h"
 #include "conffile.h"
 #include "process.h"
 
+#if __APPLE__
+/* apple's poll() does not work on char devs */
+# define USE_SELECT 1
+#endif
+
 /* XXX should be from autoconf */
 static const char *configfile="/etc/secnet/secnet.conf";
 static const char *sites_key="sites";
 bool_t just_check_config=False;
 static char *userid=NULL;
 static uid_t uid=0;
+static gid_t gid;
 bool_t background=True;
 static char *pidfile=NULL;
 bool_t require_root_privileges=False;
@@ -57,7 +64,7 @@ static void parse_options(int argc, char **argv)
            {"nodetach", 0, 0, 'n'},
            {"silent", 0, 0, 'f'},
            {"quiet", 0, 0, 'f'},
-           {"debug", 1, 0, 'd'},
+           {"debug", 0, 0, 'd'},
            {"config", 1, 0, 'c'},
            {"just-check-config", 0, 0, 'j'},
            {"sites-key", 1, 0, 's'},
@@ -82,7 +89,7 @@ static void parse_options(int argc, char **argv)
                   "  -s, --sites-key=name    configuration key that "
                   "specifies active sites\n"
                   "  -n, --nodetach          do not run in background\n"
-                  "  -d, --debug=item,...    set debug options\n"
+                  "  -d, --debug             output debug messages\n"
                   "      --help              display this help and exit\n"
                   "      --version           output version information "
                   "and exit\n"
@@ -136,6 +143,7 @@ static void parse_options(int argc, char **argv)
            break;
 
        case '?':
+           exit(1);
            break;
 
        default:
@@ -176,17 +184,10 @@ static void setup(dict_t *config)
     /* Who are we supposed to run as? */
     userid=dict_read_string(system,"userid",False,"system",loc);
     if (userid) {
-       do {
-           pw=getpwent();
-           if (pw && strcmp(pw->pw_name,userid)==0) {
-               uid=pw->pw_uid;
-               break;
-           }
-       } while(pw);
-       endpwent();
-       if (uid==0) {
+       if(!(pw=getpwnam(userid)))
            fatal("userid \"%s\" not found",userid);
-       }
+       uid=pw->pw_uid;
+       gid=pw->pw_gid;
     }
 
     /* Pidfile name */
@@ -247,6 +248,41 @@ static void system_phase_hook(void *sst, uint32_t newphase)
     }
 }
 
+#if USE_SELECT
+static int fakepoll(struct pollfd *fds, int nfds, int timeout) {
+    fd_set infds[1], outfds[1];
+    int maxfd = -1, i, rc;
+    struct timeval tvtimeout;
+    FD_ZERO(infds);
+    FD_ZERO(outfds);
+    for(i = 0; i < nfds; ++i) {
+       if(fds[i].events & POLLIN)
+           FD_SET(fds[i].fd, infds);
+       if(fds[i].events & POLLOUT)
+           FD_SET(fds[i].fd, outfds);
+       if(fds[i].fd > maxfd)
+           maxfd = fds[i].fd;
+    }
+    if(timeout != -1) {
+       tvtimeout.tv_sec = timeout / 1000;
+       tvtimeout.tv_usec = 1000 * (timeout % 1000);
+    }
+    rc = select(maxfd + 1, infds, outfds, NULL, 
+               timeout == -1 ? NULL : &tvtimeout);
+    if(rc >= 0) {
+       for(i = 0; i < nfds; ++i) {
+           int revents = 0;
+           if(FD_ISSET(fds[i].fd, infds))
+               revents |= POLLIN;
+           if(FD_ISSET(fds[i].fd, outfds))
+               revents |= POLLOUT;
+           fds[i].revents = revents;
+       }
+    }
+    return rc;
+}
+#endif
+
 struct timeval tv_now_global;
 uint64_t now_global;
 
@@ -269,6 +305,12 @@ static void run(void)
                   ((uint64_t)tv_now_global.tv_usec/(uint64_t)1000);
        idx=0;
        for (i=reg; i; i=i->next) {
+           int check;
+           for (check=0; check<i->nfds; check++) {
+               if(fds[idx+check].revents & POLLNVAL) {
+                   fatal("run: poll (%s#%d) set POLLNVAL", i->desc, check);
+               }
+           }
            i->after(i->state, fds+idx, i->nfds);
            idx+=i->nfds;
        }
@@ -292,7 +334,11 @@ static void run(void)
        }
        do {
            if (finished) break;
+#if USE_SELECT
+           rv=fakepoll(fds, idx, timeout);
+#else
            rv=poll(fds, idx, timeout);
+#endif
            if (rv<0) {
                if (errno!=EINTR) {
                    fatal_perror("run: poll");
@@ -325,10 +371,18 @@ static void droppriv(void)
     }
 
     /* Now drop privileges */
-    if (uid!=0) {
+    if (userid) {
+       if (setgid(gid)!=0)
+           fatal_perror("can't set gid to %ld",(long)gid);
+       if(initgroups(userid, gid) < 0)
+           fatal_perror("initgroups"); 
        if (setuid(uid)!=0) {
            fatal_perror("can't set uid to \"%s\"",userid);
        }
+       assert(getuid() == uid);
+       assert(geteuid() == uid);
+       assert(getgid() == gid);
+       assert(getegid() == gid);
     }
     if (background) {
        p=fork();