Mercurial > trustbridge
view cinst/main.c @ 363:d10d9bc2e84f
Update Windows api usage. Warning: To build on windows you need
a shell32.dll with SHGetKnownFolder
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Mon, 14 Apr 2014 16:57:41 +0000 |
parents | 5fa58979cb3a |
children | 124f08a85532 |
line wrap: on
line source
/** * @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 instruction=<instruction_file_name>|uninstall * * 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 * 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 + instructions 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 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. * * @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 * * @returns: 0 on success. An error code otherwise. */ static int read_instructions_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 instructions * * @returns 0 on success, an error otherwise */ int validate_instructions (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, *instruction_file_name = NULL; size_t list_len = 0; list_status_t list_status; bool do_uninstall = false; /* 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 (!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_valid_certs, to_install); if (ret) { return ret; } } if (to_remove) { ret = validate_instructions (all_valid_certs, to_remove); if (ret) { 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; }