/* This is the default inquiry callback. It merely handles the Pinentry notification. */ static gpg_error_t default_inq_cb (void *opaque, const char *line) { (void)opaque; if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17])) { gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10)); /* We do not return errors to avoid breaking other code. */ } else log_debug ("ignoring gpg-agent inquiry '%s'\n", line); return 0; }
/* This is the default inquiry callback. It mainly handles the Pinentry notifications. */ static gpg_error_t default_inq_cb (void *opaque, const char *line) { (void)opaque; if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17])) { /* There is no working server mode yet thus we use AllowSetForegroundWindow window right here. We might want to do this anyway in case gpg is called on the console. */ gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10)); /* We do not pass errors to avoid breaking other code. */ } else log_debug ("ignoring gpg-agent inquiry `%s'\n", line); return 0; }
/* Helper to notify the client about Pinentry events. Because that might disturb some older clients, this is only done when enabled via an option. If it is not enabled we tell Windows to allow setting the foreground window right here. Returns an gpg error code. */ gpg_error_t gpg_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line) { if (!ctrl || !ctrl->server_local || !ctrl->server_local->allow_pinentry_notify) { gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10)); /* Client might be interested in that event - send as status line. */ if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17])) { for (line += 17; *line && spacep (line); line++) ; write_status_text (STATUS_PINENTRY_LAUNCHED, line); } return 0; } return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0); }
/* Fork and exec the PGMNAME, see exechelp.h for details. */ gpg_error_t gnupg_spawn_process (const char *pgmname, const char *argv[], gpg_err_source_t errsource, void (*preexec)(void), unsigned int flags, estream_t infp, estream_t *r_outfp, estream_t *r_errfp, pid_t *pid) { 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; HANDLE inhandle = INVALID_HANDLE_VALUE; HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; estream_t outfp = NULL; estream_t errfp = NULL; HANDLE nullhd[3] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; int i; es_syshd_t syshd; if (r_outfp) *r_outfp = NULL; if (r_errfp) *r_errfp = NULL; *pid = (pid_t)(-1); /* Always required. */ if (infp) { es_fflush (infp); es_rewind (infp); es_syshd (infp, &syshd); switch (syshd.type) { case ES_SYSHD_FD: inhandle = (HANDLE)_get_osfhandle (syshd.u.fd); break; case ES_SYSHD_SOCK: inhandle = (HANDLE)_get_osfhandle (syshd.u.sock); break; case ES_SYSHD_HANDLE: inhandle = syshd.u.handle; break; default: inhandle = INVALID_HANDLE_VALUE; break; } if (inhandle == INVALID_HANDLE_VALUE) return gpg_err_make (errsource, GPG_ERR_INV_VALUE); /* FIXME: In case we can't get a system handle (e.g. due to es_fopencookie we should create a piper and a feeder thread. */ } if (r_outfp) { if (create_inheritable_pipe (outpipe, 1)) { err = gpg_err_make (errsource, GPG_ERR_GENERAL); log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); return err; } syshd.type = ES_SYSHD_HANDLE; syshd.u.handle = outpipe[0]; outfp = es_sysopen (&syshd, "r"); if (!outfp) { err = gpg_err_make (errsource, gpg_err_code_from_syserror ()); log_error (_("error creating a stream for a pipe: %s\n"), gpg_strerror (err)); CloseHandle (outpipe[0]); CloseHandle (outpipe[1]); outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE; return err; } } if (r_errfp) { if (create_inheritable_pipe (errpipe, 1)) { err = gpg_err_make (errsource, GPG_ERR_GENERAL); log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); return err; } syshd.type = ES_SYSHD_HANDLE; syshd.u.handle = errpipe[0]; errfp = es_sysopen (&syshd, "r"); if (!errfp) { err = gpg_err_make (errsource, gpg_err_code_from_syserror ()); log_error (_("error creating a stream for a pipe: %s\n"), gpg_strerror (err)); CloseHandle (errpipe[0]); CloseHandle (errpipe[1]); errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE; if (outfp) es_fclose (outfp); else if (outpipe[0] != INVALID_HANDLE_VALUE) CloseHandle (outpipe[0]); if (outpipe[1] != INVALID_HANDLE_VALUE) CloseHandle (outpipe[1]); return err; } } /* 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; if (inhandle != INVALID_HANDLE_VALUE) nullhd[0] = w32_open_null (0); if (outpipe[1] != INVALID_HANDLE_VALUE) nullhd[1] = w32_open_null (0); if (errpipe[1] != INVALID_HANDLE_VALUE) nullhd[2] = w32_open_null (0); /* Start the process. Note that we can't run the PREEXEC function because this might change our own environment. */ (void)preexec; 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 = inhandle == INVALID_HANDLE_VALUE? nullhd[0] : inhandle; si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1]; si.hStdError = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1]; cr_flags = (CREATE_DEFAULT_ERROR_MODE | ((flags & 128)? DETACHED_PROCESS : 0) | GetPriorityClass (GetCurrentProcess ()) | CREATE_SUSPENDED); /* log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", 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); if (outfp) es_fclose (outfp); else if (outpipe[0] != INVALID_HANDLE_VALUE) CloseHandle (outpipe[0]); if (outpipe[1] != INVALID_HANDLE_VALUE) CloseHandle (outpipe[1]); if (errfp) es_fclose (errfp); else if (errpipe[0] != INVALID_HANDLE_VALUE) CloseHandle (errpipe[0]); if (errpipe[1] != INVALID_HANDLE_VALUE) CloseHandle (errpipe[1]); return gpg_err_make (errsource, GPG_ERR_GENERAL); } xfree (cmdline); cmdline = NULL; /* Close the inherited handles to /dev/null. */ for (i=0; i < DIM (nullhd); i++) if (nullhd[i] != INVALID_HANDLE_VALUE) CloseHandle (nullhd[i]); /* Close the inherited ends of the pipes. */ if (outpipe[1] != INVALID_HANDLE_VALUE) CloseHandle (outpipe[1]); if (errpipe[1] != INVALID_HANDLE_VALUE) CloseHandle (errpipe[1]); /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */ /* " dwProcessID=%d dwThreadId=%d\n", */ /* pi.hProcess, pi.hThread, */ /* (int) pi.dwProcessId, (int) pi.dwThreadId); */ /* log_debug (" outfp=%p errfp=%p\n", outfp, errfp); */ /* Fixme: For unknown reasons AllowSetForegroundWindow returns an invalid argument error if we pass it the correct processID. As a workaround we use -1 (ASFW_ANY). */ if ( (flags & 64) ) gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/); /* Process has been created suspended; resume it now. */ ResumeThread (pi.hThread); CloseHandle (pi.hThread); if (r_outfp) *r_outfp = outfp; if (r_errfp) *r_errfp = errfp; *pid = handle_to_pid (pi.hProcess); return 0; }