]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/tmpfiles/offline-passwd.c
tree-wide: use -EBADF for fd initialization
[thirdparty/systemd.git] / src / tmpfiles / offline-passwd.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
a3451c2c 2
f4351959 3#include "chase-symlinks.h"
a3451c2c
LP
4#include "fd-util.h"
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 12 _cleanup_free_ char *p = NULL;
254d1313 13 _cleanup_close_ int fd = -EBADF;
00267438
LP
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
69e3234d 39 /* The directory list is hardcoded here: /etc is the standard, and rpm-ostree uses /usr/lib. This
241947d1 40 * could be made configurable, but I don't see the point right now. */
a3451c2c 41
241947d1
ZJS
42 FOREACH_STRING(fname, "/etc/passwd", "/usr/lib/passwd") {
43 _cleanup_fclose_ FILE *f = NULL;
a3451c2c 44
241947d1
ZJS
45 r = open_passwd_file(root, fname, &f);
46 if (r == -ENOENT)
47 continue;
48 if (r < 0)
49 return r;
a3451c2c 50
241947d1 51 struct passwd *pw;
a3451c2c
LP
52 while ((r = fgetpwent_sane(f, &pw)) > 0) {
53 _cleanup_free_ char *n = NULL;
54
55 n = strdup(pw->pw_name);
56 if (!n)
57 return -ENOMEM;
58
241947d1
ZJS
59 r = hashmap_put(cache, n, UID_TO_PTR(pw->pw_uid));
60 if (IN_SET(r, 0 -EEXIST))
a3451c2c 61 continue;
a3451c2c
LP
62 if (r < 0)
63 return r;
241947d1
ZJS
64 TAKE_PTR(n);
65 }
66 }
67
68 *ret = TAKE_PTR(cache);
69 return 0;
70}
71
72static int populate_gid_cache(const char *root, Hashmap **ret) {
73 _cleanup_(hashmap_freep) Hashmap *cache = NULL;
74 int r;
75
76 cache = hashmap_new(&uid_gid_hash_ops);
77 if (!cache)
78 return -ENOMEM;
79
241947d1
ZJS
80 FOREACH_STRING(fname, "/etc/group", "/usr/lib/group") {
81 _cleanup_fclose_ FILE *f = NULL;
a3451c2c 82
241947d1
ZJS
83 r = open_passwd_file(root, fname, &f);
84 if (r == -ENOENT)
85 continue;
86 if (r < 0)
87 return r;
88
89 struct group *gr;
90 while ((r = fgetgrent_sane(f, &gr)) > 0) {
91 _cleanup_free_ char *n = NULL;
92
93 n = strdup(gr->gr_name);
94 if (!n)
95 return -ENOMEM;
96
97 r = hashmap_put(cache, n, GID_TO_PTR(gr->gr_gid));
98 if (IN_SET(r, 0, -EEXIST))
99 continue;
100 if (r < 0)
101 return r;
a3451c2c
LP
102 TAKE_PTR(n);
103 }
241947d1
ZJS
104 }
105
106 *ret = TAKE_PTR(cache);
107 return 0;
108}
109
110int name_to_uid_offline(
111 const char *root,
112 const char *user,
113 uid_t *ret_uid,
114 Hashmap **cache) {
115
116 void *found;
117 int r;
a3451c2c 118
241947d1
ZJS
119 assert(user);
120 assert(ret_uid);
121 assert(cache);
122
123 if (!*cache) {
124 r = populate_uid_cache(root, cache);
125 if (r < 0)
126 return r;
a3451c2c
LP
127 }
128
129 found = hashmap_get(*cache, user);
130 if (!found)
131 return -ESRCH;
132
133 *ret_uid = PTR_TO_UID(found);
134 return 0;
135}
136
137int name_to_gid_offline(
138 const char *root,
139 const char *group,
140 gid_t *ret_gid,
141 Hashmap **cache) {
142
143 void *found;
144 int r;
145
146 assert(group);
147 assert(ret_gid);
148 assert(cache);
149
150 if (!*cache) {
241947d1
ZJS
151 r = populate_gid_cache(root, cache);
152 if (r < 0)
153 return r;
a3451c2c
LP
154 }
155
156 found = hashmap_get(*cache, group);
157 if (!found)
158 return -ESRCH;
159
160 *ret_gid = PTR_TO_GID(found);
161 return 0;
162}