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 
43 static void
44 argv_init(struct argv *a)
45 {
46  a->capacity = 0;
47  a->argc = 0;
48  a->argv = NULL;
49 }
50 
51 struct argv
52 argv_new(void)
53 {
54  struct argv ret;
55  argv_init(&ret);
56  return ret;
57 }
58 
59 void
60 argv_reset(struct argv *a)
61 {
62  size_t i;
63  for (i = 0; i < a->argc; ++i)
64  {
65  free(a->argv[i]);
66  }
67  free(a->argv);
68  argv_init(a);
69 }
70 
71 static void
72 argv_extend(struct argv *a, const size_t newcap)
73 {
74  if (newcap > a->capacity)
75  {
76  char **newargv;
77  size_t i;
78  ALLOC_ARRAY_CLEAR(newargv, char *, newcap);
79  for (i = 0; i < a->argc; ++i)
80  {
81  newargv[i] = a->argv[i];
82  }
83  free(a->argv);
84  a->argv = newargv;
85  a->capacity = newcap;
86  }
87 }
88 
89 static void
90 argv_grow(struct argv *a, const size_t add)
91 {
92  const size_t newargc = a->argc + add + 1;
93  ASSERT(newargc > a->argc);
94  argv_extend(a, adjust_power_of_2(newargc));
95 }
96 
97 static void
98 argv_append(struct argv *a, char *str) /* str must have been malloced or be NULL */
99 {
100  argv_grow(a, 1);
101  a->argv[a->argc++] = str;
102 }
103 
104 static struct argv
105 argv_clone(const struct argv *a, const size_t headroom)
106 {
107  struct argv r;
108  size_t i;
109 
110  argv_init(&r);
111  for (i = 0; i < headroom; ++i)
112  {
113  argv_append(&r, NULL);
114  }
115  if (a)
116  {
117  for (i = 0; i < a->argc; ++i)
118  {
119  argv_append(&r, string_alloc(a->argv[i], NULL));
120  }
121  }
122  return r;
123 }
124 
125 struct argv
126 argv_insert_head(const struct argv *a, const char *head)
127 {
128  struct argv r;
129  r = argv_clone(a, 1);
130  r.argv[0] = string_alloc(head, NULL);
131  return r;
132 }
133 
134 static char *
135 argv_term(const char **f)
136 {
137  const char *p = *f;
138  const char *term = NULL;
139  size_t termlen = 0;
140 
141  if (*p == '\0')
142  {
143  return NULL;
144  }
145 
146  while (true)
147  {
148  const int c = *p;
149  if (c == '\0')
150  {
151  break;
152  }
153  if (term)
154  {
155  if (!isspace(c))
156  {
157  ++termlen;
158  }
159  else
160  {
161  break;
162  }
163  }
164  else
165  {
166  if (!isspace(c))
167  {
168  term = p;
169  termlen = 1;
170  }
171  }
172  ++p;
173  }
174  *f = p;
175 
176  if (term)
177  {
178  char *ret;
179  ASSERT(termlen > 0);
180  ret = malloc(termlen + 1);
181  check_malloc_return(ret);
182  memcpy(ret, term, termlen);
183  ret[termlen] = '\0';
184  return ret;
185  }
186  else
187  {
188  return NULL;
189  }
190 }
191 
192 const char *
193 argv_str(const struct argv *a, struct gc_arena *gc, const unsigned int flags)
194 {
195  if (a->argv)
196  {
197  return print_argv((const char **)a->argv, gc, flags);
198  }
199  else
200  {
201  return "";
202  }
203 }
204 
205 void
206 argv_msg(const int msglev, const struct argv *a)
207 {
208  struct gc_arena gc = gc_new();
209  msg(msglev, "%s", argv_str(a, &gc, 0));
210  gc_free(&gc);
211 }
212 
213 void
214 argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix)
215 {
216  struct gc_arena gc = gc_new();
217  msg(msglev, "%s: %s", prefix, argv_str(a, &gc, 0));
218  gc_free(&gc);
219 }
220 
221 static void
222 argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
223 {
224  char *term;
225  const char *f = format;
226 
227  argv_extend(a, 1); /* ensure trailing NULL */
228 
229  while ((term = argv_term(&f)) != NULL)
230  {
231  if (term[0] == '%')
232  {
233  if (!strcmp(term, "%s"))
234  {
235  char *s = va_arg(arglist, char *);
236  if (!s)
237  {
238  s = "";
239  }
240  argv_append(a, string_alloc(s, NULL));
241  }
242  else if (!strcmp(term, "%d"))
243  {
244  char numstr[64];
245  openvpn_snprintf(numstr, sizeof(numstr), "%d", va_arg(arglist, int));
246  argv_append(a, string_alloc(numstr, NULL));
247  }
248  else if (!strcmp(term, "%u"))
249  {
250  char numstr[64];
251  openvpn_snprintf(numstr, sizeof(numstr), "%u", va_arg(arglist, unsigned int));
252  argv_append(a, string_alloc(numstr, NULL));
253  }
254  else if (!strcmp(term, "%lu"))
255  {
256  char numstr[64];
257  openvpn_snprintf(numstr, sizeof(numstr), "%lu",
258  va_arg(arglist, unsigned long));
259  argv_append(a, string_alloc(numstr, NULL));
260  }
261  else if (!strcmp(term, "%s/%d"))
262  {
263  char numstr[64];
264  char *s = va_arg(arglist, char *);
265 
266  if (!s)
267  {
268  s = "";
269  }
270 
271  openvpn_snprintf(numstr, sizeof(numstr), "%d", va_arg(arglist, int));
272 
273  {
274  const size_t len = strlen(s) + strlen(numstr) + 2;
275  char *combined = (char *) malloc(len);
276  check_malloc_return(combined);
277 
278  strcpy(combined, s);
279  strcat(combined, "/");
280  strcat(combined, numstr);
281  argv_append(a, combined);
282  }
283  }
284  else if (!strcmp(term, "%s%sc"))
285  {
286  char *s1 = va_arg(arglist, char *);
287  char *s2 = va_arg(arglist, char *);
288  char *combined;
289 
290  if (!s1)
291  {
292  s1 = "";
293  }
294  if (!s2)
295  {
296  s2 = "";
297  }
298  combined = (char *) malloc(strlen(s1) + strlen(s2) + 1);
299  check_malloc_return(combined);
300  strcpy(combined, s1);
301  strcat(combined, s2);
302  argv_append(a, combined);
303  }
304  else
305  {
306  ASSERT(0);
307  }
308  free(term);
309  }
310  else
311  {
312  argv_append(a, term);
313  }
314  }
315 }
316 
317 void
318 argv_printf(struct argv *a, const char *format, ...)
319 {
320  va_list arglist;
321  argv_reset(a);
322  va_start(arglist, format);
323  argv_printf_arglist(a, format, arglist);
324  va_end(arglist);
325 }
326 
327 void
328 argv_printf_cat(struct argv *a, const char *format, ...)
329 {
330  va_list arglist;
331  va_start(arglist, format);
332  argv_printf_arglist(a, format, arglist);
333  va_end(arglist);
334 }
335 
336 void
337 argv_parse_cmd(struct argv *a, const char *s)
338 {
339  int nparms;
340  char *parms[MAX_PARMS + 1];
341  struct gc_arena gc = gc_new();
342 
343  argv_reset(a);
344  argv_extend(a, 1); /* ensure trailing NULL */
345 
346  nparms = parse_line(s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
347  if (nparms)
348  {
349  int i;
350  for (i = 0; i < nparms; ++i)
351  {
352  argv_append(a, string_alloc(parms[i], NULL));
353  }
354  }
355  else
356  {
357  argv_append(a, string_alloc(s, NULL));
358  }
359 
360  gc_free(&gc);
361 }
static void argv_grow(struct argv *a, const size_t add)
Definition: argv.c:90
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:688
struct argv argv_new(void)
Definition: argv.c:52
static void argv_extend(struct argv *a, const size_t newcap)
Definition: argv.c:72
static void argv_init(struct argv *a)
Definition: argv.c:44
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1023
const char * argv_str(const struct argv *a, struct gc_arena *gc, const unsigned int flags)
Definition: argv.c:193
#define D_ARGV_PARSE_CMD
Definition: errlevel.h:143
#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:4231
char * print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
Definition: buffer.c:757
#define ASSERT(x)
Definition: error.h:221
void argv_msg(const int msglev, const struct argv *a)
Definition: argv.c:206
int add(int a, int b)
list flags
static void argv_append(struct argv *a, char *str)
Definition: argv.c:98
bool openvpn_snprintf(char *str, size_t size, const char *format,...)
Definition: buffer.c:299
string f
Definition: http-client.py:6
static struct gc_arena gc_new(void)
Definition: buffer.h:1015
#define malloc
Definition: cmocka.c:1795
size_t capacity
Definition: argv.h:36
char ** argv
Definition: argv.h:38
static size_t adjust_power_of_2(size_t u)
Definition: integer.h:136
void argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix)
Definition: argv.c:214
void argv_parse_cmd(struct argv *a, const char *s)
Definition: argv.c:337
#define msg
Definition: error.h:173
static void argv_printf_arglist(struct argv *a, const char *format, va_list arglist)
Definition: argv.c:222
static char * argv_term(const char **f)
Definition: argv.c:135
size_t argc
Definition: argv.h:37
#define ALLOC_ARRAY_CLEAR(dptr, type, n)
Definition: buffer.h:1066
static void check_malloc_return(const void *p)
Definition: buffer.h:1093
void argv_printf_cat(struct argv *a, const char *format,...)
Definition: argv.c:328
#define free
Definition: cmocka.c:1850
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
void argv_reset(struct argv *a)
Definition: argv.c:60
Definition: argv.h:35
static struct argv argv_clone(const struct argv *a, const size_t headroom)
Definition: argv.c:105
struct argv argv_insert_head(const struct argv *a, const char *head)
Definition: argv.c:126
void argv_printf(struct argv *a, const char *format,...)
Definition: argv.c:318