OpenVPN
buffer.c
Go to the documentation of this file.
1 /*
2  * OpenVPN -- An application to securely tunnel IP networks
3  * over a single 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 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #elif defined(_MSC_VER)
27 #include "config-msvc.h"
28 #endif
29 
30 #include "syshead.h"
31 
32 #include "common.h"
33 #include "buffer.h"
34 #include "error.h"
35 #include "mtu.h"
36 #include "misc.h"
37 
38 #include "memdbg.h"
39 
40 #include <wchar.h>
41 
42 size_t
43 array_mult_safe(const size_t m1, const size_t m2, const size_t extra)
44 {
45  const size_t limit = 0xFFFFFFFF;
46  unsigned long long res = (unsigned long long)m1 * (unsigned long long)m2 + (unsigned long long)extra;
47  if (unlikely(m1 > limit) || unlikely(m2 > limit) || unlikely(extra > limit) || unlikely(res > (unsigned long long)limit))
48  {
49  msg(M_FATAL, "attemped allocation of excessively large array");
50  }
51  return (size_t) res;
52 }
53 
54 void
55 buf_size_error(const size_t size)
56 {
57  msg(M_FATAL, "fatal buffer size error, size=%lu", (unsigned long)size);
58 }
59 
60 struct buffer
61 #ifdef DMALLOC
62 alloc_buf_debug(size_t size, const char *file, int line)
63 #else
64 alloc_buf(size_t size)
65 #endif
66 {
67  struct buffer buf;
68 
69  if (!buf_size_valid(size))
70  {
71  buf_size_error(size);
72  }
73  buf.capacity = (int)size;
74  buf.offset = 0;
75  buf.len = 0;
76 #ifdef DMALLOC
77  buf.data = openvpn_dmalloc(file, line, size);
78 #else
79  buf.data = calloc(1, size);
80 #endif
82 
83  return buf;
84 }
85 
86 struct buffer
87 #ifdef DMALLOC
88 alloc_buf_gc_debug(size_t size, struct gc_arena *gc, const char *file, int line)
89 #else
90 alloc_buf_gc(size_t size, struct gc_arena *gc)
91 #endif
92 {
93  struct buffer buf;
94  if (!buf_size_valid(size))
95  {
96  buf_size_error(size);
97  }
98  buf.capacity = (int)size;
99  buf.offset = 0;
100  buf.len = 0;
101 #ifdef DMALLOC
102  buf.data = (uint8_t *) gc_malloc_debug(size, false, gc, file, line);
103 #else
104  buf.data = (uint8_t *) gc_malloc(size, false, gc);
105 #endif
106  if (size)
107  {
108  *buf.data = 0;
109  }
110  return buf;
111 }
112 
113 struct buffer
114 #ifdef DMALLOC
115 clone_buf_debug(const struct buffer *buf, const char *file, int line)
116 #else
117 clone_buf(const struct buffer *buf)
118 #endif
119 {
120  struct buffer ret;
121  ret.capacity = buf->capacity;
122  ret.offset = buf->offset;
123  ret.len = buf->len;
124 #ifdef DMALLOC
125  ret.data = (uint8_t *) openvpn_dmalloc(file, line, buf->capacity);
126 #else
127  ret.data = (uint8_t *) malloc(buf->capacity);
128 #endif
130  memcpy(BPTR(&ret), BPTR(buf), BLEN(buf));
131  return ret;
132 }
133 
134 #ifdef BUF_INIT_TRACKING
135 
136 bool
137 buf_init_debug(struct buffer *buf, int offset, const char *file, int line)
138 {
139  buf->debug_file = file;
140  buf->debug_line = line;
141  return buf_init_dowork(buf, offset);
142 }
143 
144 static inline int
145 buf_debug_line(const struct buffer *buf)
146 {
147  return buf->debug_line;
148 }
149 
150 static const char *
151 buf_debug_file(const struct buffer *buf)
152 {
153  return buf->debug_file;
154 }
155 
156 #else /* ifdef BUF_INIT_TRACKING */
157 
158 #define buf_debug_line(buf) 0
159 #define buf_debug_file(buf) "[UNDEF]"
160 
161 #endif /* ifdef BUF_INIT_TRACKING */
162 
163 void
164 buf_clear(struct buffer *buf)
165 {
166  if (buf->capacity > 0)
167  {
168  secure_memzero(buf->data, buf->capacity);
169  }
170  buf->len = 0;
171  buf->offset = 0;
172 }
173 
174 bool
175 buf_assign(struct buffer *dest, const struct buffer *src)
176 {
177  if (!buf_init(dest, src->offset))
178  {
179  return false;
180  }
181  return buf_write(dest, BPTR(src), BLEN(src));
182 }
183 
184 void
185 free_buf(struct buffer *buf)
186 {
187  if (buf->data)
188  {
189  free(buf->data);
190  }
191  CLEAR(*buf);
192 }
193 
194 static void
195 free_buf_gc(struct buffer *buf, struct gc_arena *gc)
196 {
197  if (gc)
198  {
199  struct gc_entry **e = &gc->list;
200 
201  while (*e)
202  {
203  /* check if this object is the one we want to delete */
204  if ((uint8_t *)(*e + 1) == buf->data)
205  {
206  struct gc_entry *to_delete = *e;
207 
208  /* remove element from linked list and free it */
209  *e = (*e)->next;
210  free(to_delete);
211 
212  break;
213  }
214 
215  e = &(*e)->next;
216  }
217  }
218 
219  CLEAR(*buf);
220 }
221 
222 /*
223  * Return a buffer for write that is a subset of another buffer
224  */
225 struct buffer
226 buf_sub(struct buffer *buf, int size, bool prepend)
227 {
228  struct buffer ret;
229  uint8_t *data;
230 
231  CLEAR(ret);
232  data = prepend ? buf_prepend(buf, size) : buf_write_alloc(buf, size);
233  if (data)
234  {
235  ret.capacity = size;
236  ret.data = data;
237  }
238  return ret;
239 }
240 
241 /*
242  * printf append to a buffer with overflow check
243  */
244 bool
245 buf_printf(struct buffer *buf, const char *format, ...)
246 {
247  int ret = false;
248  if (buf_defined(buf))
249  {
250  va_list arglist;
251  uint8_t *ptr = BEND(buf);
252  int cap = buf_forward_capacity(buf);
253 
254  if (cap > 0)
255  {
256  int stat;
257  va_start(arglist, format);
258  stat = vsnprintf((char *)ptr, cap, format, arglist);
259  va_end(arglist);
260  *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
261  buf->len += (int) strlen((char *)ptr);
262  if (stat >= 0 && stat < cap)
263  {
264  ret = true;
265  }
266  }
267  }
268  return ret;
269 }
270 
271 bool
272 buf_puts(struct buffer *buf, const char *str)
273 {
274  int ret = false;
275  uint8_t *ptr = BEND(buf);
276  int cap = buf_forward_capacity(buf);
277  if (cap > 0)
278  {
279  strncpynt((char *)ptr,str, cap);
280  *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
281  buf->len += (int) strlen((char *)ptr);
282  ret = true;
283  }
284  return ret;
285 }
286 
287 
288 /*
289  * This is necessary due to certain buggy implementations of snprintf,
290  * that don't guarantee null termination for size > 0.
291  *
292  * Return false on overflow.
293  *
294  * This functionality is duplicated in src/openvpnserv/common.c
295  * Any modifications here should be done to the other place as well.
296  */
297 
298 bool
299 openvpn_snprintf(char *str, size_t size, const char *format, ...)
300 {
301  va_list arglist;
302  int len = -1;
303  if (size > 0)
304  {
305  va_start(arglist, format);
306  len = vsnprintf(str, size, format, arglist);
307  va_end(arglist);
308  str[size - 1] = 0;
309  }
310  return (len >= 0 && len < size);
311 }
312 
313 /*
314  * openvpn_swprintf() is currently only used by Windows code paths
315  * and when enabled for all platforms it will currently break older
316  * OpenBSD versions lacking vswprintf(3) support in their libc.
317  */
318 
319 #ifdef _WIN32
320 bool
321 openvpn_swprintf(wchar_t *const str, const size_t size, const wchar_t *const format, ...)
322 {
323  va_list arglist;
324  int len = -1;
325  if (size > 0)
326  {
327  va_start(arglist, format);
328  len = vswprintf(str, size, format, arglist);
329  va_end(arglist);
330  str[size - 1] = L'\0';
331  }
332  return (len >= 0 && len < size);
333 }
334 #endif
335 
336 /*
337  * write a string to the end of a buffer that was
338  * truncated by buf_printf
339  */
340 void
341 buf_catrunc(struct buffer *buf, const char *str)
342 {
343  if (buf_forward_capacity(buf) <= 1)
344  {
345  int len = (int) strlen(str) + 1;
346  if (len < buf_forward_capacity_total(buf))
347  {
348  strncpynt((char *)(buf->data + buf->capacity - len), str, len);
349  }
350  }
351 }
352 
353 /*
354  * convert a multi-line output to one line
355  */
356 void
357 convert_to_one_line(struct buffer *buf)
358 {
359  uint8_t *cp = BPTR(buf);
360  int len = BLEN(buf);
361  while (len--)
362  {
363  if (*cp == '\n')
364  {
365  *cp = '|';
366  }
367  ++cp;
368  }
369 }
370 
371 bool
372 buffer_write_file(const char *filename, const struct buffer *buf)
373 {
374  bool ret = false;
375  int fd = platform_open(filename, O_CREAT | O_TRUNC | O_WRONLY,
376  S_IRUSR | S_IWUSR);
377  if (fd == -1)
378  {
379  msg(M_ERRNO, "Cannot open file '%s' for write", filename);
380  return false;
381  }
382 
383  const int size = write(fd, BPTR(buf), BLEN(buf));
384  if (size != BLEN(buf))
385  {
386  msg(M_ERRNO, "Write error on file '%s'", filename);
387  goto cleanup;
388  }
389 
390  ret = true;
391 cleanup:
392  if (close(fd) < 0)
393  {
394  msg(M_ERRNO, "Close error on file %s", filename);
395  ret = false;
396  }
397  return ret;
398 }
399 
400 /*
401  * Garbage collection
402  */
403 
404 void *
405 #ifdef DMALLOC
406 gc_malloc_debug(size_t size, bool clear, struct gc_arena *a, const char *file, int line)
407 #else
408 gc_malloc(size_t size, bool clear, struct gc_arena *a)
409 #endif
410 {
411  void *ret;
412  if (a)
413  {
414  struct gc_entry *e;
415 #ifdef DMALLOC
416  e = (struct gc_entry *) openvpn_dmalloc(file, line, size + sizeof(struct gc_entry));
417 #else
418  e = (struct gc_entry *) malloc(size + sizeof(struct gc_entry));
419 #endif
421  ret = (char *) e + sizeof(struct gc_entry);
422  e->next = a->list;
423  a->list = e;
424  }
425  else
426  {
427 #ifdef DMALLOC
428  ret = openvpn_dmalloc(file, line, size);
429 #else
430  ret = malloc(size);
431 #endif
432  check_malloc_return(ret);
433  }
434 #ifndef ZERO_BUFFER_ON_ALLOC
435  if (clear)
436 #endif
437  memset(ret, 0, size);
438  return ret;
439 }
440 
441 void
442 x_gc_free(struct gc_arena *a)
443 {
444  struct gc_entry *e;
445  e = a->list;
446  a->list = NULL;
447 
448  while (e != NULL)
449  {
450  struct gc_entry *next = e->next;
451  free(e);
452  e = next;
453  }
454 }
455 
456 /*
457  * Functions to handle special objects in gc_entries
458  */
459 
460 void
461 x_gc_freespecial(struct gc_arena *a)
462 {
463  struct gc_entry_special *e;
464  e = a->list_special;
465  a->list_special = NULL;
466 
467  while (e != NULL)
468  {
469  struct gc_entry_special *next = e->next;
470  e->free_fnc(e->addr);
471  free(e);
472  e = next;
473  }
474 }
475 
476 void
477 gc_addspecial(void *addr, void(free_function)(void *), struct gc_arena *a)
478 {
479  ASSERT(a);
480  struct gc_entry_special *e;
481 #ifdef DMALLOC
482  e = (struct gc_entry_special *) openvpn_dmalloc(file, line, sizeof(struct gc_entry_special));
483 #else
484  e = (struct gc_entry_special *) malloc(sizeof(struct gc_entry_special));
485 #endif
487  e->free_fnc = free_function;
488  e->addr = addr;
489 
490  e->next = a->list_special;
491  a->list_special = e;
492 }
493 
494 
495 /*
496  * Transfer src arena to dest, resetting src to an empty arena.
497  */
498 void
499 gc_transfer(struct gc_arena *dest, struct gc_arena *src)
500 {
501  if (dest && src)
502  {
503  struct gc_entry *e = src->list;
504  if (e)
505  {
506  while (e->next != NULL)
507  {
508  e = e->next;
509  }
510  e->next = dest->list;
511  dest->list = src->list;
512  src->list = NULL;
513  }
514  }
515 }
516 
517 /*
518  * Hex dump -- Output a binary buffer to a hex string and return it.
519  */
520 
521 char *
522 format_hex_ex(const uint8_t *data, int size, int maxoutput,
523  unsigned int space_break_flags, const char *separator,
524  struct gc_arena *gc)
525 {
526  const size_t bytes_per_hexblock = space_break_flags & FHE_SPACE_BREAK_MASK;
527  const size_t separator_len = separator ? strlen(separator) : 0;
528  static_assert(INT_MAX <= SIZE_MAX, "Code assumes INT_MAX <= SIZE_MAX");
529  const size_t out_len = maxoutput > 0 ? maxoutput :
530  ((size * 2) + ((size / bytes_per_hexblock) * separator_len) + 2);
531 
532  struct buffer out = alloc_buf_gc(out_len, gc);
533  for (int i = 0; i < size; ++i)
534  {
535  if (separator && i && !(i % bytes_per_hexblock))
536  {
537  buf_printf(&out, "%s", separator);
538  }
539  if (space_break_flags & FHE_CAPS)
540  {
541  buf_printf(&out, "%02X", data[i]);
542  }
543  else
544  {
545  buf_printf(&out, "%02x", data[i]);
546  }
547  }
548  buf_catrunc(&out, "[more...]");
549  return (char *)out.data;
550 }
551 
552 /*
553  * remove specific trailing character
554  */
555 
556 void
557 buf_rmtail(struct buffer *buf, uint8_t remove)
558 {
559  uint8_t *cp = BLAST(buf);
560  if (cp && *cp == remove)
561  {
562  *cp = '\0';
563  --buf->len;
564  }
565 }
566 
567 /*
568  * force a null termination even it requires
569  * truncation of the last char.
570  */
571 void
572 buf_null_terminate(struct buffer *buf)
573 {
574  char *last = (char *) BLAST(buf);
575  if (last && *last == '\0') /* already terminated? */
576  {
577  return;
578  }
579 
580  if (!buf_safe(buf, 1)) /* make space for trailing null */
581  {
582  buf_inc_len(buf, -1);
583  }
584 
585  buf_write_u8(buf, 0);
586 }
587 
588 /*
589  * Remove trailing \r and \n chars and ensure
590  * null termination.
591  */
592 void
593 buf_chomp(struct buffer *buf)
594 {
595  while (true)
596  {
597  char *last = (char *) BLAST(buf);
598  if (!last)
599  {
600  break;
601  }
602  if (char_class(*last, CC_CRLF|CC_NULL))
603  {
604  if (!buf_inc_len(buf, -1))
605  {
606  break;
607  }
608  }
609  else
610  {
611  break;
612  }
613  }
614  buf_null_terminate(buf);
615 }
616 
617 const char *
618 skip_leading_whitespace(const char *str)
619 {
620  while (*str)
621  {
622  const char c = *str;
623  if (!(c == ' ' || c == '\t'))
624  {
625  break;
626  }
627  ++str;
628  }
629  return str;
630 }
631 
632 /*
633  * like buf_null_terminate, but operate on strings
634  */
635 void
636 string_null_terminate(char *str, int len, int capacity)
637 {
638  ASSERT(len >= 0 && len <= capacity && capacity > 0);
639  if (len < capacity)
640  {
641  *(str + len) = '\0';
642  }
643  else if (len == capacity)
644  {
645  *(str + len - 1) = '\0';
646  }
647 }
648 
649 /*
650  * Remove trailing \r and \n chars.
651  */
652 void
653 chomp(char *str)
654 {
655  rm_trailing_chars(str, "\r\n");
656 }
657 
658 /*
659  * Remove trailing chars
660  */
661 void
662 rm_trailing_chars(char *str, const char *what_to_delete)
663 {
664  bool modified;
665  do
666  {
667  const int len = strlen(str);
668  modified = false;
669  if (len > 0)
670  {
671  char *cp = str + (len - 1);
672  if (strchr(what_to_delete, *cp) != NULL)
673  {
674  *cp = '\0';
675  modified = true;
676  }
677  }
678  } while (modified);
679 }
680 
681 /*
682  * Allocate a string
683  */
684 char *
685 #ifdef DMALLOC
686 string_alloc_debug(const char *str, struct gc_arena *gc, const char *file, int line)
687 #else
688 string_alloc(const char *str, struct gc_arena *gc)
689 #endif
690 {
691  if (str)
692  {
693  const int n = strlen(str) + 1;
694  char *ret;
695 
696  if (gc)
697  {
698 #ifdef DMALLOC
699  ret = (char *) gc_malloc_debug(n, false, gc, file, line);
700 #else
701  ret = (char *) gc_malloc(n, false, gc);
702 #endif
703  }
704  else
705  {
706  /* If there are no garbage collector available, it's expected
707  * that the caller cleans up afterwards. This is coherent with the
708  * earlier behaviour when gc_malloc() would be called with gc == NULL
709  */
710 #ifdef DMALLOC
711  ret = openvpn_dmalloc(file, line, n);
712  memset(ret, 0, n);
713 #else
714  ret = calloc(1, n);
715 #endif
716  check_malloc_return(ret);
717  }
718  memcpy(ret, str, n);
719  return ret;
720  }
721  else
722  {
723  return NULL;
724  }
725 }
726 
727 /*
728  * Erase all characters in a string
729  */
730 void
731 string_clear(char *str)
732 {
733  if (str)
734  {
735  secure_memzero(str, strlen(str));
736  }
737 }
738 
739 /*
740  * Return the length of a string array
741  */
742 int
743 string_array_len(const char **array)
744 {
745  int i = 0;
746  if (array)
747  {
748  while (array[i])
749  {
750  ++i;
751  }
752  }
753  return i;
754 }
755 
756 char *
757 print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
758 {
759  struct buffer out = alloc_buf_gc(256, gc);
760  int i = 0;
761  for (;; )
762  {
763  const char *cp = *p++;
764  if (!cp)
765  {
766  break;
767  }
768  if (i)
769  {
770  buf_printf(&out, " ");
771  }
772  if (flags & PA_BRACKET)
773  {
774  buf_printf(&out, "[%s]", cp);
775  }
776  else
777  {
778  buf_printf(&out, "%s", cp);
779  }
780  ++i;
781  }
782  return BSTR(&out);
783 }
784 
785 /*
786  * Allocate a string inside a buffer
787  */
788 struct buffer
789 #ifdef DMALLOC
790 string_alloc_buf_debug(const char *str, struct gc_arena *gc, const char *file, int line)
791 #else
792 string_alloc_buf(const char *str, struct gc_arena *gc)
793 #endif
794 {
795  struct buffer buf;
796 
797  ASSERT(str);
798 
799 #ifdef DMALLOC
800  buf_set_read(&buf, (uint8_t *) string_alloc_debug(str, gc, file, line), strlen(str) + 1);
801 #else
802  buf_set_read(&buf, (uint8_t *) string_alloc(str, gc), strlen(str) + 1);
803 #endif
804 
805  if (buf.len > 0) /* Don't count trailing '\0' as part of length */
806  {
807  --buf.len;
808  }
809 
810  return buf;
811 }
812 
813 /*
814  * String comparison
815  */
816 
817 bool
818 buf_string_match_head_str(const struct buffer *src, const char *match)
819 {
820  const int size = strlen(match);
821  if (size < 0 || size > src->len)
822  {
823  return false;
824  }
825  return memcmp(BPTR(src), match, size) == 0;
826 }
827 
828 bool
829 buf_string_compare_advance(struct buffer *src, const char *match)
830 {
831  if (buf_string_match_head_str(src, match))
832  {
833  buf_advance(src, strlen(match));
834  return true;
835  }
836  else
837  {
838  return false;
839  }
840 }
841 
842 int
843 buf_substring_len(const struct buffer *buf, int delim)
844 {
845  int i = 0;
846  struct buffer tmp = *buf;
847  int c;
848 
849  while ((c = buf_read_u8(&tmp)) >= 0)
850  {
851  ++i;
852  if (c == delim)
853  {
854  return i;
855  }
856  }
857  return -1;
858 }
859 
860 /*
861  * String parsing
862  */
863 
864 bool
865 buf_parse(struct buffer *buf, const int delim, char *line, const int size)
866 {
867  bool eol = false;
868  int n = 0;
869  int c;
870 
871  ASSERT(size > 0);
872 
873  do
874  {
875  c = buf_read_u8(buf);
876  if (c < 0)
877  {
878  eol = true;
879  }
880  if (c <= 0 || c == delim)
881  {
882  c = 0;
883  }
884  if (n >= size)
885  {
886  break;
887  }
888  line[n++] = c;
889  }
890  while (c);
891 
892  line[size-1] = '\0';
893  return !(eol && !strlen(line));
894 }
895 
896 /*
897  * Print a string which might be NULL
898  */
899 const char *
900 np(const char *str)
901 {
902  if (str)
903  {
904  return str;
905  }
906  else
907  {
908  return "[NULL]";
909  }
910 }
911 
912 /*
913  * Classify and mutate strings based on character types.
914  */
915 
916 bool
917 char_class(const unsigned char c, const unsigned int flags)
918 {
919  if (!flags)
920  {
921  return false;
922  }
923  if (flags & CC_ANY)
924  {
925  return true;
926  }
927 
928  if ((flags & CC_NULL) && c == '\0')
929  {
930  return true;
931  }
932 
933  if ((flags & CC_ALNUM) && isalnum(c))
934  {
935  return true;
936  }
937  if ((flags & CC_ALPHA) && isalpha(c))
938  {
939  return true;
940  }
941  if ((flags & CC_ASCII) && isascii(c))
942  {
943  return true;
944  }
945  if ((flags & CC_CNTRL) && iscntrl(c))
946  {
947  return true;
948  }
949  if ((flags & CC_DIGIT) && isdigit(c))
950  {
951  return true;
952  }
953  if ((flags & CC_PRINT) && (c >= 32 && c != 127)) /* allow ascii non-control and UTF-8, consider DEL to be a control */
954  {
955  return true;
956  }
957  if ((flags & CC_PUNCT) && ispunct(c))
958  {
959  return true;
960  }
961  if ((flags & CC_SPACE) && isspace(c))
962  {
963  return true;
964  }
965  if ((flags & CC_XDIGIT) && isxdigit(c))
966  {
967  return true;
968  }
969 
970  if ((flags & CC_BLANK) && (c == ' ' || c == '\t'))
971  {
972  return true;
973  }
974  if ((flags & CC_NEWLINE) && c == '\n')
975  {
976  return true;
977  }
978  if ((flags & CC_CR) && c == '\r')
979  {
980  return true;
981  }
982 
983  if ((flags & CC_BACKSLASH) && c == '\\')
984  {
985  return true;
986  }
987  if ((flags & CC_UNDERBAR) && c == '_')
988  {
989  return true;
990  }
991  if ((flags & CC_DASH) && c == '-')
992  {
993  return true;
994  }
995  if ((flags & CC_DOT) && c == '.')
996  {
997  return true;
998  }
999  if ((flags & CC_COMMA) && c == ',')
1000  {
1001  return true;
1002  }
1003  if ((flags & CC_COLON) && c == ':')
1004  {
1005  return true;
1006  }
1007  if ((flags & CC_SLASH) && c == '/')
1008  {
1009  return true;
1010  }
1011  if ((flags & CC_SINGLE_QUOTE) && c == '\'')
1012  {
1013  return true;
1014  }
1015  if ((flags & CC_DOUBLE_QUOTE) && c == '\"')
1016  {
1017  return true;
1018  }
1019  if ((flags & CC_REVERSE_QUOTE) && c == '`')
1020  {
1021  return true;
1022  }
1023  if ((flags & CC_AT) && c == '@')
1024  {
1025  return true;
1026  }
1027  if ((flags & CC_EQUAL) && c == '=')
1028  {
1029  return true;
1030  }
1031  if ((flags & CC_LESS_THAN) && c == '<')
1032  {
1033  return true;
1034  }
1035  if ((flags & CC_GREATER_THAN) && c == '>')
1036  {
1037  return true;
1038  }
1039  if ((flags & CC_PIPE) && c == '|')
1040  {
1041  return true;
1042  }
1043  if ((flags & CC_QUESTION_MARK) && c == '?')
1044  {
1045  return true;
1046  }
1047  if ((flags & CC_ASTERISK) && c == '*')
1048  {
1049  return true;
1050  }
1051 
1052  return false;
1053 }
1054 
1055 static inline bool
1056 char_inc_exc(const char c, const unsigned int inclusive, const unsigned int exclusive)
1057 {
1058  return char_class(c, inclusive) && !char_class(c, exclusive);
1059 }
1060 
1061 bool
1062 string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive)
1063 {
1064  char c;
1065  ASSERT(str);
1066  while ((c = *str++))
1067  {
1068  if (!char_inc_exc(c, inclusive, exclusive))
1069  {
1070  return false;
1071  }
1072  }
1073  return true;
1074 }
1075 
1076 /*
1077  * Modify string in place.
1078  * Guaranteed to not increase string length.
1079  */
1080 bool
1081 string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
1082 {
1083  const char *in = str;
1084  bool ret = true;
1085 
1086  ASSERT(str);
1087 
1088  while (true)
1089  {
1090  char c = *in++;
1091  if (c)
1092  {
1093  if (!char_inc_exc(c, inclusive, exclusive))
1094  {
1095  c = replace;
1096  ret = false;
1097  }
1098  if (c)
1099  {
1100  *str++ = c;
1101  }
1102  }
1103  else
1104  {
1105  *str = '\0';
1106  break;
1107  }
1108  }
1109  return ret;
1110 }
1111 
1112 const char *
1113 string_mod_const(const char *str,
1114  const unsigned int inclusive,
1115  const unsigned int exclusive,
1116  const char replace,
1117  struct gc_arena *gc)
1118 {
1119  if (str)
1120  {
1121  char *buf = string_alloc(str, gc);
1122  string_mod(buf, inclusive, exclusive, replace);
1123  return buf;
1124  }
1125  else
1126  {
1127  return NULL;
1128  }
1129 }
1130 
1131 void
1132 string_replace_leading(char *str, const char match, const char replace)
1133 {
1134  ASSERT(match != '\0');
1135  while (*str)
1136  {
1137  if (*str == match)
1138  {
1139  *str = replace;
1140  }
1141  else
1142  {
1143  break;
1144  }
1145  ++str;
1146  }
1147 }
1148 
1149 #ifdef CHARACTER_CLASS_DEBUG
1150 
1151 #define CC_INCLUDE (CC_PRINT)
1152 #define CC_EXCLUDE (0)
1153 #define CC_REPLACE ('.')
1154 
1155 void
1156 character_class_debug(void)
1157 {
1158  char buf[256];
1159 
1160  while (fgets(buf, sizeof(buf), stdin) != NULL)
1161  {
1162  string_mod(buf, CC_INCLUDE, CC_EXCLUDE, CC_REPLACE);
1163  printf("%s", buf);
1164  }
1165 }
1166 
1167 #endif
1168 
1169 #ifdef VERIFY_ALIGNMENT
1170 void
1171 valign4(const struct buffer *buf, const char *file, const int line)
1172 {
1173  if (buf && buf->len)
1174  {
1175  int msglevel = D_ALIGN_DEBUG;
1176  const unsigned int u = (unsigned int) BPTR(buf);
1177 
1178  if (u & (PAYLOAD_ALIGN-1))
1179  {
1180  msglevel = D_ALIGN_ERRORS;
1181  }
1182 
1183  msg(msglevel, "%sAlignment at %s/%d ptr=" ptr_format " OLC=%d/%d/%d I=%s/%d",
1184  (msglevel == D_ALIGN_ERRORS) ? "ERROR: " : "",
1185  file,
1186  line,
1187  (ptr_type)buf->data,
1188  buf->offset,
1189  buf->len,
1190  buf->capacity,
1191  buf_debug_file(buf),
1192  buf_debug_line(buf));
1193  }
1194 }
1195 #endif /* ifdef VERIFY_ALIGNMENT */
1196 
1197 /*
1198  * struct buffer_list
1199  */
1200 struct buffer_list *
1202 {
1203  struct buffer_list *ret;
1204  ALLOC_OBJ_CLEAR(ret, struct buffer_list);
1205  ret->max_size = max_size;
1206  ret->size = 0;
1207  return ret;
1208 }
1209 
1210 void
1212 {
1213  if (ol)
1214  {
1215  buffer_list_reset(ol);
1216  free(ol);
1217  }
1218 }
1219 
1220 bool
1222 {
1223  return ol && ol->head != NULL;
1224 }
1225 
1226 void
1228 {
1229  struct buffer_entry *e = ol->head;
1230  while (e)
1231  {
1232  struct buffer_entry *next = e->next;
1233  free_buf(&e->buf);
1234  free(e);
1235  e = next;
1236  }
1237  ol->head = ol->tail = NULL;
1238  ol->size = 0;
1239 }
1240 
1241 void
1242 buffer_list_push(struct buffer_list *ol, const char *str)
1243 {
1244  if (str)
1245  {
1246  const size_t len = strlen((const char *)str);
1247  struct buffer_entry *e = buffer_list_push_data(ol, str, len+1);
1248  if (e)
1249  {
1250  e->buf.len = len; /* Don't count trailing '\0' as part of length */
1251  }
1252  }
1253 }
1254 
1255 struct buffer_entry *
1256 buffer_list_push_data(struct buffer_list *ol, const void *data, size_t size)
1257 {
1258  struct buffer_entry *e = NULL;
1259  if (data && (!ol->max_size || ol->size < ol->max_size))
1260  {
1261  ALLOC_OBJ_CLEAR(e, struct buffer_entry);
1262 
1263  ++ol->size;
1264  if (ol->tail)
1265  {
1266  ASSERT(ol->head);
1267  ol->tail->next = e;
1268  }
1269  else
1270  {
1271  ASSERT(!ol->head);
1272  ol->head = e;
1273  }
1274  e->buf = alloc_buf(size);
1275  memcpy(e->buf.data, data, size);
1276  e->buf.len = (int)size;
1277  ol->tail = e;
1278  }
1279  return e;
1280 }
1281 
1282 struct buffer *
1284 {
1285  if (ol && ol->head)
1286  {
1287  return &ol->head->buf;
1288  }
1289  else
1290  {
1291  return NULL;
1292  }
1293 }
1294 
1295 void
1296 buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max_len,
1297  const char *sep)
1298 {
1299  const int sep_len = strlen(sep);
1300  struct buffer_entry *more = bl->head;
1301  size_t size = 0;
1302  int count = 0;
1303  for (count = 0; more; ++count)
1304  {
1305  size_t extra_len = BLEN(&more->buf) + sep_len;
1306  if (size + extra_len > max_len)
1307  {
1308  break;
1309  }
1310 
1311  size += extra_len;
1312  more = more->next;
1313  }
1314 
1315  if (count >= 2)
1316  {
1317  struct buffer_entry *f;
1318  ALLOC_OBJ_CLEAR(f, struct buffer_entry);
1319  f->buf = alloc_buf(size + 1); /* prevent 0-byte malloc */
1320 
1321  struct buffer_entry *e = bl->head;
1322  for (size_t i = 0; e && i < count; ++i)
1323  {
1324  struct buffer_entry *next = e->next;
1325  buf_copy(&f->buf, &e->buf);
1326  buf_write(&f->buf, sep, sep_len);
1327  free_buf(&e->buf);
1328  free(e);
1329  e = next;
1330  }
1331  bl->head = f;
1332  bl->size -= count - 1;
1333  f->next = more;
1334  if (!more)
1335  {
1336  bl->tail = f;
1337  }
1338  }
1339 }
1340 
1341 void
1342 buffer_list_aggregate(struct buffer_list *bl, const size_t max)
1343 {
1344  buffer_list_aggregate_separator(bl, max, "");
1345 }
1346 
1347 void
1349 {
1350  if (ol && ol->head)
1351  {
1352  struct buffer_entry *e = ol->head->next;
1353  free_buf(&ol->head->buf);
1354  free(ol->head);
1355  ol->head = e;
1356  --ol->size;
1357  if (!e)
1358  {
1359  ol->tail = NULL;
1360  }
1361  }
1362 }
1363 
1364 void
1366 {
1367  if (ol->head)
1368  {
1369  struct buffer *buf = &ol->head->buf;
1370  ASSERT(buf_advance(buf, n));
1371  if (!BLEN(buf))
1372  {
1373  buffer_list_pop(ol);
1374  }
1375  }
1376 }
1377 
1378 struct buffer_list *
1379 buffer_list_file(const char *fn, int max_line_len)
1380 {
1381  FILE *fp = platform_fopen(fn, "r");
1382  struct buffer_list *bl = NULL;
1383 
1384  if (fp)
1385  {
1386  char *line = (char *) malloc(max_line_len);
1387  if (line)
1388  {
1389  bl = buffer_list_new(0);
1390  while (fgets(line, max_line_len, fp) != NULL)
1391  {
1392  buffer_list_push(bl, line);
1393  }
1394  free(line);
1395  }
1396  fclose(fp);
1397  }
1398  return bl;
1399 }
1400 
1401 struct buffer
1402 buffer_read_from_file(const char *filename, struct gc_arena *gc)
1403 {
1404  struct buffer ret = { 0 };
1405 
1406  platform_stat_t file_stat = {0};
1407  if (platform_stat(filename, &file_stat) < 0)
1408  {
1409  return ret;
1410  }
1411 
1412  FILE *fp = platform_fopen(filename, "r");
1413  if (!fp)
1414  {
1415  return ret;
1416  }
1417 
1418  const size_t size = file_stat.st_size;
1419  ret = alloc_buf_gc(size + 1, gc); /* space for trailing \0 */
1420  ssize_t read_size = fread(BPTR(&ret), 1, size, fp);
1421  if (read_size < 0)
1422  {
1423  free_buf_gc(&ret, gc);
1424  goto cleanup;
1425  }
1426  ASSERT(buf_inc_len(&ret, read_size));
1427  buf_null_terminate(&ret);
1428 
1429 cleanup:
1430  fclose(fp);
1431  return ret;
1432 }
bool string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive)
Definition: buffer.c:1062
static bool buf_write_u8(struct buffer *dest, int data)
Definition: buffer.h:712
#define CC_ALNUM
Definition: buffer.h:909
static void strncpynt(char *dest, const char *src, size_t maxlen)
Definition: buffer.h:348
bool buffer_list_defined(const struct buffer_list *ol)
Checks if the list is valid and non-empty.
Definition: buffer.c:1221
void free_buf(struct buffer *buf)
Definition: buffer.c:185
void gc_addspecial(void *addr, void(free_function)(void *), struct gc_arena *a)
Definition: buffer.c:477
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:688
struct buffer_list * buffer_list_file(const char *fn, int max_line_len)
Definition: buffer.c:1379
void string_clear(char *str)
Definition: buffer.c:731
static void secure_memzero(void *data, size_t len)
Securely zeroise memory.
Definition: buffer.h:401
static bool buf_advance(struct buffer *buf, int size)
Definition: buffer.h:638
#define FHE_SPACE_BREAK_MASK
Definition: buffer.h:517
struct buffer_entry * head
Definition: buffer.h:1111
#define CC_LESS_THAN
Definition: buffer.h:935
unsigned long ptr_type
Definition: common.h:67
bool char_class(const unsigned char c, const unsigned int flags)
Definition: buffer.c:917
#define PAYLOAD_ALIGN
Definition: mtu.h:86
struct buffer string_alloc_buf(const char *str, struct gc_arena *gc)
Definition: buffer.c:792
#define buf_debug_file(buf)
Definition: buffer.c:159
bool buf_assign(struct buffer *dest, const struct buffer *src)
Definition: buffer.c:175
#define CC_PRINT
Definition: buffer.h:914
static bool buf_safe(const struct buffer *buf, int len)
Definition: buffer.h:540
struct buffer_list * buffer_list_new(const int max_size)
Allocate an empty buffer list of capacity max_size.
Definition: buffer.c:1201
#define ASSERT(x)
Definition: error.h:221
void gc_transfer(struct gc_arena *dest, struct gc_arena *src)
Definition: buffer.c:499
struct gc_entry_special * next
Definition: buffer.h:100
#define unlikely(x)
Definition: syshead.h:36
static uint8_t * buf_write_alloc(struct buffer *buf, int size)
Definition: buffer.h:655
struct gc_entry * next
Pointer to the next item in the linked list.
Definition: buffer.h:89
#define CC_REVERSE_QUOTE
Definition: buffer.h:932
#define CC_DIGIT
Definition: buffer.h:913
struct buffer alloc_buf(size_t size)
Definition: buffer.c:64
void buffer_list_free(struct buffer_list *ol)
Frees a buffer list and all the buffers in it.
Definition: buffer.c:1211
static bool match(const WIN32_FIND_DATA *find, LPCTSTR ext)
Definition: automatic.c:112
void buffer_list_aggregate(struct buffer_list *bl, const size_t max)
Aggregates as many buffers as possible from bl in a new buffer of maximum length max_len ...
Definition: buffer.c:1342
#define M_FATAL
Definition: error.h:94
bool buf_printf(struct buffer *buf, const char *format,...)
Definition: buffer.c:245
#define CC_XDIGIT
Definition: buffer.h:917
#define CLEAR(x)
Definition: basic.h:33
#define CC_CR
Definition: buffer.h:921
static int buf_read_u8(struct buffer *buf)
Definition: buffer.h:811
#define CC_EQUAL
Definition: buffer.h:934
#define CC_CNTRL
Definition: buffer.h:912
char * print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
Definition: buffer.c:757
struct buffer buffer_read_from_file(const char *filename, struct gc_arena *gc)
buffer_read_from_file - copy the content of a file into a buffer
Definition: buffer.c:1402
struct buffer_entry * tail
Definition: buffer.h:1112
static bool char_inc_exc(const char c, const unsigned int inclusive, const unsigned int exclusive)
Definition: buffer.c:1056
bool buffer_write_file(const char *filename, const struct buffer *buf)
Write buffer contents to file.
Definition: buffer.c:372
const char * np(const char *str)
Definition: buffer.c:900
#define CC_BACKSLASH
Definition: buffer.h:923
int max_size
Definition: buffer.h:1114
#define CC_AT
Definition: buffer.h:933
const char * skip_leading_whitespace(const char *str)
Definition: buffer.c:618
#define CC_DOT
Definition: buffer.h:926
#define S_IWUSR
Definition: config-msvc.h:108
int offset
Offset in bytes of the actual content within the allocated memory.
Definition: buffer.h:64
Garbage collection entry for a specially allocated structure that needs a custom free function to be ...
Definition: buffer.h:98
#define CC_COMMA
Definition: buffer.h:927
int capacity
Size in bytes of memory allocated by malloc().
Definition: buffer.h:62
list flags
int len
Length in bytes of the actual content within the allocated memory.
Definition: buffer.h:66
void string_null_terminate(char *str, int len, int capacity)
Definition: buffer.c:636
static bool buf_write(struct buffer *dest, const void *src, int size)
Definition: buffer.h:688
FILE * platform_fopen(const char *path, const char *mode)
Definition: platform.c:302
Garbage collection entry for one dynamically allocated block of memory.
Definition: buffer.h:87
#define BPTR(buf)
Definition: buffer.h:124
bool openvpn_snprintf(char *str, size_t size, const char *format,...)
Definition: buffer.c:299
#define D_ALIGN_ERRORS
Definition: errlevel.h:70
#define D_ALIGN_DEBUG
Definition: errlevel.h:138
static bool buf_size_valid(const size_t size)
Definition: buffer.h:272
static uint8_t * buf_prepend(struct buffer *buf, int size)
Definition: buffer.h:626
#define CC_UNDERBAR
Definition: buffer.h:924
#define CC_ASTERISK
Definition: buffer.h:939
static bool buf_init_dowork(struct buffer *buf, int offset)
Definition: buffer.h:306
int platform_open(const char *path, int flags, int mode)
Definition: platform.c:315
bool buf_puts(struct buffer *buf, const char *str)
Definition: buffer.c:272
void x_gc_free(struct gc_arena *a)
Definition: buffer.c:442
void rm_trailing_chars(char *str, const char *what_to_delete)
Definition: buffer.c:662
string f
Definition: http-client.py:6
void buf_null_terminate(struct buffer *buf)
Definition: buffer.c:572
#define malloc
Definition: cmocka.c:1795
int size
Definition: buffer.h:1113
void chomp(char *str)
Definition: buffer.c:653
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition: buffer.h:1049
struct buffer buf_sub(struct buffer *buf, int size, bool prepend)
Definition: buffer.c:226
void buffer_list_advance(struct buffer_list *ol, int n)
Definition: buffer.c:1365
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition: buffer.c:408
#define CC_NULL
Definition: buffer.h:907
size_t array_mult_safe(const size_t m1, const size_t m2, const size_t extra)
Definition: buffer.c:43
struct buffer buf
Definition: buffer.h:1105
struct gc_entry * list
First element of the linked list of gc_entry structures.
Definition: buffer.h:118
static int buf_forward_capacity(const struct buffer *buf)
Definition: buffer.h:561
#define vsnprintf
#define S_IRUSR
Definition: config-msvc.h:107
void buf_clear(struct buffer *buf)
Definition: buffer.c:164
void buffer_list_reset(struct buffer_list *ol)
Empty the list ol and frees all the contained buffers.
Definition: buffer.c:1227
static bool buf_copy(struct buffer *dest, const struct buffer *src)
Definition: buffer.h:733
char * format_hex_ex(const uint8_t *data, int size, int maxoutput, unsigned int space_break_flags, const char *separator, struct gc_arena *gc)
Definition: buffer.c:522
int buf_substring_len(const struct buffer *buf, int delim)
Definition: buffer.c:843
#define buf_debug_line(buf)
Definition: buffer.c:158
uint8_t * data
Pointer to the allocated memory.
Definition: buffer.h:68
void buf_chomp(struct buffer *buf)
Definition: buffer.c:593
int platform_stat(const char *path, platform_stat_t *buf)
Definition: platform.c:328
void buf_size_error(const size_t size)
Definition: buffer.c:55
#define CC_QUESTION_MARK
Definition: buffer.h:938
void buf_catrunc(struct buffer *buf, const char *str)
Definition: buffer.c:341
#define CC_SINGLE_QUOTE
Definition: buffer.h:930
#define BLEN(buf)
Definition: buffer.h:127
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:1113
void x_gc_freespecial(struct gc_arena *a)
Definition: buffer.c:461
void * addr
Definition: buffer.h:102
struct buffer_entry * next
Definition: buffer.h:1106
static bool buf_defined(const struct buffer *buf)
Definition: buffer.h:215
unsigned __int8 uint8_t
Definition: config-msvc.h:123
bool string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
Definition: buffer.c:1081
void buffer_list_push(struct buffer_list *ol, const char *str)
Allocates and appends a new buffer containing str as data to ol.
Definition: buffer.c:1242
int string_array_len(const char **array)
Definition: buffer.c:743
struct gc_entry_special * list_special
Definition: buffer.h:120
#define CC_GREATER_THAN
Definition: buffer.h:936
static bool buf_inc_len(struct buffer *buf, int inc)
Definition: buffer.h:610
static void check_malloc_return(const void *p)
Definition: buffer.h:1092
bool buf_parse(struct buffer *buf, const int delim, char *line, const int size)
Definition: buffer.c:865
void string_replace_leading(char *str, const char match, const char replace)
Definition: buffer.c:1132
#define CC_SLASH
Definition: buffer.h:929
#define PA_BRACKET
Definition: buffer.h:144
#define CC_PIPE
Definition: buffer.h:937
#define msg
Definition: error.h:173
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
#define buf_init(buf, offset)
Definition: buffer.h:196
void buf_rmtail(struct buffer *buf, uint8_t remove)
Definition: buffer.c:557
#define CC_BLANK
Definition: buffer.h:919
#define FHE_CAPS
Definition: buffer.h:518
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition: buffer.c:90
void convert_to_one_line(struct buffer *buf)
Definition: buffer.c:357
static int buf_forward_capacity_total(const struct buffer *buf)
Definition: buffer.h:579
#define free
Definition: cmocka.c:1850
bool openvpn_swprintf(wchar_t *const str, const size_t size, const wchar_t *const format,...)
Definition: buffer.c:321
Definition: buffer.h:1103
#define CC_SPACE
Definition: buffer.h:916
#define CC_ASCII
Definition: buffer.h:911
#define static_assert(expr, diagnostic)
Definition: error.h:232
#define BLAST(buf)
Definition: buffer.h:126
#define BSTR(buf)
Definition: buffer.h:129
#define BEND(buf)
Definition: buffer.h:125
#define M_ERRNO
Definition: error.h:99
static void free_buf_gc(struct buffer *buf, struct gc_arena *gc)
Definition: buffer.c:195
void(* free_fnc)(void *)
Definition: buffer.h:101
struct buffer clone_buf(const struct buffer *buf)
Definition: buffer.c:117
#define CC_COLON
Definition: buffer.h:928
#define CC_CRLF
Definition: buffer.h:943
char * dest
Definition: compat-lz4.h:431
#define CC_DASH
Definition: buffer.h:925
#define CC_PUNCT
Definition: buffer.h:915
void buffer_list_pop(struct buffer_list *ol)
Definition: buffer.c:1348
struct buffer * buffer_list_peek(struct buffer_list *ol)
Retrieve the head buffer.
Definition: buffer.c:1283
#define ssize_t
Definition: config-msvc.h:105
void buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max_len, const char *sep)
Aggregates as many buffers as possible from bl in a new buffer of maximum length max_len ...
Definition: buffer.c:1296
struct buffer_entry * buffer_list_push_data(struct buffer_list *ol, const void *data, size_t size)
Allocates and appends a new buffer containing data of length size.
Definition: buffer.c:1256
static void buf_set_read(struct buffer *buf, const uint8_t *data, int size)
Definition: buffer.h:335
#define CC_ANY
Definition: buffer.h:906
bool buf_string_match_head_str(const struct buffer *src, const char *match)
Definition: buffer.c:818
struct _stat platform_stat_t
Definition: platform.h:141
#define CC_NEWLINE
Definition: buffer.h:920
#define CC_DOUBLE_QUOTE
Definition: buffer.h:931
bool buf_string_compare_advance(struct buffer *src, const char *match)
Definition: buffer.c:829
#define CC_ALPHA
Definition: buffer.h:910
#define ptr_format
Definition: common.h:58