s6

Mirror/fork of https://skarnet.org/software/s6/
git clone https://ccx.te2000.cz/git/s6
Log | Files | Refs | README | LICENSE

s6-envuidgid.c (4119B)


      1 /* ISC license. */
      2 
      3 #include <string.h>
      4 #include <pwd.h>
      5 #include <grp.h>
      6 #include <errno.h>
      7 #include <limits.h>
      8 
      9 #include <skalibs/types.h>
     10 #include <skalibs/sgetopt.h>
     11 #include <skalibs/strerr.h>
     12 #include <skalibs/djbunix.h>
     13 #include <skalibs/exec.h>
     14 
     15 #define USAGE "s6-envuidgid [ -i | -D defaultuid:defaultgid:defaultgidlist ] [ -u | -g | -B ] [ -n ] account prog..."
     16 #define dieusage() strerr_dieusage(100, USAGE)
     17 
     18 static inline size_t scan_defaults (char const *s, uid_t *uid, gid_t *gid, size_t *n, gid_t *tab)
     19 {
     20   size_t pos = uid_scan(s, uid) ;
     21   if (!pos)
     22   {
     23     if (*s != ':') return 0 ;
     24     *uid = 0 ;
     25   }
     26   s += pos ;
     27   if (!*s) goto zgid ;
     28   if (*s++ != ':') return 0 ;
     29   if (!*s) goto zgid ;
     30   pos = gid_scan(s, gid) ;
     31   if (!pos)
     32   {
     33     if (*s != ':') return 0 ;
     34     *gid = 0 ;
     35   }
     36   s += pos ;
     37   if (!*s) goto zn ;
     38   if (*s++ != ':') return 0 ;
     39   if (!*s) goto zn ;
     40   return gid_scanlist(tab, NGROUPS_MAX, s, n) ;
     41 
     42  zgid:
     43   *gid = 0 ;
     44  zn:
     45   *n = 0 ;
     46   return 1 ;
     47 }
     48 
     49 static int prot_readgroups (char const *name, gid_t *tab, unsigned int max)
     50 {
     51   unsigned int n = 0 ;
     52   for (;;)
     53   {
     54     struct group *gr ;
     55     char **member ;
     56     errno = 0 ;
     57     if (n >= max) break ;
     58     gr = getgrent() ;
     59     if (!gr) break ;
     60     for (member = gr->gr_mem ; *member ; member++)
     61       if (!strcmp(name, *member)) break ;
     62     if (*member) tab[n++] = gr->gr_gid ;
     63   }
     64   endgrent() ;
     65   return errno ? -1 : n ;
     66 }
     67 
     68 int main (int argc, char *const *argv)
     69 {
     70   char const *user = 0 ;
     71   char const *group = 0 ;
     72   unsigned int what = 7 ;
     73   int numfallback = 0 ;
     74   int insist = 1 ;
     75   uid_t uid ;
     76   gid_t gid ;
     77   size_t n ;
     78   gid_t tab[NGROUPS_MAX] ;
     79   PROG = "s6-envuidgid" ;
     80   {
     81     subgetopt l = SUBGETOPT_ZERO ;
     82     for (;;)
     83     {
     84       int opt = subgetopt_r(argc, (char const *const *)argv, "ugBniD:", &l) ;
     85       if (opt == -1) break ;
     86       switch (opt)
     87       {
     88         case 'u' : what = 1 ; break ;
     89         case 'g' : what = 2 ; break ;
     90         case 'B' : what = 3 ; break ;
     91         case 'n' : what &= 3 ; numfallback = 1 ; break ;
     92         case 'i' : insist = 1 ; break ;
     93         case 'D' :
     94           if (!scan_defaults(l.arg, &uid, &gid, &n, tab)) dieusage() ;
     95           insist = 0 ;
     96           break ;
     97         default : dieusage() ;
     98       }
     99     }
    100     argc -= l.ind ; argv += l.ind ;
    101   }
    102   if (argc < 2) dieusage() ;
    103 
    104   switch (what)
    105   {
    106     case 7 : /* account */
    107     case 1 : /* user */
    108       user = argv[0] ;
    109       break ;
    110     case 2 : /* group */
    111       group = argv[0] ;
    112       break ;
    113     case 3 : /* both */
    114     {
    115       char *colon = strchr(argv[0], ':') ;
    116       user = argv[0] ;
    117       if (colon)
    118       {
    119         *colon = 0 ;
    120         group = colon + 1 ;
    121         if (colon == argv[0]) user = 0 ;
    122         if (!group[0]) group = 0 ;
    123       }
    124       break ;
    125     }
    126     default : strerr_dief1x(101, "inconsistent option management - please submit a bug-report") ;
    127   }
    128   
    129   if (group)
    130   {
    131     struct group *gr = getgrnam(group) ;
    132     if (gr) gid = gr->gr_gid ;
    133     else if (numfallback && gid_scan(group, &gid)) ;
    134     else if (insist) strerr_dief2x(1, "unknown group: ", group) ;
    135   }
    136 
    137   if (user)
    138   {
    139     struct passwd *pw = getpwnam(user) ;
    140     if (pw)
    141     {
    142       uid = pw->pw_uid ;
    143       if (what == 7)
    144       {
    145         int r = prot_readgroups(argv[0], tab, NGROUPS_MAX) ;
    146         if (r < 0)
    147           strerr_diefu2sys(111, "get supplementary groups for ", argv[0]) ;
    148         n = r ;
    149         gid = pw->pw_gid ;
    150       }
    151     }
    152     else if (numfallback && uid_scan(user, &uid)) ;
    153     else if (insist) strerr_dief2x(1, "unknown user: ", user) ;
    154   }
    155 
    156   {
    157     size_t pos = 0 ;
    158     char fmt[19 + UID_FMT + (NGROUPS_MAX+1) * GID_FMT] ;
    159     if (what & 1)
    160     {
    161       memcpy(fmt + pos, "UID=", 4) ; pos += 4 ;
    162       pos += uid_fmt(fmt + pos, uid) ;
    163       fmt[pos++] = 0 ;
    164     }  
    165     if (what & 2)
    166     {
    167       memcpy(fmt + pos, "GID=", 4) ; pos += 4 ;
    168       pos += gid_fmt(fmt + pos, gid) ;
    169       fmt[pos++] = 0 ;
    170     }
    171     if (what & 4)
    172     {
    173       memcpy(fmt + pos, "GIDLIST=", 8) ; pos += 8 ;
    174       pos += gid_fmtlist(fmt + pos, tab, n) ;
    175       fmt[pos++] = 0 ;
    176     }
    177     xmexec_m((char const *const *)argv + 1, fmt, pos) ;
    178   }
    179 }