Mercurial > trustbridge
view cinst/nssstore_win.c @ 340:9001eaa55549
Add first draft of packaging to build upon
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Wed, 09 Apr 2014 17:39:24 +0000 |
parents | 1e6d1eab8395 |
children | c0eac5c8c245 |
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 <io.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) { \ DEBUGPRINTF(msg " : %s\n", my_error); \ ERRORPRINTF(msg" : %s\n", my_error); \ free (my_error); \ } \ DEBUGPRINTF ("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] base64 encoded der certificates to write * @param [in] write_handle to write to * @param [in] remove weather the certificate should be installed or removed * * @returns true on success, false on failure */ static bool write_instructions(char **certificates, HANDLE write_handle, bool remove) { int i = 0; int cHandle = -1; FILE *write_stream = NULL; if (!certificates) { return true; } cHandle = _open_osfhandle ((intptr_t)write_handle, 0); if (cHandle == -1) { ERRORPRINTF ("Failed to open write handle.\n"); } write_stream = _fdopen(cHandle, "w"); for (i = 0; certificates[i]; i++) { int ret = 0; DEBUGPRINTF("Writing \n"); if (remove) ret = fprintf (write_stream, "R:%s\n", certificates[i]); else ret = fprintf (write_stream, "I:%s\n", certificates[i]); if (ret <= 0) { DEBUGPRINTF ("Failed to write everything.\n"); break; } } DEBUGPRINTF("Write done\n"); 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_r; siStartInfo.dwFlags = STARTF_USESTDHANDLES; success = CreateProcessAsUserW (hToken, lpApplicationName, NULL, /* Commandline */ NULL, /* Process attributes. Take hToken */ NULL, /* Thread attribues. Take hToken */ TRUE, /* Inherit Handles */ CREATE_UNICODE_ENVIRONMENT, /* Creation flags. */ 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, false)) { ERRORPRINTF ("Failed to write install instructions.\n"); goto closepipes; } if (!write_instructions (to_remove, h_stdin_child_w, true)) { 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 (lpEnvironment) DestroyEnvironmentBlock (lpEnvironment); 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