Coverage Report

Created: 2026-07-16 06:11

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
/* Return a string for the cipher MODE.  For unknown modes "?" is
128
 * returned.  */
129
const char *
130
gnupg_cipher_mode_name (int mode)
131
979
{
132
979
  switch (mode)
133
979
    {
134
0
    case GCRY_CIPHER_MODE_CBC: return "CBC";
135
0
    case GCRY_CIPHER_MODE_GCM: return "GCM";
136
93
    case GCRY_CIPHER_MODE_OCB: return "OCB";
137
886
    case GCRY_CIPHER_MODE_EAX: return "EAX";
138
0
    default: return "?";
139
979
    }
140
979
}
141
142
143
void
144
obsolete_option (const char *configname, unsigned int configlineno,
145
                 const char *name)
146
0
{
147
0
  if (configname)
148
0
    log_info (_("%s:%u: obsolete option \"%s\" - it has no effect\n"),
149
0
              configname, configlineno, name);
150
0
  else
151
0
    log_info (_("WARNING: \"%s%s\" is an obsolete option - it has no effect\n"),
152
0
              "--", name);
153
0
}
154
155
156
/* Decide whether the filename is stdout or a real filename and return
157
 * an appropriate string.  */
158
const char *
159
print_fname_stdout (const char *s)
160
0
{
161
0
    if( !s || (*s == '-' && !s[1]) )
162
0
  return "[stdout]";
163
0
    return s;
164
0
}
165
166
167
/* Decide whether the filename is stdin or a real filename and return
168
 * an appropriate string.  */
169
const char *
170
print_fname_stdin (const char *s)
171
0
{
172
0
    if( !s || (*s == '-' && !s[1]) )
173
0
  return "[stdin]";
174
0
    return s;
175
0
}
176
177
178
static int
179
do_print_utf8_buffer (estream_t stream,
180
                      const void *buffer, size_t length,
181
                      const char *delimiters, size_t *bytes_written)
182
36.3k
{
183
36.3k
  const char *p = buffer;
184
36.3k
  size_t i;
185
186
  /* We can handle plain ascii simpler, so check for it first. */
187
181k
  for (i=0; i < length; i++ )
188
147k
    {
189
147k
      if ( (p[i] & 0x80) )
190
2.57k
        break;
191
147k
    }
192
36.3k
  if (i < length)
193
2.57k
    {
194
2.57k
      int delim = delimiters? *delimiters : 0;
195
2.57k
      char *buf;
196
2.57k
      int ret;
197
198
      /*(utf8 conversion already does the control character quoting). */
199
2.57k
      buf = utf8_to_native (p, length, delim);
200
2.57k
      if (bytes_written)
201
0
        *bytes_written = strlen (buf);
202
2.57k
      ret = es_fputs (buf, stream);
203
2.57k
      xfree (buf);
204
2.57k
      return ret == EOF? ret : (int)i;
205
2.57k
    }
206
33.7k
  else
207
33.7k
    return es_write_sanitized (stream, p, length, delimiters, bytes_written);
208
36.3k
}
209
210
211
void
212
print_utf8_buffer3 (estream_t stream, const void *p, size_t n,
213
                    const char *delim)
214
0
{
215
0
  do_print_utf8_buffer (stream, p, n, delim, NULL);
216
0
}
217
218
219
void
220
print_utf8_buffer2 (estream_t stream, const void *p, size_t n, int delim)
221
0
{
222
0
  char tmp[2];
223
224
0
  tmp[0] = delim;
225
0
  tmp[1] = 0;
226
0
  do_print_utf8_buffer (stream, p, n, tmp, NULL);
227
0
}
228
229
230
void
231
print_utf8_buffer (estream_t stream, const void *p, size_t n)
232
36.3k
{
233
36.3k
  do_print_utf8_buffer (stream, p, n, NULL, NULL);
234
36.3k
}
235
236
237
void
238
print_utf8_string (estream_t stream, const char *p)
239
0
{
240
0
  if (!p)
241
0
    p = "";
242
0
  do_print_utf8_buffer (stream, p, strlen (p), NULL, NULL);
243
0
}
244
245
246
/* Write LENGTH bytes of BUFFER to FP as a hex encoded string.
247
   RESERVED must be 0. */
248
void
249
print_hexstring (FILE *fp, const void *buffer, size_t length, int reserved)
250
0
{
251
0
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
252
0
  const unsigned char *s;
253
254
0
  (void)reserved;
255
256
0
  for (s = buffer; length; s++, length--)
257
0
    {
258
0
      putc ( tohex ((*s>>4)&15), fp);
259
0
      putc ( tohex (*s&15), fp);
260
0
    }
261
0
#undef tohex
262
0
}
263
264
265
/* Create a string from the buffer P_ARG of length N which is suitable
266
 * for printing.  Caller must release the created string using xfree.
267
 * On error ERRNO is set and NULL returned.  Errors are only possible
268
 * due to malloc failure.  */
269
char *
270
try_make_printable_string (const void *p_arg, size_t n, int delim)
271
4.66k
{
272
4.66k
  const unsigned char *p = p_arg;
273
4.66k
  size_t save_n, buflen;
274
4.66k
  const unsigned char *save_p;
275
4.66k
  char *buffer, *d;
276
277
  /* First count length. */
278
33.8k
  for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ )
279
29.2k
    {
280
29.2k
      if ( *p < 0x20 || *p == 0x7f || *p == delim  || (delim && *p=='\\'))
281
6.57k
        {
282
6.57k
          if ( *p=='\n' || *p=='\r' || *p=='\f'
283
6.25k
               || *p=='\v' || *p=='\b' || !*p )
284
4.15k
            buflen += 2;
285
2.42k
          else
286
2.42k
            buflen += 5;
287
6.57k
  }
288
22.6k
      else
289
22.6k
        buflen++;
290
29.2k
    }
291
4.66k
  p = save_p;
292
4.66k
  n = save_n;
293
  /* And now make the string */
294
4.66k
  d = buffer = xtrymalloc (buflen);
295
33.8k
  for ( ; n; n--, p++ )
296
29.2k
    {
297
29.2k
      if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
298
6.57k
        *d++ = '\\';
299
6.57k
        if( *p == '\n' )
300
200
          *d++ = 'n';
301
6.37k
        else if( *p == '\r' )
302
61
          *d++ = 'r';
303
6.31k
        else if( *p == '\f' )
304
62
          *d++ = 'f';
305
6.25k
        else if( *p == '\v' )
306
160
          *d++ = 'v';
307
6.09k
        else if( *p == '\b' )
308
866
          *d++ = 'b';
309
5.22k
        else if( !*p )
310
2.80k
          *d++ = '0';
311
2.42k
        else {
312
2.42k
          sprintf(d, "x%02x", *p );
313
2.42k
          d += 3;
314
2.42k
        }
315
6.57k
      }
316
22.6k
      else
317
22.6k
        *d++ = *p;
318
29.2k
    }
319
4.66k
  *d = 0;
320
4.66k
  return buffer;
321
4.66k
}
322
323
324
/* Same as try_make_printable_string but terminates the process on
325
 * memory shortage.  */
326
char *
327
make_printable_string (const void *p, size_t n, int delim )
328
0
{
329
0
  char *string = try_make_printable_string (p, n, delim);
330
0
  if (!string)
331
0
    xoutofcore ();
332
0
  return string;
333
0
}
334
335
336
/* Decode the C formatted string SRC and return the result in a newly
337
 * allocated buffer.  In error returns NULL and sets ERRNO. */
338
char *
339
decode_c_string (const char *src)
340
0
{
341
0
  char *buffer, *dst;
342
0
  int val;
343
344
  /* The converted string will never be larger than the original
345
     string.  */
346
0
  buffer = dst = xtrymalloc (strlen (src) + 1);
347
0
  if (!buffer)
348
0
    return NULL;
349
350
0
  while (*src)
351
0
    {
352
0
      if (*src != '\\')
353
0
  {
354
0
    *dst++ = *src++;
355
0
    continue;
356
0
  }
357
358
0
#define DECODE_ONE(_m,_r) case _m: src += 2; *dst++ = _r; break;
359
360
0
      switch (src[1])
361
0
  {
362
0
    DECODE_ONE ('n', '\n');
363
0
    DECODE_ONE ('r', '\r');
364
0
    DECODE_ONE ('f', '\f');
365
0
    DECODE_ONE ('v', '\v');
366
0
    DECODE_ONE ('b', '\b');
367
0
    DECODE_ONE ('t', '\t');
368
0
    DECODE_ONE ('\\', '\\');
369
0
    DECODE_ONE ('\'', '\'');
370
0
    DECODE_ONE ('\"', '\"');
371
372
0
  case 'x':
373
0
          val = hextobyte (src+2);
374
0
          if (val == -1)  /* Bad coding, keep as is. */
375
0
            {
376
0
              *dst++ = *src++;
377
0
              *dst++ = *src++;
378
0
              if (*src)
379
0
                *dst++ = *src++;
380
0
              if (*src)
381
0
                *dst++ = *src++;
382
0
            }
383
0
          else if (!val)
384
0
            {
385
              /* A binary zero is not representable in a C string thus
386
               * we keep the C-escaping.  Note that this will also
387
               * never be larger than the source string.  */
388
0
              *dst++ = '\\';
389
0
              *dst++ = '0';
390
0
              src += 4;
391
0
            }
392
0
          else
393
0
            {
394
0
              *(unsigned char *)dst++ = val;
395
0
              src += 4;
396
0
            }
397
0
    break;
398
399
0
  default: /* Bad coding; keep as is..  */
400
0
          *dst++ = *src++;
401
0
          *dst++ = *src++;
402
0
          break;
403
0
        }
404
0
#undef DECODE_ONE
405
0
    }
406
0
  *dst++ = 0;
407
408
0
  return buffer;
409
0
}
410
411
412
/* Try match against each substring of multistr, delimited by | */
413
int
414
match_multistr (const char *multistr,const char *match)
415
0
{
416
0
  do
417
0
    {
418
0
      size_t seglen = strcspn (multistr,"|");
419
0
      if (!seglen)
420
0
  break;
421
      /* Using the localized strncasecmp! */
422
0
      if (strncasecmp(multistr,match,seglen)==0)
423
0
  return 1;
424
0
      multistr += seglen;
425
0
      if (*multistr == '|')
426
0
  multistr++;
427
0
    }
428
0
  while (*multistr);
429
430
0
  return 0;
431
0
}
432
433
434

435
/* Parse the first portion of the version number S and store it at
436
   NUMBER.  On success, the function returns a pointer into S starting
437
   with the first character, which is not part of the initial number
438
   portion; on failure, NULL is returned.  */
439
static const char*
440
parse_version_number (const char *s, int *number)
441
0
{
442
0
  int val = 0;
443
444
0
  if (*s == '0' && digitp (s+1))
445
0
    return NULL; /* Leading zeros are not allowed.  */
446
0
  for (; digitp (s); s++ )
447
0
    {
448
0
      val *= 10;
449
0
      val += *s - '0';
450
0
    }
451
0
  *number = val;
452
0
  return val < 0? NULL : s;
453
0
}
454
455
/* Break up the complete string representation of the version number S,
456
   which is expected to have this format:
457
458
      <major number>.<minor number>.<micro number><patch level>.
459
460
   The major, minor and micro number components will be stored at
461
   MAJOR, MINOR and MICRO. On success, a pointer to the last
462
   component, the patch level, will be returned; on failure, NULL will
463
   be returned.  */
464
static const char *
465
parse_version_string (const char *s, int *major, int *minor, int *micro)
466
0
{
467
0
  s = parse_version_number (s, major);
468
0
  if (!s || *s != '.')
469
0
    return NULL;
470
0
  s++;
471
0
  s = parse_version_number (s, minor);
472
0
  if (!s || *s != '.')
473
0
    return NULL;
474
0
  s++;
475
0
  s = parse_version_number (s, micro);
476
0
  if (!s)
477
0
    return NULL;
478
0
  return s; /* Patchlevel.  */
479
0
}
480
481
/* Return true if version string is at least version B. */
482
int
483
gnupg_compare_version (const char *a, const char *b)
484
0
{
485
0
  int a_major, a_minor, a_micro;
486
0
  int b_major, b_minor, b_micro;
487
0
  const char *a_plvl, *b_plvl;
488
489
0
  if (!a || !b)
490
0
    return 0;
491
492
  /* Parse version A.  */
493
0
  a_plvl = parse_version_string (a, &a_major, &a_minor, &a_micro);
494
0
  if (!a_plvl )
495
0
    return 0; /* Invalid version number.  */
496
497
  /* Parse version B.  */
498
0
  b_plvl = parse_version_string (b, &b_major, &b_minor, &b_micro);
499
0
  if (!b_plvl )
500
0
    return 0; /* Invalid version number.  */
501
502
  /* Compare version numbers.  */
503
0
  return (a_major > b_major
504
0
          || (a_major == b_major && a_minor > b_minor)
505
0
          || (a_major == b_major && a_minor == b_minor
506
0
              && a_micro > b_micro)
507
0
          || (a_major == b_major && a_minor == b_minor
508
0
              && a_micro == b_micro
509
0
              && strcmp (a_plvl, b_plvl) >= 0));
510
0
}
511
512
513

514
/* Parse an --debug style argument.  We allow the use of number values
515
 * in the usual C notation or a string with comma separated keywords.
516
 *
517
 * Returns: 0 on success or -1 and ERRNO set on error.  On success the
518
 *          supplied variable is updated by the parsed flags.
519
 *
520
 * If STRING is NULL the enabled debug flags are printed.
521
 *
522
 * See doc/DETAILS for a summary of used debug options.
523
 */
524
int
525
parse_debug_flag (const char *string, unsigned int *debugvar,
526
                  const struct debug_flags_s *flags)
527
528
0
{
529
0
  unsigned long result = 0;
530
0
  int i, j;
531
532
0
  if (!string)
533
0
    {
534
0
      if (debugvar)
535
0
        {
536
0
          log_info ("enabled debug flags:");
537
0
          for (i=0; flags[i].name; i++)
538
0
            if ((*debugvar & flags[i].flag))
539
0
              log_printf (" %s", flags[i].name);
540
0
          log_printf ("\n");
541
0
        }
542
0
      return 0;
543
0
    }
544
545
0
  while (spacep (string))
546
0
    string++;
547
0
  if (*string == '-')
548
0
    {
549
0
      errno = EINVAL;
550
0
      return -1;
551
0
    }
552
553
0
  if (!strcmp (string, "?") || !strcmp (string, "help"))
554
0
    {
555
0
      log_info ("available debug flags:\n");
556
0
      for (i=0; flags[i].name; i++)
557
0
        log_info (" %5u %s\n", flags[i].flag, flags[i].name);
558
0
      if (flags[i].flag != 77)
559
0
        exit (0);
560
0
    }
561
0
  else if (digitp (string))
562
0
    {
563
0
      errno = 0;
564
0
      result = strtoul (string, NULL, 0);
565
0
      if (result == ULONG_MAX && errno == ERANGE)
566
0
        return -1;
567
0
    }
568
0
  else
569
0
    {
570
0
      char **words;
571
0
      words = strtokenize (string, ",");
572
0
      if (!words)
573
0
        return -1;
574
0
      for (i=0; words[i]; i++)
575
0
        {
576
0
          if (*words[i])
577
0
            {
578
0
              for (j=0; flags[j].name; j++)
579
0
                if (!strcmp (words[i], flags[j].name))
580
0
                  {
581
0
                    result |= flags[j].flag;
582
0
                    break;
583
0
                  }
584
0
              if (!flags[j].name)
585
0
                {
586
0
                  if (!strcmp (words[i], "none"))
587
0
                    {
588
0
                      *debugvar = 0;
589
0
                      result = 0;
590
0
                    }
591
0
                  else if (!strcmp (words[i], "all"))
592
0
                    result = ~0;
593
0
                  else
594
0
                    log_info (_("unknown debug flag '%s' ignored\n"), words[i]);
595
0
                }
596
0
            }
597
0
        }
598
0
      xfree (words);
599
0
    }
600
601
0
  *debugvar |= result;
602
0
  return 0;
603
0
}
604
605
606

607
/* Parse an --comaptibility_flags style argument consisting of comma
608
 * separated strings.
609
 *
610
 * Returns: 0 on success or -1 and ERRNO set on error.  On success the
611
 *          supplied variable is updated by the parsed flags.
612
 *
613
 * If STRING is NULL the enabled flags are printed.
614
 */
615
int
616
parse_compatibility_flags (const char *string, unsigned int *flagvar,
617
                           const struct compatibility_flags_s *flags)
618
619
0
{
620
0
  unsigned long result = 0;
621
0
  int i, j;
622
623
0
  if (!string)
624
0
    {
625
0
      if (flagvar)
626
0
        {
627
0
          log_info ("enabled compatibility flags:");
628
0
          for (i=0; flags[i].name; i++)
629
0
            if ((*flagvar & flags[i].flag))
630
0
              log_printf (" %s", flags[i].name);
631
0
          log_printf ("\n");
632
0
        }
633
0
      return 0;
634
0
    }
635
636
0
  while (spacep (string))
637
0
    string++;
638
639
0
  if (!strcmp (string, "?") || !strcmp (string, "help"))
640
0
    {
641
0
      log_info ("available compatibility flags:\n");
642
0
      for (i=0; flags[i].name; i++)
643
0
        log_info (" %s\n", flags[i].name);
644
0
      if (flags[i].flag != 77)
645
0
        exit (0);
646
0
    }
647
0
  else
648
0
    {
649
0
      char **words;
650
0
      words = strtokenize (string, ",");
651
0
      if (!words)
652
0
        return -1;
653
0
      for (i=0; words[i]; i++)
654
0
        {
655
0
          if (*words[i])
656
0
            {
657
0
              for (j=0; flags[j].name; j++)
658
0
                if (!strcmp (words[i], flags[j].name))
659
0
                  {
660
0
                    result |= flags[j].flag;
661
0
                    break;
662
0
                  }
663
0
              if (!flags[j].name)
664
0
                {
665
0
                  if (!strcmp (words[i], "none"))
666
0
                    {
667
0
                      *flagvar = 0;
668
0
                      result = 0;
669
0
                    }
670
0
                  else if (!strcmp (words[i], "all"))
671
0
                    result = ~0;
672
0
                  else
673
0
                    log_info ("unknown compatibility flag '%s' ignored\n",
674
0
                              words[i]);
675
0
                }
676
0
            }
677
0
        }
678
0
      xfree (words);
679
0
    }
680
681
0
  *flagvar |= result;
682
0
  return 0;
683
0
}
684
685
686
/* Convert STRING consisting of base64 characters into its binary
687
 * representation and store the result in a newly allocated buffer at
688
 * R_BUFFER with its length at R_BUFLEN.  If TITLE is NULL a plain
689
 * base64 decoding is done.  If it is the empty string the decoder
690
 * will skip everything until a "-----BEGIN " line has been seen,
691
 * decoding then ends at a "----END " line.  On failure the function
692
 * returns an error code and sets R_BUFFER to NULL.  If the decoded
693
 * data has a length of 0 a dummy buffer will still be allocated and
694
 * the length is set to 0. */
695
gpg_error_t
696
b64decode (const char *string, const char *title,
697
           void **r_buffer, size_t *r_buflen)
698
0
{
699
0
  gpg_error_t err;
700
0
  gpgrt_b64state_t state;
701
0
  size_t nbytes;
702
0
  char *buffer;
703
704
0
  *r_buffer = NULL;
705
0
  *r_buflen = 0;
706
707
0
  buffer = xtrystrdup (string);
708
0
  if (!buffer)
709
0
    return gpg_error_from_syserror();
710
711
0
  state = gpgrt_b64dec_start (title);
712
0
  if (!state)
713
0
    {
714
0
      err = gpg_error_from_syserror ();
715
0
      xfree (buffer);
716
0
      return err;
717
0
    }
718
0
  err = gpgrt_b64dec_proc (state, buffer, strlen (buffer), &nbytes);
719
0
  if (!err)
720
0
    {
721
0
      err = gpgrt_b64dec_finish (state);
722
0
      state = NULL;
723
0
    }
724
0
  if (err)
725
0
    xfree (buffer);
726
0
  else
727
0
    {
728
0
      *r_buffer = buffer;
729
0
      *r_buflen = nbytes;
730
0
    }
731
0
  gpgrt_b64dec_finish (state);  /* Make sure it is released.  */
732
0
  return err;
733
0
}