changeset 324:eff8e7ce4dae

Add first compiling implementation of nssstore_win.c
author Andre Heinecke <aheinecke@intevation.de>
date Mon, 07 Apr 2014 13:34:50 +0000
parents 31ba7ed4d50f
children c89bfb0e638e
files cinst/CMakeLists.txt cinst/main.c cinst/nssstore_win.c
diffstat 3 files changed, 262 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/cinst/CMakeLists.txt	Mon Apr 07 13:20:34 2014 +0200
+++ b/cinst/CMakeLists.txt	Mon Apr 07 13:34:50 2014 +0000
@@ -7,12 +7,13 @@
 set(CINST_SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/windowsstore.c
     ${CMAKE_CURRENT_SOURCE_DIR}/nssstore_linux.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nssstore_win.c
     ${CMAKE_CURRENT_SOURCE_DIR}/main.c
 )
 add_executable(cinst ${CINST_SOURCES})
 
 if (WIN32)
-   set(WIN_EXTRA_LIBS -lcrypt32)
+   set(WIN_EXTRA_LIBS -lcrypt32 -luserenv)
 endif(WIN32)
 
 target_link_libraries(cinst
--- a/cinst/main.c	Mon Apr 07 13:20:34 2014 +0200
+++ b/cinst/main.c	Mon Apr 07 13:34:50 2014 +0000
@@ -307,9 +307,7 @@
       ERRORPRINTF ("Failed to write windows stores retval: %i\n", ret);
     }
 #endif
-#ifndef WIN32 /* TODO Remove ifdef once it is implemented */
   ret = write_stores_nss (to_install, to_remove);
-#endif
   if (ret != 0)
     {
       ERRORPRINTF ("Failed to write nss stores");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cinst/nssstore_win.c	Mon Apr 07 13:34:50 2014 +0000
@@ -0,0 +1,260 @@
+#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

http://wald.intevation.org/projects/trustbridge/