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-2023 OpenVPN Technologies, Inc. <sales@openvpn.net>
9  * Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com>
10  * Copyright (C) 2016-2023 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 
47 static char *
48 construct_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 
62 static bool
63 env_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 
93 static bool
94 remove_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 
126 static void
127 add_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 
142 static bool
143 env_set_del_nolock(struct env_set *es, const char *str)
144 {
145  return remove_env_item(str, es->gc == NULL, &es->list);
146 }
147 
148 static void
149 env_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 
155 struct env_set *
157 {
158  struct env_set *es;
159  ALLOC_OBJ_CLEAR_GC(es, struct env_set, gc);
160  es->list = NULL;
161  es->gc = gc;
162  return es;
163 }
164 
165 void
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 
182 bool
183 env_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 
192 void
193 env_set_add(struct env_set *es, const char *str)
194 {
195  ASSERT(es);
196  ASSERT(str);
197  env_set_add_nolock(es, str);
198 }
199 
200 const char *
201 env_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 
211 void
212 env_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  {
226  if (env_safe_to_print(e->string))
227  {
228  msg(msglevel, "ENV [%d] '%s'", i, e->string);
229  }
230  ++i;
231  e = e->next;
232  }
233  }
234  }
235 }
236 
237 void
238 env_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 
258 void
259 setenv_counter(struct env_set *es, const char *name, counter_type value)
260 {
261  char buf[64];
262  openvpn_snprintf(buf, sizeof(buf), counter_format, value);
263  setenv_str(es, name, buf);
264 }
265 
266 void
267 setenv_int(struct env_set *es, const char *name, int value)
268 {
269  char buf[64];
270  openvpn_snprintf(buf, sizeof(buf), "%d", value);
271  setenv_str(es, name, buf);
272 }
273 
274 void
275 setenv_long_long(struct env_set *es, const char *name, long long value)
276 {
277  char buf[64];
278  openvpn_snprintf(buf, sizeof(buf), "%" PRIi64, (int64_t)value);
279  setenv_str(es, name, buf);
280 }
281 
282 void
283 setenv_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 
288 void
289 setenv_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 
304 void
305 setenv_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(openvpn_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 
327 void
328 setenv_del(struct env_set *es, const char *name)
329 {
330  ASSERT(name);
331  setenv_str(es, name, NULL);
332 }
333 
334 void
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  */
379 static const char *
380 setenv_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 
394 void
395 setenv_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 
403 void
404 setenv_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 
412 bool
413 env_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 
420 const char **
421 make_env_array(const struct env_set *es,
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 }
setenv_format_indexed_name
static const char * setenv_format_indexed_name(const char *name, const int i, struct gc_arena *gc)
Definition: env_set.c:380
M_INFO
#define M_INFO
Definition: errlevel.h:55
env_item::next
struct env_item * next
Definition: env_set.h:39
env_string_equal
static bool env_string_equal(const char *s1, const char *s2)
Definition: env_set.c:63
env_set::gc
struct gc_arena * gc
Definition: env_set.h:43
gc_new
static struct gc_arena gc_new(void)
Definition: buffer.h:1031
run_command.h
env_item::string
char * string
Definition: env_set.h:38
env_set_destroy
void env_set_destroy(struct env_set *es)
Definition: env_set.c:166
setenv_str_i
void setenv_str_i(struct env_set *es, const char *name, const char *value, const int i)
Definition: env_set.c:404
es
struct env_set * es
Definition: test_pkcs11.c:133
BSTR
#define BSTR(buf)
Definition: buffer.h:129
alloc_buf_gc
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition: buffer.c:88
setenv_int_i
void setenv_int_i(struct env_set *es, const char *name, const int value, const int i)
Definition: env_set.c:395
SSEC_PW_ENV
#define SSEC_PW_ENV
Definition: run_command.h:34
env_set_inherit
void env_set_inherit(struct env_set *es, const struct env_set *src)
Definition: env_set.c:238
CC_NAME
#define CC_NAME
alphanumeric plus underscore
Definition: buffer.h:937
dns_options::gc
struct gc_arena gc
Definition: dns.h:74
setenv_int
void setenv_int(struct env_set *es, const char *name, int value)
Definition: env_set.c:267
setenv_counter
void setenv_counter(struct env_set *es, const char *name, counter_type value)
Definition: env_set.c:259
env_set_print
void env_set_print(int msglevel, const struct env_set *es)
Definition: env_set.c:212
env_set_add
void env_set_add(struct env_set *es, const char *str)
Definition: env_set.c:193
env_set::list
struct env_item * list
Definition: env_set.h:44
string_alloc
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:693
secure_memzero
static void secure_memzero(void *data, size_t len)
Securely zeroise memory.
Definition: buffer.h:414
ASSERT
#define ASSERT(x)
Definition: error.h:201
counter_type
uint64_t counter_type
Definition: common.h:30
remove_env_item
static bool remove_env_item(const char *str, const bool do_free, struct env_item **list)
Definition: env_set.c:94
env_set.h
CC_PRINT
#define CC_PRINT
printable (>= 32, != 127)
Definition: buffer.h:909
ALLOC_ARRAY_CLEAR_GC
#define ALLOC_ARRAY_CLEAR_GC(dptr, type, n, gc)
Definition: buffer.h:1088
M_WARN
#define M_WARN
Definition: error.h:97
ALLOC_OBJ_CLEAR_GC
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Definition: buffer.h:1103
construct_name_value
static char * construct_name_value(const char *name, const char *value, struct gc_arena *gc)
Definition: env_set.c:48
env_allowed
bool env_allowed(const char *str)
Definition: env_set.c:413
is_password_env_var
static bool is_password_env_var(const char *str)
Definition: env_set.h:98
buffer
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
setenv_str_incr
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
env_set_create
struct env_set * env_set_create(struct gc_arena *gc)
Definition: env_set.c:156
add_env_item
static void add_env_item(char *str, const bool do_alloc, struct env_item **list, struct gc_arena *gc)
Definition: env_set.c:127
syshead.h
gc_arena
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
setenv_str
void setenv_str(struct env_set *es, const char *name, const char *value)
Definition: env_set.c:283
buf_set_write
static void buf_set_write(struct buffer *buf, uint8_t *data, int size)
Definition: buffer.h:331
env_set
Definition: env_set.h:42
env_set_del
bool env_set_del(struct env_set *es, const char *str)
Definition: env_set.c:183
env_set_add_nolock
static void env_set_add_nolock(struct env_set *es, const char *str)
Definition: env_set.c:149
counter_format
#define counter_format
Definition: common.h:31
check_debug_level
static bool check_debug_level(unsigned int level)
Definition: error.h:226
gc_malloc
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition: buffer.c:380
D_TLS_DEBUG_MED
#define D_TLS_DEBUG_MED
Definition: errlevel.h:157
openvpn_snprintf
bool openvpn_snprintf(char *str, size_t size, const char *format,...)
Definition: buffer.c:294
gc_free
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1039
env_set_del_nolock
static bool env_set_del_nolock(struct env_set *es, const char *str)
Definition: env_set.c:143
env_item
Definition: env_set.h:37
config.h
setenv_str_ex
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
setenv_del
void setenv_del(struct env_set *es, const char *name)
Definition: env_set.c:328
string_mod_const
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:1117
setenv_str_safe
void setenv_str_safe(struct env_set *es, const char *name, const char *value)
Definition: env_set.c:289
msg
#define msg(flags,...)
Definition: error.h:150
env_set_get
const char * env_set_get(const struct env_set *es, const char *name)
Definition: env_set.c:201
setenv_long_long
void setenv_long_long(struct env_set *es, const char *name, long long value)
Definition: env_set.c:275
env_safe_to_print
static bool env_safe_to_print(const char *str)
Definition: env_set.h:105
make_env_array
const char ** make_env_array(const struct env_set *es, const bool check_allowed, struct gc_arena *gc)
Definition: env_set.c:421
buf_printf
bool buf_printf(struct buffer *buf, const char *format,...)
Definition: buffer.c:240
script_security
int script_security(void)
Definition: run_command.c:43
ALLOC_OBJ_GC
#define ALLOC_OBJ_GC(dptr, type, gc)
Definition: buffer.h:1098