1
0
mirror of https://github.com/slicer69/doas synced 2024-07-09 03:55:50 +00:00
doas/env.c
Jesse Smith c8cb4d999e Avoid echoing stdin when output is piped to doas.
Fix asprintf() compile warning when building on Linux.
2019-03-10 19:11:40 -03:00

217 lines
4.3 KiB
C

/* $OpenBSD: env.c,v 1.5 2016/09/15 00:58:23 deraadt Exp $ */
/*
* Copyright (c) 2016 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.
*/
#include <sys/types.h>
#ifndef linux
#include <sys/tree.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <unistd.h>
#include <errno.h>
#ifdef linux
#include "tree.h"
#endif
#include "doas.h"
struct envnode {
RB_ENTRY(envnode) node;
const char *key;
const char *value;
};
struct env {
RB_HEAD(envtree, envnode) root;
u_int count;
};
int
envcmp(struct envnode *a, struct envnode *b)
{
return strcmp(a->key, b->key);
}
#ifdef __DragonFly__
RB_PROTOTYPE_STATIC(envtree, envnode, node, envcmp);
#endif
RB_GENERATE_STATIC(envtree, envnode, node, envcmp)
static struct envnode *
createnode(const char *key, const char *value)
{
struct envnode *node;
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;
env = malloc(sizeof(*env));
if (!env)
err(1, NULL);
RB_INIT(&env->root);
env->count = 0;
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 name[1024];
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;
}
static char **
flattenenv(struct env *env)
{
char **envp;
struct envnode *node;
u_int i;
envp = reallocarray(NULL, env->count + 1, sizeof(char *));
if (!envp)
err(1, NULL);
i = 0;
RB_FOREACH(node, envtree, &env->root) {
if (asprintf(&envp[i], "%s=%s", node->key, node->value) == -1)
err(1, NULL);
i++;
}
envp[i] = NULL;
return envp;
}
static void
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++) {
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++;
}
}
}
char **
prepenv(struct rule *rule)
{
static const char *safeset[] = {
"DISPLAY", "HOME", "LOGNAME", "MAIL",
"PATH", "TERM", "USER", "USERNAME",
NULL
};
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)
fillenv(env, rule->envlist);
return flattenenv(env);
}