Mercurial > trustbridge
view cinst/main.c @ 502:e551de11d8b6
Properly handle the case that the file does not exist.
TRUNCATE makes create file fail if the file does not exist
but we need TRUNCATE in the case that the file already exists
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Mon, 28 Apr 2014 09:18:07 +0000 |
parents | f925ddfe6301 |
children | f595fcbe3e76 |
line wrap: on
line source
/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik * Software engineering by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ /** * @file main.c * @brief Main entry point for the cinst process. * * The cinst process may or may not be run with elevated * privileges. When run with elevated privileges this * process will modify system wide certificate stores. * Otherwise only the users certificate stores are modified. * * The first parameter to this process should be list=<file_name> * of the certificate list to work on. The second parameter should * be choices=<choices_file_name>|uninstall * * choices_file_name should be the absolute path to an * choices file formatted as: * * I:<certificate> * R:<certificate> * * Line breaks can be system dependent in the Choices file. * * It will only execute the choices if the * I and R choices 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 * to remove all certificates (Even those marked with I) that * are part of the list. * **/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <stdbool.h> #include "strhelp.h" #include "listutil.h" #include "logging.h" #include "errorcodes.h" #include "windowsstore.h" #include "nssstore.h" /* The certificate list + choices may only be so long as * twice the accepted certificatelist size */ #define MAX_INPUT_SIZE MAX_LINE_LENGTH * MAX_LINES * 2 /* @brief Read stdin into data structures. * * Reads choices from an input file into the to_install * and to_remove buffers. * * Lines starting with I: are treated as install choices. * Lines starting with R: are treated as remove choices. * 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. * * @param[in] file_name absolute path to the choices file. * @param[out] to_install strv of installation choices or NULL * @param[out] to_remove strv of remove choices or NULL * * @returns: 0 on success. An error code otherwise. */ static int read_choices_file (char *file_name, char ***to_install, char ***to_remove) { int lines_read = 0; char buf[MAX_LINE_LENGTH + 2]; FILE *f = NULL; long file_size; if (*to_install || *to_remove) { printf ("Error invalid parameters.\n"); return -1; } 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) { 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"); fclose (f); return ERR_INVALID_INPUT; } if (lines_read++ > MAX_LINES) { printf ("Too many lines\n"); fclose (f); return ERR_TOO_MUCH_INPUT; } if (*buf == 'I') { char *trimmed = buf+2; /* Remove leading I: and trailing whitespace */ str_trim(&trimmed); strv_append (to_install, trimmed, strlen(trimmed)); continue; } if (*buf == 'R') { char *trimmed = buf+2; /* Remove leading R: and trailing whitespace */ str_trim(&trimmed); strv_append (to_remove, trimmed, strlen(trimmed)); continue; } } fclose (f); return 0; } /** @brief Check that the insturctions match to the list * * Only certificates part of the certificate_list are allowed * for installation. * * @param[in] all_certs strv of all valid certificates in a list * @param[in] to_validate strv of choices * * @returns 0 on success, an error otherwise */ int validate_choices (char **all_certs, char **to_validate) { int i = 0, j = 0; if (!all_certs || strv_length (all_certs) < 1) { /* Invalid parameters */ return -1; } if (to_validate == NULL) { /* Nothing is valid */ return 0; } for (i = 0; to_validate[i]; i++) { bool found = false; for (j = 0; all_certs[j]; j++) { if (strncmp (to_validate[i], all_certs[j], MAX_LINE_LENGTH) == 0) { found = true; break; } } if (!found) { DEBUGPRINTF ("Failed to find certificate; \n%s\n", to_validate[i]); return ERR_INVALID_INSTRUCTIONS; } } return 0; } int main (int argc, char **argv) { /* 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, *choices_file_name = NULL; size_t list_len = 0; list_status_t list_status; bool do_uninstall = false; /* Some very static argument parsing. list= and choices= 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], "choices=", 8) != 0) { ERRORPRINTF ("Invalid arguments.\n" "Expected arguments: list=<certificate_list> \n" " choices=<choices_file>|uninstall\n"); return ERR_INVALID_PARAMS; } certificate_file_name = strchr(argv[1], '=') + 1; choices_file_name = strchr(argv[2], '=') + 1; if (!certificate_file_name || !choices_file_name) { ERRORPRINTF ("Invalid arguments.\n" "Expected arguments: list=<certificate_list> \n" " choices=<choices_file>|uninstall\n"); return ERR_INVALID_PARAMS; } if (strncmp(choices_file_name, "uninstall", 9) == 0) { do_uninstall = true; choices_file_name = NULL; } list_status = read_and_verify_list (certificate_file_name, &certificate_list, &list_len); if (list_status != Valid) { if (list_status == InvalidSignature) { ERRORPRINTF ("Failed to verify signature.\n"); return ERR_INVALID_SIGNATURE; } ERRORPRINTF ("Failed to read certificate list.\n"); 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_choices_file (choices_file_name, &to_install, &to_remove); if (ret) { ERRORPRINTF ("Failed to read choices file\n"); return ret; } if (!strv_length (to_install) && !strv_length (to_remove) ) { ERRORPRINTF ("Failed to read choices file\n"); return ERR_NO_INSTRUCTIONS; } /* Check that the choices are ok to execute */ if (to_install) { ret = validate_choices (all_valid_certs, to_install); if (ret) { ERRORPRINTF ("Failed to validate choices\n"); return ret; } } if (to_remove) { ret = validate_choices (all_valid_certs, to_remove); if (ret) { ERRORPRINTF ("Failed to validate removal choices\n"); return ret; } } #ifdef WIN32 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); strv_free (to_remove); free (certificate_list); return 0; }