]>
Commit | Line | Data |
---|---|---|
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 | ||
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 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 | ||
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 | |
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 | ||
73 | static 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 | ||
112 | int 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 | ||
139 | int 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 | } |