summaryrefslogtreecommitdiffstats
path: root/common/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/init.c')
-rw-r--r--common/init.c384
1 files changed, 384 insertions, 0 deletions
diff --git a/common/init.c b/common/init.c
new file mode 100644
index 0000000..4ae7cbc
--- /dev/null
+++ b/common/init.c
@@ -0,0 +1,384 @@
+/* init.c - Various initializations
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#ifdef HAVE_W32_SYSTEM
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# endif
+# include <windows.h>
+#endif
+#ifdef HAVE_W32CE_SYSTEM
+# include <assuan.h> /* For _assuan_w32ce_finish_pipe. */
+#endif
+
+#include <gcrypt.h>
+#include "util.h"
+#include "i18n.h"
+#include "w32help.h"
+
+/* This object is used to register memory cleanup functions.
+ Technically they are not needed but they can avoid frequent
+ questions about un-released memory. Note that we use the system
+ malloc and not any wrappers. */
+struct mem_cleanup_item_s;
+typedef struct mem_cleanup_item_s *mem_cleanup_item_t;
+
+struct mem_cleanup_item_s
+{
+ mem_cleanup_item_t next;
+ void (*func) (void);
+};
+
+static mem_cleanup_item_t mem_cleanup_list;
+
+
+/* The default error source of the application. This is different
+ from GPG_ERR_SOURCE_DEFAULT in that it does not depend on the
+ source file and thus is usable in code shared by applications.
+ Note that we need to initialize it because otherwise some linkers
+ (OS X at least) won't find the symbol when linking the t-*.c
+ files. */
+gpg_err_source_t default_errsource = 0;
+
+
+#ifdef HAVE_W32CE_SYSTEM
+static void parse_std_file_handles (int *argcp, char ***argvp);
+static void
+sleep_on_exit (void)
+{
+ /* The sshd on CE swallows some of the command output. Sleeping a
+ while usually helps. */
+ Sleep (400);
+}
+#endif /*HAVE_W32CE_SYSTEM*/
+
+#if HAVE_W32_SYSTEM
+static void prepare_w32_commandline (int *argcp, char ***argvp);
+#endif /*HAVE_W32_SYSTEM*/
+
+
+
+static void
+run_mem_cleanup (void)
+{
+ mem_cleanup_item_t next;
+
+ while (mem_cleanup_list)
+ {
+ next = mem_cleanup_list->next;
+ mem_cleanup_list->func ();
+ free (mem_cleanup_list);
+ mem_cleanup_list = next;
+ }
+}
+
+
+void
+register_mem_cleanup_func (void (*func)(void))
+{
+ mem_cleanup_item_t item;
+
+ for (item = mem_cleanup_list; item; item = item->next)
+ if (item->func == func)
+ return; /* Function has already been registered. */
+
+ item = malloc (sizeof *item);
+ if (item)
+ {
+ item->func = func;
+ item->next = mem_cleanup_list;
+ mem_cleanup_list = item;
+ }
+}
+
+
+/* If STRING is not NULL write string to es_stdout or es_stderr. MODE
+ must be 1 or 2. If STRING is NULL flush the respective stream. */
+static int
+writestring_via_estream (int mode, const char *string)
+{
+ if (mode == 1 || mode == 2)
+ {
+ if (string)
+ return es_fputs (string, mode == 1? es_stdout : es_stderr);
+ else
+ return es_fflush (mode == 1? es_stdout : es_stderr);
+ }
+ else
+ return -1;
+}
+
+
+/* This function should be the first called after main. */
+void
+early_system_init (void)
+{
+}
+
+
+/* This function is to be used early at program startup to make sure
+ that some subsystems are initialized. This is in particular
+ important for W32 to initialize the sockets so that our socket
+ emulation code used directly as well as in libassuan may be used.
+ It should best be called before any I/O is done so that setup
+ required for logging is ready. ARGCP and ARGVP are the addresses
+ of the parameters given to main. This function may modify them.
+
+ This function should be called only via the macro
+ init_common_subsystems.
+
+ CAUTION: This might be called while running suid(root). */
+void
+_init_common_subsystems (gpg_err_source_t errsource, int *argcp, char ***argvp)
+{
+ /* Store the error source in a global variable. */
+ default_errsource = errsource;
+
+ atexit (run_mem_cleanup);
+
+ /* Try to auto set the character set. */
+ set_native_charset (NULL);
+
+#ifdef HAVE_W32_SYSTEM
+ /* For W32 we need to initialize the socket layer. This is because
+ we use recv and send in libassuan as well as at some other
+ places. */
+ {
+ WSADATA wsadat;
+
+ WSAStartup (0x202, &wsadat);
+ }
+#endif
+
+#ifdef HAVE_W32CE_SYSTEM
+ /* Register the sleep exit function before the estream init so that
+ the sleep will be called after the estream registered atexit
+ function which flushes the left open estream streams and in
+ particular es_stdout. */
+ atexit (sleep_on_exit);
+#endif
+
+ if (!gcry_check_version (NEED_LIBGCRYPT_VERSION))
+ {
+ log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
+ NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL));
+ }
+
+ /* Initialize the Estream library. */
+ gpgrt_init ();
+ gpgrt_set_alloc_func (gcry_realloc);
+
+#ifdef HAVE_W32CE_SYSTEM
+ /* Special hack for Windows CE: We extract some options from arg
+ to setup the standard handles. */
+ parse_std_file_handles (argcp, argvp);
+#endif
+
+#ifdef HAVE_W32_SYSTEM
+ /* We want gettext to always output UTF-8 and we put the console in
+ * utf-8 mode. */
+ gettext_use_utf8 (1);
+ if (!SetConsoleCP (CP_UTF8) || !SetConsoleOutputCP (CP_UTF8))
+ {
+ /* Don't show the error if the program does not have a console.
+ * This is for example the case for daemons. */
+ int rc = GetLastError ();
+ if (rc != ERROR_INVALID_HANDLE)
+ {
+ log_info ("SetConsoleCP failed: %s\n", w32_strerror (rc));
+ log_info ("Warning: Garbled console data possible\n");
+ }
+ }
+#endif
+
+ /* Access the standard estreams as early as possible. If we don't
+ do this the original stdio streams may have been closed when
+ _es_get_std_stream is first use and in turn it would connect to
+ the bit bucket. */
+ {
+ int i;
+ for (i=0; i < 3; i++)
+ (void)_gpgrt_get_std_stream (i);
+ }
+
+ /* --version et al shall use estream as well. */
+ gnupg_set_usage_outfnc (writestring_via_estream);
+
+ /* Register our string mapper with gpgrt. */
+ gnupg_set_fixed_string_mapper (map_static_macro_string);
+
+ /* Logging shall use the standard socket directory as fallback. */
+ log_set_socket_dir_cb (gnupg_socketdir);
+
+#if HAVE_W32_SYSTEM
+ /* For Standard Windows we use our own parser for the command line
+ * so that we can return an array of utf-8 encoded strings. */
+ prepare_w32_commandline (argcp, argvp);
+#else
+ (void)argcp;
+ (void)argvp;
+#endif
+
+}
+
+
+
+/* WindowsCE uses a very strange way of handling the standard streams.
+ There is a function SetStdioPath to associate a standard stream
+ with a file or a device but what we really want is to use pipes as
+ standard streams. Despite that we implement pipes using a device,
+ we would have some limitations on the number of open pipes due to
+ the 3 character limit of device file name. Thus we don't take this
+ path. Another option would be to install a file system driver with
+ support for pipes; this would allow us to get rid of the device
+ name length limitation. However, with GnuPG we can get away be
+ redefining the standard streams and passing the handles to be used
+ on the command line. This has also the advantage that it makes
+ creating a process much easier and does not require the
+ SetStdioPath set and restore game. The caller needs to pass the
+ rendezvous ids using up to three options:
+
+ -&S0=<rvid> -&S1=<rvid> -&S2=<rvid>
+
+ They are all optional but they must be the first arguments on the
+ command line. Parsing stops as soon as an invalid option is found.
+ These rendezvous ids are then used to finish the pipe creation.*/
+#ifdef HAVE_W32CE_SYSTEM
+static void
+parse_std_file_handles (int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ const char *s;
+ assuan_fd_t fd;
+ int i;
+ int fixup = 0;
+
+ if (!argc)
+ return;
+
+ for (argc--, argv++; argc; argc--, argv++)
+ {
+ s = *argv;
+ if (*s == '-' && s[1] == '&' && s[2] == 'S'
+ && (s[3] == '0' || s[3] == '1' || s[3] == '2')
+ && s[4] == '='
+ && (strchr ("-01234567890", s[5]) || !strcmp (s+5, "null")))
+ {
+ if (s[5] == 'n')
+ fd = ASSUAN_INVALID_FD;
+ else
+ fd = _assuan_w32ce_finish_pipe (atoi (s+5), s[3] != '0');
+ _es_set_std_fd (s[3] - '0', (int)fd);
+ fixup++;
+ }
+ else
+ break;
+ }
+
+ if (fixup)
+ {
+ argc = *argcp;
+ argc -= fixup;
+ *argcp = argc;
+
+ argv = *argvp;
+ for (i=1; i < argc; i++)
+ argv[i] = argv[i + fixup];
+ for (; i < argc + fixup; i++)
+ argv[i] = NULL;
+ }
+
+
+}
+#endif /*HAVE_W32CE_SYSTEM*/
+
+
+/* For Windows we need to parse the command line so that we can
+ * provide an UTF-8 encoded argv. If there is any Unicode character
+ * we return a new array but if there is no Unicode character we do
+ * nothing. */
+#ifdef HAVE_W32_SYSTEM
+static void
+prepare_w32_commandline (int *r_argc, char ***r_argv)
+{
+ const wchar_t *wcmdline, *ws;
+ char *cmdline;
+ int argc;
+ char **argv;
+ const char *s;
+ int i, globing, itemsalloced;
+
+ s = strusage (95);
+ globing = (s && *s == '1');
+
+ wcmdline = GetCommandLineW ();
+ if (!wcmdline)
+ {
+ log_error ("GetCommandLineW failed\n");
+ return; /* Ooops. */
+ }
+
+ if (!globing)
+ {
+ /* If globbing is not enabled we use our own parser only if
+ * there are any non-ASCII characters. */
+ for (ws=wcmdline; *ws; ws++)
+ if (!iswascii (*ws))
+ break;
+ if (!*ws)
+ return; /* No Unicode - return directly. */
+ }
+
+ cmdline = wchar_to_utf8 (wcmdline);
+ if (!cmdline)
+ {
+ log_error ("parsing command line failed: %s\n", strerror (errno));
+ return; /* Ooops. */
+ }
+ gpgrt_annotate_leaked_object (cmdline);
+
+ argv = w32_parse_commandline (cmdline, globing, &argc, &itemsalloced);
+ if (!argv)
+ {
+ log_error ("parsing command line failed: %s\n", "internal error");
+ return; /* Ooops. */
+ }
+ gpgrt_annotate_leaked_object (argv);
+ if (itemsalloced)
+ {
+ for (i=0; i < argc; i++)
+ gpgrt_annotate_leaked_object (argv[i]);
+ }
+ *r_argv = argv;
+ *r_argc = argc;
+}
+#endif /*HAVE_W32_SYSTEM*/