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