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