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