Coverage Report

Created: 2026-05-30 06:22

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
2.06k
{
132
2.06k
  switch (mode)
133
2.06k
    {
134
0
    case GCRY_CIPHER_MODE_CBC: return "CBC";
135
0
    case GCRY_CIPHER_MODE_GCM: return "GCM";
136
25
    case GCRY_CIPHER_MODE_OCB: return "OCB";
137
2.04k
    case GCRY_CIPHER_MODE_EAX: return "EAX";
138
0
    default: return "?";
139
2.06k
    }
140
2.06k
}
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
13.0k
{
183
13.0k
  const char *p = buffer;
184
13.0k
  size_t i;
185
186
  /* We can handle plain ascii simpler, so check for it first. */
187
123k
  for (i=0; i < length; i++ )
188
112k
    {
189
112k
      if ( (p[i] & 0x80) )
190
1.27k
        break;
191
112k
    }
192
13.0k
  if (i < length)
193
1.27k
    {
194
1.27k
      int delim = delimiters? *delimiters : 0;
195
1.27k
      char *buf;
196
1.27k
      int ret;
197
198
      /*(utf8 conversion already does the control character quoting). */
199
1.27k
      buf = utf8_to_native (p, length, delim);
200
1.27k
      if (bytes_written)
201
0
        *bytes_written = strlen (buf);
202
1.27k
      ret = es_fputs (buf, stream);
203
1.27k
      xfree (buf);
204
1.27k
      return ret == EOF? ret : (int)i;
205
1.27k
    }
206
11.7k
  else
207
11.7k
    return es_write_sanitized (stream, p, length, delimiters, bytes_written);
208
13.0k
}
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
13.0k
{
233
13.0k
  do_print_utf8_buffer (stream, p, n, NULL, NULL);
234
13.0k
}
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
5.25k
{
272
5.25k
  const unsigned char *p = p_arg;
273
5.25k
  size_t save_n, buflen;
274
5.25k
  const unsigned char *save_p;
275
5.25k
  char *buffer, *d;
276
277
  /* First count length. */
278
33.1k
  for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ )
279
27.8k
    {
280
27.8k
      if ( *p < 0x20 || *p == 0x7f || *p == delim  || (delim && *p=='\\'))
281
7.42k
        {
282
7.42k
          if ( *p=='\n' || *p=='\r' || *p=='\f'
283
7.18k
               || *p=='\v' || *p=='\b' || !*p )
284
4.25k
            buflen += 2;
285
3.16k
          else
286
3.16k
            buflen += 5;
287
7.42k
  }
288
20.4k
      else
289
20.4k
        buflen++;
290
27.8k
    }
291
5.25k
  p = save_p;
292
5.25k
  n = save_n;
293
  /* And now make the string */
294
5.25k
  d = buffer = xtrymalloc (buflen);
295
33.1k
  for ( ; n; n--, p++ )
296
27.8k
    {
297
27.8k
      if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
298
7.42k
        *d++ = '\\';
299
7.42k
        if( *p == '\n' )
300
161
          *d++ = 'n';
301
7.26k
        else if( *p == '\r' )
302
57
          *d++ = 'r';
303
7.20k
        else if( *p == '\f' )
304
17
          *d++ = 'f';
305
7.18k
        else if( *p == '\v' )
306
120
          *d++ = 'v';
307
7.06k
        else if( *p == '\b' )
308
439
          *d++ = 'b';
309
6.63k
        else if( !*p )
310
3.46k
          *d++ = '0';
311
3.16k
        else {
312
3.16k
          sprintf(d, "x%02x", *p );
313
3.16k
          d += 3;
314
3.16k
        }
315
7.42k
      }
316
20.4k
      else
317
20.4k
        *d++ = *p;
318
27.8k
    }
319
5.25k
  *d = 0;
320
5.25k
  return buffer;
321
5.25k
}
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
}