From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2155) id A41893858C50; Sat, 14 Jan 2023 16:49:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A41893858C50 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1673714947; bh=TZVGhcTpnBLtcZCXPPRjHkFl8nuHB08T1WewkTUAoRM=; h=From:To:Subject:Date:From; b=ruyR+P85zBTBKViUQ9iRiWJbLIpZAKpjYg31V3/7Nw7YkRDQb1MYrS7xsccaZ5UoH k7gc3PSmE4knyH704Ba26l1NYB6/trOA1ts7FAEfnr1uAKlZFcPfVvy1pXiOoUQiZQ NnBOdAOuTq14rhOvOcGXLpFks3TsbSHQmVm5psaw= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Corinna Vinschen To: cygwin-cvs@sourceware.org Subject: [newlib-cygwin/main] Cygwin: newgrp: first full version X-Act-Checkin: newlib-cygwin X-Git-Author: Corinna Vinschen X-Git-Refname: refs/heads/main X-Git-Oldrev: 73e4ded2fe17b3a970c94a421c4b2191ca49a194 X-Git-Newrev: 8bd56ec8734539ba014c9ed993c3c9e19173ed82 Message-Id: <20230114164907.A41893858C50@sourceware.org> Date: Sat, 14 Jan 2023 16:49:07 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D8bd56ec8734= 539ba014c9ed993c3c9e19173ed82 commit 8bd56ec8734539ba014c9ed993c3c9e19173ed82 Author: Corinna Vinschen AuthorDate: Sat Jan 14 17:46:55 2023 +0100 Commit: Corinna Vinschen CommitDate: Sat Jan 14 17:47:48 2023 +0100 Cygwin: newgrp: first full version =20 - add '-' option - make group argument optional - drop ability to take a numerical group argument - simplify usage output to bare minimum - Add manpage and documentation =20 Signed-off-by: Corinna Vinschen Diff: --- winsup/doc/utils.xml | 50 ++++++++++++ winsup/utils/Makefile.am | 1 + winsup/utils/newgrp.c | 200 ++++++++++++++++++++++++++++++++++++++-----= ---- 3 files changed, 212 insertions(+), 39 deletions(-) diff --git a/winsup/doc/utils.xml b/winsup/doc/utils.xml index 895988037904..927dc7c6b85e 100644 --- a/winsup/doc/utils.xml +++ b/winsup/doc/utils.xml @@ -1939,6 +1939,56 @@ D: on /d type fat (binary,user,noumount) =20 + + + newgrp + 1 + Cygwin Utilities + + + + newgrp + change primary group for a command + + + + + newgrp + - + group + command + args + + + + + + Description + newgrp changes the primary group for a + command. + + If the '-' flag is given as first argument, the user's environ= ment + will be reinitialized as though the user had logged in, otherwise = the + current environment, including current working directory, remains + unchanged. + + newgrp changes the current primary group to= the + named group, or to the default group listed in /etc/passwd if no g= roup + name is given. + + By default, the user's standard shell is started, called as lo= gin + shell if the '-' flag has been specified. If a group has been giv= en + as argument, a command and its arguments can be specified on the + command line. + + Please note that setting the primary group to any arbitrary gr= oup + is no privileged operation on Windows. However, if this group is = not + in your current user token, or if the group is in your user token but + marked as deny-only, no additional permissions can + be obtained by setting this group as primary group. + + + passwd diff --git a/winsup/utils/Makefile.am b/winsup/utils/Makefile.am index 75da1163b629..d4d56386f72e 100644 --- a/winsup/utils/Makefile.am +++ b/winsup/utils/Makefile.am @@ -87,6 +87,7 @@ pldd_LDADD =3D $(LDADD) -lpsapi profiler_CXXFLAGS =3D -I$(srcdir) -idirafter ${top_srcdir}/cygwin/local_in= cludes -idirafter ${top_srcdir}/cygwin/include $(AM_CXXFLAGS) profiler_LDADD =3D $(LDADD) -lntdll cygps_LDADD =3D $(LDADD) -lpsapi -lntdll +newgrp_LDADD =3D $(LDADD) -luserenv =20 if CROSS_BOOTSTRAP SUBDIRS =3D mingw diff --git a/winsup/utils/newgrp.c b/winsup/utils/newgrp.c index 012c3188f477..88586352e108 100644 --- a/winsup/utils/newgrp.c +++ b/winsup/utils/newgrp.c @@ -6,86 +6,204 @@ This software is a copyrighted work licensed under the t= erms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ =20 +#define _GNU_SOURCE 1 #include #include +#include #include #include #include #include +#include +#include #include #include =20 +#include +#include +#include + +#define PATH_PREFIX "PATH=3D/usr/bin:" + +char * +create_env_var (const char *name, const char *val) +{ + char *var, *cp; + + var =3D (char *) calloc (strlen (name) + strlen (val) + 2, sizeof (char = *)); + cp =3D stpcpy (var, name); + *cp++ =3D '=3D'; + stpcpy (cp, val); + return var; +} + +char ** +create_child_env (struct passwd *pw) +{ + char **posix_env, *cp; + wchar_t *win_env, *wep; + size_t max_cnt =3D 0; + size_t idx =3D 0; + HANDLE token; + + /* Fecth Windows default environment of current user */ + if (!OpenProcessToken (GetCurrentProcess (), + TOKEN_QUERY | TOKEN_DUPLICATE, &token)) + { + fprintf (stderr, "%s: creating environment failed with error %u " + "(OpenProcessToken)\n", + program_invocation_short_name, GetLastError ()); + return NULL; + } + if (!CreateEnvironmentBlock ((PVOID *) &win_env, token, FALSE)) + { + fprintf (stderr, "%s: creating environment failed with error %u " + "(CreateEnvironmentBlock)\n", + program_invocation_short_name, GetLastError ()); + CloseHandle (token); + return NULL; + } + CloseHandle (token); + /* Convert to Posix env */ + for (wep =3D win_env; *wep; wep =3D wcschr (wep, '\0') + 1) + ++max_cnt; + posix_env =3D (char **) calloc (max_cnt + 6, sizeof (char *)); + if (!posix_env) + { + fprintf (stderr, "%s: allocating environment failed: %s\n", + program_invocation_short_name, strerror (errno)); + return NULL; + } + for (wep =3D win_env; *wep; ++idx, wep =3D wcschr (wep, '\0') + 1) + { + /* For $PATH we must prepend /usr/bin to the converted POSIX path li= st */ + if (!wcsncasecmp (wep, L"PATH=3D", 5)) + { + size_t len =3D cygwin_conv_path_list (CCP_WIN_W_TO_POSIX, + wep + 5, NULL, 0); + posix_env[idx] =3D (char *) calloc (sizeof (PATH_PREFIX) + len, + sizeof (char *)); + if (!posix_env[idx]) + { + fprintf (stderr, "%s: allocating environment failed: %s\n", + program_invocation_short_name, strerror (errno)); + return NULL; + } + cp =3D stpcpy (posix_env[idx], PATH_PREFIX); + cygwin_conv_path_list (CCP_WIN_W_TO_POSIX, wep + 5, cp, len); + } + else + { + size_t len =3D wcstombs (NULL, wep, 0); + + if (len =3D=3D (size_t) -1) + { + fprintf (stderr, + "%s: invalid char in environment variable: %ls\n", + program_invocation_short_name, wep); + return NULL; + } + posix_env[idx] =3D (char *) calloc (len + 1, sizeof (char *)); + if (!posix_env[idx]) + { + fprintf (stderr, "%s: allocating environment failed: %s\n", + program_invocation_short_name, strerror (errno)); + return NULL; + } + wcstombs (posix_env[idx], wep, len + 1); + } + } + DestroyEnvironmentBlock (win_env); + /* Add USER, LOGNAME, HOME, LANG, just like sshd */ + posix_env[idx++] =3D create_env_var ("USER", pw->pw_name); + posix_env[idx++] =3D create_env_var ("LOGNAME", pw->pw_name); + posix_env[idx++] =3D create_env_var ("HOME", pw->pw_dir); + cp =3D getenv("LANG"); + if (cp) + posix_env[idx] =3D create_env_var ("LANG", cp); + cp =3D getenv("TERM"); + if (cp) + posix_env[idx] =3D create_env_var ("TERM", cp); + return posix_env; +} + int main (int argc, const char **argv) { + const char *cmd, **cmd_av, *fake_av[2]; + struct passwd *pw; struct group *gr; + char **child_env; + bool new_child_env =3D false; gid_t gid; - const char *cmd; - const char **cmd_av; - const char *fake_av[2]; =20 - /* TODO: Implement '-' option */ - /* TODO: Add command description to documentation */ + setlocale (LC_ALL, ""); =20 - if (argc < 2 || argv[1][0] =3D=3D '-') + if (argc < 2 || (argv[1][0] =3D=3D '-' && argv[1][1])) { - fprintf (stderr, - "Usage: %1$s group [command [args...]]\n" - "\n" - "%1$s changes the current primary group for a command.\n" - "The primary group must be member of the supplementary group\n" - "list of the user.\n" - "The command and its arguments are specified on the command\n" - "line. Default is the user's standard shell.\n", + fprintf (stderr, "Usage: %s [-] [group] [command [args...]]\n", program_invocation_short_name); return 1; } - if (isdigit ((int) argv[1][0])) + + /* Check if we have to regenerate a stock environment */ + if (argv[1][0] =3D=3D '-') { - char *e =3D NULL; + new_child_env =3D true; + --argc; + ++argv; + } =20 - gid =3D strtol (argv[1], &e, 10); - if (e && *e !=3D '\0') - { - fprintf (stderr, "%s: invalid gid `%s'\n", - program_invocation_short_name, argv[1]); - return 2; - } - gr =3D getgrgid (gid); - if (!gr) - { - fprintf (stderr, "%s: unknown group gid `%u'\n", - program_invocation_short_name, gid); - return 2; - } + pw =3D getpwuid (getuid ()); + + /* Fetch group */ + if (argv[1] =3D=3D NULL) + { + gid =3D pw->pw_gid; } else { gr =3D getgrnam (argv[1]); if (!gr) { - fprintf (stderr, "%s: unknown group name `%s'\n", + fprintf (stderr, "%s: group '%s' does not exist\n", program_invocation_short_name, argv[1]); return 2; } gid =3D gr->gr_gid; + --argc; + ++argv; } + + /* Set primary group */ if (setgid (gid) !=3D 0) { - fprintf (stderr, "%s: can't switch primary group to `%s'\n", + fprintf (stderr, "%s: can't switch primary group to '%s'\n", program_invocation_short_name, argv[1]); return 2; } - argc -=3D 2; - argv +=3D 2; + + /* Maybe generate stock child environment */ + if (!new_child_env) + child_env =3D environ; + else + { + child_env =3D create_child_env (pw); + if (!child_env) + return 3; + chdir (pw->pw_dir); + } + + /* Set argc/argv for execvpe */ + --argc; + ++argv; if (argc < 1) { - struct passwd *pw =3D getpwuid (getuid ()); if (!pw) cmd =3D "/usr/bin/bash"; else cmd =3D pw->pw_shell; - fake_av[0] =3D cmd; + fake_av[0] =3D new_child_env ? "-" : cmd; fake_av[1] =3D NULL; cmd_av =3D fake_av; } @@ -94,8 +212,12 @@ main (int argc, const char **argv) cmd =3D argv[0]; cmd_av =3D argv; } - execvp (cmd, (char **) cmd_av); - fprintf (stderr, "%s: failed to start `%s': %s\n", + + /* Exec child process */ + execvpe (cmd, (char **) cmd_av, child_env); + + /* Oops */ + fprintf (stderr, "%s: failed to start '%s': %s\n", program_invocation_short_name, cmd, strerror (errno)); - return 3; + return 4; }