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