]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/setpriv.c
docs: update year in libs docs
[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 "caputils.h"
36 #include "closestream.h"
37 #include "nls.h"
38 #include "optutils.h"
39 #include "strutils.h"
40 #include "xalloc.h"
41 #include "pathnames.h"
42 #include "signames.h"
43 #include "env.h"
44
45 #ifndef PR_SET_NO_NEW_PRIVS
46 # define PR_SET_NO_NEW_PRIVS 38
47 #endif
48 #ifndef PR_GET_NO_NEW_PRIVS
49 # define PR_GET_NO_NEW_PRIVS 39
50 #endif
51
52 #define SETPRIV_EXIT_PRIVERR 127 /* how we exit when we fail to set privs */
53
54 /* The shell to set SHELL env.variable if none is given in the user's passwd entry. */
55 #define DEFAULT_SHELL "/bin/sh"
56
57 static gid_t get_group(const char *s, const char *err);
58
59 enum cap_type {
60 CAP_TYPE_EFFECTIVE = CAPNG_EFFECTIVE,
61 CAP_TYPE_PERMITTED = CAPNG_PERMITTED,
62 CAP_TYPE_INHERITABLE = CAPNG_INHERITABLE,
63 CAP_TYPE_BOUNDING = CAPNG_BOUNDING_SET,
64 CAP_TYPE_AMBIENT = (1 << 4)
65 };
66
67 /*
68 * Note: We are subject to https://bugzilla.redhat.com/show_bug.cgi?id=895105
69 * and we will therefore have problems if new capabilities are added. Once
70 * that bug is fixed, I'll (Andy Lutomirski) submit a corresponding fix to
71 * setpriv. In the mean time, the code here tries to work reasonably well.
72 */
73
74 struct privctx {
75 unsigned int
76 nnp:1, /* no_new_privs */
77 have_ruid:1, /* real uid */
78 have_euid:1, /* effective uid */
79 have_rgid:1, /* real gid */
80 have_egid:1, /* effective gid */
81 have_passwd:1, /* passwd entry */
82 have_groups:1, /* add groups */
83 keep_groups:1, /* keep groups */
84 clear_groups:1, /* remove groups */
85 init_groups:1, /* initialize groups */
86 reset_env:1, /* reset environment */
87 have_securebits:1; /* remove groups */
88
89 /* uids and gids */
90 uid_t ruid, euid;
91 gid_t rgid, egid;
92
93 /* real user passwd entry */
94 struct passwd passwd;
95
96 /* supplementary groups */
97 size_t num_groups;
98 gid_t *groups;
99
100 /* caps */
101 const char *caps_to_inherit;
102 const char *ambient_caps;
103 const char *bounding_set;
104
105 /* securebits */
106 int securebits;
107 /* parent death signal (<0 clear, 0 nothing, >0 signal) */
108 int pdeathsig;
109
110 /* LSMs */
111 const char *selinux_label;
112 const char *apparmor_profile;
113 };
114
115 static void __attribute__((__noreturn__)) usage(void)
116 {
117 FILE *out = stdout;
118 fputs(USAGE_HEADER, out);
119 fprintf(out, _(" %s [options] <program> [<argument>...]\n"),
120 program_invocation_short_name);
121
122 fputs(USAGE_SEPARATOR, out);
123 fputs(_("Run a program with different privilege settings.\n"), out);
124
125 fputs(USAGE_OPTIONS, out);
126 fputs(_(" -d, --dump show current state (and do not exec)\n"), out);
127 fputs(_(" --nnp, --no-new-privs disallow granting new privileges\n"), out);
128 fputs(_(" --ambient-caps <caps,...> set ambient capabilities\n"), out);
129 fputs(_(" --inh-caps <caps,...> set inheritable capabilities\n"), out);
130 fputs(_(" --bounding-set <caps> set capability bounding set\n"), out);
131 fputs(_(" --ruid <uid|user> set real uid\n"), out);
132 fputs(_(" --euid <uid|user> set effective uid\n"), out);
133 fputs(_(" --rgid <gid|user> set real gid\n"), out);
134 fputs(_(" --egid <gid|group> set effective gid\n"), out);
135 fputs(_(" --reuid <uid|user> set real and effective uid\n"), out);
136 fputs(_(" --regid <gid|group> set real and effective gid\n"), out);
137 fputs(_(" --clear-groups clear supplementary groups\n"), out);
138 fputs(_(" --keep-groups keep supplementary groups\n"), out);
139 fputs(_(" --init-groups initialize supplementary groups\n"), out);
140 fputs(_(" --groups <group,...> set supplementary groups by UID or name\n"), out);
141 fputs(_(" --securebits <bits> set securebits\n"), out);
142 fputs(_(" --pdeathsig keep|clear|<signame>\n"
143 " set or clear parent death signal\n"), out);
144 fputs(_(" --selinux-label <label> set SELinux label\n"), out);
145 fputs(_(" --apparmor-profile <pr> set AppArmor profile\n"), out);
146 fputs(_(" --reset-env clear all environment and initialize\n"
147 " HOME, SHELL, USER, LOGNAME and PATH\n"), out);
148
149 fputs(USAGE_SEPARATOR, out);
150 printf(USAGE_HELP_OPTIONS(29));
151 fputs(USAGE_SEPARATOR, out);
152 fputs(_(" This tool can be dangerous. Read the manpage, and be careful.\n"), out);
153 printf(USAGE_MAN_TAIL("setpriv(1)"));
154
155 exit(EXIT_SUCCESS);
156 }
157
158 static int has_cap(enum cap_type which, unsigned int i)
159 {
160 switch (which) {
161 case CAP_TYPE_EFFECTIVE:
162 case CAP_TYPE_BOUNDING:
163 case CAP_TYPE_INHERITABLE:
164 case CAP_TYPE_PERMITTED:
165 return capng_have_capability((capng_type_t)which, i);
166 case CAP_TYPE_AMBIENT:
167 return prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET,
168 (unsigned long) i, 0UL, 0UL);
169 default:
170 warnx(_("invalid capability type"));
171 return -1;
172 }
173 }
174
175 /* Returns the number of capabilities printed. */
176 static int print_caps(FILE *f, enum cap_type which)
177 {
178 int i, n = 0, max = cap_last_cap();
179
180 for (i = 0; i <= max; i++) {
181 int ret = has_cap(which, i);
182
183 if (i == 0 && ret < 0)
184 return -1;
185
186 if (ret == 1) {
187 const char *name = capng_capability_to_name(i);
188 if (n)
189 fputc(',', f);
190 if (name)
191 fputs(name, f);
192 else
193 /* cap-ng has very poor handling of
194 * CAP_LAST_CAP changes. This is the
195 * best we can do. */
196 printf("cap_%d", i);
197 n++;
198 }
199 }
200
201 return n;
202 }
203
204 static void dump_one_secbit(int *first, int *bits, int bit, const char *name)
205 {
206 if (*bits & bit) {
207 if (*first)
208 *first = 0;
209 else
210 printf(",");
211 fputs(name, stdout);
212 *bits &= ~bit;
213 }
214 }
215
216 static void dump_securebits(void)
217 {
218 int first = 1;
219 int bits = prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
220
221 if (bits < 0) {
222 warnx(_("getting process secure bits failed"));
223 return;
224 }
225
226 printf(_("Securebits: "));
227
228 dump_one_secbit(&first, &bits, SECBIT_NOROOT, "noroot");
229 dump_one_secbit(&first, &bits, SECBIT_NOROOT_LOCKED, "noroot_locked");
230 dump_one_secbit(&first, &bits, SECBIT_NO_SETUID_FIXUP,
231 "no_setuid_fixup");
232 dump_one_secbit(&first, &bits, SECBIT_NO_SETUID_FIXUP_LOCKED,
233 "no_setuid_fixup_locked");
234 bits &= ~SECBIT_KEEP_CAPS;
235 dump_one_secbit(&first, &bits, SECBIT_KEEP_CAPS_LOCKED,
236 "keep_caps_locked");
237 if (bits) {
238 if (first)
239 first = 0;
240 else
241 printf(",");
242 printf("0x%x", (unsigned)bits);
243 }
244
245 if (first)
246 printf(_("[none]\n"));
247 else
248 printf("\n");
249 }
250
251 static void dump_label(const char *name)
252 {
253 char buf[4097];
254 ssize_t len;
255 int fd, e;
256
257 fd = open(_PATH_PROC_ATTR_CURRENT, O_RDONLY);
258 if (fd == -1) {
259 warn(_("cannot open %s"), _PATH_PROC_ATTR_CURRENT);
260 return;
261 }
262
263 len = read(fd, buf, sizeof(buf));
264 e = errno;
265 close(fd);
266 if (len < 0) {
267 errno = e;
268 warn(_("cannot read %s"), name);
269 return;
270 }
271 if (sizeof(buf) - 1 <= (size_t)len) {
272 warnx(_("%s: too long"), name);
273 return;
274 }
275
276 buf[len] = 0;
277 if (0 < len && buf[len - 1] == '\n')
278 buf[len - 1] = 0;
279 printf("%s: %s\n", name, buf);
280 }
281
282 static void dump_groups(void)
283 {
284 int n = getgroups(0, NULL);
285 gid_t *groups;
286
287 if (n < 0) {
288 warn("getgroups failed");
289 return;
290 }
291
292 groups = xmalloc(n * sizeof(gid_t));
293 n = getgroups(n, groups);
294 if (n < 0) {
295 free(groups);
296 warn("getgroups failed");
297 return;
298 }
299
300 printf(_("Supplementary groups: "));
301 if (n == 0)
302 printf(_("[none]"));
303 else {
304 int i;
305 for (i = 0; i < n; i++) {
306 if (0 < i)
307 printf(",");
308 printf("%ld", (long)groups[i]);
309 }
310 }
311 printf("\n");
312 free(groups);
313 }
314
315 static void dump_pdeathsig(void)
316 {
317 int pdeathsig;
318
319 if (prctl(PR_GET_PDEATHSIG, &pdeathsig) != 0) {
320 warn(_("get pdeathsig failed"));
321 return;
322 }
323
324 printf("Parent death signal: ");
325 if (pdeathsig && signum_to_signame(pdeathsig) != NULL)
326 printf("%s\n", signum_to_signame(pdeathsig));
327 else if (pdeathsig)
328 printf("%d\n", pdeathsig);
329 else
330 printf("[none]\n");
331 }
332
333 static void dump(int dumplevel)
334 {
335 int x;
336 uid_t ru, eu, su;
337 gid_t rg, eg, sg;
338
339 if (getresuid(&ru, &eu, &su) == 0) {
340 printf(_("uid: %u\n"), ru);
341 printf(_("euid: %u\n"), eu);
342 /* Saved and fs uids always equal euid. */
343 if (3 <= dumplevel)
344 printf(_("suid: %u\n"), su);
345 } else
346 warn(_("getresuid failed"));
347
348 if (getresgid(&rg, &eg, &sg) == 0) {
349 printf("gid: %ld\n", (long)rg);
350 printf("egid: %ld\n", (long)eg);
351 /* Saved and fs gids always equal egid. */
352 if (dumplevel >= 3)
353 printf("sgid: %ld\n", (long)sg);
354 } else
355 warn(_("getresgid failed"));
356
357 dump_groups();
358
359 x = prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0);
360 if (0 <= x)
361 printf("no_new_privs: %d\n", x);
362 else
363 warn("setting no_new_privs failed");
364
365 if (2 <= dumplevel) {
366 printf(_("Effective capabilities: "));
367 if (print_caps(stdout, CAP_TYPE_EFFECTIVE) == 0)
368 printf(_("[none]"));
369 printf("\n");
370
371 printf(_("Permitted capabilities: "));
372 if (print_caps(stdout, CAP_TYPE_PERMITTED) == 0)
373 printf(_("[none]"));
374 printf("\n");
375 }
376
377 printf(_("Inheritable capabilities: "));
378 if (print_caps(stdout, CAP_TYPE_INHERITABLE) == 0)
379 printf(_("[none]"));
380 printf("\n");
381
382 printf(_("Ambient capabilities: "));
383 x = print_caps(stdout, CAP_TYPE_AMBIENT);
384 if (x == 0)
385 printf(_("[none]"));
386 if (x < 0)
387 printf(_("[unsupported]"));
388 printf("\n");
389
390 printf(_("Capability bounding set: "));
391 if (print_caps(stdout, CAP_TYPE_BOUNDING) == 0)
392 printf(_("[none]"));
393 printf("\n");
394
395 dump_securebits();
396 dump_pdeathsig();
397
398 if (access(_PATH_SYS_SELINUX, F_OK) == 0)
399 dump_label(_("SELinux label"));
400
401 if (access(_PATH_SYS_APPARMOR, F_OK) == 0) {
402 dump_label(_("AppArmor profile"));
403 }
404 }
405
406 static void list_known_caps(void)
407 {
408 int i, max = cap_last_cap();
409
410 for (i = 0; i <= max; i++) {
411 const char *name = capng_capability_to_name(i);
412 if (name)
413 printf("%s\n", name);
414 else
415 warnx(_("cap %d: libcap-ng is broken"), i);
416 }
417 }
418
419 static void parse_groups(struct privctx *opts, const char *str)
420 {
421 char *groups = xstrdup(str);
422 char *buf = groups; /* We'll reuse it */
423 char *c;
424 size_t i = 0;
425
426 opts->have_groups = 1;
427 opts->num_groups = 0;
428 while ((c = strsep(&groups, ",")))
429 opts->num_groups++;
430
431 /* Start again */
432 strcpy(buf, str); /* It's exactly the right length */
433 groups = buf;
434
435 opts->groups = xcalloc(opts->num_groups, sizeof(gid_t));
436 while ((c = strsep(&groups, ",")))
437 opts->groups[i++] = get_group(c, _("Invalid supplementary group id"));
438
439 free(groups);
440 }
441
442 static void parse_pdeathsig(struct privctx *opts, const char *str)
443 {
444 if (!strcmp(str, "keep")) {
445 if (prctl(PR_GET_PDEATHSIG, &opts->pdeathsig) != 0)
446 errx(SETPRIV_EXIT_PRIVERR,
447 _("failed to get parent death signal"));
448 } else if (!strcmp(str, "clear")) {
449 opts->pdeathsig = -1;
450 } else if ((opts->pdeathsig = signame_to_signum(str)) < 0) {
451 errx(EXIT_FAILURE, _("unknown signal: %s"), str);
452 }
453 }
454
455 static void do_setresuid(const struct privctx *opts)
456 {
457 uid_t ruid, euid, suid;
458 if (getresuid(&ruid, &euid, &suid) != 0)
459 err(SETPRIV_EXIT_PRIVERR, _("getresuid failed"));
460 if (opts->have_ruid)
461 ruid = opts->ruid;
462 if (opts->have_euid)
463 euid = opts->euid;
464
465 /* Also copy effective to saved (for paranoia). */
466 if (setresuid(ruid, euid, euid) != 0)
467 err(SETPRIV_EXIT_PRIVERR, _("setresuid failed"));
468 }
469
470 static void do_setresgid(const struct privctx *opts)
471 {
472 gid_t rgid, egid, sgid;
473 if (getresgid(&rgid, &egid, &sgid) != 0)
474 err(SETPRIV_EXIT_PRIVERR, _("getresgid failed"));
475 if (opts->have_rgid)
476 rgid = opts->rgid;
477 if (opts->have_egid)
478 egid = opts->egid;
479
480 /* Also copy effective to saved (for paranoia). */
481 if (setresgid(rgid, egid, egid) != 0)
482 err(SETPRIV_EXIT_PRIVERR, _("setresgid failed"));
483 }
484
485 static void bump_cap(unsigned int cap)
486 {
487 if (capng_have_capability(CAPNG_PERMITTED, cap))
488 capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, cap);
489 }
490
491 static int cap_update(capng_act_t action,
492 enum cap_type type, unsigned int cap)
493 {
494 switch (type) {
495 case CAP_TYPE_EFFECTIVE:
496 case CAP_TYPE_BOUNDING:
497 case CAP_TYPE_INHERITABLE:
498 case CAP_TYPE_PERMITTED:
499 return capng_update(action, (capng_type_t) type, cap);
500 case CAP_TYPE_AMBIENT:
501 {
502 int ret;
503
504 if (action == CAPNG_ADD)
505 ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE,
506 (unsigned long) cap, 0UL, 0UL);
507 else
508 ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER,
509 (unsigned long) cap, 0UL, 0UL);
510
511 return ret;
512 }
513 default:
514 errx(EXIT_FAILURE, _("unsupported capability type"));
515 return -1;
516 }
517 }
518
519 static void do_caps(enum cap_type type, const char *caps)
520 {
521 char *my_caps = xstrdup(caps);
522 char *c;
523
524 while ((c = strsep(&my_caps, ","))) {
525 capng_act_t action;
526 if (*c == '+')
527 action = CAPNG_ADD;
528 else if (*c == '-')
529 action = CAPNG_DROP;
530 else
531 errx(EXIT_FAILURE, _("bad capability string"));
532
533 if (!strcmp(c + 1, "all")) {
534 int i;
535 /* It would be really bad if -all didn't drop all
536 * caps. It's better to just fail. */
537 if (cap_last_cap() > CAP_LAST_CAP)
538 errx(SETPRIV_EXIT_PRIVERR,
539 _("libcap-ng is too old for \"all\" caps"));
540 for (i = 0; i <= CAP_LAST_CAP; i++)
541 cap_update(action, type, i);
542 } else {
543 int cap = capng_name_to_capability(c + 1);
544 if (0 <= cap)
545 cap_update(action, type, cap);
546 else if (sscanf(c + 1, "cap_%d", &cap) == 1
547 && 0 <= cap && cap <= cap_last_cap())
548 cap_update(action, type, cap);
549 else
550 errx(EXIT_FAILURE,
551 _("unknown capability \"%s\""), c + 1);
552 }
553 }
554
555 free(my_caps);
556 }
557
558 static void parse_securebits(struct privctx *opts, const char *arg)
559 {
560 char *buf = xstrdup(arg);
561 char *c;
562
563 opts->have_securebits = 1;
564 opts->securebits = prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
565 if (opts->securebits < 0)
566 err(SETPRIV_EXIT_PRIVERR, _("getting process secure bits failed"));
567
568 if (opts->securebits & ~(int)(SECBIT_NOROOT |
569 SECBIT_NOROOT_LOCKED |
570 SECBIT_NO_SETUID_FIXUP |
571 SECBIT_NO_SETUID_FIXUP_LOCKED |
572 SECBIT_KEEP_CAPS |
573 SECBIT_KEEP_CAPS_LOCKED))
574 errx(SETPRIV_EXIT_PRIVERR,
575 _("unrecognized securebit set -- refusing to adjust"));
576
577 while ((c = strsep(&buf, ","))) {
578 if (*c != '+' && *c != '-')
579 errx(EXIT_FAILURE, _("bad securebits string"));
580
581 if (!strcmp(c + 1, "all")) {
582 if (*c == '-')
583 opts->securebits = 0;
584 else
585 errx(EXIT_FAILURE,
586 _("+all securebits is not allowed"));
587 } else {
588 int bit;
589 if (!strcmp(c + 1, "noroot"))
590 bit = SECBIT_NOROOT;
591 else if (!strcmp(c + 1, "noroot_locked"))
592 bit = SECBIT_NOROOT_LOCKED;
593 else if (!strcmp(c + 1, "no_setuid_fixup"))
594 bit = SECBIT_NO_SETUID_FIXUP;
595 else if (!strcmp(c + 1, "no_setuid_fixup_locked"))
596 bit = SECBIT_NO_SETUID_FIXUP_LOCKED;
597 else if (!strcmp(c + 1, "keep_caps"))
598 errx(EXIT_FAILURE,
599 _("adjusting keep_caps does not make sense"));
600 else if (!strcmp(c + 1, "keep_caps_locked"))
601 bit = SECBIT_KEEP_CAPS_LOCKED; /* sigh */
602 else
603 errx(EXIT_FAILURE, _("unrecognized securebit"));
604
605 if (*c == '+')
606 opts->securebits |= bit;
607 else
608 opts->securebits &= ~bit;
609 }
610 }
611
612 opts->securebits |= SECBIT_KEEP_CAPS; /* We need it, and it's reset on exec */
613
614 free(buf);
615 }
616
617 static void do_selinux_label(const char *label)
618 {
619 int fd;
620 size_t len;
621
622 if (access(_PATH_SYS_SELINUX, F_OK) != 0)
623 errx(SETPRIV_EXIT_PRIVERR, _("SELinux is not running"));
624
625 fd = open(_PATH_PROC_ATTR_EXEC, O_RDWR);
626 if (fd == -1)
627 err(SETPRIV_EXIT_PRIVERR,
628 _("cannot open %s"), _PATH_PROC_ATTR_EXEC);
629
630 len = strlen(label);
631 errno = 0;
632 if (write(fd, label, len) != (ssize_t) len)
633 err(SETPRIV_EXIT_PRIVERR,
634 _("write failed: %s"), _PATH_PROC_ATTR_EXEC);
635
636 if (close(fd) != 0)
637 err(SETPRIV_EXIT_PRIVERR,
638 _("close failed: %s"), _PATH_PROC_ATTR_EXEC);
639 }
640
641 static void do_apparmor_profile(const char *label)
642 {
643 FILE *f;
644
645 if (access(_PATH_SYS_APPARMOR, F_OK) != 0)
646 errx(SETPRIV_EXIT_PRIVERR, _("AppArmor is not running"));
647
648 f = fopen(_PATH_PROC_ATTR_EXEC, "r+");
649 if (!f)
650 err(SETPRIV_EXIT_PRIVERR,
651 _("cannot open %s"), _PATH_PROC_ATTR_EXEC);
652
653 fprintf(f, "exec %s", label);
654
655 if (close_stream(f) != 0)
656 err(SETPRIV_EXIT_PRIVERR,
657 _("write failed: %s"), _PATH_PROC_ATTR_EXEC);
658 }
659
660
661 static void do_reset_environ(struct passwd *pw)
662 {
663 char *term = getenv("TERM");
664
665 if (term)
666 term = xstrdup(term);
667 #ifdef HAVE_CLEARENV
668 clearenv();
669 #else
670 environ = NULL;
671 #endif
672 if (term) {
673 xsetenv("TERM", term, 1);
674 free(term);
675 }
676
677 if (pw->pw_shell && *pw->pw_shell)
678 xsetenv("SHELL", pw->pw_shell, 1);
679 else
680 xsetenv("SHELL", DEFAULT_SHELL, 1);
681
682 xsetenv("HOME", pw->pw_dir, 1);
683 xsetenv("USER", pw->pw_name, 1);
684 xsetenv("LOGNAME", pw->pw_name, 1);
685
686 if (pw->pw_uid)
687 xsetenv("PATH", _PATH_DEFPATH, 1);
688 else
689 xsetenv("PATH", _PATH_DEFPATH_ROOT, 1);
690 }
691
692 static uid_t get_user(const char *s, const char *err)
693 {
694 struct passwd *pw;
695 long tmp;
696 pw = getpwnam(s);
697 if (pw)
698 return pw->pw_uid;
699 tmp = strtol_or_err(s, err);
700 return tmp;
701 }
702
703 static gid_t get_group(const char *s, const char *err)
704 {
705 struct group *gr;
706 long tmp;
707 gr = getgrnam(s);
708 if (gr)
709 return gr->gr_gid;
710 tmp = strtol_or_err(s, err);
711 return tmp;
712 }
713
714 static struct passwd *get_passwd(const char *s, uid_t *uid, const char *err)
715 {
716 struct passwd *pw;
717 long tmp;
718 pw = getpwnam(s);
719 if (pw) {
720 *uid = pw->pw_uid;
721 } else {
722 tmp = strtol_or_err(s, err);
723 *uid = tmp;
724 pw = getpwuid(*uid);
725 }
726 return pw;
727 }
728
729 static struct passwd *passwd_copy(struct passwd *dst, const struct passwd *src)
730 {
731 struct passwd *rv;
732 rv = memcpy(dst, src, sizeof(*dst));
733 rv->pw_name = xstrdup(rv->pw_name);
734 rv->pw_passwd = xstrdup(rv->pw_passwd);
735 rv->pw_gecos = xstrdup(rv->pw_gecos);
736 rv->pw_dir = xstrdup(rv->pw_dir);
737 rv->pw_shell = xstrdup(rv->pw_shell);
738 return rv;
739 }
740
741 int main(int argc, char **argv)
742 {
743 enum {
744 NNP = CHAR_MAX + 1,
745 RUID,
746 EUID,
747 RGID,
748 EGID,
749 REUID,
750 REGID,
751 CLEAR_GROUPS,
752 KEEP_GROUPS,
753 INIT_GROUPS,
754 GROUPS,
755 INHCAPS,
756 AMBCAPS,
757 LISTCAPS,
758 CAPBSET,
759 SECUREBITS,
760 PDEATHSIG,
761 SELINUX_LABEL,
762 APPARMOR_PROFILE,
763 RESET_ENV
764 };
765
766 static const struct option longopts[] = {
767 { "dump", no_argument, NULL, 'd' },
768 { "nnp", no_argument, NULL, NNP },
769 { "no-new-privs", no_argument, NULL, NNP },
770 { "inh-caps", required_argument, NULL, INHCAPS },
771 { "ambient-caps", required_argument, NULL, AMBCAPS },
772 { "list-caps", no_argument, NULL, LISTCAPS },
773 { "ruid", required_argument, NULL, RUID },
774 { "euid", required_argument, NULL, EUID },
775 { "rgid", required_argument, NULL, RGID },
776 { "egid", required_argument, NULL, EGID },
777 { "reuid", required_argument, NULL, REUID },
778 { "regid", required_argument, NULL, REGID },
779 { "clear-groups", no_argument, NULL, CLEAR_GROUPS },
780 { "keep-groups", no_argument, NULL, KEEP_GROUPS },
781 { "init-groups", no_argument, NULL, INIT_GROUPS },
782 { "groups", required_argument, NULL, GROUPS },
783 { "bounding-set", required_argument, NULL, CAPBSET },
784 { "securebits", required_argument, NULL, SECUREBITS },
785 { "pdeathsig", required_argument, NULL, PDEATHSIG, },
786 { "selinux-label", required_argument, NULL, SELINUX_LABEL },
787 { "apparmor-profile", required_argument, NULL, APPARMOR_PROFILE },
788 { "help", no_argument, NULL, 'h' },
789 { "reset-env", no_argument, NULL, RESET_ENV, },
790 { "version", no_argument, NULL, 'V' },
791 { NULL, 0, NULL, 0 }
792 };
793
794 static const ul_excl_t excl[] = {
795 /* keep in same order with enum definitions */
796 {CLEAR_GROUPS, KEEP_GROUPS, INIT_GROUPS, GROUPS},
797 {0}
798 };
799 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
800
801 int c;
802 struct privctx opts;
803 struct passwd *pw = NULL;
804 int dumplevel = 0;
805 int total_opts = 0;
806 int list_caps = 0;
807
808 setlocale(LC_ALL, "");
809 bindtextdomain(PACKAGE, LOCALEDIR);
810 textdomain(PACKAGE);
811 close_stdout_atexit();
812
813 memset(&opts, 0, sizeof(opts));
814
815 while ((c = getopt_long(argc, argv, "+dhV", longopts, NULL)) != -1) {
816 err_exclusive_options(c, longopts, excl, excl_st);
817 total_opts++;
818 switch (c) {
819 case 'd':
820 dumplevel++;
821 break;
822 case NNP:
823 if (opts.nnp)
824 errx(EXIT_FAILURE,
825 _("duplicate --no-new-privs option"));
826 opts.nnp = 1;
827 break;
828 case RUID:
829 if (opts.have_ruid)
830 errx(EXIT_FAILURE, _("duplicate ruid"));
831 opts.have_ruid = 1;
832 pw = get_passwd(optarg, &opts.ruid, _("failed to parse ruid"));
833 if (pw) {
834 passwd_copy(&opts.passwd, pw);
835 opts.have_passwd = 1;
836 }
837 break;
838 case EUID:
839 if (opts.have_euid)
840 errx(EXIT_FAILURE, _("duplicate euid"));
841 opts.have_euid = 1;
842 opts.euid = get_user(optarg, _("failed to parse euid"));
843 break;
844 case REUID:
845 if (opts.have_ruid || opts.have_euid)
846 errx(EXIT_FAILURE, _("duplicate ruid or euid"));
847 opts.have_ruid = opts.have_euid = 1;
848 pw = get_passwd(optarg, &opts.ruid, _("failed to parse reuid"));
849 opts.euid = opts.ruid;
850 if (pw) {
851 passwd_copy(&opts.passwd, pw);
852 opts.have_passwd = 1;
853 }
854 break;
855 case RGID:
856 if (opts.have_rgid)
857 errx(EXIT_FAILURE, _("duplicate rgid"));
858 opts.have_rgid = 1;
859 opts.rgid = get_group(optarg, _("failed to parse rgid"));
860 break;
861 case EGID:
862 if (opts.have_egid)
863 errx(EXIT_FAILURE, _("duplicate egid"));
864 opts.have_egid = 1;
865 opts.egid = get_group(optarg, _("failed to parse egid"));
866 break;
867 case REGID:
868 if (opts.have_rgid || opts.have_egid)
869 errx(EXIT_FAILURE, _("duplicate rgid or egid"));
870 opts.have_rgid = opts.have_egid = 1;
871 opts.rgid = opts.egid = get_group(optarg, _("failed to parse regid"));
872 break;
873 case CLEAR_GROUPS:
874 if (opts.clear_groups)
875 errx(EXIT_FAILURE,
876 _("duplicate --clear-groups option"));
877 opts.clear_groups = 1;
878 break;
879 case KEEP_GROUPS:
880 if (opts.keep_groups)
881 errx(EXIT_FAILURE,
882 _("duplicate --keep-groups option"));
883 opts.keep_groups = 1;
884 break;
885 case INIT_GROUPS:
886 if (opts.init_groups)
887 errx(EXIT_FAILURE,
888 _("duplicate --init-groups option"));
889 opts.init_groups = 1;
890 break;
891 case GROUPS:
892 if (opts.have_groups)
893 errx(EXIT_FAILURE,
894 _("duplicate --groups option"));
895 parse_groups(&opts, optarg);
896 break;
897 case PDEATHSIG:
898 if (opts.pdeathsig)
899 errx(EXIT_FAILURE,
900 _("duplicate --keep-pdeathsig option"));
901 parse_pdeathsig(&opts, optarg);
902 break;
903 case LISTCAPS:
904 list_caps = 1;
905 break;
906 case INHCAPS:
907 if (opts.caps_to_inherit)
908 errx(EXIT_FAILURE,
909 _("duplicate --inh-caps option"));
910 opts.caps_to_inherit = optarg;
911 break;
912 case AMBCAPS:
913 if (opts.ambient_caps)
914 errx(EXIT_FAILURE,
915 _("duplicate --ambient-caps option"));
916 opts.ambient_caps = optarg;
917 break;
918 case CAPBSET:
919 if (opts.bounding_set)
920 errx(EXIT_FAILURE,
921 _("duplicate --bounding-set option"));
922 opts.bounding_set = optarg;
923 break;
924 case SECUREBITS:
925 if (opts.have_securebits)
926 errx(EXIT_FAILURE,
927 _("duplicate --securebits option"));
928 parse_securebits(&opts, optarg);
929 break;
930 case SELINUX_LABEL:
931 if (opts.selinux_label)
932 errx(EXIT_FAILURE,
933 _("duplicate --selinux-label option"));
934 opts.selinux_label = optarg;
935 break;
936 case APPARMOR_PROFILE:
937 if (opts.apparmor_profile)
938 errx(EXIT_FAILURE,
939 _("duplicate --apparmor-profile option"));
940 opts.apparmor_profile = optarg;
941 break;
942 case RESET_ENV:
943 opts.reset_env = 1;
944 break;
945
946 case 'h':
947 usage();
948 case 'V':
949 print_version(EXIT_SUCCESS);
950 default:
951 errtryhelp(EXIT_FAILURE);
952 }
953 }
954
955 if (dumplevel) {
956 if (total_opts != dumplevel || optind < argc)
957 errx(EXIT_FAILURE,
958 _("--dump is incompatible with all other options"));
959 dump(dumplevel);
960 return EXIT_SUCCESS;
961 }
962
963 if (list_caps) {
964 if (total_opts != 1 || optind < argc)
965 errx(EXIT_FAILURE,
966 _("--list-caps must be specified alone"));
967 list_known_caps();
968 return EXIT_SUCCESS;
969 }
970
971 if (argc <= optind)
972 errx(EXIT_FAILURE, _("No program specified"));
973
974 if ((opts.have_rgid || opts.have_egid)
975 && !opts.keep_groups && !opts.clear_groups && !opts.init_groups
976 && !opts.have_groups)
977 errx(EXIT_FAILURE,
978 _("--[re]gid requires --keep-groups, --clear-groups, --init-groups, or --groups"));
979
980 if (opts.init_groups && !opts.have_ruid)
981 errx(EXIT_FAILURE,
982 _("--init-groups requires --ruid or --reuid"));
983
984 if (opts.init_groups && !opts.have_passwd)
985 errx(EXIT_FAILURE,
986 _("uid %ld not found, --init-groups requires an user that "
987 "can be found on the system"),
988 (long) opts.ruid);
989
990 if (opts.reset_env) {
991 if (opts.have_passwd)
992 /* pwd according to --ruid or --reuid */
993 pw = &opts.passwd;
994 else
995 /* pwd for the current user */
996 pw = getpwuid(getuid());
997 do_reset_environ(pw);
998 }
999
1000 if (opts.nnp && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
1001 err(EXIT_FAILURE, _("disallow granting new privileges failed"));
1002
1003 if (opts.selinux_label)
1004 do_selinux_label(opts.selinux_label);
1005 if (opts.apparmor_profile)
1006 do_apparmor_profile(opts.apparmor_profile);
1007
1008 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
1009 err(EXIT_FAILURE, _("keep process capabilities failed"));
1010
1011 /* We're going to want CAP_SETPCAP, CAP_SETUID, and CAP_SETGID if
1012 * possible. */
1013 bump_cap(CAP_SETPCAP);
1014 bump_cap(CAP_SETUID);
1015 bump_cap(CAP_SETGID);
1016 if (capng_apply(CAPNG_SELECT_CAPS) != 0)
1017 err(SETPRIV_EXIT_PRIVERR, _("activate capabilities"));
1018
1019 if (opts.have_ruid || opts.have_euid) {
1020 do_setresuid(&opts);
1021 /* KEEPCAPS doesn't work for the effective mask. */
1022 if (capng_apply(CAPNG_SELECT_CAPS) != 0)
1023 err(SETPRIV_EXIT_PRIVERR, _("reactivate capabilities"));
1024 }
1025
1026 if (opts.have_rgid || opts.have_egid)
1027 do_setresgid(&opts);
1028
1029 if (opts.have_groups) {
1030 if (setgroups(opts.num_groups, opts.groups) != 0)
1031 err(SETPRIV_EXIT_PRIVERR, _("setgroups failed"));
1032 } else if (opts.init_groups) {
1033 if (initgroups(opts.passwd.pw_name, opts.passwd.pw_gid) != 0)
1034 err(SETPRIV_EXIT_PRIVERR, _("initgroups failed"));
1035 } else if (opts.clear_groups) {
1036 gid_t x = 0;
1037 if (setgroups(0, &x) != 0)
1038 err(SETPRIV_EXIT_PRIVERR, _("setgroups failed"));
1039 }
1040
1041 if (opts.have_securebits && prctl(PR_SET_SECUREBITS, opts.securebits, 0, 0, 0) != 0)
1042 err(SETPRIV_EXIT_PRIVERR, _("set process securebits failed"));
1043
1044 if (opts.bounding_set) {
1045 do_caps(CAP_TYPE_BOUNDING, opts.bounding_set);
1046 errno = EPERM; /* capng doesn't set errno if we're missing CAP_SETPCAP */
1047 if (capng_apply(CAPNG_SELECT_BOUNDS) != 0)
1048 err(SETPRIV_EXIT_PRIVERR, _("apply bounding set"));
1049 }
1050
1051 if (opts.caps_to_inherit) {
1052 do_caps(CAP_TYPE_INHERITABLE, opts.caps_to_inherit);
1053 if (capng_apply(CAPNG_SELECT_CAPS) != 0)
1054 err(SETPRIV_EXIT_PRIVERR, _("apply capabilities"));
1055 }
1056
1057 if (opts.ambient_caps) {
1058 do_caps(CAP_TYPE_AMBIENT, opts.ambient_caps);
1059 }
1060
1061 /* Clear or set parent death signal */
1062 if (opts.pdeathsig && prctl(PR_SET_PDEATHSIG, opts.pdeathsig < 0 ? 0 : opts.pdeathsig) != 0)
1063 err(SETPRIV_EXIT_PRIVERR, _("set parent death signal failed"));
1064
1065 execvp(argv[optind], argv + optind);
1066 errexec(argv[optind]);
1067 }