From d61c009f7a7ba9c99797855d8cd4e0a503c2fda5 Mon Sep 17 00:00:00 2001 From: Fredrik Gustafsson Date: Wed, 20 Nov 2019 11:48:48 +0100 Subject: [PATCH] apk: do not manage file ownership as non-root or when asked so If apk is run as a non-root user, it's not possible to chown files. Maintainers note: minor wording changes on commit log and man page. Signed-off-by: Fredrik Gustafsson --- doc/apk-add.8.scd | 6 ++++++ src/apk_archive.h | 5 ++++- src/apk_database.h | 1 + src/app_add.c | 8 ++++++++ src/database.c | 6 +++++- src/io_archive.c | 29 ++++++++++++++++------------- 6 files changed, 40 insertions(+), 15 deletions(-) diff --git a/doc/apk-add.8.scd b/doc/apk-add.8.scd index f7b52bd..7959a99 100644 --- a/doc/apk-add.8.scd +++ b/doc/apk-add.8.scd @@ -39,6 +39,12 @@ following options: virtual package, and by deleting that package the *apk add* operation may be easily reverted later. +*--no-chown* + Do not change file owner or group. By default apk will manage the file + ownership when running as root. However, this option is turned on when + running as non-root user, as changing file ownership is not permitted + by the system then. + # AUTHORS Natanael Copa ++ diff --git a/src/apk_archive.h b/src/apk_archive.h index bb16c48..bd24733 100644 --- a/src/apk_archive.h +++ b/src/apk_archive.h @@ -16,6 +16,8 @@ #include "apk_blob.h" #include "apk_io.h" +#define APK_EXTRACTF_NO_CHOWN 0x0001 + typedef int (*apk_archive_entry_parser)(void *ctx, const struct apk_file_info *ae, struct apk_istream *istream); @@ -30,6 +32,7 @@ int apk_tar_write_padding(struct apk_ostream *, const struct apk_file_info *ae); int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae, const char *extract_name, const char *hardlink_name, struct apk_istream *is, - apk_progress_cb cb, void *cb_ctx); + apk_progress_cb cb, void *cb_ctx, + unsigned int extract_flags); #endif diff --git a/src/apk_database.h b/src/apk_database.h index 30684c3..bcd5719 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -155,6 +155,7 @@ struct apk_database { unsigned int local_repos, available_repos, cache_max_age; unsigned int repo_update_errors, repo_update_counter; unsigned int pending_triggers; + unsigned int extract_flags; int performing_self_upgrade : 1; int permanent : 1; int autoupdate : 1; diff --git a/src/app_add.c b/src/app_add.c index 8b0ed1a..f5edae0 100644 --- a/src/app_add.c +++ b/src/app_add.c @@ -20,6 +20,7 @@ struct add_ctx { const char *virtpkg; unsigned short solver_flags; + unsigned short extract_flags; }; static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg) @@ -30,6 +31,9 @@ static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt case 0x10000: dbopts->open_flags |= APK_OPENF_CREATE; break; + case 0x10001: + actx->extract_flags |= APK_EXTRACTF_NO_CHOWN; + break; case 'u': actx->solver_flags |= APK_SOLVERF_UPGRADE; break; @@ -47,6 +51,7 @@ static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt static const struct apk_option options_applet[] = { { 0x10000, "initdb" }, + { 0x10001, "no-chown" }, { 'u', "upgrade" }, { 'l', "latest" }, { 't', "virtual", required_argument, "NAME" }, @@ -118,6 +123,9 @@ static int add_main(void *ctx, struct apk_database *db, struct apk_string_array apk_dependency_array_copy(&world, db->world); + if (getuid() != 0 || (actx->extract_flags & APK_EXTRACTF_NO_CHOWN)) + db->extract_flags |= APK_EXTRACTF_NO_CHOWN; + if (actx->virtpkg) { apk_blob_t b = APK_BLOB_STR(actx->virtpkg); apk_blob_pull_dep(&b, db, &virtdep); diff --git a/src/database.c b/src/database.c index cbc6667..dd27e2a 100644 --- a/src/database.c +++ b/src/database.c @@ -1347,6 +1347,10 @@ static int apk_db_create(struct apk_database *db) if (fd < 0) return -errno; close(fd); + fd = openat(db->root_fd, apk_installed_file, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 0644); + if (fd < 0) + return -errno; + close(fd); return 0; } @@ -2554,7 +2558,7 @@ static int apk_db_install_archive_entry(void *_ctx, db->root_fd, ae, format_tmpname(pkg, file, tmpname_file), format_tmpname(pkg, link_target_file, tmpname_link_target), - is, extract_cb, ctx); + is, extract_cb, ctx, db->extract_flags); switch (r) { case 0: diff --git a/src/io_archive.c b/src/io_archive.c index 22145ab..1d34927 100644 --- a/src/io_archive.c +++ b/src/io_archive.c @@ -337,7 +337,8 @@ int apk_tar_write_padding(struct apk_ostream *os, const struct apk_file_info *ae int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae, const char *extract_name, const char *link_target, struct apk_istream *is, - apk_progress_cb cb, void *cb_ctx) + apk_progress_cb cb, void *cb_ctx, + unsigned int apk_extract_flags) { struct apk_xattr *xattr; const char *fn = extract_name ?: ae->name; @@ -385,22 +386,24 @@ int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae, return ret; } - r = fchownat(atfd, fn, ae->uid, ae->gid, atflags); - if (r < 0) { - apk_error("Failed to set ownership on %s: %s", - fn, strerror(errno)); - if (!ret) ret = -errno; - } - - /* chown resets suid bit so we need set it again */ - if (ae->mode & 07000) { - r = fchmodat(atfd, fn, ae->mode & 07777, atflags); + if (!(apk_extract_flags & APK_EXTRACTF_NO_CHOWN)) { + r = fchownat(atfd, fn, ae->uid, ae->gid, atflags); if (r < 0) { - apk_error("Failed to set file permissions " - "on %s: %s", + apk_error("Failed to set ownership on %s: %s", fn, strerror(errno)); if (!ret) ret = -errno; } + + /* chown resets suid bit so we need set it again */ + if (ae->mode & 07000) { + r = fchmodat(atfd, fn, ae->mode & 07777, atflags); + if (r < 0) { + apk_error("Failed to set file permissions " + "on %s: %s", + fn, strerror(errno)); + if (!ret) ret = -errno; + } + } } /* extract xattrs */