Coverage Report

Created: 2026-02-26 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/common/init.c
Line
Count
Source
1
/* init.c - Various initializations
2
 *  Copyright (C) 2007 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
32
#ifdef HAVE_W32_SYSTEM
33
# if _WIN32_WINNT < 0x0600
34
#   define _WIN32_WINNT 0x0600  /* Required for SetProcessDEPPolicy.  */
35
# endif
36
# ifdef HAVE_WINSOCK2_H
37
#  include <winsock2.h>
38
# endif
39
# include <windows.h>
40
# include <wctype.h>
41
#endif
42
43
#include <gcrypt.h>
44
#include "util.h"
45
#include "i18n.h"
46
#include "w32help.h"
47
48
/* This object is used to register memory cleanup functions.
49
   Technically they are not needed but they can avoid frequent
50
   questions about un-released memory.  Note that we use the system
51
   malloc and not any wrappers.  */
52
struct mem_cleanup_item_s;
53
typedef struct mem_cleanup_item_s *mem_cleanup_item_t;
54
55
struct mem_cleanup_item_s
56
{
57
  mem_cleanup_item_t next;
58
  void (*func) (void);
59
};
60
61
static mem_cleanup_item_t mem_cleanup_list;
62
63
64
/* The default error source of the application.  This is different
65
   from GPG_ERR_SOURCE_DEFAULT in that it does not depend on the
66
   source file and thus is usable in code shared by applications.
67
   Note that we need to initialize it because otherwise some linkers
68
   (OS X at least) won't find the symbol when linking the t-*.c
69
   files.  */
70
gpg_err_source_t default_errsource = 0;
71
72
73
74
#if HAVE_W32_SYSTEM
75
static void prepare_w32_commandline (int *argcp, char ***argvp);
76
77
/* Whether or not if this program is running under Wine. */
78
int windows_semihosted_by_wine;
79
#endif /*HAVE_W32_SYSTEM*/
80
81
82
83
static void
84
run_mem_cleanup (void)
85
0
{
86
0
  mem_cleanup_item_t next;
87
88
0
  while (mem_cleanup_list)
89
0
    {
90
0
      next = mem_cleanup_list->next;
91
0
      mem_cleanup_list->func ();
92
0
      free (mem_cleanup_list);
93
0
      mem_cleanup_list = next;
94
0
    }
95
0
}
96
97
98
void
99
register_mem_cleanup_func (void (*func)(void))
100
1
{
101
1
  mem_cleanup_item_t item;
102
103
1
  for (item = mem_cleanup_list; item; item = item->next)
104
0
    if (item->func == func)
105
0
      return; /* Function has already been registered.  */
106
107
1
  item = malloc (sizeof *item);
108
1
  if (item)
109
1
    {
110
1
      item->func = func;
111
1
      item->next = mem_cleanup_list;
112
1
      mem_cleanup_list = item;
113
1
    }
114
1
}
115
116
117
/* If STRING is not NULL write string to es_stdout or es_stderr.  MODE
118
   must be 1 or 2.  If STRING is NULL flush the respective stream.  */
119
static int
120
writestring_via_estream (int mode, const char *string)
121
0
{
122
0
  if (mode == 1 || mode == 2)
123
0
    {
124
0
      if (string)
125
0
        return es_fputs (string, mode == 1? es_stdout : es_stderr);
126
0
      else
127
0
        return es_fflush (mode == 1? es_stdout : es_stderr);
128
0
    }
129
0
  else
130
0
    return -1;
131
0
}
132
133
134
/* This function should be the first called after main.  */
135
void
136
early_system_init (void)
137
0
{
138
0
}
139
140
141
/* This function is to be used early at program startup to make sure
142
   that some subsystems are initialized.  This is in particular
143
   important for W32 to initialize the sockets so that our socket
144
   emulation code used directly as well as in libassuan may be used.
145
   It should best be called before any I/O is done so that setup
146
   required for logging is ready.  ARGCP and ARGVP are the addresses
147
   of the parameters given to main.  This function may modify them.
148
149
   This function should be called only via the macro
150
   init_common_subsystems.
151
152
   CAUTION: This might be called while running suid(root).  */
153
void
154
_init_common_subsystems (gpg_err_source_t errsource, int *argcp, char ***argvp)
155
0
{
156
  /* Store the error source in a global variable. */
157
0
  default_errsource = errsource;
158
159
0
  atexit (run_mem_cleanup);
160
161
  /* Try to auto set the character set.  */
162
0
  set_native_charset (NULL);
163
164
#ifdef HAVE_W32_SYSTEM
165
  /* For W32 we need to initialize the socket layer.  This is because
166
     we use recv and send in libassuan as well as at some other
167
     places.  */
168
  {
169
    WSADATA wsadat;
170
171
    WSAStartup (0x202, &wsadat);
172
  }
173
  {
174
    HMODULE hntdll = GetModuleHandle ("ntdll.dll");
175
    if (hntdll
176
        && GetProcAddress (hntdll, "wine_get_version"))
177
      windows_semihosted_by_wine = 1;
178
  }
179
#endif
180
181
0
  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION))
182
0
    {
183
0
      log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
184
0
                 NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL));
185
0
    }
186
187
  /* Initialize the Estream library. */
188
0
  gpgrt_init ();
189
0
  gpgrt_set_alloc_func (gcry_realloc);
190
191
192
#ifdef HAVE_W32_SYSTEM
193
  /* We want gettext to always output UTF-8 and we put the console in
194
   * utf-8 mode.  */
195
  gettext_use_utf8 (1);
196
  if (!SetConsoleCP (CP_UTF8) || !SetConsoleOutputCP (CP_UTF8))
197
    {
198
      /* Don't show the error if the program does not have a console.
199
       * This is for example the case for daemons.  */
200
      int rc = GetLastError ();
201
      if (rc != ERROR_INVALID_HANDLE)
202
        {
203
          log_info ("SetConsoleCP failed: %s\n", w32_strerror (rc));
204
          log_info ("Warning: Garbled console data possible\n");
205
        }
206
    }
207
#endif
208
209
  /* Access the standard estreams as early as possible.  If we don't
210
     do this the original stdio streams may have been closed when
211
     _es_get_std_stream is first use and in turn it would connect to
212
     the bit bucket.  */
213
0
  {
214
0
    int i;
215
0
    for (i=0; i < 3; i++)
216
0
      (void)_gpgrt_get_std_stream (i);
217
0
  }
218
219
  /* --version et al shall use estream as well.  */
220
0
  gpgrt_set_usage_outfnc (writestring_via_estream);
221
222
  /* Register our string mapper with gpgrt.  */
223
0
  gpgrt_set_fixed_string_mapper (map_static_macro_string);
224
225
  /* Logging shall use the standard socket directory as fallback.  */
226
0
  log_set_socket_dir_cb (gnupg_socketdir);
227
228
#if HAVE_W32_SYSTEM
229
  /* Make sure that Data Execution Prevention is enabled.  */
230
  if (GetSystemDEPPolicy () >= 2)
231
    {
232
      DWORD flags;
233
      BOOL perm;
234
235
      if (!GetProcessDEPPolicy (GetCurrentProcess (), &flags, &perm))
236
        log_info ("error getting DEP policy: %s\n",
237
                  w32_strerror (GetLastError()));
238
      else if (!(flags & PROCESS_DEP_ENABLE)
239
               && !SetProcessDEPPolicy (PROCESS_DEP_ENABLE))
240
        log_info ("Warning: Enabling DEP failed: %s (%d,%d)\n",
241
                  w32_strerror (GetLastError ()), (int)flags, (int)perm);
242
    }
243
  /* On Windows we use our own parser for the command line
244
   * so that we can return an array of utf-8 encoded strings.  */
245
  prepare_w32_commandline (argcp, argvp);
246
#else
247
0
  (void)argcp;
248
0
  (void)argvp;
249
0
#endif
250
251
0
}
252
253
254
255
/* For Windows we need to parse the command line so that we can
256
 * provide an UTF-8 encoded argv.  If there is any Unicode character
257
 * we return a new array but if there is no Unicode character we do
258
 * nothing.  */
259
#ifdef HAVE_W32_SYSTEM
260
static void
261
prepare_w32_commandline (int *r_argc, char ***r_argv)
262
{
263
  const wchar_t *wcmdline, *ws;
264
  char *cmdline;
265
  int argc;
266
  char **argv;
267
  const char *s;
268
  int i, globing, itemsalloced;
269
270
  s = gpgrt_strusage (95);
271
  globing = (s && *s == '1');
272
273
  wcmdline = GetCommandLineW ();
274
  if (!wcmdline)
275
    {
276
      log_error ("GetCommandLineW failed\n");
277
      return;  /* Ooops.  */
278
    }
279
280
  if (!globing)
281
    {
282
      /* If globbing is not enabled we use our own parser only if
283
       * there are any non-ASCII characters.  */
284
      for (ws=wcmdline; *ws; ws++)
285
        if (!iswascii (*ws))
286
          break;
287
      if (!*ws)
288
        return;  /* No Unicode - return directly.  */
289
    }
290
291
  cmdline = wchar_to_utf8 (wcmdline);
292
  if (!cmdline)
293
    {
294
      log_error ("parsing command line failed: %s\n", strerror (errno));
295
      return;  /* Ooops.  */
296
    }
297
  gpgrt_annotate_leaked_object (cmdline);
298
299
  argv = w32_parse_commandline (cmdline, globing, &argc, &itemsalloced);
300
  if (!argv)
301
    {
302
      log_error ("parsing command line failed: %s\n", "internal error");
303
      return;  /* Ooops.  */
304
    }
305
  gpgrt_annotate_leaked_object (argv);
306
  if (itemsalloced)
307
    {
308
      for (i=0; i < argc; i++)
309
        gpgrt_annotate_leaked_object (argv[i]);
310
    }
311
  *r_argv = argv;
312
  *r_argc = argc;
313
}
314
#endif /*HAVE_W32_SYSTEM*/