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