OpenVPN
argv.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-2018 OpenVPN Inc <sales@openvpn.net>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2
12  * as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  *
24  * A printf-like function (that only recognizes a subset of standard printf
25  * format operators) that prints arguments to an argv list instead
26  * of a standard string. This is used to build up argv arrays for passing
27  * to execve.
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #elif defined(_MSC_VER)
33 #include "config-msvc.h"
34 #endif
35 
36 #include "syshead.h"
37 
38 #include "argv.h"
39 #include "integer.h"
40 #include "env_set.h"
41 #include "options.h"
42 
50 static void
51 argv_extend(struct argv *a, const size_t newcap)
52 {
53  if (newcap > a->capacity)
54  {
55  char **newargv;
56  size_t i;
57  ALLOC_ARRAY_CLEAR_GC(newargv, char *, newcap, &a->gc);
58  for (i = 0; i < a->argc; ++i)
59  {
60  newargv[i] = a->argv[i];
61  }
62  a->argv = newargv;
63  a->capacity = newcap;
64  }
65 }
66 
73 static void
74 argv_init(struct argv *a)
75 {
76  a->capacity = 0;
77  a->argc = 0;
78  a->argv = NULL;
79  a->gc = gc_new();
80  argv_extend(a, 8);
81 }
82 
89 struct argv
90 argv_new(void)
91 {
92  struct argv ret;
93  argv_init(&ret);
94  return ret;
95 }
96 
103 void
104 argv_free(struct argv *a)
105 {
106  gc_free(&a->gc);
107 }
108 
115 static void
116 argv_reset(struct argv *a)
117 {
118  if (a->argc)
119  {
120  size_t i;
121  for (i = 0; i < a->argc; ++i)
122  {
123  a->argv[i] = NULL;
124  }
125  a->argc = 0;
126  }
127 }
128 
142 static void
143 argv_grow(struct argv *a, const size_t add)
144 {
145  const size_t newargc = a->argc + add + 1;
146  ASSERT(newargc > a->argc);
147  argv_extend(a, adjust_power_of_2(newargc));
148 }
149 
159 static void
160 argv_append(struct argv *a, char *str)
161 {
162  argv_grow(a, 1);
163  a->argv[a->argc++] = str;
164 }
165 
181 static struct argv
182 argv_clone(const struct argv *source, const size_t headroom)
183 {
184  struct argv r;
185  argv_init(&r);
186 
187  for (size_t i = 0; i < headroom; ++i)
188  {
189  argv_append(&r, NULL);
190  }
191  if (source)
192  {
193  for (size_t i = 0; i < source->argc; ++i)
194  {
195  argv_append(&r, string_alloc(source->argv[i], &r.gc));
196  }
197  }
198  return r;
199 }
200 
209 struct argv
210 argv_insert_head(const struct argv *a, const char *head)
211 {
212  struct argv r;
213  r = argv_clone(a, 1);
214  r.argv[0] = string_alloc(head, &r.gc);
215  return r;
216 }
217 
232 const char *
233 argv_str(const struct argv *a, struct gc_arena *gc, const unsigned int flags)
234 {
235  return print_argv((const char **)a->argv, gc, flags);
236 }
237 
244 void
245 argv_msg(const int msglev, const struct argv *a)
246 {
247  struct gc_arena gc = gc_new();
248  msg(msglev, "%s", argv_str(a, &gc, 0));
249  gc_free(&gc);
250 }
251 
261 void
262 argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix)
263 {
264  struct gc_arena gc = gc_new();
265  msg(msglev, "%s: %s", prefix, argv_str(a, &gc, 0));
266  gc_free(&gc);
267 }
268 
289 static char *
290 argv_prep_format(const char *format, const char delim, size_t *count,
291  struct gc_arena *gc)
292 {
293  if (format == NULL)
294  {
295  return NULL;
296  }
297 
298  bool in_token = false;
299  char *f = gc_malloc(strlen(format) + 1, true, gc);
300  for (int i = 0, j = 0; i < strlen(format); i++)
301  {
302  if (format[i] == ' ')
303  {
304  in_token = false;
305  continue;
306  }
307 
308  if (!in_token)
309  {
310  (*count)++;
311 
312  /*
313  * We don't add any delimiter to the output string if
314  * the string is empty; the resulting format string
315  * will never start with a delimiter.
316  */
317  if (j > 0) /* Has anything been written to the output string? */
318  {
319  f[j++] = delim;
320  }
321  }
322 
323  f[j++] = format[i];
324  in_token = true;
325  }
326 
327  return f;
328 }
329 
350 static bool
351 argv_printf_arglist(struct argv *argres, const char *format, va_list arglist)
352 {
353  const char delim = 0x1D; /* ASCII Group Separator (GS) */
354  bool res = false;
355 
356  /*
357  * Prepare a format string which will be used by vsnprintf() later on.
358  *
359  * This means all space separators in the input format string will be
360  * replaced by the GS (0x1D), so we can split this up again after the
361  * the vsnprintf() call into individual arguments again which will be
362  * saved in the struct argv.
363  *
364  */
365  size_t argc = argres->argc;
366  char *f = argv_prep_format(format, delim, &argc, &argres->gc);
367  if (f == NULL)
368  {
369  goto out;
370  }
371 
372  /*
373  * Determine minimum buffer size.
374  *
375  * With C99, vsnprintf(NULL, 0, ...) will return the number of bytes
376  * it would have written, had the buffer been large enough.
377  */
378  va_list tmplist;
379  va_copy(tmplist, arglist);
380  int len = vsnprintf(NULL, 0, f, tmplist);
381  va_end(tmplist);
382  if (len < 0)
383  {
384  goto out;
385  }
386 
387  /*
388  * Do the actual vsnprintf() operation, which expands the format
389  * string with the provided arguments.
390  */
391  size_t size = len + 1;
392  char *buf = gc_malloc(size, false, &argres->gc);
393  len = vsnprintf(buf, size, f, arglist);
394  if (len < 0 || len >= size)
395  {
396  goto out;
397  }
398 
399  /*
400  * Split the string at the GS (0x1D) delimiters and put each elemen
401  * into the struct argv being returned to the caller.
402  */
403  char *end = strchr(buf, delim);
404  while (end)
405  {
406  *end = '\0';
407  argv_append(argres, buf);
408  buf = end + 1;
409  end = strchr(buf, delim);
410  }
411  argv_append(argres, buf);
412 
413  if (argres->argc != argc)
414  {
415  /* Someone snuck in a GS (0x1D), fail gracefully */
416  argv_reset(argres);
417  goto out;
418  }
419  res = true;
420 
421 out:
422  return res;
423 }
424 
441 bool
442 argv_printf(struct argv *argres, const char *format, ...)
443 {
444  va_list arglist;
445  va_start(arglist, format);
446 
447  argv_reset(argres);
448  bool res = argv_printf_arglist(argres, format, arglist);
449  va_end(arglist);
450  return res;
451 }
452 
465 bool
466 argv_printf_cat(struct argv *argres, const char *format, ...)
467 {
468  va_list arglist;
469  va_start(arglist, format);
470  bool res = argv_printf_arglist(argres, format, arglist);
471  va_end(arglist);
472  return res;
473 }
474 
484 void
485 argv_parse_cmd(struct argv *argres, const char *cmdstr)
486 {
487  argv_reset(argres);
488 
489  char *parms[MAX_PARMS + 1] = { 0 };
490  int nparms = parse_line(cmdstr, parms, MAX_PARMS, "SCRIPT-ARGV", 0,
491  D_ARGV_PARSE_CMD, &argres->gc);
492  if (nparms)
493  {
494  int i;
495  for (i = 0; i < nparms; ++i)
496  {
497  argv_append(argres, parms[i]);
498  }
499  }
500  else
501  {
502  argv_append(argres, string_alloc(cmdstr, &argres->gc));
503  }
504 }
bool argv_printf_cat(struct argv *argres, const char *format,...)
printf() inspired argv concatenation.
Definition: argv.c:466
static bool argv_printf_arglist(struct argv *argres, const char *format, va_list arglist)
Create a struct argv based on a format string.
Definition: argv.c:351
static void argv_grow(struct argv *a, const size_t add)
Extends an existing struct argv to carry minimum &#39;add&#39; number of new arguments.
Definition: argv.c:143
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:685
struct argv argv_new(void)
Allocates a new struct argv and ensures it is initialised.
Definition: argv.c:90
static void argv_extend(struct argv *a, const size_t newcap)
Resizes the list of arguments struct argv can carry.
Definition: argv.c:51
static void argv_init(struct argv *a)
Initialise an already allocated struct argv.
Definition: argv.c:74
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1023
static void argv_reset(struct argv *a)
Resets the struct argv to an initial state.
Definition: argv.c:116
const char * argv_str(const struct argv *a, struct gc_arena *gc, const unsigned int flags)
Generate a single string with all the arguments in a struct argv concatenated.
Definition: argv.c:233
#define D_ARGV_PARSE_CMD
Definition: errlevel.h:145
#define MAX_PARMS
Definition: options.h:51
int parse_line(const char *line, char *p[], const int n, const char *file, const int line_num, int msglevel, struct gc_arena *gc)
Definition: options.c:4446
char * print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
Definition: buffer.c:754
#define ASSERT(x)
Definition: error.h:221
static struct argv argv_clone(const struct argv *source, const size_t headroom)
Clones a struct argv with all the contents to a new allocated struct argv.
Definition: argv.c:182
void argv_msg(const int msglev, const struct argv *a)
Write the arguments stored in a struct argv via the msg() command.
Definition: argv.c:245
int add(int a, int b)
static char * argv_prep_format(const char *format, const char delim, size_t *count, struct gc_arena *gc)
Prepares argv format string for further processing.
Definition: argv.c:290
list flags
static void argv_append(struct argv *a, char *str)
Appends a string to to the list of arguments stored in a struct argv This will ensure the list size i...
Definition: argv.c:160
string f
Definition: http-client.py:6
static struct gc_arena gc_new(void)
Definition: buffer.h:1015
struct gc_arena gc
Definition: argv.h:36
size_t capacity
Definition: argv.h:37
char ** argv
Definition: argv.h:39
static size_t adjust_power_of_2(size_t u)
Definition: integer.h:136
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition: buffer.c:405
void argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix)
Similar to argv_msg() but prefixes the messages being written with a given string.
Definition: argv.c:262
#define vsnprintf
#define msg
Definition: error.h:173
const char * source
Definition: compat-lz4.h:688
size_t argc
Definition: argv.h:38
#define ALLOC_ARRAY_CLEAR_GC(dptr, type, n, gc)
Definition: buffer.h:1072
void argv_parse_cmd(struct argv *argres, const char *cmdstr)
Parses a command string, tokenizes it and puts each element into a separate struct argv argument slot...
Definition: argv.c:485
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
void argv_free(struct argv *a)
Frees all memory allocations allocated by the struct argv related functions.
Definition: argv.c:104
Definition: argv.h:35
struct argv argv_insert_head(const struct argv *a, const char *head)
Inserts an argument string in front of all other argument slots.
Definition: argv.c:210
bool argv_printf(struct argv *argres, const char *format,...)
printf() variant which populates a struct argv.
Definition: argv.c:442