]>
Commit | Line | Data |
---|---|---|
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 | ||
9 | DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(uid_gid_hash_ops, char, string_hash_func, string_compare_func, free); | |
10 | ||
241947d1 | 11 | static 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 | ||
31 | static 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 | ||
72 | static 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 | ||
110 | int 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 | ||
137 | int 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 | } |