aheinecke@25: /** @brief Main entry point for the cinst process. aheinecke@25: * aheinecke@25: * The cinst process may or may not be run with elevated aheinecke@25: * privileges. When run with elevated privileges this aheinecke@25: * process will modify system wide certificate stores. aheinecke@25: * Otherwise only the users certificate stores are modified. aheinecke@25: * aheinecke@59: * It expects a certificatelist on stdin enclosed in a aheinecke@59: * -----BEGIN CERTIFICATE LIST----- aheinecke@59: * ... aheinecke@59: * -----END CERTIFICATE LIST----- aheinecke@59: * aheinecke@59: * Followed by additional instruction lines of: aheinecke@59: * I: aheinecke@59: * R: aheinecke@59: * aheinecke@59: * It will only execute the instructions if the aheinecke@59: * I and R instructions are also part of the signed aheinecke@59: * certificate list. The signature is validated with the aheinecke@59: * built in key. aheinecke@59: * aheinecke@59: * The special instruction "UNINSTALL" will cause the installer aheinecke@59: * to remove all certificates (Even those marked with I) that aheinecke@59: * are part of the list to be removed. aheinecke@25: * aheinecke@25: **/ aheinecke@59: #define MAX_LINE_LENGTH 1000 aheinecke@59: #define MAX_LINES 1000 aheinecke@59: #define MAX_INPUT_SIZE 2000000 /* MAX_LINE_LENGTH * (MAX_LINES *2) */ aheinecke@25: aheinecke@25: #include aheinecke@64: #include aheinecke@59: #include aheinecke@59: #include aheinecke@59: aheinecke@59: #include "strhelp.h" aheinecke@59: #include "listutil.h" aheinecke@60: #include "errorcodes.h" aheinecke@59: aheinecke@59: /* @brief Read stdin into data structures. aheinecke@59: * aheinecke@59: * Reads from stdin and sorts the input into the respective aheinecke@59: * variables. The pointers returned need to be freed by the caller. aheinecke@59: * Terminates in OOM conditions. aheinecke@59: * aheinecke@60: * The caller needs to free the memory allocated by this function aheinecke@60: * even when an error is returned. aheinecke@60: * aheinecke@60: * @returns: 0 on success. An error code otherwise. aheinecke@59: */ aheinecke@64: int readInput(char **certificate_list, char ***to_install, aheinecke@59: char ***to_remove) aheinecke@59: { aheinecke@59: int lines_read = 0; aheinecke@59: int readingList = 0; aheinecke@59: char buf[MAX_LINE_LENGTH + 1]; aheinecke@59: aheinecke@59: while (fgets(buf, MAX_LINE_LENGTH + 1, stdin)) { aheinecke@60: size_t len = strlen(buf); /* fgets ensures buf is terminated */ aheinecke@59: if (lines_read ++ > MAX_LINES) { aheinecke@59: printf("Too many lines\n"); aheinecke@60: return ERR_TOO_MUCH_INPUT; aheinecke@59: } aheinecke@64: if (strcmp("-----BEGIN CERTIFICATE LIST-----\r\n", buf) == 0){ aheinecke@59: readingList = 1; aheinecke@59: continue; aheinecke@59: } aheinecke@64: if (strcmp("-----END CERTIFICATE LIST-----\r\n", buf) == 0){ aheinecke@59: readingList = 0; aheinecke@59: continue; aheinecke@59: } aheinecke@59: if (readingList) { aheinecke@64: str_append_str(certificate_list, buf, len); aheinecke@59: continue; aheinecke@59: } aheinecke@59: if (*buf == 'I') { aheinecke@60: array_append_str(to_install, buf+2, len - 2); aheinecke@59: continue; aheinecke@59: } aheinecke@59: if (*buf == 'R') { aheinecke@60: array_append_str(to_remove, buf+2, len - 2); aheinecke@59: continue; aheinecke@59: } aheinecke@59: if (strcmp("UNINSTALL", buf) == 0) { aheinecke@60: array_append_str(to_remove, buf, len - 2); aheinecke@59: } aheinecke@59: } aheinecke@59: aheinecke@60: return 0; aheinecke@59: } aheinecke@25: aheinecke@64: int validate_instructions(const char *certificate_list, aheinecke@64: const size_t listLen, aheinecke@64: const char **to_install, aheinecke@64: const char **to_remove) aheinecke@64: { aheinecke@64: /* TODO */ aheinecke@64: return 0; aheinecke@64: } aheinecke@64: andre@26: int main() { aheinecke@59: char **to_install = NULL; aheinecke@59: char **to_remove = NULL; aheinecke@64: char *certificate_list = NULL; aheinecke@64: size_t listLen = 0; aheinecke@59: int ret = -1; aheinecke@59: aheinecke@64: ret = readInput(&certificate_list, &to_install, &to_remove); aheinecke@60: aheinecke@60: if (ret != 0) { aheinecke@60: return ret; aheinecke@60: } aheinecke@60: aheinecke@64: if (!certificate_list) { aheinecke@60: return ERR_INVALID_INPUT_NO_LIST; aheinecke@60: } aheinecke@59: aheinecke@64: listLen = strnlen(certificate_list, MAX_INPUT_SIZE); aheinecke@59: aheinecke@64: ret = verify_list(certificate_list, listLen); aheinecke@64: aheinecke@64: if (ret != 0) { aheinecke@64: return ERR_INVALID_SIGNATURE; aheinecke@64: } aheinecke@64: aheinecke@64: if (!strv_length(to_install) && !strv_length(to_remove)) { aheinecke@64: return ERR_NO_INSTRUCTIONS; aheinecke@64: } aheinecke@64: aheinecke@64: /* Check that the instructions are ok to execute */ aheinecke@64: ret = validate_instructions(certificate_list, to_install, to_remove); aheinecke@64: aheinecke@64: if (ret != 0) { aheinecke@64: return ERR_INVALID_INSTRUCTIONS; aheinecke@64: } aheinecke@64: aheinecke@64: /* Make valgrind happy */ aheinecke@64: strfreev (to_install); aheinecke@64: strfreev (to_remove); aheinecke@64: free (certificate_list); aheinecke@59: aheinecke@25: return 0; aheinecke@25: }