OpenVPN
env_set.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2024 OpenVPN Technologies, Inc. <sales@openvpn.net>
9 * Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com>
10 * Copyright (C) 2016-2024 David Sommerseth <davids@openvpn.net>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2
14 * as published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING included with this
23 * distribution); if not, write to the Free Software Foundation, Inc.,
24 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include "syshead.h"
32
33#include "env_set.h"
34
35#include "run_command.h"
36
37/*
38 * Set environmental variable (int or string).
39 *
40 * On Posix, we use putenv for portability,
41 * and put up with its painful semantics
42 * that require all the support code below.
43 */
44
45/* General-purpose environmental variable set functions */
46
47static char *
48construct_name_value(const char *name, const char *value, struct gc_arena *gc)
49{
50 struct buffer out;
51
52 ASSERT(name);
53 if (!value)
54 {
55 value = "";
56 }
57 out = alloc_buf_gc(strlen(name) + strlen(value) + 2, gc);
58 buf_printf(&out, "%s=%s", name, value);
59 return BSTR(&out);
60}
61
62static bool
63env_string_equal(const char *s1, const char *s2)
64{
65 int c1, c2;
66 ASSERT(s1);
67 ASSERT(s2);
68
69 while (true)
70 {
71 c1 = *s1++;
72 c2 = *s2++;
73 if (c1 == '=')
74 {
75 c1 = 0;
76 }
77 if (c2 == '=')
78 {
79 c2 = 0;
80 }
81 if (!c1 && !c2)
82 {
83 return true;
84 }
85 if (c1 != c2)
86 {
87 break;
88 }
89 }
90 return false;
91}
92
93static bool
94remove_env_item(const char *str, const bool do_free, struct env_item **list)
95{
96 struct env_item *current, *prev;
97
98 ASSERT(str);
99 ASSERT(list);
100
101 for (current = *list, prev = NULL; current != NULL; current = current->next)
102 {
103 if (env_string_equal(current->string, str))
104 {
105 if (prev)
106 {
107 prev->next = current->next;
108 }
109 else
110 {
111 *list = current->next;
112 }
113 if (do_free)
114 {
115 secure_memzero(current->string, strlen(current->string));
116 free(current->string);
117 free(current);
118 }
119 return true;
120 }
121 prev = current;
122 }
123 return false;
124}
125
126static void
127add_env_item(char *str, const bool do_alloc, struct env_item **list, struct gc_arena *gc)
128{
129 struct env_item *item;
130
131 ASSERT(str);
132 ASSERT(list);
133
134 ALLOC_OBJ_GC(item, struct env_item, gc);
135 item->string = do_alloc ? string_alloc(str, gc) : str;
136 item->next = *list;
137 *list = item;
138}
139
140/* struct env_set functions */
141
142static bool
143env_set_del_nolock(struct env_set *es, const char *str)
144{
145 return remove_env_item(str, es->gc == NULL, &es->list);
146}
147
148static void
149env_set_add_nolock(struct env_set *es, const char *str)
150{
151 remove_env_item(str, es->gc == NULL, &es->list);
152 add_env_item((char *)str, true, &es->list, es->gc);
153}
154
155struct env_set *
157{
158 struct env_set *es;
160 es->list = NULL;
161 es->gc = gc;
162 return es;
163}
164
165void
167{
168 if (es && es->gc == NULL)
169 {
170 struct env_item *e = es->list;
171 while (e)
172 {
173 struct env_item *next = e->next;
174 free(e->string);
175 free(e);
176 e = next;
177 }
178 free(es);
179 }
180}
181
182bool
183env_set_del(struct env_set *es, const char *str)
184{
185 bool ret;
186 ASSERT(es);
187 ASSERT(str);
188 ret = env_set_del_nolock(es, str);
189 return ret;
190}
191
192void
193env_set_add(struct env_set *es, const char *str)
194{
195 ASSERT(es);
196 ASSERT(str);
198}
199
200const char *
201env_set_get(const struct env_set *es, const char *name)
202{
203 const struct env_item *item = es->list;
204 while (item && !env_string_equal(item->string, name))
205 {
206 item = item->next;
207 }
208 return item ? item->string : NULL;
209}
210
211void
212env_set_print(int msglevel, const struct env_set *es)
213{
214 if (check_debug_level(msglevel))
215 {
216 const struct env_item *e;
217 int i;
218
219 if (es)
220 {
221 e = es->list;
222 i = 0;
223
224 while (e)
225 {
227 {
228 msg(msglevel, "ENV [%d] '%s'", i, e->string);
229 }
230 ++i;
231 e = e->next;
232 }
233 }
234 }
235}
236
237void
238env_set_inherit(struct env_set *es, const struct env_set *src)
239{
240 const struct env_item *e;
241
242 ASSERT(es);
243
244 if (src)
245 {
246 e = src->list;
247 while (e)
248 {
250 e = e->next;
251 }
252 }
253}
254
255
256/* add/modify/delete environmental strings */
257
258void
259setenv_counter(struct env_set *es, const char *name, counter_type value)
260{
261 char buf[64];
262 snprintf(buf, sizeof(buf), counter_format, value);
263 setenv_str(es, name, buf);
264}
265
266void
267setenv_int(struct env_set *es, const char *name, int value)
268{
269 char buf[64];
270 snprintf(buf, sizeof(buf), "%d", value);
271 setenv_str(es, name, buf);
272}
273
274void
275setenv_long_long(struct env_set *es, const char *name, long long value)
276{
277 char buf[64];
278 snprintf(buf, sizeof(buf), "%" PRIi64, (int64_t)value);
279 setenv_str(es, name, buf);
280}
281
282void
283setenv_str(struct env_set *es, const char *name, const char *value)
284{
285 setenv_str_ex(es, name, value, CC_NAME, 0, 0, CC_PRINT, 0, 0);
286}
287
288void
289setenv_str_safe(struct env_set *es, const char *name, const char *value)
290{
291 uint8_t b[64];
292 struct buffer buf;
293 buf_set_write(&buf, b, sizeof(b));
294 if (buf_printf(&buf, "OPENVPN_%s", name))
295 {
296 setenv_str(es, BSTR(&buf), value);
297 }
298 else
299 {
300 msg(M_WARN, "setenv_str_safe: name overflow");
301 }
302}
303
304void
305setenv_str_incr(struct env_set *es, const char *name, const char *value)
306{
307 unsigned int counter = 1;
308 const size_t tmpname_len = strlen(name) + 5; /* 3 digits counter max */
309 char *tmpname = gc_malloc(tmpname_len, true, NULL);
310 strcpy(tmpname, name);
311 while (NULL != env_set_get(es, tmpname) && counter < 1000)
312 {
313 ASSERT(snprintf(tmpname, tmpname_len, "%s_%u", name, counter));
314 counter++;
315 }
316 if (counter < 1000)
317 {
318 setenv_str(es, tmpname, value);
319 }
320 else
321 {
322 msg(D_TLS_DEBUG_MED, "Too many same-name env variables, ignoring: %s", name);
323 }
324 free(tmpname);
325}
326
327void
328setenv_del(struct env_set *es, const char *name)
329{
330 ASSERT(name);
331 setenv_str(es, name, NULL);
332}
333
334void
336 const char *name,
337 const char *value,
338 const unsigned int name_include,
339 const unsigned int name_exclude,
340 const char name_replace,
341 const unsigned int value_include,
342 const unsigned int value_exclude,
343 const char value_replace)
344{
345 struct gc_arena gc = gc_new();
346 const char *name_tmp;
347 const char *val_tmp = NULL;
348
349 ASSERT(name && strlen(name) > 1);
350
351 name_tmp = string_mod_const(name, name_include, name_exclude, name_replace, &gc);
352
353 if (value)
354 {
355 val_tmp = string_mod_const(value, value_include, value_exclude, value_replace, &gc);
356 }
357
358 ASSERT(es);
359
360 if (val_tmp)
361 {
362 const char *str = construct_name_value(name_tmp, val_tmp, &gc);
363 env_set_add(es, str);
364#if DEBUG_VERBOSE_SETENV
365 msg(M_INFO, "SETENV_ES '%s'", str);
366#endif
367 }
368 else
369 {
370 env_set_del(es, name_tmp);
371 }
372
373 gc_free(&gc);
374}
375
376/*
377 * Setenv functions that append an integer index to the name
378 */
379static const char *
380setenv_format_indexed_name(const char *name, const int i, struct gc_arena *gc)
381{
382 struct buffer out = alloc_buf_gc(strlen(name) + 16, gc);
383 if (i >= 0)
384 {
385 buf_printf(&out, "%s_%d", name, i);
386 }
387 else
388 {
389 buf_printf(&out, "%s", name);
390 }
391 return BSTR(&out);
392}
393
394void
395setenv_int_i(struct env_set *es, const char *name, const int value, const int i)
396{
397 struct gc_arena gc = gc_new();
398 const char *name_str = setenv_format_indexed_name(name, i, &gc);
399 setenv_int(es, name_str, value);
400 gc_free(&gc);
401}
402
403void
404setenv_str_i(struct env_set *es, const char *name, const char *value, const int i)
405{
406 struct gc_arena gc = gc_new();
407 const char *name_str = setenv_format_indexed_name(name, i, &gc);
408 setenv_str(es, name_str, value);
409 gc_free(&gc);
410}
411
412bool
413env_allowed(const char *str)
414{
415 return (script_security() >= SSEC_PW_ENV || !is_password_env_var(str));
416}
417
418/* Make arrays of strings */
419
420const char **
422 const bool check_allowed,
423 struct gc_arena *gc)
424{
425 char **ret = NULL;
426 struct env_item *e = NULL;
427 int i = 0, n = 0;
428
429 /* figure length of es */
430 if (es)
431 {
432 for (e = es->list; e != NULL; e = e->next)
433 {
434 ++n;
435 }
436 }
437
438 /* alloc return array */
439 ALLOC_ARRAY_CLEAR_GC(ret, char *, n+1, gc);
440
441 /* fill return array */
442 if (es)
443 {
444 i = 0;
445 for (e = es->list; e != NULL; e = e->next)
446 {
447 if (!check_allowed || env_allowed(e->string))
448 {
449 ASSERT(i < n);
450 ret[i++] = e->string;
451 }
452 }
453 }
454
455 ret[i] = NULL;
456 return (const char **)ret;
457}
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:240
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition buffer.c:336
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
const char * string_mod_const(const char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace, struct gc_arena *gc)
Returns a copy of a string with certain classes of characters of it replaced with a specified charact...
Definition buffer.c:1090
char * string_alloc(const char *str, struct gc_arena *gc)
Definition buffer.c:649
#define BSTR(buf)
Definition buffer.h:129
#define ALLOC_ARRAY_CLEAR_GC(dptr, type, n, gc)
Definition buffer.h:1082
static void buf_set_write(struct buffer *buf, uint8_t *data, int size)
Definition buffer.h:331
static void secure_memzero(void *data, size_t len)
Securely zeroise memory.
Definition buffer.h:414
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Definition buffer.h:1097
#define ALLOC_OBJ_GC(dptr, type, gc)
Definition buffer.h:1092
#define CC_NAME
alphanumeric plus underscore
Definition buffer.h:919
static void gc_free(struct gc_arena *a)
Definition buffer.h:1033
#define CC_PRINT
printable (>= 32, != 127)
Definition buffer.h:891
static struct gc_arena gc_new(void)
Definition buffer.h:1025
uint64_t counter_type
Definition common.h:30
#define counter_format
Definition common.h:31
void setenv_counter(struct env_set *es, const char *name, counter_type value)
Definition env_set.c:259
void env_set_print(int msglevel, const struct env_set *es)
Definition env_set.c:212
static bool env_set_del_nolock(struct env_set *es, const char *str)
Definition env_set.c:143
void env_set_destroy(struct env_set *es)
Definition env_set.c:166
void setenv_int(struct env_set *es, const char *name, int value)
Definition env_set.c:267
void setenv_int_i(struct env_set *es, const char *name, const int value, const int i)
Definition env_set.c:395
static const char * setenv_format_indexed_name(const char *name, const int i, struct gc_arena *gc)
Definition env_set.c:380
void setenv_str_i(struct env_set *es, const char *name, const char *value, const int i)
Definition env_set.c:404
static void env_set_add_nolock(struct env_set *es, const char *str)
Definition env_set.c:149
static char * construct_name_value(const char *name, const char *value, struct gc_arena *gc)
Definition env_set.c:48
void setenv_str(struct env_set *es, const char *name, const char *value)
Definition env_set.c:283
const char ** make_env_array(const struct env_set *es, const bool check_allowed, struct gc_arena *gc)
Definition env_set.c:421
void env_set_add(struct env_set *es, const char *str)
Definition env_set.c:193
static bool env_string_equal(const char *s1, const char *s2)
Definition env_set.c:63
static void add_env_item(char *str, const bool do_alloc, struct env_item **list, struct gc_arena *gc)
Definition env_set.c:127
void setenv_str_ex(struct env_set *es, const char *name, const char *value, const unsigned int name_include, const unsigned int name_exclude, const char name_replace, const unsigned int value_include, const unsigned int value_exclude, const char value_replace)
Definition env_set.c:335
const char * env_set_get(const struct env_set *es, const char *name)
Definition env_set.c:201
void env_set_inherit(struct env_set *es, const struct env_set *src)
Definition env_set.c:238
void setenv_str_incr(struct env_set *es, const char *name, const char *value)
Store the supplied name value pair in the env_set.
Definition env_set.c:305
void setenv_str_safe(struct env_set *es, const char *name, const char *value)
Definition env_set.c:289
struct env_set * env_set_create(struct gc_arena *gc)
Definition env_set.c:156
bool env_allowed(const char *str)
Definition env_set.c:413
bool env_set_del(struct env_set *es, const char *str)
Definition env_set.c:183
void setenv_long_long(struct env_set *es, const char *name, long long value)
Definition env_set.c:275
static bool remove_env_item(const char *str, const bool do_free, struct env_item **list)
Definition env_set.c:94
void setenv_del(struct env_set *es, const char *name)
Definition env_set.c:328
static bool is_password_env_var(const char *str)
Definition env_set.h:98
static bool env_safe_to_print(const char *str)
Definition env_set.h:105
#define D_TLS_DEBUG_MED
Definition errlevel.h:157
#define M_INFO
Definition errlevel.h:55
static bool check_debug_level(unsigned int level)
Definition error.h:220
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
#define M_WARN
Definition error.h:91
int script_security(void)
Definition run_command.c:43
#define SSEC_PW_ENV
Definition run_command.h:34
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
char * string
Definition env_set.h:38
struct env_item * next
Definition env_set.h:39
struct env_item * list
Definition env_set.h:44
struct gc_arena * gc
Definition env_set.h:43
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
struct env_set * es
struct gc_arena gc
Definition test_ssl.c:155