changeset 302:fac7e1b0e558

Add nss store calling function and use it in cinst
author Andre Heinecke <andre.heinecke@intevation.de>
date Thu, 03 Apr 2014 14:28:23 +0200
parents aec9008c3b30
children b54ab152a57e
files cinst/CMakeLists.txt cinst/main.c cinst/nssstore.h cinst/nssstore_linux.c
diffstat 4 files changed, 225 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/cinst/CMakeLists.txt	Thu Apr 03 14:26:43 2014 +0200
+++ b/cinst/CMakeLists.txt	Thu Apr 03 14:28:23 2014 +0200
@@ -6,6 +6,7 @@
 
 set(CINST_SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/windowsstore.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nssstore_linux.c
     ${CMAKE_CURRENT_SOURCE_DIR}/main.c
 )
 add_executable(cinst ${CINST_SOURCES})
--- a/cinst/main.c	Thu Apr 03 14:26:43 2014 +0200
+++ b/cinst/main.c	Thu Apr 03 14:28:23 2014 +0200
@@ -40,6 +40,7 @@
 #include "logging.h"
 #include "errorcodes.h"
 #include "windowsstore.h"
+#include "nssstore.h"
 
 /* The certificate list + instructions may only be so long as
  * twice the accepted certificatelist size */
@@ -200,11 +201,6 @@
   list_status_t list_status;
   bool do_uninstall = false;
 
-  for (ret = 0; ret < argc; ret++)
-    {
-      printf("Arg %i : %s \n", ret, argv[ret]);
-    }
-
   /* Some very static argument parsing. list= and instructions= is only
      added to make it more transparent how this programm is called if
      a user looks at the detailed uac dialog. */
@@ -260,11 +256,14 @@
   if (do_uninstall)
     {
 #ifdef WIN32
-      return write_stores_win (NULL, all_valid_certs);
-#else
-    /*TODO*/
-      return 0;
+      ret = write_stores_win (NULL, all_valid_certs);
+      if (ret != 0)
+        {
+          ERRORPRINTF ("Failed to write windows stores retval: %i\n", ret);
+        }
 #endif
+      ret = write_stores_nss (NULL, all_valid_certs);
+      return ret;
     }
 
   ret = read_instructions_file (instruction_file_name, &to_install,
@@ -300,8 +299,18 @@
     }
 
 #ifdef WIN32
-  return write_stores_win (to_install, to_remove);
+  ret = write_stores_win (to_install, to_remove);
+  if (ret != 0)
+    {
+      ERRORPRINTF ("Failed to write windows stores retval: %i\n", ret);
+    }
 #endif
+  ret = write_stores_nss (to_install, to_remove);
+
+  if (ret != 0)
+    {
+      ERRORPRINTF ("Failed to write nss stores");
+    }
 
   /* Make valgrind happy */
   strv_free (to_install);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cinst/nssstore.h	Thu Apr 03 14:28:23 2014 +0200
@@ -0,0 +1,27 @@
+#ifndef NSSSTORE_H
+#define NSSSTORE_H
+/** @file
+ * @brief Helper functions controlling the NSS installation process.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @brief Write into NSS stores
+ *
+ * Starts the nss installation process for all users
+ * we have the right to impersonate and installs / removes
+ * the certificates in their stores.
+
+ * @param [in] to_install strv of DER encoded certificates to be added.
+ * @param [in] to_remove strv of DER encoded certificates to be remvoed.
+ * @returns 0 on success an errorcode otherwise.
+ */
+int write_stores_nss (char **to_install, char **to_remove);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NSSSTORE_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cinst/nssstore_linux.c	Thu Apr 03 14:28:23 2014 +0200
@@ -0,0 +1,178 @@
+#ifndef WIN32
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "nssstore.h"
+#include "logging.h"
+#include "strhelp.h"
+
+/**@brief Start the process to install / remove
+ *
+ * This forks the process and executes the NSS installation
+ * process. It also writes the Instructions to that process.
+ *
+ * @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] uid_t uid of the user to install certificates for.
+ * @param [in] gid_t the gid of the user to install certificates for.
+ * @param [in] homedir the homedir of the user.
+ *
+ * @returns childs pid on success. -1 on failure
+ */
+static int
+start_procces_for_user (char **to_install, char **to_remove,
+                        uid_t uid, gid_t gid, char *homedir)
+{
+  int pipe_fd[2];
+  pid_t pid = 0;
+  char *argv[] = {"mozilla", NULL},
+       *envp[2];
+  size_t homedir_len = 0;
+  int ret = -1,
+      i = 0;
+  FILE *stream = NULL;
+  bool success = false;
+
+  if (homedir == NULL)
+    {
+      ERRORPRINTF ("Invalid call to start_process_for_user\n");
+      return -1;
+    }
+
+  homedir_len = strlen (homedir);
+
+  /* Allocate space for HOME=homedir\0 */
+  envp[0] = xmalloc (homedir_len + 6);
+  envp[1] = NULL;
+
+  ret = snprintf (envp[0], homedir_len + 6, "HOME=%s", homedir);
+
+  if (ret < 0 || (size_t) ret != homedir_len + 5)
+    {
+      ERRORPRINTF ("Error setting home env variable.\n");
+      xfree (envp[0]);
+      return -1;
+    }
+
+  DEBUGPRINTF ("Home: %s \n", envp[0]);
+
+  if (pipe (pipe_fd))
+    {
+      ERRORPRINTF ("Failed to create pipe.\n");
+      return -1;
+    }
+
+  pid = fork();
+
+  if (pid == (pid_t) -1)
+    {
+      ERRORPRINTF ("Failed to fork child.\n");
+      return -1;
+    }
+
+  if (pid == (pid_t) 0)
+    {
+      /* Drop privileges */
+      if (setuid (uid) || setgid (gid))
+        {
+          exit(-1);
+        }
+
+      close (pipe_fd[1]);
+      dup2 (pipe_fd[0], 0);
+      close (pipe_fd[0]);
+      /* TODO find path based on current executable */
+      execve ("mozilla", argv, envp);
+      exit (127);
+    }
+
+  close (pipe_fd[0]);
+  stream = fdopen(pipe_fd[1], "w");
+  if (stream == NULL)
+    {
+      ERRORPRINTF ("Failed to open pipe for writing\n");
+      goto done;
+    }
+
+  /* Send the instructions */
+  for (i = 0; to_install && to_install[i]; i++)
+    {
+      if (fprintf (stream, "I:%s\n", to_install[i]) <= 3)
+        {
+          ERRORPRINTF ("Write failed \n");
+          goto done;
+        }
+    }
+
+  for (i = 0; to_remove && to_remove[i]; i++)
+    {
+      if (fprintf (stream, "R:%s\n", to_remove[i]) <= 3)
+        {
+          ERRORPRINTF ("Write failed \n");
+          goto done;
+        }
+    }
+
+  success = true;
+
+done:
+  if (stream) {
+    fclose (stream);
+  }
+  xfree (envp[0]);
+  close(pipe_fd[0]);
+  close(pipe_fd[1]);
+
+  if (success)
+    {
+      return pid;
+    }
+  return -1;
+}
+
+int
+write_stores_nss (char **to_install, char **to_remove)
+{
+  uid_t my_uid = getuid();
+
+  if (my_uid != 0)
+    {
+      /* Running as a user */
+      char *homedir = getenv ("HOME");
+      pid_t childprocess = -1; /* Only one child for single user installation */
+      int status = -1;
+      if (!homedir)
+        {
+          ERRORPRINTF ("Failed to find home directory\n");
+        }
+
+      childprocess = start_procces_for_user (to_install, to_remove,
+                                             my_uid, getgid(), homedir);
+
+      if (childprocess == -1)
+        {
+          ERRORPRINTF ("Failed to start childprocess!\n");
+          return -1;
+        }
+
+      childprocess = waitpid (childprocess, &status, 0);
+      if (childprocess == -1 || !WIFEXITED(status))
+        {
+          ERRORPRINTF ("Waitpid failed.\n");
+          return -1;
+        }
+      DEBUGPRINTF ("Child returned status: %i", WEXITSTATUS(status));
+
+      return 0;
+    }
+  printf ("Installation as root is not yet implemented\n");
+  /* TODO root parse /etc/passwd for users with a home directory */
+  return 0;
+}
+#endif

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