]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - sys-utils/setpriv.c
misc: cosmetics, remove argument from usage(FILE*)
[thirdparty/util-linux.git] / sys-utils / setpriv.c
index 977ccd14a9e4198ac87d8bfe641678e4990a4658..310e6938d233f2142fb55baf452cc8aec3b67d39 100644 (file)
@@ -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;
@@ -87,8 +92,9 @@ struct privctx {
        const char *apparmor_profile;
 };
 
-static void __attribute__((__noreturn__)) usage(FILE *out)
+static void __attribute__((__noreturn__)) usage(void)
 {
+       FILE *out = stdout;
        fputs(USAGE_HEADER, out);
        fprintf(out, _(" %s [options] <program> [<argument>...]\n"),
                program_invocation_short_name);
@@ -109,6 +115,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);
@@ -121,7 +128,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
        fputs(_(" This tool can be dangerous.  Read the manpage, and be careful.\n"), out);
        fprintf(out, USAGE_MAN_TAIL("setpriv(1)"));
 
-       exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+       exit(EXIT_SUCCESS);
 }
 
 static int real_cap_last_cap(void)
@@ -252,7 +259,7 @@ static void dump_label(const char *name)
 
 static void dump_groups(void)
 {
-       int n = getgroups(0, 0);
+       int n = getgroups(0, NULL);
        gid_t *groups;
 
        if (n < 0) {
@@ -580,6 +587,33 @@ 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;
+}
+
+static struct passwd *passwd_copy(struct passwd *dst, const struct passwd *src)
+{
+       struct passwd *rv;
+       rv = memcpy(dst, src, sizeof(*dst));
+       rv->pw_name = xstrdup(rv->pw_name);
+       rv->pw_passwd = xstrdup(rv->pw_passwd);
+       rv->pw_gecos = xstrdup(rv->pw_gecos);
+       rv->pw_dir = xstrdup(rv->pw_dir);
+       rv->pw_shell = xstrdup(rv->pw_shell);
+       return rv;
+}
+
 int main(int argc, char **argv)
 {
        enum {
@@ -592,6 +626,7 @@ int main(int argc, char **argv)
                REGID,
                CLEAR_GROUPS,
                KEEP_GROUPS,
+               INIT_GROUPS,
                GROUPS,
                INHCAPS,
                LISTCAPS,
@@ -602,38 +637,40 @@ int main(int argc, char **argv)
        };
 
        static const struct option longopts[] = {
-               {"dump", no_argument, 0, 'd'},
-               {"nnp", no_argument, 0, NNP},
-               {"no-new-privs", no_argument, 0, NNP},
-               {"inh-caps", required_argument, 0, INHCAPS},
-               {"list-caps", no_argument, 0, LISTCAPS},
-               {"ruid", required_argument, 0, RUID},
-               {"euid", required_argument, 0, EUID},
-               {"rgid", required_argument, 0, RGID},
-               {"egid", required_argument, 0, EGID},
-               {"reuid", required_argument, 0, REUID},
-               {"regid", required_argument, 0, REGID},
-               {"clear-groups", no_argument, 0, CLEAR_GROUPS},
-               {"keep-groups", no_argument, 0, KEEP_GROUPS},
-               {"groups", required_argument, 0, GROUPS},
-               {"bounding-set", required_argument, 0, CAPBSET},
-               {"securebits", required_argument, 0, SECUREBITS},
-               {"selinux-label", required_argument, 0, SELINUX_LABEL},
-               {"apparmor-profile", required_argument, 0, APPARMOR_PROFILE},
-               {"help", no_argument, 0, 'h'},
-               {"version", no_argument, 0, 'V'},
-               {NULL, 0, 0, 0}
+               { "dump",             no_argument,       NULL, 'd'              },
+               { "nnp",              no_argument,       NULL, NNP              },
+               { "no-new-privs",     no_argument,       NULL, NNP              },
+               { "inh-caps",         required_argument, NULL, INHCAPS          },
+               { "list-caps",        no_argument,       NULL, LISTCAPS         },
+               { "ruid",             required_argument, NULL, RUID             },
+               { "euid",             required_argument, NULL, EUID             },
+               { "rgid",             required_argument, NULL, RGID             },
+               { "egid",             required_argument, NULL, EGID             },
+               { "reuid",            required_argument, NULL, REUID            },
+               { "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       },
+               { "selinux-label",    required_argument, NULL, SELINUX_LABEL    },
+               { "apparmor-profile", required_argument, NULL, APPARMOR_PROFILE },
+               { "help",             no_argument,       NULL, 'h'              },
+               { "version",          no_argument,       NULL, 'V'              },
+               { NULL, 0, NULL, 0 }
        };
 
        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 +699,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) {
+                               passwd_copy(&opts.passwd, pw);
+                               opts.have_passwd = 1;
+                       }
                        break;
                case EUID:
                        if (opts.have_euid)
@@ -674,7 +715,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) {
+                               passwd_copy(&opts.passwd, pw);
+                               opts.have_passwd = 1;
+                       }
                        break;
                case RGID:
                        if (opts.have_rgid)
@@ -706,6 +752,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,
@@ -746,14 +798,12 @@ int main(int argc, char **argv)
                        opts.apparmor_profile = optarg;
                        break;
                case 'h':
-                       usage(stdout);
+                       usage();
                case 'V':
                        printf(UTIL_LINUX_VERSION);
                        return EXIT_SUCCESS;
-               case '?':
-                       usage(stderr);
                default:
-                       errx(EXIT_FAILURE, _("unrecognized option '%c'"), c);
+                       errtryhelp(EXIT_FAILURE);
                }
        }
 
@@ -777,9 +827,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"));
@@ -813,6 +874,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)