]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nss-mymachines/nss-mymachines.c
headers: remove unneeded includes from util.h
[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"
ca78ad1d 13#include "format-util.h"
25300b5a 14#include "hostname-util.h"
07630cea
LP
15#include "in-addr-util.h"
16#include "macro.h"
0a970718 17#include "memory-util.h"
07630cea 18#include "nss-util.h"
0c5eb056 19#include "signal-util.h"
07630cea 20#include "string-util.h"
b1d4f8e1 21#include "user-util.h"
cabb0bc6
LP
22
23NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
c01ff965
LP
24NSS_GETPW_PROTOTYPES(mymachines);
25NSS_GETGR_PROTOTYPES(mymachines);
cabb0bc6 26
cf3bdcfe
LP
27#define HOST_UID_LIMIT ((uid_t) UINT32_C(0x10000))
28#define HOST_GID_LIMIT ((gid_t) UINT32_C(0x10000))
29
0dd25fb9 30static int count_addresses(sd_bus_message *m, int af, unsigned *ret) {
cabb0bc6
LP
31 unsigned c = 0;
32 int r;
33
34 assert(m);
35 assert(ret);
36
3a6fb33c 37 while ((r = sd_bus_message_enter_container(m, 'r', "iay")) > 0) {
0dd25fb9 38 int family;
cabb0bc6 39
0dd25fb9 40 r = sd_bus_message_read(m, "i", &family);
cabb0bc6
LP
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
313cefa1 55 c++;
cabb0bc6
LP
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
2f28018c
LP
68static 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
cabb0bc6
LP
82enum 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;
4afd3348
LP
90 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
91 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
634af566 92 _cleanup_free_ int *ifindices = NULL;
cabb0bc6
LP
93 _cleanup_free_ char *class = NULL;
94 size_t l, ms, idx;
95 unsigned i = 0, c = 0;
96 char *r_name;
634af566 97 int n_ifindices, r;
cabb0bc6 98
06202b9e 99 PROTECT_ERRNO;
0c5eb056
LP
100 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
101
cabb0bc6
LP
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
634af566
LP
116 n_ifindices = sd_machine_get_ifindices(name, &ifindices);
117 if (n_ifindices < 0) {
118 r = n_ifindices;
cabb0bc6
LP
119 goto fail;
120 }
121
2f28018c
LP
122 if (avoid_deadlock()) {
123 r = -EDEADLK;
124 goto fail;
125 }
126
cabb0bc6
LP
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
0dd25fb9 142 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
cabb0bc6
LP
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) {
cabb0bc6
LP
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) {
cdccd29f 158 UNPROTECT_ERRNO;
0192cbdb 159 *errnop = ERANGE;
cda458a5 160 *h_errnop = NETDB_INTERNAL;
cabb0bc6
LP
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);
0dd25fb9
LP
171 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
172 int family;
cabb0bc6
LP
173 const void *a;
174 size_t sz;
175
0dd25fb9 176 r = sd_bus_message_read(reply, "i", &family);
cabb0bc6
LP
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
555bd6e9
LP
188 if (!IN_SET(family, AF_INET, AF_INET6)) {
189 r = -EAFNOSUPPORT;
190 goto fail;
191 }
192
9d485985 193 if (sz != FAMILY_ADDRESS_SIZE(family)) {
cabb0bc6
LP
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;
634af566 202 r_tuple->scopeid = n_ifindices == 1 ? ifindices[0] : 0;
cabb0bc6
LP
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
06202b9e
YW
225 /* Explicitly reset both *h_errnop and h_errno to work around
226 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
e70df46b
LP
227 *h_errnop = NETDB_SUCCESS;
228 h_errno = 0;
229
cabb0bc6
LP
230 return NSS_STATUS_SUCCESS;
231
232fail:
cdccd29f 233 UNPROTECT_ERRNO;
0192cbdb 234 *errnop = -r;
cabb0bc6
LP
235 *h_errnop = NO_DATA;
236 return NSS_STATUS_UNAVAIL;
237}
238
239enum 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
4afd3348
LP
248 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
249 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
cabb0bc6
LP
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
06202b9e 256 PROTECT_ERRNO;
0c5eb056
LP
257 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
258
cabb0bc6
LP
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
2f28018c
LP
281 if (avoid_deadlock()) {
282 r = -EDEADLK;
283 goto fail;
284 }
285
cabb0bc6
LP
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
0dd25fb9 301 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
cabb0bc6
LP
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) {
cabb0bc6
LP
310 *h_errnop = HOST_NOT_FOUND;
311 return NSS_STATUS_NOTFOUND;
312 }
313
9d485985 314 alen = FAMILY_ADDRESS_SIZE(af);
cabb0bc6
LP
315 l = strlen(name);
316
66a16e7e 317 ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*);
cabb0bc6
LP
318
319 if (buflen < ms) {
cdccd29f 320 UNPROTECT_ERRNO;
0192cbdb 321 *errnop = ERANGE;
cda458a5 322 *h_errnop = NETDB_INTERNAL;
cabb0bc6
LP
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;
0dd25fb9
LP
338 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
339 int family;
cabb0bc6
LP
340 const void *a;
341 size_t sz;
342
0dd25fb9 343 r = sd_bus_message_read(reply, "i", &family);
cabb0bc6
LP
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
06202b9e
YW
396 /* Explicitly reset both *h_errnop and h_errno to work around
397 * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
e70df46b
LP
398 *h_errnop = NETDB_SUCCESS;
399 h_errno = 0;
400
cabb0bc6
LP
401 return NSS_STATUS_SUCCESS;
402
403fail:
cdccd29f 404 UNPROTECT_ERRNO;
0192cbdb 405 *errnop = -r;
cabb0bc6
LP
406 *h_errnop = NO_DATA;
407 return NSS_STATUS_UNAVAIL;
408}
409
c01ff965
LP
410NSS_GETHOSTBYNAME_FALLBACKS(mymachines);
411
412enum nss_status _nss_mymachines_getpwnam_r(
413 const char *name,
414 struct passwd *pwd,
415 char *buffer, size_t buflen,
416 int *errnop) {
417
4afd3348
LP
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;
c01ff965
LP
421 const char *p, *e, *machine;
422 uint32_t mapped;
423 uid_t uid;
424 size_t l;
425 int r;
426
06202b9e 427 PROTECT_ERRNO;
0c5eb056
LP
428 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
429
c01ff965
LP
430 assert(name);
431 assert(pwd);
432
433 p = startswith(name, "vu-");
434 if (!p)
06202b9e 435 return NSS_STATUS_NOTFOUND;
c01ff965
LP
436
437 e = strrchr(p, '-');
438 if (!e || e == p)
06202b9e 439 return NSS_STATUS_NOTFOUND;
c01ff965 440
cb31827d 441 if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
06202b9e 442 return NSS_STATUS_NOTFOUND;
cb31827d 443
c01ff965
LP
444 r = parse_uid(e + 1, &uid);
445 if (r < 0)
06202b9e 446 return NSS_STATUS_NOTFOUND;
c01ff965
LP
447
448 machine = strndupa(p, e - p);
449 if (!machine_name_is_valid(machine))
06202b9e 450 return NSS_STATUS_NOTFOUND;
c01ff965 451
71e0accc 452 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
6e32c03e
LP
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. */
06202b9e 456 return NSS_STATUS_NOTFOUND;
6e32c03e 457
2f28018c
LP
458 if (avoid_deadlock()) {
459 r = -EDEADLK;
460 goto fail;
461 }
462
c01ff965
LP
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))
06202b9e 478 return NSS_STATUS_NOTFOUND;
c01ff965
LP
479
480 goto fail;
481 }
482
483 r = sd_bus_message_read(reply, "u", &mapped);
484 if (r < 0)
485 goto fail;
486
cf3bdcfe
LP
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)
06202b9e 489 return NSS_STATUS_NOTFOUND;
cf3bdcfe 490
c01ff965
LP
491 l = strlen(name);
492 if (buflen < l+1) {
cdccd29f 493 UNPROTECT_ERRNO;
0192cbdb 494 *errnop = ERANGE;
c01ff965
LP
495 return NSS_STATUS_TRYAGAIN;
496 }
497
498 memcpy(buffer, name, l+1);
499
500 pwd->pw_name = buffer;
501 pwd->pw_uid = mapped;
3a664727 502 pwd->pw_gid = GID_NOBODY;
c01ff965
LP
503 pwd->pw_gecos = buffer;
504 pwd->pw_passwd = (char*) "*"; /* locked */
505 pwd->pw_dir = (char*) "/";
506 pwd->pw_shell = (char*) "/sbin/nologin";
507
c01ff965
LP
508 return NSS_STATUS_SUCCESS;
509
c01ff965 510fail:
cdccd29f 511 UNPROTECT_ERRNO;
0192cbdb 512 *errnop = -r;
c01ff965
LP
513 return NSS_STATUS_UNAVAIL;
514}
515
516enum nss_status _nss_mymachines_getpwuid_r(
517 uid_t uid,
518 struct passwd *pwd,
519 char *buffer, size_t buflen,
520 int *errnop) {
521
4afd3348
LP
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;
31d99bd1 525 const char *machine;
c01ff965
LP
526 uint32_t mapped;
527 int r;
528
06202b9e 529 PROTECT_ERRNO;
0c5eb056
LP
530 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
531
d6c575e3 532 if (!uid_is_valid(uid))
06202b9e 533 return NSS_STATUS_NOTFOUND;
c01ff965
LP
534
535 /* We consider all uids < 65536 host uids */
cf3bdcfe 536 if (uid < HOST_UID_LIMIT)
06202b9e 537 return NSS_STATUS_NOTFOUND;
c01ff965 538
71e0accc 539 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
06202b9e 540 return NSS_STATUS_NOTFOUND;
6e32c03e 541
2f28018c
LP
542 if (avoid_deadlock()) {
543 r = -EDEADLK;
544 goto fail;
545 }
546
c01ff965
LP
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))
06202b9e 562 return NSS_STATUS_NOTFOUND;
c01ff965
LP
563
564 goto fail;
565 }
566
31d99bd1 567 r = sd_bus_message_read(reply, "sou", &machine, NULL, &mapped);
c01ff965
LP
568 if (r < 0)
569 goto fail;
570
cf3bdcfe 571 if (mapped == uid)
06202b9e 572 return NSS_STATUS_NOTFOUND;
cf3bdcfe 573
c01ff965 574 if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) {
cdccd29f 575 UNPROTECT_ERRNO;
0192cbdb 576 *errnop = ERANGE;
c01ff965
LP
577 return NSS_STATUS_TRYAGAIN;
578 }
579
580 pwd->pw_name = buffer;
581 pwd->pw_uid = uid;
3a664727 582 pwd->pw_gid = GID_NOBODY;
c01ff965
LP
583 pwd->pw_gecos = buffer;
584 pwd->pw_passwd = (char*) "*"; /* locked */
585 pwd->pw_dir = (char*) "/";
586 pwd->pw_shell = (char*) "/sbin/nologin";
587
c01ff965
LP
588 return NSS_STATUS_SUCCESS;
589
c01ff965 590fail:
cdccd29f 591 UNPROTECT_ERRNO;
0192cbdb 592 *errnop = -r;
c01ff965
LP
593 return NSS_STATUS_UNAVAIL;
594}
595
3e75a1bb
YW
596#pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess"
597
c01ff965
LP
598enum nss_status _nss_mymachines_getgrnam_r(
599 const char *name,
600 struct group *gr,
601 char *buffer, size_t buflen,
602 int *errnop) {
603
4afd3348
LP
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;
c01ff965
LP
607 const char *p, *e, *machine;
608 uint32_t mapped;
609 uid_t gid;
610 size_t l;
611 int r;
612
06202b9e 613 PROTECT_ERRNO;
0c5eb056
LP
614 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
615
c01ff965
LP
616 assert(name);
617 assert(gr);
618
619 p = startswith(name, "vg-");
620 if (!p)
06202b9e 621 return NSS_STATUS_NOTFOUND;
c01ff965
LP
622
623 e = strrchr(p, '-');
624 if (!e || e == p)
06202b9e 625 return NSS_STATUS_NOTFOUND;
c01ff965 626
cb31827d 627 if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
06202b9e 628 return NSS_STATUS_NOTFOUND;
cb31827d 629
c01ff965
LP
630 r = parse_gid(e + 1, &gid);
631 if (r < 0)
06202b9e 632 return NSS_STATUS_NOTFOUND;
c01ff965
LP
633
634 machine = strndupa(p, e - p);
635 if (!machine_name_is_valid(machine))
06202b9e 636 return NSS_STATUS_NOTFOUND;
c01ff965 637
71e0accc 638 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
06202b9e 639 return NSS_STATUS_NOTFOUND;
6e32c03e 640
2f28018c
LP
641 if (avoid_deadlock()) {
642 r = -EDEADLK;
643 goto fail;
644 }
645
c01ff965
LP
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))
06202b9e 661 return NSS_STATUS_NOTFOUND;
c01ff965
LP
662
663 goto fail;
664 }
665
666 r = sd_bus_message_read(reply, "u", &mapped);
667 if (r < 0)
668 goto fail;
669
cf3bdcfe 670 if (mapped < HOST_GID_LIMIT || mapped == gid)
06202b9e 671 return NSS_STATUS_NOTFOUND;
cf3bdcfe 672
c01ff965
LP
673 l = sizeof(char*) + strlen(name) + 1;
674 if (buflen < l) {
cdccd29f 675 UNPROTECT_ERRNO;
0192cbdb 676 *errnop = ERANGE;
c01ff965
LP
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*);
ee73a176 684 gr->gr_gid = mapped;
c01ff965
LP
685 gr->gr_passwd = (char*) "*"; /* locked */
686 gr->gr_mem = (char**) buffer;
687
c01ff965
LP
688 return NSS_STATUS_SUCCESS;
689
c01ff965 690fail:
cdccd29f 691 UNPROTECT_ERRNO;
0192cbdb 692 *errnop = -r;
c01ff965
LP
693 return NSS_STATUS_UNAVAIL;
694}
695
696enum nss_status _nss_mymachines_getgrgid_r(
697 gid_t gid,
698 struct group *gr,
699 char *buffer, size_t buflen,
700 int *errnop) {
701
4afd3348
LP
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;
31d99bd1 705 const char *machine;
c01ff965
LP
706 uint32_t mapped;
707 int r;
708
06202b9e 709 PROTECT_ERRNO;
0c5eb056
LP
710 BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
711
d6c575e3 712 if (!gid_is_valid(gid))
06202b9e 713 return NSS_STATUS_NOTFOUND;
c01ff965
LP
714
715 /* We consider all gids < 65536 host gids */
cf3bdcfe 716 if (gid < HOST_GID_LIMIT)
06202b9e 717 return NSS_STATUS_NOTFOUND;
c01ff965 718
71e0accc 719 if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
06202b9e 720 return NSS_STATUS_NOTFOUND;
6e32c03e 721
2f28018c
LP
722 if (avoid_deadlock()) {
723 r = -EDEADLK;
724 goto fail;
725 }
726
c01ff965
LP
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))
06202b9e 742 return NSS_STATUS_NOTFOUND;
c01ff965
LP
743
744 goto fail;
745 }
746
31d99bd1 747 r = sd_bus_message_read(reply, "sou", &machine, NULL, &mapped);
c01ff965
LP
748 if (r < 0)
749 goto fail;
750
cf3bdcfe 751 if (mapped == gid)
06202b9e 752 return NSS_STATUS_NOTFOUND;
cf3bdcfe 753
c01ff965 754 if (buflen < sizeof(char*) + 1) {
cdccd29f 755 UNPROTECT_ERRNO;
0192cbdb 756 *errnop = ERANGE;
c01ff965
LP
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) {
cdccd29f 762 UNPROTECT_ERRNO;
0192cbdb 763 *errnop = ERANGE;
c01ff965
LP
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
c01ff965
LP
772 return NSS_STATUS_SUCCESS;
773
c01ff965 774fail:
cdccd29f 775 UNPROTECT_ERRNO;
0192cbdb 776 *errnop = -r;
c01ff965
LP
777 return NSS_STATUS_UNAVAIL;
778}