Add an --init-groups option which initializes the supplementary groups from the system's group database (e.g /etc/group) using initgroups(3). --- sys-utils/setpriv.1 | 8 +++++++ sys-utils/setpriv.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/sys-utils/setpriv.1 b/sys-utils/setpriv.1 index bf18fe050..be97c0799 100644 --- a/sys-utils/setpriv.1 +++ b/sys-utils/setpriv.1 @@ -52,6 +52,14 @@ Preserve supplementary groups. Only useful in conjunction with .BR \-\-egid ", or" .BR \-\-regid . .TP +.B \-\-init\-groups +Initialize supplementary groups using +.BR initgroups "(3)." +Only useful in conjunction with +.BR \-\-ruid +or +.BR \-\-reuid . +.TP .BR \-\-list\-caps List all known capabilities. This option must be specified alone. .TP diff --git a/sys-utils/setpriv.c b/sys-utils/setpriv.c index 2129115a0..618119385 100644 --- a/sys-utils/setpriv.c +++ b/sys-utils/setpriv.c @@ -62,15 +62,20 @@ struct privctx { 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 */ 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; @@ -109,6 +114,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out) fputs(_(" --regid <gid> 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 <group,...> set supplementary groups\n"), out); fputs(_(" --securebits <bits> set securebits\n"), out); fputs(_(" --selinux-label <label> set SELinux label\n"), out); @@ -580,6 +586,21 @@ static gid_t get_group(const char *s, const char *err) return tmp; } +static struct passwd *get_passwd(const char *s, uid_t *uid, const char *err) +{ + struct passwd *pw; + long tmp; + pw = getpwnam(s); + if (pw) { + *uid = pw->pw_uid; + } else { + tmp = strtol_or_err(s, err); + *uid = tmp; + pw = getpwuid(*uid); + } + return pw; +} + int main(int argc, char **argv) { enum { @@ -592,6 +613,7 @@ int main(int argc, char **argv) REGID, CLEAR_GROUPS, KEEP_GROUPS, + INIT_GROUPS, GROUPS, INHCAPS, LISTCAPS, @@ -615,6 +637,7 @@ int main(int argc, char **argv) { "regid", required_argument, NULL, REGID }, { "clear-groups", no_argument, NULL, CLEAR_GROUPS }, { "keep-groups", no_argument, NULL, KEEP_GROUPS }, + { "init-groups", no_argument, NULL, INIT_GROUPS }, { "groups", required_argument, NULL, GROUPS }, { "bounding-set", required_argument, NULL, CAPBSET }, { "securebits", required_argument, NULL, SECUREBITS }, @@ -627,13 +650,14 @@ int main(int argc, char **argv) static const ul_excl_t excl[] = { /* keep in same order with enum definitions */ - {CLEAR_GROUPS, KEEP_GROUPS, GROUPS}, + {CLEAR_GROUPS, KEEP_GROUPS, INIT_GROUPS, GROUPS}, {0} }; int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; int c; struct privctx opts; + struct passwd *pw = NULL; int dumplevel = 0; int total_opts = 0; int list_caps = 0; @@ -662,7 +686,11 @@ int main(int argc, char **argv) if (opts.have_ruid) errx(EXIT_FAILURE, _("duplicate ruid")); opts.have_ruid = 1; - opts.ruid = get_user(optarg, _("failed to parse ruid")); + pw = get_passwd(optarg, &opts.ruid, _("failed to parse ruid")); + if (pw) { + memcpy(&opts.passwd, pw, sizeof(opts.passwd)); + opts.have_passwd = 1; + } break; case EUID: if (opts.have_euid) @@ -674,7 +702,12 @@ int main(int argc, char **argv) if (opts.have_ruid || opts.have_euid) errx(EXIT_FAILURE, _("duplicate ruid or euid")); opts.have_ruid = opts.have_euid = 1; - opts.ruid = opts.euid = get_user(optarg, _("failed to parse reuid")); + pw = get_passwd(optarg, &opts.ruid, _("failed to parse reuid")); + opts.euid = opts.ruid; + if (pw) { + memcpy(&opts.passwd, pw, sizeof(opts.passwd)); + opts.have_passwd = 1; + } break; case RGID: if (opts.have_rgid) @@ -706,6 +739,12 @@ int main(int argc, char **argv) _("duplicate --keep-groups option")); opts.keep_groups = 1; break; + case INIT_GROUPS: + if (opts.init_groups) + errx(EXIT_FAILURE, + _("duplicate --init-groups option")); + opts.init_groups = 1; + break; case GROUPS: if (opts.have_groups) errx(EXIT_FAILURE, @@ -775,9 +814,20 @@ int main(int argc, char **argv) errx(EXIT_FAILURE, _("No program specified")); if ((opts.have_rgid || opts.have_egid) - && !opts.keep_groups && !opts.clear_groups && !opts.have_groups) + && !opts.keep_groups && !opts.clear_groups && !opts.init_groups + && !opts.have_groups) + errx(EXIT_FAILURE, + _("--[re]gid requires --keep-groups, --clear-groups, --init-groups, or --groups")); + + if (opts.init_groups && !opts.have_ruid) + errx(EXIT_FAILURE, + _("--init-groups requires --ruid or --reuid")); + + if (opts.init_groups && !opts.have_passwd) errx(EXIT_FAILURE, - _("--[re]gid requires --keep-groups, --clear-groups, or --groups")); + _("uid %ld not found, --init-groups requires an user that " + "can be found on the system"), + (long) opts.ruid); if (opts.nnp && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) err(EXIT_FAILURE, _("disallow granting new privileges failed")); @@ -811,6 +861,9 @@ int main(int argc, char **argv) if (opts.have_groups) { if (setgroups(opts.num_groups, opts.groups) != 0) err(SETPRIV_EXIT_PRIVERR, _("setgroups failed")); + } else if (opts.init_groups) { + if (initgroups(opts.passwd.pw_name, opts.passwd.pw_gid) != 0) + err(SETPRIV_EXIT_PRIVERR, _("initgroups failed")); } else if (opts.clear_groups) { gid_t x = 0; if (setgroups(0, &x) != 0) -- 2.13.0 -- To unsubscribe from this list: send the line "unsubscribe util-linux" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html