mirror of
https://github.com/slicer69/doas
synced 2024-10-06 16:09:06 +00:00
Merge branch 'katakk-up' Brings us up to speed with OpenBSD 5.9.
This commit is contained in:
commit
31f072078a
7
doas.1
7
doas.1
|
@ -25,6 +25,7 @@
|
|||
.Op Fl a Ar style
|
||||
.Op Fl C Ar config
|
||||
.Op Fl u Ar user
|
||||
.Op Fl -
|
||||
.Ar command
|
||||
.Op Ar args
|
||||
.Sh DESCRIPTION
|
||||
|
@ -80,6 +81,8 @@ or
|
|||
Execute the command as
|
||||
.Ar user .
|
||||
The default is root.
|
||||
.It Fl -
|
||||
Any dashes after a combined double dash (--) will be interpreted as part of the command to be run or its paramters. Not an argument passed to doas itself.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std doas
|
||||
|
@ -88,7 +91,7 @@ It may fail for one of the following reasons:
|
|||
.Bl -bullet -compact
|
||||
.It
|
||||
The config file
|
||||
.Pa /etc/doas.conf
|
||||
.Pa /usr/local/etc/doas.conf
|
||||
could not be parsed.
|
||||
.It
|
||||
The user attempted to run a command which is not permitted.
|
||||
|
@ -106,4 +109,4 @@ The
|
|||
command first appeared in
|
||||
.Ox 5.8 .
|
||||
.Sh AUTHORS
|
||||
.An Ted Unangst Aq Mt tedu@openbsd.org
|
||||
.An Ted Unangst Aq Mt tedu@openbsd.org
|
||||
|
|
118
doas.c
118
doas.c
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if defined(HAVE_INTTYPES_H)
|
||||
#include <inttypes.h>
|
||||
|
@ -39,6 +40,7 @@
|
|||
#include <grp.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#if defined(HAVE_LOGIN_CAP_H)
|
||||
#include <login_cap.h>
|
||||
|
@ -83,18 +85,6 @@ errc(int eval, int code, const char *format)
|
|||
}
|
||||
#endif
|
||||
|
||||
size_t
|
||||
arraylen(const char **arr)
|
||||
{
|
||||
size_t cnt = 0;
|
||||
|
||||
while (*arr) {
|
||||
cnt++;
|
||||
arr++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int
|
||||
parseuid(const char *s, uid_t *uid)
|
||||
{
|
||||
|
@ -254,6 +244,54 @@ checkconfig(const char *confpath, int argc, char **argv,
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(USE_BSD_AUTH)
|
||||
static void
|
||||
authuser(char *myname, char *login_style, int persist)
|
||||
{
|
||||
char *challenge = NULL, *response, rbuf[1024], cbuf[128];
|
||||
auth_session_t *as;
|
||||
int fd = -1;
|
||||
|
||||
if (persist)
|
||||
fd = open("/dev/tty", O_RDWR);
|
||||
if (fd != -1) {
|
||||
if (ioctl(fd, TIOCCHKVERAUTH) == 0)
|
||||
goto good;
|
||||
}
|
||||
|
||||
if (!(as = auth_userchallenge(myname, login_style, "auth-doas",
|
||||
&challenge)))
|
||||
errx(1, "Authorization failed");
|
||||
if (!challenge) {
|
||||
char host[HOST_NAME_MAX + 1];
|
||||
if (gethostname(host, sizeof(host)))
|
||||
snprintf(host, sizeof(host), "?");
|
||||
snprintf(cbuf, sizeof(cbuf),
|
||||
"\rdoas (%.32s@%.32s) password: ", myname, host);
|
||||
challenge = cbuf;
|
||||
}
|
||||
response = readpassphrase(challenge, rbuf, sizeof(rbuf),
|
||||
RPP_REQUIRE_TTY);
|
||||
if (response == NULL && errno == ENOTTY) {
|
||||
syslog(LOG_AUTHPRIV | LOG_NOTICE,
|
||||
"tty required for %s", myname);
|
||||
errx(1, "a tty is required");
|
||||
}
|
||||
if (!auth_userresponse(as, response, 0)) {
|
||||
syslog(LOG_AUTHPRIV | LOG_NOTICE,
|
||||
"failed auth for %s", myname);
|
||||
errc(1, EPERM, NULL);
|
||||
}
|
||||
explicit_bzero(rbuf, sizeof(rbuf));
|
||||
good:
|
||||
if (fd != -1) {
|
||||
int secs = 5 * 60;
|
||||
ioctl(fd, TIOCSETVERAUTH, &secs);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
@ -283,11 +321,6 @@ main(int argc, char **argv)
|
|||
setprogname("doas");
|
||||
#endif
|
||||
|
||||
/*
|
||||
if (pledge("stdio rpath getpw tty proc exec id", NULL) == -1)
|
||||
err(1, "pledge");
|
||||
*/
|
||||
|
||||
#ifndef linux
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
#endif
|
||||
|
@ -295,6 +328,7 @@ main(int argc, char **argv)
|
|||
uid = getuid();
|
||||
|
||||
while ((ch = getopt(argc, argv, "a:C:nsu:")) != -1) {
|
||||
/* while ((ch = getopt(argc, argv, "a:C:Lnsu:")) != -1) { */
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
login_style = optarg;
|
||||
|
@ -302,6 +336,12 @@ main(int argc, char **argv)
|
|||
case 'C':
|
||||
confpath = optarg;
|
||||
break;
|
||||
/* case 'L':
|
||||
i = open("/dev/tty", O_RDWR);
|
||||
if (i != -1)
|
||||
ioctl(i, TIOCCLRVERAUTH);
|
||||
exit(i != -1);
|
||||
*/
|
||||
case 'u':
|
||||
if (parseuid(optarg, &target) != 0)
|
||||
errx(1, "unknown user");
|
||||
|
@ -343,9 +383,11 @@ main(int argc, char **argv)
|
|||
|
||||
if (sflag) {
|
||||
sh = getenv("SHELL");
|
||||
if (sh == NULL || *sh == '\0')
|
||||
shargv[0] = pw->pw_shell;
|
||||
else
|
||||
if (sh == NULL || *sh == '\0') {
|
||||
shargv[0] = strdup(pw->pw_shell);
|
||||
if (shargv[0] == NULL)
|
||||
err(1, NULL);
|
||||
} else
|
||||
shargv[0] = sh;
|
||||
argv = shargv;
|
||||
argc = 1;
|
||||
|
@ -357,11 +399,14 @@ main(int argc, char **argv)
|
|||
exit(1); /* fail safe */
|
||||
}
|
||||
|
||||
if (geteuid())
|
||||
errx(1, "not installed setuid");
|
||||
|
||||
parseconfig(DOAS_CONF, 1);
|
||||
|
||||
/* cmdline is used only for logging, no need to abort on truncate */
|
||||
#ifndef linux
|
||||
(void) strlcpy(cmdline, argv[0], sizeof(cmdline));
|
||||
(void)strlcpy(cmdline, argv[0], sizeof(cmdline));
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strlcat(cmdline, " ", sizeof(cmdline)) >= sizeof(cmdline))
|
||||
break;
|
||||
|
@ -379,7 +424,7 @@ main(int argc, char **argv)
|
|||
|
||||
cmd = argv[0];
|
||||
if (!permit(uid, groups, ngroups, &rule, target, cmd,
|
||||
(const char**)argv + 1)) {
|
||||
(const char **)argv + 1)) {
|
||||
syslog(LOG_AUTHPRIV | LOG_NOTICE,
|
||||
"failed command for %s: %s", myname, cmdline);
|
||||
errc(1, EPERM, NULL);
|
||||
|
@ -387,36 +432,10 @@ main(int argc, char **argv)
|
|||
|
||||
if (!(rule->options & NOPASS)) {
|
||||
#if defined(USE_BSD_AUTH)
|
||||
char *challenge = NULL, *response, rbuf[1024], cbuf[128];
|
||||
auth_session_t *as;
|
||||
|
||||
if (nflag)
|
||||
errx(1, "Authorization required");
|
||||
|
||||
if (!(as = auth_userchallenge(myname, login_style, "auth-doas",
|
||||
&challenge)))
|
||||
errx(1, "Authorization failed");
|
||||
if (!challenge) {
|
||||
char host[MAXHOSTNAME + 1];
|
||||
if (gethostname(host, sizeof(host)))
|
||||
snprintf(host, sizeof(host), "?");
|
||||
snprintf(cbuf, sizeof(cbuf),
|
||||
"\rdoas (%.32s@%.32s) password: ", myname, host);
|
||||
challenge = cbuf;
|
||||
}
|
||||
response = readpassphrase(challenge, rbuf, sizeof(rbuf),
|
||||
RPP_REQUIRE_TTY);
|
||||
if (response == NULL && errno == ENOTTY) {
|
||||
syslog(LOG_AUTHPRIV | LOG_NOTICE,
|
||||
"tty required for %s", myname);
|
||||
errx(1, "a tty is required");
|
||||
}
|
||||
if (!auth_userresponse(as, response, 0)) {
|
||||
syslog(LOG_AUTHPRIV | LOG_NOTICE,
|
||||
"failed auth for %s", myname);
|
||||
errc(1, EPERM, NULL);
|
||||
}
|
||||
explicit_bzero(rbuf, sizeof(rbuf));
|
||||
authuser(myname, login_style, rule->options & PERSIST);
|
||||
#elif defined(USE_PAM)
|
||||
#define PAM_END(msg) do { \
|
||||
syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err)); \
|
||||
|
@ -518,7 +537,6 @@ main(int argc, char **argv)
|
|||
#else
|
||||
#error No auth module!
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
38
doas.conf.5
38
doas.conf.5
|
@ -1,4 +1,4 @@
|
|||
.\" $OpenBSD: doas.conf.5,v 1.26 2016/06/11 17:17:10 tedu Exp $
|
||||
.\" $OpenBSD: doas.conf.5,v 1.31 2016/12/05 10:58:07 schwarze Exp $
|
||||
.\"
|
||||
.\"Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
|
||||
.\"
|
||||
|
@ -13,7 +13,7 @@
|
|||
.\"WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
.\"ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\"OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.Dd $Mdocdate: June 11 2016 $
|
||||
.Dd $Mdocdate: December 5 2016 $
|
||||
.Dt DOAS.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -35,7 +35,7 @@ The rules have the following format:
|
|||
.Op Ar options
|
||||
.Ar identity
|
||||
.Op Ic as Ar target
|
||||
.Op Ic cmd Ar command Op Ic args ...
|
||||
.Op Ic cmd Ar command Op Ic args No ...
|
||||
.Ed
|
||||
.Pp
|
||||
Rules consist of the following parts:
|
||||
|
@ -47,6 +47,9 @@ Options are:
|
|||
.Bl -tag -width keepenv
|
||||
.It Ic nopass
|
||||
The user is not required to enter a password.
|
||||
.It Ic persist
|
||||
After the user successfully authenticates, do not ask for a password
|
||||
again for some time. Works on OpenBSD only, persist is not available on Linux or FreeBSD.
|
||||
.It Ic keepenv
|
||||
The user's environment is maintained.
|
||||
The default is to reset the environment, except for the variables
|
||||
|
@ -59,9 +62,18 @@ The default is to reset the environment, except for the variables
|
|||
.Ev USER
|
||||
and
|
||||
.Ev USERNAME .
|
||||
.It Ic keepenv { Oo Ar variable ... Oc Ic }
|
||||
.It Ic setenv { Oo Ar variable ... Oc Oo Ar variable=value ... Oc Ic }
|
||||
In addition to the variables mentioned above, keep the space-separated
|
||||
specified variables.
|
||||
Variables may also be removed with a leading
|
||||
.Sq -
|
||||
or set using the latter syntax.
|
||||
If the first character of
|
||||
.Ar value
|
||||
is a
|
||||
.Ql $
|
||||
then the value to be set is taken from the existing environment
|
||||
variable of the same name.
|
||||
.El
|
||||
.It Ar identity
|
||||
The username to match.
|
||||
|
@ -78,7 +90,7 @@ Be advised that it is best to specify absolute paths.
|
|||
If a relative path is specified, only a restricted
|
||||
.Ev PATH
|
||||
will be searched.
|
||||
.It Ic args ...
|
||||
.It Ic args Op Ar argument ...
|
||||
Arguments to command.
|
||||
The command arguments provided by the user need to match those specified.
|
||||
The keyword
|
||||
|
@ -109,25 +121,27 @@ If quotes or backslashes are used in a word,
|
|||
it is not considered a keyword.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
The following example permits users in group wsrc to build ports,
|
||||
The following example permits users in group wsrc to build ports;
|
||||
wheel to execute commands as any user while keeping the environment
|
||||
variables
|
||||
.Ev ENV ,
|
||||
.Ev PS1 ,
|
||||
.Ev PS1
|
||||
and
|
||||
.Ev SSH_AUTH_SOCK ,
|
||||
permits tedu to run procmap as root without a password,
|
||||
.Ev SSH_AUTH_SOCK
|
||||
and
|
||||
unsetting
|
||||
.Ev ENV ;
|
||||
permits tedu to run procmap as root without a password;
|
||||
and additionally permits root to run unrestricted commands as itself.
|
||||
.Bd -literal -offset indent
|
||||
# Non-exhaustive list of variables needed to
|
||||
# build release(8) and ports(7)
|
||||
permit nopass keepenv { \e
|
||||
permit nopass setenv { \e
|
||||
FTPMODE PKG_CACHE PKG_PATH SM_PATH SSH_AUTH_SOCK \e
|
||||
DESTDIR DISTDIR FETCH_CMD FLAVOR GROUP MAKE MAKECONF \e
|
||||
MULTI_PACKAGES NOMAN OKAY_FILES OWNER PKG_DBDIR \e
|
||||
PKG_DESTDIR PKG_TMPDIR PORTSDIR RELEASEDIR SHARED_ONLY \e
|
||||
SUBPACKAGE WRKOBJDIR SUDO_PORT_V1 } :wsrc
|
||||
permit nopass keepenv { ENV PS1 SSH_AUTH_SOCK } :wheel
|
||||
permit setenv { -ENV PS1=$DOAS_PS1 SSH_AUTH_SOCK } :wheel
|
||||
permit nopass tedu as root cmd /usr/sbin/procmap
|
||||
permit nopass keepenv root as root
|
||||
.Ed
|
||||
|
|
23
doas.h
23
doas.h
|
@ -1,4 +1,20 @@
|
|||
/* $OpenBSD: doas.h,v 1.8 2016/06/19 19:29:43 martijn Exp $ */
|
||||
/* $OpenBSD: doas.h,v 1.12 2016/10/05 17:40:25 tedu Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
struct rule {
|
||||
int action;
|
||||
int options;
|
||||
|
@ -10,11 +26,9 @@ struct rule {
|
|||
};
|
||||
|
||||
extern struct rule **rules;
|
||||
extern int nrules, maxrules;
|
||||
extern int nrules;
|
||||
extern int parse_errors;
|
||||
|
||||
size_t arraylen(const char **);
|
||||
|
||||
char **prepenv(struct rule *);
|
||||
|
||||
#define PERMIT 1
|
||||
|
@ -22,6 +36,7 @@ char **prepenv(struct rule *);
|
|||
|
||||
#define NOPASS 0x1
|
||||
#define KEEPENV 0x2
|
||||
#define PERSIST 0x4
|
||||
|
||||
#ifndef UID_MAX
|
||||
#define UID_MAX 65535
|
||||
|
|
191
env.c
191
env.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: env.c,v 1.2 2016/06/19 19:29:43 martijn Exp $ */
|
||||
/* $OpenBSD: env.c,v 1.5 2016/09/15 00:58:23 deraadt Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2016 Ted Unangst <tedu@openbsd.org>
|
||||
*
|
||||
|
@ -54,12 +54,31 @@ RB_PROTOTYPE_STATIC(envtree, envnode, node, envcmp);
|
|||
#endif
|
||||
RB_GENERATE_STATIC(envtree, envnode, node, envcmp)
|
||||
|
||||
struct env *createenv(char **);
|
||||
struct env *filterenv(struct env *, struct rule *);
|
||||
char **flattenenv(struct env *);
|
||||
static struct envnode *
|
||||
createnode(const char *key, const char *value)
|
||||
{
|
||||
struct envnode *node;
|
||||
|
||||
struct env *
|
||||
createenv(char **envp)
|
||||
node = malloc(sizeof(*node));
|
||||
if (!node)
|
||||
err(1, NULL);
|
||||
node->key = strdup(key);
|
||||
node->value = strdup(value);
|
||||
if (!node->key || !node->value)
|
||||
err(1, NULL);
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
freenode(struct envnode *node)
|
||||
{
|
||||
free((char *)node->key);
|
||||
free((char *)node->value);
|
||||
free(node);
|
||||
}
|
||||
|
||||
static struct env *
|
||||
createenv(struct rule *rule)
|
||||
{
|
||||
struct env *env;
|
||||
u_int i;
|
||||
|
@ -70,41 +89,47 @@ createenv(char **envp)
|
|||
RB_INIT(&env->root);
|
||||
env->count = 0;
|
||||
|
||||
for (i = 0; envp[i] != NULL; i++) {
|
||||
struct envnode *node;
|
||||
const char *e, *eq;
|
||||
if (rule->options & KEEPENV) {
|
||||
extern const char **environ;
|
||||
|
||||
e = envp[i];
|
||||
for (i = 0; environ[i] != NULL; i++) {
|
||||
struct envnode *node;
|
||||
const char *e, *eq;
|
||||
size_t len;
|
||||
char name[1024];
|
||||
|
||||
if ((eq = strchr(e, '=')) == NULL || eq == e)
|
||||
continue;
|
||||
node = malloc(sizeof(*node));
|
||||
if (!node)
|
||||
err(1, NULL);
|
||||
node->key = strndup(envp[i], eq - e);
|
||||
node->value = strdup(eq + 1);
|
||||
if (!node->key || !node->value)
|
||||
err(1, NULL);
|
||||
if (RB_FIND(envtree, &env->root, node)) {
|
||||
free((char *)node->key);
|
||||
free((char *)node->value);
|
||||
free(node);
|
||||
} else {
|
||||
RB_INSERT(envtree, &env->root, node);
|
||||
env->count++;
|
||||
e = environ[i];
|
||||
|
||||
/* ignore invalid or overlong names */
|
||||
if ((eq = strchr(e, '=')) == NULL || eq == e)
|
||||
continue;
|
||||
len = eq - e;
|
||||
if (len > sizeof(name) - 1)
|
||||
continue;
|
||||
memcpy(name, e, len);
|
||||
name[len] = '\0';
|
||||
|
||||
node = createnode(name, eq + 1);
|
||||
if (RB_INSERT(envtree, &env->root, node)) {
|
||||
/* ignore any later duplicates */
|
||||
freenode(node);
|
||||
} else {
|
||||
env->count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
char **
|
||||
static char **
|
||||
flattenenv(struct env *env)
|
||||
{
|
||||
char **envp;
|
||||
struct envnode *node;
|
||||
u_int i;
|
||||
|
||||
envp = reallocarray(NULL, (env->count + 1), sizeof(char *));
|
||||
envp = reallocarray(NULL, env->count + 1, sizeof(char *));
|
||||
if (!envp)
|
||||
err(1, NULL);
|
||||
i = 0;
|
||||
|
@ -118,72 +143,74 @@ flattenenv(struct env *env)
|
|||
}
|
||||
|
||||
static void
|
||||
copyenv(struct env *orig, struct env *copy, const char **envlist)
|
||||
fillenv(struct env *env, const char **envlist)
|
||||
{
|
||||
struct envnode *node, key;
|
||||
const char *e, *eq;
|
||||
const char *val;
|
||||
char name[1024];
|
||||
u_int i;
|
||||
size_t len;
|
||||
|
||||
for (i = 0; envlist[i]; i++) {
|
||||
key.key = envlist[i];
|
||||
if ((node = RB_FIND(envtree, &orig->root, &key))) {
|
||||
RB_REMOVE(envtree, &orig->root, node);
|
||||
orig->count--;
|
||||
RB_INSERT(envtree, ©->root, node);
|
||||
copy->count++;
|
||||
e = envlist[i];
|
||||
|
||||
/* parse out env name */
|
||||
if ((eq = strchr(e, '=')) == NULL)
|
||||
len = strlen(e);
|
||||
else
|
||||
len = eq - e;
|
||||
if (len > sizeof(name) - 1)
|
||||
continue;
|
||||
memcpy(name, e, len);
|
||||
name[len] = '\0';
|
||||
|
||||
/* delete previous copies */
|
||||
key.key = name;
|
||||
if (*name == '-')
|
||||
key.key = name + 1;
|
||||
if ((node = RB_FIND(envtree, &env->root, &key))) {
|
||||
RB_REMOVE(envtree, &env->root, node);
|
||||
freenode(node);
|
||||
env->count--;
|
||||
}
|
||||
if (*name == '-')
|
||||
continue;
|
||||
|
||||
/* assign value or inherit from environ */
|
||||
if (eq) {
|
||||
val = eq + 1;
|
||||
if (*val == '$')
|
||||
val = getenv(val + 1);
|
||||
} else {
|
||||
val = getenv(name);
|
||||
}
|
||||
/* at last, we have something to insert */
|
||||
if (val) {
|
||||
node = createnode(name, val);
|
||||
RB_INSERT(envtree, &env->root, node);
|
||||
env->count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct env *
|
||||
filterenv(struct env *orig, struct rule *rule)
|
||||
{
|
||||
const char *safeset[] = {
|
||||
"DISPLAY", "HOME", "LOGNAME", "MAIL",
|
||||
"PATH", "TERM", "USER", "USERNAME",
|
||||
NULL
|
||||
};
|
||||
const char *badset[] = {
|
||||
"ENV",
|
||||
NULL
|
||||
};
|
||||
struct env *copy;
|
||||
struct envnode *node, key;
|
||||
u_int i;
|
||||
|
||||
if ((rule->options & KEEPENV) && !rule->envlist) {
|
||||
for (i = 0; badset[i]; i++) {
|
||||
key.key = badset[i];
|
||||
if ((node = RB_FIND(envtree, &orig->root, &key))) {
|
||||
RB_REMOVE(envtree, &orig->root, node);
|
||||
free((char *)node->key);
|
||||
free((char *)node->value);
|
||||
free(node);
|
||||
orig->count--;
|
||||
}
|
||||
}
|
||||
return orig;
|
||||
}
|
||||
|
||||
copy = malloc(sizeof(*copy));
|
||||
if (!copy)
|
||||
err(1, NULL);
|
||||
RB_INIT(©->root);
|
||||
copy->count = 0;
|
||||
|
||||
if (rule->envlist)
|
||||
copyenv(orig, copy, rule->envlist);
|
||||
copyenv(orig, copy, safeset);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
char **
|
||||
prepenv(struct rule *rule)
|
||||
{
|
||||
extern char **environ;
|
||||
static const char *safeset[] = {
|
||||
"DISPLAY", "HOME", "LOGNAME", "MAIL",
|
||||
"PATH", "TERM", "USER", "USERNAME",
|
||||
NULL
|
||||
};
|
||||
struct env *env;
|
||||
|
||||
env = createenv(environ);
|
||||
env = filterenv(env, rule);
|
||||
|
||||
env = createenv(rule);
|
||||
|
||||
/* if we started with blank, fill some defaults then apply rules */
|
||||
if (!(rule->options & KEEPENV))
|
||||
fillenv(env, safeset);
|
||||
if (rule->envlist)
|
||||
fillenv(env, rule->envlist);
|
||||
|
||||
return flattenenv(env);
|
||||
}
|
||||
|
|
91
parse.y
91
parse.y
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: parse.y,v 1.18 2016/06/07 16:49:23 tedu Exp $ */
|
||||
/* $OpenBSD: parse.y,v 1.26 2017/01/02 01:40:20 tedu Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
|
||||
*
|
||||
|
@ -37,6 +37,7 @@ typedef struct {
|
|||
const char **cmdargs;
|
||||
const char **envlist;
|
||||
};
|
||||
const char **strlist;
|
||||
const char *str;
|
||||
};
|
||||
int lineno;
|
||||
|
@ -47,17 +48,30 @@ typedef struct {
|
|||
FILE *yyfp;
|
||||
|
||||
struct rule **rules;
|
||||
int nrules, maxrules;
|
||||
int nrules;
|
||||
static int maxrules;
|
||||
|
||||
int parse_errors = 0;
|
||||
|
||||
void yyerror(const char *, ...);
|
||||
int yylex(void);
|
||||
int yyparse(void);
|
||||
static void yyerror(const char *, ...);
|
||||
static int yylex(void);
|
||||
|
||||
static size_t
|
||||
arraylen(const char **arr)
|
||||
{
|
||||
size_t cnt = 0;
|
||||
|
||||
while (*arr) {
|
||||
cnt++;
|
||||
arr++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%token TPERMIT TDENY TAS TCMD TARGS
|
||||
%token TNOPASS TKEEPENV
|
||||
%token TNOPASS TPERSIST TKEEPENV TSETENV
|
||||
%token TSTRING
|
||||
|
||||
%%
|
||||
|
@ -98,15 +112,23 @@ action: TPERMIT options {
|
|||
$$.envlist = $2.envlist;
|
||||
} | TDENY {
|
||||
$$.action = DENY;
|
||||
$$.options = 0;
|
||||
$$.envlist = NULL;
|
||||
} ;
|
||||
|
||||
options: /* none */
|
||||
| options option {
|
||||
options: /* none */ {
|
||||
$$.options = 0;
|
||||
$$.envlist = NULL;
|
||||
} | options option {
|
||||
$$.options = $1.options | $2.options;
|
||||
$$.envlist = $1.envlist;
|
||||
if (($$.options & (NOPASS|PERSIST)) == (NOPASS|PERSIST)) {
|
||||
yyerror("can't combine nopass and persist");
|
||||
YYERROR;
|
||||
}
|
||||
if ($2.envlist) {
|
||||
if ($$.envlist) {
|
||||
yyerror("can't have two keepenv sections");
|
||||
yyerror("can't have two setenv sections");
|
||||
YYERROR;
|
||||
} else
|
||||
$$.envlist = $2.envlist;
|
||||
|
@ -114,24 +136,29 @@ options: /* none */
|
|||
} ;
|
||||
option: TNOPASS {
|
||||
$$.options = NOPASS;
|
||||
$$.envlist = NULL;
|
||||
} | TPERSIST {
|
||||
$$.options = PERSIST;
|
||||
$$.envlist = NULL;
|
||||
} | TKEEPENV {
|
||||
$$.options = KEEPENV;
|
||||
} | TKEEPENV '{' envlist '}' {
|
||||
$$.options = KEEPENV;
|
||||
$$.envlist = $3.envlist;
|
||||
$$.envlist = NULL;
|
||||
} | TSETENV '{' strlist '}' {
|
||||
$$.options = 0;
|
||||
$$.envlist = $3.strlist;
|
||||
} ;
|
||||
|
||||
envlist: /* empty */ {
|
||||
if (!($$.envlist = calloc(1, sizeof(char *))))
|
||||
errx(1, "can't allocate envlist");
|
||||
} | envlist TSTRING {
|
||||
int nenv = arraylen($1.envlist);
|
||||
if (!($$.envlist = reallocarray($1.envlist, nenv + 2,
|
||||
strlist: /* empty */ {
|
||||
if (!($$.strlist = calloc(1, sizeof(char *))))
|
||||
errx(1, "can't allocate strlist");
|
||||
} | strlist TSTRING {
|
||||
int nstr = arraylen($1.strlist);
|
||||
if (!($$.strlist = reallocarray($1.strlist, nstr + 2,
|
||||
sizeof(char *))))
|
||||
errx(1, "can't allocate envlist");
|
||||
$$.envlist[nenv] = $2.str;
|
||||
$$.envlist[nenv + 1] = NULL;
|
||||
}
|
||||
errx(1, "can't allocate strlist");
|
||||
$$.strlist[nstr] = $2.str;
|
||||
$$.strlist[nstr + 1] = NULL;
|
||||
} ;
|
||||
|
||||
|
||||
ident: TSTRING {
|
||||
|
@ -154,20 +181,8 @@ cmd: /* optional */ {
|
|||
|
||||
args: /* empty */ {
|
||||
$$.cmdargs = NULL;
|
||||
} | TARGS argslist {
|
||||
$$.cmdargs = $2.cmdargs;
|
||||
} ;
|
||||
|
||||
argslist: /* empty */ {
|
||||
if (!($$.cmdargs = calloc(1, sizeof(char *))))
|
||||
errx(1, "can't allocate args");
|
||||
} | argslist TSTRING {
|
||||
int nargs = arraylen($1.cmdargs);
|
||||
if (!($$.cmdargs = reallocarray($1.cmdargs, nargs + 2,
|
||||
sizeof(char *))))
|
||||
errx(1, "can't allocate args");
|
||||
$$.cmdargs[nargs] = $2.str;
|
||||
$$.cmdargs[nargs + 1] = NULL;
|
||||
} | TARGS strlist {
|
||||
$$.cmdargs = $2.strlist;
|
||||
} ;
|
||||
|
||||
%%
|
||||
|
@ -185,7 +200,7 @@ yyerror(const char *fmt, ...)
|
|||
parse_errors++;
|
||||
}
|
||||
|
||||
struct keyword {
|
||||
static struct keyword {
|
||||
const char *word;
|
||||
int token;
|
||||
} keywords[] = {
|
||||
|
@ -195,7 +210,9 @@ struct keyword {
|
|||
{ "cmd", TCMD },
|
||||
{ "args", TARGS },
|
||||
{ "nopass", TNOPASS },
|
||||
{ "persist", TPERSIST },
|
||||
{ "keepenv", TKEEPENV },
|
||||
{ "setenv", TSETENV },
|
||||
};
|
||||
|
||||
int
|
||||
|
|
Loading…
Reference in a new issue