summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2010-06-12 13:43:29 +0300
committerTimo Teräs <timo.teras@iki.fi>2010-06-12 13:43:29 +0300
commit3062d681f9052aabd4e02884e67a0fa1cf413f8b (patch)
tree13005e78d400349314753d326a18efe78d51cc70
parent43cb554c3fd94ba394b708265c5fa2225a37a9eb (diff)
downloadapk-tools-3062d681f9052aabd4e02884e67a0fa1cf413f8b.tar.bz2
apk-tools-3062d681f9052aabd4e02884e67a0fa1cf413f8b.tar.xz
archive: honor username/groupname instead of uid/gid
Take the uid/gid from passwd and group.
-rw-r--r--src/apk.c2
-rw-r--r--src/apk_io.h6
-rw-r--r--src/archive.c5
-rw-r--r--src/io.c126
-rw-r--r--src/package.c2
5 files changed, 140 insertions, 1 deletions
diff --git a/src/apk.c b/src/apk.c
index 315fa8a..81bb950 100644
--- a/src/apk.c
+++ b/src/apk.c
@@ -244,6 +244,7 @@ int main(int argc, char **argv)
memset(&dbopts, 0, sizeof(dbopts));
list_init(&dbopts.repository_list);
umask(0);
+ apk_id_cache_init();
applet = deduce_applet(argc, argv);
num_options = ARRAY_SIZE(generic_options) + 1;
@@ -365,6 +366,7 @@ int main(int argc, char **argv)
r = applet->main(ctx, &db, argc, argv);
apk_db_close(&db);
+ apk_id_cache_free();
if (r == -EINVAL)
return usage(applet);
diff --git a/src/apk_io.h b/src/apk_io.h
index 68f9925..3a3abff 100644
--- a/src/apk_io.h
+++ b/src/apk_io.h
@@ -95,4 +95,10 @@ int apk_file_get_info(int atfd, const char *filename, unsigned int flags,
int apk_url_download(const char *url, int atfd, const char *file);
const char *apk_url_local_file(const char *url);
+void apk_id_cache_init(void);
+void apk_id_cache_free(void);
+void apk_id_cache_reset(void);
+uid_t apk_resolve_uid(const char *username, uid_t default_uid);
+uid_t apk_resolve_gid(const char *groupname, uid_t default_gid);
+
#endif
diff --git a/src/archive.c b/src/archive.c
index e7260b6..f60cb1b 100644
--- a/src/archive.c
+++ b/src/archive.c
@@ -388,7 +388,10 @@ int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
break;
}
if (r == 0) {
- r = fchownat(atfd, fn, ae->uid, ae->gid, atflags);
+ r = fchownat(atfd, fn,
+ apk_resolve_uid(ae->uname, ae->uid),
+ apk_resolve_gid(ae->gname, ae->gid),
+ atflags);
if (r < 0) {
apk_error("Failed to set ownership on %s: %s",
fn, strerror(errno));
diff --git a/src/io.c b/src/io.c
index 57e2d2d..2b0c892 100644
--- a/src/io.c
+++ b/src/io.c
@@ -15,9 +15,12 @@
#include <unistd.h>
#include <malloc.h>
#include <sys/mman.h>
+#include <pwd.h>
+#include <grp.h>
#include "apk_defines.h"
#include "apk_io.h"
+#include "apk_hash.h"
struct apk_fd_istream {
struct apk_istream is;
@@ -715,3 +718,126 @@ size_t apk_ostream_write_string(struct apk_ostream *os, const char *string)
return len;
}
+
+struct cache_item {
+ apk_hash_node hash_node;
+ unsigned int genid;
+ union {
+ uid_t uid;
+ gid_t gid;
+ };
+ unsigned short len;
+ char name[];
+};
+
+static apk_blob_t cache_item_get_key(apk_hash_item item)
+{
+ struct cache_item *ci = (struct cache_item *) item;
+ return APK_BLOB_PTR_LEN(ci->name, ci->len);
+}
+
+static const struct apk_hash_ops id_hash_ops = {
+ .node_offset = offsetof(struct cache_item, hash_node),
+ .get_key = cache_item_get_key,
+ .hash_key = apk_blob_hash,
+ .compare = apk_blob_compare,
+ .delete_item = (apk_hash_delete_f) free,
+};
+
+static struct cache_item *resolve_cache_item(struct apk_hash *hash, apk_blob_t name)
+{
+ struct cache_item *ci;
+ unsigned long h;
+
+ h = id_hash_ops.hash_key(name);
+ ci = (struct cache_item *) apk_hash_get_hashed(hash, name, h);
+ if (ci != NULL)
+ return ci;
+
+ ci = calloc(1, sizeof(struct cache_item) + name.len);
+ if (ci == NULL)
+ return NULL;
+
+ ci->len = name.len;
+ memcpy(ci->name, name.ptr, name.len);
+ apk_hash_insert_hashed(hash, ci, h);
+
+ return ci;
+}
+
+static unsigned int id_genid = 0;
+static struct apk_hash uid_cache, gid_cache;
+
+void apk_id_cache_init(void)
+{
+ apk_hash_init(&uid_cache, &id_hash_ops, 256);
+ apk_hash_init(&gid_cache, &id_hash_ops, 256);
+ id_genid = 1;
+}
+
+void apk_id_cache_free(void)
+{
+ apk_hash_free(&uid_cache);
+ apk_hash_free(&gid_cache);
+}
+
+void apk_id_cache_reset(void)
+{
+ id_genid++;
+ if (id_genid == 0)
+ id_genid = 1;
+}
+
+uid_t apk_resolve_uid(const char *username, uid_t default_uid)
+{
+ struct cache_item *ci;
+ struct passwd pwent, *pwd;
+ char buf[1024];
+ int r;
+
+ ci = resolve_cache_item(&uid_cache, APK_BLOB_STR(username));
+ if (ci == NULL)
+ return default_uid;
+
+ if (ci->genid != id_genid) {
+ r = getpwnam_r(username, &pwent, buf, sizeof(buf), &pwd);
+ if (pwd != NULL)
+ ci->uid = pwd->pw_uid;
+ else
+ ci->uid = -1;
+ if (r == 0)
+ ci->genid = id_genid;
+ }
+
+ if (ci->uid != -1)
+ return ci->uid;
+
+ return default_uid;
+}
+
+uid_t apk_resolve_gid(const char *groupname, uid_t default_gid)
+{
+ struct cache_item *ci;
+ struct group grent, *grp;
+ char buf[1024];
+ int r;
+
+ ci = resolve_cache_item(&gid_cache, APK_BLOB_STR(groupname));
+ if (ci == NULL)
+ return default_gid;
+
+ if (ci->genid != id_genid) {
+ r = getgrnam_r(groupname, &grent, buf, sizeof(buf), &grp);
+ if (grp != NULL)
+ ci->gid = grp->gr_gid;
+ else
+ ci->gid = -1;
+ if (r == 0)
+ ci->genid = id_genid;
+ }
+
+ if (ci->gid != -1)
+ return ci->gid;
+
+ return default_gid;
+}
diff --git a/src/package.c b/src/package.c
index 0dd89d3..e73814a 100644
--- a/src/package.c
+++ b/src/package.c
@@ -910,6 +910,8 @@ int apk_ipkg_run_script(struct apk_installed_package *ipkg, int root_fd,
}
waitpid(pid, &status, 0);
unlinkat(root_fd, fn, 0);
+ apk_id_cache_reset();
+
if (WIFEXITED(status))
return WEXITSTATUS(status);
return -1;