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