From 88e973677c68f9573d7d5c0332bb0c3309c9c603 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 12 Jun 2009 16:58:45 +0000 Subject: [PATCH] Improved W32 SetForegroundWindow hacks. --- trunk/src/ChangeLog | 23 +++++++++ trunk/src/dirinfo.c | 2 +- trunk/src/engine-assuan.c | 2 +- trunk/src/engine-gpg.c | 6 +-- trunk/src/engine-gpgconf.c | 4 +- trunk/src/engine-gpgsm.c | 2 +- trunk/src/gpgme-w32spawn.c | 101 ++++++++++++++++++++++++++++++------- trunk/src/posix-io.c | 5 +- trunk/src/posix-util.c | 2 +- trunk/src/priv-io.h | 6 ++- trunk/src/util.h | 2 +- trunk/src/version.c | 2 +- trunk/src/w32-glib-io.c | 15 ++++-- trunk/src/w32-io.c | 18 ++++--- trunk/src/w32-qt-io.cpp | 11 ++-- trunk/src/w32-util.c | 19 +++++-- 16 files changed, 171 insertions(+), 49 deletions(-) diff --git a/trunk/src/ChangeLog b/trunk/src/ChangeLog index 3e03da5..db21dc4 100644 --- a/trunk/src/ChangeLog +++ b/trunk/src/ChangeLog @@ -1,3 +1,26 @@ +2009-06-12 Werner Koch + + * gpgme-w32spawn.c (translate_get_from_file): Parse optional spawn + flags. Add new arg R_FLAGS. Fix segv on file w/o LF. + (translate_handles): Add new arg R_FLAGS. Avoid possible segv. + (main): Pass flags for my_spawn. + (my_spawn): Add arg FLAGS and implement AllowSetForegroundWindow. + + * priv-io.h (IOSPAWN_FLAG_ALLOW_SET_FG): New. + * w32-io.c (_gpgme_io_spawn): Add arg FLAGS and implement it. + * w32-glib-io.c (_gpgme_io_spawn): Ditto. + * w32-qt-io.cpp (_gpgme_io_spawn): Ditto. + * posix-io.c (_gpgme_io_spawn): Add dummy arg FLAGS. + * engine-gpg.c (start): Call spawn with new flag. + + * w32-util.c (_gpgme_allow_set_foregound_window): Rename to + _gpgme_allow_set_foreground_window. Change all callers. + * posix-util.c (_gpgme_allow_set_foreground_window): Ditto. + +2009-06-10 Werner Koch + + * w32-util.c (_gpgme_allow_set_foregound_window): Add trace support. + 2009-06-09 Werner Koch * engine-gpg.c (gpg_io_event): Test for cmd.fd. diff --git a/trunk/src/dirinfo.c b/trunk/src/dirinfo.c index 45f09c0..ab15a59 100644 --- a/trunk/src/dirinfo.c +++ b/trunk/src/dirinfo.c @@ -102,7 +102,7 @@ read_gpgconf_dirs (void) cfd[0].fd = rp[1]; - status = _gpgme_io_spawn (pgmname, argv, cfd, NULL); + status = _gpgme_io_spawn (pgmname, argv, 0, cfd, NULL); if (status < 0) { _gpgme_io_close (rp[0]); diff --git a/trunk/src/engine-assuan.c b/trunk/src/engine-assuan.c index 12de042..08ae388 100644 --- a/trunk/src/engine-assuan.c +++ b/trunk/src/engine-assuan.c @@ -377,7 +377,7 @@ inquire_cb (engine_llass_t llass, const char *keyword, const char *args) if (llass->opt.gpg_agent && !strcmp (keyword, "PINENTRY_LAUNCHED")) { - _gpgme_allow_set_foregound_window ((pid_t)strtoul (args, NULL, 10)); + _gpgme_allow_set_foreground_window ((pid_t)strtoul (args, NULL, 10)); } if (llass->user.inq_cb) diff --git a/trunk/src/engine-gpg.c b/trunk/src/engine-gpg.c index 34bd613..eec3fa6 100644 --- a/trunk/src/engine-gpg.c +++ b/trunk/src/engine-gpg.c @@ -1328,7 +1328,9 @@ start (engine_gpg_t gpg) fd_list[n].dup_to = -1; status = _gpgme_io_spawn (gpg->file_name ? gpg->file_name : - _gpgme_get_gpg_path (), gpg->argv, fd_list, &pid); + _gpgme_get_gpg_path (), gpg->argv, + IOSPAWN_FLAG_ALLOW_SET_FG, + fd_list, &pid); saved_errno = errno; free (fd_list); @@ -1376,8 +1378,6 @@ start (engine_gpg_t gpg) } } - _gpgme_allow_set_foregound_window (pid); - gpg_io_event (gpg, GPGME_EVENT_START, NULL); /* fixme: check what data we can release here */ diff --git a/trunk/src/engine-gpgconf.c b/trunk/src/engine-gpgconf.c index d1f27c2..cfa04ce 100644 --- a/trunk/src/engine-gpgconf.c +++ b/trunk/src/engine-gpgconf.c @@ -221,7 +221,7 @@ gpgconf_read (void *engine, char *arg1, char *arg2, cfd[0].fd = rp[1]; - status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, NULL); + status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL); if (status < 0) { _gpgme_io_close (rp[0]); @@ -659,7 +659,7 @@ gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf) cfd[0].fd = rp[0]; - status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, NULL); + status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL); if (status < 0) { _gpgme_io_close (rp[0]); diff --git a/trunk/src/engine-gpgsm.c b/trunk/src/engine-gpgsm.c index 49d36c1..2d92732 100644 --- a/trunk/src/engine-gpgsm.c +++ b/trunk/src/engine-gpgsm.c @@ -292,7 +292,7 @@ default_inq_cb (engine_gpgsm_t gpgsm, const char *line) { if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17])) { - _gpgme_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10)); + _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10)); } return 0; diff --git a/trunk/src/gpgme-w32spawn.c b/trunk/src/gpgme-w32spawn.c index f132a8f..6f7c609 100644 --- a/trunk/src/gpgme-w32spawn.c +++ b/trunk/src/gpgme-w32spawn.c @@ -34,6 +34,13 @@ #include #include +/* Flag values as used by gpgme. */ +#define IOSPAWN_FLAG_ALLOW_SET_FG 1 + + +/* Name of this program. */ +#define PGM "gpgme-w32spawn" + struct spawn_fd_item_s @@ -101,7 +108,7 @@ build_commandline (char **argv) int -my_spawn (char **argv, struct spawn_fd_item_s *fd_list) +my_spawn (char **argv, struct spawn_fd_item_s *fd_list, unsigned int flags) { SECURITY_ATTRIBUTES sec_attr; PROCESS_INFORMATION pi = @@ -127,7 +134,7 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list) i = 0; while (argv[i]) { - fprintf (stderr, "argv[%2i] = %s\n", i, argv[i]); + fprintf (stderr, PGM": argv[%2i] = %s\n", i, argv[i]); i++; } @@ -147,7 +154,7 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list) si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE); si.hStdError = GetStdHandle (STD_ERROR_HANDLE); - fprintf (stderr, "spawning: %s\n", arg_string); + fprintf (stderr, PGM": spawning: %s\n", arg_string); for (i = 0; fd_list[i].handle != -1; i++) { @@ -156,19 +163,19 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list) { si.hStdInput = (HANDLE) fd_list[i].peer_name; duped_stdin = 1; - fprintf (stderr, "dup 0x%x to stdin\n", fd_list[i].peer_name); + fprintf (stderr, PGM": dup 0x%x to stdin\n", fd_list[i].peer_name); } else if (fd_list[i].dup_to == 1) { si.hStdOutput = (HANDLE) fd_list[i].peer_name; duped_stdout = 1; - fprintf (stderr, "dup 0x%x to stdout\n", fd_list[i].peer_name); + fprintf (stderr, PGM": dup 0x%x to stdout\n", fd_list[i].peer_name); } else if (fd_list[i].dup_to == 2) { si.hStdError = (HANDLE) fd_list[i].peer_name; duped_stderr = 1; - fprintf (stderr, "dup 0x%x to stderr\n", fd_list[i].peer_name); + fprintf (stderr, PGM":dup 0x%x to stderr\n", fd_list[i].peer_name); } } @@ -231,6 +238,33 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list) for (i = 0; fd_list[i].handle != -1; i++) CloseHandle ((HANDLE) fd_list[i].handle); + + if (flags & IOSPAWN_FLAG_ALLOW_SET_FG) + { + static int initialized; + static BOOL (WINAPI * func)(DWORD); + void *handle; + + if (!initialized) + { + /* Available since W2000; thus we dynload it. */ + initialized = 1; + handle = LoadLibrary ("user32.dll"); + if (handle) + { + func = GetProcAddress (handle, "AllowSetForegroundWindow"); + if (!func) + FreeLibrary (handle); + } + } + + if (func) + { + int rc = func (pi.dwProcessId); + fprintf (stderr, PGM": AllowSetForegroundWindow(%d): rc=%d\n", + (int)pi.dwProcessId, rc); + } + } ResumeThread (pi.hThread); CloseHandle (pi.hThread); @@ -244,12 +278,13 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list) int translate_get_from_file (const char *trans_file, - struct spawn_fd_item_s *fd_list) + struct spawn_fd_item_s *fd_list, + unsigned int *r_flags) { /* Hold roughly MAX_TRANS triplets of 64 bit numbers in hex notation: "0xFEDCBA9876543210". 10*19*4 - 1 = 759. This plans ahead for a time when a HANDLE is 64 bit. */ -#define BUFFER_MAX 800 +#define BUFFER_MAX 810 char line[BUFFER_MAX + 1]; char *linep; @@ -257,6 +292,8 @@ translate_get_from_file (const char *trans_file, int res; int fd; + *r_flags = 0; + fd = open (trans_file, O_RDONLY); if (fd < 0) return -1; @@ -269,10 +306,12 @@ translate_get_from_file (const char *trans_file, line[BUFFER_MAX] = '\0'; linep = strchr (line, '\n'); - if (linep > line && linep[-1] == '\r') - linep--; - *linep = '\0'; - + if (linep) + { + if (linep > line && linep[-1] == '\r') + linep--; + *linep = '\0'; + } linep = line; /* Now start to read mapping pairs. */ @@ -289,6 +328,21 @@ translate_get_from_file (const char *trans_file, linep++; if (*linep == '\0') break; + if (!idx && *linep == '~') + { + /* Spawn flags have been passed. */ + linep++; + *r_flags = strtoul (linep, &tail, 0); + if (tail == NULL || ! (*tail == '\0' || isspace (*tail))) + break; + linep = tail; + + while (isspace (*((unsigned char *)linep))) + linep++; + if (*linep == '\0') + break; + } + from = strtoul (linep, &tail, 0); if (tail == NULL || ! (*tail == '\0' || isspace (*tail))) break; @@ -339,13 +393,14 @@ translate_get_from_file (const char *trans_file, FD_LIST (which must be MAX_TRANS+1 large). */ char ** translate_handles (const char *trans_file, const char * const *argv, - struct spawn_fd_item_s *fd_list) + struct spawn_fd_item_s *fd_list, unsigned int *r_flags) { int res; int idx; + int n_args; char **args; - res = translate_get_from_file (trans_file, fd_list); + res = translate_get_from_file (trans_file, fd_list, r_flags); if (res < 0) return NULL; @@ -359,6 +414,7 @@ translate_handles (const char *trans_file, const char * const *argv, return NULL; } args[idx] = NULL; + n_args = idx; for (idx = 0; fd_list[idx].handle != -1; idx++) { @@ -369,6 +425,12 @@ translate_handles (const char *trans_file, const char * const *argv, if (aidx == 0) continue; + if (aidx >= n_args) + { + fprintf (stderr, PGM": translation file does not match args\n"); + return NULL; + } + args[aidx] = malloc (sizeof (buf)); /* We currently disable translation for stdin/stdout/stderr. We assume that the spawned program handles 0/1/2 specially @@ -394,6 +456,7 @@ main (int argc, const char * const *argv) int rc = 0; char **argv_spawn; struct spawn_fd_item_s fd_list[MAX_TRANS + 1]; + unsigned int flags; if (argc < 3) { @@ -401,7 +464,7 @@ main (int argc, const char * const *argv) goto leave; } - argv_spawn = translate_handles (argv[1], &argv[2], fd_list); + argv_spawn = translate_handles (argv[1], &argv[2], fd_list, &flags); if (!argv_spawn) { rc = 2; @@ -411,10 +474,10 @@ main (int argc, const char * const *argv) /* Using execv does not replace the existing program image, but spawns a new one and daemonizes it, confusing the command line interpreter. So we have to use spawnv. */ - rc = my_spawn (argv_spawn, fd_list); + rc = my_spawn (argv_spawn, fd_list, flags); if (rc < 0) { - fprintf (stderr, "gpgwrap: executing `%s' failed: %s\n", + fprintf (stderr, PGM": executing `%s' failed: %s\n", argv[0], strerror (errno)); rc = 2; goto leave; @@ -422,12 +485,12 @@ main (int argc, const char * const *argv) leave: if (rc) - fprintf (stderr, "gpg-w32spawn: internal error\n"); + fprintf (stderr, PGM": internal error\n"); /* Always try to delete the temporary file. */ if (argc >= 2) { if (DeleteFile (argv[1]) == 0) - fprintf (stderr, "Failed to delete %s: ec=%ld\n", + fprintf (stderr, PGM": failed to delete %s: ec=%ld\n", argv[1], GetLastError ()); } return rc; diff --git a/trunk/src/posix-io.c b/trunk/src/posix-io.c index c85255e..869d070 100644 --- a/trunk/src/posix-io.c +++ b/trunk/src/posix-io.c @@ -304,13 +304,16 @@ _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal) /* Returns 0 on success, -1 on error. */ int -_gpgme_io_spawn (const char *path, char *const argv[], +_gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags, struct spawn_fd_item_s *fd_list, pid_t *r_pid) { pid_t pid; int i; int status; int signo; + + (void)flags; + TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path, "path=%s", path); i = 0; diff --git a/trunk/src/posix-util.c b/trunk/src/posix-util.c index 9e66949..b0d17b0 100644 --- a/trunk/src/posix-util.c +++ b/trunk/src/posix-util.c @@ -67,7 +67,7 @@ _gpgme_get_conf_int (const char *key, int *value) } void -_gpgme_allow_set_foregound_window (pid_t pid) +_gpgme_allow_set_foreground_window (pid_t pid) { (void)pid; /* Not needed. */ diff --git a/trunk/src/priv-io.h b/trunk/src/priv-io.h index 4a87f65..7194a42 100644 --- a/trunk/src/priv-io.h +++ b/trunk/src/priv-io.h @@ -59,11 +59,15 @@ int _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler, void *value); int _gpgme_io_set_nonblocking (int fd); +/* A flag to tell the spawn function to allow the child process to set + the foreground window. */ +#define IOSPAWN_FLAG_ALLOW_SET_FG 1 + /* Spawn the executable PATH with ARGV as arguments. After forking close all fds except for those in FD_LIST in the child, then optionally dup() the child fds. Finally, all fds in the list are closed in the parent. */ -int _gpgme_io_spawn (const char *path, char *const argv[], +int _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags, struct spawn_fd_item_s *fd_list, pid_t *r_pid); int _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock); diff --git a/trunk/src/util.h b/trunk/src/util.h index d429d5d..a221bcc 100644 --- a/trunk/src/util.h +++ b/trunk/src/util.h @@ -33,7 +33,7 @@ const char *_gpgme_get_gpg_path (void); const char *_gpgme_get_gpgsm_path (void); const char *_gpgme_get_gpgconf_path (void); int _gpgme_get_conf_int (const char *key, int *value); -void _gpgme_allow_set_foregound_window (pid_t pid); +void _gpgme_allow_set_foreground_window (pid_t pid); /*-- dirinfo.c --*/ const char *_gpgme_get_default_homedir (void); diff --git a/trunk/src/version.c b/trunk/src/version.c index cef49a3..f777da4 100644 --- a/trunk/src/version.c +++ b/trunk/src/version.c @@ -310,7 +310,7 @@ _gpgme_get_program_version (const char *const file_name) cfd[0].fd = rp[1]; - status = _gpgme_io_spawn (file_name, argv, cfd, NULL); + status = _gpgme_io_spawn (file_name, argv, 0, cfd, NULL); if (status < 0) { _gpgme_io_close (rp[0]); diff --git a/trunk/src/w32-glib-io.c b/trunk/src/w32-glib-io.c index 5f8c886..c1542cc 100644 --- a/trunk/src/w32-glib-io.c +++ b/trunk/src/w32-glib-io.c @@ -584,7 +584,7 @@ build_commandline (char **argv) int -_gpgme_io_spawn (const char *path, char * const argv[], +_gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags, struct spawn_fd_item_s *fd_list, pid_t *r_pid) { SECURITY_ATTRIBUTES sec_attr; @@ -596,8 +596,8 @@ _gpgme_io_spawn (const char *path, char * const argv[], 0 /* returns tid */ }; STARTUPINFO si; - int cr_flags = CREATE_DEFAULT_ERROR_MODE - | GetPriorityClass (GetCurrentProcess ()); + int cr_flags = (CREATE_DEFAULT_ERROR_MODE + | GetPriorityClass (GetCurrentProcess ())); int i; char **args; char *arg_string; @@ -679,6 +679,9 @@ _gpgme_io_spawn (const char *path, char * const argv[], free (arg_string); + if (flags & IOSPAWN_FLAG_ALLOW_SET_FG) + _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId); + /* Insert the inherited handles. */ for (i = 0; fd_list[i].fd != -1; i++) { @@ -721,8 +724,10 @@ _gpgme_io_spawn (const char *path, char * const argv[], int written; size_t len; - line[0] = '\n'; - line[1] = '\0'; + if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG)) + strcpy (line, "~1 \n"); + else + strcpy (line, "\n"); for (i = 0; fd_list[i].fd != -1; i++) { /* Strip the newline. */ diff --git a/trunk/src/w32-io.c b/trunk/src/w32-io.c index 69d8a39..b6dd6fb 100644 --- a/trunk/src/w32-io.c +++ b/trunk/src/w32-io.c @@ -1009,7 +1009,7 @@ build_commandline (char **argv) int -_gpgme_io_spawn (const char *path, char *const argv[], +_gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags, struct spawn_fd_item_s *fd_list, pid_t *r_pid) { SECURITY_ATTRIBUTES sec_attr; @@ -1021,8 +1021,8 @@ _gpgme_io_spawn (const char *path, char *const argv[], 0 /* returns tid */ }; STARTUPINFO si; - int cr_flags = CREATE_DEFAULT_ERROR_MODE - | GetPriorityClass (GetCurrentProcess ()); + int cr_flags = (CREATE_DEFAULT_ERROR_MODE + | GetPriorityClass (GetCurrentProcess ())); int i; char **args; char *arg_string; @@ -1104,6 +1104,9 @@ _gpgme_io_spawn (const char *path, char *const argv[], free (arg_string); + if (flags & IOSPAWN_FLAG_ALLOW_SET_FG) + _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId); + /* Insert the inherited handles. */ for (i = 0; fd_list[i].fd != -1; i++) { @@ -1139,14 +1142,16 @@ _gpgme_io_spawn (const char *path, char *const argv[], notation: "0xFEDCBA9876543210" with an extra white space after every quadruplet. 10*(19*4 + 1) - 1 = 769. This plans ahead for a time when a HANDLE is 64 bit. */ -#define BUFFER_MAX 800 +#define BUFFER_MAX 810 char line[BUFFER_MAX + 1]; int res; int written; size_t len; - line[0] = '\n'; - line[1] = '\0'; + if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG)) + strcpy (line, "~1 \n"); + else + strcpy (line, "\n"); for (i = 0; fd_list[i].fd != -1; i++) { /* Strip the newline. */ @@ -1181,6 +1186,7 @@ _gpgme_io_spawn (const char *path, char *const argv[], if (r_pid) *r_pid = (pid_t)pi.dwProcessId; + if (ResumeThread (pi.hThread) < 0) TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ()); diff --git a/trunk/src/w32-qt-io.cpp b/trunk/src/w32-qt-io.cpp index 08f780f..03e9ea8 100644 --- a/trunk/src/w32-qt-io.cpp +++ b/trunk/src/w32-qt-io.cpp @@ -397,7 +397,7 @@ build_commandline (char **argv) int -_gpgme_io_spawn (const char *path, char * const argv[], +_gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags, struct spawn_fd_item_s *fd_list, pid_t *r_pid) { SECURITY_ATTRIBUTES sec_attr; @@ -492,6 +492,9 @@ _gpgme_io_spawn (const char *path, char * const argv[], free (arg_string); + if (flags & IOSPAWN_FLAG_ALLOW_SET_FG) + _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId); + /* Insert the inherited handles. */ for (i = 0; fd_list[i].fd != -1; i++) { @@ -533,8 +536,10 @@ _gpgme_io_spawn (const char *path, char * const argv[], int written; size_t len; - line[0] = '\n'; - line[1] = '\0'; + if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG)) + strcpy (line, "~1 \n"); + else + strcpy (line, "\n"); for (i = 0; fd_list[i].fd != -1; i++) { /* Strip the newline. */ diff --git a/trunk/src/w32-util.c b/trunk/src/w32-util.c index a4a01f4..a4b713e 100644 --- a/trunk/src/w32-util.c +++ b/trunk/src/w32-util.c @@ -393,7 +393,7 @@ _gpgme_get_conf_int (const char *key, int *value) void -_gpgme_allow_set_foregound_window (pid_t pid) +_gpgme_allow_set_foreground_window (pid_t pid) { static int initialized; static BOOL (WINAPI * func)(DWORD); @@ -416,9 +416,22 @@ _gpgme_allow_set_foregound_window (pid_t pid) } if (!pid || pid == (pid_t)(-1)) - ; + { + TRACE1 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0, + "no action for pid %d", (int)pid); + } else if (func) - func (pid); + { + int rc = func (pid); + TRACE2 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0, + "called for pid %d; result=%d", (int)pid, rc); + + } + else + { + TRACE0 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0, + "function not available"); + } } -- 2.26.2