]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
setpriv: add --reset-env
authorKarel Zak <kzak@redhat.com>
Wed, 22 Aug 2018 09:43:32 +0000 (11:43 +0200)
committerKarel Zak <kzak@redhat.com>
Wed, 22 Aug 2018 09:43:32 +0000 (11:43 +0200)
Clear environment in way like su(1), but PATH is set to hard-coded
defaults and /etc/login.defs is not used at all (I guess we want to
keep setpriv(1) simple).

If you need anything more advanced than use env(1).

Addresses: https://github.com/karelzak/util-linux/issues/325
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/setpriv.1
sys-utils/setpriv.c

index 9b7f43bc8f578134e7c7cc13c9d2584abceac1c5..9ff9058ecd6336bb0af1af9b91962488ce1dea0d 100644 (file)
@@ -165,6 +165,15 @@ to abort if AppArmor is not in use, and the transition may be ignored or cause
 .BR execve (2)
 to fail at AppArmor's whim.
 .TP
+.BI \-\-reset\-env
+Clears all the environment variables except TERM; initializes the environment variables HOME, SHELL, USER, LOGNAME
+according to the user's passwd entry; sets PATH to \fI/usr/local/bin:/bin:/usr/bin\fR for a regual user and to
+\fI/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\fR for root.
+.sp
+The environment variable PATH may be different on systems where /bin and /sbin
+are merged into /usr.  The environment variable SHELL defaults to \fI/bin/sh\fR if none is given in the user's
+passwd entry.
+.TP
 .BR \-V , " \-\-version"
 Display version information and exit.
 .TP
index 564c56d48fe8b3ae9f8033f96edf880b6c13df86..eba5decab3a0183845bc6b3d71b047e5d5890988 100644 (file)
@@ -39,6 +39,7 @@
 #include "xalloc.h"
 #include "pathnames.h"
 #include "signames.h"
+#include "env.h"
 
 #ifndef PR_SET_NO_NEW_PRIVS
 # define PR_SET_NO_NEW_PRIVS 38
@@ -56,6 +57,9 @@
 
 #define SETPRIV_EXIT_PRIVERR 127       /* how we exit when we fail to set privs */
 
+/* The shell to set SHELL env.variable if none is given in the user's passwd entry.  */
+#define DEFAULT_SHELL "/bin/sh"
+
 static gid_t get_group(const char *s, const char *err);
 
 enum cap_type {
@@ -85,6 +89,7 @@ struct privctx {
                keep_groups:1,          /* keep groups */
                clear_groups:1,         /* remove groups */
                init_groups:1,          /* initialize groups */
+               reset_env:1,            /* reset environment */
                have_securebits:1;      /* remove groups */
 
        /* uids and gids */
@@ -140,10 +145,13 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" --init-groups               initialize supplementary groups\n"), out);
        fputs(_(" --groups <group,...>        set supplementary groups by UID or name\n"), out);
        fputs(_(" --securebits <bits>         set securebits\n"), out);
+       fputs(_(" --reset-env                 reset environment variables\n"), out);
        fputs(_(" --pdeathsig keep|clear|<signame>\n"
                "                             set or clear parent death signal\n"), out);
        fputs(_(" --selinux-label <label>     set SELinux label\n"), out);
        fputs(_(" --apparmor-profile <pr>     set AppArmor profile\n"), out);
+       fputs(_(" --reset-env                 clear all environment and initialize\n"
+               "                               HOME, SHELL, USER, LOGNAME and PATH\n"), out);
 
        fputs(USAGE_SEPARATOR, out);
        printf(USAGE_HELP_OPTIONS(29));
@@ -681,6 +689,36 @@ static void do_apparmor_profile(const char *label)
                    _("write failed: %s"), _PATH_PROC_ATTR_EXEC);
 }
 
+
+static void do_reset_environ(struct passwd *pw)
+{
+       char *term = getenv("TERM");
+
+       if (term)
+               term = xstrdup(term);
+#ifdef HAVE_CLEARENV
+       clearenv();
+#else
+       environ = NULL;
+#endif
+       if (term)
+               xsetenv("TERM", term, 1);
+
+       if (pw->pw_shell && *pw->pw_shell)
+               xsetenv("SHELL", pw->pw_shell, 1);
+       else
+               xsetenv("SHELL", DEFAULT_SHELL, 1);
+
+       xsetenv("HOME", pw->pw_dir, 1);
+       xsetenv("USER", pw->pw_name, 1);
+       xsetenv("LOGNAME", pw->pw_name, 1);
+
+       if (pw->pw_uid)
+               xsetenv("PATH", _PATH_DEFPATH, 1);
+       else
+               xsetenv("PATH", _PATH_DEFPATH_ROOT, 1);
+}
+
 static uid_t get_user(const char *s, const char *err)
 {
        struct passwd *pw;
@@ -751,7 +789,8 @@ int main(int argc, char **argv)
                SECUREBITS,
                PDEATHSIG,
                SELINUX_LABEL,
-               APPARMOR_PROFILE
+               APPARMOR_PROFILE,
+               RESET_ENV
        };
 
        static const struct option longopts[] = {
@@ -777,6 +816,7 @@ int main(int argc, char **argv)
                { "selinux-label",    required_argument, NULL, SELINUX_LABEL    },
                { "apparmor-profile", required_argument, NULL, APPARMOR_PROFILE },
                { "help",             no_argument,       NULL, 'h'              },
+               { "reset-env",        no_argument,       NULL, RESET_ENV,       },
                { "version",          no_argument,       NULL, 'V'              },
                { NULL, 0, NULL, 0 }
        };
@@ -929,6 +969,9 @@ int main(int argc, char **argv)
                                     _("duplicate --apparmor-profile option"));
                        opts.apparmor_profile = optarg;
                        break;
+               case RESET_ENV:
+                       opts.reset_env = 1;
+                       break;
                case 'h':
                        usage();
                case 'V':
@@ -974,6 +1017,16 @@ int main(int argc, char **argv)
                       "can be found on the system"),
                     (long) opts.ruid);
 
+       if (opts.reset_env) {
+               if (opts.have_passwd)
+                       /* pwd according to --ruid or --reuid */
+                       pw = &opts.passwd;
+               else
+                       /* pwd for the current user */
+                       pw = getpwuid(getuid());
+               do_reset_environ(pw);
+       }
+
        if (opts.nnp && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
                err(EXIT_FAILURE, _("disallow granting new privileges failed"));