int mailprivacy_spawn_and_wait(char * command, char * passphrase, char * stdoutfile, char * stderrfile, int * bad_passphrase) { #ifdef WIN32 int res; 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; HANDLE wp_passphrase[2]; HANDLE fd_out; HANDLE fd_err; int code; /* Prepare security attributes. */ memset (&sec_attr, 0, sizeof sec_attr); sec_attr.nLength = sizeof sec_attr; sec_attr.bInheritHandle = TRUE; fd_out = CreateFile (stdoutfile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sec_attr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fd_out == INVALID_HANDLE_VALUE) { res = ERROR_PASSPHRASE_FILE; goto err; } fd_err = CreateFile (stderrfile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sec_attr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fd_err == INVALID_HANDLE_VALUE) { res = ERROR_PASSPHRASE_FILE; goto close_out; } /* Create a pipe for the passphrase. */ if (create_inheritable_pipe (wp_passphrase)) { res = ERROR_PASSPHRASE_FILE; goto close_err; } /* Prepare security attributes. */ memset (&sec_attr, 0, sizeof sec_attr); sec_attr.nLength = sizeof sec_attr; sec_attr.bInheritHandle = FALSE; /* Start the process. */ 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 = wp_passphrase[0]; si.hStdOutput = fd_out; si.hStdError = fd_err; cr_flags = (CREATE_DEFAULT_ERROR_MODE | GetPriorityClass (GetCurrentProcess ()) | CREATE_SUSPENDED); if (!CreateProcess (NULL, /* Program to start. */ command, /* 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. */ )) { CloseHandle (wp_passphrase[0]); CloseHandle (wp_passphrase[1]); res = ERROR_PASSPHRASE_COMMAND; goto close_err; } /* Close the other end of the pipe. */ CloseHandle (wp_passphrase[0]); CloseHandle (fd_out); CloseHandle (fd_err); /* Process has been created suspended; resume it now. */ ResumeThread (pi.hThread); CloseHandle (pi.hThread); if ((passphrase != NULL) && (strlen(passphrase) > 0)) { DWORD written; WriteFile (wp_passphrase[1], passphrase, strlen(passphrase), &written, NULL); } else { DWORD written; /* dummy password */ WriteFile(wp_passphrase[1], "*dummy*", 7, &written, NULL); } CloseHandle(wp_passphrase[1]); code = WaitForSingleObject (pi.hProcess, INFINITE); if (code == WAIT_OBJECT_0) { DWORD exc; if (GetExitCodeProcess (pi.hProcess, &exc)) { if (exc) *bad_passphrase = 1; } else res = ERROR_PASSPHRASE_COMMAND; } else res = ERROR_PASSPHRASE_COMMAND; CloseHandle (pi.hProcess); return 0; close_err: CloseHandle (fd_err); close_out: CloseHandle (fd_out); err: return res; #else int res; int fd_out; int fd_err; pid_t pid; int passphrase_input[2]; int r; fd_out = open(stdoutfile, O_RDWR | O_CREAT | O_TRUNC, 0600); if (fd_out < 0) { res = ERROR_PASSPHRASE_FILE; goto err; } fd_err = open(stderrfile, O_RDWR | O_CREAT | O_TRUNC, 0600); if (fd_err < 0) { res = ERROR_PASSPHRASE_FILE; goto close_out; } r = pipe(passphrase_input); if (r < 0) { res = ERROR_PASSPHRASE_FILE; goto close_err; } pid = fork(); switch (pid) { case -1: { close (passphrase_input[0]); close (passphrase_input[1]); res = ERROR_PASSPHRASE_COMMAND; goto close_err; } case 0: /* child */ { int status; /* close unneeded fd */ close(passphrase_input[1]); dup2(passphrase_input[0], 0); close(passphrase_input[0]); dup2(fd_out, 1); close(fd_out); dup2(fd_err, 2); close(fd_err); status = system(command); exit(WEXITSTATUS(status)); } break; default: /* parent */ { int status; /* close unneeded fd */ close(fd_err); close(fd_out); close(passphrase_input[0]); if ((passphrase != NULL) && (strlen(passphrase) > 0)) { r = (int) write(passphrase_input[1], passphrase, strlen(passphrase)); if (r != (int) strlen(passphrase)) { close(passphrase_input[1]); return ERROR_PASSPHRASE_FILE; } } else { /* dummy password */ r = (int) write(passphrase_input[1], "*dummy*", 7); if (r != 7) { close(passphrase_input[1]); return ERROR_PASSPHRASE_FILE; } } close(passphrase_input[1]); waitpid(pid, &status, 0); if (WEXITSTATUS(status) != 0) *bad_passphrase = 1; return MAIL_NO_ERROR; } break; } close_err: close(fd_err); close_out: close(fd_out); err: return res; #endif }
/* Portable function to create a pipe. Under Windows the read end is inheritable (i.e. an rendezvous id). */ gpg_error_t gnupg_create_outbound_pipe (int filedes[2]) { return create_inheritable_pipe (filedes, 0); }