utils.c (14234B)
1 /*
2 * Copyright (c) 2013-2022 Joris Vink <joris@coders.se>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <sys/types.h>
18 #include <sys/time.h>
19
20 #include <ctype.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <time.h>
26 #include <limits.h>
27
28 #include "kore.h"
29
30 static struct {
31 char *name;
32 int value;
33 } month_names[] = {
34 { "Jan", 0 },
35 { "Feb", 1 },
36 { "Mar", 2 },
37 { "Apr", 3 },
38 { "May", 4 },
39 { "Jun", 5 },
40 { "Jul", 6 },
41 { "Aug", 7 },
42 { "Sep", 8 },
43 { "Oct", 9 },
44 { "Nov", 10 },
45 { "Dec", 11 },
46 { NULL, 0 },
47 };
48
49 static void fatal_log(const char *, va_list);
50 static int utils_base64_encode(const void *, size_t, char **,
51 const char *, int);
52 static int utils_base64_decode(const char *, u_int8_t **,
53 size_t *, const char *, int);
54 static int utils_x509name_tobuf(void *, int, int, const char *,
55 const void *, size_t, int);
56
57 static char b64_table[] = \
58 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
59
60 static char b64url_table[] = \
61 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
62
63 /* b64_table and b64url_table are the same size. */
64 #define B64_TABLE_LEN (sizeof(b64_table))
65
66 #if defined(KORE_DEBUG)
67 void
68 kore_debug_internal(char *file, int line, const char *fmt, ...)
69 {
70 va_list args;
71 char buf[2048];
72
73 va_start(args, fmt);
74 (void)vsnprintf(buf, sizeof(buf), fmt, args);
75 va_end(args);
76
77 printf("[%d] %s:%d - %s\n", kore_pid, file, line, buf);
78 }
79 #endif
80
81 size_t
82 kore_strlcpy(char *dst, const char *src, const size_t len)
83 {
84 char *d = dst;
85 const char *s = src;
86 const char *end = dst + len - 1;
87
88 if (len == 0)
89 fatal("kore_strlcpy: len == 0");
90
91 while ((*d = *s) != '\0') {
92 if (d == end) {
93 *d = '\0';
94 break;
95 }
96
97 d++;
98 s++;
99 }
100
101 while (*s != '\0')
102 s++;
103
104 return (s - src);
105 }
106
107 int
108 kore_snprintf(char *str, size_t size, int *len, const char *fmt, ...)
109 {
110 int l;
111 va_list args;
112
113 va_start(args, fmt);
114 l = vsnprintf(str, size, fmt, args);
115 va_end(args);
116
117 if (l == -1 || (size_t)l >= size)
118 return (KORE_RESULT_ERROR);
119
120 if (len != NULL)
121 *len = l;
122
123 return (KORE_RESULT_OK);
124 }
125
126 long long
127 kore_strtonum(const char *str, int base, long long min, long long max, int *err)
128 {
129 long long l;
130 char *ep;
131
132 if (min > max) {
133 *err = KORE_RESULT_ERROR;
134 return (0);
135 }
136
137 errno = 0;
138 l = strtoll(str, &ep, base);
139 if (errno != 0 || str == ep || *ep != '\0') {
140 *err = KORE_RESULT_ERROR;
141 return (0);
142 }
143
144 if (l < min) {
145 *err = KORE_RESULT_ERROR;
146 return (0);
147 }
148
149 if (l > max) {
150 *err = KORE_RESULT_ERROR;
151 return (0);
152 }
153
154 *err = KORE_RESULT_OK;
155 return (l);
156 }
157
158 u_int64_t
159 kore_strtonum64(const char *str, int sign, int *err)
160 {
161 u_int64_t l;
162 long long ll;
163 char *ep;
164 int check;
165
166 l = 0;
167 check = 1;
168
169 ll = strtoll(str, &ep, 10);
170 if ((errno == EINVAL || errno == ERANGE) &&
171 (ll == LLONG_MIN || ll == LLONG_MAX)) {
172 if (sign) {
173 *err = KORE_RESULT_ERROR;
174 return (0);
175 }
176
177 check = 0;
178 }
179
180 if (!sign) {
181 l = strtoull(str, &ep, 10);
182 if ((errno == EINVAL || errno == ERANGE) && l == ULONG_MAX) {
183 *err = KORE_RESULT_ERROR;
184 return (0);
185 }
186
187 if (check && ll < 0) {
188 *err = KORE_RESULT_ERROR;
189 return (0);
190 }
191 }
192
193 if (str == ep || *ep != '\0') {
194 *err = KORE_RESULT_ERROR;
195 return (0);
196 }
197
198 *err = KORE_RESULT_OK;
199 return ((sign) ? (u_int64_t)ll : l);
200 }
201
202 double
203 kore_strtodouble(const char *str, long double min, long double max, int *err)
204 {
205 double d;
206 char *ep;
207
208 if (min > max) {
209 *err = KORE_RESULT_ERROR;
210 return (0);
211 }
212
213 errno = 0;
214 d = strtod(str, &ep);
215 if (errno == ERANGE || str == ep || *ep != '\0') {
216 *err = KORE_RESULT_ERROR;
217 return (0);
218 }
219
220 if (d < min) {
221 *err = KORE_RESULT_ERROR;
222 return (0);
223 }
224
225 if (d > max) {
226 *err = KORE_RESULT_ERROR;
227 return (0);
228 }
229
230 *err = KORE_RESULT_OK;
231 return (d);
232 }
233
234 int
235 kore_split_string(char *input, const char *delim, char **out, size_t ele)
236 {
237 int count;
238 char **ap;
239
240 if (ele == 0)
241 return (0);
242
243 count = 0;
244 for (ap = out; ap < &out[ele - 1] &&
245 (*ap = strsep(&input, delim)) != NULL;) {
246 if (**ap != '\0') {
247 ap++;
248 count++;
249 }
250 }
251
252 *ap = NULL;
253 return (count);
254 }
255
256 void
257 kore_strip_chars(char *in, const char strip, char **out)
258 {
259 u_int32_t len;
260 char *s, *p;
261
262 len = strlen(in);
263 *out = kore_malloc(len + 1);
264 p = *out;
265
266 for (s = in; s < (in + len); s++) {
267 if (*s == strip)
268 continue;
269
270 *p++ = *s;
271 }
272
273 *p = '\0';
274 }
275
276 time_t
277 kore_date_to_time(const char *http_date)
278 {
279 time_t t;
280 int err, i;
281 struct tm tm, *ltm;
282 char *args[7], *tbuf[5], *sdup;
283
284 time(&t);
285 ltm = localtime(&t);
286 sdup = kore_strdup(http_date);
287
288 t = KORE_RESULT_ERROR;
289
290 if (kore_split_string(sdup, " ", args, 7) != 6) {
291 kore_debug("misformed http-date: '%s'", http_date);
292 goto out;
293 }
294
295 memset(&tm, 0, sizeof(tm));
296
297 tm.tm_year = kore_strtonum(args[3], 10, 1900, 2068, &err) - 1900;
298 if (err == KORE_RESULT_ERROR) {
299 kore_debug("misformed year in http-date: '%s'", http_date);
300 goto out;
301 }
302
303 for (i = 0; month_names[i].name != NULL; i++) {
304 if (!strcmp(month_names[i].name, args[2])) {
305 tm.tm_mon = month_names[i].value;
306 break;
307 }
308 }
309
310 if (month_names[i].name == NULL) {
311 kore_debug("misformed month in http-date: '%s'", http_date);
312 goto out;
313 }
314
315 tm.tm_mday = kore_strtonum(args[1], 10, 1, 31, &err);
316 if (err == KORE_RESULT_ERROR) {
317 kore_debug("misformed mday in http-date: '%s'", http_date);
318 goto out;
319 }
320
321 if (kore_split_string(args[4], ":", tbuf, 5) != 3) {
322 kore_debug("misformed HH:MM:SS in http-date: '%s'", http_date);
323 goto out;
324 }
325
326 tm.tm_hour = kore_strtonum(tbuf[0], 10, 0, 23, &err);
327 if (err == KORE_RESULT_ERROR) {
328 kore_debug("misformed hour in http-date: '%s'", http_date);
329 goto out;
330 }
331
332 tm.tm_min = kore_strtonum(tbuf[1], 10, 0, 59, &err);
333 if (err == KORE_RESULT_ERROR) {
334 kore_debug("misformed minutes in http-date: '%s'", http_date);
335 goto out;
336 }
337
338 tm.tm_sec = kore_strtonum(tbuf[2], 10, 0, 60, &err);
339 if (err == KORE_RESULT_ERROR) {
340 kore_debug("misformed seconds in http-date: '%s'", http_date);
341 goto out;
342 }
343
344 tm.tm_isdst = ltm->tm_isdst;
345 t = mktime(&tm) + ltm->tm_gmtoff;
346 if (t == -1) {
347 t = 0;
348 kore_debug("mktime() on '%s' failed", http_date);
349 }
350
351 out:
352 kore_free(sdup);
353 return (t);
354 }
355
356 char *
357 kore_time_to_date(time_t now)
358 {
359 struct tm *tm;
360 static time_t last = 0;
361 static char tbuf[32];
362
363 if (now != last) {
364 last = now;
365
366 tm = gmtime(&now);
367 if (!strftime(tbuf, sizeof(tbuf), "%a, %d %b %Y %T GMT", tm)) {
368 kore_debug("strftime() gave us NULL (%ld)", now);
369 return (NULL);
370 }
371 }
372
373 return (tbuf);
374 }
375
376 u_int64_t
377 kore_time_ms(void)
378 {
379 struct timespec ts;
380
381 (void)clock_gettime(CLOCK_MONOTONIC, &ts);
382
383 return ((u_int64_t)(ts.tv_sec * 1000 + (ts.tv_nsec / 1000000)));
384 }
385
386 int
387 kore_base64url_encode(const void *data, size_t len, char **out, int flags)
388 {
389 return (utils_base64_encode(data, len, out, b64url_table, flags));
390 }
391
392 int
393 kore_base64_encode(const void *data, size_t len, char **out)
394 {
395 return (utils_base64_encode(data, len, out, b64_table, 0));
396 }
397
398 int
399 kore_base64url_decode(const char *in, u_int8_t **out, size_t *olen, int flags)
400 {
401 return (utils_base64_decode(in, out, olen, b64url_table, flags));
402 }
403
404 int
405 kore_base64_decode(const char *in, u_int8_t **out, size_t *olen)
406 {
407 return (utils_base64_decode(in, out, olen, b64_table, 0));
408 }
409
410 void *
411 kore_mem_find(void *src, size_t slen, const void *needle, size_t len)
412 {
413 size_t pos;
414
415 for (pos = 0; pos < slen; pos++) {
416 if ( *((u_int8_t *)src + pos) != *(const u_int8_t *)needle)
417 continue;
418
419 if ((slen - pos) < len)
420 return (NULL);
421
422 if (!memcmp((u_int8_t *)src + pos, needle, len))
423 return ((u_int8_t *)src + pos);
424 }
425
426 return (NULL);
427 }
428
429 char *
430 kore_text_trim(char *string, size_t len)
431 {
432 char *end;
433
434 if (len == 0)
435 return (string);
436
437 end = (string + len) - 1;
438 while (isspace(*(unsigned char *)string) && string < end)
439 string++;
440
441 while (isspace(*(unsigned char *)end) && end > string)
442 *(end)-- = '\0';
443
444 return (string);
445 }
446
447 char *
448 kore_read_line(FILE *fp, char *in, size_t len)
449 {
450 char *p, *t;
451
452 if (fgets(in, len, fp) == NULL)
453 return (NULL);
454
455 p = in;
456 in[strcspn(in, "\n")] = '\0';
457
458 while (isspace(*(unsigned char *)p))
459 p++;
460
461 if (p[0] == '#' || p[0] == '\0') {
462 p[0] = '\0';
463 return (p);
464 }
465
466 for (t = p; *t != '\0'; t++) {
467 if (*t == '\t')
468 *t = ' ';
469 }
470
471 return (p);
472 }
473
474 const char *
475 kore_worker_name(int id)
476 {
477 static char buf[64];
478
479 switch (id) {
480 case KORE_WORKER_KEYMGR:
481 (void)snprintf(buf, sizeof(buf), "[keymgr]");
482 break;
483 case KORE_WORKER_ACME:
484 (void)snprintf(buf, sizeof(buf), "[acme]");
485 break;
486 default:
487 (void)snprintf(buf, sizeof(buf), "[wrk %d]", id);
488 break;
489 }
490
491 return (buf);
492 }
493
494 int
495 kore_x509_issuer_name(struct connection *c, char **out, int flags)
496 {
497 struct kore_buf buf;
498 KORE_X509_NAMES *name;
499
500 if ((name = kore_tls_x509_issuer_name(c)) == NULL)
501 return (KORE_RESULT_ERROR);
502
503 kore_buf_init(&buf, 1024);
504
505 if (!kore_tls_x509name_foreach(name, flags, &buf,
506 utils_x509name_tobuf)) {
507 kore_buf_cleanup(&buf);
508 return (KORE_RESULT_ERROR);
509 }
510
511 *out = kore_buf_stringify(&buf, NULL);
512
513 buf.offset = 0;
514 buf.data = NULL;
515
516 return (KORE_RESULT_OK);
517 }
518
519 int
520 kore_x509_subject_name(struct connection *c, char **out, int flags)
521 {
522 struct kore_buf buf;
523 KORE_X509_NAMES *name;
524
525 if ((name = kore_tls_x509_subject_name(c)) == NULL)
526 return (KORE_RESULT_ERROR);
527
528 kore_buf_init(&buf, 1024);
529
530 if (!kore_tls_x509name_foreach(name, flags, &buf,
531 utils_x509name_tobuf)) {
532 kore_buf_cleanup(&buf);
533 return (KORE_RESULT_ERROR);
534 }
535
536 *out = kore_buf_stringify(&buf, NULL);
537
538 buf.offset = 0;
539 buf.data = NULL;
540
541 return (KORE_RESULT_OK);
542 }
543
544 void
545 fatal(const char *fmt, ...)
546 {
547 va_list args;
548
549 va_start(args, fmt);
550 fatal_log(fmt, args);
551 va_end(args);
552
553 exit(1);
554 }
555
556 void
557 fatalx(const char *fmt, ...)
558 {
559 va_list args;
560
561 /* In case people call fatalx() from the parent context. */
562 if (worker != NULL)
563 kore_msg_send(KORE_MSG_PARENT, KORE_MSG_SHUTDOWN, NULL, 0);
564
565 va_start(args, fmt);
566 fatal_log(fmt, args);
567 va_end(args);
568
569 exit(1);
570 }
571
572 static void
573 fatal_log(const char *fmt, va_list args)
574 {
575 char buf[2048];
576
577 (void)vsnprintf(buf, sizeof(buf), fmt, args);
578 kore_log(LOG_ERR, "FATAL: %s", buf);
579
580 if (worker != NULL && worker->id == KORE_WORKER_KEYMGR)
581 kore_keymgr_cleanup(1);
582 }
583
584 static int
585 utils_x509name_tobuf(void *udata, int islast, int nid, const char *field,
586 const void *data, size_t len, int flags)
587 {
588 struct kore_buf *buf = udata;
589
590 if (flags & KORE_X509_COMMON_NAME_ONLY) {
591 if (nid == KORE_X509_NAME_COMMON_NAME)
592 kore_buf_append(buf, data, len);
593 } else {
594 kore_buf_appendf(buf, "%s=", field);
595 kore_buf_append(buf, data, len);
596 if (!islast)
597 kore_buf_appendf(buf, " ");
598 }
599
600 return (KORE_RESULT_OK);
601 }
602
603 static int
604 utils_base64_encode(const void *data, size_t len, char **out,
605 const char *table, int flags)
606 {
607 u_int8_t n;
608 size_t nb;
609 const u_int8_t *ptr;
610 u_int32_t bytes;
611 struct kore_buf result;
612
613 nb = 0;
614 ptr = data;
615 kore_buf_init(&result, (len / 3) * 4);
616
617 while (len > 0) {
618 if (len > 2) {
619 nb = 3;
620 bytes = *ptr++ << 16;
621 bytes |= *ptr++ << 8;
622 bytes |= *ptr++;
623 } else if (len > 1) {
624 nb = 2;
625 bytes = *ptr++ << 16;
626 bytes |= *ptr++ << 8;
627 } else if (len == 1) {
628 nb = 1;
629 bytes = *ptr++ << 16;
630 } else {
631 kore_buf_cleanup(&result);
632 return (KORE_RESULT_ERROR);
633 }
634
635 n = (bytes >> 18) & 0x3f;
636 kore_buf_append(&result, &(table[n]), 1);
637 n = (bytes >> 12) & 0x3f;
638 kore_buf_append(&result, &(table[n]), 1);
639 if (nb > 1) {
640 n = (bytes >> 6) & 0x3f;
641 kore_buf_append(&result, &(table[n]), 1);
642 if (nb > 2) {
643 n = bytes & 0x3f;
644 kore_buf_append(&result, &(table[n]), 1);
645 }
646 }
647
648 len -= nb;
649 }
650
651 if (!(flags & KORE_BASE64_RAW)) {
652 switch (nb) {
653 case 1:
654 kore_buf_appendf(&result, "==");
655 break;
656 case 2:
657 kore_buf_appendf(&result, "=");
658 break;
659 case 3:
660 break;
661 default:
662 kore_buf_cleanup(&result);
663 return (KORE_RESULT_ERROR);
664 }
665 }
666
667 /* result.data gets taken over so no need to cleanup result. */
668 *out = kore_buf_stringify(&result, NULL);
669
670 return (KORE_RESULT_OK);
671 }
672
673 static int
674 utils_base64_decode(const char *in, u_int8_t **out, size_t *olen,
675 const char *table, int flags)
676 {
677 int i, c;
678 u_int8_t d, n, o;
679 struct kore_buf *res, buf;
680 const char *ptr, *pad;
681 u_int32_t b, len, plen, idx;
682
683 i = 4;
684 b = 0;
685 d = 0;
686 c = 0;
687 len = strlen(in);
688 memset(&buf, 0, sizeof(buf));
689
690 if (flags & KORE_BASE64_RAW) {
691 switch (len % 4) {
692 case 2:
693 plen = 2;
694 pad = "==";
695 break;
696 case 3:
697 plen = 1;
698 pad = "=";
699 break;
700 default:
701 return (KORE_RESULT_ERROR);
702 }
703
704 kore_buf_init(&buf, len + plen);
705 kore_buf_append(&buf, in, len);
706 kore_buf_append(&buf, pad, plen);
707
708 len = len + plen;
709 ptr = (const char *)buf.data;
710 } else {
711 ptr = in;
712 }
713
714 res = kore_buf_alloc(len);
715
716 for (idx = 0; idx < len; idx++) {
717 c = ptr[idx];
718 if (c == '=')
719 break;
720
721 for (o = 0; o < B64_TABLE_LEN; o++) {
722 if (table[o] == c) {
723 d = o;
724 break;
725 }
726 }
727
728 if (o == B64_TABLE_LEN) {
729 *out = NULL;
730 kore_buf_free(res);
731 kore_buf_cleanup(&buf);
732 return (KORE_RESULT_ERROR);
733 }
734
735 b |= (d & 0x3f) << ((i - 1) * 6);
736 i--;
737 if (i == 0) {
738 for (i = 2; i >= 0; i--) {
739 n = (b >> (8 * i));
740 kore_buf_append(res, &n, 1);
741 }
742
743 b = 0;
744 i = 4;
745 }
746 }
747
748 if (c == '=') {
749 if (i > 2) {
750 *out = NULL;
751 kore_buf_free(res);
752 kore_buf_cleanup(&buf);
753 return (KORE_RESULT_ERROR);
754 }
755
756 o = i;
757 for (i = 2; i >= o; i--) {
758 n = (b >> (8 * i));
759 kore_buf_append(res, &n, 1);
760 }
761 }
762
763 kore_buf_cleanup(&buf);
764 *out = kore_buf_release(res, olen);
765
766 return (KORE_RESULT_OK);
767 }