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