aheinecke@44: aheinecke@44: #include aheinecke@44: #include aheinecke@44: #include aheinecke@44: #include aheinecke@44: #include aheinecke@44: #include aheinecke@44: #include aheinecke@44: aheinecke@99: /* @file Mozilla installation process aheinecke@99: * aheinecke@99: * Reads from stdin a list of instructions in the form: aheinecke@99: * aheinecke@99: * I:\r\n aheinecke@99: * R:\r\n aheinecke@99: * ... aheinecke@99: * aheinecke@99: * The maximum size of an input line is 1000 characters aheinecke@99: * (including the \r\n) at the end of the line. aheinecke@99: * aheinecke@99: * Certificates marked with I: will be installed and the ones aheinecke@99: * marked with R: will be searched and if available removed from aheinecke@99: * the databases. aheinecke@99: * aheinecke@99: * This tool tries to find all NSS databases the user has aheinecke@99: * access to and to execute the instructions on all of them. aheinecke@99: * aheinecke@99: * If there are other processes accessing the databases the caller aheinecke@99: * has to ensure that those are terminated before this process is aheinecke@99: * executed. aheinecke@99: * aheinecke@99: * Returns 0 on success (Even when no stores where found) an error value aheinecke@99: * as defined in errorcodes.h otherwise. aheinecke@99: * aheinecke@99: * Success messages are written to stdout. Errors to stderr. For logging aheinecke@99: * purposes each installation / removal of a certificate will be reported aheinecke@99: * with the profile name that it modified. aheinecke@99: * aheinecke@99: */ aheinecke@99: aheinecke@44: /* @brief IniParser for mozilla profiles.ini aheinecke@44: * aheinecke@44: * Parse data to find values formed in aheinecke@44: * aheinecke@44: * [Profile99] aheinecke@44: * IsRelative=1 aheinecke@44: * Path=Profiles/fooo.bar aheinecke@44: * aheinecke@44: * or aheinecke@44: * [Profile0] aheinecke@44: * IsRelative=0 aheinecke@44: * Path=c:\foo\bar\baz aheinecke@44: * aheinecke@44: * Mozilla also accepts the ini file on Windows even if it is UTF-16 aheinecke@44: * encoded. aheinecke@44: * */ aheinecke@44: aheinecke@44: aheinecke@44: /** aheinecke@44: * @brief Read a file into memory. aheinecke@44: * aheinecke@44: * @param[in] fileName Name of the file (UTF-8 encoded). aheinecke@44: * @param[out] data Newly allocated pointer to the file content. aheinecke@44: * @param[out] size Size in Bytes of the file content. aheinecke@44: * @param[in] maxSize the maximum size to read. aheinecke@44: * aheinecke@44: * @return 0 on success an error code otherwise. aheinecke@44: */ aheinecke@44: aheinecke@44: #define RAF_UNKNOWN -1 aheinecke@44: #define RAF_UNREADABLE -2 aheinecke@44: #define RAF_STATFAILED -3 aheinecke@44: #define RAF_TOOLARGE -4 aheinecke@44: #define RAF_OUTOFCORE -5 aheinecke@44: int readFile(const char *fileName, char **data, size_t *size, aheinecke@44: const size_t maxSize) aheinecke@44: { aheinecke@99: /* TODO aheinecke@99: * split out the read file from common/listutil.c and use that. */ aheinecke@44: int fd = -1; aheinecke@44: struct stat fileStat; aheinecke@44: int rc = 0; aheinecke@44: ssize_t bRead = 0; aheinecke@44: int retval = -1; aheinecke@44: aheinecke@44: memset(&fileStat, 0, sizeof(fileStat)); aheinecke@44: aheinecke@44: fd = open(fileName, O_RDONLY); aheinecke@44: if (fd == -1) { aheinecke@44: retval = RAF_UNREADABLE; aheinecke@44: goto cleanup; aheinecke@44: } aheinecke@44: aheinecke@44: rc = fstat(fd, &fileStat); aheinecke@44: if (rc < 0) { aheinecke@44: retval = RAF_STATFAILED; aheinecke@44: goto cleanup; aheinecke@44: } aheinecke@44: aheinecke@44: // Check the size of the file aheinecke@44: if (!fileStat.st_size) { aheinecke@44: retval = RAF_STATFAILED; aheinecke@44: goto cleanup; aheinecke@44: } aheinecke@44: aheinecke@44: if (fileStat.st_size > maxSize && aheinecke@44: fileStat.st_size > 0) { aheinecke@44: retval = RAF_TOOLARGE; aheinecke@44: goto cleanup; aheinecke@44: } aheinecke@44: aheinecke@44: *size = (size_t) fileStat.st_size; aheinecke@44: aheinecke@44: *data = (char*) malloc(*size); aheinecke@44: aheinecke@44: if (*data == NULL) { aheinecke@44: retval = RAF_OUTOFCORE; aheinecke@44: goto cleanup; aheinecke@44: } aheinecke@44: aheinecke@44: bRead = read(fd, *data, *size); aheinecke@44: aheinecke@44: if (bRead < 0 || (size_t) bRead != *size) { aheinecke@44: if (bRead == -1) { aheinecke@44: printf("Error: %s \n", strerror(errno)); aheinecke@44: } aheinecke@44: retval = RAF_UNKNOWN; aheinecke@44: *size = 0; aheinecke@44: if (*data) { aheinecke@44: free(*data); aheinecke@44: *data = NULL; aheinecke@44: } aheinecke@44: goto cleanup; aheinecke@44: } aheinecke@44: aheinecke@44: cleanup: aheinecke@44: aheinecke@44: if (fd && fd != -1) { aheinecke@44: close(fd); aheinecke@44: fd = -1; aheinecke@44: } aheinecke@44: aheinecke@44: return retval; aheinecke@44: } aheinecke@44: aheinecke@44: aheinecke@44: #ifndef _WIN32 aheinecke@44: aheinecke@44: #define INI_LOCATIONS { \ aheinecke@44: "/.mozilla/firefox/profiles.ini", \ aheinecke@44: "/.mozilla/thunderbird/profiles.ini", \ aheinecke@44: NULL } aheinecke@44: aheinecke@44: /** aheinecke@44: * @brief Get a list of all mozilla profile directories for this user aheinecke@44: * aheinecke@44: * Read the profiles.ini and extract all profile paths from that. aheinecke@44: * aheinecke@44: * @return NULL terminated array of strings containing containing the aheinecke@44: * absolute path of the profile directories. The array needs to aheinecke@44: * be freed by the caller. aheinecke@44: */ aheinecke@44: char **getProfilePaths() { aheinecke@44: char *homedir = NULL, aheinecke@44: **retval = NULL; aheinecke@44: const char* const iniLocations[] = INI_LOCATIONS; aheinecke@44: int i = 0; aheinecke@44: aheinecke@44: homedir = getenv ("HOME"); aheinecke@44: aheinecke@44: if (!homedir) { aheinecke@44: printf ("Could not get HOME\n"); aheinecke@44: return NULL; aheinecke@44: } aheinecke@44: aheinecke@44: for (i = 0; iniLocations[i] != NULL; i++) { aheinecke@44: char *candidate[MAX_PATH_LEN], aheinecke@44: *fileContent = NULL; aheinecke@44: const size_t needed = strnlen (homedir, MAX_PATH_LEN) + aheinecke@44: strnlen (iniLocations[i], MAX_PATH_LEN); aheinecke@44: fileSize = 0; aheinecke@44: int err = 0; aheinecke@44: aheinecke@44: memset (candidate, 0, MAX_PATH_LEN); aheinecke@44: aheinecke@44: /* Verify that addition of strlen did not overflow and aheinecke@44: * that the buffer is large enough */ aheinecke@44: if (needed < strnlen (homedir, MAX_PATH_LEN_LEN) || needed >= MAX_PATH - 1) { aheinecke@44: printf ("Error invalid HOME environment variable"); aheinecke@44: return NULL; aheinecke@44: } aheinecke@44: aheinecke@44: strncpy (candidate, homedir, MAX_PATH_LEN); aheinecke@44: /* Environment might have been modified */ aheinecke@44: if (candidate[MAX_PATH_LEN - 1] != '\0') { aheinecke@44: printf ("Error invalid HOME"); aheinecke@44: return NULL; aheinecke@44: } aheinecke@44: strncat (candidate, iniLocations[i], MAX_PATH_LEN - strnlen(candidate, aheinecke@44: MAX_PATH_LEN) - 1); aheinecke@44: aheinecke@44: rc = readFile (candidate, &fileContent, &fileSize, MAX_FILESIZE); aheinecke@44: aheinecke@44: if (err) { aheinecke@44: printf ("Failed to read file.\n"); aheinecke@44: continue; aheinecke@44: } aheinecke@44: parseIni (fileContent, &retval); aheinecke@44: } aheinecke@44: } aheinecke@44: #else /* _WIN32 */ aheinecke@44: char **getProfilePaths() { aheinecke@44: return NULL; aheinecke@44: } aheinecke@44: #endif aheinecke@44: aheinecke@44: int main(int argc, char *argv) { aheinecke@44: }