]>
Commit | Line | Data |
---|---|---|
52ad194e | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
5eef597e | 2 | |
5eef597e | 3 | #include <netdb.h> |
db2df898 | 4 | #include <nss.h> |
5eef597e MP |
5 | |
6 | #include "sd-bus.h" | |
7 | #include "sd-login.h" | |
db2df898 MP |
8 | |
9 | #include "alloc-util.h" | |
7035cd9e | 10 | #include "bus-common-errors.h" |
8a584da2 | 11 | #include "env-util.h" |
bb4f798a MB |
12 | #include "errno-util.h" |
13 | #include "format-util.h" | |
13d276d0 | 14 | #include "hostname-util.h" |
db2df898 MP |
15 | #include "in-addr-util.h" |
16 | #include "macro.h" | |
bb4f798a | 17 | #include "memory-util.h" |
db2df898 | 18 | #include "nss-util.h" |
4c89c718 | 19 | #include "signal-util.h" |
db2df898 MP |
20 | #include "string-util.h" |
21 | #include "user-util.h" | |
5eef597e MP |
22 | |
23 | NSS_GETHOSTBYNAME_PROTOTYPES(mymachines); | |
7035cd9e MP |
24 | NSS_GETPW_PROTOTYPES(mymachines); |
25 | NSS_GETGR_PROTOTYPES(mymachines); | |
5eef597e | 26 | |
4c89c718 MP |
27 | #define HOST_UID_LIMIT ((uid_t) UINT32_C(0x10000)) |
28 | #define HOST_GID_LIMIT ((gid_t) UINT32_C(0x10000)) | |
29 | ||
5eef597e MP |
30 | static int count_addresses(sd_bus_message *m, int af, unsigned *ret) { |
31 | unsigned c = 0; | |
32 | int r; | |
33 | ||
34 | assert(m); | |
35 | assert(ret); | |
36 | ||
37 | while ((r = sd_bus_message_enter_container(m, 'r', "iay")) > 0) { | |
38 | int family; | |
39 | ||
40 | r = sd_bus_message_read(m, "i", &family); | |
41 | if (r < 0) | |
42 | return r; | |
43 | ||
44 | r = sd_bus_message_skip(m, "ay"); | |
45 | if (r < 0) | |
46 | return r; | |
47 | ||
48 | r = sd_bus_message_exit_container(m); | |
49 | if (r < 0) | |
50 | return r; | |
51 | ||
52 | if (af != AF_UNSPEC && family != af) | |
53 | continue; | |
54 | ||
aa27b158 | 55 | c++; |
5eef597e MP |
56 | } |
57 | if (r < 0) | |
58 | return r; | |
59 | ||
60 | r = sd_bus_message_rewind(m, false); | |
61 | if (r < 0) | |
62 | return r; | |
63 | ||
64 | *ret = c; | |
65 | return 0; | |
66 | } | |
67 | ||
6e866b33 MB |
68 | static bool avoid_deadlock(void) { |
69 | ||
70 | /* Check whether this lookup might have a chance of deadlocking because we are called from the service manager | |
71 | * code activating systemd-machined.service. After all, we shouldn't synchronously do lookups to | |
72 | * systemd-machined if we are required to finish before it can be started. This of course won't detect all | |
73 | * possible dead locks of this kind, but it should work for the most obvious cases. */ | |
74 | ||
75 | if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */ | |
76 | return false; | |
77 | ||
78 | return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-machined.service") && | |
79 | streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system"); | |
80 | } | |
81 | ||
5eef597e MP |
82 | enum nss_status _nss_mymachines_gethostbyname4_r( |
83 | const char *name, | |
84 | struct gaih_addrtuple **pat, | |
85 | char *buffer, size_t buflen, | |
86 | int *errnop, int *h_errnop, | |
87 | int32_t *ttlp) { | |
88 | ||
89 | struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; | |
4c89c718 MP |
90 | _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; |
91 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; | |
5eef597e MP |
92 | _cleanup_free_ int *ifindices = NULL; |
93 | _cleanup_free_ char *class = NULL; | |
94 | size_t l, ms, idx; | |
95 | unsigned i = 0, c = 0; | |
96 | char *r_name; | |
97 | int n_ifindices, r; | |
98 | ||
6e866b33 | 99 | PROTECT_ERRNO; |
4c89c718 MP |
100 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); |
101 | ||
5eef597e MP |
102 | assert(name); |
103 | assert(pat); | |
104 | assert(buffer); | |
105 | assert(errnop); | |
106 | assert(h_errnop); | |
107 | ||
108 | r = sd_machine_get_class(name, &class); | |
109 | if (r < 0) | |
110 | goto fail; | |
111 | if (!streq(class, "container")) { | |
112 | r = -ENOTTY; | |
113 | goto fail; | |
114 | } | |
115 | ||
116 | n_ifindices = sd_machine_get_ifindices(name, &ifindices); | |
117 | if (n_ifindices < 0) { | |
118 | r = n_ifindices; | |
119 | goto fail; | |
120 | } | |
121 | ||
6e866b33 MB |
122 | if (avoid_deadlock()) { |
123 | r = -EDEADLK; | |
124 | goto fail; | |
125 | } | |
126 | ||
5eef597e MP |
127 | r = sd_bus_open_system(&bus); |
128 | if (r < 0) | |
129 | goto fail; | |
130 | ||
131 | r = sd_bus_call_method(bus, | |
132 | "org.freedesktop.machine1", | |
133 | "/org/freedesktop/machine1", | |
134 | "org.freedesktop.machine1.Manager", | |
135 | "GetMachineAddresses", | |
136 | NULL, | |
137 | &reply, | |
138 | "s", name); | |
139 | if (r < 0) | |
140 | goto fail; | |
141 | ||
142 | r = sd_bus_message_enter_container(reply, 'a', "(iay)"); | |
143 | if (r < 0) | |
144 | goto fail; | |
145 | ||
146 | r = count_addresses(reply, AF_UNSPEC, &c); | |
147 | if (r < 0) | |
148 | goto fail; | |
149 | ||
150 | if (c <= 0) { | |
5eef597e MP |
151 | *h_errnop = HOST_NOT_FOUND; |
152 | return NSS_STATUS_NOTFOUND; | |
153 | } | |
154 | ||
155 | l = strlen(name); | |
156 | ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c; | |
157 | if (buflen < ms) { | |
7c20daf6 | 158 | UNPROTECT_ERRNO; |
2897b343 MP |
159 | *errnop = ERANGE; |
160 | *h_errnop = NETDB_INTERNAL; | |
5eef597e MP |
161 | return NSS_STATUS_TRYAGAIN; |
162 | } | |
163 | ||
164 | /* First, append name */ | |
165 | r_name = buffer; | |
166 | memcpy(r_name, name, l+1); | |
167 | idx = ALIGN(l+1); | |
168 | ||
169 | /* Second, append addresses */ | |
170 | r_tuple_first = (struct gaih_addrtuple*) (buffer + idx); | |
171 | while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) { | |
172 | int family; | |
173 | const void *a; | |
174 | size_t sz; | |
175 | ||
176 | r = sd_bus_message_read(reply, "i", &family); | |
177 | if (r < 0) | |
178 | goto fail; | |
179 | ||
180 | r = sd_bus_message_read_array(reply, 'y', &a, &sz); | |
181 | if (r < 0) | |
182 | goto fail; | |
183 | ||
184 | r = sd_bus_message_exit_container(reply); | |
185 | if (r < 0) | |
186 | goto fail; | |
187 | ||
188 | if (!IN_SET(family, AF_INET, AF_INET6)) { | |
189 | r = -EAFNOSUPPORT; | |
190 | goto fail; | |
191 | } | |
192 | ||
193 | if (sz != FAMILY_ADDRESS_SIZE(family)) { | |
194 | r = -EINVAL; | |
195 | goto fail; | |
196 | } | |
197 | ||
198 | r_tuple = (struct gaih_addrtuple*) (buffer + idx); | |
199 | r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple))); | |
200 | r_tuple->name = r_name; | |
201 | r_tuple->family = family; | |
202 | r_tuple->scopeid = n_ifindices == 1 ? ifindices[0] : 0; | |
203 | memcpy(r_tuple->addr, a, sz); | |
204 | ||
205 | idx += ALIGN(sizeof(struct gaih_addrtuple)); | |
206 | i++; | |
207 | } | |
208 | ||
209 | assert(i == c); | |
210 | ||
211 | r = sd_bus_message_exit_container(reply); | |
212 | if (r < 0) | |
213 | goto fail; | |
214 | ||
215 | assert(idx == ms); | |
216 | ||
217 | if (*pat) | |
218 | **pat = *r_tuple_first; | |
219 | else | |
220 | *pat = r_tuple_first; | |
221 | ||
222 | if (ttlp) | |
223 | *ttlp = 0; | |
224 | ||
6e866b33 MB |
225 | /* Explicitly reset both *h_errnop and h_errno to work around |
226 | * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */ | |
5eef597e MP |
227 | *h_errnop = NETDB_SUCCESS; |
228 | h_errno = 0; | |
229 | ||
230 | return NSS_STATUS_SUCCESS; | |
231 | ||
232 | fail: | |
7c20daf6 | 233 | UNPROTECT_ERRNO; |
5eef597e | 234 | *errnop = -r; |
bb4f798a | 235 | *h_errnop = NO_RECOVERY; |
5eef597e MP |
236 | return NSS_STATUS_UNAVAIL; |
237 | } | |
238 | ||
239 | enum nss_status _nss_mymachines_gethostbyname3_r( | |
240 | const char *name, | |
241 | int af, | |
242 | struct hostent *result, | |
243 | char *buffer, size_t buflen, | |
244 | int *errnop, int *h_errnop, | |
245 | int32_t *ttlp, | |
246 | char **canonp) { | |
247 | ||
4c89c718 MP |
248 | _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; |
249 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; | |
5eef597e MP |
250 | _cleanup_free_ char *class = NULL; |
251 | unsigned c = 0, i = 0; | |
252 | char *r_name, *r_aliases, *r_addr, *r_addr_list; | |
253 | size_t l, idx, ms, alen; | |
254 | int r; | |
255 | ||
6e866b33 | 256 | PROTECT_ERRNO; |
4c89c718 MP |
257 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); |
258 | ||
5eef597e MP |
259 | assert(name); |
260 | assert(result); | |
261 | assert(buffer); | |
262 | assert(errnop); | |
263 | assert(h_errnop); | |
264 | ||
265 | if (af == AF_UNSPEC) | |
266 | af = AF_INET; | |
267 | ||
268 | if (af != AF_INET && af != AF_INET6) { | |
269 | r = -EAFNOSUPPORT; | |
270 | goto fail; | |
271 | } | |
272 | ||
273 | r = sd_machine_get_class(name, &class); | |
274 | if (r < 0) | |
275 | goto fail; | |
276 | if (!streq(class, "container")) { | |
277 | r = -ENOTTY; | |
278 | goto fail; | |
279 | } | |
280 | ||
6e866b33 MB |
281 | if (avoid_deadlock()) { |
282 | r = -EDEADLK; | |
283 | goto fail; | |
284 | } | |
285 | ||
5eef597e MP |
286 | r = sd_bus_open_system(&bus); |
287 | if (r < 0) | |
288 | goto fail; | |
289 | ||
290 | r = sd_bus_call_method(bus, | |
291 | "org.freedesktop.machine1", | |
292 | "/org/freedesktop/machine1", | |
293 | "org.freedesktop.machine1.Manager", | |
294 | "GetMachineAddresses", | |
295 | NULL, | |
296 | &reply, | |
297 | "s", name); | |
298 | if (r < 0) | |
299 | goto fail; | |
300 | ||
301 | r = sd_bus_message_enter_container(reply, 'a', "(iay)"); | |
302 | if (r < 0) | |
303 | goto fail; | |
304 | ||
305 | r = count_addresses(reply, af, &c); | |
306 | if (r < 0) | |
307 | goto fail; | |
308 | ||
309 | if (c <= 0) { | |
5eef597e MP |
310 | *h_errnop = HOST_NOT_FOUND; |
311 | return NSS_STATUS_NOTFOUND; | |
312 | } | |
313 | ||
314 | alen = FAMILY_ADDRESS_SIZE(af); | |
315 | l = strlen(name); | |
316 | ||
317 | ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*); | |
318 | ||
319 | if (buflen < ms) { | |
7c20daf6 | 320 | UNPROTECT_ERRNO; |
2897b343 MP |
321 | *errnop = ERANGE; |
322 | *h_errnop = NETDB_INTERNAL; | |
5eef597e MP |
323 | return NSS_STATUS_TRYAGAIN; |
324 | } | |
325 | ||
326 | /* First, append name */ | |
327 | r_name = buffer; | |
328 | memcpy(r_name, name, l+1); | |
329 | idx = ALIGN(l+1); | |
330 | ||
331 | /* Second, create aliases array */ | |
332 | r_aliases = buffer + idx; | |
333 | ((char**) r_aliases)[0] = NULL; | |
334 | idx += sizeof(char*); | |
335 | ||
336 | /* Third, append addresses */ | |
337 | r_addr = buffer + idx; | |
338 | while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) { | |
339 | int family; | |
340 | const void *a; | |
341 | size_t sz; | |
342 | ||
343 | r = sd_bus_message_read(reply, "i", &family); | |
344 | if (r < 0) | |
345 | goto fail; | |
346 | ||
347 | r = sd_bus_message_read_array(reply, 'y', &a, &sz); | |
348 | if (r < 0) | |
349 | goto fail; | |
350 | ||
351 | r = sd_bus_message_exit_container(reply); | |
352 | if (r < 0) | |
353 | goto fail; | |
354 | ||
355 | if (family != af) | |
356 | continue; | |
357 | ||
358 | if (sz != alen) { | |
359 | r = -EINVAL; | |
360 | goto fail; | |
361 | } | |
362 | ||
363 | memcpy(r_addr + i*ALIGN(alen), a, alen); | |
364 | i++; | |
365 | } | |
366 | ||
367 | assert(i == c); | |
368 | idx += c * ALIGN(alen); | |
369 | ||
370 | r = sd_bus_message_exit_container(reply); | |
371 | if (r < 0) | |
372 | goto fail; | |
373 | ||
374 | /* Third, append address pointer array */ | |
375 | r_addr_list = buffer + idx; | |
376 | for (i = 0; i < c; i++) | |
377 | ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen); | |
378 | ||
379 | ((char**) r_addr_list)[i] = NULL; | |
380 | idx += (c+1) * sizeof(char*); | |
381 | ||
382 | assert(idx == ms); | |
383 | ||
384 | result->h_name = r_name; | |
385 | result->h_aliases = (char**) r_aliases; | |
386 | result->h_addrtype = af; | |
387 | result->h_length = alen; | |
388 | result->h_addr_list = (char**) r_addr_list; | |
389 | ||
390 | if (ttlp) | |
391 | *ttlp = 0; | |
392 | ||
393 | if (canonp) | |
394 | *canonp = r_name; | |
395 | ||
6e866b33 MB |
396 | /* Explicitly reset both *h_errnop and h_errno to work around |
397 | * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */ | |
5eef597e MP |
398 | *h_errnop = NETDB_SUCCESS; |
399 | h_errno = 0; | |
400 | ||
401 | return NSS_STATUS_SUCCESS; | |
402 | ||
403 | fail: | |
7c20daf6 | 404 | UNPROTECT_ERRNO; |
5eef597e | 405 | *errnop = -r; |
bb4f798a | 406 | *h_errnop = NO_RECOVERY; |
5eef597e MP |
407 | return NSS_STATUS_UNAVAIL; |
408 | } | |
409 | ||
7035cd9e MP |
410 | NSS_GETHOSTBYNAME_FALLBACKS(mymachines); |
411 | ||
412 | enum nss_status _nss_mymachines_getpwnam_r( | |
413 | const char *name, | |
414 | struct passwd *pwd, | |
415 | char *buffer, size_t buflen, | |
416 | int *errnop) { | |
417 | ||
4c89c718 MP |
418 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
419 | _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; | |
420 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; | |
7035cd9e MP |
421 | const char *p, *e, *machine; |
422 | uint32_t mapped; | |
423 | uid_t uid; | |
424 | size_t l; | |
425 | int r; | |
426 | ||
6e866b33 | 427 | PROTECT_ERRNO; |
4c89c718 MP |
428 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); |
429 | ||
7035cd9e MP |
430 | assert(name); |
431 | assert(pwd); | |
432 | ||
433 | p = startswith(name, "vu-"); | |
434 | if (!p) | |
6e866b33 | 435 | return NSS_STATUS_NOTFOUND; |
7035cd9e MP |
436 | |
437 | e = strrchr(p, '-'); | |
438 | if (!e || e == p) | |
6e866b33 | 439 | return NSS_STATUS_NOTFOUND; |
7035cd9e | 440 | |
4c89c718 | 441 | if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */ |
6e866b33 | 442 | return NSS_STATUS_NOTFOUND; |
4c89c718 | 443 | |
7035cd9e MP |
444 | r = parse_uid(e + 1, &uid); |
445 | if (r < 0) | |
6e866b33 | 446 | return NSS_STATUS_NOTFOUND; |
7035cd9e MP |
447 | |
448 | machine = strndupa(p, e - p); | |
449 | if (!machine_name_is_valid(machine)) | |
6e866b33 | 450 | return NSS_STATUS_NOTFOUND; |
7035cd9e | 451 | |
f5e65279 | 452 | if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0) |
8a584da2 MP |
453 | /* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve |
454 | * these UIDs, but that should be unproblematic as containers should never be able to connect to a bus | |
455 | * running on the host. */ | |
6e866b33 MB |
456 | return NSS_STATUS_NOTFOUND; |
457 | ||
458 | if (avoid_deadlock()) { | |
459 | r = -EDEADLK; | |
460 | goto fail; | |
461 | } | |
8a584da2 | 462 | |
7035cd9e MP |
463 | r = sd_bus_open_system(&bus); |
464 | if (r < 0) | |
465 | goto fail; | |
466 | ||
467 | r = sd_bus_call_method(bus, | |
468 | "org.freedesktop.machine1", | |
469 | "/org/freedesktop/machine1", | |
470 | "org.freedesktop.machine1.Manager", | |
471 | "MapFromMachineUser", | |
472 | &error, | |
473 | &reply, | |
474 | "su", | |
475 | machine, (uint32_t) uid); | |
476 | if (r < 0) { | |
477 | if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING)) | |
6e866b33 | 478 | return NSS_STATUS_NOTFOUND; |
7035cd9e MP |
479 | |
480 | goto fail; | |
481 | } | |
482 | ||
483 | r = sd_bus_message_read(reply, "u", &mapped); | |
484 | if (r < 0) | |
485 | goto fail; | |
486 | ||
4c89c718 MP |
487 | /* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */ |
488 | if (mapped < HOST_UID_LIMIT || mapped == uid) | |
6e866b33 | 489 | return NSS_STATUS_NOTFOUND; |
4c89c718 | 490 | |
7035cd9e MP |
491 | l = strlen(name); |
492 | if (buflen < l+1) { | |
7c20daf6 | 493 | UNPROTECT_ERRNO; |
2897b343 | 494 | *errnop = ERANGE; |
7035cd9e MP |
495 | return NSS_STATUS_TRYAGAIN; |
496 | } | |
497 | ||
498 | memcpy(buffer, name, l+1); | |
499 | ||
500 | pwd->pw_name = buffer; | |
501 | pwd->pw_uid = mapped; | |
52ad194e | 502 | pwd->pw_gid = GID_NOBODY; |
7035cd9e MP |
503 | pwd->pw_gecos = buffer; |
504 | pwd->pw_passwd = (char*) "*"; /* locked */ | |
505 | pwd->pw_dir = (char*) "/"; | |
506 | pwd->pw_shell = (char*) "/sbin/nologin"; | |
507 | ||
7035cd9e MP |
508 | return NSS_STATUS_SUCCESS; |
509 | ||
7035cd9e | 510 | fail: |
7c20daf6 | 511 | UNPROTECT_ERRNO; |
7035cd9e MP |
512 | *errnop = -r; |
513 | return NSS_STATUS_UNAVAIL; | |
514 | } | |
515 | ||
516 | enum nss_status _nss_mymachines_getpwuid_r( | |
517 | uid_t uid, | |
518 | struct passwd *pwd, | |
519 | char *buffer, size_t buflen, | |
520 | int *errnop) { | |
521 | ||
4c89c718 MP |
522 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
523 | _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; | |
524 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; | |
b012e921 | 525 | const char *machine; |
7035cd9e MP |
526 | uint32_t mapped; |
527 | int r; | |
528 | ||
6e866b33 | 529 | PROTECT_ERRNO; |
4c89c718 MP |
530 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); |
531 | ||
2897b343 | 532 | if (!uid_is_valid(uid)) |
6e866b33 | 533 | return NSS_STATUS_NOTFOUND; |
7035cd9e MP |
534 | |
535 | /* We consider all uids < 65536 host uids */ | |
4c89c718 | 536 | if (uid < HOST_UID_LIMIT) |
6e866b33 | 537 | return NSS_STATUS_NOTFOUND; |
7035cd9e | 538 | |
f5e65279 | 539 | if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0) |
6e866b33 MB |
540 | return NSS_STATUS_NOTFOUND; |
541 | ||
542 | if (avoid_deadlock()) { | |
543 | r = -EDEADLK; | |
544 | goto fail; | |
545 | } | |
8a584da2 | 546 | |
7035cd9e MP |
547 | r = sd_bus_open_system(&bus); |
548 | if (r < 0) | |
549 | goto fail; | |
550 | ||
551 | r = sd_bus_call_method(bus, | |
552 | "org.freedesktop.machine1", | |
553 | "/org/freedesktop/machine1", | |
554 | "org.freedesktop.machine1.Manager", | |
555 | "MapToMachineUser", | |
556 | &error, | |
557 | &reply, | |
558 | "u", | |
559 | (uint32_t) uid); | |
560 | if (r < 0) { | |
561 | if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING)) | |
6e866b33 | 562 | return NSS_STATUS_NOTFOUND; |
7035cd9e MP |
563 | |
564 | goto fail; | |
565 | } | |
566 | ||
b012e921 | 567 | r = sd_bus_message_read(reply, "sou", &machine, NULL, &mapped); |
7035cd9e MP |
568 | if (r < 0) |
569 | goto fail; | |
570 | ||
4c89c718 | 571 | if (mapped == uid) |
6e866b33 | 572 | return NSS_STATUS_NOTFOUND; |
4c89c718 | 573 | |
7035cd9e | 574 | if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) { |
7c20daf6 | 575 | UNPROTECT_ERRNO; |
2897b343 | 576 | *errnop = ERANGE; |
7035cd9e MP |
577 | return NSS_STATUS_TRYAGAIN; |
578 | } | |
579 | ||
580 | pwd->pw_name = buffer; | |
581 | pwd->pw_uid = uid; | |
52ad194e | 582 | pwd->pw_gid = GID_NOBODY; |
7035cd9e MP |
583 | pwd->pw_gecos = buffer; |
584 | pwd->pw_passwd = (char*) "*"; /* locked */ | |
585 | pwd->pw_dir = (char*) "/"; | |
586 | pwd->pw_shell = (char*) "/sbin/nologin"; | |
587 | ||
7035cd9e MP |
588 | return NSS_STATUS_SUCCESS; |
589 | ||
7035cd9e | 590 | fail: |
7c20daf6 | 591 | UNPROTECT_ERRNO; |
7035cd9e MP |
592 | *errnop = -r; |
593 | return NSS_STATUS_UNAVAIL; | |
594 | } | |
595 | ||
98393f85 MB |
596 | #pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess" |
597 | ||
7035cd9e MP |
598 | enum nss_status _nss_mymachines_getgrnam_r( |
599 | const char *name, | |
600 | struct group *gr, | |
601 | char *buffer, size_t buflen, | |
602 | int *errnop) { | |
603 | ||
4c89c718 MP |
604 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
605 | _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; | |
606 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; | |
7035cd9e MP |
607 | const char *p, *e, *machine; |
608 | uint32_t mapped; | |
609 | uid_t gid; | |
610 | size_t l; | |
611 | int r; | |
612 | ||
6e866b33 | 613 | PROTECT_ERRNO; |
4c89c718 MP |
614 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); |
615 | ||
7035cd9e MP |
616 | assert(name); |
617 | assert(gr); | |
618 | ||
619 | p = startswith(name, "vg-"); | |
620 | if (!p) | |
6e866b33 | 621 | return NSS_STATUS_NOTFOUND; |
7035cd9e MP |
622 | |
623 | e = strrchr(p, '-'); | |
624 | if (!e || e == p) | |
6e866b33 | 625 | return NSS_STATUS_NOTFOUND; |
7035cd9e | 626 | |
4c89c718 | 627 | if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */ |
6e866b33 | 628 | return NSS_STATUS_NOTFOUND; |
4c89c718 | 629 | |
7035cd9e MP |
630 | r = parse_gid(e + 1, &gid); |
631 | if (r < 0) | |
6e866b33 | 632 | return NSS_STATUS_NOTFOUND; |
7035cd9e MP |
633 | |
634 | machine = strndupa(p, e - p); | |
635 | if (!machine_name_is_valid(machine)) | |
6e866b33 | 636 | return NSS_STATUS_NOTFOUND; |
7035cd9e | 637 | |
f5e65279 | 638 | if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0) |
6e866b33 MB |
639 | return NSS_STATUS_NOTFOUND; |
640 | ||
641 | if (avoid_deadlock()) { | |
642 | r = -EDEADLK; | |
643 | goto fail; | |
644 | } | |
8a584da2 | 645 | |
7035cd9e MP |
646 | r = sd_bus_open_system(&bus); |
647 | if (r < 0) | |
648 | goto fail; | |
649 | ||
650 | r = sd_bus_call_method(bus, | |
651 | "org.freedesktop.machine1", | |
652 | "/org/freedesktop/machine1", | |
653 | "org.freedesktop.machine1.Manager", | |
654 | "MapFromMachineGroup", | |
655 | &error, | |
656 | &reply, | |
657 | "su", | |
658 | machine, (uint32_t) gid); | |
659 | if (r < 0) { | |
660 | if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING)) | |
6e866b33 | 661 | return NSS_STATUS_NOTFOUND; |
7035cd9e MP |
662 | |
663 | goto fail; | |
664 | } | |
665 | ||
666 | r = sd_bus_message_read(reply, "u", &mapped); | |
667 | if (r < 0) | |
668 | goto fail; | |
669 | ||
4c89c718 | 670 | if (mapped < HOST_GID_LIMIT || mapped == gid) |
6e866b33 | 671 | return NSS_STATUS_NOTFOUND; |
4c89c718 | 672 | |
7035cd9e MP |
673 | l = sizeof(char*) + strlen(name) + 1; |
674 | if (buflen < l) { | |
7c20daf6 | 675 | UNPROTECT_ERRNO; |
2897b343 | 676 | *errnop = ERANGE; |
7035cd9e MP |
677 | return NSS_STATUS_TRYAGAIN; |
678 | } | |
679 | ||
680 | memzero(buffer, sizeof(char*)); | |
681 | strcpy(buffer + sizeof(char*), name); | |
682 | ||
683 | gr->gr_name = buffer + sizeof(char*); | |
b012e921 | 684 | gr->gr_gid = mapped; |
7035cd9e MP |
685 | gr->gr_passwd = (char*) "*"; /* locked */ |
686 | gr->gr_mem = (char**) buffer; | |
687 | ||
7035cd9e MP |
688 | return NSS_STATUS_SUCCESS; |
689 | ||
7035cd9e | 690 | fail: |
7c20daf6 | 691 | UNPROTECT_ERRNO; |
7035cd9e MP |
692 | *errnop = -r; |
693 | return NSS_STATUS_UNAVAIL; | |
694 | } | |
695 | ||
696 | enum nss_status _nss_mymachines_getgrgid_r( | |
697 | gid_t gid, | |
698 | struct group *gr, | |
699 | char *buffer, size_t buflen, | |
700 | int *errnop) { | |
701 | ||
4c89c718 MP |
702 | _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; |
703 | _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; | |
704 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; | |
b012e921 | 705 | const char *machine; |
7035cd9e MP |
706 | uint32_t mapped; |
707 | int r; | |
708 | ||
6e866b33 | 709 | PROTECT_ERRNO; |
4c89c718 MP |
710 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); |
711 | ||
2897b343 | 712 | if (!gid_is_valid(gid)) |
6e866b33 | 713 | return NSS_STATUS_NOTFOUND; |
7035cd9e MP |
714 | |
715 | /* We consider all gids < 65536 host gids */ | |
4c89c718 | 716 | if (gid < HOST_GID_LIMIT) |
6e866b33 | 717 | return NSS_STATUS_NOTFOUND; |
7035cd9e | 718 | |
f5e65279 | 719 | if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0) |
6e866b33 MB |
720 | return NSS_STATUS_NOTFOUND; |
721 | ||
722 | if (avoid_deadlock()) { | |
723 | r = -EDEADLK; | |
724 | goto fail; | |
725 | } | |
8a584da2 | 726 | |
7035cd9e MP |
727 | r = sd_bus_open_system(&bus); |
728 | if (r < 0) | |
729 | goto fail; | |
730 | ||
731 | r = sd_bus_call_method(bus, | |
732 | "org.freedesktop.machine1", | |
733 | "/org/freedesktop/machine1", | |
734 | "org.freedesktop.machine1.Manager", | |
735 | "MapToMachineGroup", | |
736 | &error, | |
737 | &reply, | |
738 | "u", | |
739 | (uint32_t) gid); | |
740 | if (r < 0) { | |
741 | if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING)) | |
6e866b33 | 742 | return NSS_STATUS_NOTFOUND; |
7035cd9e MP |
743 | |
744 | goto fail; | |
745 | } | |
746 | ||
b012e921 | 747 | r = sd_bus_message_read(reply, "sou", &machine, NULL, &mapped); |
7035cd9e MP |
748 | if (r < 0) |
749 | goto fail; | |
750 | ||
4c89c718 | 751 | if (mapped == gid) |
6e866b33 | 752 | return NSS_STATUS_NOTFOUND; |
4c89c718 | 753 | |
7035cd9e | 754 | if (buflen < sizeof(char*) + 1) { |
7c20daf6 | 755 | UNPROTECT_ERRNO; |
2897b343 | 756 | *errnop = ERANGE; |
7035cd9e MP |
757 | return NSS_STATUS_TRYAGAIN; |
758 | } | |
759 | ||
760 | memzero(buffer, sizeof(char*)); | |
761 | if (snprintf(buffer + sizeof(char*), buflen - sizeof(char*), "vg-%s-" GID_FMT, machine, (gid_t) mapped) >= (int) buflen) { | |
7c20daf6 | 762 | UNPROTECT_ERRNO; |
2897b343 | 763 | *errnop = ERANGE; |
7035cd9e MP |
764 | return NSS_STATUS_TRYAGAIN; |
765 | } | |
766 | ||
767 | gr->gr_name = buffer + sizeof(char*); | |
768 | gr->gr_gid = gid; | |
769 | gr->gr_passwd = (char*) "*"; /* locked */ | |
770 | gr->gr_mem = (char**) buffer; | |
771 | ||
7035cd9e MP |
772 | return NSS_STATUS_SUCCESS; |
773 | ||
7035cd9e | 774 | fail: |
7c20daf6 | 775 | UNPROTECT_ERRNO; |
7035cd9e MP |
776 | *errnop = -r; |
777 | return NSS_STATUS_UNAVAIL; | |
778 | } |