]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/offline-passwd.c
offline-passwd: use chase_symlinks()
[thirdparty/systemd.git] / src / shared / offline-passwd.c
CommitLineData
a3451c2c
LP
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include "fd-util.h"
00267438 4#include "fs-util.h"
a3451c2c
LP
5#include "offline-passwd.h"
6#include "path-util.h"
7#include "user-util.h"
8
9DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(uid_gid_hash_ops, char, string_hash_func, string_compare_func, free);
10
241947d1 11static int open_passwd_file(const char *root, const char *fname, FILE **ret_file) {
00267438
LP
12 _cleanup_free_ char *p = NULL;
13 _cleanup_close_ int fd = -1;
14
15 fd = chase_symlinks_and_open(fname, root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC, &p);
16 if (fd < 0)
17 return fd;
a3451c2c 18
00267438 19 FILE *f = fdopen(fd, "r");
241947d1
ZJS
20 if (!f)
21 return -errno;
22
00267438
LP
23 TAKE_FD(fd);
24
241947d1
ZJS
25 log_debug("Reading %s entries from %s...", basename(fname), p);
26
27 *ret_file = f;
28 return 0;
29}
30
31static int populate_uid_cache(const char *root, Hashmap **ret) {
32 _cleanup_(hashmap_freep) Hashmap *cache = NULL;
a3451c2c
LP
33 int r;
34
241947d1
ZJS
35 cache = hashmap_new(&uid_gid_hash_ops);
36 if (!cache)
37 return -ENOMEM;
a3451c2c 38
241947d1
ZJS
39 /* The directory list is harcoded here: /etc is the standard, and rpm-ostree uses /usr/lib. This
40 * could be made configurable, but I don't see the point right now. */
a3451c2c 41
241947d1
ZJS
42 const char *fname;
43 FOREACH_STRING(fname, "/etc/passwd", "/usr/lib/passwd") {
44 _cleanup_fclose_ FILE *f = NULL;
a3451c2c 45
241947d1
ZJS
46 r = open_passwd_file(root, fname, &f);
47 if (r == -ENOENT)
48 continue;
49 if (r < 0)
50 return r;
a3451c2c 51
241947d1 52 struct passwd *pw;
a3451c2c
LP
53 while ((r = fgetpwent_sane(f, &pw)) > 0) {
54 _cleanup_free_ char *n = NULL;
55
56 n = strdup(pw->pw_name);
57 if (!n)
58 return -ENOMEM;
59
241947d1
ZJS
60 r = hashmap_put(cache, n, UID_TO_PTR(pw->pw_uid));
61 if (IN_SET(r, 0 -EEXIST))
a3451c2c 62 continue;
a3451c2c
LP
63 if (r < 0)
64 return r;
241947d1
ZJS
65 TAKE_PTR(n);
66 }
67 }
68
69 *ret = TAKE_PTR(cache);
70 return 0;
71}
72
73static int populate_gid_cache(const char *root, Hashmap **ret) {
74 _cleanup_(hashmap_freep) Hashmap *cache = NULL;
75 int r;
76
77 cache = hashmap_new(&uid_gid_hash_ops);
78 if (!cache)
79 return -ENOMEM;
80
81 const char *fname;
82 FOREACH_STRING(fname, "/etc/group", "/usr/lib/group") {
83 _cleanup_fclose_ FILE *f = NULL;
a3451c2c 84
241947d1
ZJS
85 r = open_passwd_file(root, fname, &f);
86 if (r == -ENOENT)
87 continue;
88 if (r < 0)
89 return r;
90
91 struct group *gr;
92 while ((r = fgetgrent_sane(f, &gr)) > 0) {
93 _cleanup_free_ char *n = NULL;
94
95 n = strdup(gr->gr_name);
96 if (!n)
97 return -ENOMEM;
98
99 r = hashmap_put(cache, n, GID_TO_PTR(gr->gr_gid));
100 if (IN_SET(r, 0, -EEXIST))
101 continue;
102 if (r < 0)
103 return r;
a3451c2c
LP
104 TAKE_PTR(n);
105 }
241947d1
ZJS
106 }
107
108 *ret = TAKE_PTR(cache);
109 return 0;
110}
111
112int name_to_uid_offline(
113 const char *root,
114 const char *user,
115 uid_t *ret_uid,
116 Hashmap **cache) {
117
118 void *found;
119 int r;
a3451c2c 120
241947d1
ZJS
121 assert(user);
122 assert(ret_uid);
123 assert(cache);
124
125 if (!*cache) {
126 r = populate_uid_cache(root, cache);
127 if (r < 0)
128 return r;
a3451c2c
LP
129 }
130
131 found = hashmap_get(*cache, user);
132 if (!found)
133 return -ESRCH;
134
135 *ret_uid = PTR_TO_UID(found);
136 return 0;
137}
138
139int name_to_gid_offline(
140 const char *root,
141 const char *group,
142 gid_t *ret_gid,
143 Hashmap **cache) {
144
145 void *found;
146 int r;
147
148 assert(group);
149 assert(ret_gid);
150 assert(cache);
151
152 if (!*cache) {
241947d1
ZJS
153 r = populate_gid_cache(root, cache);
154 if (r < 0)
155 return r;
a3451c2c
LP
156 }
157
158 found = hashmap_get(*cache, group);
159 if (!found)
160 return -ESRCH;
161
162 *ret_gid = PTR_TO_GID(found);
163 return 0;
164}