changeset 289:9ad00a3255f4

Change cinst from stdin input to use arguments. As we have to execute this process on Windows over the shell a stdin / stdout communication is not really possible without some major hacks. So you now have to supply an instructions file and the path to the certificatelist as arguments when this process is called
author Andre Heinecke <aheinecke@intevation.de>
date Wed, 02 Apr 2014 13:52:02 +0000
parents c4a989a0d6cf
children b460d2cf088d
files cinst/main.c common/errorcodes.h
diffstat 2 files changed, 132 insertions(+), 110 deletions(-) [+]
line wrap: on
line diff
--- a/cinst/main.c	Wed Apr 02 13:49:04 2014 +0000
+++ b/cinst/main.c	Wed Apr 02 13:52:02 2014 +0000
@@ -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,6 +37,7 @@
 
 #include "strhelp.h"
 #include "listutil.h"
+#include "logging.h"
 #include "errorcodes.h"
 #include "windowsstore.h"
 
@@ -43,40 +47,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 +113,16 @@
           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);
+          /* Remove leading I: and trailing \n */
+          strv_append (to_install, buf + 2, len - 3);
           continue;
         }
       if (*buf == 'R')
         {
-          /* Remove leading R: and trailing \r\n */
-          strv_append (readingList ? all_certs : to_remove, buf + 2, len - 4);
+          /* Remove leading R: and trailing \n */
+          strv_append (to_remove, buf + 2, len - 3);
           continue;
         }
     }
@@ -189,47 +181,97 @@
 
 
 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;
+    }
+
+
+#ifdef WIN32
+  /* For uninstall we are done now */
+  if (do_uninstall)
+    {
+      return write_stores_win (NULL, all_valid_certs);
+    }
+#endif
+
+  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,35 +280,13 @@
 
   if (to_remove)
     {
-      if (to_remove[0]
-          && strncmp ("UNINSTALL", to_remove[0], MAX_LINE_LENGTH) == 0)
-        {
-          uninstall = true;
-          strv_free (to_remove);
-          to_remove = NULL;
-        }
-      else
+      ret = validate_instructions (all_valid_certs, to_remove);
+      if (ret)
         {
-          ret = validate_instructions (all_certs, to_remove);
-          if (ret)
-            {
-              return ret;
-            }
+          return ret;
         }
     }
 
-  if (uninstall)
-    {
-      /* To uninstall does not have to be verified as it part of the
-       * signed list.*/
-      to_remove = all_certs;
-    }
-  else
-    {
-      strv_free (all_certs);
-      all_certs = NULL;
-    }
-
 #ifdef WIN32
   return write_stores_win (to_install, to_remove);
 #endif
--- a/common/errorcodes.h	Wed Apr 02 13:49:04 2014 +0000
+++ b/common/errorcodes.h	Wed Apr 02 13:52:02 2014 +0000
@@ -3,7 +3,7 @@
 
 /* No error */
 #define ERR_NO_ERROR 0
-/* No begin certificate / end certificate could be found */
+/* Failed to read / verify the certificate list */
 #define ERR_INVALID_INPUT_NO_LIST 2
 /* Too much input for the installer process */
 #define ERR_TOO_MUCH_INPUT 3
@@ -21,6 +21,8 @@
 #define ERR_INVALID_INPUT 9
 /* Generic invalid certificate */
 #define ERR_INVALID_CERT 10
+/* Invalid parameters in call */
+#define ERR_INVALID_PARAMS 11
 
 /***********************************************************************
  * mozilla specific errors and warnings

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