Coverage Report

Created: 2026-01-09 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/common/miscellaneous.c
Line
Count
Source
1
/* miscellaneous.c - Stuff not fitting elsewhere
2
 *  Copyright (C) 2003, 2006 Free Software Foundation, Inc.
3
 *
4
 * This file is part of GnuPG.
5
 *
6
 * This file is free software; you can redistribute it and/or modify
7
 * it under the terms of either
8
 *
9
 *   - the GNU Lesser General Public License as published by the Free
10
 *     Software Foundation; either version 3 of the License, or (at
11
 *     your option) any later version.
12
 *
13
 * or
14
 *
15
 *   - the GNU General Public License as published by the Free
16
 *     Software Foundation; either version 2 of the License, or (at
17
 *     your option) any later version.
18
 *
19
 * or both in parallel, as here.
20
 *
21
 * This file is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
28
 */
29
30
#include <config.h>
31
#include <stdlib.h>
32
#include <limits.h>
33
#include <errno.h>
34
35
#include "util.h"
36
#include "iobuf.h"
37
#include "i18n.h"
38
39
40
/* This function is called by libgcrypt on a fatal error.  */
41
static void
42
my_gcry_fatalerror_handler (void *opaque, int rc, const char *text)
43
0
{
44
0
  (void)opaque;
45
46
0
  log_fatal ("libgcrypt problem: %s\n", text ? text : gpg_strerror (rc));
47
0
  abort ();
48
0
}
49
50
51
/* This function is called by libgcrypt if it ran out of core and
52
   there is no way to return that error to the caller.  We do our own
53
   function here to make use of our logging functions. */
54
static int
55
my_gcry_outofcore_handler (void *opaque, size_t req_n, unsigned int flags)
56
0
{
57
0
  static int been_here;  /* Used to protect against recursive calls. */
58
59
0
  (void)opaque;
60
61
0
  if (!been_here)
62
0
    {
63
0
      been_here = 1;
64
0
      if ( (flags & 1) )
65
0
        log_fatal (_("out of core in secure memory "
66
0
                     "while allocating %lu bytes"), (unsigned long)req_n);
67
0
      else
68
0
        log_fatal (_("out of core while allocating %lu bytes"),
69
0
                   (unsigned long)req_n);
70
0
    }
71
0
  return 0; /* Let libgcrypt call its own fatal error handler.
72
               Actually this will turn out to be
73
               my_gcry_fatalerror_handler. */
74
0
}
75
76
77
/* Setup libgcrypt to use our own logging functions.  Should be used
78
   early at startup. */
79
void
80
setup_libgcrypt_logging (void)
81
0
{
82
0
  gcry_set_fatalerror_handler (my_gcry_fatalerror_handler, NULL);
83
0
  gcry_set_outofcore_handler (my_gcry_outofcore_handler, NULL);
84
0
}
85
86
87
/* Print an out of core message and let the process die.  The printed
88
 * error is taken from ERRNO.  */
89
void
90
xoutofcore (void)
91
0
{
92
0
  gpg_error_t err = gpg_error_from_syserror ();
93
0
  log_fatal (_("error allocating enough memory: %s\n"), gpg_strerror (err));
94
0
  abort (); /* Never called; just to make the compiler happy.  */
95
0
}
96
97
98
/* Wrapper around gpgrt_reallocarray.   */
99
void *
100
xreallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size)
101
0
{
102
0
  void *p = gpgrt_reallocarray (a, oldnmemb, nmemb, size);
103
0
  if (!p)
104
0
    xoutofcore ();
105
0
  return p;
106
0
}
107
108
109
/* A wrapper around gcry_cipher_algo_name to return the string
110
   "AES-128" instead of "AES".  Given that we have an alias in
111
   libgcrypt for it, it does not harm to too much to return this other
112
   string.  Some users complained that we print "AES" but "AES192"
113
   and "AES256".  We can't fix that in libgcrypt but it is pretty
114
   safe to do it in an application. */
115
const char *
116
gnupg_cipher_algo_name (int algo)
117
0
{
118
0
  const char *s;
119
120
0
  s = gcry_cipher_algo_name (algo);
121
0
  if (!strcmp (s, "AES"))
122
0
    s = "AES128";
123
0
  return s;
124
0
}
125
126
127
void
128
obsolete_option (const char *configname, unsigned int configlineno,
129
                 const char *name)
130
0
{
131
0
  if (configname)
132
0
    log_info (_("%s:%u: obsolete option \"%s\" - it has no effect\n"),
133
0
              configname, configlineno, name);
134
0
  else
135
0
    log_info (_("WARNING: \"%s%s\" is an obsolete option - it has no effect\n"),
136
0
              "--", name);
137
0
}
138
139
140
/* Decide whether the filename is stdout or a real filename and return
141
 * an appropriate string.  */
142
const char *
143
print_fname_stdout (const char *s)
144
0
{
145
0
    if( !s || (*s == '-' && !s[1]) )
146
0
  return "[stdout]";
147
0
    return s;
148
0
}
149
150
151
/* Decide whether the filename is stdin or a real filename and return
152
 * an appropriate string.  */
153
const char *
154
print_fname_stdin (const char *s)
155
0
{
156
0
    if( !s || (*s == '-' && !s[1]) )
157
0
  return "[stdin]";
158
0
    return s;
159
0
}
160
161
162
static int
163
do_print_utf8_buffer (estream_t stream,
164
                      const void *buffer, size_t length,
165
                      const char *delimiters, size_t *bytes_written)
166
0
{
167
0
  const char *p = buffer;
168
0
  size_t i;
169
170
  /* We can handle plain ascii simpler, so check for it first. */
171
0
  for (i=0; i < length; i++ )
172
0
    {
173
0
      if ( (p[i] & 0x80) )
174
0
        break;
175
0
    }
176
0
  if (i < length)
177
0
    {
178
0
      int delim = delimiters? *delimiters : 0;
179
0
      char *buf;
180
0
      int ret;
181
182
      /*(utf8 conversion already does the control character quoting). */
183
0
      buf = utf8_to_native (p, length, delim);
184
0
      if (bytes_written)
185
0
        *bytes_written = strlen (buf);
186
0
      ret = es_fputs (buf, stream);
187
0
      xfree (buf);
188
0
      return ret == EOF? ret : (int)i;
189
0
    }
190
0
  else
191
0
    return es_write_sanitized (stream, p, length, delimiters, bytes_written);
192
0
}
193
194
195
void
196
print_utf8_buffer3 (estream_t stream, const void *p, size_t n,
197
                    const char *delim)
198
0
{
199
0
  do_print_utf8_buffer (stream, p, n, delim, NULL);
200
0
}
201
202
203
void
204
print_utf8_buffer2 (estream_t stream, const void *p, size_t n, int delim)
205
0
{
206
0
  char tmp[2];
207
208
0
  tmp[0] = delim;
209
0
  tmp[1] = 0;
210
0
  do_print_utf8_buffer (stream, p, n, tmp, NULL);
211
0
}
212
213
214
void
215
print_utf8_buffer (estream_t stream, const void *p, size_t n)
216
0
{
217
0
  do_print_utf8_buffer (stream, p, n, NULL, NULL);
218
0
}
219
220
221
void
222
print_utf8_string (estream_t stream, const char *p)
223
0
{
224
0
  if (!p)
225
0
    p = "";
226
0
  do_print_utf8_buffer (stream, p, strlen (p), NULL, NULL);
227
0
}
228
229
230
/* Write LENGTH bytes of BUFFER to FP as a hex encoded string.
231
   RESERVED must be 0. */
232
void
233
print_hexstring (FILE *fp, const void *buffer, size_t length, int reserved)
234
0
{
235
0
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
236
0
  const unsigned char *s;
237
238
0
  (void)reserved;
239
240
0
  for (s = buffer; length; s++, length--)
241
0
    {
242
0
      putc ( tohex ((*s>>4)&15), fp);
243
0
      putc ( tohex (*s&15), fp);
244
0
    }
245
0
#undef tohex
246
0
}
247
248
249
/* Create a string from the buffer P_ARG of length N which is suitable
250
 * for printing.  Caller must release the created string using xfree.
251
 * On error ERRNO is set and NULL returned.  Errors are only possible
252
 * due to malloc failure.  */
253
char *
254
try_make_printable_string (const void *p_arg, size_t n, int delim)
255
3.08k
{
256
3.08k
  const unsigned char *p = p_arg;
257
3.08k
  size_t save_n, buflen;
258
3.08k
  const unsigned char *save_p;
259
3.08k
  char *buffer, *d;
260
261
  /* First count length. */
262
27.2k
  for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ )
263
24.1k
    {
264
24.1k
      if ( *p < 0x20 || *p == 0x7f || *p == delim  || (delim && *p=='\\'))
265
5.24k
        {
266
5.24k
          if ( *p=='\n' || *p=='\r' || *p=='\f'
267
4.88k
               || *p=='\v' || *p=='\b' || !*p )
268
2.99k
            buflen += 2;
269
2.24k
          else
270
2.24k
            buflen += 5;
271
5.24k
  }
272
18.9k
      else
273
18.9k
        buflen++;
274
24.1k
    }
275
3.08k
  p = save_p;
276
3.08k
  n = save_n;
277
  /* And now make the string */
278
3.08k
  d = buffer = xtrymalloc (buflen);
279
27.2k
  for ( ; n; n--, p++ )
280
24.1k
    {
281
24.1k
      if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
282
5.24k
        *d++ = '\\';
283
5.24k
        if( *p == '\n' )
284
222
          *d++ = 'n';
285
5.02k
        else if( *p == '\r' )
286
99
          *d++ = 'r';
287
4.92k
        else if( *p == '\f' )
288
36
          *d++ = 'f';
289
4.88k
        else if( *p == '\v' )
290
270
          *d++ = 'v';
291
4.61k
        else if( *p == '\b' )
292
236
          *d++ = 'b';
293
4.37k
        else if( !*p )
294
2.13k
          *d++ = '0';
295
2.24k
        else {
296
2.24k
          sprintf(d, "x%02x", *p );
297
2.24k
          d += 3;
298
2.24k
        }
299
5.24k
      }
300
18.9k
      else
301
18.9k
        *d++ = *p;
302
24.1k
    }
303
3.08k
  *d = 0;
304
3.08k
  return buffer;
305
3.08k
}
306
307
308
/* Same as try_make_printable_string but terminates the process on
309
 * memory shortage.  */
310
char *
311
make_printable_string (const void *p, size_t n, int delim )
312
0
{
313
0
  char *string = try_make_printable_string (p, n, delim);
314
0
  if (!string)
315
0
    xoutofcore ();
316
0
  return string;
317
0
}
318
319
320
/* Decode the C formatted string SRC and return the result in a newly
321
 * allocated buffer.  In error returns NULL and sets ERRNO. */
322
char *
323
decode_c_string (const char *src)
324
0
{
325
0
  char *buffer, *dst;
326
0
  int val;
327
328
  /* The converted string will never be larger than the original
329
     string.  */
330
0
  buffer = dst = xtrymalloc (strlen (src) + 1);
331
0
  if (!buffer)
332
0
    return NULL;
333
334
0
  while (*src)
335
0
    {
336
0
      if (*src != '\\')
337
0
  {
338
0
    *dst++ = *src++;
339
0
    continue;
340
0
  }
341
342
0
#define DECODE_ONE(_m,_r) case _m: src += 2; *dst++ = _r; break;
343
344
0
      switch (src[1])
345
0
  {
346
0
    DECODE_ONE ('n', '\n');
347
0
    DECODE_ONE ('r', '\r');
348
0
    DECODE_ONE ('f', '\f');
349
0
    DECODE_ONE ('v', '\v');
350
0
    DECODE_ONE ('b', '\b');
351
0
    DECODE_ONE ('t', '\t');
352
0
    DECODE_ONE ('\\', '\\');
353
0
    DECODE_ONE ('\'', '\'');
354
0
    DECODE_ONE ('\"', '\"');
355
356
0
  case 'x':
357
0
          val = hextobyte (src+2);
358
0
          if (val == -1)  /* Bad coding, keep as is. */
359
0
            {
360
0
              *dst++ = *src++;
361
0
              *dst++ = *src++;
362
0
              if (*src)
363
0
                *dst++ = *src++;
364
0
              if (*src)
365
0
                *dst++ = *src++;
366
0
            }
367
0
          else if (!val)
368
0
            {
369
              /* A binary zero is not representable in a C string thus
370
               * we keep the C-escaping.  Note that this will also
371
               * never be larger than the source string.  */
372
0
              *dst++ = '\\';
373
0
              *dst++ = '0';
374
0
              src += 4;
375
0
            }
376
0
          else
377
0
            {
378
0
              *(unsigned char *)dst++ = val;
379
0
              src += 4;
380
0
            }
381
0
    break;
382
383
0
  default: /* Bad coding; keep as is..  */
384
0
          *dst++ = *src++;
385
0
          *dst++ = *src++;
386
0
          break;
387
0
        }
388
0
#undef DECODE_ONE
389
0
    }
390
0
  *dst++ = 0;
391
392
0
  return buffer;
393
0
}
394
395
396
/* Try match against each substring of multistr, delimited by | */
397
int
398
match_multistr (const char *multistr,const char *match)
399
0
{
400
0
  do
401
0
    {
402
0
      size_t seglen = strcspn (multistr,"|");
403
0
      if (!seglen)
404
0
  break;
405
      /* Using the localized strncasecmp! */
406
0
      if (strncasecmp(multistr,match,seglen)==0)
407
0
  return 1;
408
0
      multistr += seglen;
409
0
      if (*multistr == '|')
410
0
  multistr++;
411
0
    }
412
0
  while (*multistr);
413
414
0
  return 0;
415
0
}
416
417
418

419
/* Parse the first portion of the version number S and store it at
420
   NUMBER.  On success, the function returns a pointer into S starting
421
   with the first character, which is not part of the initial number
422
   portion; on failure, NULL is returned.  */
423
static const char*
424
parse_version_number (const char *s, int *number)
425
0
{
426
0
  int val = 0;
427
428
0
  if (*s == '0' && digitp (s+1))
429
0
    return NULL; /* Leading zeros are not allowed.  */
430
0
  for (; digitp (s); s++ )
431
0
    {
432
0
      val *= 10;
433
0
      val += *s - '0';
434
0
    }
435
0
  *number = val;
436
0
  return val < 0? NULL : s;
437
0
}
438
439
/* Break up the complete string representation of the version number S,
440
   which is expected to have this format:
441
442
      <major number>.<minor number>.<micro number><patch level>.
443
444
   The major, minor and micro number components will be stored at
445
   MAJOR, MINOR and MICRO. On success, a pointer to the last
446
   component, the patch level, will be returned; on failure, NULL will
447
   be returned.  */
448
static const char *
449
parse_version_string (const char *s, int *major, int *minor, int *micro)
450
0
{
451
0
  s = parse_version_number (s, major);
452
0
  if (!s || *s != '.')
453
0
    return NULL;
454
0
  s++;
455
0
  s = parse_version_number (s, minor);
456
0
  if (!s || *s != '.')
457
0
    return NULL;
458
0
  s++;
459
0
  s = parse_version_number (s, micro);
460
0
  if (!s)
461
0
    return NULL;
462
0
  return s; /* Patchlevel.  */
463
0
}
464
465
/* Return true if version string is at least version B. */
466
int
467
gnupg_compare_version (const char *a, const char *b)
468
0
{
469
0
  int a_major, a_minor, a_micro;
470
0
  int b_major, b_minor, b_micro;
471
0
  const char *a_plvl, *b_plvl;
472
473
0
  if (!a || !b)
474
0
    return 0;
475
476
  /* Parse version A.  */
477
0
  a_plvl = parse_version_string (a, &a_major, &a_minor, &a_micro);
478
0
  if (!a_plvl )
479
0
    return 0; /* Invalid version number.  */
480
481
  /* Parse version B.  */
482
0
  b_plvl = parse_version_string (b, &b_major, &b_minor, &b_micro);
483
0
  if (!b_plvl )
484
0
    return 0; /* Invalid version number.  */
485
486
  /* Compare version numbers.  */
487
0
  return (a_major > b_major
488
0
          || (a_major == b_major && a_minor > b_minor)
489
0
          || (a_major == b_major && a_minor == b_minor
490
0
              && a_micro > b_micro)
491
0
          || (a_major == b_major && a_minor == b_minor
492
0
              && a_micro == b_micro
493
0
              && strcmp (a_plvl, b_plvl) >= 0));
494
0
}
495
496
497

498
/* Parse an --debug style argument.  We allow the use of number values
499
 * in the usual C notation or a string with comma separated keywords.
500
 *
501
 * Returns: 0 on success or -1 and ERRNO set on error.  On success the
502
 *          supplied variable is updated by the parsed flags.
503
 *
504
 * If STRING is NULL the enabled debug flags are printed.
505
 *
506
 * See doc/DETAILS for a summary of used debug options.
507
 */
508
int
509
parse_debug_flag (const char *string, unsigned int *debugvar,
510
                  const struct debug_flags_s *flags)
511
512
0
{
513
0
  unsigned long result = 0;
514
0
  int i, j;
515
516
0
  if (!string)
517
0
    {
518
0
      if (debugvar)
519
0
        {
520
0
          log_info ("enabled debug flags:");
521
0
          for (i=0; flags[i].name; i++)
522
0
            if ((*debugvar & flags[i].flag))
523
0
              log_printf (" %s", flags[i].name);
524
0
          log_printf ("\n");
525
0
        }
526
0
      return 0;
527
0
    }
528
529
0
  while (spacep (string))
530
0
    string++;
531
0
  if (*string == '-')
532
0
    {
533
0
      errno = EINVAL;
534
0
      return -1;
535
0
    }
536
537
0
  if (!strcmp (string, "?") || !strcmp (string, "help"))
538
0
    {
539
0
      log_info ("available debug flags:\n");
540
0
      for (i=0; flags[i].name; i++)
541
0
        log_info (" %5u %s\n", flags[i].flag, flags[i].name);
542
0
      if (flags[i].flag != 77)
543
0
        exit (0);
544
0
    }
545
0
  else if (digitp (string))
546
0
    {
547
0
      errno = 0;
548
0
      result = strtoul (string, NULL, 0);
549
0
      if (result == ULONG_MAX && errno == ERANGE)
550
0
        return -1;
551
0
    }
552
0
  else
553
0
    {
554
0
      char **words;
555
0
      words = strtokenize (string, ",");
556
0
      if (!words)
557
0
        return -1;
558
0
      for (i=0; words[i]; i++)
559
0
        {
560
0
          if (*words[i])
561
0
            {
562
0
              for (j=0; flags[j].name; j++)
563
0
                if (!strcmp (words[i], flags[j].name))
564
0
                  {
565
0
                    result |= flags[j].flag;
566
0
                    break;
567
0
                  }
568
0
              if (!flags[j].name)
569
0
                {
570
0
                  if (!strcmp (words[i], "none"))
571
0
                    {
572
0
                      *debugvar = 0;
573
0
                      result = 0;
574
0
                    }
575
0
                  else if (!strcmp (words[i], "all"))
576
0
                    result = ~0;
577
0
                  else
578
0
                    log_info (_("unknown debug flag '%s' ignored\n"), words[i]);
579
0
                }
580
0
            }
581
0
        }
582
0
      xfree (words);
583
0
    }
584
585
0
  *debugvar |= result;
586
0
  return 0;
587
0
}
588
589
590

591
/* Parse an --comaptibility_flags style argument consisting of comma
592
 * separated strings.
593
 *
594
 * Returns: 0 on success or -1 and ERRNO set on error.  On success the
595
 *          supplied variable is updated by the parsed flags.
596
 *
597
 * If STRING is NULL the enabled flags are printed.
598
 */
599
int
600
parse_compatibility_flags (const char *string, unsigned int *flagvar,
601
                           const struct compatibility_flags_s *flags)
602
603
0
{
604
0
  unsigned long result = 0;
605
0
  int i, j;
606
607
0
  if (!string)
608
0
    {
609
0
      if (flagvar)
610
0
        {
611
0
          log_info ("enabled compatibility flags:");
612
0
          for (i=0; flags[i].name; i++)
613
0
            if ((*flagvar & flags[i].flag))
614
0
              log_printf (" %s", flags[i].name);
615
0
          log_printf ("\n");
616
0
        }
617
0
      return 0;
618
0
    }
619
620
0
  while (spacep (string))
621
0
    string++;
622
623
0
  if (!strcmp (string, "?") || !strcmp (string, "help"))
624
0
    {
625
0
      log_info ("available compatibility flags:\n");
626
0
      for (i=0; flags[i].name; i++)
627
0
        log_info (" %s\n", flags[i].name);
628
0
      if (flags[i].flag != 77)
629
0
        exit (0);
630
0
    }
631
0
  else
632
0
    {
633
0
      char **words;
634
0
      words = strtokenize (string, ",");
635
0
      if (!words)
636
0
        return -1;
637
0
      for (i=0; words[i]; i++)
638
0
        {
639
0
          if (*words[i])
640
0
            {
641
0
              for (j=0; flags[j].name; j++)
642
0
                if (!strcmp (words[i], flags[j].name))
643
0
                  {
644
0
                    result |= flags[j].flag;
645
0
                    break;
646
0
                  }
647
0
              if (!flags[j].name)
648
0
                {
649
0
                  if (!strcmp (words[i], "none"))
650
0
                    {
651
0
                      *flagvar = 0;
652
0
                      result = 0;
653
0
                    }
654
0
                  else if (!strcmp (words[i], "all"))
655
0
                    result = ~0;
656
0
                  else
657
0
                    log_info ("unknown compatibility flag '%s' ignored\n",
658
0
                              words[i]);
659
0
                }
660
0
            }
661
0
        }
662
0
      xfree (words);
663
0
    }
664
665
0
  *flagvar |= result;
666
0
  return 0;
667
0
}
668
669
670
/* Convert STRING consisting of base64 characters into its binary
671
 * representation and store the result in a newly allocated buffer at
672
 * R_BUFFER with its length at R_BUFLEN.  If TITLE is NULL a plain
673
 * base64 decoding is done.  If it is the empty string the decoder
674
 * will skip everything until a "-----BEGIN " line has been seen,
675
 * decoding then ends at a "----END " line.  On failure the function
676
 * returns an error code and sets R_BUFFER to NULL.  If the decoded
677
 * data has a length of 0 a dummy buffer will still be allocated and
678
 * the length is set to 0. */
679
gpg_error_t
680
b64decode (const char *string, const char *title,
681
           void **r_buffer, size_t *r_buflen)
682
0
{
683
0
  gpg_error_t err;
684
0
  gpgrt_b64state_t state;
685
0
  size_t nbytes;
686
0
  char *buffer;
687
688
0
  *r_buffer = NULL;
689
0
  *r_buflen = 0;
690
691
0
  buffer = xtrystrdup (string);
692
0
  if (!buffer)
693
0
    return gpg_error_from_syserror();
694
695
0
  state = gpgrt_b64dec_start (title);
696
0
  if (!state)
697
0
    {
698
0
      err = gpg_error_from_syserror ();
699
0
      xfree (buffer);
700
0
      return err;
701
0
    }
702
0
  err = gpgrt_b64dec_proc (state, buffer, strlen (buffer), &nbytes);
703
0
  if (!err)
704
0
    {
705
0
      err = gpgrt_b64dec_finish (state);
706
0
      state = NULL;
707
0
    }
708
0
  if (err)
709
0
    xfree (buffer);
710
0
  else
711
0
    {
712
0
      *r_buffer = buffer;
713
0
      *r_buflen = nbytes;
714
0
    }
715
0
  gpgrt_b64dec_finish (state);  /* Make sure it is released.  */
716
0
  return err;
717
0
}