Mercurial > trustbridge
view cinst/main.c @ 92:4980b0deb773
Fix memleak in case of invalid signature
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Fri, 21 Mar 2014 09:47:54 +0000 |
parents | 80ab2168760f |
children | c602d8cfa619 |
line wrap: on
line source
/** @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. * * It expects a certificatelist on stdin enclosed in a * -----BEGIN CERTIFICATE LIST----- * ... * -----END CERTIFICATE LIST----- * * Followed by additional instruction lines of: * I:<certificate> * R:<certificate> * * 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 to be removed. * **/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <polarssl/base64.h> #include "strhelp.h" #include "listutil.h" #include "errorcodes.h" #ifdef WIN32 #include <windows.h> #include <wincrypt.h> #endif /* 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 from stdin and sorts the input into the respective * variables. The pointers returned need to be freed by the caller. * Terminates in OOM conditions. * * The caller needs to free the memory allocated by this function * even when an error is returned. * * @returns: 0 on success. An error code otherwise. */ int readInput(char **certificate_list, char ***to_install, char ***to_remove) { int lines_read = 0; int readingList = 0; size_t list_size = 0; char buf[MAX_LINE_LENGTH + 1]; if (*certificate_list || *to_install || *to_remove) { printf("Error invalid parameters\n"); return -1; } while (fgets(buf, MAX_LINE_LENGTH + 1, stdin)) { size_t len = strlen(buf); /* fgets ensures buf is terminated */ if (len < 2) { printf("Line to short.\n"); return ERR_INVALID_INPUT; } if (lines_read ++ > MAX_LINES) { printf("Too many lines\n"); return ERR_TOO_MUCH_INPUT; } 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); continue; } if (*buf == 'I') { /* Remove leading I: and trailing \r\n */ array_append_str(to_install, buf+2, len - 4); continue; } if (*buf == 'R') { /* Remove leading R: and trailing \r\n */ array_append_str(to_remove, buf+2, len - 4); continue; } if (strcmp("UNINSTALL", buf) == 0) { /* Remove trailing \r\n */ array_append_str(to_remove, buf, len - 2); } } return 0; } /* int validate_instructions(const char *certificate_list, const size_t list_len, const char **to_install, const char **to_remove) { TODO (void *) certificate_list; (void **) to_install; (void **) to_remove; (void) list_len; return 0; } */ #ifdef WIN32 /** @brief Install certificates into Windows store * * @param [in] to_install NULL terminated array of base64 encoded certificates. * @param [in] user_store set to True if the certificates shoudl be installed * only for the current user. O for system wide installation. * @returns 0 on success an errorcode otherwise. */ int install_certificates_win(const char **to_install, int user_store) { int i = 0; HCERTSTORE hStore = NULL; if (!user_store) { // Access user store hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, L"Root"); } else { // Access machine store hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"Root"); } if (!hStore) { return ERR_STORE_ACCESS_DENIED; } while (to_install[i]) { size_t needed_len = 0; size_t cert_len = strnlen(to_install[i], MAX_LINE_LENGTH); int ret = -1; unsigned char *buf; /* Check the needed size for the buffer */ ret = base64_decode(NULL, &needed_len, (unsigned char *)to_install[i], cert_len); if (ret != 0 && ret != POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL) { return ERR_INVALID_INSTRUCTIONS; } buf = xmalloc(needed_len); memset (buf, 0, needed_len); ret = base64_decode(buf, &needed_len, (unsigned char *)to_install[i], cert_len); if (ret != 0) { return ERR_INVALID_INSTRUCTIONS; } ret = CertAddEncodedCTLToStore (hStore, X509_ASN_ENCODING, (PBYTE)buf, needed_len, CERT_STORE_ADD_ALWAYS, NULL); if (ret != 0) { printf("Failed to add certificate\n"); free(buf); return ret; } free(buf); } if(hStore) { CertCloseStore(hStore, 0); } return 0; } #endif int main() { char **to_install = NULL; char **to_remove = NULL; char *certificate_list = NULL; size_t list_len = 0; int ret = -1; /* i = 0 , uninstall = 0; */ ret = readInput(&certificate_list, &to_install, &to_remove); if (ret != 0) { 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 != 0) { 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 ret = validate_instructions(certificate_list, list_len, to_install, to_remove); if (ret != 0) { return ERR_INVALID_INSTRUCTIONS; } if (to_remove) { for (i=0; to_remove[i]; i++) { if (strncmp("UNINSTALL", to_remove[i], MAX_LINE_LENGTH)) { uninstall = 1; break; } } } if (uninstall) { } */ #ifdef WIN32 install_certificates_win((const char**) to_install, 1); //remove_certificates_win((const char**) to_remove, 1); #endif /* Make valgrind happy */ strfreev(to_install); strfreev(to_remove); free(certificate_list); return 0; }