about summary refs log tree commit diff
path: root/src/daemontools-extras/s6-envuidgid.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemontools-extras/s6-envuidgid.c')
-rw-r--r--src/daemontools-extras/s6-envuidgid.c108
1 files changed, 68 insertions, 40 deletions
diff --git a/src/daemontools-extras/s6-envuidgid.c b/src/daemontools-extras/s6-envuidgid.c
index 2971e6a..57c178f 100644
--- a/src/daemontools-extras/s6-envuidgid.c
+++ b/src/daemontools-extras/s6-envuidgid.c
@@ -16,17 +16,48 @@
 #define USAGE "s6-envuidgid [ -i | -D defaultuid:defaultgid ] [ -u | -g | -B ] [ -n ] account prog..."
 #define dieusage() strerr_dieusage(100, USAGE)
 
+static inline unsigned int scan_defaults (char const *s, uint64 *uid, gid_t *gid, unsigned int *n, gid_t *tab)
+{
+  unsigned int pos = uint64_scan(s, uid) ;
+  if (!pos)
+  {
+    if (*s != ':') return 0 ;
+    *uid = 0 ;
+  }
+  s += pos ;
+  if (!*s) goto zgid ;
+  if (*s++ != ':') return 0 ;
+  if (!*s) goto zgid ;
+  pos = gid_scan(s, gid) ;
+  if (!pos)
+  {
+    if (*s != ':') return 0 ;
+    *gid = 0 ;
+  }
+  s += pos ;
+  if (!*s) goto zn ;
+  if (*s++ != ':') return 0 ;
+  if (!*s) goto zn ;
+  return gid_scanlist(tab, NGROUPS_MAX, s, n) ;
+
+ zgid:
+  *gid = 0 ;
+ zn:
+  *n = 0 ;
+  return 1 ;
+}
+
 int main (int argc, char *const *argv, char const *const *envp)
 {
   char const *user = 0 ;
   char const *group = 0 ;
-  int what = 0 ;
+  unsigned int what = 7 ;
   int numfallback = 0 ;
   int insist = 1 ;
-  unsigned int pos ;
   uint64 uid ;
   gid_t gid ;
-  char fmt[19 + UINT64_FMT + (NGROUPS_MAX+1) * GID_FMT] ;
+  unsigned int n ;
+  gid_t tab[NGROUPS_MAX] ;
   PROG = "s6-envuidgid" ;
   {
     subgetopt_t l = SUBGETOPT_ZERO ;
@@ -39,27 +70,12 @@ int main (int argc, char *const *argv, char const *const *envp)
         case 'u' : what = 1 ; break ;
         case 'g' : what = 2 ; break ;
         case 'B' : what = 3 ; break ;
-        case 'n' : what = 3 ; numfallback = 1 ; break ;
+        case 'n' : what &= 3 ; numfallback = 1 ; break ;
         case 'i' : insist = 1 ; break ;
         case 'D' :
-        {
-          unsigned int pos = uint64_scan(l.arg, &uid) ;
-          if (!pos)
-          {
-            if (l.arg[pos] != ':') dieusage() ;
-            uid = 0 ;
-          }
-          if (!l.arg[pos]) gid = 0 ;
-          else
-          {
-            if (l.arg[pos++] != ':') dieusage() ;
-            if (!l.arg[pos]) gid = 0 ;
-            else if (!gid0_scan(l.arg + pos, &gid)) dieusage() ;
-          }
+          if (!scan_defaults(l.arg, &uid, &gid, &n, tab)) dieusage() ;
           insist = 0 ;
-          what = 3 ;
           break ;
-        }
         default : dieusage() ;
       }
     }
@@ -69,7 +85,7 @@ int main (int argc, char *const *argv, char const *const *envp)
 
   switch (what)
   {
-    case 0 : /* account */
+    case 7 : /* account */
     case 1 : /* user */
       user = argv[0] ;
       break ;
@@ -77,8 +93,9 @@ int main (int argc, char *const *argv, char const *const *envp)
       group = argv[0] ;
       break ;
     case 3 : /* both */
+    {
+      unsigned int pos = str_chr(argv[0], ':') ;
       user = argv[0] ;
-      pos = str_chr(argv[0], ':') ;
       if (argv[0][pos])
       {
         argv[0][pos] = 0 ;
@@ -87,20 +104,16 @@ int main (int argc, char *const *argv, char const *const *envp)
         if (!group[0]) group = 0 ;
       }
       break ;
+    }
     default : strerr_dief1x(101, "inconsistent option management - please submit a bug-report") ;
   }
   
-  pos = 0 ;
-
   if (group)
   {
     struct group *gr = getgrnam(group) ;
     if (gr) gid = gr->gr_gid ;
     else if (numfallback && gid_scan(group, &gid)) ;
     else if (insist) strerr_dief2x(1, "unknown group: ", group) ;
-    byte_copy(fmt + pos, 4, "GID=") ; pos += 4 ;
-    pos += gid_fmt(fmt + pos, gid) ;
-    fmt[pos++] = 0 ;
   }
 
   if (user)
@@ -109,26 +122,41 @@ int main (int argc, char *const *argv, char const *const *envp)
     if (pw)
     {
       uid = pw->pw_uid ;
-      if (!what)
+      if (what == 7)
       {
-        gid_t tab[NGROUPS_MAX] ;
-        int n = prot_readgroups(argv[0], tab, NGROUPS_MAX) ;
-        if (n < 0)
+        int r = prot_readgroups(argv[0], tab, NGROUPS_MAX) ;
+        if (r < 0)
           strerr_diefu2sys(111, "get supplementary groups for ", argv[0]) ;
-        byte_copy(fmt + pos, 4, "GID=") ; pos += 4 ;
-        pos += gid_fmt(fmt + pos, pw->pw_gid) ;
-        byte_copy(fmt + pos, 9, "\0GIDLIST=") ; pos += 9 ;
-        pos += gid_fmtlist(fmt + pos, tab, n) ;
-        fmt[pos++] = 0 ;
+        n = r ;
+        gid = pw->pw_gid ;
       }
     }
     else if (numfallback && uint64_scan(user, &uid)) ;
     else if (insist) strerr_dief2x(1, "unknown user: ", user) ;
-    byte_copy(fmt + pos, 4, "UID=") ; pos += 4 ;
-    pos += uint64_fmt(fmt + pos, uid) ;
-    fmt[pos++] = 0 ;
   }
 
-  pathexec_r((char const *const *)argv + 1, envp, env_len(envp), fmt, pos) ;
+  {
+    unsigned int pos = 0 ;
+    char fmt[19 + UINT64_FMT + (NGROUPS_MAX+1) * GID_FMT] ;
+    if (what & 1)
+    {
+      byte_copy(fmt + pos, 4, "UID=") ; pos += 4 ;
+      pos += uint64_fmt(fmt + pos, uid) ;
+      fmt[pos++] = 0 ;
+    }  
+    if (what & 2)
+    {
+      byte_copy(fmt + pos, 4, "GID=") ; pos += 4 ;
+      pos += gid_fmt(fmt + pos, gid) ;
+      fmt[pos++] = 0 ;
+    }
+    if (what & 4)
+    {
+      byte_copy(fmt + pos, 8, "GIDLIST=") ; pos += 8 ;
+      pos += gid_fmtlist(fmt + pos, tab, n) ;
+      fmt[pos++] = 0 ;
+    }
+    pathexec_r((char const *const *)argv + 1, envp, env_len(envp), fmt, pos) ;
+  }
   strerr_dieexec(111, argv[1]) ;
 }