]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nss-mymachines/nss-mymachines.c
Revert "nss: prevent PROTECT_ERRNO from squashing changes to *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) {
0192cbdb 156 *errnop = ERANGE;
cda458a5 157 *h_errnop = NETDB_INTERNAL;
cabb0bc6
LP
158 return NSS_STATUS_TRYAGAIN;
159 }
160
161 /* First, append name */
162 r_name = buffer;
163 memcpy(r_name, name, l+1);
164 idx = ALIGN(l+1);
165
166 /* Second, append addresses */
167 r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
0dd25fb9
LP
168 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
169 int family;
cabb0bc6
LP
170 const void *a;
171 size_t sz;
172
0dd25fb9 173 r = sd_bus_message_read(reply, "i", &family);
cabb0bc6
LP
174 if (r < 0)
175 goto fail;
176
177 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
178 if (r < 0)
179 goto fail;
180
181 r = sd_bus_message_exit_container(reply);
182 if (r < 0)
183 goto fail;
184
555bd6e9
LP
185 if (!IN_SET(family, AF_INET, AF_INET6)) {
186 r = -EAFNOSUPPORT;
187 goto fail;
188 }
189
9d485985 190 if (sz != FAMILY_ADDRESS_SIZE(family)) {
cabb0bc6
LP
191 r = -EINVAL;
192 goto fail;
193 }
194
195 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
196 r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
197 r_tuple->name = r_name;
198 r_tuple->family = family;
634af566 199 r_tuple->scopeid = n_ifindices == 1 ? ifindices[0] : 0;
cabb0bc6
LP
200 memcpy(r_tuple->addr, a, sz);
201
202 idx += ALIGN(sizeof(struct gaih_addrtuple));
203 i++;
204 }
205
206 assert(i == c);
207
208 r = sd_bus_message_exit_container(reply);
209 if (r < 0)
210 goto fail;
211
212 assert(idx == ms);
213
214 if (*pat)
215 **pat = *r_tuple_first;
216 else
217 *pat = r_tuple_first;
218
219 if (ttlp)
220 *ttlp = 0;
221
06202b9e
YW
222 /* Explicitly reset both *h_errnop and h_errno to work around
223 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
e70df46b
LP
224 *h_errnop = NETDB_SUCCESS;
225 h_errno = 0;
226
cabb0bc6
LP
227 return NSS_STATUS_SUCCESS;
228
229fail:
0192cbdb 230 *errnop = -r;
cabb0bc6
LP
231 *h_errnop = NO_DATA;
232 return NSS_STATUS_UNAVAIL;
233}
234
235enum nss_status _nss_mymachines_gethostbyname3_r(
236 const char *name,
237 int af,
238 struct hostent *result,
239 char *buffer, size_t buflen,
240 int *errnop, int *h_errnop,
241 int32_t *ttlp,
242 char **canonp) {
243
4afd3348
LP
244 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
245 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
cabb0bc6
LP
246 _cleanup_free_ char *class = NULL;
247 unsigned c = 0, i = 0;
248 char *r_name, *r_aliases, *r_addr, *r_addr_list;
249 size_t l, idx, ms, alen;
250 int r;
251
06202b9e 252 PROTECT_ERRNO;
0c5eb056
LP
253 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
254
cabb0bc6
LP
255 assert(name);
256 assert(result);
257 assert(buffer);
258 assert(errnop);
259 assert(h_errnop);
260
261 if (af == AF_UNSPEC)
262 af = AF_INET;
263
264 if (af != AF_INET && af != AF_INET6) {
265 r = -EAFNOSUPPORT;
266 goto fail;
267 }
268
269 r = sd_machine_get_class(name, &class);
270 if (r < 0)
271 goto fail;
272 if (!streq(class, "container")) {
273 r = -ENOTTY;
274 goto fail;
275 }
276
2f28018c
LP
277 if (avoid_deadlock()) {
278 r = -EDEADLK;
279 goto fail;
280 }
281
cabb0bc6
LP
282 r = sd_bus_open_system(&bus);
283 if (r < 0)
284 goto fail;
285
286 r = sd_bus_call_method(bus,
287 "org.freedesktop.machine1",
288 "/org/freedesktop/machine1",
289 "org.freedesktop.machine1.Manager",
290 "GetMachineAddresses",
291 NULL,
292 &reply,
293 "s", name);
294 if (r < 0)
295 goto fail;
296
0dd25fb9 297 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
cabb0bc6
LP
298 if (r < 0)
299 goto fail;
300
301 r = count_addresses(reply, af, &c);
302 if (r < 0)
303 goto fail;
304
305 if (c <= 0) {
cabb0bc6
LP
306 *h_errnop = HOST_NOT_FOUND;
307 return NSS_STATUS_NOTFOUND;
308 }
309
9d485985 310 alen = FAMILY_ADDRESS_SIZE(af);
cabb0bc6
LP
311 l = strlen(name);
312
66a16e7e 313 ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*);
cabb0bc6
LP
314
315 if (buflen < ms) {
0192cbdb 316 *errnop = ERANGE;
cda458a5 317 *h_errnop = NETDB_INTERNAL;
cabb0bc6
LP
318 return NSS_STATUS_TRYAGAIN;
319 }
320
321 /* First, append name */
322 r_name = buffer;
323 memcpy(r_name, name, l+1);
324 idx = ALIGN(l+1);
325
326 /* Second, create aliases array */
327 r_aliases = buffer + idx;
328 ((char**) r_aliases)[0] = NULL;
329 idx += sizeof(char*);
330
331 /* Third, append addresses */
332 r_addr = buffer + idx;
0dd25fb9
LP
333 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
334 int family;
cabb0bc6
LP
335 const void *a;
336 size_t sz;
337
0dd25fb9 338 r = sd_bus_message_read(reply, "i", &family);
cabb0bc6
LP
339 if (r < 0)
340 goto fail;
341
342 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
343 if (r < 0)
344 goto fail;
345
346 r = sd_bus_message_exit_container(reply);
347 if (r < 0)
348 goto fail;
349
350 if (family != af)
351 continue;
352
353 if (sz != alen) {
354 r = -EINVAL;
355 goto fail;
356 }
357
358 memcpy(r_addr + i*ALIGN(alen), a, alen);
359 i++;
360 }
361
362 assert(i == c);
363 idx += c * ALIGN(alen);
364
365 r = sd_bus_message_exit_container(reply);
366 if (r < 0)
367 goto fail;
368
369 /* Third, append address pointer array */
370 r_addr_list = buffer + idx;
371 for (i = 0; i < c; i++)
372 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
373
374 ((char**) r_addr_list)[i] = NULL;
375 idx += (c+1) * sizeof(char*);
376
377 assert(idx == ms);
378
379 result->h_name = r_name;
380 result->h_aliases = (char**) r_aliases;
381 result->h_addrtype = af;
382 result->h_length = alen;
383 result->h_addr_list = (char**) r_addr_list;
384
385 if (ttlp)
386 *ttlp = 0;
387
388 if (canonp)
389 *canonp = r_name;
390
06202b9e
YW
391 /* Explicitly reset both *h_errnop and h_errno to work around
392 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
e70df46b
LP
393 *h_errnop = NETDB_SUCCESS;
394 h_errno = 0;
395
cabb0bc6
LP
396 return NSS_STATUS_SUCCESS;
397
398fail:
0192cbdb 399 *errnop = -r;
cabb0bc6
LP
400 *h_errnop = NO_DATA;
401 return NSS_STATUS_UNAVAIL;
402}
403
c01ff965
LP
404NSS_GETHOSTBYNAME_FALLBACKS(mymachines);
405
406enum nss_status _nss_mymachines_getpwnam_r(
407 const char *name,
408 struct passwd *pwd,
409 char *buffer, size_t buflen,
410 int *errnop) {
411
4afd3348
LP
412 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
413 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
414 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
c01ff965
LP
415 const char *p, *e, *machine;
416 uint32_t mapped;
417 uid_t uid;
418 size_t l;
419 int r;
420
06202b9e 421 PROTECT_ERRNO;
0c5eb056
LP
422 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
423
c01ff965
LP
424 assert(name);
425 assert(pwd);
426
427 p = startswith(name, "vu-");
428 if (!p)
06202b9e 429 return NSS_STATUS_NOTFOUND;
c01ff965
LP
430
431 e = strrchr(p, '-');
432 if (!e || e == p)
06202b9e 433 return NSS_STATUS_NOTFOUND;
c01ff965 434
cb31827d 435 if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
06202b9e 436 return NSS_STATUS_NOTFOUND;
cb31827d 437
c01ff965
LP
438 r = parse_uid(e + 1, &uid);
439 if (r < 0)
06202b9e 440 return NSS_STATUS_NOTFOUND;
c01ff965
LP
441
442 machine = strndupa(p, e - p);
443 if (!machine_name_is_valid(machine))
06202b9e 444 return NSS_STATUS_NOTFOUND;
c01ff965 445
71e0accc 446 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
6e32c03e
LP
447 /* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve
448 * these UIDs, but that should be unproblematic as containers should never be able to connect to a bus
449 * running on the host. */
06202b9e 450 return NSS_STATUS_NOTFOUND;
6e32c03e 451
2f28018c
LP
452 if (avoid_deadlock()) {
453 r = -EDEADLK;
454 goto fail;
455 }
456
c01ff965
LP
457 r = sd_bus_open_system(&bus);
458 if (r < 0)
459 goto fail;
460
461 r = sd_bus_call_method(bus,
462 "org.freedesktop.machine1",
463 "/org/freedesktop/machine1",
464 "org.freedesktop.machine1.Manager",
465 "MapFromMachineUser",
466 &error,
467 &reply,
468 "su",
469 machine, (uint32_t) uid);
470 if (r < 0) {
471 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
06202b9e 472 return NSS_STATUS_NOTFOUND;
c01ff965
LP
473
474 goto fail;
475 }
476
477 r = sd_bus_message_read(reply, "u", &mapped);
478 if (r < 0)
479 goto fail;
480
cf3bdcfe
LP
481 /* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */
482 if (mapped < HOST_UID_LIMIT || mapped == uid)
06202b9e 483 return NSS_STATUS_NOTFOUND;
cf3bdcfe 484
c01ff965
LP
485 l = strlen(name);
486 if (buflen < l+1) {
0192cbdb 487 *errnop = ERANGE;
c01ff965
LP
488 return NSS_STATUS_TRYAGAIN;
489 }
490
491 memcpy(buffer, name, l+1);
492
493 pwd->pw_name = buffer;
494 pwd->pw_uid = mapped;
3a664727 495 pwd->pw_gid = GID_NOBODY;
c01ff965
LP
496 pwd->pw_gecos = buffer;
497 pwd->pw_passwd = (char*) "*"; /* locked */
498 pwd->pw_dir = (char*) "/";
499 pwd->pw_shell = (char*) "/sbin/nologin";
500
c01ff965
LP
501 return NSS_STATUS_SUCCESS;
502
c01ff965 503fail:
0192cbdb 504 *errnop = -r;
c01ff965
LP
505 return NSS_STATUS_UNAVAIL;
506}
507
508enum nss_status _nss_mymachines_getpwuid_r(
509 uid_t uid,
510 struct passwd *pwd,
511 char *buffer, size_t buflen,
512 int *errnop) {
513
4afd3348
LP
514 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
515 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
516 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
31d99bd1 517 const char *machine;
c01ff965
LP
518 uint32_t mapped;
519 int r;
520
06202b9e 521 PROTECT_ERRNO;
0c5eb056
LP
522 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
523
d6c575e3 524 if (!uid_is_valid(uid))
06202b9e 525 return NSS_STATUS_NOTFOUND;
c01ff965
LP
526
527 /* We consider all uids < 65536 host uids */
cf3bdcfe 528 if (uid < HOST_UID_LIMIT)
06202b9e 529 return NSS_STATUS_NOTFOUND;
c01ff965 530
71e0accc 531 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
06202b9e 532 return NSS_STATUS_NOTFOUND;
6e32c03e 533
2f28018c
LP
534 if (avoid_deadlock()) {
535 r = -EDEADLK;
536 goto fail;
537 }
538
c01ff965
LP
539 r = sd_bus_open_system(&bus);
540 if (r < 0)
541 goto fail;
542
543 r = sd_bus_call_method(bus,
544 "org.freedesktop.machine1",
545 "/org/freedesktop/machine1",
546 "org.freedesktop.machine1.Manager",
547 "MapToMachineUser",
548 &error,
549 &reply,
550 "u",
551 (uint32_t) uid);
552 if (r < 0) {
553 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
06202b9e 554 return NSS_STATUS_NOTFOUND;
c01ff965
LP
555
556 goto fail;
557 }
558
31d99bd1 559 r = sd_bus_message_read(reply, "sou", &machine, NULL, &mapped);
c01ff965
LP
560 if (r < 0)
561 goto fail;
562
cf3bdcfe 563 if (mapped == uid)
06202b9e 564 return NSS_STATUS_NOTFOUND;
cf3bdcfe 565
c01ff965 566 if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) {
0192cbdb 567 *errnop = ERANGE;
c01ff965
LP
568 return NSS_STATUS_TRYAGAIN;
569 }
570
571 pwd->pw_name = buffer;
572 pwd->pw_uid = uid;
3a664727 573 pwd->pw_gid = GID_NOBODY;
c01ff965
LP
574 pwd->pw_gecos = buffer;
575 pwd->pw_passwd = (char*) "*"; /* locked */
576 pwd->pw_dir = (char*) "/";
577 pwd->pw_shell = (char*) "/sbin/nologin";
578
c01ff965
LP
579 return NSS_STATUS_SUCCESS;
580
c01ff965 581fail:
0192cbdb 582 *errnop = -r;
c01ff965
LP
583 return NSS_STATUS_UNAVAIL;
584}
585
3e75a1bb
YW
586#pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess"
587
c01ff965
LP
588enum nss_status _nss_mymachines_getgrnam_r(
589 const char *name,
590 struct group *gr,
591 char *buffer, size_t buflen,
592 int *errnop) {
593
4afd3348
LP
594 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
595 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
596 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
c01ff965
LP
597 const char *p, *e, *machine;
598 uint32_t mapped;
599 uid_t gid;
600 size_t l;
601 int r;
602
06202b9e 603 PROTECT_ERRNO;
0c5eb056
LP
604 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
605
c01ff965
LP
606 assert(name);
607 assert(gr);
608
609 p = startswith(name, "vg-");
610 if (!p)
06202b9e 611 return NSS_STATUS_NOTFOUND;
c01ff965
LP
612
613 e = strrchr(p, '-');
614 if (!e || e == p)
06202b9e 615 return NSS_STATUS_NOTFOUND;
c01ff965 616
cb31827d 617 if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
06202b9e 618 return NSS_STATUS_NOTFOUND;
cb31827d 619
c01ff965
LP
620 r = parse_gid(e + 1, &gid);
621 if (r < 0)
06202b9e 622 return NSS_STATUS_NOTFOUND;
c01ff965
LP
623
624 machine = strndupa(p, e - p);
625 if (!machine_name_is_valid(machine))
06202b9e 626 return NSS_STATUS_NOTFOUND;
c01ff965 627
71e0accc 628 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
06202b9e 629 return NSS_STATUS_NOTFOUND;
6e32c03e 630
2f28018c
LP
631 if (avoid_deadlock()) {
632 r = -EDEADLK;
633 goto fail;
634 }
635
c01ff965
LP
636 r = sd_bus_open_system(&bus);
637 if (r < 0)
638 goto fail;
639
640 r = sd_bus_call_method(bus,
641 "org.freedesktop.machine1",
642 "/org/freedesktop/machine1",
643 "org.freedesktop.machine1.Manager",
644 "MapFromMachineGroup",
645 &error,
646 &reply,
647 "su",
648 machine, (uint32_t) gid);
649 if (r < 0) {
650 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
06202b9e 651 return NSS_STATUS_NOTFOUND;
c01ff965
LP
652
653 goto fail;
654 }
655
656 r = sd_bus_message_read(reply, "u", &mapped);
657 if (r < 0)
658 goto fail;
659
cf3bdcfe 660 if (mapped < HOST_GID_LIMIT || mapped == gid)
06202b9e 661 return NSS_STATUS_NOTFOUND;
cf3bdcfe 662
c01ff965
LP
663 l = sizeof(char*) + strlen(name) + 1;
664 if (buflen < l) {
0192cbdb 665 *errnop = ERANGE;
c01ff965
LP
666 return NSS_STATUS_TRYAGAIN;
667 }
668
669 memzero(buffer, sizeof(char*));
670 strcpy(buffer + sizeof(char*), name);
671
672 gr->gr_name = buffer + sizeof(char*);
ee73a176 673 gr->gr_gid = mapped;
c01ff965
LP
674 gr->gr_passwd = (char*) "*"; /* locked */
675 gr->gr_mem = (char**) buffer;
676
c01ff965
LP
677 return NSS_STATUS_SUCCESS;
678
c01ff965 679fail:
0192cbdb 680 *errnop = -r;
c01ff965
LP
681 return NSS_STATUS_UNAVAIL;
682}
683
684enum nss_status _nss_mymachines_getgrgid_r(
685 gid_t gid,
686 struct group *gr,
687 char *buffer, size_t buflen,
688 int *errnop) {
689
4afd3348
LP
690 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
691 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
692 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
31d99bd1 693 const char *machine;
c01ff965
LP
694 uint32_t mapped;
695 int r;
696
06202b9e 697 PROTECT_ERRNO;
0c5eb056
LP
698 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
699
d6c575e3 700 if (!gid_is_valid(gid))
06202b9e 701 return NSS_STATUS_NOTFOUND;
c01ff965
LP
702
703 /* We consider all gids < 65536 host gids */
cf3bdcfe 704 if (gid < HOST_GID_LIMIT)
06202b9e 705 return NSS_STATUS_NOTFOUND;
c01ff965 706
71e0accc 707 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
06202b9e 708 return NSS_STATUS_NOTFOUND;
6e32c03e 709
2f28018c
LP
710 if (avoid_deadlock()) {
711 r = -EDEADLK;
712 goto fail;
713 }
714
c01ff965
LP
715 r = sd_bus_open_system(&bus);
716 if (r < 0)
717 goto fail;
718
719 r = sd_bus_call_method(bus,
720 "org.freedesktop.machine1",
721 "/org/freedesktop/machine1",
722 "org.freedesktop.machine1.Manager",
723 "MapToMachineGroup",
724 &error,
725 &reply,
726 "u",
727 (uint32_t) gid);
728 if (r < 0) {
729 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
06202b9e 730 return NSS_STATUS_NOTFOUND;
c01ff965
LP
731
732 goto fail;
733 }
734
31d99bd1 735 r = sd_bus_message_read(reply, "sou", &machine, NULL, &mapped);
c01ff965
LP
736 if (r < 0)
737 goto fail;
738
cf3bdcfe 739 if (mapped == gid)
06202b9e 740 return NSS_STATUS_NOTFOUND;
cf3bdcfe 741
c01ff965 742 if (buflen < sizeof(char*) + 1) {
0192cbdb 743 *errnop = ERANGE;
c01ff965
LP
744 return NSS_STATUS_TRYAGAIN;
745 }
746
747 memzero(buffer, sizeof(char*));
748 if (snprintf(buffer + sizeof(char*), buflen - sizeof(char*), "vg-%s-" GID_FMT, machine, (gid_t) mapped) >= (int) buflen) {
0192cbdb 749 *errnop = ERANGE;
c01ff965
LP
750 return NSS_STATUS_TRYAGAIN;
751 }
752
753 gr->gr_name = buffer + sizeof(char*);
754 gr->gr_gid = gid;
755 gr->gr_passwd = (char*) "*"; /* locked */
756 gr->gr_mem = (char**) buffer;
757
c01ff965
LP
758 return NSS_STATUS_SUCCESS;
759
c01ff965 760fail:
0192cbdb 761 *errnop = -r;
c01ff965
LP
762 return NSS_STATUS_UNAVAIL;
763}