]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
unshare: allow to set user ID and group ID
authorLaurent Vivier <laurent@vivier.eu>
Fri, 5 Oct 2018 11:09:30 +0000 (13:09 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 12 Nov 2018 10:52:15 +0000 (11:52 +0100)
This patch introduces two new parameters to set the
user ID and the group ID of the program to be executed.
Setting group ID also drops supplementary groups.

The option names used are the same as for nsenter,
-S, --setuid and -G, --setgid.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
bash-completion/unshare
sys-utils/unshare.1
sys-utils/unshare.c

index 64aea678419df25f5b6e717ea0649729e95d6f59..10afffe1999d081e4a966d58284954766580aff6 100644 (file)
@@ -35,7 +35,9 @@ _unshare_module()
                                --help
                                --version
                                --root
-                               --wd"
+                               --wd
+                               --setuid
+                               --setgid"
                        COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
                        return 0
                        ;;
index 40cbedbd151d876cfcd0b5537cf41ffd6bf8ef5d..d2ba6c3a5cadbb259e9a434216de7ced91c831e4 100644 (file)
@@ -192,6 +192,13 @@ run the command with root directory set to \fIdir\fP.
 .BR \-w, "\-\-wd=\fIdir"
 change working directory to \fIdir\fP.
 .TP
+.BR \-S, "\-\-setuid \fIuid"
+Set the user ID which will be used in the entered namespace.
+.TP
+.BR \-G, "\-\-setgid \fIgid"
+Set the group ID which will be used in the entered namespace and drop
+supplementary groups.
+.TP
 .BR \-V , " \-\-version"
 Display version information and exit.
 .TP
index 12ef044f855a530288030b6191d2bcb65adc1197..e9ddb09de3d23cd595452bc915c83a5d1a426389 100644 (file)
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/prctl.h>
+#include <grp.h>
 
 /* we only need some defines missing in sys/mount.h, no libmount linkage */
 #include <libmount.h>
@@ -42,6 +43,7 @@
 #include "pathnames.h"
 #include "all-io.h"
 #include "signames.h"
+#include "strutils.h"
 
 /* synchronize parent and child by pipe */
 #define PIPE_SYNC_BYTE 0x06
@@ -272,6 +274,8 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(USAGE_SEPARATOR, out);
        fputs(_(" -R, --root=<dir>          run the command with root directory set to <dir>\n"), out);
        fputs(_(" -w, --wd=<dir>            change working directory to <dir>\n"), out);
+       fputs(_(" -S, --setuid <uid>        set uid in entered namespace\n"), out);
+       fputs(_(" -G, --setgid <gid>        set gid in entered namespace\n"), out);
 
        fputs(USAGE_SEPARATOR, out);
        printf(USAGE_HELP_OPTIONS(27));
@@ -306,6 +310,8 @@ int main(int argc, char *argv[])
                { "map-root-user", no_argument,       NULL, 'r'             },
                { "propagation",   required_argument, NULL, OPT_PROPAGATION },
                { "setgroups",     required_argument, NULL, OPT_SETGROUPS   },
+               { "setuid",        required_argument, NULL, 'S'             },
+               { "setgid",        required_argument, NULL, 'G'             },
                { "root",          required_argument, NULL, 'R'             },
                { "wd",            required_argument, NULL, 'w'             },
                { NULL, 0, NULL, 0 }
@@ -322,15 +328,16 @@ int main(int argc, char *argv[])
        int fds[2];
        int status;
        unsigned long propagation = UNSHARE_PROPAGATION_DEFAULT;
-       uid_t real_euid = geteuid();
-       gid_t real_egid = getegid();
+       int force_uid = 0, force_gid = 0;
+       uid_t uid = 0, real_euid = geteuid();
+       gid_t gid = 0, real_egid = getegid();
 
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
        atexit(close_stdout);
 
-       while ((c = getopt_long(argc, argv, "+fhVmuinpCUrR:w:", longopts, NULL)) != -1) {
+       while ((c = getopt_long(argc, argv, "+fhVmuinpCUrR:w:S:G:", longopts, NULL)) != -1) {
                switch (c) {
                case 'f':
                        forkit = 1;
@@ -399,6 +406,14 @@ int main(int argc, char *argv[])
                                kill_child_signo = SIGKILL;
                        }
                        break;
+               case 'S':
+                       uid = strtoul_or_err(optarg, _("failed to parse uid"));
+                       force_uid = 1;
+                       break;
+               case 'G':
+                       gid = strtoul_or_err(optarg, _("failed to parse gid"));
+                       force_gid = 1;
+                       break;
                case 'R':
                        newroot = optarg;
                        break;
@@ -500,6 +515,15 @@ int main(int argc, char *argv[])
                        err(EXIT_FAILURE, _("mount %s failed"), procmnt);
        }
 
+       if (force_gid) {
+               if (setgroups(0, NULL) != 0)    /* drop supplementary groups */
+                       err(EXIT_FAILURE, _("setgroups failed"));
+               if (setgid(gid) < 0)            /* change GID */
+                       err(EXIT_FAILURE, _("setgid failed"));
+       }
+       if (force_uid && setuid(uid) < 0)       /* change UID */
+               err(EXIT_FAILURE, _("setuid failed"));
+
        if (optind < argc) {
                execvp(argv[optind], argv + optind);
                errexec(argv[optind]);