/* * setpriv(1) - set various kernel privilege bits and run something * * Copyright (C) 2012 Andy Lutomirski * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "c.h" #include "closestream.h" #include "nls.h" #include "optutils.h" #include "strutils.h" #include "xalloc.h" #include "pathnames.h" #include "signames.h" #include "env.h" #ifndef PR_SET_NO_NEW_PRIVS # define PR_SET_NO_NEW_PRIVS 38 #endif #ifndef PR_GET_NO_NEW_PRIVS # define PR_GET_NO_NEW_PRIVS 39 #endif #ifndef PR_CAP_AMBIENT # define PR_CAP_AMBIENT 47 # define PR_CAP_AMBIENT_IS_SET 1 # define PR_CAP_AMBIENT_RAISE 2 # define PR_CAP_AMBIENT_LOWER 3 #endif #define SETPRIV_EXIT_PRIVERR 127 /* how we exit when we fail to set privs */ /* The shell to set SHELL env.variable if none is given in the user's passwd entry. */ #define DEFAULT_SHELL "/bin/sh" static gid_t get_group(const char *s, const char *err); enum cap_type { CAP_TYPE_EFFECTIVE = CAPNG_EFFECTIVE, CAP_TYPE_PERMITTED = CAPNG_PERMITTED, CAP_TYPE_INHERITABLE = CAPNG_INHERITABLE, CAP_TYPE_BOUNDING = CAPNG_BOUNDING_SET, CAP_TYPE_AMBIENT = (1 << 4) }; /* * Note: We are subject to https://bugzilla.redhat.com/show_bug.cgi?id=895105 * and we will therefore have problems if new capabilities are added. Once * that bug is fixed, I'll (Andy Lutomirski) submit a corresponding fix to * setpriv. In the mean time, the code here tries to work reasonably well. */ struct privctx { unsigned int nnp:1, /* no_new_privs */ have_ruid:1, /* real uid */ have_euid:1, /* effective uid */ have_rgid:1, /* real gid */ have_egid:1, /* effective gid */ have_passwd:1, /* passwd entry */ have_groups:1, /* add groups */ keep_groups:1, /* keep groups */ clear_groups:1, /* remove groups */ init_groups:1, /* initialize groups */ reset_env:1, /* reset environment */ have_securebits:1; /* remove groups */ /* uids and gids */ uid_t ruid, euid; gid_t rgid, egid; /* real user passwd entry */ struct passwd passwd; /* supplementary groups */ size_t num_groups; gid_t *groups; /* caps */ const char *caps_to_inherit; const char *ambient_caps; const char *bounding_set; /* securebits */ int securebits; /* parent death signal (<0 clear, 0 nothing, >0 signal) */ int pdeathsig; /* LSMs */ const char *selinux_label; const char *apparmor_profile; }; static void __attribute__((__noreturn__)) usage(void) { FILE *out = stdout; fputs(USAGE_HEADER, out); fprintf(out, _(" %s [options] [...]\n"), program_invocation_short_name); fputs(USAGE_SEPARATOR, out); fputs(_("Run a program with different privilege settings.\n"), out); fputs(USAGE_OPTIONS, out); fputs(_(" -d, --dump show current state (and do not exec)\n"), out); fputs(_(" --nnp, --no-new-privs disallow granting new privileges\n"), out); fputs(_(" --ambient-caps set ambient capabilities\n"), out); fputs(_(" --inh-caps set inheritable capabilities\n"), out); fputs(_(" --bounding-set set capability bounding set\n"), out); fputs(_(" --ruid set real uid\n"), out); fputs(_(" --euid set effective uid\n"), out); fputs(_(" --rgid set real gid\n"), out); fputs(_(" --egid set effective gid\n"), out); fputs(_(" --reuid set real and effective uid\n"), out); fputs(_(" --regid set real and effective gid\n"), out); fputs(_(" --clear-groups clear supplementary groups\n"), out); fputs(_(" --keep-groups keep supplementary groups\n"), out); fputs(_(" --init-groups initialize supplementary groups\n"), out); fputs(_(" --groups set supplementary groups by UID or name\n"), out); fputs(_(" --securebits set securebits\n"), out); fputs(_(" --pdeathsig keep|clear|\n" " set or clear parent death signal\n"), out); fputs(_(" --selinux-label