1 /* This program is free software; you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License as published by
3  * the Free Software Foundation; version 2 of the License. For a copy,
4  * see http://www.gnu.org/licenses/gpl-2.0.html.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  */
11 
12 #include "config.h"
13 #include <sys/types.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdbool.h>
17 #include <stdarg.h>
18 #include <string.h>
19 #include <limits.h>
20 #include <regex.h>
21 #include "global.h"
22 #include "alternative.h"
23 #include "libstr.h"
24 #include "memdbg.h"
25 
26 #define MAX_DEC_VALUE (INT_MAX - 10) / 10
27 #define MAX_HEX_VALUE (INT_MAX - 16) / 16
28 
29 /* Memory free functions
30  */
check_free(void * ptr)31 void check_free(void *ptr) {
32 	if (ptr != NULL) {
33 		free(ptr);
34 	}
35 }
36 
clear_free(void * ptr,int size)37 void clear_free(void *ptr, int size) {
38 	if (size == CHECK_USE_STRLEN) {
39 		size = strlen(ptr);
40 	}
41 
42 	memset(ptr, 0, size);
43 	free(ptr);
44 }
45 
check_clear_free(void * ptr,int size)46 void check_clear_free(void *ptr, int size) {
47 	if (ptr != NULL) {
48 		clear_free(ptr, size);
49 	}
50 }
51 
52 /* Convert string to a boolean.
53  */
parse_yesno(char * yesno,bool * result)54 int parse_yesno(char *yesno, bool *result) {
55 	if ((strcmp(yesno, "no") == 0) || (strcmp(yesno, "false") == 0)) {
56 		*result = false;
57 	} else if ((strcmp(yesno, "yes") == 0) || (strcmp(yesno, "true") == 0)) {
58 		*result = true;
59 	} else {
60 		return -1;
61 	}
62 
63 	return 0;
64 }
65 
66 /* Convert a string to an integer.
67  */
str_to_int(char * str)68 int str_to_int(char *str) {
69 	int value = 0;
70 
71 	if (str == NULL) {
72 		return -1;
73 	} else if (*str == '\0') {
74 		return -1;
75 	}
76 
77 	do {
78 		if (value >= MAX_DEC_VALUE) {
79 			return -1;
80 		}
81 		if ((*str < '0') || (*str > '9')) {
82 			return -1;
83 		}
84 		value = (10 * value) + (*str - '0');
85 		str++;
86 	} while (*str != '\0');
87 
88 	return value;
89 }
90 
91 /* Convert a time string to an integer
92  */
time_str_to_int(char * str)93 int time_str_to_int(char *str) {
94 	int value, mul;
95 	size_t len;
96 
97 	if (str == NULL) {
98 		return -1;
99 	} else if ((len = strlen(str)) == 0) {
100 		return -1;
101 	}
102 
103 	if (str[len - 1] == 'm') {
104 		mul = MINUTE;
105 		str[len - 1] = '\0';
106 	} else if (str[len - 1] == 'h') {
107 		mul = HOUR;
108 		str[len - 1] = '\0';
109 	} else if (str[len - 1] == 'd') {
110 		mul = DAY;
111 		str[len - 1] = '\0';
112 	} else {
113 		mul = 1;
114 	}
115 
116 	if ((value = str_to_int(str)) == -1) {
117 		return -1;
118 	}
119 
120 	if ((mul > 1) && (value > 3650)) {
121 		return -1;
122 	}
123 
124 	return value * mul;
125 }
126 
127 /* Check if string is empty
128  */
empty_string(char * str)129 bool empty_string(char *str) {
130 	if (str == NULL) {
131 		return true;
132 	}
133 
134 	while (*str != '\0') {
135 		if ((*str != ' ') && (*str != '\t')) {
136 			return false;
137 		}
138 		str++;
139 	}
140 
141 	return true;
142 }
143 
144 /* Convert a hexadecimal char to decimal.
145  */
hex_char_to_int(char c)146 short hex_char_to_int(char c) {
147 	 if ((c >= '0') && (c <= '9')) {
148 		 return c - '0';
149 	 } else if ((c >= 'A') && (c <= 'F')) {
150 		 return c - 'A' + 10;
151 	 } else if ((c >= 'a') && (c <= 'f')) {
152 		 return c - 'a' + 10;
153 	 }
154 
155 	 return -1;
156 }
157 
158 /* Convert a hexadecimal string to an integer.
159  */
hex_to_int(char * str)160 int hex_to_int(char *str) {
161 	int value = 0;
162 	short digit;
163 
164 	if (str == NULL) {
165 		return -1;
166 	} else if (*str == '\0') {
167 		return -1;
168 	}
169 
170 	do {
171 		if (value >= MAX_HEX_VALUE) {
172 			return -1;
173 		}
174 		if ((digit = hex_char_to_int(*str)) == -1) {
175 			return -1;
176 		}
177 		value = (16 * value) + digit;
178 		str++;
179 	} while (*str != '\0');
180 
181 	return value;
182 }
183 
184 /* Count chars in string
185  */
str_count(char * str,char c)186 int str_count(char *str, char c) {
187 	int count = 0;
188 
189 	if (str == NULL) {
190 		return -1;
191 	}
192 
193 	while (*str != '\0') {
194 		if (*str == c) {
195 			count++;
196 		}
197 		str++;
198 	}
199 
200 	return count;
201 }
202 
203 /* Remove the leading and trailing spaces in a string.
204  */
remove_spaces(char * str)205 char *remove_spaces(char *str) {
206 	int pos;
207 
208 	if (str != NULL) {
209 		while ((*str == ' ') || (*str == '\t')) {
210 			str++;
211 		}
212 		pos = strlen(str) - 1;
213 		while (pos >= 0) {
214 			switch (*(str + pos)) {
215 				case ' ':
216 				case '\t':
217 				case '\r':
218 				case '\n':
219 					*(str + pos) = '\0';
220 					pos--;
221 					break;
222 				default:
223 					pos = -1;
224 			}
225 		}
226 	}
227 
228 	return str;
229 }
230 
231 /* Remove comment from a string.
232  */
uncomment(char * str)233 char *uncomment(char *str) {
234 	char *hash;
235 
236 	if (str == NULL) {
237 		return NULL;
238 	}
239 
240 	if (*str == '#') {
241 		*str = '\0';
242 		return str;
243 	}
244 
245 	if ((hash = strstr(str, " #")) != NULL) {
246 		*hash = '\0';
247 	}
248 
249 	if ((hash = strstr(str, "\t#")) != NULL) {
250 		*hash = '\0';
251 	}
252 
253 	return remove_spaces(str);
254 }
255 
256 /* Covert a string to lowercase.
257  */
strlower(char * str)258 char *strlower(char *str) {
259 	char *c;
260 
261 	if (str != NULL) {
262 		c = str;
263 		while (*c != '\0') {
264 			if ((*c >= 'A') && (*c <= 'Z')) {
265 				*c += 32;
266 			}
267 			c++;
268 		}
269 	}
270 
271 	return str;
272 }
273 
274 /* Split a string in 2 strings.
275  */
split_string(const char * str,char ** key,char ** value,char c)276 int split_string(const char *str, char **key, char **value, char c) {
277 	if ((str == NULL) || (key == NULL) || (value == NULL)) {
278 		return -1;
279 	}
280 
281 	*key = (char*)str;
282 	if ((*value = strchr(*key, c)) == NULL) {
283 		return -1;
284 	}
285 
286 	*(*value)++ = '\0';
287 	*key = remove_spaces(*key);
288 	*value = remove_spaces(*value);
289 
290 	return 0;
291 }
292 
split_configline(const char * str,char ** key,char ** value)293 int split_configline(const char *str, char **key, char **value) {
294 	int eq = 0;
295 
296 	if ((str == NULL) || (key == NULL) || (value == NULL)) {
297 		return -1;
298 	}
299 
300 	*key = remove_spaces((char*)str);
301 	*value = *key;
302 
303 	while (**value != '\0') {
304 		if ((**value == ' ') || (**value == '=')) {
305 			if (**value == '=') {
306 				eq++;
307 			}
308 			**value = '\0';
309 
310 			do {
311 				(*value)++;
312 				if (**value == '=') {
313 					eq++;
314 				}
315 			} while ((**value == ' ') || (**value == '='));
316 
317 			return (eq > 1) ? -1 : 0;
318 		}
319 
320 		(*value)++;
321 	}
322 
323 	return -1;
324 }
325 
326 /* Check the validity of an URL.
327  */
valid_uri(char * uri,bool allow_dot_files)328 bool valid_uri(char *uri, bool allow_dot_files) {
329 	char *pos;
330 	size_t size;
331 #ifdef CYGWIN
332 	size_t last_pos;
333 #endif
334 
335 	if (uri == NULL) {
336 		return false;
337 	} else if (*uri != '/') {
338 		return false;
339 	}
340 
341 	size = strlen(uri);
342 
343 	if (allow_dot_files && (size >= 10)) {
344 		if (strcmp(uri + size - 10, "/.hiawatha") == 0) {
345 			return false;
346 		}
347 #ifdef CYGWIN
348 		if (strcmp(uri + size - 10, "\\.hiawatha") == 0) {
349 			return false;
350 		}
351 #endif
352 	}
353 
354 #ifdef CYGWIN
355 	/* Deny trailing dots and spaces */
356 	last_pos = size - 1;
357 	if (*(uri + last_pos) == '.') {
358 		return false;
359 	} else if (*(uri + last_pos) == ' ') {
360 		return false;
361 	}
362 
363 	/* Deny 8.3 file format */
364 	if (last_pos >= 6) {
365 		if ((*(uri + last_pos - 5) == '~') && (*(uri + last_pos - 4) >= '0') &&
366 			(*(uri + last_pos - 4) <= '9') && (*(uri + last_pos - 3) == '.')) {
367 			return false;
368 		}
369 	}
370 
371 	if (allow_dot_files == false) {
372 		if ((pos = strstr(uri, "\\.")) != NULL) {
373 			return false;
374 		}
375 	} else {
376 		if ((pos = strstr(uri, "\\..")) != NULL) {
377 			return false;
378 		}
379 	}
380 #endif
381 
382 	/* RFC 5785 */
383 	if (strncmp(uri, "/.well-known", 12) != 0) {
384 		pos = uri;
385 	} else if (*(uri + 12) == '/') {
386 		pos = uri + 12;
387 	} else {
388 		return *(uri + 12) == '\0';
389 	}
390 
391 	if (allow_dot_files == false) {
392 		if ((pos = strstr(pos, "/.")) != NULL) {
393 			return false;
394 		}
395 	} else {
396 		if ((pos = strstr(pos, "/..")) != NULL) {
397 			return false;
398 		}
399 	}
400 
401 	while (*(++uri) != '\0') {
402 		if ((unsigned char)*uri < 32) {
403 			return false;
404 		}
405 	}
406 
407 	return true;
408 }
409 
410 /* Encode a string to an URL encoded one
411  */
char_needs_encoding(char c)412 static bool char_needs_encoding(char c) {
413 	return (c <= 32) || (strchr("\"#\%&'+:<>?", c) != NULL) || (c >= 126);
414 }
url_encode(char * str,char ** encoded)415 int url_encode(char *str, char **encoded) {
416 	char *c, *e;
417 	int replaced = 0;
418 
419 	if (str == NULL) {
420 		return -1;
421 	}
422 
423 	c = str;
424 	while (*c != '\0') {
425 		if (char_needs_encoding(*c)) {
426 			replaced++;
427 		}
428 		c++;
429 	}
430 
431 	if (replaced == 0) {
432 		*encoded = NULL;
433 		return 0;
434 	} else if ((*encoded = (char*)malloc(strlen(str) + (2 * replaced) + 1)) == NULL) {
435 		return -1;
436 	}
437 
438 	c = str;
439 	e = *encoded;
440 	while (*c != '\0') {
441 		if (char_needs_encoding(*c)) {
442 			sprintf(e, "%%%02hhx", *c);
443 			e += 2;
444 		} else {
445 			*e = *c;
446 		}
447 		c++;
448 		e++;
449 	}
450 	*e = '\0';
451 
452 	return replaced;
453 }
454 
455 /* Decode the URL encoded characters (%XX).
456  */
url_decode(char * str)457 void url_decode(char *str) {
458 	short low, high;
459 	char *dest = str;
460 
461 	if (str == NULL) {
462 		return;
463 	}
464 
465 	while (*str != '\0') {
466 		if (*str == '%') {
467 			if ((high = hex_char_to_int(*(str + 1))) != -1) {
468 				if ((low = hex_char_to_int(*(str + 2))) != -1) {
469 					str += 2;
470 					*str = (char)(high<<4) + low;
471 				}
472 			}
473 		}
474 		*(dest++) = *(str++);
475 	}
476 
477 	*dest = '\0';
478 }
479 
480 /* Scan for characters with ASCII value < 32.
481  */
forbidden_chars_present(char * str)482 bool forbidden_chars_present(char *str) {
483 	short low, high;
484 
485 	if (str == NULL) {
486 		return false;
487 	}
488 
489 	while (*str != '\0') {
490 		if ((*str > 0) && (*str < 32)) {
491 			return true;
492 		} else if (*str == '%') {
493 			if ((high = hex_char_to_int(*(str + 1))) != -1) {
494 				if ((low = hex_char_to_int(*(str + 2))) != -1) {
495 					if (((high << 4) + low) < 32) {
496 						return true;
497 					}
498 				}
499 			}
500 		}
501 		str++;
502 	}
503 
504 	return false;
505 }
506 
str_replace(char * src,char * from,char * to,char ** dst)507 int str_replace(char *src, char *from, char *to, char **dst) {
508 	char *pos, *start;
509 	int replaced = 0, len_from, len_to, len_start;
510 
511 	if ((src == NULL) || (from == NULL) || (to == NULL) || (dst == NULL)) {
512 		return 0;
513 	}
514 
515 	if ((len_from = strlen(from)) == 0) {
516 		return -1;
517 	}
518 	len_to = strlen(to);
519 
520 	start = src;
521 	while ((pos = strstr(start, from)) != NULL) {
522 		if ((*dst = (char*)malloc(strlen(src) - len_from + len_to + 1)) == NULL) {
523 			if (replaced > 0) {
524 				free(src);
525 			}
526 			return -1;
527 		}
528 		len_start = pos - src;
529 		memcpy(*dst, src, len_start);
530 		if (len_to > 0) {
531 			memcpy(*dst + len_start, to, len_to);
532 		}
533 		strcpy(*dst + len_start + len_to, pos + len_from);
534 
535 		if (replaced > 0) {
536 			free(src);
537 		}
538 		if (replaced++ == 100) {
539 			if (*dst != NULL) {
540 				free(*dst);
541 			}
542 			return -1;
543 		}
544 		src = *dst;
545 		start = src + len_start + len_to;
546 	}
547 
548 	return replaced;
549 }
550 
min_strlen(char * str,int n)551 bool min_strlen(char *str, int n) {
552 	int i = 0;
553 
554 	if (str != NULL) {
555 		while (i < n) {
556 			if (*(str + i) == '\0') {
557 				return false;
558 			}
559 			i++;
560 		}
561 	}
562 
563 	return true;
564 }
565 
header_to_variable(char * header,char * variable,int size)566 int header_to_variable(char *header, char *variable, int size) {
567 	char *column;
568 	int len, i;
569 
570 	if ((column = strchr(header, ':')) == NULL) {
571 		return -1;
572 	}
573 	len = column - header;
574 	if (len + 6 > size) {
575 		return -1;
576 	}
577 
578 	strcpy(variable, "HTTP_");
579 
580 	for (i = 0; i < len; i++) {
581 		if (((header[i] >= 'A') && (header[i] <= 'Z')) || ((header[i] >= '0') && (header[i] <= '9'))) {
582 			variable[i + 5] = header[i];
583 		} else if ((header[i] >= 'a') && (header[i] <= 'z')) {
584 			variable[i + 5] = header[i] - 32;
585 		} else if (header[i] == '-') {
586 			variable[i + 5] = '_';
587 		} else {
588 			return -1;
589 		}
590 	}
591 	variable[len + 5] = '\0';
592 
593 	return 0;
594 }
595 
596 /* Converts a filesize to a string.
597  */
filesize2str(char * buffer,int len,off_t fsize)598 int filesize2str(char *buffer, int len, off_t fsize) {
599 	int result = 0;
600 
601 	if (fsize < KILOBYTE) {
602 		result = snprintf(buffer, len - 1, "%llu byte", (long long)fsize);
603 	} else if (fsize < MEGABYTE) {
604 		result = snprintf(buffer, len - 1, "%0.1f kB", ((double)(fsize >> 6)) / 16);
605 	} else if (fsize < GIGABYTE) {
606 		result = snprintf(buffer, len - 1, "%0.1f MB", ((double)(fsize >> 16)) / 16);
607 	} else {
608 		result = snprintf(buffer, len - 1, "%0.1f GB", ((double)(fsize >> 26)) / 16);
609 	}
610 	buffer[len - 1] = '\0';
611 
612 	if (result == -1) {
613 		return -1;
614 	} else if (result >= len) {
615 		return -1;
616 	}
617 
618 	return result;
619 }
620 
621 /* Add 'str' with length 'len' to 'buffer' with size 'size'. If it does not
622  * fit, expand buffer with 'extra_size' bytes.
623  */
add_str(char ** buffer,int * size,int extra_size,int * len,char * str)624 int add_str(char **buffer, int *size, int extra_size, int *len, char *str) {
625 	size_t str_len;
626 	char *new;
627 
628 	str_len = strlen(str);
629 	while (*len + (int)str_len >= *size) {
630 		*size += extra_size;
631 		if ((new = (char*)realloc(*buffer, *size)) == NULL) {
632 			*size -= extra_size;
633 			return -1;
634 		}
635 		*buffer = new;
636 	}
637 
638 	memcpy(*buffer + *len, str, str_len);
639 	*len += str_len;
640 	*(*buffer + *len) = '\0';
641 
642 	return 0;
643 }
644 
strpcmp(char * str,regex_t * regexp)645 int strpcmp(char *str, regex_t *regexp) {
646 	return (regexec(regexp, str, 0, NULL, 0) == 0) ? 0 : -1;
647 }
648 
649 /* strcmp with remote timing-attack prevention
650  */
strcmp_rtap(const char * s1,const char * s2)651 int strcmp_rtap(const char *s1, const char *s2) {
652 	size_t l1, l2, len = 0, extra = 0, i;
653 	int result = 0;
654 
655 	if ((s1 == NULL) || (s2 == NULL)) {
656 		return -1;
657 	}
658 
659 	l1 = strlen(s1);
660 	l2 = strlen(s2);
661 
662 	if (l1 < l2) {
663 		result = 1;
664 		len = l1;
665 		extra = 0;
666 	}
667 	if (l1 > l2) {
668 		result = 1;
669 		len = l2;
670 		extra = l1 - l2;
671 	}
672 	if (l1 == l2) {
673 		result = 0;
674 		len = l1;
675 		extra = 0;
676 	}
677 
678 	for (i = 0; i < len; i++) {
679 		result |= s1[i] ^ s2[i];
680 	}
681 
682 	for (i = 0; i < extra; i++) {
683 		result |= s1[i] ^ s2[0];
684 	}
685 
686 	return result;
687 }
688 
md5_bin2hex(unsigned char bin[16],char hex[33])689 void md5_bin2hex(unsigned char bin[16], char hex[33]) {
690 	int i;
691 
692 	for (i = 0; i < 16; i++) {
693 		sprintf(&hex[2 * i], "%02x", bin[i]);
694 	}
695 	hex[32] = '\0';
696 }
697 
sha256_bin2hex(unsigned char bin[32],char hex[65])698 void sha256_bin2hex(unsigned char bin[32], char hex[65]) {
699 	int i;
700 
701 	for (i = 0; i < 32; i++) {
702 		sprintf(&hex[2 * i], "%02x", bin[i]);
703 	}
704 	hex[64] = '\0';
705 }
706 
hostname_match(char * hostname,char * pattern)707 bool hostname_match(char *hostname, char *pattern) {
708 	size_t len, len_hostname;
709 
710 	if ((len_hostname = strlen(hostname)) == 0) {
711 		return false;
712 	}
713 
714 	if (strcmp(hostname, pattern) == 0) {
715 		/* Exact match
716 		 */
717 		return true;
718 	} else if (strncmp(pattern, "*.", 2) == 0) {
719 		/* Wildcard in configuration
720 		 */
721 		if (strcmp(hostname, pattern + 2) == 0) {
722 			/* Only domainname requested
723 			 */
724 			return true;
725 		} else {
726 			len = strlen(pattern);
727 			if (len_hostname >= len) {
728 				if (strcmp(hostname + len_hostname - len + 1, pattern + 1) == 0) {
729 					/* Wildcard match for hostname
730 					 */
731 					return true;
732 				}
733 			}
734 		}
735 	}
736 
737 	return false;
738 }
739 
extension_from_uri(char * line,char * extension,size_t size)740 bool extension_from_uri(char *line, char *extension, size_t size) {
741 	char *c, *dot = NULL, *qmark = NULL;
742 	size_t len;
743 
744 	if ((line == NULL) || (extension == NULL)) {
745 		return false;
746 	}
747 
748 	c = line;
749 	while (*c != '\0') {
750 		if (*c == '?') {
751 			qmark = c;
752 			break;
753 		} else if (*c == '.') {
754 			dot = c + 1;
755 		}
756 		c++;
757 	}
758 
759 	if (dot == NULL) {
760 		return false;
761 	} else if (qmark == NULL) {
762 		len = strlen(dot);
763 	} else {
764 		len = qmark - dot;
765 	}
766 
767 	if (len >= size) {
768 		return false;
769 	}
770 
771 	memcpy(extension, dot, len);
772 	*(extension + len) = '\0';
773 
774 	return true;
775 }
776