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
array_mult_safe(const size_t m1,const size_t m2,const size_t extra)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
buf_size_error(const size_t size)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
alloc_buf_debug(size_t size,const char * file,int line)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
81     check_malloc_return(buf.data);
82 
83     return buf;
84 }
85 
86 struct buffer
87 #ifdef DMALLOC
alloc_buf_gc_debug(size_t size,struct gc_arena * gc,const char * file,int line)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
clone_buf_debug(const struct buffer * buf,const char * file,int line)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
129     check_malloc_return(ret.data);
130     memcpy(BPTR(&ret), BPTR(buf), BLEN(buf));
131     return ret;
132 }
133 
134 #ifdef BUF_INIT_TRACKING
135 
136 bool
buf_init_debug(struct buffer * buf,int offset,const char * file,int line)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
buf_debug_line(const struct buffer * buf)145 buf_debug_line(const struct buffer *buf)
146 {
147     return buf->debug_line;
148 }
149 
150 static const char *
buf_debug_file(const struct buffer * buf)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
buf_clear(struct buffer * buf)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
buf_assign(struct buffer * dest,const struct buffer * src)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
free_buf(struct buffer * buf)185 free_buf(struct buffer *buf)
186 {
187     free(buf->data);
188     CLEAR(*buf);
189 }
190 
191 static void
free_buf_gc(struct buffer * buf,struct gc_arena * gc)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
buf_sub(struct buffer * buf,int size,bool prepend)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
buf_printf(struct buffer * buf,const char * format,...)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
buf_puts(struct buffer * buf,const char * str)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
openvpn_snprintf(char * str,size_t size,const char * format,...)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
openvpn_swprintf(wchar_t * const str,const size_t size,const wchar_t * const format,...)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
buf_catrunc(struct buffer * buf,const char * str)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
convert_to_one_line(struct buffer * buf)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
buffer_write_file(const char * filename,const struct buffer * buf)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
gc_malloc_debug(size_t size,bool clear,struct gc_arena * a,const char * file,int line)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
417         check_malloc_return(e);
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
x_gc_free(struct gc_arena * a)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
x_gc_freespecial(struct gc_arena * a)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
gc_addspecial(void * addr,void (* free_function)(void *),struct gc_arena * a)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
483     check_malloc_return(e);
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
gc_transfer(struct gc_arena * dest,struct gc_arena * src)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 *
format_hex_ex(const uint8_t * data,int size,int maxoutput,unsigned int space_break_flags,const char * separator,struct gc_arena * gc)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
buf_rmtail(struct buffer * buf,uint8_t remove)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
buf_null_terminate(struct buffer * buf)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
buf_chomp(struct buffer * buf)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 *
skip_leading_whitespace(const char * str)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
string_null_terminate(char * str,int len,int capacity)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
chomp(char * str)650 chomp(char *str)
651 {
652     rm_trailing_chars(str, "\r\n");
653 }
654 
655 /*
656  * Remove trailing chars
657  */
658 void
rm_trailing_chars(char * str,const char * what_to_delete)659 rm_trailing_chars(char *str, const char *what_to_delete)
660 {
661     bool modified;
662     do
663     {
664         const size_t 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
string_alloc_debug(const char * str,struct gc_arena * gc,const char * file,int line)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 size_t 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 #else
710             ret = calloc(1, n);
711 #endif
712             check_malloc_return(ret);
713         }
714         memcpy(ret, str, n);
715         return ret;
716     }
717     else
718     {
719         return NULL;
720     }
721 }
722 
723 /*
724  * Erase all characters in a string
725  */
726 void
string_clear(char * str)727 string_clear(char *str)
728 {
729     if (str)
730     {
731         secure_memzero(str, strlen(str));
732     }
733 }
734 
735 /*
736  * Return the length of a string array
737  */
738 int
string_array_len(const char ** array)739 string_array_len(const char **array)
740 {
741     int i = 0;
742     if (array)
743     {
744         while (array[i])
745         {
746             ++i;
747         }
748     }
749     return i;
750 }
751 
752 char *
print_argv(const char ** p,struct gc_arena * gc,const unsigned int flags)753 print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
754 {
755     struct buffer out = alloc_buf_gc(256, gc);
756     int i = 0;
757     for (;; )
758     {
759         const char *cp = *p++;
760         if (!cp)
761         {
762             break;
763         }
764         if (i)
765         {
766             buf_printf(&out, " ");
767         }
768         if (flags & PA_BRACKET)
769         {
770             buf_printf(&out, "[%s]", cp);
771         }
772         else
773         {
774             buf_printf(&out, "%s", cp);
775         }
776         ++i;
777     }
778     return BSTR(&out);
779 }
780 
781 /*
782  * Allocate a string inside a buffer
783  */
784 struct buffer
785 #ifdef DMALLOC
string_alloc_buf_debug(const char * str,struct gc_arena * gc,const char * file,int line)786 string_alloc_buf_debug(const char *str, struct gc_arena *gc, const char *file, int line)
787 #else
788 string_alloc_buf(const char *str, struct gc_arena *gc)
789 #endif
790 {
791     struct buffer buf;
792 
793     ASSERT(str);
794 
795 #ifdef DMALLOC
796     buf_set_read(&buf, (uint8_t *) string_alloc_debug(str, gc, file, line), strlen(str) + 1);
797 #else
798     buf_set_read(&buf, (uint8_t *) string_alloc(str, gc), strlen(str) + 1);
799 #endif
800 
801     if (buf.len > 0) /* Don't count trailing '\0' as part of length */
802     {
803         --buf.len;
804     }
805 
806     return buf;
807 }
808 
809 /*
810  * String comparison
811  */
812 
813 bool
buf_string_match_head_str(const struct buffer * src,const char * match)814 buf_string_match_head_str(const struct buffer *src, const char *match)
815 {
816     const size_t size = strlen(match);
817     if (size < 0 || size > src->len)
818     {
819         return false;
820     }
821     return memcmp(BPTR(src), match, size) == 0;
822 }
823 
824 bool
buf_string_compare_advance(struct buffer * src,const char * match)825 buf_string_compare_advance(struct buffer *src, const char *match)
826 {
827     if (buf_string_match_head_str(src, match))
828     {
829         buf_advance(src, (int)strlen(match));
830         return true;
831     }
832     else
833     {
834         return false;
835     }
836 }
837 
838 int
buf_substring_len(const struct buffer * buf,int delim)839 buf_substring_len(const struct buffer *buf, int delim)
840 {
841     int i = 0;
842     struct buffer tmp = *buf;
843     int c;
844 
845     while ((c = buf_read_u8(&tmp)) >= 0)
846     {
847         ++i;
848         if (c == delim)
849         {
850             return i;
851         }
852     }
853     return -1;
854 }
855 
856 /*
857  * String parsing
858  */
859 
860 bool
buf_parse(struct buffer * buf,const int delim,char * line,const int size)861 buf_parse(struct buffer *buf, const int delim, char *line, const int size)
862 {
863     bool eol = false;
864     int n = 0;
865     int c;
866 
867     ASSERT(size > 0);
868 
869     do
870     {
871         c = buf_read_u8(buf);
872         if (c < 0)
873         {
874             eol = true;
875         }
876         if (c <= 0 || c == delim)
877         {
878             c = 0;
879         }
880         if (n >= size)
881         {
882             break;
883         }
884         line[n++] = c;
885     }
886     while (c);
887 
888     line[size-1] = '\0';
889     return !(eol && !strlen(line));
890 }
891 
892 /*
893  * Print a string which might be NULL
894  */
895 const char *
np(const char * str)896 np(const char *str)
897 {
898     if (str)
899     {
900         return str;
901     }
902     else
903     {
904         return "[NULL]";
905     }
906 }
907 
908 /*
909  * Classify and mutate strings based on character types.
910  */
911 
912 bool
char_class(const unsigned char c,const unsigned int flags)913 char_class(const unsigned char c, const unsigned int flags)
914 {
915     if (!flags)
916     {
917         return false;
918     }
919     if (flags & CC_ANY)
920     {
921         return true;
922     }
923 
924     if ((flags & CC_NULL) && c == '\0')
925     {
926         return true;
927     }
928 
929     if ((flags & CC_ALNUM) && isalnum(c))
930     {
931         return true;
932     }
933     if ((flags & CC_ALPHA) && isalpha(c))
934     {
935         return true;
936     }
937     if ((flags & CC_ASCII) && isascii(c))
938     {
939         return true;
940     }
941     if ((flags & CC_CNTRL) && iscntrl(c))
942     {
943         return true;
944     }
945     if ((flags & CC_DIGIT) && isdigit(c))
946     {
947         return true;
948     }
949     if ((flags & CC_PRINT) && (c >= 32 && c != 127)) /* allow ascii non-control and UTF-8, consider DEL to be a control */
950     {
951         return true;
952     }
953     if ((flags & CC_PUNCT) && ispunct(c))
954     {
955         return true;
956     }
957     if ((flags & CC_SPACE) && isspace(c))
958     {
959         return true;
960     }
961     if ((flags & CC_XDIGIT) && isxdigit(c))
962     {
963         return true;
964     }
965 
966     if ((flags & CC_BLANK) && (c == ' ' || c == '\t'))
967     {
968         return true;
969     }
970     if ((flags & CC_NEWLINE) && c == '\n')
971     {
972         return true;
973     }
974     if ((flags & CC_CR) && c == '\r')
975     {
976         return true;
977     }
978 
979     if ((flags & CC_BACKSLASH) && c == '\\')
980     {
981         return true;
982     }
983     if ((flags & CC_UNDERBAR) && c == '_')
984     {
985         return true;
986     }
987     if ((flags & CC_DASH) && c == '-')
988     {
989         return true;
990     }
991     if ((flags & CC_DOT) && c == '.')
992     {
993         return true;
994     }
995     if ((flags & CC_COMMA) && c == ',')
996     {
997         return true;
998     }
999     if ((flags & CC_COLON) && c == ':')
1000     {
1001         return true;
1002     }
1003     if ((flags & CC_SLASH) && c == '/')
1004     {
1005         return true;
1006     }
1007     if ((flags & CC_SINGLE_QUOTE) && c == '\'')
1008     {
1009         return true;
1010     }
1011     if ((flags & CC_DOUBLE_QUOTE) && c == '\"')
1012     {
1013         return true;
1014     }
1015     if ((flags & CC_REVERSE_QUOTE) && c == '`')
1016     {
1017         return true;
1018     }
1019     if ((flags & CC_AT) && c == '@')
1020     {
1021         return true;
1022     }
1023     if ((flags & CC_EQUAL) && c == '=')
1024     {
1025         return true;
1026     }
1027     if ((flags & CC_LESS_THAN) && c == '<')
1028     {
1029         return true;
1030     }
1031     if ((flags & CC_GREATER_THAN) && c == '>')
1032     {
1033         return true;
1034     }
1035     if ((flags & CC_PIPE) && c == '|')
1036     {
1037         return true;
1038     }
1039     if ((flags & CC_QUESTION_MARK) && c == '?')
1040     {
1041         return true;
1042     }
1043     if ((flags & CC_ASTERISK) && c == '*')
1044     {
1045         return true;
1046     }
1047 
1048     return false;
1049 }
1050 
1051 static inline bool
char_inc_exc(const char c,const unsigned int inclusive,const unsigned int exclusive)1052 char_inc_exc(const char c, const unsigned int inclusive, const unsigned int exclusive)
1053 {
1054     return char_class(c, inclusive) && !char_class(c, exclusive);
1055 }
1056 
1057 bool
string_class(const char * str,const unsigned int inclusive,const unsigned int exclusive)1058 string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive)
1059 {
1060     char c;
1061     ASSERT(str);
1062     while ((c = *str++))
1063     {
1064         if (!char_inc_exc(c, inclusive, exclusive))
1065         {
1066             return false;
1067         }
1068     }
1069     return true;
1070 }
1071 
1072 /*
1073  * Modify string in place.
1074  * Guaranteed to not increase string length.
1075  */
1076 bool
string_mod(char * str,const unsigned int inclusive,const unsigned int exclusive,const char replace)1077 string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
1078 {
1079     const char *in = str;
1080     bool ret = true;
1081 
1082     ASSERT(str);
1083 
1084     while (true)
1085     {
1086         char c = *in++;
1087         if (c)
1088         {
1089             if (!char_inc_exc(c, inclusive, exclusive))
1090             {
1091                 c = replace;
1092                 ret = false;
1093             }
1094             if (c)
1095             {
1096                 *str++ = c;
1097             }
1098         }
1099         else
1100         {
1101             *str = '\0';
1102             break;
1103         }
1104     }
1105     return ret;
1106 }
1107 
1108 const char *
string_mod_const(const char * str,const unsigned int inclusive,const unsigned int exclusive,const char replace,struct gc_arena * gc)1109 string_mod_const(const char *str,
1110                  const unsigned int inclusive,
1111                  const unsigned int exclusive,
1112                  const char replace,
1113                  struct gc_arena *gc)
1114 {
1115     if (str)
1116     {
1117         char *buf = string_alloc(str, gc);
1118         string_mod(buf, inclusive, exclusive, replace);
1119         return buf;
1120     }
1121     else
1122     {
1123         return NULL;
1124     }
1125 }
1126 
1127 void
string_replace_leading(char * str,const char match,const char replace)1128 string_replace_leading(char *str, const char match, const char replace)
1129 {
1130     ASSERT(match != '\0');
1131     while (*str)
1132     {
1133         if (*str == match)
1134         {
1135             *str = replace;
1136         }
1137         else
1138         {
1139             break;
1140         }
1141         ++str;
1142     }
1143 }
1144 
1145 #ifdef CHARACTER_CLASS_DEBUG
1146 
1147 #define CC_INCLUDE    (CC_PRINT)
1148 #define CC_EXCLUDE    (0)
1149 #define CC_REPLACE    ('.')
1150 
1151 void
character_class_debug(void)1152 character_class_debug(void)
1153 {
1154     char buf[256];
1155 
1156     while (fgets(buf, sizeof(buf), stdin) != NULL)
1157     {
1158         string_mod(buf, CC_INCLUDE, CC_EXCLUDE, CC_REPLACE);
1159         printf("%s", buf);
1160     }
1161 }
1162 
1163 #endif
1164 
1165 #ifdef VERIFY_ALIGNMENT
1166 void
valign4(const struct buffer * buf,const char * file,const int line)1167 valign4(const struct buffer *buf, const char *file, const int line)
1168 {
1169     if (buf && buf->len)
1170     {
1171         int msglevel = D_ALIGN_DEBUG;
1172         const unsigned int u = (unsigned int) BPTR(buf);
1173 
1174         if (u & (PAYLOAD_ALIGN-1))
1175         {
1176             msglevel = D_ALIGN_ERRORS;
1177         }
1178 
1179         msg(msglevel, "%sAlignment at %s/%d ptr=" ptr_format " OLC=%d/%d/%d I=%s/%d",
1180             (msglevel == D_ALIGN_ERRORS) ? "ERROR: " : "",
1181             file,
1182             line,
1183             (ptr_type)buf->data,
1184             buf->offset,
1185             buf->len,
1186             buf->capacity,
1187             buf_debug_file(buf),
1188             buf_debug_line(buf));
1189     }
1190 }
1191 #endif /* ifdef VERIFY_ALIGNMENT */
1192 
1193 /*
1194  * struct buffer_list
1195  */
1196 struct buffer_list *
buffer_list_new(const int max_size)1197 buffer_list_new(const int max_size)
1198 {
1199     struct buffer_list *ret;
1200     ALLOC_OBJ_CLEAR(ret, struct buffer_list);
1201     ret->max_size = max_size;
1202     ret->size = 0;
1203     return ret;
1204 }
1205 
1206 void
buffer_list_free(struct buffer_list * ol)1207 buffer_list_free(struct buffer_list *ol)
1208 {
1209     if (ol)
1210     {
1211         buffer_list_reset(ol);
1212         free(ol);
1213     }
1214 }
1215 
1216 bool
buffer_list_defined(const struct buffer_list * ol)1217 buffer_list_defined(const struct buffer_list *ol)
1218 {
1219     return ol && ol->head != NULL;
1220 }
1221 
1222 void
buffer_list_reset(struct buffer_list * ol)1223 buffer_list_reset(struct buffer_list *ol)
1224 {
1225     struct buffer_entry *e = ol->head;
1226     while (e)
1227     {
1228         struct buffer_entry *next = e->next;
1229         free_buf(&e->buf);
1230         free(e);
1231         e = next;
1232     }
1233     ol->head = ol->tail = NULL;
1234     ol->size = 0;
1235 }
1236 
1237 void
buffer_list_push(struct buffer_list * ol,const char * str)1238 buffer_list_push(struct buffer_list *ol, const char *str)
1239 {
1240     if (str)
1241     {
1242         const size_t len = strlen((const char *)str);
1243         struct buffer_entry *e = buffer_list_push_data(ol, str, len+1);
1244         if (e)
1245         {
1246             e->buf.len = (int)len; /* Don't count trailing '\0' as part of length */
1247         }
1248     }
1249 }
1250 
1251 struct buffer_entry *
buffer_list_push_data(struct buffer_list * ol,const void * data,size_t size)1252 buffer_list_push_data(struct buffer_list *ol, const void *data, size_t size)
1253 {
1254     struct buffer_entry *e = NULL;
1255     if (data && (!ol->max_size || ol->size < ol->max_size))
1256     {
1257         ALLOC_OBJ_CLEAR(e, struct buffer_entry);
1258 
1259         ++ol->size;
1260         if (ol->tail)
1261         {
1262             ASSERT(ol->head);
1263             ol->tail->next = e;
1264         }
1265         else
1266         {
1267             ASSERT(!ol->head);
1268             ol->head = e;
1269         }
1270         e->buf = alloc_buf(size);
1271         memcpy(e->buf.data, data, size);
1272         e->buf.len = (int)size;
1273         ol->tail = e;
1274     }
1275     return e;
1276 }
1277 
1278 struct buffer *
buffer_list_peek(struct buffer_list * ol)1279 buffer_list_peek(struct buffer_list *ol)
1280 {
1281     if (ol && ol->head)
1282     {
1283         return &ol->head->buf;
1284     }
1285     else
1286     {
1287         return NULL;
1288     }
1289 }
1290 
1291 void
buffer_list_aggregate_separator(struct buffer_list * bl,const size_t max_len,const char * sep)1292 buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max_len,
1293                                 const char *sep)
1294 {
1295     const size_t sep_len = strlen(sep);
1296     struct buffer_entry *more = bl->head;
1297     size_t size = 0;
1298     int count = 0;
1299     for (count = 0; more; ++count)
1300     {
1301         size_t extra_len = BLEN(&more->buf) + sep_len;
1302         if (size + extra_len > max_len)
1303         {
1304             break;
1305         }
1306 
1307         size += extra_len;
1308         more = more->next;
1309     }
1310 
1311     if (count >= 2)
1312     {
1313         struct buffer_entry *f;
1314         ALLOC_OBJ_CLEAR(f, struct buffer_entry);
1315         f->buf = alloc_buf(size + 1); /* prevent 0-byte malloc */
1316 
1317         struct buffer_entry *e = bl->head;
1318         for (size_t i = 0; e && i < count; ++i)
1319         {
1320             struct buffer_entry *next = e->next;
1321             buf_copy(&f->buf, &e->buf);
1322             buf_write(&f->buf, sep, sep_len);
1323             free_buf(&e->buf);
1324             free(e);
1325             e = next;
1326         }
1327         bl->head = f;
1328         bl->size -= count - 1;
1329         f->next = more;
1330         if (!more)
1331         {
1332             bl->tail = f;
1333         }
1334     }
1335 }
1336 
1337 void
buffer_list_aggregate(struct buffer_list * bl,const size_t max)1338 buffer_list_aggregate(struct buffer_list *bl, const size_t max)
1339 {
1340     buffer_list_aggregate_separator(bl, max, "");
1341 }
1342 
1343 void
buffer_list_pop(struct buffer_list * ol)1344 buffer_list_pop(struct buffer_list *ol)
1345 {
1346     if (ol && ol->head)
1347     {
1348         struct buffer_entry *e = ol->head->next;
1349         free_buf(&ol->head->buf);
1350         free(ol->head);
1351         ol->head = e;
1352         --ol->size;
1353         if (!e)
1354         {
1355             ol->tail = NULL;
1356         }
1357     }
1358 }
1359 
1360 void
buffer_list_advance(struct buffer_list * ol,int n)1361 buffer_list_advance(struct buffer_list *ol, int n)
1362 {
1363     if (ol->head)
1364     {
1365         struct buffer *buf = &ol->head->buf;
1366         ASSERT(buf_advance(buf, n));
1367         if (!BLEN(buf))
1368         {
1369             buffer_list_pop(ol);
1370         }
1371     }
1372 }
1373 
1374 struct buffer_list *
buffer_list_file(const char * fn,int max_line_len)1375 buffer_list_file(const char *fn, int max_line_len)
1376 {
1377     FILE *fp = platform_fopen(fn, "r");
1378     struct buffer_list *bl = NULL;
1379 
1380     if (fp)
1381     {
1382         char *line = (char *) malloc(max_line_len);
1383         if (line)
1384         {
1385             bl = buffer_list_new(0);
1386             while (fgets(line, max_line_len, fp) != NULL)
1387             {
1388                 buffer_list_push(bl, line);
1389             }
1390             free(line);
1391         }
1392         fclose(fp);
1393     }
1394     return bl;
1395 }
1396 
1397 struct buffer
buffer_read_from_file(const char * filename,struct gc_arena * gc)1398 buffer_read_from_file(const char *filename, struct gc_arena *gc)
1399 {
1400     struct buffer ret = { 0 };
1401 
1402     platform_stat_t file_stat = { 0 };
1403     if (platform_stat(filename, &file_stat) < 0)
1404     {
1405         return ret;
1406     }
1407 
1408     FILE *fp = platform_fopen(filename, "r");
1409     if (!fp)
1410     {
1411         return ret;
1412     }
1413 
1414     const size_t size = file_stat.st_size;
1415     ret = alloc_buf_gc(size + 1, gc); /* space for trailing \0 */
1416     size_t read_size = fread(BPTR(&ret), 1, size, fp);
1417     if (read_size == 0)
1418     {
1419         free_buf_gc(&ret, gc);
1420         goto cleanup;
1421     }
1422     ASSERT(buf_inc_len(&ret, (int)read_size));
1423     buf_null_terminate(&ret);
1424 
1425 cleanup:
1426     fclose(fp);
1427     return ret;
1428 }
1429