]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nss-mymachines/nss-mymachines.c
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
[thirdparty/systemd.git] / src / nss-mymachines / nss-mymachines.c
CommitLineData
cabb0bc6
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
cabb0bc6 22#include <netdb.h>
07630cea 23#include <nss.h>
cabb0bc6
LP
24
25#include "sd-bus.h"
26#include "sd-login.h"
07630cea 27
b5efdb8a 28#include "alloc-util.h"
c01ff965 29#include "bus-common-errors.h"
07630cea 30#include "bus-util.h"
25300b5a 31#include "hostname-util.h"
07630cea
LP
32#include "in-addr-util.h"
33#include "macro.h"
34#include "nss-util.h"
35#include "string-util.h"
b1d4f8e1 36#include "user-util.h"
07630cea 37#include "util.h"
cabb0bc6
LP
38
39NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
c01ff965
LP
40NSS_GETPW_PROTOTYPES(mymachines);
41NSS_GETGR_PROTOTYPES(mymachines);
cabb0bc6 42
0dd25fb9 43static int count_addresses(sd_bus_message *m, int af, unsigned *ret) {
cabb0bc6
LP
44 unsigned c = 0;
45 int r;
46
47 assert(m);
48 assert(ret);
49
3a6fb33c 50 while ((r = sd_bus_message_enter_container(m, 'r', "iay")) > 0) {
0dd25fb9 51 int family;
cabb0bc6 52
0dd25fb9 53 r = sd_bus_message_read(m, "i", &family);
cabb0bc6
LP
54 if (r < 0)
55 return r;
56
57 r = sd_bus_message_skip(m, "ay");
58 if (r < 0)
59 return r;
60
61 r = sd_bus_message_exit_container(m);
62 if (r < 0)
63 return r;
64
65 if (af != AF_UNSPEC && family != af)
66 continue;
67
68 c ++;
69 }
70 if (r < 0)
71 return r;
72
73 r = sd_bus_message_rewind(m, false);
74 if (r < 0)
75 return r;
76
77 *ret = c;
78 return 0;
79}
80
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
LP
97
98 assert(name);
99 assert(pat);
100 assert(buffer);
101 assert(errnop);
102 assert(h_errnop);
103
104 r = sd_machine_get_class(name, &class);
105 if (r < 0)
106 goto fail;
107 if (!streq(class, "container")) {
108 r = -ENOTTY;
109 goto fail;
110 }
111
634af566
LP
112 n_ifindices = sd_machine_get_ifindices(name, &ifindices);
113 if (n_ifindices < 0) {
114 r = n_ifindices;
cabb0bc6
LP
115 goto fail;
116 }
117
118 r = sd_bus_open_system(&bus);
119 if (r < 0)
120 goto fail;
121
122 r = sd_bus_call_method(bus,
123 "org.freedesktop.machine1",
124 "/org/freedesktop/machine1",
125 "org.freedesktop.machine1.Manager",
126 "GetMachineAddresses",
127 NULL,
128 &reply,
129 "s", name);
130 if (r < 0)
131 goto fail;
132
0dd25fb9 133 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
cabb0bc6
LP
134 if (r < 0)
135 goto fail;
136
137 r = count_addresses(reply, AF_UNSPEC, &c);
138 if (r < 0)
139 goto fail;
140
141 if (c <= 0) {
555bd6e9 142 *errnop = ESRCH;
cabb0bc6
LP
143 *h_errnop = HOST_NOT_FOUND;
144 return NSS_STATUS_NOTFOUND;
145 }
146
147 l = strlen(name);
148 ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c;
149 if (buflen < ms) {
150 *errnop = ENOMEM;
555bd6e9 151 *h_errnop = TRY_AGAIN;
cabb0bc6
LP
152 return NSS_STATUS_TRYAGAIN;
153 }
154
155 /* First, append name */
156 r_name = buffer;
157 memcpy(r_name, name, l+1);
158 idx = ALIGN(l+1);
159
160 /* Second, append addresses */
161 r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
0dd25fb9
LP
162 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
163 int family;
cabb0bc6
LP
164 const void *a;
165 size_t sz;
166
0dd25fb9 167 r = sd_bus_message_read(reply, "i", &family);
cabb0bc6
LP
168 if (r < 0)
169 goto fail;
170
171 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
172 if (r < 0)
173 goto fail;
174
175 r = sd_bus_message_exit_container(reply);
176 if (r < 0)
177 goto fail;
178
555bd6e9
LP
179 if (!IN_SET(family, AF_INET, AF_INET6)) {
180 r = -EAFNOSUPPORT;
181 goto fail;
182 }
183
9d485985 184 if (sz != FAMILY_ADDRESS_SIZE(family)) {
cabb0bc6
LP
185 r = -EINVAL;
186 goto fail;
187 }
188
189 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
190 r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
191 r_tuple->name = r_name;
192 r_tuple->family = family;
634af566 193 r_tuple->scopeid = n_ifindices == 1 ? ifindices[0] : 0;
cabb0bc6
LP
194 memcpy(r_tuple->addr, a, sz);
195
196 idx += ALIGN(sizeof(struct gaih_addrtuple));
197 i++;
198 }
199
200 assert(i == c);
201
202 r = sd_bus_message_exit_container(reply);
203 if (r < 0)
204 goto fail;
205
206 assert(idx == ms);
207
208 if (*pat)
209 **pat = *r_tuple_first;
210 else
211 *pat = r_tuple_first;
212
213 if (ttlp)
214 *ttlp = 0;
215
e70df46b
LP
216 /* Explicitly reset all error variables */
217 *errnop = 0;
218 *h_errnop = NETDB_SUCCESS;
219 h_errno = 0;
220
cabb0bc6
LP
221 return NSS_STATUS_SUCCESS;
222
223fail:
224 *errnop = -r;
225 *h_errnop = NO_DATA;
226 return NSS_STATUS_UNAVAIL;
227}
228
229enum nss_status _nss_mymachines_gethostbyname3_r(
230 const char *name,
231 int af,
232 struct hostent *result,
233 char *buffer, size_t buflen,
234 int *errnop, int *h_errnop,
235 int32_t *ttlp,
236 char **canonp) {
237
4afd3348
LP
238 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
239 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
cabb0bc6
LP
240 _cleanup_free_ char *class = NULL;
241 unsigned c = 0, i = 0;
242 char *r_name, *r_aliases, *r_addr, *r_addr_list;
243 size_t l, idx, ms, alen;
244 int r;
245
246 assert(name);
247 assert(result);
248 assert(buffer);
249 assert(errnop);
250 assert(h_errnop);
251
252 if (af == AF_UNSPEC)
253 af = AF_INET;
254
255 if (af != AF_INET && af != AF_INET6) {
256 r = -EAFNOSUPPORT;
257 goto fail;
258 }
259
260 r = sd_machine_get_class(name, &class);
261 if (r < 0)
262 goto fail;
263 if (!streq(class, "container")) {
264 r = -ENOTTY;
265 goto fail;
266 }
267
268 r = sd_bus_open_system(&bus);
269 if (r < 0)
270 goto fail;
271
272 r = sd_bus_call_method(bus,
273 "org.freedesktop.machine1",
274 "/org/freedesktop/machine1",
275 "org.freedesktop.machine1.Manager",
276 "GetMachineAddresses",
277 NULL,
278 &reply,
279 "s", name);
280 if (r < 0)
281 goto fail;
282
0dd25fb9 283 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
cabb0bc6
LP
284 if (r < 0)
285 goto fail;
286
287 r = count_addresses(reply, af, &c);
288 if (r < 0)
289 goto fail;
290
291 if (c <= 0) {
292 *errnop = ENOENT;
293 *h_errnop = HOST_NOT_FOUND;
294 return NSS_STATUS_NOTFOUND;
295 }
296
9d485985 297 alen = FAMILY_ADDRESS_SIZE(af);
cabb0bc6
LP
298 l = strlen(name);
299
66a16e7e 300 ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*);
cabb0bc6
LP
301
302 if (buflen < ms) {
303 *errnop = ENOMEM;
304 *h_errnop = NO_RECOVERY;
305 return NSS_STATUS_TRYAGAIN;
306 }
307
308 /* First, append name */
309 r_name = buffer;
310 memcpy(r_name, name, l+1);
311 idx = ALIGN(l+1);
312
313 /* Second, create aliases array */
314 r_aliases = buffer + idx;
315 ((char**) r_aliases)[0] = NULL;
316 idx += sizeof(char*);
317
318 /* Third, append addresses */
319 r_addr = buffer + idx;
0dd25fb9
LP
320 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
321 int family;
cabb0bc6
LP
322 const void *a;
323 size_t sz;
324
0dd25fb9 325 r = sd_bus_message_read(reply, "i", &family);
cabb0bc6
LP
326 if (r < 0)
327 goto fail;
328
329 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
330 if (r < 0)
331 goto fail;
332
333 r = sd_bus_message_exit_container(reply);
334 if (r < 0)
335 goto fail;
336
337 if (family != af)
338 continue;
339
340 if (sz != alen) {
341 r = -EINVAL;
342 goto fail;
343 }
344
345 memcpy(r_addr + i*ALIGN(alen), a, alen);
346 i++;
347 }
348
349 assert(i == c);
350 idx += c * ALIGN(alen);
351
352 r = sd_bus_message_exit_container(reply);
353 if (r < 0)
354 goto fail;
355
356 /* Third, append address pointer array */
357 r_addr_list = buffer + idx;
358 for (i = 0; i < c; i++)
359 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
360
361 ((char**) r_addr_list)[i] = NULL;
362 idx += (c+1) * sizeof(char*);
363
364 assert(idx == ms);
365
366 result->h_name = r_name;
367 result->h_aliases = (char**) r_aliases;
368 result->h_addrtype = af;
369 result->h_length = alen;
370 result->h_addr_list = (char**) r_addr_list;
371
372 if (ttlp)
373 *ttlp = 0;
374
375 if (canonp)
376 *canonp = r_name;
377
e70df46b
LP
378 /* Explicitly reset all error variables */
379 *errnop = 0;
380 *h_errnop = NETDB_SUCCESS;
381 h_errno = 0;
382
cabb0bc6
LP
383 return NSS_STATUS_SUCCESS;
384
385fail:
386 *errnop = -r;
387 *h_errnop = NO_DATA;
388 return NSS_STATUS_UNAVAIL;
389}
390
c01ff965
LP
391NSS_GETHOSTBYNAME_FALLBACKS(mymachines);
392
393enum nss_status _nss_mymachines_getpwnam_r(
394 const char *name,
395 struct passwd *pwd,
396 char *buffer, size_t buflen,
397 int *errnop) {
398
4afd3348
LP
399 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
400 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
401 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
c01ff965
LP
402 const char *p, *e, *machine;
403 uint32_t mapped;
404 uid_t uid;
405 size_t l;
406 int r;
407
408 assert(name);
409 assert(pwd);
410
411 p = startswith(name, "vu-");
412 if (!p)
413 goto not_found;
414
415 e = strrchr(p, '-');
416 if (!e || e == p)
417 goto not_found;
418
cb31827d
ZJS
419 if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
420 goto not_found;
421
c01ff965
LP
422 r = parse_uid(e + 1, &uid);
423 if (r < 0)
424 goto not_found;
425
426 machine = strndupa(p, e - p);
427 if (!machine_name_is_valid(machine))
428 goto not_found;
429
430 r = sd_bus_open_system(&bus);
431 if (r < 0)
432 goto fail;
433
434 r = sd_bus_call_method(bus,
435 "org.freedesktop.machine1",
436 "/org/freedesktop/machine1",
437 "org.freedesktop.machine1.Manager",
438 "MapFromMachineUser",
439 &error,
440 &reply,
441 "su",
442 machine, (uint32_t) uid);
443 if (r < 0) {
444 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
445 goto not_found;
446
447 goto fail;
448 }
449
450 r = sd_bus_message_read(reply, "u", &mapped);
451 if (r < 0)
452 goto fail;
453
454 l = strlen(name);
455 if (buflen < l+1) {
456 *errnop = ENOMEM;
457 return NSS_STATUS_TRYAGAIN;
458 }
459
460 memcpy(buffer, name, l+1);
461
462 pwd->pw_name = buffer;
463 pwd->pw_uid = mapped;
464 pwd->pw_gid = 65534; /* nobody */
465 pwd->pw_gecos = buffer;
466 pwd->pw_passwd = (char*) "*"; /* locked */
467 pwd->pw_dir = (char*) "/";
468 pwd->pw_shell = (char*) "/sbin/nologin";
469
470 *errnop = 0;
471 return NSS_STATUS_SUCCESS;
472
473not_found:
474 *errnop = 0;
475 return NSS_STATUS_NOTFOUND;
476
477fail:
478 *errnop = -r;
479 return NSS_STATUS_UNAVAIL;
480}
481
482enum nss_status _nss_mymachines_getpwuid_r(
483 uid_t uid,
484 struct passwd *pwd,
485 char *buffer, size_t buflen,
486 int *errnop) {
487
4afd3348
LP
488 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
489 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
490 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
c01ff965
LP
491 const char *machine, *object;
492 uint32_t mapped;
493 int r;
494
c077529b 495 if (!uid_is_valid(uid)) {
c01ff965
LP
496 r = -EINVAL;
497 goto fail;
498 }
499
500 /* We consider all uids < 65536 host uids */
501 if (uid < 0x10000)
502 goto not_found;
503
504 r = sd_bus_open_system(&bus);
505 if (r < 0)
506 goto fail;
507
508 r = sd_bus_call_method(bus,
509 "org.freedesktop.machine1",
510 "/org/freedesktop/machine1",
511 "org.freedesktop.machine1.Manager",
512 "MapToMachineUser",
513 &error,
514 &reply,
515 "u",
516 (uint32_t) uid);
517 if (r < 0) {
518 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
519 goto not_found;
520
521 goto fail;
522 }
523
524 r = sd_bus_message_read(reply, "sou", &machine, &object, &mapped);
525 if (r < 0)
526 goto fail;
527
528 if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) {
529 *errnop = ENOMEM;
530 return NSS_STATUS_TRYAGAIN;
531 }
532
533 pwd->pw_name = buffer;
534 pwd->pw_uid = uid;
535 pwd->pw_gid = 65534; /* nobody */
536 pwd->pw_gecos = buffer;
537 pwd->pw_passwd = (char*) "*"; /* locked */
538 pwd->pw_dir = (char*) "/";
539 pwd->pw_shell = (char*) "/sbin/nologin";
540
541 *errnop = 0;
542 return NSS_STATUS_SUCCESS;
543
544not_found:
545 *errnop = 0;
546 return NSS_STATUS_NOTFOUND;
547
548fail:
549 *errnop = -r;
550 return NSS_STATUS_UNAVAIL;
551}
552
553enum nss_status _nss_mymachines_getgrnam_r(
554 const char *name,
555 struct group *gr,
556 char *buffer, size_t buflen,
557 int *errnop) {
558
4afd3348
LP
559 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
560 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
561 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
c01ff965
LP
562 const char *p, *e, *machine;
563 uint32_t mapped;
564 uid_t gid;
565 size_t l;
566 int r;
567
568 assert(name);
569 assert(gr);
570
571 p = startswith(name, "vg-");
572 if (!p)
573 goto not_found;
574
575 e = strrchr(p, '-');
576 if (!e || e == p)
577 goto not_found;
578
cb31827d
ZJS
579 if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
580 goto not_found;
581
c01ff965
LP
582 r = parse_gid(e + 1, &gid);
583 if (r < 0)
584 goto not_found;
585
586 machine = strndupa(p, e - p);
587 if (!machine_name_is_valid(machine))
588 goto not_found;
589
590 r = sd_bus_open_system(&bus);
591 if (r < 0)
592 goto fail;
593
594 r = sd_bus_call_method(bus,
595 "org.freedesktop.machine1",
596 "/org/freedesktop/machine1",
597 "org.freedesktop.machine1.Manager",
598 "MapFromMachineGroup",
599 &error,
600 &reply,
601 "su",
602 machine, (uint32_t) gid);
603 if (r < 0) {
604 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
605 goto not_found;
606
607 goto fail;
608 }
609
610 r = sd_bus_message_read(reply, "u", &mapped);
611 if (r < 0)
612 goto fail;
613
614 l = sizeof(char*) + strlen(name) + 1;
615 if (buflen < l) {
616 *errnop = ENOMEM;
617 return NSS_STATUS_TRYAGAIN;
618 }
619
620 memzero(buffer, sizeof(char*));
621 strcpy(buffer + sizeof(char*), name);
622
623 gr->gr_name = buffer + sizeof(char*);
624 gr->gr_gid = gid;
625 gr->gr_passwd = (char*) "*"; /* locked */
626 gr->gr_mem = (char**) buffer;
627
628 *errnop = 0;
629 return NSS_STATUS_SUCCESS;
630
631not_found:
632 *errnop = 0;
633 return NSS_STATUS_NOTFOUND;
634
635fail:
636 *errnop = -r;
637 return NSS_STATUS_UNAVAIL;
638}
639
640enum nss_status _nss_mymachines_getgrgid_r(
641 gid_t gid,
642 struct group *gr,
643 char *buffer, size_t buflen,
644 int *errnop) {
645
4afd3348
LP
646 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
647 _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
648 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
c01ff965
LP
649 const char *machine, *object;
650 uint32_t mapped;
651 int r;
652
c077529b 653 if (!gid_is_valid(gid)) {
c01ff965
LP
654 r = -EINVAL;
655 goto fail;
656 }
657
658 /* We consider all gids < 65536 host gids */
659 if (gid < 0x10000)
660 goto not_found;
661
662 r = sd_bus_open_system(&bus);
663 if (r < 0)
664 goto fail;
665
666 r = sd_bus_call_method(bus,
667 "org.freedesktop.machine1",
668 "/org/freedesktop/machine1",
669 "org.freedesktop.machine1.Manager",
670 "MapToMachineGroup",
671 &error,
672 &reply,
673 "u",
674 (uint32_t) gid);
675 if (r < 0) {
676 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
677 goto not_found;
678
679 goto fail;
680 }
681
682 r = sd_bus_message_read(reply, "sou", &machine, &object, &mapped);
683 if (r < 0)
684 goto fail;
685
686 if (buflen < sizeof(char*) + 1) {
687 *errnop = ENOMEM;
688 return NSS_STATUS_TRYAGAIN;
689 }
690
691 memzero(buffer, sizeof(char*));
692 if (snprintf(buffer + sizeof(char*), buflen - sizeof(char*), "vg-%s-" GID_FMT, machine, (gid_t) mapped) >= (int) buflen) {
693 *errnop = ENOMEM;
694 return NSS_STATUS_TRYAGAIN;
695 }
696
697 gr->gr_name = buffer + sizeof(char*);
698 gr->gr_gid = gid;
699 gr->gr_passwd = (char*) "*"; /* locked */
700 gr->gr_mem = (char**) buffer;
701
702 *errnop = 0;
703 return NSS_STATUS_SUCCESS;
704
705not_found:
706 *errnop = 0;
707 return NSS_STATUS_NOTFOUND;
708
709fail:
710 *errnop = -r;
711 return NSS_STATUS_UNAVAIL;
712}