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*/ |