diff --git a/bin/xbps-pkgdb/Makefile b/bin/xbps-pkgdb/Makefile index a278b063..e99a22f0 100644 --- a/bin/xbps-pkgdb/Makefile +++ b/bin/xbps-pkgdb/Makefile @@ -5,5 +5,6 @@ BIN = xbps-pkgdb OBJS = main.o check.o check_pkg_files.o OBJS += check_pkg_alternatives.o check_pkg_rundeps.o OBJS += check_pkg_symlinks.o check_pkg_unneeded.o +OBJS += check_files.o include $(TOPDIR)/mk/prog.mk diff --git a/bin/xbps-pkgdb/check_files.c b/bin/xbps-pkgdb/check_files.c new file mode 100644 index 00000000..437efe48 --- /dev/null +++ b/bin/xbps-pkgdb/check_files.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include + +#include "defs.h" + + + +int +file_mode_check(const char *file, const mode_t mode) { + struct stat sb; + + assert(file != NULL); + assert(mode); + + if (lstat(file, &sb) == -1) + return -errno; + + if (sb.st_mode != mode) + return ERANGE; + + return 0; +} + +int +file_owner_check(const char *file, const char *owner) { + struct stat sb; + struct passwd *pw; + + assert(file != NULL); + assert(owner != NULL); + + if (lstat(file, &sb) == -1) + return -errno; + + if ((pw = getpwnam(owner)) == NULL) + return -errno; + + if (sb.st_uid != pw->pw_uid) + return ERANGE; + + return 0; +} + +int +file_group_check(const char *file, const char *grp) { + struct stat sb; + struct group *gr; + + assert(file != NULL); + assert(grp != NULL); + + if (lstat(file, &sb) == -1) + return -errno; + + if ((gr = getgrnam(grp)) == NULL) + return -errno; + + if (sb.st_uid != gr->gr_gid) + return ERANGE; + + return 0; +} diff --git a/bin/xbps-pkgdb/check_pkg_files.c b/bin/xbps-pkgdb/check_pkg_files.c index b79b8e8f..c11805e5 100644 --- a/bin/xbps-pkgdb/check_pkg_files.c +++ b/bin/xbps-pkgdb/check_pkg_files.c @@ -111,7 +111,7 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg) /* check mode */ mode = 0; if (xbps_dictionary_get_uint32(obj, "mode", &mode)) { - rv = xbps_file_mode_check(path, mode); + rv = file_mode_check(path, mode); switch (rv) { case 0: break; @@ -122,7 +122,7 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg) } break; default: - xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(rv)); + xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv)); break; } } @@ -130,7 +130,7 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg) /* check owner */ owner = NULL; if (xbps_dictionary_get_cstring_nocopy(obj, "owner", &owner)) { - rv = xbps_file_owner_check(path, owner); + rv = file_owner_check(path, owner); switch (rv) { case 0: break; @@ -141,7 +141,7 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg) } break; default: - xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(rv)); + xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv)); break; } } @@ -149,7 +149,7 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg) /* check group */ group = NULL; if (xbps_dictionary_get_cstring_nocopy(obj, "group", &group)) { - rv = xbps_file_group_check(path, group); + rv = file_group_check(path, group); switch (rv) { case 0: break; @@ -160,7 +160,7 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg) } break; default: - xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(rv)); + xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv)); break; } } diff --git a/bin/xbps-pkgdb/check_pkg_symlinks.c b/bin/xbps-pkgdb/check_pkg_symlinks.c index 4f699a5f..0194c391 100644 --- a/bin/xbps-pkgdb/check_pkg_symlinks.c +++ b/bin/xbps-pkgdb/check_pkg_symlinks.c @@ -97,7 +97,7 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg) } if (xbps_dictionary_get_cstring_nocopy(obj, "owner", &owner)) { - rv = xbps_file_owner_check(path, owner); + rv = file_owner_check(path, owner); switch (rv) { case 0: break; @@ -106,13 +106,13 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg) test_broken = true; break; default: - xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(rv)); + xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv)); break; } } if (xbps_dictionary_get_cstring_nocopy(obj, "group", &group)) { - rv = xbps_file_group_check(path, group); + rv = file_group_check(path, group); switch (rv) { case 0: break; @@ -121,7 +121,7 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg) test_broken = true; break; default: - xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(rv)); + xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv)); break; } } diff --git a/bin/xbps-pkgdb/defs.h b/bin/xbps-pkgdb/defs.h index f9663f41..9ee1764a 100644 --- a/bin/xbps-pkgdb/defs.h +++ b/bin/xbps-pkgdb/defs.h @@ -45,4 +45,9 @@ CHECK_PKG_DECL(alternatives); /* from convert.c */ void convert_pkgdb_format(struct xbps_handle *); +/* from check_files.c */ +int file_mode_check(const char *, const mode_t); +int file_owner_check(const char *, const char *); +int file_group_check(const char *, const char *); + #endif /* !_XBPS_PKGDB_DEFS_H_ */ diff --git a/lib/Makefile b/lib/Makefile index 0cf6ac84..c267c152 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -32,7 +32,7 @@ LIBFETCH_INCS = fetch/common.h LIBFETCH_GEN = fetch/ftperr.h fetch/httperr.h # External code used by libxbps -EXTOBJS = external/dewey.o external/fexec.o external/mkpath.o +EXTOBJS = external/dewey.o external/fexec.o external/mkpath.o #external/idtree.o # libxbps OBJS = package_configure.o package_config_files.o package_orphans.o diff --git a/lib/external/idtree.c b/lib/external/idtree.c new file mode 100644 index 00000000..82b75164 --- /dev/null +++ b/lib/external/idtree.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2015-2020 Leah Neukirchen + * Parts of code derived from musl libc, which is + * Copyright (C) 2005-2014 Rich Felker, et al. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +/* AA-tree implementation, adapted from https://github.com/ccxvii/minilibs */ +struct idtree { + long id; + char *name; + struct idtree *left, *right; + int level; +}; + +static struct idtree idtree_sentinel = { 0, 0, &idtree_sentinel, &idtree_sentinel, 0 }; + +static struct idtree * +idtree_make(long id, char *name) +{ + struct idtree *node = malloc(sizeof (struct idtree)); + node->id = id; + node->name = name; + node->left = node->right = &idtree_sentinel; + node->level = 1; + return node; +} + +char * +idtree_lookup(struct idtree *node, long id) +{ + if (node) { + while (node != &idtree_sentinel) { + if (id == node->id) + return node->name; + else if (id < node->id) + node = node->left; + else + node = node->right; + } + } + + return 0; +} + +static struct idtree * +idtree_skew(struct idtree *node) +{ + if (node->left->level == node->level) { + struct idtree *save = node; + node = node->left; + save->left = node->right; + node->right = save; + } + return node; +} + +static struct idtree * +idtree_split(struct idtree *node) +{ + if (node->right->right->level == node->level) { + struct idtree *save = node; + node = node->right; + save->right = node->left; + node->left = save; + node->level++; + } + return node; +} + +struct idtree * +idtree_insert(struct idtree *node, long id, char *name) +{ + if (node && node != &idtree_sentinel) { + if (id == node->id) + return node; + else if (id < node->id) + node->left = idtree_insert(node->left, id, name); + else + node->right = idtree_insert(node->right, id, name); + node = idtree_skew(node); + node = idtree_split(node); + return node; + } + return idtree_make(id, name); +} +/**/ + +static char * +strid(long id) +{ + static char buf[32]; + snprintf(buf, sizeof buf, "%ld", id); + return buf; +} + +static char * +groupname(struct idtree *groups, gid_t gid) +{ + char *name = idtree_lookup(groups, gid); + + if (name) + return name; + + struct group *g = getgrgid(gid); + if (g) { + char *name = strdup(g->gr_name); + groups = idtree_insert(groups, gid, name); + return name; + } + + return strid(gid); +} + +static char * +username(struct idtree *users, uid_t uid) +{ + char *name = idtree_lookup(users, uid); + + if (name) + return name; + + struct passwd *p = getpwuid(uid); + if (p) { + char *name = strdup(p->pw_name); + users = idtree_insert(users, uid, name); + return name; + } + + return strid(uid); +}