-.\" $OpenBSD: doas.conf.5,v 1.26 2016/06/11 17:17:10 tedu Exp $
+.\" $OpenBSD: doas.conf.5,v 1.27 2016/06/27 15:41:17 tedu Exp $
.\"
.\"Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
.\"
.\"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: June 27 2016 $
.Dt DOAS.CONF 5
.Os
.Sh NAME
.Ev USER
and
.Ev USERNAME .
-.It Ic keepenv { Oo Ar variable ... Oc Ic }
+.It Ic setenv { Oo Ar variable ... Oc Ic 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 - 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.
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
and
-.Ev SSH_AUTH_SOCK ,
+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 nopass 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
-/* $OpenBSD: env.c,v 1.2 2016/06/19 19:29:43 martijn Exp $ */
+/* $OpenBSD: env.c,v 1.3 2016/06/27 15:41:17 tedu Exp $ */
/*
* Copyright (c) 2016 Ted Unangst <tedu@openbsd.org>
*
u_int count;
};
-int
+static int
envcmp(struct envnode *a, struct envnode *b)
{
return strcmp(a->key, b->key);
}
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;
RB_INIT(&env->root);
env->count = 0;
- for (i = 0; envp[i] != NULL; i++) {
- struct envnode *node;
- const char *e, *eq;
-
- e = envp[i];
-
- 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++;
+ if (rule->options & KEEPENV) {
+ extern const char **environ;
+
+ for (i = 0; environ[i] != NULL; i++) {
+ struct envnode *node;
+ const char *e, *eq;
+ size_t len;
+ char keybuf[1024];
+
+ e = environ[i];
+
+ /* ignore invalid or overlong names */
+ if ((eq = strchr(e, '=')) == NULL || eq == e)
+ continue;
+ len = eq - e;
+ if (len > sizeof(keybuf) - 1)
+ continue;
+ memcpy(keybuf, e, len);
+ keybuf[len] = '\0';
+
+ node = createnode(keybuf, 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;
}
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)
+char **
+prepenv(struct rule *rule)
{
- const char *safeset[] = {
+ static 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;
+ struct env *env;
+
+ env = createenv(rule);
+ /* if we started with blank, fill some defaults then apply rules */
+ if (!(rule->options & KEEPENV))
+ fillenv(env, safeset);
if (rule->envlist)
- copyenv(orig, copy, rule->envlist);
- copyenv(orig, copy, safeset);
-
- return copy;
-}
+ fillenv(env, rule->envlist);
-char **
-prepenv(struct rule *rule)
-{
- extern char **environ;
- struct env *env;
-
- env = createenv(environ);
- env = filterenv(env, rule);
return flattenenv(env);
}