Add option to change user and group after initialization. Naughtily
[fwd] / fw.c
diff --git a/fw.c b/fw.c
index 4db1fdb..68871a6 100644 (file)
--- a/fw.c
+++ b/fw.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: fw.c,v 1.6 1999/12/22 15:44:10 mdw Exp $
+ * $Id: fw.c,v 1.7 2000/03/23 00:37:33 mdw Exp $
  *
  * Port forwarding thingy
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: fw.c,v $
+ * Revision 1.7  2000/03/23 00:37:33  mdw
+ * Add option to change user and group after initialization.  Naughtily
+ * reassign short equivalents of --grammar and --options.
+ *
  * Revision 1.6  1999/12/22 15:44:10  mdw
  * Make syslog a separate option, and do it better.
  *
@@ -67,6 +71,9 @@
 #include <unistd.h>
 #include <syslog.h>
 
+#include <grp.h>
+#include <pwd.h>
+
 #include <mLib/bres.h>
 #include <mLib/dstr.h>
 #include <mLib/mdwopt.h>
@@ -212,13 +219,15 @@ are:\n\
 -v, --version    Display the program's version number.\n\
 -u, --usage      Display a terse usage summary.\n\
 \n\
--g, --grammar    Show a summary of the configuration language.\n\
--o, --options    Show a summary of the source and target options.\n\
+-G, --grammar    Show a summary of the configuration language.\n\
+-O, --options    Show a summary of the source and target options.\n\
 \n\
 -f, --file=FILE          Read configuration from a file.\n\
 -q, --quiet      Don't emit any logging information.\n\
 -d, --daemon     Fork into background after initializing.\n\
 -l, --syslog     Send log output to the system logger.\n\
+-s, --setuid=USER Change uid to USER after initializing sources.\n\
+-g, --setgid=GRP  Change gid to GRP after initializing sources.\n\
 \n\
 Configuration may be supplied in one or more configuration files, or on\n\
 the command line (or both).  If no `-f' option is present, and no\n\
@@ -344,6 +353,8 @@ int main(int argc, char *argv[])
   sel_state sst;
   sig s_term, s_int;
   scanner sc;
+  uid_t drop = -1;
+  gid_t dropg = -1;
 
   enum {
     f_bogus = 1,
@@ -405,12 +416,16 @@ int main(int argc, char *argv[])
       { "syslog",      0,              0,      'l' },
       { "log",         0,              0,      'l' },
       { "quiet",       0,              0,      'q' },
+      { "setuid",      OPTF_ARGREQ,    0,      's' },
+      { "uid",         OPTF_ARGREQ,    0,      's' },
+      { "setgid",      OPTF_ARGREQ,    0,      'g' },
+      { "gid",         OPTF_ARGREQ,    0,      'g' },
 
       /* --- Magic terminator --- */
 
       { 0,             0,              0,      0 }
     };
-    int i = mdwopt(argc, argv, "+hvu go f:dl", opts, 0, 0, 0);
+    int i = mdwopt(argc, argv, "+hvu GO f:dls:g:", opts, 0, 0, 0);
 
     if (i < 0)
       break;
@@ -427,11 +442,11 @@ int main(int argc, char *argv[])
        usage(stdout);
        exit(0);
        break;
-      case 'g':
+      case 'G':
        grammar(stdout);
        exit(0);
        break;
-      case 'o':
+      case 'O':
        options(stdout);
        exit(0);
        break;
@@ -455,6 +470,32 @@ int main(int argc, char *argv[])
       case 'q':
        flags |= FW_QUIET;
        break;
+      case 's':
+        if (isdigit((unsigned char )optarg[0])) {
+         char *q;
+         drop = strtol(optarg, &q, 0);
+         if (*q)
+           die(1, "bad uid `%s'", optarg);
+       } else {
+         struct passwd *pw = getpwnam(optarg);
+         if (!pw)
+           die(1, "unknown user `%s'", optarg);
+         drop = pw->pw_uid;
+       }
+       break;
+      case 'g':
+        if (isdigit((unsigned char )optarg[0])) {
+         char *q;
+         dropg = strtol(optarg, &q, 0);
+         if (*q)
+           die(1, "bad gid `%s'", optarg);
+       } else {
+         struct group *gr = getgrnam(optarg);
+         if (!gr)
+           die(1, "unknown group `%s'", optarg);
+         dropg = gr->gr_gid;
+       }
+       break;
       default:
        f |= f_bogus;
        break;
@@ -484,6 +525,16 @@ int main(int argc, char *argv[])
 
   conf_parse(&sc);
 
+  /* --- Drop privileges --- */
+
+#ifdef HAVE_SETGROUPS
+  if ((dropg != -1 && (setgid(dropg) || setgroups(1, &dropg))) ||
+#else
+  if ((dropg != -1 && setgid(dropg)) ||
+#endif
+      (drop != -1 && setuid(drop)))
+    die(1, "couldn't drop privileges: %s", strerror(errno));
+
   /* --- Fork into the background --- */
 
   if (f & f_fork) {