diff --git a/doc/TODO b/doc/TODO index 3b37d9ee765..882e8f29eb2 100644 --- a/doc/TODO +++ b/doc/TODO @@ -13,8 +13,6 @@ xbps-bin: * Add support to handle conf_files and keep_dirs from package metadata. * Add support to remove recursively all deps of a package. [IN PROGRESS] * Add support to detect orphaned packages. - * Add support to check sha256 hashes of all installed files, as well as - hashes for binary packages before installation happens. * Add support to install binary packages without any repository. xbps-repo: diff --git a/include/util.h b/include/util.h index 7a72ca14280..3905a8307ab 100644 --- a/include/util.h +++ b/include/util.h @@ -28,6 +28,7 @@ /* from lib/util.c */ char * xbps_append_full_path(bool, const char *, const char *); +int xbps_check_file_hash(const char *, const char *); int xbps_check_is_installed_pkg(const char *); bool xbps_check_is_installed_pkgname(const char *); char * xbps_get_pkg_index_plist(const char *); diff --git a/lib/depends.c b/lib/depends.c index be441873099..e3f586717bd 100644 --- a/lib/depends.c +++ b/lib/depends.c @@ -98,6 +98,7 @@ store_dependency(prop_dictionary_t origind, prop_dictionary_t depd, size_t len = 0, dirdepscnt = 0, indirdepscnt = 0; const char *pkgname, *version, *reqbyname, *reqbyver, *arch; const char *repoloc, *binfile, *originpkg, *short_desc; + const char *sha256; char *reqby, *pkgnver; int rv = 0; bool indirectdep = false; @@ -114,6 +115,7 @@ store_dependency(prop_dictionary_t origind, prop_dictionary_t depd, prop_dictionary_get_cstring_nocopy(depd, "filename", &binfile); prop_dictionary_get_cstring_nocopy(depd, "short_desc", &short_desc); prop_dictionary_get_cstring_nocopy(depd, "architecture", &arch); + prop_dictionary_get_cstring_nocopy(depd, "filename-sha256", &sha256); prop_dictionary_get_uint32(depd, "priority", &prio); prop_dictionary_get_cstring_nocopy(origind, "pkgname", &reqbyname); prop_dictionary_get_cstring_nocopy(origind, "version", &reqbyver); @@ -205,6 +207,7 @@ store_dependency(prop_dictionary_t origind, prop_dictionary_t depd, prop_dictionary_set_cstring(dict, "short_desc", short_desc); prop_dictionary_set_bool(dict, "indirect_dep", indirectdep); prop_dictionary_set_cstring(dict, "architecture", arch); + prop_dictionary_set_cstring(dict, "filename-sha256", sha256); /* * Add the dictionary into the array. diff --git a/lib/install.c b/lib/install.c index 45229e293fc..e5fac161115 100644 --- a/lib/install.c +++ b/lib/install.c @@ -54,29 +54,24 @@ xbps_install_binary_pkg_fini(prop_dictionary_t repo, prop_dictionary_t pkg, prop_dictionary_get_cstring_nocopy(pkg, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(pkg, "version", &version); prop_dictionary_get_cstring_nocopy(pkg, "short_desc", &desc); - assert(pkgname != NULL); - assert(version != NULL); - assert(desc != NULL); if (repo == false) automatic = true; - printf("Installing %s%s: found version %s ... ", + printf("Installing %s%s: found version %s ...\n", automatic ? "dependency " : "", pkgname, version); - (void)fflush(stdout); rv = xbps_unpack_binary_pkg(repo, pkg, destdir, flags); if (rv == 0) { rv = xbps_register_pkg(pkg, pkgname, version, desc, automatic); if (rv != 0) { - printf("failed!\n"); + printf("ERROR: couldn't register %s-%s! (%s)\n", + pkgname, version, strerror(rv)); return rv; } } - printf("done.\n"); - return 0; } diff --git a/lib/remove.c b/lib/remove.c index 8a724ea7265..2a2c47b3e1b 100644 --- a/lib/remove.c +++ b/lib/remove.c @@ -36,6 +36,13 @@ #include +struct rm_cbarg { + const char *destdir; + int flags; +}; + +static int remove_pkg_files(prop_object_t, void *, bool *); + int xbps_unregister_pkg(const char *pkgname) { @@ -100,11 +107,74 @@ xbps_remove_binary_pkg_meta(const char *pkgname, const char *destdir, int flags) return rv; } +static int +remove_pkg_files(prop_object_t obj, void *arg, bool *loop_done) +{ + struct rm_cbarg *rmcb = arg; + const char *file = NULL, *sha256; + char *path = NULL; + int rv = 0; + + (void)loop_done; + + prop_dictionary_get_cstring_nocopy(obj, "file", &file); + if (file != NULL) { + path = xbps_append_full_path(false, rmcb->destdir, file); + if (path == NULL) + return EINVAL; + + prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256); + if ((rv = xbps_check_file_hash(path, sha256)) == ERANGE) { + if (rmcb->flags & XBPS_UNPACK_VERBOSE) + printf("WARNING: SHA256 doesn't match for " + "file %s, ignoring...\n", file); + goto out; + } + + if ((rv = unlink(path)) == -1) { + if (rmcb->flags & XBPS_UNPACK_VERBOSE) + printf("WARNING: can't remove file %s (%s)\n", + file, strerror(errno)); + goto out; + } + if (rmcb->flags & XBPS_UNPACK_VERBOSE) + printf("Removed file: %s\n", file); + + goto out; + } + + prop_dictionary_get_cstring_nocopy(obj, "dir", &file); + if (file != NULL) { + path = xbps_append_full_path(false, rmcb->destdir, file); + if (path == NULL) + return EINVAL; + + if ((rv = rmdir(path)) == -1) { + if (errno == ENOTEMPTY) + goto out; + + if (rmcb->flags & XBPS_UNPACK_VERBOSE) { + printf("WARNING: can't remove " + "directory %s (%s)\n", file, + strerror(errno)); + goto out; + } + if (rmcb->flags & XBPS_UNPACK_VERBOSE) + printf("Removed directory: %s\n", file); + } + } +out: + free(path); + + return 0; +} + int xbps_remove_binary_pkg(const char *pkgname, const char *destdir, int flags) { - FILE *flist; - char path[PATH_MAX - 1], line[LINE_MAX - 1], *p, *buf; + prop_dictionary_t fdict; + struct rm_cbarg rmcbarg; + char path[PATH_MAX - 1], *buf; int fd, rv = 0; size_t len = 0; bool prepostf = false; @@ -136,8 +206,8 @@ xbps_remove_binary_pkg(const char *pkgname, const char *destdir, int flags) /* Find out if the prepost-rm file exists */ if ((fd = open(buf, O_RDONLY)) == -1) { if (errno != ENOENT) { - rv = errno; - goto out; + free(buf); + return errno; } } else { /* Run the preremove action */ @@ -147,89 +217,48 @@ xbps_remove_binary_pkg(const char *pkgname, const char *destdir, int flags) NULL)) != 0) { printf("%s: prerm action target error (%s)\n", pkgname, strerror(errno)); - goto out; + free(buf); + return rv; } } - (void)snprintf(path, sizeof(path), "%s%s/metadata/%s/flist", + /* + * Iterate over the pkg file list dictionary and remove all + * files/dirs associated. + */ + (void)snprintf(path, sizeof(path), "%s%s/metadata/%s/files.plist", destdir, XBPS_META_PATH, pkgname); - if ((flist = fopen(path, "r")) == NULL) { - rv = errno; - goto out; + fdict = prop_dictionary_internalize_from_file(path); + if (fdict == NULL) { + free(buf); + return errno; } - while (!feof(flist)) { - p = fgets(line, sizeof(line), flist); - if (p == NULL) { - if (feof(flist)) - break; - if (ferror(flist)) { - rv = errno; - break; - } - } - if (strlen(line) == 0 || line[0] == '#' || - isspace((unsigned char)line[0]) != 0) - continue; + rmcbarg.destdir = destdir; + rmcbarg.flags = flags; - len = strlen(line) + 1; - p = calloc(1, len); - if (p == NULL) { - rv = errno; - break; - } - - (void)strncpy(p, line, len - 2); - (void)snprintf(path, sizeof(path), "%s%s", - destdir, p); - - /* - * Remove the file or the directory if it's empty. - */ - if ((rv = unlink(path)) == -1) { - if (errno == EISDIR) { - if ((rv = rmdir(path)) == -1) { - if (errno == ENOTEMPTY) { - rv = 0; - goto next; - } - if (flags & XBPS_UNPACK_VERBOSE) - printf("WARNING: can't remove " - "directory %s (%s)\n", - path, strerror(errno)); - goto next; - } - if (flags & XBPS_UNPACK_VERBOSE) - printf("Removed directory: %s\n", path); - goto next; - } - if (flags & XBPS_UNPACK_VERBOSE) - printf("WARNING: can't remove file %s (%s)\n", path, - strerror(errno)); - goto next; - } - if (flags & XBPS_UNPACK_VERBOSE) - printf("Removed file: %s\n", path); -next: - free(p); - p = NULL; + rv = xbps_callback_array_iter_in_dict(fdict, "filelist", + remove_pkg_files, (void *)&rmcbarg); + if (rv != 0) { + free(buf); + prop_object_release(fdict); + return rv; } - (void)fclose(flist); + prop_object_release(fdict); /* If successful, unregister pkg from db */ - if (rv == 0) { - if (((rv = xbps_unregister_pkg(pkgname)) == 0) && prepostf) { - /* Run the postremove action target */ - if ((rv = xbps_file_exec(buf, destdir, "post", - pkgname, NULL)) != 0) { - printf("%s: postrm action target error (%s)\n", - pkgname, strerror(errno)); - } + if (((rv = xbps_unregister_pkg(pkgname)) == 0) && prepostf) { + /* Run the postremove action target */ + if ((rv = xbps_file_exec(buf, destdir, "post", + pkgname, NULL)) != 0) { + printf("%s: postrm action target error (%s)\n", + pkgname, strerror(errno)); + free(buf); + return rv; } } -out: free(buf); rv = xbps_remove_binary_pkg_meta(pkgname, destdir, flags); diff --git a/lib/unpack.c b/lib/unpack.c index f7dd832d034..d9f2aeb7d49 100644 --- a/lib/unpack.c +++ b/lib/unpack.c @@ -45,6 +45,7 @@ xbps_unpack_binary_pkg(prop_dictionary_t repo, prop_dictionary_t pkg, const char *destdir, int flags) { prop_string_t filename, repoloc, arch; + const char *sha256; char *binfile, *path; int rv = 0; @@ -53,6 +54,7 @@ xbps_unpack_binary_pkg(prop_dictionary_t repo, prop_dictionary_t pkg, /* Append filename to the full path for binary pkg */ filename = prop_dictionary_get(pkg, "filename"); arch = prop_dictionary_get(pkg, "architecture"); + prop_dictionary_get_cstring_nocopy(pkg, "filename-sha256", &sha256); if (repo) repoloc = prop_dictionary_get(repo, "location-local"); else @@ -72,6 +74,13 @@ xbps_unpack_binary_pkg(prop_dictionary_t repo, prop_dictionary_t pkg, } free(path); + if ((rv = xbps_check_file_hash(binfile, sha256)) == ERANGE) { + printf("ERROR: SHA256 doesn't match for %s!", + prop_string_cstring_nocopy(filename)); + free(binfile); + return rv; + } + rv = unpack_archive_init(pkg, destdir, binfile, flags); free(binfile); return rv; diff --git a/lib/util.c b/lib/util.c index b6ac5c775f5..8a08220deb6 100644 --- a/lib/util.c +++ b/lib/util.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,31 @@ static const char *rootdir; +int +xbps_check_file_hash(const char *path, const char *sha256) +{ + SHA256_CTX ctx; + const char *res; + uint8_t buf[BUFSIZ * 20], digest[SHA256_DIGEST_LENGTH * 2 + 1]; + ssize_t bytes; + int fd, rv = 0; + + if ((fd = open(path, O_RDONLY)) == -1) + return errno; + + SHA256_Init(&ctx); + while ((bytes = read(fd, buf, sizeof(buf))) > 0) + SHA256_Update(&ctx, buf, (size_t)bytes); + res = SHA256_End(&ctx, digest); + + if (strcmp(sha256, res)) + rv = ERANGE; + + (void)close(fd); + + return rv; +} + int xbps_check_is_installed_pkg(const char *pkg) {