doas

https://man.openbsd.org/doas.1
git clone anongit@rnpnr.xyz:doas.git
Log | Files | Refs | Feed

env.c (4801B)


      1 /* $OpenBSD: env.c,v 1.10 2019/07/07 19:21:28 tedu Exp $ */
      2 /*
      3  * Copyright (c) 2016 Ted Unangst <tedu@openbsd.org>
      4  *
      5  * Permission to use, copy, modify, and distribute this software for any
      6  * purpose with or without fee is hereby granted, provided that the above
      7  * copyright notice and this permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16  */
     17 
     18 #include <sys/types.h>
     19 #include <sys/tree.h>
     20 
     21 #include <string.h>
     22 #include <stdio.h>
     23 #include <stdlib.h>
     24 #include <err.h>
     25 #include <unistd.h>
     26 #include <errno.h>
     27 #include <pwd.h>
     28 
     29 #include "doas.h"
     30 
     31 const char *safepath = "/bin";
     32 
     33 struct envnode {
     34 	RB_ENTRY(envnode) node;
     35 	const char *key;
     36 	const char *value;
     37 };
     38 
     39 struct env {
     40 	RB_HEAD(envtree, envnode) root;
     41 	u_int count;
     42 };
     43 
     44 static void fillenv(struct env *env, const char **envlist);
     45 
     46 static int
     47 envcmp(struct envnode *a, struct envnode *b)
     48 {
     49 	return strcmp(a->key, b->key);
     50 }
     51 RB_GENERATE_STATIC(envtree, envnode, node, envcmp)
     52 
     53 static struct envnode *
     54 createnode(const char *key, const char *value)
     55 {
     56 	struct envnode *node;
     57 
     58 	node = malloc(sizeof(*node));
     59 	if (!node)
     60 		err(1, NULL);
     61 	node->key = strdup(key);
     62 	node->value = strdup(value);
     63 	if (!node->key || !node->value)
     64 		err(1, NULL);
     65 	return node;
     66 }
     67 
     68 static void
     69 freenode(struct envnode *node)
     70 {
     71 	free((char *)node->key);
     72 	free((char *)node->value);
     73 	free(node);
     74 }
     75 
     76 static void
     77 addnode(struct env *env, const char *key, const char *value)
     78 {
     79 	struct envnode *node;
     80 
     81 	node = createnode(key, value);
     82 	RB_INSERT(envtree, &env->root, node);
     83 	env->count++;
     84 }
     85 
     86 static struct env *
     87 createenv(const struct rule *rule, const struct passwd *mypw,
     88     const struct passwd *targpw)
     89 {
     90 	static const char *copyset[] = {
     91 		"DISPLAY", "TERM",
     92 		NULL
     93 	};
     94 	struct env *env;
     95 	u_int i;
     96 
     97 	env = malloc(sizeof(*env));
     98 	if (!env)
     99 		err(1, NULL);
    100 	RB_INIT(&env->root);
    101 	env->count = 0;
    102 
    103 	addnode(env, "DOAS_USER", mypw->pw_name);
    104 	addnode(env, "HOME", targpw->pw_dir);
    105 	addnode(env, "LOGNAME", targpw->pw_name);
    106 	addnode(env, "PATH", safepath);
    107 	addnode(env, "SHELL", targpw->pw_shell);
    108 	addnode(env, "USER", targpw->pw_name);
    109 
    110 	fillenv(env, copyset);
    111 
    112 	if (rule->options & KEEPENV) {
    113 		extern const char **environ;
    114 
    115 		for (i = 0; environ[i] != NULL; i++) {
    116 			struct envnode *node;
    117 			const char *e, *eq;
    118 			size_t len;
    119 			char name[1024];
    120 
    121 			e = environ[i];
    122 
    123 			/* ignore invalid or overlong names */
    124 			if ((eq = strchr(e, '=')) == NULL || eq == e)
    125 				continue;
    126 			len = eq - e;
    127 			if (len > sizeof(name) - 1)
    128 				continue;
    129 			memcpy(name, e, len);
    130 			name[len] = '\0';
    131 
    132 			node = createnode(name, eq + 1);
    133 			if (RB_INSERT(envtree, &env->root, node)) {
    134 				/* ignore any later duplicates */
    135 				freenode(node);
    136 			} else {
    137 				env->count++;
    138 			}
    139 		}
    140 	}
    141 
    142 	return env;
    143 }
    144 
    145 static char **
    146 flattenenv(struct env *env)
    147 {
    148 	char **envp;
    149 	struct envnode *node;
    150 	u_int i;
    151 
    152 	envp = reallocarray(NULL, env->count + 1, sizeof(char *));
    153 	if (!envp)
    154 		err(1, NULL);
    155 	i = 0;
    156 	RB_FOREACH(node, envtree, &env->root) {
    157 		if (asprintf(&envp[i], "%s=%s", node->key, node->value) == -1)
    158 			err(1, NULL);
    159 		i++;
    160 	}
    161 	envp[i] = NULL;
    162 	return envp;
    163 }
    164 
    165 static void
    166 fillenv(struct env *env, const char **envlist)
    167 {
    168 	struct envnode *node, key;
    169 	const char *e, *eq;
    170 	const char *val;
    171 	char name[1024];
    172 	u_int i;
    173 	size_t len;
    174 
    175 	for (i = 0; envlist[i]; i++) {
    176 		e = envlist[i];
    177 
    178 		/* parse out env name */
    179 		if ((eq = strchr(e, '=')) == NULL)
    180 			len = strlen(e);
    181 		else
    182 			len = eq - e;
    183 		if (len > sizeof(name) - 1)
    184 			continue;
    185 		memcpy(name, e, len);
    186 		name[len] = '\0';
    187 
    188 		/* delete previous copies */
    189 		key.key = name;
    190 		if (*name == '-')
    191 			key.key = name + 1;
    192 		if ((node = RB_FIND(envtree, &env->root, &key))) {
    193 			RB_REMOVE(envtree, &env->root, node);
    194 			freenode(node);
    195 			env->count--;
    196 		}
    197 		if (*name == '-')
    198 			continue;
    199 
    200 		/* assign value or inherit from environ */
    201 		if (eq) {
    202 			val = eq + 1;
    203 			if (*val == '$')
    204 				val = getenv(val + 1);
    205 		} else {
    206 			val = getenv(name);
    207 		}
    208 		/* at last, we have something to insert */
    209 		if (val) {
    210 			node = createnode(name, val);
    211 			RB_INSERT(envtree, &env->root, node);
    212 			env->count++;
    213 		}
    214 	}
    215 }
    216 
    217 char **
    218 prepenv(const struct rule *rule, const struct passwd *mypw,
    219     const struct passwd *targpw)
    220 {
    221 	struct env *env;
    222 
    223 	env = createenv(rule, mypw, targpw);
    224 	if (rule->envlist)
    225 		fillenv(env, rule->envlist);
    226 
    227 	return flattenenv(env);
    228 }