1 /* $OpenBSD: env.c,v 1.5 2016/09/15 00:58:23 deraadt Exp $ */
3 * Copyright (c) 2016 Ted Unangst <tedu@openbsd.org>
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.
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.
18 #include <sys/types.h>
37 RB_ENTRY(envnode
) node
;
43 RB_HEAD(envtree
, envnode
) root
;
48 envcmp(struct envnode
*a
, struct envnode
*b
)
50 return strcmp(a
->key
, b
->key
);
53 RB_PROTOTYPE_STATIC(envtree
, envnode
, node
, envcmp
);
55 RB_GENERATE_STATIC(envtree
, envnode
, node
, envcmp
)
57 static struct envnode
*
58 createnode(const char *key
, const char *value
)
62 node
= malloc(sizeof(*node
));
65 node
->key
= strdup(key
);
66 node
->value
= strdup(value
);
67 if (!node
->key
|| !node
->value
)
73 freenode(struct envnode
*node
)
75 free((char *)node
->key
);
76 free((char *)node
->value
);
81 createenv(struct rule
*rule
)
86 env
= malloc(sizeof(*env
));
92 if (rule
->options
& KEEPENV
) {
93 extern const char **environ
;
95 for (i
= 0; environ
[i
] != NULL
; i
++) {
103 /* ignore invalid or overlong names */
104 if ((eq
= strchr(e
, '=')) == NULL
|| eq
== e
)
107 if (len
> sizeof(name
) - 1)
109 memcpy(name
, e
, len
);
112 node
= createnode(name
, eq
+ 1);
113 if (RB_INSERT(envtree
, &env
->root
, node
)) {
114 /* ignore any later duplicates */
126 flattenenv(struct env
*env
)
129 struct envnode
*node
;
132 envp
= reallocarray(NULL
, env
->count
+ 1, sizeof(char *));
136 RB_FOREACH(node
, envtree
, &env
->root
) {
137 if (asprintf(&envp
[i
], "%s=%s", node
->key
, node
->value
) == -1)
146 fillenv(struct env
*env
, const char **envlist
)
148 struct envnode
*node
, key
;
155 for (i
= 0; envlist
[i
]; i
++) {
158 /* parse out env name */
159 if ((eq
= strchr(e
, '=')) == NULL
)
163 if (len
> sizeof(name
) - 1)
165 memcpy(name
, e
, len
);
168 /* delete previous copies */
172 if ((node
= RB_FIND(envtree
, &env
->root
, &key
))) {
173 RB_REMOVE(envtree
, &env
->root
, node
);
180 /* assign value or inherit from environ */
184 val
= getenv(val
+ 1);
188 /* at last, we have something to insert */
190 node
= createnode(name
, val
);
191 RB_INSERT(envtree
, &env
->root
, node
);
198 prepenv(struct rule
*rule
)
200 static const char *safeset
[] = {
201 "DISPLAY", "HOME", "LOGNAME", "MAIL",
202 "PATH", "TERM", "USER", "USERNAME",
207 env
= createenv(rule
);
209 /* if we started with blank, fill some defaults then apply rules */
210 if (!(rule
->options
& KEEPENV
))
211 fillenv(env
, safeset
);
213 fillenv(env
, rule
->envlist
);
215 return flattenenv(env
);