|
20 | 20 | #include <libgen.h>
|
21 | 21 | #undef basename /* Use the GNU version of basename. */
|
22 | 22 | #include <limits.h>
|
| 23 | +#include <pwd.h> |
23 | 24 | #include <sched.h>
|
24 | 25 | #include <stdio.h>
|
25 | 26 | #include <stdlib.h>
|
@@ -213,33 +214,71 @@ strtopid(struct error *err, const char *str, pid_t *pid)
|
213 | 214 | }
|
214 | 215 |
|
215 | 216 | int
|
216 |
| -strtougid(struct error *err, const char *str, uid_t *uid, gid_t *gid) |
| 217 | +strtougid(struct error *err, char *str, uid_t *uid, gid_t *gid) |
217 | 218 | {
|
218 | 219 | char *ptr;
|
219 |
| - uintmax_t n1, n2; |
| 220 | + uintmax_t n; |
| 221 | + struct passwd *passwd = NULL; |
| 222 | + struct group *group = NULL; |
220 | 223 |
|
221 |
| - n1 = strtoumax(str, &ptr, 10); |
222 |
| - if (ptr == str || *ptr != ':') { |
223 |
| - errno = EINVAL; |
224 |
| - goto fail; |
| 224 | + n = strtoumax(str, &ptr, 10); |
| 225 | + if (ptr != str) { |
| 226 | + if (*ptr != '\0' && *ptr != ':') { |
| 227 | + errno = EINVAL; |
| 228 | + goto fail; |
| 229 | + } |
| 230 | + if (n == UINTMAX_MAX || n != (uid_t)n) { |
| 231 | + errno = ERANGE; |
| 232 | + goto fail; |
| 233 | + } |
| 234 | + if (*ptr == ':') |
| 235 | + ++ptr; |
| 236 | + *uid = (uid_t)n; |
| 237 | + } else { |
| 238 | + /* Not a numeric UID, check for a username. */ |
| 239 | + if ((ptr = strchr(str, ':')) != NULL) |
| 240 | + *ptr++ = '\0'; |
| 241 | + if ((passwd = getpwnam(str)) == NULL) { |
| 242 | + errno = ENOENT; |
| 243 | + goto fail; |
| 244 | + } |
| 245 | + *uid = passwd->pw_uid; |
225 | 246 | }
|
226 |
| - str = ptr + 1; |
227 |
| - n2 = strtoumax(str, &ptr, 10); |
228 |
| - if (ptr == str || *ptr != '\0') { |
229 |
| - errno = EINVAL; |
230 |
| - goto fail; |
| 247 | + |
| 248 | + str = ptr; |
| 249 | + if (str == NULL || *str == '\0') { |
| 250 | + /* No group specified, infer it from the UID */ |
| 251 | + if (passwd == NULL && (passwd = getpwuid(*uid)) == NULL) { |
| 252 | + errno = ENOENT; |
| 253 | + goto fail; |
| 254 | + } |
| 255 | + *gid = passwd->pw_gid; |
| 256 | + return (0); |
231 | 257 | }
|
232 |
| - if (n1 == UINTMAX_MAX || n1 != (uid_t)n1 || |
233 |
| - n2 == UINTMAX_MAX || n2 != (gid_t)n2) { |
234 |
| - errno = ERANGE; |
235 |
| - goto fail; |
| 258 | + |
| 259 | + n = strtoumax(str, &ptr, 10); |
| 260 | + if (ptr != str) { |
| 261 | + if (*ptr != '\0') { |
| 262 | + errno = EINVAL; |
| 263 | + goto fail; |
| 264 | + } |
| 265 | + if (n == UINTMAX_MAX || n != (gid_t)n) { |
| 266 | + errno = ERANGE; |
| 267 | + goto fail; |
| 268 | + } |
| 269 | + *gid = (gid_t)n; |
| 270 | + } else { |
| 271 | + /* Not a numeric GID, check for a groupname. */ |
| 272 | + if ((group = getgrnam(str)) == NULL) { |
| 273 | + errno = ENOENT; |
| 274 | + goto fail; |
| 275 | + } |
| 276 | + *gid = group->gr_gid; |
236 | 277 | }
|
237 |
| - *uid = (uid_t)n1; |
238 |
| - *gid = (gid_t)n2; |
239 | 278 | return (0);
|
240 | 279 |
|
241 | 280 | fail:
|
242 |
| - error_set(err, "parse userspec failed"); |
| 281 | + error_set(err, "parse user/group failed"); |
243 | 282 | return (-1);
|
244 | 283 | }
|
245 | 284 |
|
|
0 commit comments