*-T*, *--time*[=_file_]::
Enter the time namespace. If no file is specified, enter the time namespace of the target process. If _file_ is specified, enter the time namespace specified by _file_.
-*-G*, *--setgid* _gid_::
-Set the group ID which will be used in the entered namespace and drop supplementary groups. *nsenter* always sets GID for user namespaces, the default is 0.
-
-*-S*, *--setuid* _uid_::
-Set the user ID which will be used in the entered namespace. *nsenter* always sets UID for user namespaces, the default is 0.
+*-G*, *--setgid*[=_gid_]::
+Set the group ID which will be used in the entered namespace and drop supplementary groups.
+*nsenter* always sets GID for user namespaces, the default is 0.
+If no argument is specified the GID of the target process is used.
+
+*-S*, *--setuid*[=_uid_]::
+Set the user ID which will be used in the entered namespace.
+*nsenter* always sets UID for user namespaces, the default is 0.
+If no argument is specified the UID of the target process is used.
*--preserve-credentials*::
Don't modify UID and GID when enter user namespace. The default is to drops supplementary groups and sets GID and UID to 0.
fputs(_(" -C, --cgroup[=<file>] enter cgroup namespace\n"), out);
fputs(_(" -U, --user[=<file>] enter user namespace\n"), out);
fputs(_(" -T, --time[=<file>] enter time namespace\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(_(" -S, --setuid=[<uid>] set uid in entered namespace\n"), out);
+ fputs(_(" -G, --setgid=[<gid>] set gid in entered namespace\n"), out);
fputs(_(" --preserve-credentials do not touch uids or gids\n"), out);
fputs(_(" -r, --root[=<dir>] set the root directory\n"), out);
fputs(_(" -w, --wd[=<dir>] set the working directory\n"), out);
static pid_t namespace_target_pid = 0;
static int root_fd = -1;
static int wd_fd = -1;
+static int uid_gid_fd = -1;
static void open_target_fd(int *fd, const char *type, const char *path)
{
{ "user", optional_argument, NULL, 'U' },
{ "cgroup", optional_argument, NULL, 'C' },
{ "time", optional_argument, NULL, 'T' },
- { "setuid", required_argument, NULL, 'S' },
- { "setgid", required_argument, NULL, 'G' },
+ { "setuid", optional_argument, NULL, 'S' },
+ { "setgid", optional_argument, NULL, 'G' },
{ "root", optional_argument, NULL, 'r' },
{ "wd", optional_argument, NULL, 'w' },
{ "wdns", optional_argument, NULL, 'W' },
struct namespace_file *nsfile;
int c, pass, namespaces = 0, setgroups_nerrs = 0, preserve_cred = 0;
- bool do_rd = false, do_wd = false, force_uid = false, force_gid = false;
+ bool do_rd = false, do_wd = false, do_uid = false, force_uid = false, do_gid = false, force_gid = false;
bool do_all = false;
int do_fork = -1; /* unknown yet */
char *wdns = NULL;
close_stdout_atexit();
while ((c =
- getopt_long(argc, argv, "+ahVt:m::u::i::n::p::C::U::T::S:G:r::w::W:FZ",
+ getopt_long(argc, argv, "+ahVt:m::u::i::n::p::C::U::T::S::G::r::w::W:FZ",
longopts, NULL)) != -1) {
err_exclusive_options(c, longopts, excl, excl_st);
namespaces |= CLONE_NEWTIME;
break;
case 'S':
- uid = strtoul_or_err(optarg, _("failed to parse uid"));
+ if (optarg)
+ uid = strtoul_or_err(optarg, _("failed to parse uid"));
+ else
+ do_uid = true;
force_uid = true;
break;
case 'G':
- gid = strtoul_or_err(optarg, _("failed to parse gid"));
+ if (optarg)
+ gid = strtoul_or_err(optarg, _("failed to parse gid"));
+ else
+ do_gid = true;
force_gid = true;
break;
case 'F':
open_target_fd(&root_fd, "root", NULL);
if (do_wd)
open_target_fd(&wd_fd, "cwd", NULL);
+ if (do_uid || do_gid)
+ open_target_fd(&uid_gid_fd, "", NULL);
/*
* Update namespaces variable to contain all requested namespaces
wd_fd = -1;
}
+ if (uid_gid_fd >= 0) {
+ struct stat st;
+
+ if (fstat(uid_gid_fd, &st) > 0)
+ err(EXIT_FAILURE, _("can not get process stat"));
+
+ close(uid_gid_fd);
+ uid_gid_fd = -1;
+
+ if (do_uid)
+ uid = st.st_uid;
+ if (do_gid)
+ gid = st.st_gid;
+ }
+
if (do_fork == 1)
continue_as_child();