lnstools

Linux namespace tools
git clone https://ccx.te2000.cz/git/lnstools
Log | Files | Refs | README

lns-envuidgid_main.c (4186B)


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