Coverage Report

Created: 2022-12-08 06:10

/src/libgpg-error/src/init.c
Line
Count
Source (jump to first uncovered line)
1
/* init.c - Initialize the GnuPG error library.
2
   Copyright (C) 2005, 2010 g10 Code GmbH
3
4
   This file is part of libgpg-error.
5
6
   libgpg-error is free software; you can redistribute it and/or
7
   modify it under the terms of the GNU Lesser General Public License
8
   as published by the Free Software Foundation; either version 2.1 of
9
   the License, or (at your option) any later version.
10
11
   libgpg-error is distributed in the hope that it will be useful, but
12
   WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
   Lesser General Public License for more details.
15
16
   You should have received a copy of the GNU Lesser General Public
17
   License along with this program; if not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
#if HAVE_CONFIG_H
21
#include <config.h>
22
#endif
23
24
#include <stdlib.h>
25
#include <stdio.h>
26
#include <string.h>
27
#include <errno.h>
28
29
#include "gpgrt-int.h"
30
#include "gettext.h"
31
#include "init.h"
32
33

34
/* Locale directory support.  */
35
36
#if HAVE_W32_SYSTEM
37
38
#include <windows.h>
39
40
static int tls_index = TLS_OUT_OF_INDEXES;  /* Index for the TLS functions.  */
41
42
static char *get_locale_dir (void);
43
static void drop_locale_dir (char *locale_dir);
44
45
#else /*!HAVE_W32_SYSTEM*/
46
47
8
#define get_locale_dir() LOCALEDIR
48
#define drop_locale_dir(dir)
49
50
#endif /*!HAVE_W32_SYSTEM*/
51
52
53
/* The list of emergency cleanup functions; see _gpgrt_abort and
54
 * _gpgrt_add_emergency_cleanup.  */
55
struct emergency_cleanup_item_s;
56
typedef struct emergency_cleanup_item_s *emergency_cleanup_item_t;
57
struct emergency_cleanup_item_s
58
{
59
  emergency_cleanup_item_t next;
60
  void (*func) (void);
61
};
62
static emergency_cleanup_item_t emergency_cleanup_list;
63
64
65
66
67
/* The realloc function as set by gpgrt_set_alloc_func.  */
68
static void *(*custom_realloc)(void *a, size_t n);
69
70
71

72
static void
73
real_init (void)
74
8
{
75
8
#ifdef ENABLE_NLS
76
8
  char *locale_dir;
77
78
  /* We only have to bind our locale directory to our text domain.  */
79
8
  locale_dir = get_locale_dir ();
80
8
  if (locale_dir)
81
8
    {
82
8
      bindtextdomain (PACKAGE, locale_dir);
83
8
      drop_locale_dir (locale_dir);
84
8
    }
85
8
#endif
86
8
  _gpgrt_estream_init ();
87
8
}
88
89
/* Initialize the library.  This function should be run early.  */
90
gpg_error_t
91
_gpg_err_init (void)
92
8
{
93
#ifdef HAVE_W32_SYSTEM
94
# ifdef DLL_EXPORT
95
  /* We always have a constructor and thus this function is called
96
     automatically.  Due to the way the C init code of mingw works,
97
     the constructors are called before our DllMain function is
98
     called.  The problem with that is that the TLS has not been setup
99
     and w32-gettext.c requires TLS.  To solve this we do nothing here
100
     but call the actual init code from our DllMain.  */
101
# else /*!DLL_EXPORT*/
102
  /* Note that if the TLS is actually used, we can't release the TLS
103
     as there is no way to know when a thread terminates (i.e. no
104
     thread-specific-atexit).  You are really better off to use the
105
     DLL! */
106
  if (tls_index == TLS_OUT_OF_INDEXES)
107
    {
108
      tls_index = TlsAlloc ();
109
      if (tls_index == TLS_OUT_OF_INDEXES)
110
        {
111
          /* No way to continue - commit suicide.  */
112
          _gpgrt_abort ();
113
        }
114
      _gpg_w32__init_gettext_module ();
115
      real_init ();
116
    }
117
# endif /*!DLL_EXPORT*/
118
#else
119
8
  real_init ();
120
8
#endif
121
8
  return 0;
122
8
}
123
124
125
/* Deinitialize libgpg-error.  This function is only used in special
126
   circumstances.  No gpg-error function should be used after this
127
   function has been called.  A value of 0 passed for MODE
128
   deinitializes the entire libgpg-error, a value of 1 releases
129
   resources allocated for the current thread and only that thread may
130
   not anymore access libgpg-error after such a call.  Under Windows
131
   this function may be called from the DllMain function of a DLL
132
   which statically links to libgpg-error.  */
133
void
134
_gpg_err_deinit (int mode)
135
0
{
136
#if defined (HAVE_W32_SYSTEM) && !defined(DLL_EXPORT)
137
  struct tls_space_s *tls;
138
139
  tls = TlsGetValue (tls_index);
140
  if (tls)
141
    {
142
      TlsSetValue (tls_index, NULL);
143
      LocalFree (tls);
144
    }
145
146
  if (mode == 0)
147
    {
148
      TlsFree (tls_index);
149
      tls_index = TLS_OUT_OF_INDEXES;
150
    }
151
#else
152
0
  (void)mode;
153
0
#endif
154
0
}
155
156
157
/* Add the emergency cleanup function F to the list of those function.
158
 * If the a function with that address has already been registered, it
159
 * is not added a second time.  These emergency functions are called
160
 * whenever gpgrt_abort is called and at no other place.  Like signal
161
 * handles the emergency cleanup functions shall not call any
162
 * non-trivial functions and return as soon as possible.  They allow
163
 * to cleanup internal states which should not go into a core dumps or
164
 * similar.  This is independent of any atexit functions.  We don't
165
 * use locks here because in an emergency case we can't use them
166
 * anyway.  */
167
void
168
_gpgrt_add_emergency_cleanup (void (*f)(void))
169
0
{
170
0
  emergency_cleanup_item_t item;
171
172
0
  for (item = emergency_cleanup_list; item; item = item->next)
173
0
    if (item->func == f)
174
0
      return; /* Function has already been registered.  */
175
176
  /* We use a standard malloc here.  */
177
0
  item = malloc (sizeof *item);
178
0
  if (item)
179
0
    {
180
0
      item->func = f;
181
0
      item->next = emergency_cleanup_list;
182
0
      emergency_cleanup_list = item;
183
0
    }
184
0
  else
185
0
    _gpgrt_log_fatal ("out of core in gpgrt_add_emergency_cleanup\n");
186
0
}
187
188
189
/* Run the emergency handlers.  No locks are used because we are anyway
190
 * in an emergency state.  We also can't release any memory.  */
191
static void
192
run_emergency_cleanup (void)
193
0
{
194
0
  emergency_cleanup_item_t next;
195
0
  void (*f)(void);
196
197
0
  while (emergency_cleanup_list)
198
0
    {
199
0
      next = emergency_cleanup_list->next;
200
0
      f = emergency_cleanup_list->func;
201
0
      emergency_cleanup_list->func = NULL;
202
0
      emergency_cleanup_list = next;
203
0
      if (f)
204
0
        f ();
205
0
    }
206
0
}
207
208
209
/* Wrapper around abort to be able to run all emergency cleanup
210
 * functions.  */
211
void
212
_gpgrt_abort (void)
213
0
{
214
0
  run_emergency_cleanup ();
215
0
  abort ();
216
0
}
217
218
219
220
/* Register F as allocation function.  This function is used for all
221
   APIs which return an allocated buffer.  F needs to have standard
222
   realloc semantics.  It should be called as early as possible and
223
   not changed later. */
224
void
225
_gpgrt_set_alloc_func (void *(*f)(void *a, size_t n))
226
0
{
227
0
  custom_realloc = f;
228
0
}
229
230
231
/* The realloc to be used for data returned by the public API.  */
232
void *
233
_gpgrt_realloc (void *a, size_t n)
234
694k
{
235
694k
  if (custom_realloc)
236
0
    return custom_realloc (a, n);
237
238
694k
  if (!n)
239
346k
    {
240
346k
      free (a);
241
346k
      return NULL;
242
346k
    }
243
244
348k
  if (!a)
245
348k
    return malloc (n);
246
247
0
  return realloc (a, n);
248
348k
}
249
250
251
/* This is safe version of realloc useful for reallocing a calloced
252
 * array.  There are two ways to call it:  The first example
253
 * reallocates the array A to N elements each of SIZE but does not
254
 * clear the newly allocated elements:
255
 *
256
 *  p = gpgrt_reallocarray (a, n, n, nsize);
257
 *
258
 * Note that when NOLD is larger than N no cleaning is needed anyway.
259
 * The second example reallocates an array of size NOLD to N elements
260
 * each of SIZE but clear the newly allocated elements:
261
 *
262
 *  p = gpgrt_reallocarray (a, nold, n, nsize);
263
 *
264
 * Note that gpgrt_reallocarray (NULL, 0, n, nsize) is equivalent to
265
 * _gpgrt_calloc (n, nsize).
266
 *
267
 */
268
void *
269
_gpgrt_reallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size)
270
0
{
271
0
  size_t oldbytes, bytes;
272
0
  char *p;
273
274
0
  bytes = nmemb * size; /* size_t is unsigned so the behavior on overflow
275
                         * is defined. */
276
0
  if (size && bytes / size != nmemb)
277
0
    {
278
0
      _gpg_err_set_errno (ENOMEM);
279
0
      return NULL;
280
0
    }
281
282
0
  p = _gpgrt_realloc (a, bytes);
283
0
  if (p && oldnmemb < nmemb)
284
0
    {
285
      /* OLDNMEMBS is lower than NMEMB thus the user asked for a
286
         calloc.  Clear all newly allocated members.  */
287
0
      oldbytes = oldnmemb * size;
288
0
      if (size && oldbytes / size != oldnmemb)
289
0
        {
290
0
          xfree (p);
291
0
          _gpg_err_set_errno (ENOMEM);
292
0
          return NULL;
293
0
        }
294
0
      memset (p + oldbytes, 0, bytes - oldbytes);
295
0
    }
296
0
  return p;
297
0
}
298
299
300
/* The malloc to be used for data returned by the public API.  */
301
void *
302
_gpgrt_malloc (size_t n)
303
346k
{
304
346k
  if (!n)
305
0
    n++;
306
346k
  return _gpgrt_realloc (NULL, n);
307
346k
}
308
309
310
void *
311
_gpgrt_calloc (size_t n, size_t m)
312
0
{
313
0
  size_t bytes;
314
0
  void *p;
315
316
0
  bytes = n * m; /* size_t is unsigned so the behavior on overflow is
317
                    defined. */
318
0
  if (m && bytes / m != n)
319
0
    {
320
0
      _gpg_err_set_errno (ENOMEM);
321
0
      return NULL;
322
0
    }
323
324
0
  p = _gpgrt_realloc (NULL, bytes);
325
0
  if (p)
326
0
    memset (p, 0, bytes);
327
0
  return p;
328
0
}
329
330
331
char *
332
_gpgrt_strdup (const char *string)
333
0
{
334
0
  size_t len = strlen (string);
335
0
  char *p;
336
337
0
  p = _gpgrt_realloc (NULL, len + 1);
338
0
  if (p)
339
0
    strcpy (p, string);
340
0
  return p;
341
0
}
342
343
344
/* Helper for _gpgrt_strconcat and gpgrt_strconcat.  */
345
char *
346
_gpgrt_strconcat_core (const char *s1, va_list arg_ptr)
347
0
{
348
0
  const char *argv[48];
349
0
  size_t argc;
350
0
  size_t needed;
351
0
  char *buffer, *p;
352
353
0
  argc = 0;
354
0
  argv[argc++] = s1;
355
0
  needed = strlen (s1);
356
0
  while (((argv[argc] = va_arg (arg_ptr, const char *))))
357
0
    {
358
0
      needed += strlen (argv[argc]);
359
0
      if (argc >= DIM (argv)-1)
360
0
        {
361
0
          _gpg_err_set_errno (EINVAL);
362
0
          return NULL;
363
0
        }
364
0
      argc++;
365
0
    }
366
0
  needed++;
367
0
  buffer = _gpgrt_malloc (needed);
368
0
  if (buffer)
369
0
    {
370
0
      for (p = buffer, argc=0; argv[argc]; argc++)
371
0
        p = stpcpy (p, argv[argc]);
372
0
    }
373
0
  return buffer;
374
0
}
375
376
377
char *
378
_gpgrt_strconcat (const char *s1, ...)
379
0
{
380
0
  va_list arg_ptr;
381
0
  char *result;
382
383
0
  if (!s1)
384
0
    result = _gpgrt_strdup ("");
385
0
  else
386
0
    {
387
0
      va_start (arg_ptr, s1);
388
0
      result = _gpgrt_strconcat_core (s1, arg_ptr);
389
0
      va_end (arg_ptr);
390
0
    }
391
0
  return result;
392
0
}
393
394
395
/* The free to be used for data returned by the public API.  */
396
void
397
_gpgrt_free (void *a)
398
351k
{
399
351k
  int save_errno;
400
401
351k
  if (!a)
402
4.74k
    return;  /* Shortcut */
403
404
  /* In case ERRNO is set we better save it so that the free machinery
405
   * may not accidentally change ERRNO.  We restore it only if it was
406
   * already set to comply with the usual C semantic for ERRNO.
407
   * See also https://dev.gnupg.org/T5393#146261  */
408
346k
  save_errno = errno;
409
346k
  _gpgrt_realloc (a, 0);
410
346k
  if (save_errno && save_errno != errno)
411
0
    _gpg_err_set_errno (save_errno);
412
346k
}
413
414
415
void
416
_gpg_err_set_errno (int err)
417
50.4k
{
418
50.4k
  errno = err;
419
50.4k
}
420
421
422

423
/* Internal tracing functions.  Except for TRACE_FP we use flockfile
424
 * and funlockfile to protect their use.
425
 *
426
 * Warning: Take care with the trace functions - they may not use any
427
 * of our services, in particular not the syscall clamp mechanism for
428
 * reasons explained in w32-stream.c:create_reader.  */
429
static FILE *trace_fp;
430
static int trace_save_errno;
431
static int trace_with_errno;
432
static const char *trace_arg_module;
433
static const char *trace_arg_file;
434
static int trace_arg_line;
435
static int trace_missing_lf;
436
static int trace_prefix_done;
437
438
void
439
_gpgrt_internal_trace_begin (const char *module, const char *file, int line,
440
                             int with_errno)
441
0
{
442
0
  int save_errno = errno;
443
444
0
  if (!trace_fp)
445
0
    {
446
0
      FILE *fp;
447
0
      const char *s = getenv ("GPGRT_TRACE_FILE");
448
449
0
      if (!s || !(fp = fopen (s, "wb")))
450
0
        fp = stderr;
451
0
      trace_fp = fp;
452
0
    }
453
454
0
#ifdef HAVE_FLOCKFILE
455
0
  flockfile (trace_fp);
456
0
#endif
457
0
  trace_save_errno = save_errno;
458
0
  trace_with_errno = with_errno;
459
0
  trace_arg_module = module;
460
0
  trace_arg_file = file;
461
0
  trace_arg_line = line;
462
0
  trace_missing_lf = 0;
463
0
  trace_prefix_done = 0;
464
0
}
465
466
static void
467
print_internal_trace_prefix (void)
468
0
{
469
0
  if (!trace_prefix_done)
470
0
    {
471
0
      trace_prefix_done = 1;
472
0
      fprintf (trace_fp, "%s:%s:%d: ",
473
0
               trace_arg_module,/* npth_is_protected ()?"":"^",*/
474
0
               trace_arg_file, trace_arg_line);
475
0
    }
476
0
}
477
478
static void
479
do_internal_trace (const char *format, va_list arg_ptr)
480
0
{
481
0
  print_internal_trace_prefix ();
482
0
  vfprintf (trace_fp, format, arg_ptr);
483
0
  if (trace_with_errno)
484
0
    fprintf (trace_fp, " errno=%s", strerror (trace_save_errno));
485
0
  if (*format && format[strlen(format)-1] != '\n')
486
0
    fputc ('\n', trace_fp);
487
0
}
488
489
void
490
_gpgrt_internal_trace_printf (const char *format, ...)
491
0
{
492
0
  va_list arg_ptr;
493
494
0
  print_internal_trace_prefix ();
495
0
  va_start (arg_ptr, format) ;
496
0
  vfprintf (trace_fp, format, arg_ptr);
497
0
  va_end (arg_ptr);
498
0
  trace_missing_lf = (*format && format[strlen(format)-1] != '\n');
499
0
}
500
501
502
void
503
_gpgrt_internal_trace (const char *format, ...)
504
0
{
505
0
  va_list arg_ptr;
506
507
0
  va_start (arg_ptr, format) ;
508
0
  do_internal_trace (format, arg_ptr);
509
0
  va_end (arg_ptr);
510
0
}
511
512
513
void
514
_gpgrt_internal_trace_end (void)
515
0
{
516
0
  int save_errno = trace_save_errno;
517
518
0
  if (trace_missing_lf)
519
0
    fputc ('\n', trace_fp);
520
0
#ifdef HAVE_FLOCKFILE
521
0
  funlockfile (trace_fp);
522
0
#endif
523
0
  errno = save_errno;
524
0
}
525
526
527

528
#ifdef HAVE_W32_SYSTEM
529
/*****************************************
530
 ******** Below is only Windows code. ****
531
 *****************************************/
532
533
static char *
534
get_locale_dir (void)
535
{
536
  static wchar_t moddir[MAX_PATH+5];
537
  char *result, *p;
538
  int nbytes;
539
540
  if (!GetModuleFileNameW (NULL, moddir, MAX_PATH))
541
    *moddir = 0;
542
543
#define SLDIR "\\share\\locale"
544
  if (*moddir)
545
    {
546
      nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL);
547
      if (nbytes < 0)
548
        return NULL;
549
550
      result = malloc (nbytes + strlen (SLDIR) + 1);
551
      if (result)
552
        {
553
          nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1,
554
                                        result, nbytes, NULL, NULL);
555
          if (nbytes < 0)
556
            {
557
              free (result);
558
              result = NULL;
559
            }
560
          else
561
            {
562
              p = strrchr (result, '\\');
563
              if (p)
564
                *p = 0;
565
              /* If we are installed below "bin" strip that part and
566
                 use the top directory instead.
567
568
                 Background: Under Windows we don't install GnuPG
569
                 below bin/ but in the top directory with only share/,
570
                 lib/, and etc/ below it.  One of the reasons is to
571
                 keep the the length of the filenames at bay so not to
572
                 increase the limited length of the PATH envvar.
573
                 Another and more important reason, however, is that
574
                 the very first GPG versions on W32 were installed
575
                 into a flat directory structure and for best
576
                 compatibility with these versions we didn't changed
577
                 that later.  For WindowsCE we can right away install
578
                 it under bin, though.  The hack with detection of the
579
                 bin directory part allows us to eventually migrate to
580
                 such a directory layout under plain Windows without
581
                 the need to change libgpg-error.  */
582
              p = strrchr (result, '\\');
583
              if (p && !strcmp (p+1, "bin"))
584
                *p = 0;
585
              /* Append the static part.  */
586
              strcat (result, SLDIR);
587
            }
588
        }
589
    }
590
  else /* Use the old default value.  */
591
    {
592
      result = malloc (10 + strlen (SLDIR) + 1);
593
      if (result)
594
        {
595
          strcpy (result, "c:\\gnupg");
596
          strcat (result, SLDIR);
597
        }
598
    }
599
#undef SLDIR
600
  return result;
601
}
602
603
604
static void
605
drop_locale_dir (char *locale_dir)
606
{
607
  free (locale_dir);
608
}
609
610
611
/* Return the tls object.  This function is guaranteed to return a
612
   valid non-NULL object.  */
613
struct tls_space_s *
614
get_tls (void)
615
{
616
  struct tls_space_s *tls;
617
618
  tls = TlsGetValue (tls_index);
619
  if (!tls)
620
    {
621
      /* Called by a thread which existed before this DLL was loaded.
622
         Allocate the space.  */
623
      tls = LocalAlloc (LPTR, sizeof *tls);
624
      if (!tls)
625
        {
626
          /* No way to continue - commit suicide.  */
627
          _gpgrt_abort ();
628
        }
629
      tls->gt_use_utf8 = 0;
630
      TlsSetValue (tls_index, tls);
631
    }
632
633
  return tls;
634
}
635
636
637
/* Entry point called by the DLL loader.  */
638
#ifdef DLL_EXPORT
639
int WINAPI
640
DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
641
{
642
  struct tls_space_s *tls;
643
  (void)reserved;
644
  (void)hinst;
645
646
  switch (reason)
647
    {
648
    case DLL_PROCESS_ATTACH:
649
      tls_index = TlsAlloc ();
650
      if (tls_index == TLS_OUT_OF_INDEXES)
651
        return FALSE;
652
#ifndef _GPG_ERR_HAVE_CONSTRUCTOR
653
      /* If we have not constructors (e.g. MSC) we call it here.  */
654
      _gpg_w32__init_gettext_module ();
655
#endif
656
      /* fallthru.  */
657
    case DLL_THREAD_ATTACH:
658
      tls = LocalAlloc (LPTR, sizeof *tls);
659
      if (!tls)
660
        return FALSE;
661
      tls->gt_use_utf8 = 0;
662
      TlsSetValue (tls_index, tls);
663
      if (reason == DLL_PROCESS_ATTACH)
664
        {
665
          real_init ();
666
        }
667
      break;
668
669
    case DLL_THREAD_DETACH:
670
      tls = TlsGetValue (tls_index);
671
      if (tls)
672
        LocalFree (tls);
673
      break;
674
675
    case DLL_PROCESS_DETACH:
676
      tls = TlsGetValue (tls_index);
677
      if (tls)
678
        LocalFree (tls);
679
      TlsFree (tls_index);
680
      break;
681
682
    default:
683
      break;
684
    }
685
686
  return TRUE;
687
}
688
#endif /*DLL_EXPORT*/
689
690
#endif /*HAVE_W32_SYSTEM*/