diff options
author | Werner Koch <wk@gnupg.org> | 2004-12-15 15:15:54 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2004-12-15 15:15:54 +0100 |
commit | 69967b04125e53811182a01d2700984469117339 (patch) | |
tree | 3034ccf72b4bb558187f3e1d435a92ec193e093c /common | |
parent | Yep. No lost threads anymore. (diff) | |
download | gnupg2-69967b04125e53811182a01d2700984469117339.tar.xz gnupg2-69967b04125e53811182a01d2700984469117339.zip |
A whole bunch of changes to allow building for W32.
Diffstat (limited to 'common')
-rw-r--r-- | common/ChangeLog | 15 | ||||
-rw-r--r-- | common/asshelp.c | 119 | ||||
-rw-r--r-- | common/exechelp.c | 276 | ||||
-rw-r--r-- | common/iobuf.c | 4 | ||||
-rw-r--r-- | common/simple-pwquery.c | 6 | ||||
-rw-r--r-- | common/sysutils.h | 7 | ||||
-rw-r--r-- | common/ttyname.c | 32 | ||||
-rw-r--r-- | common/util.h | 4 | ||||
-rw-r--r-- | common/w32reg.c | 5 |
9 files changed, 385 insertions, 83 deletions
diff --git a/common/ChangeLog b/common/ChangeLog index afdded6d9..3115ad897 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,18 @@ +2004-12-15 Werner Koch <wk@g10code.com> + + * sysutils.h [W32]: Prototypes for registry functions. + * w32reg.c: Include sysutils.h + + * simple-pwquery.c [W32]: Dummy code to allow a build. + + * exechelp.c [W32]: Implemented for W32 . + + * ttyname.c: New. + + * asshelp.c (send_one_option): New. + (send_pinentry_environment): Cleaned up and made sure that empty + values are not send. + 2004-12-07 Werner Koch <wk@g10code.com> * asshelp.c (send_pinentry_environment) [W32]: Do not use ttyname. diff --git a/common/asshelp.c b/common/asshelp.c index 751412e6c..243d6b9e7 100644 --- a/common/asshelp.c +++ b/common/asshelp.c @@ -32,8 +32,32 @@ #include "asshelp.h" -/* Send the assuan command pertaining to the pinenry environment. The - OPT_* arguments are optional and may be used to overide the + +static gpg_error_t +send_one_option (assuan_context_t ctx, const char *name, const char *value) +{ + gpg_error_t err; + char *optstr; + + if (!value || !*value) + err = 0; /* Avoid sending empty strings. */ + else if (asprintf (&optstr, "OPTION %s=%s", name, value ) < 0) + err = gpg_error_from_errno (errno); + else + { + assuan_error_t ae; + + ae = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); + err = ae? map_assuan_err (ae) : 0; + free (optstr); + } + + return err; +} + + +/* Send the assuan commands pertaining to the pinenry environment. The + OPT_* arguments are optional and may be used to override the defaults taken from the current locale. */ gpg_error_t send_pinentry_environment (assuan_context_t ctx, @@ -43,62 +67,49 @@ send_pinentry_environment (assuan_context_t ctx, const char *opt_lc_ctype, const char *opt_lc_messages) { - int rc = 0; + gpg_error_t err = 0; char *dft_display = NULL; char *dft_ttyname = NULL; char *dft_ttytype = NULL; char *old_lc = NULL; char *dft_lc = NULL; + /* Send the DISPLAY variable. */ dft_display = getenv ("DISPLAY"); if (opt_display || dft_display) { - char *optstr; - if (asprintf (&optstr, "OPTION display=%s", - opt_display ? opt_display : dft_display) < 0) - return gpg_error_from_errno (errno); - rc = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, - NULL); - free (optstr); - if (rc) - return map_assuan_err (rc); + err = send_one_option (ctx, "display", + opt_display ? opt_display : dft_display); + if (err) + return err; } + + /* Send the name of the TTY. */ if (!opt_ttyname) { dft_ttyname = getenv ("GPG_TTY"); -#ifdef HAVE_DOSISH_SYSTEM - if (!dft_ttyname || !*dft_ttyname ) - dft_ttyname = "/dev/tty"; /* Use a fake. */ -#else if ((!dft_ttyname || !*dft_ttyname) && ttyname (0)) dft_ttyname = ttyname (0); -#endif } if (opt_ttyname || dft_ttyname) { - char *optstr; - if (asprintf (&optstr, "OPTION ttyname=%s", - opt_ttyname ? opt_ttyname : dft_ttyname) < 0) - return gpg_error_from_errno (errno); - rc = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, - NULL); - free (optstr); - if (rc) - return map_assuan_err (rc); + err = send_one_option (ctx, "ttyname", + opt_ttyname ? opt_ttyname : dft_ttyname); + if (err) + return err; } + + /* Send the type of the TTY. */ dft_ttytype = getenv ("TERM"); if (opt_ttytype || (dft_ttyname && dft_ttytype)) { - char *optstr; - if (asprintf (&optstr, "OPTION ttytype=%s", - opt_ttyname ? opt_ttytype : dft_ttytype) < 0) - return gpg_error_from_errno (errno); - rc = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, - NULL); - free (optstr); - if (rc) - return map_assuan_err (rc); + err = send_one_option (ctx, "ttytype", + opt_ttyname ? opt_ttytype : dft_ttytype); + if (err) + return err; } + + /* Send the value for LC_CTYPE. */ #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE) old_lc = setlocale (LC_CTYPE, NULL); if (old_lc) @@ -111,18 +122,8 @@ send_pinentry_environment (assuan_context_t ctx, #endif if (opt_lc_ctype || (dft_ttyname && dft_lc)) { - char *optstr; - if (asprintf (&optstr, "OPTION lc-ctype=%s", - opt_lc_ctype ? opt_lc_ctype : dft_lc) < 0) - rc = gpg_error_from_errno (errno); - else - { - rc = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, - NULL); - free (optstr); - if (rc) - rc = map_assuan_err (rc); - } + err = send_one_option (ctx, "lc-ctype", + opt_lc_ctype ? opt_lc_ctype : dft_lc); } #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE) if (old_lc) @@ -131,8 +132,10 @@ send_pinentry_environment (assuan_context_t ctx, free (old_lc); } #endif - if (rc) - return rc; + if (err) + return err; + + /* Send the value for LC_MESSAGES. */ #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES) old_lc = setlocale (LC_MESSAGES, NULL); if (old_lc) @@ -145,18 +148,8 @@ send_pinentry_environment (assuan_context_t ctx, #endif if (opt_lc_messages || (dft_ttyname && dft_lc)) { - char *optstr; - if (asprintf (&optstr, "OPTION lc-messages=%s", - opt_lc_messages ? opt_lc_messages : dft_lc) < 0) - rc = gpg_error_from_errno (errno); - else - { - rc = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, - NULL); - free (optstr); - if (rc) - rc = map_assuan_err (rc); - } + err = send_one_option (ctx, "display", + opt_lc_messages ? opt_lc_messages : dft_lc); } #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES) if (old_lc) @@ -165,7 +158,9 @@ send_pinentry_environment (assuan_context_t ctx, free (old_lc); } #endif + if (err) + return err; - return rc; + return 0; } diff --git a/common/exechelp.c b/common/exechelp.c index 206e16d51..0a9cb824f 100644 --- a/common/exechelp.c +++ b/common/exechelp.c @@ -30,8 +30,7 @@ #ifdef USE_GNU_PTH #include <pth.h> #endif -#ifdef _WIN32 -#else +#ifndef HAVE_W32_SYSTEM #include <sys/wait.h> #endif @@ -39,6 +38,9 @@ #include "i18n.h" #include "exechelp.h" +/* Define to 1 do enable debugging. */ +#define DEBUG_W32_SPAWN 1 + #ifdef _POSIX_OPEN_MAX #define MAX_OPEN_FDS _POSIX_OPEN_MAX @@ -57,6 +59,105 @@ #endif +#ifdef HAVE_W32_SYSTEM +/* We assume that a HANDLE can be represented by an int which should + be true for all i386 systems (HANDLE is defined as void *) and + these are the only systems for which Windows is available. Further + we assume that -1 denotes an invalid handle. */ +# define fd_to_handle(a) ((HANDLE)(a)) +# define handle_to_fd(a) ((int)(a)) +# define pid_to_handle(a) ((HANDLE)(a)) +# define handle_to_pid(a) ((int)(a)) +#endif + + +#ifdef HAVE_W32_SYSTEM +/* Build a command line for use with W32's CreateProcess. On success + CMDLINE gets the address of a newly allocated string. */ +static gpg_error_t +build_w32_commandline (const char *pgmname, const char **argv, char **cmdline) +{ + int i, n; + const char *s; + char *buf, *p; + + *cmdline = NULL; + n = strlen (pgmname); + for (i=0; (s=argv[i]); i++) + { + n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */ + for (; *s; s++) + if (*s == '\"') + n++; /* Need to double inner quotes. */ + } + n++; + + buf = p = xtrymalloc (n); + if (!buf) + return gpg_error_from_errno (errno); + + /* fixme: PGMNAME may not contain spaces etc. */ + p = stpcpy (p, pgmname); + for (i=0; argv[i]; i++) + { + if (!*argv[i]) /* Empty string. */ + p = stpcpy (p, " \"\""); + else if (strpbrk (argv[i], " \t\n\v\f\"")) + { + p = stpcpy (p, " \""); + for (s=argv[i]; *s; s++) + { + *p++ = *s; + if (*s == '\"') + *p++ = *s; + } + *p++ = '\"'; + *p = 0; + } + else + p = stpcpy (stpcpy (p, " "), argv[i]); + } + + *cmdline= buf; + return 0; +} +#endif /*HAVE_W32_SYSTEM*/ + + +#ifdef HAVE_W32_SYSTEM +/* Create pipe where the write end is inheritable. */ +static int +create_inheritable_pipe (int filedes[2]) +{ + HANDLE r, w, h; + SECURITY_ATTRIBUTES sec_attr; + + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + if (!CreatePipe (&r, &w, &sec_attr, 0)) + return -1; + + if (!DuplicateHandle (GetCurrentProcess(), w, + GetCurrentProcess(), &h, 0, + TRUE, DUPLICATE_SAME_ACCESS )) + { + log_error ("DuplicateHandle failed: %s\n", w32_strerror (-1)); + CloseHandle (r); + CloseHandle (w); + return -1; + } + CloseHandle (w); + w = h; + + filedes[0] = handle_to_fd (r); + filedes[1] = handle_to_fd (w); + return 0; +} +#endif /*HAVE_W32_SYSTEM*/ + + /* Fork and exec the PGMNAME, connect the file descriptor of INFILE to stdin, write the output to OUTFILE, return a new stream in @@ -73,10 +174,121 @@ gnupg_spawn_process (const char *pgmname, const char *argv[], void (*preexec)(void), FILE **statusfile, pid_t *pid) { -#ifdef _WIN32 - return gpg_error (GPG_ERR_NOT_IMPLEMENTED); +#ifdef HAVE_W32_SYSTEM + gpg_error_t err; + SECURITY_ATTRIBUTES sec_attr; + PROCESS_INFORMATION pi = + { + NULL, /* Returns process handle. */ + 0, /* Returns primary thread handle. */ + 0, /* Returns pid. */ + 0 /* Returns tid. */ + }; + STARTUPINFO si; + int cr_flags; + char *cmdline; + int fd, fdout, rp[2]; -#else /* !_WIN32 */ + /* Setup return values. */ + *statusfile = NULL; + *pid = (pid_t)(-1); + fflush (infile); + rewind (infile); + fd = _get_osfhandle (fileno (infile)); + fdout = _get_osfhandle (fileno (outfile)); + if (fd == -1 || fdout == -1) + log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n"); + + /* Prepare security attributes. */ + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + /* Build the command line. */ + err = build_w32_commandline (pgmname, argv, &cmdline); + if (err) + return err; + + /* Create a pipe. */ + if (create_inheritable_pipe (rp)) + { + err = gpg_error (GPG_ERR_GENERAL); + log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); + xfree (cmdline); + return err; + } + + /* Start the process. Note that we can't run the PREEXEC function + because this would change our own environment. */ + memset (&si, 0, sizeof si); + si.cb = sizeof (si); + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE; + si.hStdInput = fd_to_handle (fd); + si.hStdOutput = fd_to_handle (fdout); + si.hStdError = fd_to_handle (rp[1]); + + cr_flags = (CREATE_DEFAULT_ERROR_MODE + | GetPriorityClass (GetCurrentProcess ()) + | CREATE_SUSPENDED); + log_debug ("CreateProcess, path=`%s' cmdline=`%s'", pgmname, cmdline); + if (!CreateProcess (pgmname, /* Program to start. */ + cmdline, /* Command line arguments. */ + &sec_attr, /* Process security attributes. */ + &sec_attr, /* Thread security attributes. */ + TRUE, /* Inherit handles. */ + cr_flags, /* Creation flags. */ + NULL, /* Environment. */ + NULL, /* Use current drive/directory. */ + &si, /* Startup information. */ + &pi /* Returns process information. */ + )) + { + log_error ("CreateProcess failed: %s\n", w32_strerror (-1)); + xfree (cmdline); + CloseHandle (fd_to_handle (rp[0])); + CloseHandle (fd_to_handle (rp[1])); + return gpg_error (GPG_ERR_GENERAL); + } + xfree (cmdline); + cmdline = NULL; + + /* Close the other end of the pipe. */ + CloseHandle (fd_to_handle (rp[1])); + + log_debug ("CreateProcess ready: hProcess=%p hThread=%p" + " dwProcessID=%d dwThreadId=%d\n", + pi.hProcess, pi.hThread, + (int) pi.dwProcessId, (int) pi.dwThreadId); + + /* Process ha been created suspended; resume it now. */ + ResumeThread (pi.hThread); + CloseHandle (pi.hThread); + + { + int x; + + x = _open_osfhandle (rp[0], 0); + if (x == -1) + log_error ("failed to translate osfhandle %p\n", (void*)rp[0] ); + else + { + log_debug ("_open_osfhandle %p yields %d\n", (void*)fd, x ); + *statusfile = fdopen (x, "r"); + } + } + if (!*statusfile) + { + err = gpg_error_from_errno (errno); + log_error (_("can't fdopen pipe for reading: %s\n"), gpg_strerror (err)); + CloseHandle (pi.hProcess); + return err; + } + + *pid = handle_to_pid (pi.hProcess); + return 0; + +#else /* !HAVE_W32_SYSTEM */ gpg_error_t err; int fd, fdout, rp[2]; @@ -87,8 +299,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[], fd = fileno (infile); fdout = fileno (outfile); if (fd == -1 || fdout == -1) - log_fatal ("no file descriptor for file passed" - " to gnupg_spawn_process: %s\n", strerror (errno) ); + log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n"); if (pipe (rp) == -1) { @@ -170,7 +381,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[], } return 0; -#endif /* !_WIN32 */ +#endif /* !HAVE_W32_SYSTEM */ } @@ -183,10 +394,51 @@ gnupg_wait_process (const char *pgmname, pid_t pid) { gpg_err_code_t ec; -#ifdef _WIN32 - ec = GPG_ERR_NOT_IMPLEMENTED; +#ifdef HAVE_W32_SYSTEM + HANDLE proc = fd_to_handle (pid); + int code; + DWORD exc; + + if (pid == (pid_t)(-1)) + return gpg_error (GPG_ERR_INV_VALUE); + + /* FIXME: We should do a pth_waitpid here. However this has not yet + been implemented. A special W32 pth system call would even be + better. */ + code = WaitForSingleObject (proc, INFINITE); + switch (code) + { + case WAIT_FAILED: + log_error (_("waiting for process %d to terminate failed: %s\n"), + (int)pid, w32_strerror (-1)); + ec = GPG_ERR_GENERAL; + break; + + case WAIT_OBJECT_0: + if (!GetExitCodeProcess (proc, &exc)) + { + log_error (_("error getting exit code of process %d: %s\n"), + (int)pid, w32_strerror (-1) ); + ec = GPG_ERR_GENERAL; + } + else if (exc) + { + log_error (_("error running `%s': exit status %d\n"), + pgmname, (int)exc ); + ec = GPG_ERR_GENERAL; + } + else + ec = 0; + break; + + default: + log_error ("WaitForSingleObject returned unexpected " + "code %d for pid %d\n", code, (int)pid ); + ec = GPG_ERR_GENERAL; + break; + } -#else /* !_WIN32 */ +#else /* !HAVE_W32_SYSTEM */ int i, status; if (pid == (pid_t)(-1)) @@ -222,7 +474,7 @@ gnupg_wait_process (const char *pgmname, pid_t pid) } else ec = 0; -#endif /* !_WIN32 */ +#endif /* !HAVE_W32_SYSTEM */ return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec); diff --git a/common/iobuf.c b/common/iobuf.c index 4d735397e..52a388514 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -1096,7 +1096,7 @@ iobuf_cancel (iobuf_t a) if (s && *s) { #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__) - remove_name = m_strdup (s); + remove_name = xstrdup (s); #else remove (s); #endif @@ -1267,7 +1267,7 @@ iobuf_sockopen (int fd, const char *mode) size_t len; a = iobuf_alloc (strchr (mode, 'w') ? 2 : 1, 8192); - scx = m_alloc (sizeof *scx + 25); + scx = xmalloc (sizeof *scx + 25); scx->sock = fd; scx->print_only_name = 1; sprintf (scx->fname, "[sock %d]", fd); diff --git a/common/simple-pwquery.c b/common/simple-pwquery.c index 1e8eae63b..e7f992a88 100644 --- a/common/simple-pwquery.c +++ b/common/simple-pwquery.c @@ -31,7 +31,7 @@ #include <string.h> #include <errno.h> #include <unistd.h> -#ifdef _WIN32 +#ifdef HAVE_W32_SYSTEM #include <winsock2.h> #else #include <sys/socket.h> @@ -182,10 +182,8 @@ agent_send_all_options (int fd) } dft_ttyname = getenv ("GPG_TTY"); -#ifndef HAVE_W32_SYSTEM if ((!dft_ttyname || !*dft_ttyname) && ttyname (0)) dft_ttyname = ttyname (0); -#endif if (dft_ttyname && *dft_ttyname) { if ((rc=agent_send_option (fd, "ttyname", dft_ttyname))) @@ -261,7 +259,7 @@ agent_send_all_options (int fd) static int agent_open (int *rfd) { -#ifdef _WIN32 +#ifdef HAVE_W32_SYSTEM return SPWQ_NO_AGENT; /* FIXME */ #else int rc; diff --git a/common/sysutils.h b/common/sysutils.h index 66f714acd..9df292031 100644 --- a/common/sysutils.h +++ b/common/sysutils.h @@ -27,5 +27,12 @@ int enable_core_dumps (void); const unsigned char *get_session_marker (size_t *rlen); int check_permissions (const char *path,int extension,int checkonly); +#ifdef HAVE_W32_SYSTEM +/*-- w32reg.c --*/ +char *read_w32_registry_string( const char *root, + const char *dir, const char *name ); +int write_w32_registry_string(const char *root, const char *dir, + const char *name, const char *value); +#endif /*HAVE_W32_SYSTEM*/ #endif /*GNUPG_COMMON_SYSUTILS_H*/ diff --git a/common/ttyname.c b/common/ttyname.c new file mode 100644 index 000000000..822beef99 --- /dev/null +++ b/common/ttyname.c @@ -0,0 +1,32 @@ +/* ttyname.c - Replacement for ttyname. + * Copyright (C) 2004 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of 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. + * + * GnuPG 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* This one is a simple dummy and suitable for Dosish systems. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> + +char * +ttyname (int fd) +{ + return NULL; +} diff --git a/common/util.h b/common/util.h index fad7d38cc..0b9357d3a 100644 --- a/common/util.h +++ b/common/util.h @@ -147,7 +147,9 @@ int asprintf (char **result, const char *format, ...) JNLIB_GCC_A_PRINTF(2,3); #ifndef HAVE_STRSEP char *strsep (char **stringp, const char *delim); #endif - +#ifndef HAVE_TTYNAME +char *ttyname (int fd); +#endif /*-- some macros to replace ctype ones and avoid locale problems --*/ #define spacep(p) (*(p) == ' ' || *(p) == '\t') diff --git a/common/w32reg.c b/common/w32reg.c index 19fb613e7..a85ac7348 100644 --- a/common/w32reg.c +++ b/common/w32reg.c @@ -19,7 +19,7 @@ */ #include <config.h> -#if defined (_WIN32) || defined (__CYGWIN32__) +#ifdef HAVE_W32_SYSTEM /* This module is only used in this environment */ #include <stdio.h> @@ -29,6 +29,7 @@ #include <windows.h> #include "util.h" +#include "sysutils.h" static HKEY get_root_key(const char *root) @@ -169,4 +170,4 @@ write_w32_registry_string(const char *root, const char *dir, return 0; } -#endif /* __MINGW32__ || __CYGWIN32__ */ +#endif /*HAVE_W32_SYSTEM*/ |