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