]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hexdecoct.c
basic: add log_level argument to timezone_is_valid
[thirdparty/systemd.git] / src / basic / hexdecoct.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6 ***/
7
8 #include <ctype.h>
9 #include <errno.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12
13 #include "alloc-util.h"
14 #include "hexdecoct.h"
15 #include "macro.h"
16 #include "string-util.h"
17 #include "util.h"
18
19 char octchar(int x) {
20 return '0' + (x & 7);
21 }
22
23 int unoctchar(char c) {
24
25 if (c >= '0' && c <= '7')
26 return c - '0';
27
28 return -EINVAL;
29 }
30
31 char decchar(int x) {
32 return '0' + (x % 10);
33 }
34
35 int undecchar(char c) {
36
37 if (c >= '0' && c <= '9')
38 return c - '0';
39
40 return -EINVAL;
41 }
42
43 char hexchar(int x) {
44 static const char table[16] = "0123456789abcdef";
45
46 return table[x & 15];
47 }
48
49 int unhexchar(char c) {
50
51 if (c >= '0' && c <= '9')
52 return c - '0';
53
54 if (c >= 'a' && c <= 'f')
55 return c - 'a' + 10;
56
57 if (c >= 'A' && c <= 'F')
58 return c - 'A' + 10;
59
60 return -EINVAL;
61 }
62
63 char *hexmem(const void *p, size_t l) {
64 const uint8_t *x;
65 char *r, *z;
66
67 z = r = new(char, l * 2 + 1);
68 if (!r)
69 return NULL;
70
71 for (x = p; x < (const uint8_t*) p + l; x++) {
72 *(z++) = hexchar(*x >> 4);
73 *(z++) = hexchar(*x & 15);
74 }
75
76 *z = 0;
77 return r;
78 }
79
80 int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
81 _cleanup_free_ uint8_t *r = NULL;
82 uint8_t *z;
83 const char *x;
84
85 assert(mem);
86 assert(len);
87 assert(p || l == 0);
88
89 if (l == (size_t) -1)
90 l = strlen(p);
91
92 if (l % 2 != 0)
93 return -EINVAL;
94
95 z = r = malloc((l + 1) / 2 + 1);
96 if (!r)
97 return -ENOMEM;
98
99 for (x = p; x < p + l; x += 2) {
100 int a, b;
101
102 a = unhexchar(x[0]);
103 if (a < 0)
104 return a;
105
106 b = unhexchar(x[1]);
107 if (b < 0)
108 return b;
109
110 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
111 }
112
113 *z = 0;
114
115 *mem = TAKE_PTR(r);
116 *len = (l + 1) / 2;
117
118 return 0;
119 }
120
121 /* https://tools.ietf.org/html/rfc4648#section-6
122 * Notice that base32hex differs from base32 in the alphabet it uses.
123 * The distinction is that the base32hex representation preserves the
124 * order of the underlying data when compared as bytestrings, this is
125 * useful when representing NSEC3 hashes, as one can then verify the
126 * order of hashes directly from their representation. */
127 char base32hexchar(int x) {
128 static const char table[32] = "0123456789"
129 "ABCDEFGHIJKLMNOPQRSTUV";
130
131 return table[x & 31];
132 }
133
134 int unbase32hexchar(char c) {
135 unsigned offset;
136
137 if (c >= '0' && c <= '9')
138 return c - '0';
139
140 offset = '9' - '0' + 1;
141
142 if (c >= 'A' && c <= 'V')
143 return c - 'A' + offset;
144
145 return -EINVAL;
146 }
147
148 char *base32hexmem(const void *p, size_t l, bool padding) {
149 char *r, *z;
150 const uint8_t *x;
151 size_t len;
152
153 assert(p || l == 0);
154
155 if (padding)
156 /* five input bytes makes eight output bytes, padding is added so we must round up */
157 len = 8 * (l + 4) / 5;
158 else {
159 /* same, but round down as there is no padding */
160 len = 8 * l / 5;
161
162 switch (l % 5) {
163 case 4:
164 len += 7;
165 break;
166 case 3:
167 len += 5;
168 break;
169 case 2:
170 len += 4;
171 break;
172 case 1:
173 len += 2;
174 break;
175 }
176 }
177
178 z = r = malloc(len + 1);
179 if (!r)
180 return NULL;
181
182 for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
183 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
184 x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
185 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
186 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
187 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
188 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
189 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
190 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
191 *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
192 *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
193 }
194
195 switch (l % 5) {
196 case 4:
197 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
198 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
199 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
200 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
201 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
202 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
203 *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
204 if (padding)
205 *(z++) = '=';
206
207 break;
208
209 case 3:
210 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
211 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
212 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
213 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
214 *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
215 if (padding) {
216 *(z++) = '=';
217 *(z++) = '=';
218 *(z++) = '=';
219 }
220
221 break;
222
223 case 2:
224 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
225 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
226 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
227 *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
228 if (padding) {
229 *(z++) = '=';
230 *(z++) = '=';
231 *(z++) = '=';
232 *(z++) = '=';
233 }
234
235 break;
236
237 case 1:
238 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
239 *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
240 if (padding) {
241 *(z++) = '=';
242 *(z++) = '=';
243 *(z++) = '=';
244 *(z++) = '=';
245 *(z++) = '=';
246 *(z++) = '=';
247 }
248
249 break;
250 }
251
252 *z = 0;
253 return r;
254 }
255
256 int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
257 _cleanup_free_ uint8_t *r = NULL;
258 int a, b, c, d, e, f, g, h;
259 uint8_t *z;
260 const char *x;
261 size_t len;
262 unsigned pad = 0;
263
264 assert(p || l == 0);
265 assert(mem);
266 assert(_len);
267
268 if (l == (size_t) -1)
269 l = strlen(p);
270
271 /* padding ensures any base32hex input has input divisible by 8 */
272 if (padding && l % 8 != 0)
273 return -EINVAL;
274
275 if (padding) {
276 /* strip the padding */
277 while (l > 0 && p[l - 1] == '=' && pad < 7) {
278 pad++;
279 l--;
280 }
281 }
282
283 /* a group of eight input bytes needs five output bytes, in case of
284 padding we need to add some extra bytes */
285 len = (l / 8) * 5;
286
287 switch (l % 8) {
288 case 7:
289 len += 4;
290 break;
291 case 5:
292 len += 3;
293 break;
294 case 4:
295 len += 2;
296 break;
297 case 2:
298 len += 1;
299 break;
300 case 0:
301 break;
302 default:
303 return -EINVAL;
304 }
305
306 z = r = malloc(len + 1);
307 if (!r)
308 return -ENOMEM;
309
310 for (x = p; x < p + (l / 8) * 8; x += 8) {
311 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
312 e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
313 a = unbase32hexchar(x[0]);
314 if (a < 0)
315 return -EINVAL;
316
317 b = unbase32hexchar(x[1]);
318 if (b < 0)
319 return -EINVAL;
320
321 c = unbase32hexchar(x[2]);
322 if (c < 0)
323 return -EINVAL;
324
325 d = unbase32hexchar(x[3]);
326 if (d < 0)
327 return -EINVAL;
328
329 e = unbase32hexchar(x[4]);
330 if (e < 0)
331 return -EINVAL;
332
333 f = unbase32hexchar(x[5]);
334 if (f < 0)
335 return -EINVAL;
336
337 g = unbase32hexchar(x[6]);
338 if (g < 0)
339 return -EINVAL;
340
341 h = unbase32hexchar(x[7]);
342 if (h < 0)
343 return -EINVAL;
344
345 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
346 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
347 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
348 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
349 *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
350 }
351
352 switch (l % 8) {
353 case 7:
354 a = unbase32hexchar(x[0]);
355 if (a < 0)
356 return -EINVAL;
357
358 b = unbase32hexchar(x[1]);
359 if (b < 0)
360 return -EINVAL;
361
362 c = unbase32hexchar(x[2]);
363 if (c < 0)
364 return -EINVAL;
365
366 d = unbase32hexchar(x[3]);
367 if (d < 0)
368 return -EINVAL;
369
370 e = unbase32hexchar(x[4]);
371 if (e < 0)
372 return -EINVAL;
373
374 f = unbase32hexchar(x[5]);
375 if (f < 0)
376 return -EINVAL;
377
378 g = unbase32hexchar(x[6]);
379 if (g < 0)
380 return -EINVAL;
381
382 /* g == 000VV000 */
383 if (g & 7)
384 return -EINVAL;
385
386 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
387 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
388 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
389 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
390
391 break;
392 case 5:
393 a = unbase32hexchar(x[0]);
394 if (a < 0)
395 return -EINVAL;
396
397 b = unbase32hexchar(x[1]);
398 if (b < 0)
399 return -EINVAL;
400
401 c = unbase32hexchar(x[2]);
402 if (c < 0)
403 return -EINVAL;
404
405 d = unbase32hexchar(x[3]);
406 if (d < 0)
407 return -EINVAL;
408
409 e = unbase32hexchar(x[4]);
410 if (e < 0)
411 return -EINVAL;
412
413 /* e == 000SSSS0 */
414 if (e & 1)
415 return -EINVAL;
416
417 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
418 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
419 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
420
421 break;
422 case 4:
423 a = unbase32hexchar(x[0]);
424 if (a < 0)
425 return -EINVAL;
426
427 b = unbase32hexchar(x[1]);
428 if (b < 0)
429 return -EINVAL;
430
431 c = unbase32hexchar(x[2]);
432 if (c < 0)
433 return -EINVAL;
434
435 d = unbase32hexchar(x[3]);
436 if (d < 0)
437 return -EINVAL;
438
439 /* d == 000W0000 */
440 if (d & 15)
441 return -EINVAL;
442
443 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
444 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
445
446 break;
447 case 2:
448 a = unbase32hexchar(x[0]);
449 if (a < 0)
450 return -EINVAL;
451
452 b = unbase32hexchar(x[1]);
453 if (b < 0)
454 return -EINVAL;
455
456 /* b == 000YYY00 */
457 if (b & 3)
458 return -EINVAL;
459
460 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
461
462 break;
463 case 0:
464 break;
465 default:
466 return -EINVAL;
467 }
468
469 *z = 0;
470
471 *mem = TAKE_PTR(r);
472 *_len = len;
473
474 return 0;
475 }
476
477 /* https://tools.ietf.org/html/rfc4648#section-4 */
478 char base64char(int x) {
479 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
480 "abcdefghijklmnopqrstuvwxyz"
481 "0123456789+/";
482 return table[x & 63];
483 }
484
485 int unbase64char(char c) {
486 unsigned offset;
487
488 if (c >= 'A' && c <= 'Z')
489 return c - 'A';
490
491 offset = 'Z' - 'A' + 1;
492
493 if (c >= 'a' && c <= 'z')
494 return c - 'a' + offset;
495
496 offset += 'z' - 'a' + 1;
497
498 if (c >= '0' && c <= '9')
499 return c - '0' + offset;
500
501 offset += '9' - '0' + 1;
502
503 if (c == '+')
504 return offset;
505
506 offset++;
507
508 if (c == '/')
509 return offset;
510
511 return -EINVAL;
512 }
513
514 ssize_t base64mem(const void *p, size_t l, char **out) {
515 char *r, *z;
516 const uint8_t *x;
517
518 assert(p || l == 0);
519 assert(out);
520
521 /* three input bytes makes four output bytes, padding is added so we must round up */
522 z = r = malloc(4 * (l + 2) / 3 + 1);
523 if (!r)
524 return -ENOMEM;
525
526 for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
527 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
528 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
529 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
530 *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
531 *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
532 }
533
534 switch (l % 3) {
535 case 2:
536 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
537 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
538 *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
539 *(z++) = '=';
540
541 break;
542 case 1:
543 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
544 *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
545 *(z++) = '=';
546 *(z++) = '=';
547
548 break;
549 }
550
551 *z = 0;
552 *out = r;
553 return z - r;
554 }
555
556 static int base64_append_width(
557 char **prefix, int plen,
558 const char *sep, int indent,
559 const void *p, size_t l,
560 int width) {
561
562 _cleanup_free_ char *x = NULL;
563 char *t, *s;
564 ssize_t slen, len, avail;
565 int line, lines;
566
567 len = base64mem(p, l, &x);
568 if (len <= 0)
569 return len;
570
571 lines = DIV_ROUND_UP(len, width);
572
573 slen = strlen_ptr(sep);
574 t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
575 if (!t)
576 return -ENOMEM;
577
578 memcpy_safe(t + plen, sep, slen);
579
580 for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
581 int act = MIN(width, avail);
582
583 if (line > 0 || sep) {
584 memset(s, ' ', indent);
585 s += indent;
586 }
587
588 memcpy(s, x + width * line, act);
589 s += act;
590 *(s++) = line < lines - 1 ? '\n' : '\0';
591 avail -= act;
592 }
593 assert(avail == 0);
594
595 *prefix = t;
596 return 0;
597 }
598
599 int base64_append(
600 char **prefix, int plen,
601 const void *p, size_t l,
602 int indent, int width) {
603
604 if (plen > width / 2 || plen + indent > width)
605 /* leave indent on the left, keep last column free */
606 return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
607 else
608 /* leave plen on the left, keep last column free */
609 return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1);
610 }
611
612 static int unbase64_next(const char **p, size_t *l) {
613 int ret;
614
615 assert(p);
616 assert(l);
617
618 /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
619 * greedily skip all preceeding and all following whitespace. */
620
621 for (;;) {
622 if (*l == 0)
623 return -EPIPE;
624
625 if (!strchr(WHITESPACE, **p))
626 break;
627
628 /* Skip leading whitespace */
629 (*p)++, (*l)--;
630 }
631
632 if (**p == '=')
633 ret = INT_MAX; /* return padding as INT_MAX */
634 else {
635 ret = unbase64char(**p);
636 if (ret < 0)
637 return ret;
638 }
639
640 for (;;) {
641 (*p)++, (*l)--;
642
643 if (*l == 0)
644 break;
645 if (!strchr(WHITESPACE, **p))
646 break;
647
648 /* Skip following whitespace */
649 }
650
651 return ret;
652 }
653
654 int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
655 _cleanup_free_ uint8_t *buf = NULL;
656 const char *x;
657 uint8_t *z;
658 size_t len;
659
660 assert(p || l == 0);
661 assert(ret);
662 assert(ret_size);
663
664 if (l == (size_t) -1)
665 l = strlen(p);
666
667 /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
668 bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
669 len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
670
671 buf = malloc(len + 1);
672 if (!buf)
673 return -ENOMEM;
674
675 for (x = p, z = buf;;) {
676 int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
677
678 a = unbase64_next(&x, &l);
679 if (a == -EPIPE) /* End of string */
680 break;
681 if (a < 0)
682 return a;
683 if (a == INT_MAX) /* Padding is not allowed at the beginning of a 4ch block */
684 return -EINVAL;
685
686 b = unbase64_next(&x, &l);
687 if (b < 0)
688 return b;
689 if (b == INT_MAX) /* Padding is not allowed at the second character of a 4ch block either */
690 return -EINVAL;
691
692 c = unbase64_next(&x, &l);
693 if (c < 0)
694 return c;
695
696 d = unbase64_next(&x, &l);
697 if (d < 0)
698 return d;
699
700 if (c == INT_MAX) { /* Padding at the third character */
701
702 if (d != INT_MAX) /* If the third character is padding, the fourth must be too */
703 return -EINVAL;
704
705 /* b == 00YY0000 */
706 if (b & 15)
707 return -EINVAL;
708
709 if (l > 0) /* Trailing rubbish? */
710 return -ENAMETOOLONG;
711
712 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
713 break;
714 }
715
716 if (d == INT_MAX) {
717 /* c == 00ZZZZ00 */
718 if (c & 3)
719 return -EINVAL;
720
721 if (l > 0) /* Trailing rubbish? */
722 return -ENAMETOOLONG;
723
724 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
725 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
726 break;
727 }
728
729 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
730 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
731 *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
732 }
733
734 *z = 0;
735
736 if (ret_size)
737 *ret_size = (size_t) (z - buf);
738
739 *ret = TAKE_PTR(buf);
740
741 return 0;
742 }
743
744 void hexdump(FILE *f, const void *p, size_t s) {
745 const uint8_t *b = p;
746 unsigned n = 0;
747
748 assert(b || s == 0);
749
750 if (!f)
751 f = stdout;
752
753 while (s > 0) {
754 size_t i;
755
756 fprintf(f, "%04x ", n);
757
758 for (i = 0; i < 16; i++) {
759
760 if (i >= s)
761 fputs(" ", f);
762 else
763 fprintf(f, "%02x ", b[i]);
764
765 if (i == 7)
766 fputc(' ', f);
767 }
768
769 fputc(' ', f);
770
771 for (i = 0; i < 16; i++) {
772
773 if (i >= s)
774 fputc(' ', f);
775 else
776 fputc(isprint(b[i]) ? (char) b[i] : '.', f);
777 }
778
779 fputc('\n', f);
780
781 if (s < 16)
782 break;
783
784 n += 16;
785 b += 16;
786 s -= 16;
787 }
788 }