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