]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/setpriv.c
misc: cosmetics, remove argument from usage(FILE*)
[thirdparty/util-linux.git] / sys-utils / setpriv.c
1 /*
2 * setpriv(1) - set various kernel privilege bits and run something
3 *
4 * Copyright (C) 2012 Andy Lutomirski <luto@amacapital.net>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <cap-ng.h>
22 #include <errno.h>
23 #include <getopt.h>
24 #include <grp.h>
25 #include <linux/securebits.h>
26 #include <pwd.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/prctl.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33
34 #include "c.h"
35 #include "closestream.h"
36 #include "nls.h"
37 #include "optutils.h"
38 #include "strutils.h"
39 #include "xalloc.h"
40 #include "pathnames.h"
41
42 #ifndef PR_SET_NO_NEW_PRIVS
43 # define PR_SET_NO_NEW_PRIVS 38
44 #endif
45 #ifndef PR_GET_NO_NEW_PRIVS
46 # define PR_GET_NO_NEW_PRIVS 39
47 #endif
48
49 #define SETPRIV_EXIT_PRIVERR 127 /* how we exit when we fail to set privs */
50
51 /*
52 * Note: We are subject to https://bugzilla.redhat.com/show_bug.cgi?id=895105
53 * and we will therefore have problems if new capabilities are added. Once
54 * that bug is fixed, I'll (Andy Lutomirski) submit a corresponding fix to
55 * setpriv. In the mean time, the code here tries to work reasonably well.
56 */
57
58 struct privctx {
59 unsigned int
60 nnp:1, /* no_new_privs */
61 have_ruid:1, /* real uid */
62 have_euid:1, /* effective uid */
63 have_rgid:1, /* real gid */
64 have_egid:1, /* effective gid */
65 have_passwd:1, /* passwd entry */
66 have_groups:1, /* add groups */
67 keep_groups:1, /* keep groups */
68 clear_groups:1, /* remove groups */
69 init_groups:1, /* initialize groups */
70 have_securebits:1; /* remove groups */
71
72 /* uids and gids */
73 uid_t ruid, euid;
74 gid_t rgid, egid;
75
76 /* real user passwd entry */
77 struct passwd passwd;
78
79 /* supplementary groups */
80 size_t num_groups;
81 gid_t *groups;
82
83 /* caps */
84 const char *caps_to_inherit;
85 const char *bounding_set;
86
87 /* securebits */
88 int securebits;
89
90 /* LSMs */
91 const char *selinux_label;
92 const char *apparmor_profile;
93 };
94
95 static void __attribute__((__noreturn__)) usage(void)
96 {
97 FILE *out = stdout;
98 fputs(USAGE_HEADER, out);
99 fprintf(out, _(" %s [options] <program> [<argument>...]\n"),
100 program_invocation_short_name);
101
102 fputs(USAGE_SEPARATOR, out);
103 fputs(_("Run a program with different privilege settings.\n"), out);
104
105 fputs(USAGE_OPTIONS, out);
106 fputs(_(" -d, --dump show current state (and do not exec anything)\n"), out);
107 fputs(_(" --nnp, --no-new-privs disallow granting new privileges\n"), out);
108 fputs(_(" --inh-caps <caps,...> set inheritable capabilities\n"), out);
109 fputs(_(" --bounding-set <caps> set capability bounding set\n"), out);
110 fputs(_(" --ruid <uid> set real uid\n"), out);
111 fputs(_(" --euid <uid> set effective uid\n"), out);
112 fputs(_(" --rgid <gid> set real gid\n"), out);
113 fputs(_(" --egid <gid> set effective gid\n"), out);
114 fputs(_(" --reuid <uid> set real and effective uid\n"), out);
115 fputs(_(" --regid <gid> set real and effective gid\n"), out);
116 fputs(_(" --clear-groups clear supplementary groups\n"), out);
117 fputs(_(" --keep-groups keep supplementary groups\n"), out);
118 fputs(_(" --init-groups initialize supplementary groups\n"), out);
119 fputs(_(" --groups <group,...> set supplementary groups\n"), out);
120 fputs(_(" --securebits <bits> set securebits\n"), out);
121 fputs(_(" --selinux-label <label> set SELinux label\n"), out);
122 fputs(_(" --apparmor-profile <pr> set AppArmor profile\n"), out);
123
124 fputs(USAGE_SEPARATOR, out);
125 fputs(USAGE_HELP, out);
126 fputs(USAGE_VERSION, out);
127 fputs(USAGE_SEPARATOR, out);
128 fputs(_(" This tool can be dangerous. Read the manpage, and be careful.\n"), out);
129 fprintf(out, USAGE_MAN_TAIL("setpriv(1)"));
130
131 exit(EXIT_SUCCESS);
132 }
133
134 static int real_cap_last_cap(void)
135 {
136 /* CAP_LAST_CAP is untrustworthy. */
137 static int ret = -1;
138 int matched;
139 FILE *f;
140
141 if (ret != -1)
142 return ret;
143
144 f = fopen(_PATH_PROC_CAPLASTCAP, "r");
145 if (!f) {
146 ret = CAP_LAST_CAP; /* guess */
147 return ret;
148 }
149
150 matched = fscanf(f, "%d", &ret);
151 fclose(f);
152
153 if (matched != 1)
154 ret = CAP_LAST_CAP; /* guess */
155
156 return ret;
157 }
158
159 /* Returns the number of capabilities printed. */
160 static int print_caps(FILE *f, capng_type_t which)
161 {
162 int i, n = 0, max = real_cap_last_cap();
163
164 for (i = 0; i <= max; i++) {
165 if (capng_have_capability(which, i)) {
166 const char *name = capng_capability_to_name(i);
167 if (n)
168 fputc(',', f);
169 if (name)
170 fputs(name, f);
171 else
172 /* cap-ng has very poor handling of
173 * CAP_LAST_CAP changes. This is the
174 * best we can do. */
175 printf("cap_%d", i);
176 n++;
177 }
178 }
179 return n;
180 }
181
182 static void dump_one_secbit(int *first, int *bits, int bit, const char *name)
183 {
184 if (*bits & bit) {
185 if (*first)
186 *first = 0;
187 else
188 printf(",");
189 fputs(name, stdout);
190 *bits &= ~bit;
191 }
192 }
193
194 static void dump_securebits(void)
195 {
196 int first = 1;
197 int bits = prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
198
199 if (bits < 0) {
200 warnx(_("getting process secure bits failed"));
201 return;
202 }
203
204 printf(_("Securebits: "));
205
206 dump_one_secbit(&first, &bits, SECBIT_NOROOT, "noroot");
207 dump_one_secbit(&first, &bits, SECBIT_NOROOT_LOCKED, "noroot_locked");
208 dump_one_secbit(&first, &bits, SECBIT_NO_SETUID_FIXUP,
209 "no_setuid_fixup");
210 dump_one_secbit(&first, &bits, SECBIT_NO_SETUID_FIXUP_LOCKED,
211 "no_setuid_fixup_locked");
212 bits &= ~SECBIT_KEEP_CAPS;
213 dump_one_secbit(&first, &bits, SECBIT_KEEP_CAPS_LOCKED,
214 "keep_caps_locked");
215 if (bits) {
216 if (first)
217 first = 0;
218 else
219 printf(",");
220 printf("0x%x", (unsigned)bits);
221 }
222
223 if (first)
224 printf(_("[none]\n"));
225 else
226 printf("\n");
227 }
228
229 static void dump_label(const char *name)
230 {
231 char buf[4097];
232 ssize_t len;
233 int fd, e;
234
235 fd = open(_PATH_PROC_ATTR_CURRENT, O_RDONLY);
236 if (fd == -1) {
237 warn(_("cannot open %s"), _PATH_PROC_ATTR_CURRENT);
238 return;
239 }
240
241 len = read(fd, buf, sizeof(buf));
242 e = errno;
243 close(fd);
244 if (len < 0) {
245 errno = e;
246 warn(_("cannot read %s"), name);
247 return;
248 }
249 if (sizeof(buf) - 1 <= (size_t)len) {
250 warnx(_("%s: too long"), name);
251 return;
252 }
253
254 buf[len] = 0;
255 if (0 < len && buf[len - 1] == '\n')
256 buf[len - 1] = 0;
257 printf("%s: %s\n", name, buf);
258 }
259
260 static void dump_groups(void)
261 {
262 int n = getgroups(0, NULL);
263 gid_t *groups;
264
265 if (n < 0) {
266 warn("getgroups failed");
267 return;
268 }
269
270 groups = xmalloc(n * sizeof(gid_t));
271 n = getgroups(n, groups);
272 if (n < 0) {
273 free(groups);
274 warn("getgroups failed");
275 return;
276 }
277
278 printf(_("Supplementary groups: "));
279 if (n == 0)
280 printf(_("[none]"));
281 else {
282 int i;
283 for (i = 0; i < n; i++) {
284 if (0 < i)
285 printf(",");
286 printf("%ld", (long)groups[i]);
287 }
288 }
289 printf("\n");
290 free(groups);
291 }
292
293 static void dump(int dumplevel)
294 {
295 int x;
296 uid_t ru, eu, su;
297 gid_t rg, eg, sg;
298
299 if (getresuid(&ru, &eu, &su) == 0) {
300 printf(_("uid: %u\n"), ru);
301 printf(_("euid: %u\n"), eu);
302 /* Saved and fs uids always equal euid. */
303 if (3 <= dumplevel)
304 printf(_("suid: %u\n"), su);
305 } else
306 warn(_("getresuid failed"));
307
308 if (getresgid(&rg, &eg, &sg) == 0) {
309 printf("gid: %ld\n", (long)rg);
310 printf("egid: %ld\n", (long)eg);
311 /* Saved and fs gids always equal egid. */
312 if (dumplevel >= 3)
313 printf("sgid: %ld\n", (long)sg);
314 } else
315 warn(_("getresgid failed"));
316
317 dump_groups();
318
319 x = prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0);
320 if (0 <= x)
321 printf("no_new_privs: %d\n", x);
322 else
323 warn("setting no_new_privs failed");
324
325 if (2 <= dumplevel) {
326 printf(_("Effective capabilities: "));
327 if (print_caps(stdout, CAPNG_EFFECTIVE) == 0)
328 printf(_("[none]"));
329 printf("\n");
330
331 printf(_("Permitted capabilities: "));
332 if (print_caps(stdout, CAPNG_PERMITTED) == 0)
333 printf(_("[none]"));
334 printf("\n");
335 }
336
337 printf(_("Inheritable capabilities: "));
338 if (print_caps(stdout, CAPNG_INHERITABLE) == 0)
339 printf(_("[none]"));
340 printf("\n");
341
342 printf(_("Capability bounding set: "));
343 if (print_caps(stdout, CAPNG_BOUNDING_SET) == 0)
344 printf(_("[none]"));
345 printf("\n");
346
347 dump_securebits();
348
349 if (access(_PATH_SYS_SELINUX, F_OK) == 0)
350 dump_label(_("SELinux label"));
351
352 if (access(_PATH_SYS_APPARMOR, F_OK) == 0) {
353 dump_label(_("AppArmor profile"));
354 }
355 }
356
357 static void list_known_caps(void)
358 {
359 int i, max = real_cap_last_cap();
360
361 for (i = 0; i <= max; i++) {
362 const char *name = capng_capability_to_name(i);
363 if (name)
364 printf("%s\n", name);
365 else
366 warnx(_("cap %d: libcap-ng is broken"), i);
367 }
368 }
369
370 static void parse_groups(struct privctx *opts, const char *str)
371 {
372 char *groups = xstrdup(str);
373 char *buf = groups; /* We'll reuse it */
374 char *c;
375 size_t i = 0;
376
377 opts->have_groups = 1;
378 opts->num_groups = 0;
379 while ((c = strsep(&groups, ",")))
380 opts->num_groups++;
381
382 /* Start again */
383 strcpy(buf, str); /* It's exactly the right length */
384 groups = buf;
385
386 opts->groups = xcalloc(opts->num_groups, sizeof(gid_t));
387 while ((c = strsep(&groups, ",")))
388 opts->groups[i++] = (gid_t) strtol_or_err(c,
389 _("Invalid supplementary group id"));
390
391 free(groups);
392 }
393
394 static void do_setresuid(const struct privctx *opts)
395 {
396 uid_t ruid, euid, suid;
397 if (getresuid(&ruid, &euid, &suid) != 0)
398 err(SETPRIV_EXIT_PRIVERR, _("getresuid failed"));
399 if (opts->have_ruid)
400 ruid = opts->ruid;
401 if (opts->have_euid)
402 euid = opts->euid;
403
404 /* Also copy effective to saved (for paranoia). */
405 if (setresuid(ruid, euid, euid) != 0)
406 err(SETPRIV_EXIT_PRIVERR, _("setresuid failed"));
407 }
408
409 static void do_setresgid(const struct privctx *opts)
410 {
411 gid_t rgid, egid, sgid;
412 if (getresgid(&rgid, &egid, &sgid) != 0)
413 err(SETPRIV_EXIT_PRIVERR, _("getresgid failed"));
414 if (opts->have_rgid)
415 rgid = opts->rgid;
416 if (opts->have_egid)
417 egid = opts->egid;
418
419 /* Also copy effective to saved (for paranoia). */
420 if (setresgid(rgid, egid, egid) != 0)
421 err(SETPRIV_EXIT_PRIVERR, _("setresgid failed"));
422 }
423
424 static void bump_cap(unsigned int cap)
425 {
426 if (capng_have_capability(CAPNG_PERMITTED, cap))
427 capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, cap);
428 }
429
430 static void do_caps(capng_type_t type, const char *caps)
431 {
432 char *my_caps = xstrdup(caps);
433 char *c;
434
435 while ((c = strsep(&my_caps, ","))) {
436 capng_act_t action;
437 if (*c == '+')
438 action = CAPNG_ADD;
439 else if (*c == '-')
440 action = CAPNG_DROP;
441 else
442 errx(EXIT_FAILURE, _("bad capability string"));
443
444 if (!strcmp(c + 1, "all")) {
445 int i;
446 /* It would be really bad if -all didn't drop all
447 * caps. It's better to just fail. */
448 if (real_cap_last_cap() > CAP_LAST_CAP)
449 errx(SETPRIV_EXIT_PRIVERR,
450 _("libcap-ng is too old for \"all\" caps"));
451 for (i = 0; i <= CAP_LAST_CAP; i++)
452 capng_update(action, type, i);
453 } else {
454 int cap = capng_name_to_capability(c + 1);
455 if (0 <= cap)
456 capng_update(action, type, cap);
457 else
458 errx(EXIT_FAILURE,
459 _("unknown capability \"%s\""), c + 1);
460 }
461 }
462
463 free(my_caps);
464 }
465
466 static void parse_securebits(struct privctx *opts, const char *arg)
467 {
468 char *buf = xstrdup(arg);
469 char *c;
470
471 opts->have_securebits = 1;
472 opts->securebits = prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
473 if (opts->securebits < 0)
474 err(SETPRIV_EXIT_PRIVERR, _("getting process secure bits failed"));
475
476 if (opts->securebits & ~(int)(SECBIT_NOROOT |
477 SECBIT_NOROOT_LOCKED |
478 SECBIT_NO_SETUID_FIXUP |
479 SECBIT_NO_SETUID_FIXUP_LOCKED |
480 SECBIT_KEEP_CAPS |
481 SECBIT_KEEP_CAPS_LOCKED))
482 errx(SETPRIV_EXIT_PRIVERR,
483 _("unrecognized securebit set -- refusing to adjust"));
484
485 while ((c = strsep(&buf, ","))) {
486 if (*c != '+' && *c != '-')
487 errx(EXIT_FAILURE, _("bad securebits string"));
488
489 if (!strcmp(c + 1, "all")) {
490 if (*c == '-')
491 opts->securebits = 0;
492 else
493 errx(EXIT_FAILURE,
494 _("+all securebits is not allowed"));
495 } else {
496 int bit;
497 if (!strcmp(c + 1, "noroot"))
498 bit = SECBIT_NOROOT;
499 else if (!strcmp(c + 1, "noroot_locked"))
500 bit = SECBIT_NOROOT_LOCKED;
501 else if (!strcmp(c + 1, "no_setuid_fixup"))
502 bit = SECBIT_NO_SETUID_FIXUP;
503 else if (!strcmp(c + 1, "no_setuid_fixup_locked"))
504 bit = SECBIT_NO_SETUID_FIXUP_LOCKED;
505 else if (!strcmp(c + 1, "keep_caps"))
506 errx(EXIT_FAILURE,
507 _("adjusting keep_caps does not make sense"));
508 else if (!strcmp(c + 1, "keep_caps_locked"))
509 bit = SECBIT_KEEP_CAPS_LOCKED; /* sigh */
510 else
511 errx(EXIT_FAILURE, _("unrecognized securebit"));
512
513 if (*c == '+')
514 opts->securebits |= bit;
515 else
516 opts->securebits &= ~bit;
517 }
518 }
519
520 opts->securebits |= SECBIT_KEEP_CAPS; /* We need it, and it's reset on exec */
521
522 free(buf);
523 }
524
525 static void do_selinux_label(const char *label)
526 {
527 int fd;
528 size_t len;
529
530 if (access(_PATH_SYS_SELINUX, F_OK) != 0)
531 errx(SETPRIV_EXIT_PRIVERR, _("SELinux is not running"));
532
533 fd = open(_PATH_PROC_ATTR_EXEC, O_RDWR);
534 if (fd == -1)
535 err(SETPRIV_EXIT_PRIVERR,
536 _("cannot open %s"), _PATH_PROC_ATTR_EXEC);
537
538 len = strlen(label);
539 errno = 0;
540 if (write(fd, label, len) != (ssize_t) len)
541 err(SETPRIV_EXIT_PRIVERR,
542 _("write failed: %s"), _PATH_PROC_ATTR_EXEC);
543
544 if (close(fd) != 0)
545 err(SETPRIV_EXIT_PRIVERR,
546 _("close failed: %s"), _PATH_PROC_ATTR_EXEC);
547 }
548
549 static void do_apparmor_profile(const char *label)
550 {
551 FILE *f;
552
553 if (access(_PATH_SYS_APPARMOR, F_OK) != 0)
554 errx(SETPRIV_EXIT_PRIVERR, _("AppArmor is not running"));
555
556 f = fopen(_PATH_PROC_ATTR_EXEC, "r+");
557 if (!f)
558 err(SETPRIV_EXIT_PRIVERR,
559 _("cannot open %s"), _PATH_PROC_ATTR_EXEC);
560
561 fprintf(f, "exec %s", label);
562
563 if (close_stream(f) != 0)
564 err(SETPRIV_EXIT_PRIVERR,
565 _("write failed: %s"), _PATH_PROC_ATTR_EXEC);
566 }
567
568 static uid_t get_user(const char *s, const char *err)
569 {
570 struct passwd *pw;
571 long tmp;
572 pw = getpwnam(s);
573 if (pw)
574 return pw->pw_uid;
575 tmp = strtol_or_err(s, err);
576 return tmp;
577 }
578
579 static gid_t get_group(const char *s, const char *err)
580 {
581 struct group *gr;
582 long tmp;
583 gr = getgrnam(s);
584 if (gr)
585 return gr->gr_gid;
586 tmp = strtol_or_err(s, err);
587 return tmp;
588 }
589
590 static struct passwd *get_passwd(const char *s, uid_t *uid, const char *err)
591 {
592 struct passwd *pw;
593 long tmp;
594 pw = getpwnam(s);
595 if (pw) {
596 *uid = pw->pw_uid;
597 } else {
598 tmp = strtol_or_err(s, err);
599 *uid = tmp;
600 pw = getpwuid(*uid);
601 }
602 return pw;
603 }
604
605 static struct passwd *passwd_copy(struct passwd *dst, const struct passwd *src)
606 {
607 struct passwd *rv;
608 rv = memcpy(dst, src, sizeof(*dst));
609 rv->pw_name = xstrdup(rv->pw_name);
610 rv->pw_passwd = xstrdup(rv->pw_passwd);
611 rv->pw_gecos = xstrdup(rv->pw_gecos);
612 rv->pw_dir = xstrdup(rv->pw_dir);
613 rv->pw_shell = xstrdup(rv->pw_shell);
614 return rv;
615 }
616
617 int main(int argc, char **argv)
618 {
619 enum {
620 NNP = CHAR_MAX + 1,
621 RUID,
622 EUID,
623 RGID,
624 EGID,
625 REUID,
626 REGID,
627 CLEAR_GROUPS,
628 KEEP_GROUPS,
629 INIT_GROUPS,
630 GROUPS,
631 INHCAPS,
632 LISTCAPS,
633 CAPBSET,
634 SECUREBITS,
635 SELINUX_LABEL,
636 APPARMOR_PROFILE
637 };
638
639 static const struct option longopts[] = {
640 { "dump", no_argument, NULL, 'd' },
641 { "nnp", no_argument, NULL, NNP },
642 { "no-new-privs", no_argument, NULL, NNP },
643 { "inh-caps", required_argument, NULL, INHCAPS },
644 { "list-caps", no_argument, NULL, LISTCAPS },
645 { "ruid", required_argument, NULL, RUID },
646 { "euid", required_argument, NULL, EUID },
647 { "rgid", required_argument, NULL, RGID },
648 { "egid", required_argument, NULL, EGID },
649 { "reuid", required_argument, NULL, REUID },
650 { "regid", required_argument, NULL, REGID },
651 { "clear-groups", no_argument, NULL, CLEAR_GROUPS },
652 { "keep-groups", no_argument, NULL, KEEP_GROUPS },
653 { "init-groups", no_argument, NULL, INIT_GROUPS },
654 { "groups", required_argument, NULL, GROUPS },
655 { "bounding-set", required_argument, NULL, CAPBSET },
656 { "securebits", required_argument, NULL, SECUREBITS },
657 { "selinux-label", required_argument, NULL, SELINUX_LABEL },
658 { "apparmor-profile", required_argument, NULL, APPARMOR_PROFILE },
659 { "help", no_argument, NULL, 'h' },
660 { "version", no_argument, NULL, 'V' },
661 { NULL, 0, NULL, 0 }
662 };
663
664 static const ul_excl_t excl[] = {
665 /* keep in same order with enum definitions */
666 {CLEAR_GROUPS, KEEP_GROUPS, INIT_GROUPS, GROUPS},
667 {0}
668 };
669 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
670
671 int c;
672 struct privctx opts;
673 struct passwd *pw = NULL;
674 int dumplevel = 0;
675 int total_opts = 0;
676 int list_caps = 0;
677
678 setlocale(LC_ALL, "");
679 bindtextdomain(PACKAGE, LOCALEDIR);
680 textdomain(PACKAGE);
681 atexit(close_stdout);
682
683 memset(&opts, 0, sizeof(opts));
684
685 while ((c = getopt_long(argc, argv, "+dhV", longopts, NULL)) != -1) {
686 err_exclusive_options(c, longopts, excl, excl_st);
687 total_opts++;
688 switch (c) {
689 case 'd':
690 dumplevel++;
691 break;
692 case NNP:
693 if (opts.nnp)
694 errx(EXIT_FAILURE,
695 _("duplicate --no-new-privs option"));
696 opts.nnp = 1;
697 break;
698 case RUID:
699 if (opts.have_ruid)
700 errx(EXIT_FAILURE, _("duplicate ruid"));
701 opts.have_ruid = 1;
702 pw = get_passwd(optarg, &opts.ruid, _("failed to parse ruid"));
703 if (pw) {
704 passwd_copy(&opts.passwd, pw);
705 opts.have_passwd = 1;
706 }
707 break;
708 case EUID:
709 if (opts.have_euid)
710 errx(EXIT_FAILURE, _("duplicate euid"));
711 opts.have_euid = 1;
712 opts.euid = get_user(optarg, _("failed to parse euid"));
713 break;
714 case REUID:
715 if (opts.have_ruid || opts.have_euid)
716 errx(EXIT_FAILURE, _("duplicate ruid or euid"));
717 opts.have_ruid = opts.have_euid = 1;
718 pw = get_passwd(optarg, &opts.ruid, _("failed to parse reuid"));
719 opts.euid = opts.ruid;
720 if (pw) {
721 passwd_copy(&opts.passwd, pw);
722 opts.have_passwd = 1;
723 }
724 break;
725 case RGID:
726 if (opts.have_rgid)
727 errx(EXIT_FAILURE, _("duplicate rgid"));
728 opts.have_rgid = 1;
729 opts.rgid = get_group(optarg, _("failed to parse rgid"));
730 break;
731 case EGID:
732 if (opts.have_egid)
733 errx(EXIT_FAILURE, _("duplicate egid"));
734 opts.have_egid = 1;
735 opts.egid = get_group(optarg, _("failed to parse egid"));
736 break;
737 case REGID:
738 if (opts.have_rgid || opts.have_egid)
739 errx(EXIT_FAILURE, _("duplicate rgid or egid"));
740 opts.have_rgid = opts.have_egid = 1;
741 opts.rgid = opts.egid = get_group(optarg, _("failed to parse regid"));
742 break;
743 case CLEAR_GROUPS:
744 if (opts.clear_groups)
745 errx(EXIT_FAILURE,
746 _("duplicate --clear-groups option"));
747 opts.clear_groups = 1;
748 break;
749 case KEEP_GROUPS:
750 if (opts.keep_groups)
751 errx(EXIT_FAILURE,
752 _("duplicate --keep-groups option"));
753 opts.keep_groups = 1;
754 break;
755 case INIT_GROUPS:
756 if (opts.init_groups)
757 errx(EXIT_FAILURE,
758 _("duplicate --init-groups option"));
759 opts.init_groups = 1;
760 break;
761 case GROUPS:
762 if (opts.have_groups)
763 errx(EXIT_FAILURE,
764 _("duplicate --groups option"));
765 parse_groups(&opts, optarg);
766 break;
767 case LISTCAPS:
768 list_caps = 1;
769 break;
770 case INHCAPS:
771 if (opts.caps_to_inherit)
772 errx(EXIT_FAILURE,
773 _("duplicate --inh-caps option"));
774 opts.caps_to_inherit = optarg;
775 break;
776 case CAPBSET:
777 if (opts.bounding_set)
778 errx(EXIT_FAILURE,
779 _("duplicate --bounding-set option"));
780 opts.bounding_set = optarg;
781 break;
782 case SECUREBITS:
783 if (opts.have_securebits)
784 errx(EXIT_FAILURE,
785 _("duplicate --securebits option"));
786 parse_securebits(&opts, optarg);
787 break;
788 case SELINUX_LABEL:
789 if (opts.selinux_label)
790 errx(EXIT_FAILURE,
791 _("duplicate --selinux-label option"));
792 opts.selinux_label = optarg;
793 break;
794 case APPARMOR_PROFILE:
795 if (opts.apparmor_profile)
796 errx(EXIT_FAILURE,
797 _("duplicate --apparmor-profile option"));
798 opts.apparmor_profile = optarg;
799 break;
800 case 'h':
801 usage();
802 case 'V':
803 printf(UTIL_LINUX_VERSION);
804 return EXIT_SUCCESS;
805 default:
806 errtryhelp(EXIT_FAILURE);
807 }
808 }
809
810 if (dumplevel) {
811 if (total_opts != dumplevel || optind < argc)
812 errx(EXIT_FAILURE,
813 _("--dump is incompatible with all other options"));
814 dump(dumplevel);
815 return EXIT_SUCCESS;
816 }
817
818 if (list_caps) {
819 if (total_opts != 1 || optind < argc)
820 errx(EXIT_FAILURE,
821 _("--list-caps must be specified alone"));
822 list_known_caps();
823 return EXIT_SUCCESS;
824 }
825
826 if (argc <= optind)
827 errx(EXIT_FAILURE, _("No program specified"));
828
829 if ((opts.have_rgid || opts.have_egid)
830 && !opts.keep_groups && !opts.clear_groups && !opts.init_groups
831 && !opts.have_groups)
832 errx(EXIT_FAILURE,
833 _("--[re]gid requires --keep-groups, --clear-groups, --init-groups, or --groups"));
834
835 if (opts.init_groups && !opts.have_ruid)
836 errx(EXIT_FAILURE,
837 _("--init-groups requires --ruid or --reuid"));
838
839 if (opts.init_groups && !opts.have_passwd)
840 errx(EXIT_FAILURE,
841 _("uid %ld not found, --init-groups requires an user that "
842 "can be found on the system"),
843 (long) opts.ruid);
844
845 if (opts.nnp && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
846 err(EXIT_FAILURE, _("disallow granting new privileges failed"));
847
848 if (opts.selinux_label)
849 do_selinux_label(opts.selinux_label);
850 if (opts.apparmor_profile)
851 do_apparmor_profile(opts.apparmor_profile);
852
853 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
854 err(EXIT_FAILURE, _("keep process capabilities failed"));
855
856 /* We're going to want CAP_SETPCAP, CAP_SETUID, and CAP_SETGID if
857 * possible. */
858 bump_cap(CAP_SETPCAP);
859 bump_cap(CAP_SETUID);
860 bump_cap(CAP_SETGID);
861 if (capng_apply(CAPNG_SELECT_CAPS) != 0)
862 err(SETPRIV_EXIT_PRIVERR, _("activate capabilities"));
863
864 if (opts.have_ruid || opts.have_euid) {
865 do_setresuid(&opts);
866 /* KEEPCAPS doesn't work for the effective mask. */
867 if (capng_apply(CAPNG_SELECT_CAPS) != 0)
868 err(SETPRIV_EXIT_PRIVERR, _("reactivate capabilities"));
869 }
870
871 if (opts.have_rgid || opts.have_egid)
872 do_setresgid(&opts);
873
874 if (opts.have_groups) {
875 if (setgroups(opts.num_groups, opts.groups) != 0)
876 err(SETPRIV_EXIT_PRIVERR, _("setgroups failed"));
877 } else if (opts.init_groups) {
878 if (initgroups(opts.passwd.pw_name, opts.passwd.pw_gid) != 0)
879 err(SETPRIV_EXIT_PRIVERR, _("initgroups failed"));
880 } else if (opts.clear_groups) {
881 gid_t x = 0;
882 if (setgroups(0, &x) != 0)
883 err(SETPRIV_EXIT_PRIVERR, _("setgroups failed"));
884 }
885
886 if (opts.have_securebits && prctl(PR_SET_SECUREBITS, opts.securebits, 0, 0, 0) != 0)
887 err(SETPRIV_EXIT_PRIVERR, _("set process securebits failed"));
888
889 if (opts.bounding_set) {
890 do_caps(CAPNG_BOUNDING_SET, opts.bounding_set);
891 errno = EPERM; /* capng doesn't set errno if we're missing CAP_SETPCAP */
892 if (capng_apply(CAPNG_SELECT_BOUNDS) != 0)
893 err(SETPRIV_EXIT_PRIVERR, _("apply bounding set"));
894 }
895
896 if (opts.caps_to_inherit) {
897 do_caps(CAPNG_INHERITABLE, opts.caps_to_inherit);
898 if (capng_apply(CAPNG_SELECT_CAPS) != 0)
899 err(SETPRIV_EXIT_PRIVERR, _("apply capabilities"));
900 }
901
902 execvp(argv[optind], argv + optind);
903
904 err(EXIT_FAILURE, _("cannot execute: %s"), argv[optind]);
905 }