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 }