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