From 85c8521e67a73f2076a280e7ae3bf4f44adcef76 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Wed, 5 Feb 2020 04:29:55 +0000 Subject: [PATCH] env(1): grow -L user/class and -U user/class options This allows one to set the environment of the specified user either from login.conf alone (-L) or both login.conf and ~/.login_conf if present (-U). This is a supporting feature to allow service(8) to pull in the environment of the "daemon" class before invoking the rc script. This is a part of D21481. Submitted by: Andrew Gierth < andrew_tao173.riddles.org.uk> --- usr.bin/env/Makefile | 2 ++ usr.bin/env/env.1 | 34 ++++++++++++++++++++-- usr.bin/env/env.c | 69 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 100 insertions(+), 5 deletions(-) diff --git a/usr.bin/env/Makefile b/usr.bin/env/Makefile index 89ab59472630..14c3d4cca3f3 100644 --- a/usr.bin/env/Makefile +++ b/usr.bin/env/Makefile @@ -4,4 +4,6 @@ PROG= env SRCS= env.c envopts.c +LIBADD= util + .include diff --git a/usr.bin/env/env.1 b/usr.bin/env/env.1 index bb3e4e719526..4584fde75756 100644 --- a/usr.bin/env/env.1 +++ b/usr.bin/env/env.1 @@ -31,7 +31,7 @@ .\" From FreeBSD: src/usr.bin/printenv/printenv.1,v 1.17 2002/11/26 17:33:35 ru Exp .\" $FreeBSD$ .\" -.Dd November 7, 2019 +.Dd January 19, 2020 .Dt ENV 1 .Os .Sh NAME @@ -40,6 +40,7 @@ .Sh SYNOPSIS .Nm .Op Fl 0iv +.Op Fl L Ns | Ns Fl U Ar user Ns Op / Ns Ar class .Op Fl P Ar altpath .Op Fl S Ar string .Op Fl u Ar name @@ -76,6 +77,28 @@ The environment inherited by .Nm is ignored completely. +.\" -L | -U +.It Fl L | Fl U Ar user Ns Op / Ns Ar class +Add the environment variable definitions from +.Xr login.conf 5 +for the specified user and login class to the environment, after +processing any +.Fl i +or +.Fl u +options, but before processing any +.Ar name Ns = Ns Ar value +options. +If +.Fl L +is used, only the system-wide +.Pa /etc/login.conf.db +file is read; if +.Fl U +is used, then the specified user's +.Pa ~/.login_conf +is read as well. +The user may be specified by name or by uid. .\" -P .It Fl P Ar altpath Search the set of directories as specified by @@ -450,6 +473,7 @@ option as a synonym for .Xr printenv 1 , .Xr sh 1 , .Xr execvp 3 , +.Xr login.conf 5 , .Xr environ 7 .Sh STANDARDS The @@ -457,7 +481,7 @@ The utility conforms to .St -p1003.1-2001 . The -.Fl P , S , u +.Fl 0 , L , P , S , U , u and .Fl v options are non-standard extensions supported by @@ -474,6 +498,12 @@ and .Fl v options were added in .Fx 6.0 . +The +.Fl 0 , L +and +.Fl U +options were added in +.Fx 13.0 . .Sh BUGS The .Nm diff --git a/usr.bin/env/env.c b/usr.bin/env/env.c index 25aed26f2676..e408577ea7a4 100644 --- a/usr.bin/env/env.c +++ b/usr.bin/env/env.c @@ -44,11 +44,16 @@ static char sccsid[] = "@(#)env.c 8.3 (Berkeley) 4/2/94"; #include __FBSDID("$FreeBSD$"); +#include + #include #include +#include +#include +#include #include -#include #include +#include #include #include "envopts.h" @@ -71,13 +76,23 @@ main(int argc, char **argv) { char *altpath, **ep, *p, **parg, term; char *cleanenv[1]; + char *login_class, *login_name; + struct passwd *pw; + login_cap_t *lc; + bool login_as_user; + uid_t uid; int ch, want_clear; int rtrn; altpath = NULL; + login_class = NULL; + login_name = NULL; + pw = NULL; + lc = NULL; + login_as_user = false; want_clear = 0; term = '\n'; - while ((ch = getopt(argc, argv, "-0iP:S:u:v")) != -1) + while ((ch = getopt(argc, argv, "-0iL:P:S:U:u:v")) != -1) switch(ch) { case '-': case 'i': @@ -86,6 +101,12 @@ main(int argc, char **argv) case '0': term = '\0'; break; + case 'U': + login_as_user = true; + /* FALLTHROUGH */ + case 'L': + login_name = optarg; + break; case 'P': altpath = strdup(optarg); break; @@ -119,6 +140,48 @@ main(int argc, char **argv) if (env_verbosity) fprintf(stderr, "#env clearing environ\n"); } + if (login_name != NULL) { + login_class = strchr(login_name, '/'); + if (login_class) + *login_class++ = '\0'; + pw = getpwnam(login_name); + if (pw == NULL) { + char *endp = NULL; + errno = 0; + uid = strtoul(login_name, &endp, 10); + if (errno == 0 && *endp == '\0') + pw = getpwuid(uid); + } + if (pw == NULL) + errx(EXIT_FAILURE, "no such user: %s", login_name); + if (login_class != NULL) { + lc = login_getclass(login_class); + if (lc == NULL) + errx(EXIT_FAILURE, "no such login class: %s", + login_class); + } else { + lc = login_getpwclass(pw); + if (lc == NULL) + errx(EXIT_FAILURE, "login_getpwclass failed"); + } + + /* + * This is not done with setusercontext() because that will + * try and use ~/.login_conf even when we don't want it to. + */ + setclassenvironment(lc, pw, 1); + setclassenvironment(lc, pw, 0); + if (login_as_user) { + login_close(lc); + if ((lc = login_getuserclass(pw)) != NULL) { + setclassenvironment(lc, pw, 1); + setclassenvironment(lc, pw, 0); + } + } + endpwent(); + if (lc != NULL) + login_close(lc); + } for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv) { if (env_verbosity) fprintf(stderr, "#env setenv:\t%s\n", *argv); @@ -154,7 +217,7 @@ static void usage(void) { (void)fprintf(stderr, - "usage: env [-0iv] [-P utilpath] [-S string] [-u name]\n" + "usage: env [-0iv] [-L|-U user[/class]] [-P utilpath] [-S string] [-u name]\n" " [name=value ...] [utility [argument ...]]\n"); exit(1); }