diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2020-01-27 13:44:14 -0500 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2020-01-27 13:44:14 -0500 |
commit | b5919aefd1ca043ca26583f94721fb75c72ec9a4 (patch) | |
tree | 1e517222651d1b9f4b64ce47e9759cf3cea69ecb /src | |
parent | ea01a40084b4e09c8407886a5070a77aeba56d63 (diff) | |
download | spmc-b5919aefd1ca043ca26583f94721fb75c72ec9a4.tar.gz |
Fix some buffer overflows, add a few more
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/config_global.c | 13 | ||||
-rw-r--r-- | src/internal_cmd.c | 33 | ||||
-rw-r--r-- | src/manifest.c | 45 | ||||
-rw-r--r-- | src/mirrors.c | 100 | ||||
-rw-r--r-- | src/spm.c | 10 |
6 files changed, 187 insertions, 16 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0d53e9b..020e2e5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,7 +3,7 @@ include_directories( ${CMAKE_BINARY_DIR}/include ) -add_executable(spm spm.c config.c compat.c deps.c fs.c rpath.c find.c shell.c archive.c strings.c relocation.c install.c config_global.c manifest.c checksum.c extern/url.c version_spec.c spm_build.c mime.c internal_cmd.c environment.c) +add_executable(spm spm.c config.c compat.c deps.c fs.c rpath.c find.c shell.c archive.c strings.c relocation.c install.c config_global.c manifest.c checksum.c extern/url.c version_spec.c spm_build.c mime.c internal_cmd.c environment.c mirrors.c) target_link_libraries(spm rt crypto ssl curl) if(MSVC) diff --git a/src/config_global.c b/src/config_global.c index 14f3a26..0c32ebb 100644 --- a/src/config_global.c +++ b/src/config_global.c @@ -164,6 +164,7 @@ void init_config_global(void) { SPM_GLOBAL.config = NULL; SPM_GLOBAL.verbose = 0; SPM_GLOBAL.repo_target = NULL; + SPM_GLOBAL.mirror_list = NULL; if (uname(&SPM_GLOBAL.sysinfo) != 0) { fprintf(SYSERROR); @@ -205,6 +206,18 @@ void init_config_global(void) { SPM_GLOBAL.repo_target = normpath(item->value); } + // Initialize mirror list filename + SPM_GLOBAL.mirror_config = join((char *[]) {SPM_GLOBAL.user_config_basedir, SPM_MIRROR_FILENAME, NULL}, DIRSEPS); + item = config_get(SPM_GLOBAL.config, "mirror_config"); + if (item) { + free(SPM_GLOBAL.mirror_config); + SPM_GLOBAL.mirror_config = normpath(item->value); + } + + if (SPM_GLOBAL.mirror_config != NULL) { + SPM_GLOBAL.mirror_list = mirror_list(SPM_GLOBAL.mirror_config); + } + // Initialize temp directory item = config_get(SPM_GLOBAL.config, "tmp_dir"); if (item) { diff --git a/src/internal_cmd.c b/src/internal_cmd.c index 2390671..530d008 100644 --- a/src/internal_cmd.c +++ b/src/internal_cmd.c @@ -10,6 +10,7 @@ static char *internal_commands[] = { "mkprefixbin", "generate prefix manifest (binary)", "mkprefixtext", "generate prefix manifest (text)", "mkmanifest", "generate package repository manifest", + "mirror_clone", "mirror a mirror", "rpath_set", "modify binary RPATH", "rpath_autoset", "determine nearest lib directory and set RPATH", NULL, NULL, @@ -133,6 +134,35 @@ int mkmanifest_interface(int argc, char **argv) { /** * */ +void mirror_clone_interface_usage(void) { + printf("usage: mirror_clone {url} {output_dir}"); +} + +/** + * Mirror packages referenced by a remote manifest + * @param argc + * @param argv + * @return value of `manifest_write` + */ +int mirror_clone_interface(int argc, char **argv) { + if (argc < 3) { + mirror_clone_interface_usage(); + return -1; + } + char *url = argv[1]; + char *path = argv[2]; + + Manifest *manifest = manifest_read(url); + if (manifest == NULL) { + return -2; + } + + mirror_clone(manifest, path); + return 0; +} +/** + * + */ void rpath_set_interface_usage(void) { printf("usage: rpath_set {file} {rpath}\n"); } @@ -231,6 +261,9 @@ int internal_cmd(int argc, char **argv) { else if (strcmp(command, "mkmanifest") == 0) { return mkmanifest_interface(arg_count, arg_array); } + else if (strcmp(command, "mirror_clone") == 0) { + return mirror_clone_interface(arg_count, arg_array); + } else if (strcmp(command, "rpath_set") == 0) { return rpath_set_interface(arg_count, arg_array); } diff --git a/src/manifest.c b/src/manifest.c index 28cf2c4..d1298cf 100644 --- a/src/manifest.c +++ b/src/manifest.c @@ -292,6 +292,7 @@ int manifest_validate(void) { Manifest *manifest_read(char *file_or_url) { FILE *fp = NULL; char *filename = SPM_MANIFEST_FILENAME; + char *tmpdir = NULL; char path[PATH_MAX]; // When file_or_url is NULL we want to use the global manifest @@ -300,25 +301,38 @@ Manifest *manifest_read(char *file_or_url) { strcpy(path, SPM_GLOBAL.package_manifest); } else { - strcpy(path, file_or_url); + char *template = join((char *[]) {TMP_DIR, "spm_manifest_read_XXXXXX", NULL}, DIRSEPS); + tmpdir = mkdtemp(template); + if (exists(tmpdir) != 0) { + fprintf(stderr, "Failed to create temporary storage directory\n"); + fprintf(SYSERROR); + return NULL; + } + + snprintf(path, PATH_MAX, "%s%c%s", template, DIRSEP, filename); } // Handle receiving a path without the manifest filename // by appending the manifest to the path - if (endswith(path, filename) != 0) { + if (startswith(path, "http") != 0 && endswith(path, filename) != 0) { strcat(path, DIRSEPS); strcat(path, filename); } if (exists(path) != 0) { // TODO: Move this out - char *remote_manifest = join((char *[]) {"http://astroconda.org/spm", SPM_GLOBAL.repo_target, filename, NULL}, DIRSEPS); + //char *remote_manifest = join((char *[]) {"http://astroconda.org/spm", SPM_GLOBAL.repo_target, filename, NULL}, DIRSEPS); + char *remote_manifest = join((char *[]) {file_or_url, SPM_GLOBAL.repo_target, filename, NULL}, DIRSEPS); int fetch_status = fetch(remote_manifest, path); if (fetch_status >= 400) { fprintf(stderr, "HTTP %d: %s: %s\n", fetch_status, http_response_str(fetch_status), remote_manifest); free(remote_manifest); return NULL; } + else if (fetch_status == 1 || fetch_status < 0) { + free(remote_manifest); + return NULL; + } free(remote_manifest); } @@ -361,18 +375,24 @@ Manifest *manifest_read(char *file_or_url) { dptr = strip(dptr); char *garbage; char **parts = split(dptr, &separator); - char *_origin = dirname(path); + char *_origin = NULL; + if (file_or_url != NULL) { + _origin = strdup(file_or_url); + } + else { + _origin = dirname(path); + } info->packages[i] = (ManifestPackage *)calloc(1, sizeof(ManifestPackage)); - strncpy(info->packages[i]->origin, _origin, strlen(_origin)); + strncpy(info->packages[i]->origin, _origin, PACKAGE_MEMBER_ORIGIN_SIZE); free(_origin); - strncpy(info->packages[i]->archive, parts[0], strlen(parts[0])); + strncpy(info->packages[i]->archive, parts[0], PACKAGE_MEMBER_SIZE); info->packages[i]->size = strtoul(parts[1], &garbage, 10); - strncpy(info->packages[i]->name, parts[2], strlen(parts[2])); - strncpy(info->packages[i]->version, parts[3], strlen(parts[3])); - strncpy(info->packages[i]->revision, parts[4], strlen(parts[4])); + strncpy(info->packages[i]->name, parts[2], PACKAGE_MEMBER_SIZE); + strncpy(info->packages[i]->version, parts[3], PACKAGE_MEMBER_SIZE); + strncpy(info->packages[i]->revision, parts[4], PACKAGE_MEMBER_SIZE); info->packages[i]->requirements_records = (size_t) atoi(parts[5]); info->packages[i]->requirements = NULL; @@ -381,7 +401,9 @@ Manifest *manifest_read(char *file_or_url) { } if (strncmp(parts[7], SPM_MANIFEST_NODATA, strlen(SPM_MANIFEST_NODATA)) != 0) { - strncpy(info->packages[i]->checksum_sha256, parts[7], strlen(parts[7])); + memset(info->packages[i]->checksum_sha256, '\0', SHA256_DIGEST_LENGTH); + strncpy(info->packages[i]->checksum_sha256, parts[7], SHA256_DIGEST_LENGTH); + } split_free(parts); @@ -389,6 +411,9 @@ Manifest *manifest_read(char *file_or_url) { i++; } + if (tmpdir != NULL) { + free(tmpdir); + } fclose(fp); return info; } diff --git a/src/mirrors.c b/src/mirrors.c new file mode 100644 index 0000000..5c18a1c --- /dev/null +++ b/src/mirrors.c @@ -0,0 +1,100 @@ +#include "spm.h" + +char **file_readlines(const char *filename) { + FILE *fp = NULL; + char **result = NULL; + char *buffer = NULL; + size_t lines = 0; + + if ((fp = fopen(filename, "r")) == NULL) { + perror(filename); + fprintf(SYSERROR); + return NULL; + } + + // Allocate buffer + if ((buffer = calloc(BUFSIZ + 1, sizeof(char))) == NULL) { + perror("line buffer"); + fprintf(SYSERROR); + fclose(fp); + return NULL; + } + + // count number the of lines in the file + while ((fgets(buffer, BUFSIZ, fp)) != NULL) { + lines++; + } + + if (!lines) { + free(buffer); + fclose(fp); + return NULL; + } + + rewind(fp); + + // Populate results array + result = calloc(lines + 1, sizeof(char *)); + for (size_t i = 0; i < lines; i++) { + if (fgets(buffer, BUFSIZ, fp) == NULL) { + break; + } + result[i] = strdup(buffer); + } + + free(buffer); + fclose(fp); + return result; +} + +char **mirror_list(const char *filename) { + char **mirrors = file_readlines(filename); + char **result = NULL; + size_t count; + for (count = 0; mirrors[count] != NULL; count++); + + if (!count) { + return NULL; + } + + result = calloc(count + 1, sizeof(char **)); + for (size_t i = 0; mirrors[i] != NULL; i++) { + if (startswith(mirrors[i], "#") == 0 || isempty(mirrors[i])) { + continue; + } + result[i] = join((char *[]) {mirrors[i], SPM_GLOBAL.repo_target, NULL}, DIRSEPS); + free(mirrors[i]); + } + free(mirrors); + return result; +} + +void mirror_clone(Manifest *info, char *dest) { + if (exists(dest) != 0 && mkdir(dest, 0755) != 0) { + perror("Unable to create mirror directory"); + fprintf(SYSERROR); + exit(1); + } + + for (size_t i = 0; i < info->records; i++) { + long response = 0; + char *url = join((char *[]) {info->packages[i]->origin, SPM_GLOBAL.repo_target, info->packages[i]->archive, NULL}, DIRSEPS); + char *path = join((char *[]) {dest, info->packages[i]->archive, NULL}, DIRSEPS); + if (exists(path) == 0) { + char *checksum = sha256sum(path); + char *wtf_orig = checksum; + char *wtf_new = info->packages[i]->checksum_sha256; + if (strcmp(checksum, info->packages[i]->checksum_sha256) == 0) { + free(url); + free(path); + continue; + } + } + printf("Downloading: %s\n", url); + if ((response = fetch(url, path)) >= 400) { + fprintf(stderr, "Failed to retrieve (error: %ld): %s\n", response, url); + } + free(url); + free(path); + } +}
\ No newline at end of file @@ -152,11 +152,11 @@ int main(int argc, char *argv[], char *arge[]) { // TODO: Move environment allocation out of (above) this loop if possible // TODO: replace variables below with SPM_Hierarchy, and write some control functions - char *spm_binpath = join((char *[]) {root, "bin"}, DIRSEPS); - char *spm_includepath = join((char *[]) {root, "include"}, DIRSEPS); - char *spm_libpath = join((char *[]) {root, "lib"}, DIRSEPS); - char *spm_datapath = join((char *[]) {root, "share"}, DIRSEPS); - char *spm_manpath = join((char *[]) {spm_datapath, "man"}, DIRSEPS); + char *spm_binpath = join((char *[]) {root, "bin", NULL}, DIRSEPS); + char *spm_includepath = join((char *[]) {root, "include", NULL}, DIRSEPS); + char *spm_libpath = join((char *[]) {root, "lib", NULL}, DIRSEPS); + char *spm_datapath = join((char *[]) {root, "share", NULL}, DIRSEPS); + char *spm_manpath = join((char *[]) {spm_datapath, "man", NULL}, DIRSEPS); runtime_set(rt, "SPM_BIN", spm_binpath); runtime_set(rt, "SPM_INCLUDE", spm_includepath); |