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