Line data Source code
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 : # ifdef HAVE_WINSOCK2_H
34 : # include <winsock2.h>
35 : # endif
36 : # include <windows.h>
37 : #endif
38 : #ifdef HAVE_W32CE_SYSTEM
39 : # include <assuan.h> /* For _assuan_w32ce_finish_pipe. */
40 : #endif
41 :
42 : #include <gcrypt.h>
43 : #include "util.h"
44 : #include "i18n.h"
45 :
46 : /* This object is used to register memory cleanup functions.
47 : Technically they are not needed but they can avoid frequent
48 : questions about un-released memory. Note that we use the system
49 : malloc and not any wrappers. */
50 : struct mem_cleanup_item_s;
51 : typedef struct mem_cleanup_item_s *mem_cleanup_item_t;
52 :
53 : struct mem_cleanup_item_s
54 : {
55 : mem_cleanup_item_t next;
56 : void (*func) (void);
57 : };
58 :
59 : static mem_cleanup_item_t mem_cleanup_list;
60 :
61 :
62 : /* The default error source of the application. This is different
63 : from GPG_ERR_SOURCE_DEFAULT in that it does not depend on the
64 : source file and thus is usable in code shared by applications.
65 : Note that we need to initialize it because otherwise some linkers
66 : (OS X at least) won't find the symbol when linking the t-*.c
67 : files. */
68 : gpg_err_source_t default_errsource = 0;
69 :
70 :
71 : #ifdef HAVE_W32CE_SYSTEM
72 : static void parse_std_file_handles (int *argcp, char ***argvp);
73 : static void
74 : sleep_on_exit (void)
75 : {
76 : /* The sshd on CE swallows some of the command output. Sleeping a
77 : while usually helps. */
78 : Sleep (400);
79 : }
80 : #endif /*HAVE_W32CE_SYSTEM*/
81 :
82 :
83 : static void
84 1768 : run_mem_cleanup (void)
85 : {
86 : mem_cleanup_item_t next;
87 :
88 4599 : while (mem_cleanup_list)
89 : {
90 1063 : next = mem_cleanup_list->next;
91 1063 : mem_cleanup_list->func ();
92 1063 : free (mem_cleanup_list);
93 1063 : mem_cleanup_list = next;
94 : }
95 1768 : }
96 :
97 :
98 : void
99 1065 : register_mem_cleanup_func (void (*func)(void))
100 : {
101 : mem_cleanup_item_t item;
102 :
103 1065 : for (item = mem_cleanup_list; item; item = item->next)
104 0 : if (item->func == func)
105 1065 : return; /* Function has already been registered. */
106 :
107 1065 : item = malloc (sizeof *item);
108 1065 : if (item)
109 : {
110 1065 : item->func = func;
111 1065 : item->next = mem_cleanup_list;
112 1065 : mem_cleanup_list = item;
113 : }
114 : }
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 52855 : writestring_via_estream (int mode, const char *string)
121 : {
122 52855 : if (mode == 1 || mode == 2)
123 : {
124 52855 : if (string)
125 52846 : return es_fputs (string, mode == 1? es_stdout : es_stderr);
126 : else
127 9 : return es_fflush (mode == 1? es_stdout : es_stderr);
128 : }
129 : else
130 0 : return -1;
131 : }
132 :
133 :
134 : /* This function should be the first called after main. */
135 : void
136 1600 : early_system_init (void)
137 : {
138 1600 : }
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 1718 : _init_common_subsystems (gpg_err_source_t errsource, int *argcp, char ***argvp)
155 : {
156 : /* Store the error source in a global variable. */
157 1718 : default_errsource = errsource;
158 :
159 1718 : atexit (run_mem_cleanup);
160 :
161 : /* Try to auto set the character set. */
162 1718 : 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 : #endif
174 :
175 : #ifdef HAVE_W32CE_SYSTEM
176 : /* Register the sleep exit function before the estream init so that
177 : the sleep will be called after the estream registered atexit
178 : function which flushes the left open estream streams and in
179 : particular es_stdout. */
180 : atexit (sleep_on_exit);
181 : #endif
182 :
183 1718 : if (!gcry_check_version (NEED_LIBGCRYPT_VERSION))
184 : {
185 0 : log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
186 : NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL));
187 : }
188 :
189 : /* Initialize the Estream library. */
190 1718 : gpgrt_init ();
191 1718 : gpgrt_set_alloc_func (gcry_realloc);
192 :
193 : /* Special hack for Windows CE: We extract some options from arg
194 : to setup the standard handles. */
195 : #ifdef HAVE_W32CE_SYSTEM
196 : parse_std_file_handles (argcp, argvp);
197 : #else
198 : (void)argcp;
199 : (void)argvp;
200 : #endif
201 :
202 : /* Access the standard estreams as early as possible. If we don't
203 : do this the original stdio streams may have been closed when
204 : _es_get_std_stream is first use and in turn it would connect to
205 : the bit bucket. */
206 : {
207 : int i;
208 6872 : for (i=0; i < 3; i++)
209 5154 : (void)_gpgrt_get_std_stream (i);
210 : }
211 :
212 : /* --version et al shall use estream as well. */
213 1718 : argparse_register_outfnc (writestring_via_estream);
214 :
215 : /* Logging shall use the standard socket directory as fallback. */
216 1718 : log_set_socket_dir_cb (gnupg_socketdir);
217 1718 : }
218 :
219 :
220 :
221 : /* WindowsCE uses a very strange way of handling the standard streams.
222 : There is a function SetStdioPath to associate a standard stream
223 : with a file or a device but what we really want is to use pipes as
224 : standard streams. Despite that we implement pipes using a device,
225 : we would have some limitations on the number of open pipes due to
226 : the 3 character limit of device file name. Thus we don't take this
227 : path. Another option would be to install a file system driver with
228 : support for pipes; this would allow us to get rid of the device
229 : name length limitation. However, with GnuPG we can get away be
230 : redefining the standard streams and passing the handles to be used
231 : on the command line. This has also the advantage that it makes
232 : creating a process much easier and does not require the
233 : SetStdioPath set and restore game. The caller needs to pass the
234 : rendezvous ids using up to three options:
235 :
236 : -&S0=<rvid> -&S1=<rvid> -&S2=<rvid>
237 :
238 : They are all optional but they must be the first arguments on the
239 : command line. Parsing stops as soon as an invalid option is found.
240 : These rendezvous ids are then used to finish the pipe creation.*/
241 : #ifdef HAVE_W32CE_SYSTEM
242 : static void
243 : parse_std_file_handles (int *argcp, char ***argvp)
244 : {
245 : int argc = *argcp;
246 : char **argv = *argvp;
247 : const char *s;
248 : assuan_fd_t fd;
249 : int i;
250 : int fixup = 0;
251 :
252 : if (!argc)
253 : return;
254 :
255 : for (argc--, argv++; argc; argc--, argv++)
256 : {
257 : s = *argv;
258 : if (*s == '-' && s[1] == '&' && s[2] == 'S'
259 : && (s[3] == '0' || s[3] == '1' || s[3] == '2')
260 : && s[4] == '='
261 : && (strchr ("-01234567890", s[5]) || !strcmp (s+5, "null")))
262 : {
263 : if (s[5] == 'n')
264 : fd = ASSUAN_INVALID_FD;
265 : else
266 : fd = _assuan_w32ce_finish_pipe (atoi (s+5), s[3] != '0');
267 : _es_set_std_fd (s[3] - '0', (int)fd);
268 : fixup++;
269 : }
270 : else
271 : break;
272 : }
273 :
274 : if (fixup)
275 : {
276 : argc = *argcp;
277 : argc -= fixup;
278 : *argcp = argc;
279 :
280 : argv = *argvp;
281 : for (i=1; i < argc; i++)
282 : argv[i] = argv[i + fixup];
283 : for (; i < argc + fixup; i++)
284 : argv[i] = NULL;
285 : }
286 :
287 :
288 : }
289 : #endif /*HAVE_W32CE_SYSTEM*/
|