]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nss-systemd/userdb-glue.c
nss-systemd: set USERDB_SUPPRESS_SHADOW flag when looking up user records
[thirdparty/systemd.git] / src / nss-systemd / userdb-glue.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
1684c56f
LP
2
3#include "env-util.h"
4#include "fd-util.h"
037b0a47 5#include "nss-systemd.h"
1684c56f 6#include "strv.h"
e60775cb 7#include "user-record-nss.h"
1684c56f 8#include "user-record.h"
53c25ac9 9#include "user-util.h"
1684c56f
LP
10#include "userdb-glue.h"
11#include "userdb.h"
12
13UserDBFlags nss_glue_userdb_flags(void) {
80d88a82 14 UserDBFlags flags = USERDB_EXCLUDE_NSS;
1684c56f
LP
15
16 /* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
17 if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
80d88a82 18 flags |= USERDB_EXCLUDE_DYNAMIC_USER;
1684c56f
LP
19
20 return flags;
21}
22
23int nss_pack_user_record(
24 UserRecord *hr,
25 struct passwd *pwd,
26 char *buffer,
27 size_t buflen) {
28
29 const char *rn, *hd, *shell;
30 size_t required;
31
32 assert(hr);
33 assert(pwd);
34
35 assert_se(hr->user_name);
36 required = strlen(hr->user_name) + 1;
37
38 assert_se(rn = user_record_real_name(hr));
39 required += strlen(rn) + 1;
40
41 assert_se(hd = user_record_home_directory(hr));
42 required += strlen(hd) + 1;
43
44 assert_se(shell = user_record_shell(hr));
45 required += strlen(shell) + 1;
46
47 if (buflen < required)
48 return -ERANGE;
49
50 *pwd = (struct passwd) {
51 .pw_name = buffer,
52 .pw_uid = hr->uid,
53 .pw_gid = user_record_gid(hr),
53c25ac9 54 .pw_passwd = (char*) PASSWORD_SEE_SHADOW,
1684c56f
LP
55 };
56
57 assert(buffer);
58
59 pwd->pw_gecos = stpcpy(pwd->pw_name, hr->user_name) + 1;
60 pwd->pw_dir = stpcpy(pwd->pw_gecos, rn) + 1;
61 pwd->pw_shell = stpcpy(pwd->pw_dir, hd) + 1;
62 strcpy(pwd->pw_shell, shell);
63
64 return 0;
65}
66
67enum nss_status userdb_getpwnam(
68 const char *name,
69 struct passwd *pwd,
70 char *buffer, size_t buflen,
71 int *errnop) {
72
73 _cleanup_(user_record_unrefp) UserRecord *hr = NULL;
74 int r;
75
76 assert(pwd);
77 assert(errnop);
78
037b0a47 79 if (_nss_systemd_is_blocked())
1684c56f
LP
80 return NSS_STATUS_NOTFOUND;
81
09001dbd 82 r = userdb_by_name(name, nss_glue_userdb_flags()|USERDB_SUPPRESS_SHADOW, &hr);
1684c56f
LP
83 if (r == -ESRCH)
84 return NSS_STATUS_NOTFOUND;
85 if (r < 0) {
86 *errnop = -r;
87 return NSS_STATUS_UNAVAIL;
88 }
89
90 r = nss_pack_user_record(hr, pwd, buffer, buflen);
91 if (r < 0) {
92 *errnop = -r;
93 return NSS_STATUS_TRYAGAIN;
94 }
95
96 return NSS_STATUS_SUCCESS;
97}
98
99enum nss_status userdb_getpwuid(
100 uid_t uid,
101 struct passwd *pwd,
102 char *buffer,
103 size_t buflen,
104 int *errnop) {
105
106 _cleanup_(user_record_unrefp) UserRecord *hr = NULL;
107 int r;
108
109 assert(pwd);
110 assert(errnop);
111
037b0a47 112 if (_nss_systemd_is_blocked())
1684c56f
LP
113 return NSS_STATUS_NOTFOUND;
114
09001dbd 115 r = userdb_by_uid(uid, nss_glue_userdb_flags()|USERDB_SUPPRESS_SHADOW, &hr);
1684c56f
LP
116 if (r == -ESRCH)
117 return NSS_STATUS_NOTFOUND;
118 if (r < 0) {
119 *errnop = -r;
120 return NSS_STATUS_UNAVAIL;
121 }
122
123 r = nss_pack_user_record(hr, pwd, buffer, buflen);
124 if (r < 0) {
125 *errnop = -r;
126 return NSS_STATUS_TRYAGAIN;
127 }
128
129 return NSS_STATUS_SUCCESS;
130}
131
132int nss_pack_group_record(
133 GroupRecord *g,
134 char **extra_members,
135 struct group *gr,
136 char *buffer,
137 size_t buflen) {
138
139 char **array = NULL, *p, **m;
140 size_t required, n = 0, i = 0;
141
142 assert(g);
143 assert(gr);
144
145 assert_se(g->group_name);
146 required = strlen(g->group_name) + 1;
147
148 STRV_FOREACH(m, g->members) {
149 required += sizeof(char*); /* space for ptr array entry */
150 required += strlen(*m) + 1;
151 n++;
152 }
153 STRV_FOREACH(m, extra_members) {
154 if (strv_contains(g->members, *m))
155 continue;
156
157 required += sizeof(char*);
158 required += strlen(*m) + 1;
159 n++;
160 }
161
162 required += sizeof(char*); /* trailing NULL in ptr array entry */
163
164 if (buflen < required)
165 return -ERANGE;
166
167 array = (char**) buffer; /* place ptr array at beginning of buffer, under assumption buffer is aligned */
168 p = buffer + sizeof(void*) * (n + 1); /* place member strings right after the ptr array */
169
170 STRV_FOREACH(m, g->members) {
171 array[i++] = p;
172 p = stpcpy(p, *m) + 1;
173 }
174 STRV_FOREACH(m, extra_members) {
175 if (strv_contains(g->members, *m))
176 continue;
177
178 array[i++] = p;
179 p = stpcpy(p, *m) + 1;
180 }
181
182 assert_se(i == n);
183 array[n] = NULL;
184
185 *gr = (struct group) {
186 .gr_name = strcpy(p, g->group_name),
187 .gr_gid = g->gid,
53c25ac9 188 .gr_passwd = (char*) PASSWORD_SEE_SHADOW,
1684c56f
LP
189 .gr_mem = array,
190 };
191
192 return 0;
193}
194
195enum nss_status userdb_getgrnam(
196 const char *name,
197 struct group *gr,
198 char *buffer,
199 size_t buflen,
200 int *errnop) {
201
202 _cleanup_(group_record_unrefp) GroupRecord *g = NULL;
203 _cleanup_strv_free_ char **members = NULL;
204 int r;
205
206 assert(gr);
207 assert(errnop);
208
037b0a47 209 if (_nss_systemd_is_blocked())
1684c56f
LP
210 return NSS_STATUS_NOTFOUND;
211
09001dbd 212 r = groupdb_by_name(name, nss_glue_userdb_flags()|USERDB_SUPPRESS_SHADOW, &g);
1684c56f
LP
213 if (r < 0 && r != -ESRCH) {
214 *errnop = -r;
215 return NSS_STATUS_UNAVAIL;
216 }
217
09001dbd 218 r = membershipdb_by_group_strv(name, nss_glue_userdb_flags()|USERDB_SUPPRESS_SHADOW, &members);
a1aa41e4 219 if (r < 0 && r != -ESRCH) {
1684c56f
LP
220 *errnop = -r;
221 return NSS_STATUS_UNAVAIL;
222 }
223
224 if (!g) {
037b0a47 225 _cleanup_(_nss_systemd_unblockp) bool blocked = false;
1684c56f
LP
226
227 if (strv_isempty(members))
228 return NSS_STATUS_NOTFOUND;
229
230 /* Grmbl, so we are supposed to extend a group entry, but the group entry itself is not
231 * accessible via non-NSS. Hence let's do what we have to do, and query NSS after all to
232 * acquire it, so that we can extend it (that's because glibc's group merging feature will
233 * merge groups only if both GID and name match and thus we need to have both first). It
234 * sucks behaving recursively likely this, but it's apparently what everybody does. We break
037b0a47
LP
235 * the recursion for ourselves via the _nss_systemd_block_nss() lock. */
236
237 r = _nss_systemd_block(true);
238 if (r < 0)
239 return r;
1684c56f 240
037b0a47 241 blocked = true;
1684c56f 242
ed30170e 243 r = nss_group_record_by_name(name, false, &g);
1684c56f
LP
244 if (r == -ESRCH)
245 return NSS_STATUS_NOTFOUND;
246 if (r < 0) {
247 *errnop = -r;
248 return NSS_STATUS_UNAVAIL;
249 }
250 }
251
252 r = nss_pack_group_record(g, members, gr, buffer, buflen);
253 if (r < 0) {
254 *errnop = -r;
255 return NSS_STATUS_TRYAGAIN;
256 }
257
258 return NSS_STATUS_SUCCESS;
259}
260
261enum nss_status userdb_getgrgid(
262 gid_t gid,
263 struct group *gr,
264 char *buffer,
265 size_t buflen,
266 int *errnop) {
267
268
269 _cleanup_(group_record_unrefp) GroupRecord *g = NULL;
270 _cleanup_strv_free_ char **members = NULL;
271 bool from_nss;
272 int r;
273
274 assert(gr);
275 assert(errnop);
276
037b0a47 277 if (_nss_systemd_is_blocked())
1684c56f
LP
278 return NSS_STATUS_NOTFOUND;
279
09001dbd 280 r = groupdb_by_gid(gid, nss_glue_userdb_flags()|USERDB_SUPPRESS_SHADOW, &g);
1684c56f
LP
281 if (r < 0 && r != -ESRCH) {
282 *errnop = -r;
283 return NSS_STATUS_UNAVAIL;
284 }
285
286 if (!g) {
037b0a47 287 _cleanup_(_nss_systemd_unblockp) bool blocked = false;
1684c56f
LP
288
289 /* So, quite possibly we have to extend an existing group record with additional members. But
290 * to do this we need to know the group name first. The group didn't exist via non-NSS
291 * queries though, hence let's try to acquire it here recursively via NSS. */
292
037b0a47
LP
293 r = _nss_systemd_block(true);
294 if (r < 0)
295 return r;
296
297 blocked = true;
1684c56f 298
ed30170e 299 r = nss_group_record_by_gid(gid, false, &g);
1684c56f
LP
300 if (r == -ESRCH)
301 return NSS_STATUS_NOTFOUND;
1684c56f
LP
302 if (r < 0) {
303 *errnop = -r;
304 return NSS_STATUS_UNAVAIL;
305 }
306
307 from_nss = true;
308 } else
309 from_nss = false;
310
09001dbd 311 r = membershipdb_by_group_strv(g->group_name, nss_glue_userdb_flags()|USERDB_SUPPRESS_SHADOW, &members);
a1aa41e4 312 if (r < 0 && r != -ESRCH) {
1684c56f
LP
313 *errnop = -r;
314 return NSS_STATUS_UNAVAIL;
315 }
316
162392b7 317 /* If we acquired the record via NSS then there's no reason to respond unless we have to augment the
1684c56f
LP
318 * list of members of the group */
319 if (from_nss && strv_isempty(members))
320 return NSS_STATUS_NOTFOUND;
321
322 r = nss_pack_group_record(g, members, gr, buffer, buflen);
323 if (r < 0) {
324 *errnop = -r;
325 return NSS_STATUS_TRYAGAIN;
326 }
327
328 return NSS_STATUS_SUCCESS;
329}