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