From d31a3d205a62c75d52e18f64b1768a11e94f932a Mon Sep 17 00:00:00 2001 From: Juan RP Date: Fri, 26 Oct 2012 11:25:17 +0200 Subject: [PATCH] unpack: use lstat() for symlinks, respect uid/gid if euid == 0, some fixes. --- lib/package_unpack.c | 51 +++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/lib/package_unpack.c b/lib/package_unpack.c index f5c2cf6e..e0c88cd7 100644 --- a/lib/package_unpack.c +++ b/lib/package_unpack.c @@ -36,11 +36,11 @@ #include "xbps_api_impl.h" static int -set_extract_flags(void) +set_extract_flags(uid_t euid) { int flags; - if (geteuid() == 0) + if (euid == 0) flags = FEXTRACT_FLAGS; else flags = EXTRACT_FLAGS; @@ -200,6 +200,7 @@ unpack_archive(struct xbps_handle *xhp, int ar_rv, rv, rv_stat, flags; bool preserve, update, conf_file, file_exists, skip_obsoletes; bool softreplace, skip_extract; + uid_t euid; assert(prop_object_type(pkg_repod) == PROP_TYPE_DICTIONARY); assert(ar != NULL); @@ -217,6 +218,8 @@ unpack_archive(struct xbps_handle *xhp, prop_dictionary_get_cstring_nocopy(pkg_repod, "pkgver", &pkgver); prop_dictionary_get_cstring_nocopy(pkg_repod, "filename", &fname); + euid = geteuid(); + if (xhp->unpack_cb != NULL) { /* initialize data for unpack cb */ memset(&xucd, 0, sizeof(xucd)); @@ -260,10 +263,9 @@ unpack_archive(struct xbps_handle *xhp, else if (ar_rv == ARCHIVE_RETRY) continue; - skip_extract = false; entry_statp = archive_entry_stat(entry); entry_pname = archive_entry_pathname(entry); - flags = set_extract_flags(); + flags = set_extract_flags(euid); /* * Ignore directories from archive. */ @@ -386,14 +388,15 @@ unpack_archive(struct xbps_handle *xhp, * doesn't match, in that case overwrite the file. * Otherwise skip extracting it. */ - conf_file = file_exists = false; - rv_stat = stat(entry_pname, &st); + conf_file = skip_extract = file_exists = false; + rv_stat = lstat(entry_pname, &st); + if (rv_stat == 0) + file_exists = true; if (S_ISREG(entry_statp->st_mode)) { buf = strchr(entry_pname, '.') + 1; assert(buf != NULL); - if (rv_stat == 0) { - file_exists = true; + if (file_exists) { /* * Handle configuration files. Check if current * entry is a configuration file and take action @@ -448,7 +451,7 @@ unpack_archive(struct xbps_handle *xhp, * Check if current link from binpkg hasn't been * modified, otherwise extract new link. */ - if (stat(entry_pname, &st) == 0) { + if (file_exists) { buf = realpath(entry_pname, NULL); assert(buf); p = strlen(xhp->rootdir) + buf; @@ -476,7 +479,8 @@ unpack_archive(struct xbps_handle *xhp, * Check if current file mode differs from file mode * in binpkg and apply perms if true. */ - if (file_exists && (entry_statp->st_mode != st.st_mode)) { + if (file_exists && skip_extract && + (entry_statp->st_mode != st.st_mode)) { if (chmod(entry_pname, entry_statp->st_mode) != 0) { xbps_dbg_printf(xhp, @@ -489,10 +493,31 @@ unpack_archive(struct xbps_handle *xhp, rv = EINVAL; goto out; } - xbps_dbg_printf(xhp, "%s-%s: entry %s perms " - "to %s.\n", pkgname, version, entry_pname, + xbps_dbg_printf(xhp, "%s-%s: entry %s changed file " + "mode to %s.\n", pkgname, version, entry_pname, archive_entry_strmode(entry)); - skip_extract = true; + } + /* + * Check if current uid/gid differs from file in binpkg, + * and change permissions if true. + */ + if ((file_exists && skip_extract && (euid == 0)) && + (((entry_statp->st_uid != st.st_uid)) || + ((entry_statp->st_gid != st.st_gid)))) { + if (chown(entry_pname, + entry_statp->st_uid, entry_statp->st_gid) != 0) { + xbps_dbg_printf(xhp, + "%s-%s: failed " + "to set uid/gid to %u:%u (%s)\n", + pkgname, version, + entry_statp->st_uid, entry_statp->st_gid, + strerror(errno)); + } else { + xbps_dbg_printf(xhp, "%s-%s: entry %s changed " + "uid/gid to %u:%u.\n", pkgname, version, + entry_pname, + entry_statp->st_uid, entry_statp->st_gid); + } } if (!update && conf_file && file_exists && !skip_extract) {