Skip to content

Commit 9569f2e

Browse files
committed
bin/xbps-pkgdb: check file and symlink owners & perms
1 parent 3417a94 commit 9569f2e

8 files changed

Lines changed: 385 additions & 33 deletions

File tree

bin/xbps-pkgdb/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ BIN = xbps-pkgdb
55
OBJS = main.o check.o check_pkg_files.o
66
OBJS += check_pkg_alternatives.o check_pkg_rundeps.o
77
OBJS += check_pkg_symlinks.o check_pkg_unneeded.o
8+
OBJS += check_files.o
89

910
include $(TOPDIR)/mk/prog.mk

bin/xbps-pkgdb/check_files.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#include <assert.h>
2+
#include <errno.h>
3+
#include <string.h>
4+
#include <sys/stat.h>
5+
6+
#include "defs.h"
7+
8+
int
9+
file_mode_check(const char *file, const mode_t mode) {
10+
struct stat sb;
11+
12+
assert(file != NULL);
13+
assert(mode);
14+
15+
if (lstat(file, &sb) == -1)
16+
return -errno;
17+
18+
if (sb.st_mode != mode)
19+
return ERANGE;
20+
21+
return 0;
22+
}
23+
24+
int
25+
file_user_check(struct idtree * idt, const char *file, const char *user) {
26+
struct stat sb;
27+
char *act_user;
28+
29+
assert(file != NULL);
30+
assert(user != NULL);
31+
32+
if (lstat(file, &sb) == -1)
33+
return -errno;
34+
35+
act_user = idtree_username(idt, sb.st_uid);
36+
return strcmp(user, act_user) == 0 ? 0 : ERANGE;
37+
}
38+
39+
int
40+
file_group_check(struct idtree * idt, const char *file, const char *grp) {
41+
struct stat sb;
42+
char *act_grp;
43+
44+
assert(file != NULL);
45+
assert(grp != NULL);
46+
47+
if (lstat(file, &sb) == -1)
48+
return -errno;
49+
50+
act_grp = idtree_groupname(idt, sb.st_gid);
51+
return strcmp(grp, act_grp) == 0 ? 0 : ERANGE;
52+
}

bin/xbps-pkgdb/check_pkg_files.c

Lines changed: 98 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@
4343
* o Check the hash for all installed files, except
4444
* configuration files (which is expected if they are modified).
4545
*
46-
* o Compares stored file modification time.
46+
* o Check the mode for all installed files, except configuration files.
47+
*
48+
* o Check the user for all installed files, except configuration files.
49+
*
50+
* o Check the group for all installed files, except configuration files.
4751
*
4852
* Return 0 if test ran successfully, 1 otherwise and -1 on error.
4953
*/
@@ -55,56 +59,120 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg)
5559
xbps_object_t obj;
5660
xbps_object_iterator_t iter;
5761
xbps_dictionary_t pkg_filesd = arg;
58-
const char *file = NULL, *sha256 = NULL;
62+
const char *file = NULL, *sha256 = NULL, *user = NULL, *group = NULL;
5963
char *path;
60-
bool mutable, test_broken = false;
64+
bool mutable, test_broken = false, noexist = false;
6165
int rv = 0, errors = 0;
66+
mode_t mode = 0;
67+
struct idtree *idt = NULL;
6268

6369
array = xbps_dictionary_get(pkg_filesd, "files");
6470
if (array != NULL && xbps_array_count(array) > 0) {
6571
iter = xbps_array_iter_from_dict(pkg_filesd, "files");
66-
if (iter == NULL)
67-
return -1;
72+
if (iter == NULL) {
73+
errors++;
74+
goto out;
75+
}
6876

6977
while ((obj = xbps_object_iterator_next(iter))) {
78+
noexist = mutable = false;
79+
7080
xbps_dictionary_get_cstring_nocopy(obj, "file", &file);
7181
/* skip noextract files */
7282
if (xhp->noextract && xbps_patterns_match(xhp->noextract, file))
7383
continue;
7484
path = xbps_xasprintf("%s/%s", xhp->rootdir, file);
75-
xbps_dictionary_get_cstring_nocopy(obj,
76-
"sha256", &sha256);
85+
86+
xbps_dictionary_get_bool(obj, "mutable", &mutable);
87+
88+
/* check sha256 */
89+
xbps_dictionary_get_cstring_nocopy(obj, "sha256", &sha256);
7790
rv = xbps_file_sha256_check(path, sha256);
7891
switch (rv) {
7992
case 0:
80-
free(path);
8193
break;
8294
case ENOENT:
83-
xbps_error_printf("%s: unexistent file %s.\n",
84-
pkgname, file);
85-
free(path);
86-
test_broken = true;
95+
xbps_error_printf("%s: unexistent file %s.\n", pkgname, file);
96+
test_broken = noexist = true;
8797
break;
8898
case ERANGE:
89-
mutable = false;
90-
xbps_dictionary_get_bool(obj,
91-
"mutable", &mutable);
9299
if (!mutable) {
93-
xbps_error_printf("%s: hash mismatch "
94-
"for %s.\n", pkgname, file);
100+
xbps_error_printf("%s: hash mismatch for %s.\n", pkgname, file);
95101
test_broken = true;
96102
}
97-
free(path);
98103
break;
99104
default:
100-
xbps_error_printf(
101-
"%s: can't check `%s' (%s)\n",
102-
pkgname, file, strerror(rv));
103-
free(path);
105+
xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(rv));
104106
break;
105107
}
106-
}
107-
xbps_object_iterator_release(iter);
108+
109+
if (noexist) {
110+
free(path);
111+
continue;
112+
}
113+
114+
/* check mode */
115+
mode = 0;
116+
if (xbps_dictionary_get_uint32(obj, "mode", &mode)) {
117+
rv = file_mode_check(path, mode);
118+
switch (rv) {
119+
case 0:
120+
break;
121+
case ERANGE:
122+
if (!mutable) {
123+
xbps_error_printf("%s: mode mismatch for %s.\n", pkgname, file);
124+
test_broken = true;
125+
}
126+
break;
127+
default:
128+
xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv));
129+
break;
130+
}
131+
}
132+
133+
/* check user */
134+
user = NULL;
135+
xbps_dictionary_get_cstring_nocopy(obj, "user", &user);
136+
if (user == NULL)
137+
user = "root";
138+
rv = file_user_check(idt, path, user);
139+
switch (rv) {
140+
case 0:
141+
break;
142+
case ERANGE:
143+
if (!mutable) {
144+
xbps_error_printf("%s: user mismatch for %s.\n", pkgname, file);
145+
test_broken = true;
146+
}
147+
break;
148+
default:
149+
xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv));
150+
break;
151+
}
152+
153+
/* check group */
154+
group = NULL;
155+
xbps_dictionary_get_cstring_nocopy(obj, "group", &group);
156+
if (group == NULL)
157+
group = "root";
158+
rv = file_group_check(idt, path, group);
159+
switch (rv) {
160+
case 0:
161+
break;
162+
case ERANGE:
163+
if (!mutable) {
164+
xbps_error_printf("%s: group mismatch for %s.\n", pkgname, file);
165+
test_broken = true;
166+
}
167+
break;
168+
default:
169+
xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv));
170+
break;
171+
}
172+
173+
free(path);
174+
}
175+
xbps_object_iterator_release(iter);
108176
}
109177
if (test_broken) {
110178
xbps_error_printf("%s: files check FAILED.\n", pkgname);
@@ -118,8 +186,10 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg)
118186
array = xbps_dictionary_get(pkg_filesd, "conf_files");
119187
if (array != NULL && xbps_array_count(array) > 0) {
120188
iter = xbps_array_iter_from_dict(pkg_filesd, "conf_files");
121-
if (iter == NULL)
122-
return -1;
189+
if (iter == NULL) {
190+
errors++;
191+
goto out;
192+
}
123193

124194
while ((obj = xbps_object_iterator_next(iter))) {
125195
xbps_dictionary_get_cstring_nocopy(obj, "file", &file);
@@ -148,5 +218,7 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg)
148218
errors++;
149219
}
150220

221+
out:
222+
idtree_free(idt);
151223
return errors ? -1 : 0;
152224
}

bin/xbps-pkgdb/check_pkg_symlinks.c

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@
4141
* The following task is accomplished in this file:
4242
*
4343
* o Check for target file in symlinks, so that we can check that
44-
* they have not been modified.
44+
* they have not been modified or broken.
4545
*
46-
* returns 0 if test ran successfully, 1 otherwise and -1 on error.
46+
* o Check for symlink ownership.
47+
*
48+
* returns 0 if test ran successfully and -1 on error.
4749
*/
4850

4951
int
@@ -52,14 +54,16 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg)
5254
xbps_array_t array;
5355
xbps_object_t obj;
5456
xbps_dictionary_t filesd = arg;
57+
bool test_broken = false;
5558
int rv = 0;
59+
struct idtree *idt = NULL;
5660

5761
array = xbps_dictionary_get(filesd, "links");
5862
if (array == NULL)
5963
return 0;
6064

6165
for (unsigned int i = 0; i < xbps_array_count(array); i++) {
62-
const char *file = NULL, *tgt = NULL;
66+
const char *file = NULL, *tgt = NULL, *user = NULL, *group = NULL;
6367
char path[PATH_MAX], *lnk = NULL;
6468

6569
obj = xbps_array_get(array, i);
@@ -83,16 +87,53 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg)
8387
snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, file);
8488
if ((lnk = xbps_symlink_target(xhp, path, tgt)) == NULL) {
8589
xbps_error_printf("%s: broken symlink %s (target: %s)\n", pkgname, file, tgt);
86-
rv = -1;
90+
test_broken = true;
8791
continue;
8892
}
8993
if (strcmp(lnk, tgt)) {
9094
xbps_warn_printf("%s: modified symlink %s "
9195
"points to %s (shall be %s)\n",
9296
pkgname, file, lnk, tgt);
93-
rv = -1;
97+
test_broken = true;
98+
}
99+
100+
user = NULL;
101+
xbps_dictionary_get_cstring_nocopy(obj, "user", &user);
102+
if (user == NULL)
103+
user = "root";
104+
rv = file_user_check(idt, path, user);
105+
switch (rv) {
106+
case 0:
107+
break;
108+
case ERANGE:
109+
xbps_error_printf("%s: user mismatch for %s.\n", pkgname, file);
110+
test_broken = true;
111+
break;
112+
default:
113+
xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv));
114+
break;
94115
}
116+
117+
group = NULL;
118+
xbps_dictionary_get_cstring_nocopy(obj, "group", &group);
119+
if (group == NULL)
120+
group = "root";
121+
rv = file_group_check(idt, path, group);
122+
switch (rv) {
123+
case 0:
124+
break;
125+
case ERANGE:
126+
xbps_error_printf("%s: group mismatch for %s.\n", pkgname, file);
127+
test_broken = true;
128+
break;
129+
default:
130+
xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv));
131+
break;
132+
}
133+
95134
free(lnk);
96135
}
97-
return rv;
136+
137+
idtree_free(idt);
138+
return test_broken ? -1 : 0;
98139
}

bin/xbps-pkgdb/defs.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include <sys/time.h>
3030
#include <xbps.h>
3131

32+
#include "idtree.h"
33+
3234
/* from check.c */
3335
int check_pkg_integrity(struct xbps_handle *, xbps_dictionary_t, const char *);
3436
int check_pkg_integrity_all(struct xbps_handle *);
@@ -45,4 +47,9 @@ CHECK_PKG_DECL(alternatives);
4547
/* from convert.c */
4648
void convert_pkgdb_format(struct xbps_handle *);
4749

50+
/* from check_files.c */
51+
int file_mode_check(const char *, const mode_t);
52+
int file_user_check(struct idtree *, const char *, const char *);
53+
int file_group_check(struct idtree *, const char *, const char *);
54+
4855
#endif /* !_XBPS_PKGDB_DEFS_H_ */

include/idtree.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef IDTREE_H
2+
#define IDTREE_H
3+
4+
#include <sys/types.h>
5+
6+
struct idtree {
7+
long id;
8+
char *name;
9+
struct idtree *left, *right;
10+
int level;
11+
};
12+
13+
char * idtree_username(struct idtree *, uid_t);
14+
char * idtree_groupname(struct idtree *, gid_t);
15+
void idtree_free(struct idtree *);
16+
17+
#endif /* IDTREE_H */

lib/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ LIBFETCH_INCS = fetch/common.h
3232
LIBFETCH_GEN = fetch/ftperr.h fetch/httperr.h
3333

3434
# External code used by libxbps
35-
EXTOBJS = external/dewey.o external/fexec.o external/mkpath.o
35+
EXTOBJS = external/dewey.o external/fexec.o external/mkpath.o external/idtree.o
3636

3737
# libxbps
3838
OBJS = package_configure.o package_config_files.o package_orphans.o

0 commit comments

Comments
 (0)