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 }