Mercurial > trustbridge
view cinst/nssstore_win.c @ 328:18b31e2498a3
Build / dependency notes for nss
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Tue, 08 Apr 2014 14:50:31 +0000 |
parents | eff8e7ce4dae |
children | b1059360a0c7 |
line wrap: on
line source
#ifdef WIN32 /* @file @brief Windows implementation of nssstore process control. */ #include <windows.h> #include <stdio.h> #include <strsafe.h> #include <stdbool.h> #include <userenv.h> #include "logging.h" #include "util.h" #define PROCESS_TIMEOUT 30000 /* In milliseconds */ #define BUFSIZE 4096 /* used for reading childs stdout */ #define PRINTLASTERROR(msg) \ char *my_error = getLastErrorMsg(); \ if (my_error) { \ DEBUGMSG(msg " :"); \ DEBUGMSG(my_error); \ ERRORPRINTF(msg" : %s\n", my_error); \ free (my_error); \ } \ DEBUGMSG ("Failed to get error information\n"); /**@brief Write strv of instructions to a handle * * Writes the null terminated list of instructions to * the handle. * * @param [in] instructions instructions to write * @param [in] write_handle to write to * * @returns true on success, false on failure */ static bool write_instructions(char **instructions, HANDLE write_handle) { bool retval = false; int i = 0; const char *line_end = "\n\0"; if (!instructions) { return true; } for (i = 0; instructions[i]; i++) { DWORD written = 0; DWORD inst_len = strlen (instructions[i]); retval = WriteFile (write_handle, (LPCVOID) instructions[i], inst_len, &written, NULL); if (!retval) { PRINTLASTERROR ("Failed to write\n"); return false; } if (inst_len != written) { ERRORPRINTF ("Failed to write everything\n"); retval = false; return false; } written = 0; retval = WriteFile (write_handle, (LPCVOID) line_end, 2, &written, NULL); if (!retval) { PRINTLASTERROR ("Failed to write line end\n"); return false; } if (inst_len != written) { ERRORPRINTF ("Failed to write full line end\n"); retval = false; return false; } } return true; } /**@brief Start the process to install / remove * * Creates a child process with the Security handle specified in hToken * sends the instructions and then waits for the process to finish. * * If the process is not done in PROCESS_TIMEOUT seconds this assumes an * unknown error happened. * * @param [in] to_install strv of DER encoded certificates to be added. * @param [in] to_remove strv of DER encoded certificates to be remvoed. * @param [in] hToken handle to the primary token that is used to install * certificates. * * @returns true on success, false on error. */ static bool start_procces_for_user (char **to_install, char **to_remove, HANDLE hToken) { HANDLE h_stdin_child_r = NULL, h_stdin_child_w = NULL, h_stdout_child_r = NULL, h_stdout_child_w = NULL; SECURITY_ATTRIBUTES saAttr = {0}; /* TODO get this as absolute path based on current module location */ LPWSTR lpApplicationName = L"mozilla.exe"; PROCESS_INFORMATION piProcInfo = {0}; STARTUPINFOW siStartInfo = {0}; LPVOID lpEnvironment = NULL; BOOL success = FALSE; int retval = -1; saAttr.nLength = sizeof (SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; /* Use default */ /* Create a pipe for the child process's STDIN. */ if (!CreatePipe (&h_stdin_child_r, &h_stdin_child_w, &saAttr, 0)) { PRINTLASTERROR ("Create pipe failed.\n"); return -1; } /* Create a pipe for the child process's STDOUT. */ if (!CreatePipe (&h_stdout_child_r, &h_stdout_child_w, &saAttr, 0)) { PRINTLASTERROR ("Create pipe failed.\n"); return -1; } /* Ensure that read/write is properly inherited */ if (!SetHandleInformation (h_stdin_child_w, HANDLE_FLAG_INHERIT, 0) || !SetHandleInformation (h_stdout_child_r, HANDLE_FLAG_INHERIT, 0)) { PRINTLASTERROR ("SetHandleInformation failed.\n"); goto closepipes; } /* Create the environment for the user */ if (!CreateEnvironmentBlock (&lpEnvironment, hToken, FALSE)) { PRINTLASTERROR ("Failed to create the environment.\n"); goto closepipes; } /* set up handles. stdin and stdout go to the same stdout*/ siStartInfo.cb = sizeof (STARTUPINFO); siStartInfo.hStdError = h_stdout_child_w; siStartInfo.hStdOutput = h_stdout_child_w; siStartInfo.hStdInput = h_stdin_child_w; siStartInfo.dwFlags = STARTF_USESTDHANDLES; success = CreateProcessAsUserW (hToken, lpApplicationName, NULL, /* Commandline */ NULL, /* Process attributes. Take hToken */ NULL, /* Thread attribues. Take hToken */ TRUE, /* Inherit Handles */ 0, /* Creation flags. Use default */ lpEnvironment, NULL, /* Current working directory */ &siStartInfo, &piProcInfo); if (!success) { PRINTLASTERROR ("Failed to create process.\n"); goto closepipes; } if (!write_instructions (to_install, h_stdin_child_w)) { ERRORPRINTF ("Failed to write install instructions.\n"); goto closepipes; } if (!write_instructions (to_remove, h_stdin_child_w)) { ERRORPRINTF ("Failed to write remove instructions.\n"); goto closepipes; } /* Close the Handle so that the child knows we are finished telling it what to do */ CloseHandle (h_stdin_child_w); h_stdin_child_w = NULL; #ifndef RELEASE_BUILD /* print childs stdout / stderr to parents stdout */ { HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); DWORD read_bytes = 0; DWORD written = 0; bool success; char buf[BUFSIZE]; if (!stdout_handle || stdout_handle == INVALID_HANDLE_VALUE) { /* Should not happen */ ERRORPRINTF("Failed to get stdout handle.\n"); goto closeprocess; } for (;;) { success = ReadFile (h_stdout_child_r, buf, BUFSIZE, &read_bytes, NULL); if(!success || read_bytes == 0) break; success = WriteFile (stdout_handle, buf, read_bytes, &written, NULL); if (!success || written != read_bytes) break; } } #endif if (WaitForSingleObject (piProcInfo.hProcess, PROCESS_TIMEOUT) != WAIT_OBJECT_0) { /* Should not happen... */ ERRORPRINTF ("Failed to wait for process.\n"); } closeprocess: if (piProcInfo.hProcess) CloseHandle(piProcInfo.hProcess); if (piProcInfo.hThread) CloseHandle(piProcInfo.hThread); closepipes: if (h_stdin_child_w) CloseHandle(h_stdin_child_w); if (h_stdin_child_r) CloseHandle(h_stdin_child_r); if (h_stdout_child_w) CloseHandle(h_stdout_child_w); if (h_stdout_child_r) CloseHandle(h_stdout_child_r); return retval; } int write_stores_nss (char **to_install, char **to_remove) { HANDLE hToken = NULL; OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken); /* TODO loop over all users */ if (!start_procces_for_user (to_install, to_remove, hToken)) { ERRORPRINTF ("Failed to run NSS installation process.\n"); return -1; } return 0; } #endif