diff cinst/main.c @ 310:f758460ca437

Merged
author Sascha Wilde <wilde@intevation.de>
date Fri, 04 Apr 2014 09:54:19 +0200
parents fac7e1b0e558
children f17226aa2e09
line wrap: on
line diff
--- a/cinst/main.c	Fri Apr 04 09:53:55 2014 +0200
+++ b/cinst/main.c	Fri Apr 04 09:54:19 2014 +0200
@@ -7,23 +7,26 @@
  *  process will modify system wide certificate stores.
  *  Otherwise only the users certificate stores are modified.
  *
- *  It expects a certificatelist on stdin enclosed in a
- *  -----BEGIN CERTIFICATE LIST-----
- *  ...
- *  -----END CERTIFICATE LIST-----
+ *  The first parameter to this process should be list=<file_name>
+ *  of the certificate list to work on. The second parameter should
+ *  be instruction=<instruction_file_name>|uninstall
  *
- *  Followed by additional instruction lines of:
+ *  instruction_file_name should be the absolute path to an
+ *  instructions file formatted as:
+ *
  *  I:<certificate>
  *  R:<certificate>
  *
+ *  Line breaks can be system dependent in the Instructions file.
+ *
  *  It will only execute the instructions if the
  *  I and R instructions are also part of the signed
  *  certificate list. The signature is validated with the
  *  built in key.
  *
- *  The special instruction "UNINSTALL" will cause the installer
+ *  The special instruction "uninstall" will cause the installer
  *  to remove all certificates (Even those marked with I) that
- *  are part of the list to be removed.
+ *  are part of the list.
  *
  **/
 #include <stdio.h>
@@ -34,8 +37,10 @@
 
 #include "strhelp.h"
 #include "listutil.h"
+#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 */
@@ -43,40 +48,62 @@
 
 /* @brief Read stdin into data structures.
  *
- * Reads from stdin and sorts the input into the respective
- * variables. The pointers returned need to be freed by the caller.
+ * Reads instructions from an input file into the to_install
+ * and to_remove buffers.
+ *
+ * Lines starting with I: are treated as install instructions.
+ * Lines starting with R: are treated as remove instructions.
+ * Other lines are ignored.
+ *
  * Terminates in OOM conditions.
  *
  * The caller needs to free the memory allocated by this function
  * even when an error is returned.
  *
- * Uninstall certificates are all certificates that are pa
- *
- * @param[out] certificate_list the parsed certificate list
+ * @param[in] file_name absolute path to the instructions file.
  * @param[out] to_install strv of installation instructions or NULL
  * @param[out] to_remove strv of remove instructions or NULL
- * @param[out] all_certs strv of uninstallation instructions or NULL
  *
  * @returns: 0 on success. An error code otherwise.
  */
-int
-readInput (char **certificate_list, char ***to_install,
-           char ***to_remove, char ***all_certs)
+static int
+read_instructions_file (char *file_name, char ***to_install,
+                        char ***to_remove)
 {
   int lines_read = 0;
-  int readingList = 0;
-  size_t list_size = 0;
   char buf[MAX_LINE_LENGTH + 2];
+  FILE *f = NULL;
+  long file_size;
 
-  if (*certificate_list || *to_install || *to_remove)
+  if (*to_install || *to_remove)
     {
-      printf ("Error invalid parameters\n");
+      printf ("Error invalid parameters.\n");
       return -1;
     }
 
-  while (fgets (buf, MAX_LINE_LENGTH + 1, stdin) )
+  f = fopen (file_name, "rb");
+  if (f == NULL)
+    return ERR_NO_INSTRUCTIONS;
+
+  fseek (f, 0, SEEK_END);
+  file_size = ftell (f);
+  if (file_size <= 0)
     {
-      size_t len = strlen (buf);	/* fgets ensures buf is terminated */
+      fclose (f);
+      return ERR_NO_INSTRUCTIONS;
+    }
+
+  fseek (f, 0, SEEK_SET);
+
+  if (file_size + 1 == 0)
+    {
+      fclose (f);
+      return ERR_INVALID_INSTRUCTIONS;
+    }
+
+  while (fgets (buf, MAX_LINE_LENGTH + 1, f) )
+    {
+      size_t len = strlen (buf); /* fgets ensures buf is terminated */
       if (len <= 3)
         {
           printf ("Line too short.\n");
@@ -87,50 +114,20 @@
           printf ("Too many lines\n");
           return ERR_TOO_MUCH_INPUT;
         }
-
-      if (buf[len - 2] != '\r')
-        {
-          if (buf[len - 1] != '\n')
-            {
-              printf ("Line too long.\n");
-              return ERR_INVALID_INPUT;
-            }
-          buf[len - 1] = '\r';
-          buf[len] = '\n';
-          buf[len + 1] = '\0';
-          len++;
-        }
-
-      if (strcmp ("-----BEGIN CERTIFICATE LIST-----\r\n", buf) == 0)
-        {
-          readingList = 1;
-          continue;
-        }
-      if (strcmp ("-----END CERTIFICATE LIST-----\r\n", buf) == 0)
-        {
-          readingList = 0;
-          continue;
-        }
-      if (readingList)
-        {
-          str_append_str (certificate_list, &list_size, buf, len);
-        }
-      else if (strcmp ("UNINSTALL\r\n", buf) == 0)
-        {
-          /* Remove trailing \r\n */
-          strv_append (to_remove, buf, len - 2);
-          continue;
-        }
       if (*buf == 'I')
         {
-          /* Remove leading I: and trailing \r\n */
-          strv_append (readingList ? all_certs : to_install, buf + 2, len - 4);
+          char *trimmed = buf+2;
+          /* Remove leading I: and trailing whitespace */
+          str_trim(&trimmed);
+          strv_append (to_install, trimmed, strlen(trimmed));
           continue;
         }
       if (*buf == 'R')
         {
-          /* Remove leading R: and trailing \r\n */
-          strv_append (readingList ? all_certs : to_remove, buf + 2, len - 4);
+          char *trimmed = buf+2;
+          /* Remove leading R: and trailing whitespace */
+          str_trim(&trimmed);
+          strv_append (to_remove, trimmed, strlen(trimmed));
           continue;
         }
     }
@@ -170,7 +167,7 @@
       bool found = false;
       for (j = 0; all_certs[j]; j++)
         {
-          if (strncmp (to_validate[i], all_certs[j], MAX_LINE_LENGTH - 2) ==
+          if (strncmp (to_validate[i], all_certs[j], MAX_LINE_LENGTH) ==
               0)
             {
               found = true;
@@ -179,7 +176,7 @@
         }
       if (!found)
         {
-          printf ("Install instruction with invalid certificate\n.");
+          DEBUGPRINTF ("Failed to find certificate; \n%s\n", to_validate[i]);
           return ERR_INVALID_INSTRUCTIONS;
         }
     }
@@ -189,47 +186,103 @@
 
 
 int
-main ()
+main (int argc, char **argv)
 {
-  char **to_install = NULL;
-  char **to_remove = NULL;
-  char **all_certs = NULL;
-  char *certificate_list = NULL;
+  /* TODO handle wchar arguments on Windows or do conversion dance */
+  char **to_install = NULL,
+       **to_remove = NULL,
+       **all_valid_certs = NULL;
+  int ret = -1;
+
+  char *certificate_list = NULL,
+       *certificate_file_name = NULL,
+       *instruction_file_name = NULL;
   size_t list_len = 0;
-  int ret = -1;
-  bool uninstall = false;
+  list_status_t list_status;
+  bool do_uninstall = false;
 
-  ret = readInput (&certificate_list, &to_install, &to_remove, &all_certs);
+  /* 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. */
+  if (argc != 3 || strncmp(argv[1], "list=", 5) != 0 ||
+                   strncmp(argv[2], "instructions=", 13) != 0)
+    {
+      ERRORPRINTF ("Invalid arguments.\n"
+                   "Expected arguments: list=<certificate_list> \n"
+                   "                    instructions=<instructions_file>|uninstall\n");
+      return ERR_INVALID_PARAMS;
+    }
+
+  certificate_file_name = strchr(argv[1], '=') + 1;
+  instruction_file_name = strchr(argv[2], '=') + 1;
+
+  if (!certificate_file_name || !instruction_file_name)
+    {
+      ERRORPRINTF ("Invalid arguments.\n"
+                   "Expected arguments: list=<certificate_list> \n"
+                   "                    instructions=<instructions_file>|uninstall\n");
+      return ERR_INVALID_PARAMS;
+    }
+
+  if (strncmp(instruction_file_name, "uninstall", 9) == 0)
+    {
+      do_uninstall = true;
+      instruction_file_name = NULL;
+    }
+
+  list_status = read_and_verify_list (certificate_file_name, &certificate_list,
+                                      &list_len);
+
+  if (list_status != Valid)
+    {
+      if (list_status == InvalidSignature)
+        {
+          return ERR_INVALID_SIGNATURE;
+        }
+
+      return ERR_INVALID_INPUT_NO_LIST;
+    }
+
+  all_valid_certs = get_certs_from_list (certificate_list, list_len);
+
+  if (!all_valid_certs)
+    {
+      /* Impossible */
+      return -1;
+    }
+
+
+  /* For uninstall we are done now */
+  if (do_uninstall)
+    {
+#ifdef WIN32
+      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,
+                                &to_remove);
 
   if (ret)
     {
       return ret;
     }
 
-  if (!certificate_list)
-    {
-      return ERR_INVALID_INPUT_NO_LIST;
-    }
-
-  list_len = strnlen (certificate_list, MAX_INPUT_SIZE);
-
-  ret = verify_list (certificate_list, list_len);
-
-  if (ret)
-    {
-      return ERR_INVALID_SIGNATURE;
-    }
-
   if (!strv_length (to_install) && !strv_length (to_remove) )
     {
       return ERR_NO_INSTRUCTIONS;
     }
 
-
   /* Check that the instructions are ok to execute */
   if (to_install)
     {
-      ret = validate_instructions (all_certs, to_install);
+      ret = validate_instructions (all_valid_certs, to_install);
       if (ret)
         {
           return ret;
@@ -238,39 +291,27 @@
 
   if (to_remove)
     {
-      if (to_remove[0]
-          && strncmp ("UNINSTALL", to_remove[0], MAX_LINE_LENGTH) == 0)
+      ret = validate_instructions (all_valid_certs, to_remove);
+      if (ret)
         {
-          uninstall = true;
-          strv_free (to_remove);
-          to_remove = NULL;
-        }
-      else
-        {
-          ret = validate_instructions (all_certs, to_remove);
-          if (ret)
-            {
-              return ret;
-            }
+          return ret;
         }
     }
 
-  if (uninstall)
+#ifdef WIN32
+  ret = write_stores_win (to_install, to_remove);
+  if (ret != 0)
     {
-      /* To uninstall does not have to be verified as it part of the
-       * signed list.*/
-      to_remove = all_certs;
+      ERRORPRINTF ("Failed to write windows stores retval: %i\n", ret);
     }
-  else
+#endif
+  ret = write_stores_nss (to_install, to_remove);
+
+  if (ret != 0)
     {
-      strv_free (all_certs);
-      all_certs = NULL;
+      ERRORPRINTF ("Failed to write nss stores");
     }
 
-#ifdef WIN32
-  return write_stores_win (to_install, to_remove);
-#endif
-
   /* Make valgrind happy */
   strv_free (to_install);
   strv_free (to_remove);

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