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 }