Bug Summary

File:src/usr.bin/doas/env.c
Warning:line 83, column 2
Potential leak of memory pointed to by 'node'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name env.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/doas/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/doas -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/doas/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/doas/env.c
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(*__errno()).h>
27#include <pwd.h>
28
29#include "doas.h"
30
31const char *formerpath;
32
33struct envnode {
34 RB_ENTRY(envnode)struct { struct envnode *rbe_left; struct envnode *rbe_right;
struct envnode *rbe_parent; int rbe_color; }
node;
35 const char *key;
36 const char *value;
37};
38
39struct env {
40 RB_HEAD(envtree, envnode)struct envtree { struct envnode *rbh_root; } root;
41 u_int count;
42};
43
44static void fillenv(struct env *env, const char **envlist);
45
46static int
47envcmp(struct envnode *a, struct envnode *b)
48{
49 return strcmp(a->key, b->key);
50}
51RB_GENERATE_STATIC(envtree, envnode, node, envcmp)__attribute__((__unused__)) static void envtree_RB_INSERT_COLOR
(struct envtree *head, struct envnode *elm) { struct envnode *
parent, *gparent, *tmp; while ((parent = (elm)->node.rbe_parent
) && (parent)->node.rbe_color == 1) { gparent = (parent
)->node.rbe_parent; if (parent == (gparent)->node.rbe_left
) { tmp = (gparent)->node.rbe_right; if (tmp && (tmp
)->node.rbe_color == 1) { (tmp)->node.rbe_color = 0; do
{ (parent)->node.rbe_color = 0; (gparent)->node.rbe_color
= 1; } while (0); elm = gparent; continue; } if ((parent)->
node.rbe_right == elm) { do { (tmp) = (parent)->node.rbe_right
; if (((parent)->node.rbe_right = (tmp)->node.rbe_left)
) { ((tmp)->node.rbe_left)->node.rbe_parent = (parent);
} do {} while (0); if (((tmp)->node.rbe_parent = (parent)
->node.rbe_parent)) { if ((parent) == ((parent)->node.rbe_parent
)->node.rbe_left) ((parent)->node.rbe_parent)->node.
rbe_left = (tmp); else ((parent)->node.rbe_parent)->node
.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)
->node.rbe_left = (parent); (parent)->node.rbe_parent =
(tmp); do {} while (0); if (((tmp)->node.rbe_parent)) do {
} while (0); } while (0); tmp = parent; parent = elm; elm = tmp
; } do { (parent)->node.rbe_color = 0; (gparent)->node.
rbe_color = 1; } while (0); do { (tmp) = (gparent)->node.rbe_left
; if (((gparent)->node.rbe_left = (tmp)->node.rbe_right
)) { ((tmp)->node.rbe_right)->node.rbe_parent = (gparent
); } do {} while (0); if (((tmp)->node.rbe_parent = (gparent
)->node.rbe_parent)) { if ((gparent) == ((gparent)->node
.rbe_parent)->node.rbe_left) ((gparent)->node.rbe_parent
)->node.rbe_left = (tmp); else ((gparent)->node.rbe_parent
)->node.rbe_right = (tmp); } else (head)->rbh_root = (tmp
); (tmp)->node.rbe_right = (gparent); (gparent)->node.rbe_parent
= (tmp); do {} while (0); if (((tmp)->node.rbe_parent)) do
{} while (0); } while (0); } else { tmp = (gparent)->node
.rbe_left; if (tmp && (tmp)->node.rbe_color == 1) {
(tmp)->node.rbe_color = 0; do { (parent)->node.rbe_color
= 0; (gparent)->node.rbe_color = 1; } while (0); elm = gparent
; continue; } if ((parent)->node.rbe_left == elm) { do { (
tmp) = (parent)->node.rbe_left; if (((parent)->node.rbe_left
= (tmp)->node.rbe_right)) { ((tmp)->node.rbe_right)->
node.rbe_parent = (parent); } do {} while (0); if (((tmp)->
node.rbe_parent = (parent)->node.rbe_parent)) { if ((parent
) == ((parent)->node.rbe_parent)->node.rbe_left) ((parent
)->node.rbe_parent)->node.rbe_left = (tmp); else ((parent
)->node.rbe_parent)->node.rbe_right = (tmp); } else (head
)->rbh_root = (tmp); (tmp)->node.rbe_right = (parent); (
parent)->node.rbe_parent = (tmp); do {} while (0); if (((tmp
)->node.rbe_parent)) do {} while (0); } while (0); tmp = parent
; parent = elm; elm = tmp; } do { (parent)->node.rbe_color
= 0; (gparent)->node.rbe_color = 1; } while (0); do { (tmp
) = (gparent)->node.rbe_right; if (((gparent)->node.rbe_right
= (tmp)->node.rbe_left)) { ((tmp)->node.rbe_left)->
node.rbe_parent = (gparent); } do {} while (0); if (((tmp)->
node.rbe_parent = (gparent)->node.rbe_parent)) { if ((gparent
) == ((gparent)->node.rbe_parent)->node.rbe_left) ((gparent
)->node.rbe_parent)->node.rbe_left = (tmp); else ((gparent
)->node.rbe_parent)->node.rbe_right = (tmp); } else (head
)->rbh_root = (tmp); (tmp)->node.rbe_left = (gparent); (
gparent)->node.rbe_parent = (tmp); do {} while (0); if (((
tmp)->node.rbe_parent)) do {} while (0); } while (0); } } (
head->rbh_root)->node.rbe_color = 0; } __attribute__((__unused__
)) static void envtree_RB_REMOVE_COLOR(struct envtree *head, struct
envnode *parent, struct envnode *elm) { struct envnode *tmp;
while ((elm == ((void *)0) || (elm)->node.rbe_color == 0)
&& elm != (head)->rbh_root) { if ((parent)->node
.rbe_left == elm) { tmp = (parent)->node.rbe_right; if ((tmp
)->node.rbe_color == 1) { do { (tmp)->node.rbe_color = 0
; (parent)->node.rbe_color = 1; } while (0); do { (tmp) = (
parent)->node.rbe_right; if (((parent)->node.rbe_right =
(tmp)->node.rbe_left)) { ((tmp)->node.rbe_left)->node
.rbe_parent = (parent); } do {} while (0); if (((tmp)->node
.rbe_parent = (parent)->node.rbe_parent)) { if ((parent) ==
((parent)->node.rbe_parent)->node.rbe_left) ((parent)->
node.rbe_parent)->node.rbe_left = (tmp); else ((parent)->
node.rbe_parent)->node.rbe_right = (tmp); } else (head)->
rbh_root = (tmp); (tmp)->node.rbe_left = (parent); (parent
)->node.rbe_parent = (tmp); do {} while (0); if (((tmp)->
node.rbe_parent)) do {} while (0); } while (0); tmp = (parent
)->node.rbe_right; } if (((tmp)->node.rbe_left == ((void
*)0) || ((tmp)->node.rbe_left)->node.rbe_color == 0) &&
((tmp)->node.rbe_right == ((void *)0) || ((tmp)->node.
rbe_right)->node.rbe_color == 0)) { (tmp)->node.rbe_color
= 1; elm = parent; parent = (elm)->node.rbe_parent; } else
{ if ((tmp)->node.rbe_right == ((void *)0) || ((tmp)->
node.rbe_right)->node.rbe_color == 0) { struct envnode *oleft
; if ((oleft = (tmp)->node.rbe_left)) (oleft)->node.rbe_color
= 0; (tmp)->node.rbe_color = 1; do { (oleft) = (tmp)->
node.rbe_left; if (((tmp)->node.rbe_left = (oleft)->node
.rbe_right)) { ((oleft)->node.rbe_right)->node.rbe_parent
= (tmp); } do {} while (0); if (((oleft)->node.rbe_parent
= (tmp)->node.rbe_parent)) { if ((tmp) == ((tmp)->node
.rbe_parent)->node.rbe_left) ((tmp)->node.rbe_parent)->
node.rbe_left = (oleft); else ((tmp)->node.rbe_parent)->
node.rbe_right = (oleft); } else (head)->rbh_root = (oleft
); (oleft)->node.rbe_right = (tmp); (tmp)->node.rbe_parent
= (oleft); do {} while (0); if (((oleft)->node.rbe_parent
)) do {} while (0); } while (0); tmp = (parent)->node.rbe_right
; } (tmp)->node.rbe_color = (parent)->node.rbe_color; (
parent)->node.rbe_color = 0; if ((tmp)->node.rbe_right)
((tmp)->node.rbe_right)->node.rbe_color = 0; do { (tmp
) = (parent)->node.rbe_right; if (((parent)->node.rbe_right
= (tmp)->node.rbe_left)) { ((tmp)->node.rbe_left)->
node.rbe_parent = (parent); } do {} while (0); if (((tmp)->
node.rbe_parent = (parent)->node.rbe_parent)) { if ((parent
) == ((parent)->node.rbe_parent)->node.rbe_left) ((parent
)->node.rbe_parent)->node.rbe_left = (tmp); else ((parent
)->node.rbe_parent)->node.rbe_right = (tmp); } else (head
)->rbh_root = (tmp); (tmp)->node.rbe_left = (parent); (
parent)->node.rbe_parent = (tmp); do {} while (0); if (((tmp
)->node.rbe_parent)) do {} while (0); } while (0); elm = (
head)->rbh_root; break; } } else { tmp = (parent)->node
.rbe_left; if ((tmp)->node.rbe_color == 1) { do { (tmp)->
node.rbe_color = 0; (parent)->node.rbe_color = 1; } while (
0); do { (tmp) = (parent)->node.rbe_left; if (((parent)->
node.rbe_left = (tmp)->node.rbe_right)) { ((tmp)->node.
rbe_right)->node.rbe_parent = (parent); } do {} while (0);
if (((tmp)->node.rbe_parent = (parent)->node.rbe_parent
)) { if ((parent) == ((parent)->node.rbe_parent)->node.
rbe_left) ((parent)->node.rbe_parent)->node.rbe_left = (
tmp); else ((parent)->node.rbe_parent)->node.rbe_right =
(tmp); } else (head)->rbh_root = (tmp); (tmp)->node.rbe_right
= (parent); (parent)->node.rbe_parent = (tmp); do {} while
(0); if (((tmp)->node.rbe_parent)) do {} while (0); } while
(0); tmp = (parent)->node.rbe_left; } if (((tmp)->node
.rbe_left == ((void *)0) || ((tmp)->node.rbe_left)->node
.rbe_color == 0) && ((tmp)->node.rbe_right == ((void
*)0) || ((tmp)->node.rbe_right)->node.rbe_color == 0))
{ (tmp)->node.rbe_color = 1; elm = parent; parent = (elm)
->node.rbe_parent; } else { if ((tmp)->node.rbe_left ==
((void *)0) || ((tmp)->node.rbe_left)->node.rbe_color ==
0) { struct envnode *oright; if ((oright = (tmp)->node.rbe_right
)) (oright)->node.rbe_color = 0; (tmp)->node.rbe_color =
1; do { (oright) = (tmp)->node.rbe_right; if (((tmp)->
node.rbe_right = (oright)->node.rbe_left)) { ((oright)->
node.rbe_left)->node.rbe_parent = (tmp); } do {} while (0)
; if (((oright)->node.rbe_parent = (tmp)->node.rbe_parent
)) { if ((tmp) == ((tmp)->node.rbe_parent)->node.rbe_left
) ((tmp)->node.rbe_parent)->node.rbe_left = (oright); else
((tmp)->node.rbe_parent)->node.rbe_right = (oright); }
else (head)->rbh_root = (oright); (oright)->node.rbe_left
= (tmp); (tmp)->node.rbe_parent = (oright); do {} while (
0); if (((oright)->node.rbe_parent)) do {} while (0); } while
(0); tmp = (parent)->node.rbe_left; } (tmp)->node.rbe_color
= (parent)->node.rbe_color; (parent)->node.rbe_color =
0; if ((tmp)->node.rbe_left) ((tmp)->node.rbe_left)->
node.rbe_color = 0; do { (tmp) = (parent)->node.rbe_left; if
(((parent)->node.rbe_left = (tmp)->node.rbe_right)) { (
(tmp)->node.rbe_right)->node.rbe_parent = (parent); } do
{} while (0); if (((tmp)->node.rbe_parent = (parent)->
node.rbe_parent)) { if ((parent) == ((parent)->node.rbe_parent
)->node.rbe_left) ((parent)->node.rbe_parent)->node.
rbe_left = (tmp); else ((parent)->node.rbe_parent)->node
.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)
->node.rbe_right = (parent); (parent)->node.rbe_parent =
(tmp); do {} while (0); if (((tmp)->node.rbe_parent)) do {
} while (0); } while (0); elm = (head)->rbh_root; break; }
} } if (elm) (elm)->node.rbe_color = 0; } __attribute__((
__unused__)) static struct envnode * envtree_RB_REMOVE(struct
envtree *head, struct envnode *elm) { struct envnode *child,
*parent, *old = elm; int color; if ((elm)->node.rbe_left ==
((void *)0)) child = (elm)->node.rbe_right; else if ((elm
)->node.rbe_right == ((void *)0)) child = (elm)->node.rbe_left
; else { struct envnode *left; elm = (elm)->node.rbe_right
; while ((left = (elm)->node.rbe_left)) elm = left; child =
(elm)->node.rbe_right; parent = (elm)->node.rbe_parent
; color = (elm)->node.rbe_color; if (child) (child)->node
.rbe_parent = parent; if (parent) { if ((parent)->node.rbe_left
== elm) (parent)->node.rbe_left = child; else (parent)->
node.rbe_right = child; do {} while (0); } else (head)->rbh_root
= child; if ((elm)->node.rbe_parent == old) parent = elm;
(elm)->node = (old)->node; if ((old)->node.rbe_parent
) { if (((old)->node.rbe_parent)->node.rbe_left == old)
((old)->node.rbe_parent)->node.rbe_left = elm; else ((
old)->node.rbe_parent)->node.rbe_right = elm; do {} while
(0); } else (head)->rbh_root = elm; ((old)->node.rbe_left
)->node.rbe_parent = elm; if ((old)->node.rbe_right) ((
old)->node.rbe_right)->node.rbe_parent = elm; if (parent
) { left = parent; do { do {} while (0); } while ((left = (left
)->node.rbe_parent)); } goto color; } parent = (elm)->node
.rbe_parent; color = (elm)->node.rbe_color; if (child) (child
)->node.rbe_parent = parent; if (parent) { if ((parent)->
node.rbe_left == elm) (parent)->node.rbe_left = child; else
(parent)->node.rbe_right = child; do {} while (0); } else
(head)->rbh_root = child; color: if (color == 0) envtree_RB_REMOVE_COLOR
(head, parent, child); return (old); } __attribute__((__unused__
)) static struct envnode * envtree_RB_INSERT(struct envtree *
head, struct envnode *elm) { struct envnode *tmp; struct envnode
*parent = ((void *)0); int comp = 0; tmp = (head)->rbh_root
; while (tmp) { parent = tmp; comp = (envcmp)(elm, parent); if
(comp < 0) tmp = (tmp)->node.rbe_left; else if (comp >
0) tmp = (tmp)->node.rbe_right; else return (tmp); } do {
(elm)->node.rbe_parent = parent; (elm)->node.rbe_left =
(elm)->node.rbe_right = ((void *)0); (elm)->node.rbe_color
= 1; } while (0); if (parent != ((void *)0)) { if (comp <
0) (parent)->node.rbe_left = elm; else (parent)->node.
rbe_right = elm; do {} while (0); } else (head)->rbh_root =
elm; envtree_RB_INSERT_COLOR(head, elm); return (((void *)0)
); } __attribute__((__unused__)) static struct envnode * envtree_RB_FIND
(struct envtree *head, struct envnode *elm) { struct envnode *
tmp = (head)->rbh_root; int comp; while (tmp) { comp = envcmp
(elm, tmp); if (comp < 0) tmp = (tmp)->node.rbe_left; else
if (comp > 0) tmp = (tmp)->node.rbe_right; else return
(tmp); } return (((void *)0)); } __attribute__((__unused__))
static struct envnode * envtree_RB_NFIND(struct envtree *head
, struct envnode *elm) { struct envnode *tmp = (head)->rbh_root
; struct envnode *res = ((void *)0); int comp; while (tmp) { comp
= envcmp(elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp
)->node.rbe_left; } else if (comp > 0) tmp = (tmp)->
node.rbe_right; else return (tmp); } return (res); } __attribute__
((__unused__)) static struct envnode * envtree_RB_NEXT(struct
envnode *elm) { if ((elm)->node.rbe_right) { elm = (elm)->
node.rbe_right; while ((elm)->node.rbe_left) elm = (elm)->
node.rbe_left; } else { if ((elm)->node.rbe_parent &&
(elm == ((elm)->node.rbe_parent)->node.rbe_left)) elm =
(elm)->node.rbe_parent; else { while ((elm)->node.rbe_parent
&& (elm == ((elm)->node.rbe_parent)->node.rbe_right
)) elm = (elm)->node.rbe_parent; elm = (elm)->node.rbe_parent
; } } return (elm); } __attribute__((__unused__)) static struct
envnode * envtree_RB_PREV(struct envnode *elm) { if ((elm)->
node.rbe_left) { elm = (elm)->node.rbe_left; while ((elm)->
node.rbe_right) elm = (elm)->node.rbe_right; } else { if (
(elm)->node.rbe_parent && (elm == ((elm)->node.
rbe_parent)->node.rbe_right)) elm = (elm)->node.rbe_parent
; else { while ((elm)->node.rbe_parent && (elm == (
(elm)->node.rbe_parent)->node.rbe_left)) elm = (elm)->
node.rbe_parent; elm = (elm)->node.rbe_parent; } } return (
elm); } __attribute__((__unused__)) static struct envnode * envtree_RB_MINMAX
(struct envtree *head, int val) { struct envnode *tmp = (head
)->rbh_root; struct envnode *parent = ((void *)0); while (
tmp) { parent = tmp; if (val < 0) tmp = (tmp)->node.rbe_left
; else tmp = (tmp)->node.rbe_right; } return (parent); }
52
53static struct envnode *
54createnode(const char *key, const char *value)
55{
56 struct envnode *node;
57
58 node = malloc(sizeof(*node));
7
Memory is allocated
59 if (!node)
8
Assuming 'node' is non-null
9
Taking false branch
60 err(1, NULL((void *)0));
61 node->key = strdup(key);
62 node->value = strdup(value);
63 if (!node->key || !node->value)
10
Assuming field 'key' is non-null
11
Assuming field 'value' is non-null
12
Taking false branch
64 err(1, NULL((void *)0));
65 return node;
66}
67
68static void
69freenode(struct envnode *node)
70{
71 free((char *)node->key);
72 free((char *)node->value);
73 free(node);
74}
75
76static void
77addnode(struct env *env, const char *key, const char *value)
78{
79 struct envnode *node;
80
81 node = createnode(key, value);
6
Calling 'createnode'
13
Returned allocated memory
82 RB_INSERT(envtree, &env->root, node)envtree_RB_INSERT(&env->root, node);
83 env->count++;
14
Potential leak of memory pointed to by 'node'
84}
85
86static struct env *
87createenv(const struct rule *rule, const struct passwd *mypw,
88 const struct passwd *targpw)
89{
90 static const char *copyset[] = {
91 "DISPLAY", "TERM",
92 NULL((void *)0)
93 };
94 struct env *env;
95 u_int i;
96
97 env = malloc(sizeof(*env));
98 if (!env)
2
Assuming 'env' is non-null
3
Taking false branch
99 err(1, NULL((void *)0));
100 RB_INIT(&env->root)do { (&env->root)->rbh_root = ((void *)0); } while (
0)
;
4
Loop condition is false. Exiting loop
101 env->count = 0;
102
103 addnode(env, "DOAS_USER", mypw->pw_name);
104 addnode(env, "HOME", targpw->pw_dir);
5
Calling 'addnode'
105 addnode(env, "LOGNAME", targpw->pw_name);
106 addnode(env, "PATH", getenv("PATH"));
107 addnode(env, "SHELL", targpw->pw_shell);
108 addnode(env, "USER", targpw->pw_name);
109
110 fillenv(env, copyset);
111
112 if (rule->options & KEEPENV0x2) {
113 extern const char **environ;
114
115 for (i = 0; environ[i] != NULL((void *)0); 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((void *)0) || 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)envtree_RB_INSERT(&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
145static char **
146flattenenv(struct env *env)
147{
148 char **envp;
149 struct envnode *node;
150 u_int i;
151
152 envp = reallocarray(NULL((void *)0), env->count + 1, sizeof(char *));
153 if (!envp)
154 err(1, NULL((void *)0));
155 i = 0;
156 RB_FOREACH(node, envtree, &env->root)for ((node) = envtree_RB_MINMAX(&env->root, -1); (node
) != ((void *)0); (node) = envtree_RB_NEXT(node))
{
157 if (asprintf(&envp[i], "%s=%s", node->key, node->value) == -1)
158 err(1, NULL((void *)0));
159 i++;
160 }
161 envp[i] = NULL((void *)0);
162 return envp;
163}
164
165static void
166fillenv(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((void *)0))
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)envtree_RB_FIND(&env->root, &key))) {
193 RB_REMOVE(envtree, &env->root, node)envtree_RB_REMOVE(&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 if (strcmp(val + 1, "PATH") == 0)
205 val = formerpath;
206 else
207 val = getenv(val + 1);
208 }
209 } else {
210 if (strcmp(name, "PATH") == 0)
211 val = formerpath;
212 else
213 val = getenv(name);
214 }
215 /* at last, we have something to insert */
216 if (val) {
217 node = createnode(name, val);
218 RB_INSERT(envtree, &env->root, node)envtree_RB_INSERT(&env->root, node);
219 env->count++;
220 }
221 }
222}
223
224char **
225prepenv(const struct rule *rule, const struct passwd *mypw,
226 const struct passwd *targpw)
227{
228 struct env *env;
229
230 env = createenv(rule, mypw, targpw);
1
Calling 'createenv'
231 if (rule->envlist)
232 fillenv(env, rule->envlist);
233
234 return flattenenv(env);
235}