]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
cabb0bc6 | 2 | |
cabb0bc6 | 3 | #include <netdb.h> |
07630cea | 4 | #include <nss.h> |
e5d5edc3 | 5 | #include <pthread.h> |
cabb0bc6 LP |
6 | |
7 | #include "sd-bus.h" | |
8 | #include "sd-login.h" | |
07630cea | 9 | |
b5efdb8a | 10 | #include "alloc-util.h" |
c01ff965 | 11 | #include "bus-common-errors.h" |
9b71e4ab | 12 | #include "bus-locator.h" |
6e32c03e | 13 | #include "env-util.h" |
2b2fec7d | 14 | #include "errno-util.h" |
ca78ad1d | 15 | #include "format-util.h" |
25300b5a | 16 | #include "hostname-util.h" |
07630cea | 17 | #include "in-addr-util.h" |
e5d5edc3 | 18 | #include "log.h" |
07630cea | 19 | #include "macro.h" |
0a970718 | 20 | #include "memory-util.h" |
07630cea | 21 | #include "nss-util.h" |
0c5eb056 | 22 | #include "signal-util.h" |
07630cea | 23 | #include "string-util.h" |
cabb0bc6 | 24 | |
e5d5edc3 ZJS |
25 | static void setup_logging_once(void) { |
26 | static pthread_once_t once = PTHREAD_ONCE_INIT; | |
56a5f496 | 27 | assert_se(pthread_once(&once, log_parse_environment) == 0); |
e5d5edc3 ZJS |
28 | } |
29 | ||
30 | #define NSS_ENTRYPOINT_BEGIN \ | |
31 | BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); \ | |
32 | setup_logging_once() | |
33 | ||
cabb0bc6 | 34 | NSS_GETHOSTBYNAME_PROTOTYPES(mymachines); |
c01ff965 LP |
35 | NSS_GETPW_PROTOTYPES(mymachines); |
36 | NSS_GETGR_PROTOTYPES(mymachines); | |
cabb0bc6 | 37 | |
0dd25fb9 | 38 | static int count_addresses(sd_bus_message *m, int af, unsigned *ret) { |
cabb0bc6 LP |
39 | unsigned c = 0; |
40 | int r; | |
41 | ||
42 | assert(m); | |
43 | assert(ret); | |
44 | ||
3a6fb33c | 45 | while ((r = sd_bus_message_enter_container(m, 'r', "iay")) > 0) { |
0dd25fb9 | 46 | int family; |
cabb0bc6 | 47 | |
0dd25fb9 | 48 | r = sd_bus_message_read(m, "i", &family); |
cabb0bc6 LP |
49 | if (r < 0) |
50 | return r; | |
51 | ||
52 | r = sd_bus_message_skip(m, "ay"); | |
53 | if (r < 0) | |
54 | return r; | |
55 | ||
56 | r = sd_bus_message_exit_container(m); | |
57 | if (r < 0) | |
58 | return r; | |
59 | ||
60 | if (af != AF_UNSPEC && family != af) | |
61 | continue; | |
62 | ||
313cefa1 | 63 | c++; |
cabb0bc6 LP |
64 | } |
65 | if (r < 0) | |
66 | return r; | |
67 | ||
68 | r = sd_bus_message_rewind(m, false); | |
69 | if (r < 0) | |
70 | return r; | |
71 | ||
72 | *ret = c; | |
73 | return 0; | |
74 | } | |
75 | ||
2f28018c LP |
76 | static bool avoid_deadlock(void) { |
77 | ||
78 | /* Check whether this lookup might have a chance of deadlocking because we are called from the service manager | |
79 | * code activating systemd-machined.service. After all, we shouldn't synchronously do lookups to | |
80 | * systemd-machined if we are required to finish before it can be started. This of course won't detect all | |
81 | * possible dead locks of this kind, but it should work for the most obvious cases. */ | |
82 | ||
83 | if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */ | |
84 | return false; | |
85 | ||
86 | return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-machined.service") && | |
87 | streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system"); | |
88 | } | |
89 | ||
cabb0bc6 LP |
90 | enum nss_status _nss_mymachines_gethostbyname4_r( |
91 | const char *name, | |
92 | struct gaih_addrtuple **pat, | |
93 | char *buffer, size_t buflen, | |
94 | int *errnop, int *h_errnop, | |
95 | int32_t *ttlp) { | |
96 | ||
97 | struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; | |
4afd3348 LP |
98 | _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; |
99 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; | |
634af566 | 100 | _cleanup_free_ int *ifindices = NULL; |
cabb0bc6 LP |
101 | _cleanup_free_ char *class = NULL; |
102 | size_t l, ms, idx; | |
103 | unsigned i = 0, c = 0; | |
104 | char *r_name; | |
634af566 | 105 | int n_ifindices, r; |
cabb0bc6 | 106 | |
06202b9e | 107 | PROTECT_ERRNO; |
e5d5edc3 | 108 | NSS_ENTRYPOINT_BEGIN; |
0c5eb056 | 109 | |
cabb0bc6 LP |
110 | assert(name); |
111 | assert(pat); | |
112 | assert(buffer); | |
113 | assert(errnop); | |
114 | assert(h_errnop); | |
115 | ||
116 | r = sd_machine_get_class(name, &class); | |
117 | if (r < 0) | |
118 | goto fail; | |
119 | if (!streq(class, "container")) { | |
120 | r = -ENOTTY; | |
121 | goto fail; | |
122 | } | |
123 | ||
634af566 LP |
124 | n_ifindices = sd_machine_get_ifindices(name, &ifindices); |
125 | if (n_ifindices < 0) { | |
126 | r = n_ifindices; | |
cabb0bc6 LP |
127 | goto fail; |
128 | } | |
129 | ||
2f28018c LP |
130 | if (avoid_deadlock()) { |
131 | r = -EDEADLK; | |
132 | goto fail; | |
133 | } | |
134 | ||
cabb0bc6 LP |
135 | r = sd_bus_open_system(&bus); |
136 | if (r < 0) | |
137 | goto fail; | |
138 | ||
7b389878 | 139 | r = bus_call_method(bus, bus_machine_mgr, "GetMachineAddresses", NULL, &reply, "s", name); |
cabb0bc6 LP |
140 | if (r < 0) |
141 | goto fail; | |
142 | ||
0dd25fb9 | 143 | r = sd_bus_message_enter_container(reply, 'a', "(iay)"); |
cabb0bc6 LP |
144 | if (r < 0) |
145 | goto fail; | |
146 | ||
147 | r = count_addresses(reply, AF_UNSPEC, &c); | |
148 | if (r < 0) | |
149 | goto fail; | |
150 | ||
151 | if (c <= 0) { | |
cabb0bc6 LP |
152 | *h_errnop = HOST_NOT_FOUND; |
153 | return NSS_STATUS_NOTFOUND; | |
154 | } | |
155 | ||
156 | l = strlen(name); | |
157 | ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c; | |
158 | if (buflen < ms) { | |
cdccd29f | 159 | UNPROTECT_ERRNO; |
0192cbdb | 160 | *errnop = ERANGE; |
cda458a5 | 161 | *h_errnop = NETDB_INTERNAL; |
cabb0bc6 LP |
162 | return NSS_STATUS_TRYAGAIN; |
163 | } | |
164 | ||
165 | /* First, append name */ | |
166 | r_name = buffer; | |
167 | memcpy(r_name, name, l+1); | |
168 | idx = ALIGN(l+1); | |
169 | ||
170 | /* Second, append addresses */ | |
171 | r_tuple_first = (struct gaih_addrtuple*) (buffer + idx); | |
0dd25fb9 LP |
172 | while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) { |
173 | int family; | |
cabb0bc6 LP |
174 | const void *a; |
175 | size_t sz; | |
176 | ||
0dd25fb9 | 177 | r = sd_bus_message_read(reply, "i", &family); |
cabb0bc6 LP |
178 | if (r < 0) |
179 | goto fail; | |
180 | ||
181 | r = sd_bus_message_read_array(reply, 'y', &a, &sz); | |
182 | if (r < 0) | |
183 | goto fail; | |
184 | ||
185 | r = sd_bus_message_exit_container(reply); | |
186 | if (r < 0) | |
187 | goto fail; | |
188 | ||
555bd6e9 LP |
189 | if (!IN_SET(family, AF_INET, AF_INET6)) { |
190 | r = -EAFNOSUPPORT; | |
191 | goto fail; | |
192 | } | |
193 | ||
9d485985 | 194 | if (sz != FAMILY_ADDRESS_SIZE(family)) { |
cabb0bc6 LP |
195 | r = -EINVAL; |
196 | goto fail; | |
197 | } | |
198 | ||
199 | r_tuple = (struct gaih_addrtuple*) (buffer + idx); | |
200 | r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple))); | |
201 | r_tuple->name = r_name; | |
202 | r_tuple->family = family; | |
634af566 | 203 | r_tuple->scopeid = n_ifindices == 1 ? ifindices[0] : 0; |
cabb0bc6 LP |
204 | memcpy(r_tuple->addr, a, sz); |
205 | ||
206 | idx += ALIGN(sizeof(struct gaih_addrtuple)); | |
207 | i++; | |
208 | } | |
209 | ||
210 | assert(i == c); | |
211 | ||
212 | r = sd_bus_message_exit_container(reply); | |
213 | if (r < 0) | |
214 | goto fail; | |
215 | ||
216 | assert(idx == ms); | |
217 | ||
218 | if (*pat) | |
219 | **pat = *r_tuple_first; | |
220 | else | |
221 | *pat = r_tuple_first; | |
222 | ||
223 | if (ttlp) | |
224 | *ttlp = 0; | |
225 | ||
06202b9e YW |
226 | /* Explicitly reset both *h_errnop and h_errno to work around |
227 | * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */ | |
e70df46b LP |
228 | *h_errnop = NETDB_SUCCESS; |
229 | h_errno = 0; | |
230 | ||
cabb0bc6 LP |
231 | return NSS_STATUS_SUCCESS; |
232 | ||
233 | fail: | |
cdccd29f | 234 | UNPROTECT_ERRNO; |
0192cbdb | 235 | *errnop = -r; |
2b0c1bfd | 236 | *h_errnop = NO_RECOVERY; |
cabb0bc6 LP |
237 | return NSS_STATUS_UNAVAIL; |
238 | } | |
239 | ||
240 | enum nss_status _nss_mymachines_gethostbyname3_r( | |
241 | const char *name, | |
242 | int af, | |
243 | struct hostent *result, | |
244 | char *buffer, size_t buflen, | |
245 | int *errnop, int *h_errnop, | |
246 | int32_t *ttlp, | |
247 | char **canonp) { | |
248 | ||
4afd3348 LP |
249 | _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; |
250 | _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; | |
cabb0bc6 LP |
251 | _cleanup_free_ char *class = NULL; |
252 | unsigned c = 0, i = 0; | |
253 | char *r_name, *r_aliases, *r_addr, *r_addr_list; | |
254 | size_t l, idx, ms, alen; | |
255 | int r; | |
256 | ||
06202b9e | 257 | PROTECT_ERRNO; |
e5d5edc3 | 258 | NSS_ENTRYPOINT_BEGIN; |
0c5eb056 | 259 | |
cabb0bc6 LP |
260 | assert(name); |
261 | assert(result); | |
262 | assert(buffer); | |
263 | assert(errnop); | |
264 | assert(h_errnop); | |
265 | ||
266 | if (af == AF_UNSPEC) | |
267 | af = AF_INET; | |
268 | ||
269 | if (af != AF_INET && af != AF_INET6) { | |
270 | r = -EAFNOSUPPORT; | |
271 | goto fail; | |
272 | } | |
273 | ||
274 | r = sd_machine_get_class(name, &class); | |
275 | if (r < 0) | |
276 | goto fail; | |
277 | if (!streq(class, "container")) { | |
278 | r = -ENOTTY; | |
279 | goto fail; | |
280 | } | |
281 | ||
2f28018c LP |
282 | if (avoid_deadlock()) { |
283 | r = -EDEADLK; | |
284 | goto fail; | |
285 | } | |
286 | ||
cabb0bc6 LP |
287 | r = sd_bus_open_system(&bus); |
288 | if (r < 0) | |
289 | goto fail; | |
290 | ||
7b389878 | 291 | r = bus_call_method(bus, bus_machine_mgr, "GetMachineAddresses", NULL, &reply, "s", name); |
cabb0bc6 LP |
292 | if (r < 0) |
293 | goto fail; | |
294 | ||
0dd25fb9 | 295 | r = sd_bus_message_enter_container(reply, 'a', "(iay)"); |
cabb0bc6 LP |
296 | if (r < 0) |
297 | goto fail; | |
298 | ||
299 | r = count_addresses(reply, af, &c); | |
300 | if (r < 0) | |
301 | goto fail; | |
302 | ||
303 | if (c <= 0) { | |
cabb0bc6 LP |
304 | *h_errnop = HOST_NOT_FOUND; |
305 | return NSS_STATUS_NOTFOUND; | |
306 | } | |
307 | ||
9d485985 | 308 | alen = FAMILY_ADDRESS_SIZE(af); |
cabb0bc6 LP |
309 | l = strlen(name); |
310 | ||
66a16e7e | 311 | ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*); |
cabb0bc6 LP |
312 | |
313 | if (buflen < ms) { | |
cdccd29f | 314 | UNPROTECT_ERRNO; |
0192cbdb | 315 | *errnop = ERANGE; |
cda458a5 | 316 | *h_errnop = NETDB_INTERNAL; |
cabb0bc6 LP |
317 | return NSS_STATUS_TRYAGAIN; |
318 | } | |
319 | ||
320 | /* First, append name */ | |
321 | r_name = buffer; | |
322 | memcpy(r_name, name, l+1); | |
323 | idx = ALIGN(l+1); | |
324 | ||
325 | /* Second, create aliases array */ | |
326 | r_aliases = buffer + idx; | |
327 | ((char**) r_aliases)[0] = NULL; | |
328 | idx += sizeof(char*); | |
329 | ||
330 | /* Third, append addresses */ | |
331 | r_addr = buffer + idx; | |
0dd25fb9 LP |
332 | while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) { |
333 | int family; | |
cabb0bc6 LP |
334 | const void *a; |
335 | size_t sz; | |
336 | ||
0dd25fb9 | 337 | r = sd_bus_message_read(reply, "i", &family); |
cabb0bc6 LP |
338 | if (r < 0) |
339 | goto fail; | |
340 | ||
341 | r = sd_bus_message_read_array(reply, 'y', &a, &sz); | |
342 | if (r < 0) | |
343 | goto fail; | |
344 | ||
345 | r = sd_bus_message_exit_container(reply); | |
346 | if (r < 0) | |
347 | goto fail; | |
348 | ||
349 | if (family != af) | |
350 | continue; | |
351 | ||
352 | if (sz != alen) { | |
353 | r = -EINVAL; | |
354 | goto fail; | |
355 | } | |
356 | ||
357 | memcpy(r_addr + i*ALIGN(alen), a, alen); | |
358 | i++; | |
359 | } | |
360 | ||
361 | assert(i == c); | |
362 | idx += c * ALIGN(alen); | |
363 | ||
364 | r = sd_bus_message_exit_container(reply); | |
365 | if (r < 0) | |
366 | goto fail; | |
367 | ||
368 | /* Third, append address pointer array */ | |
369 | r_addr_list = buffer + idx; | |
370 | for (i = 0; i < c; i++) | |
371 | ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen); | |
372 | ||
373 | ((char**) r_addr_list)[i] = NULL; | |
374 | idx += (c+1) * sizeof(char*); | |
375 | ||
376 | assert(idx == ms); | |
377 | ||
378 | result->h_name = r_name; | |
379 | result->h_aliases = (char**) r_aliases; | |
380 | result->h_addrtype = af; | |
381 | result->h_length = alen; | |
382 | result->h_addr_list = (char**) r_addr_list; | |
383 | ||
384 | if (ttlp) | |
385 | *ttlp = 0; | |
386 | ||
387 | if (canonp) | |
388 | *canonp = r_name; | |
389 | ||
06202b9e YW |
390 | /* Explicitly reset both *h_errnop and h_errno to work around |
391 | * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */ | |
e70df46b LP |
392 | *h_errnop = NETDB_SUCCESS; |
393 | h_errno = 0; | |
394 | ||
cabb0bc6 LP |
395 | return NSS_STATUS_SUCCESS; |
396 | ||
397 | fail: | |
cdccd29f | 398 | UNPROTECT_ERRNO; |
0192cbdb | 399 | *errnop = -r; |
2b0c1bfd | 400 | *h_errnop = NO_RECOVERY; |
cabb0bc6 LP |
401 | return NSS_STATUS_UNAVAIL; |
402 | } | |
403 | ||
c01ff965 LP |
404 | NSS_GETHOSTBYNAME_FALLBACKS(mymachines); |
405 | ||
406 | enum nss_status _nss_mymachines_getpwnam_r( | |
407 | const char *name, | |
408 | struct passwd *pwd, | |
409 | char *buffer, size_t buflen, | |
410 | int *errnop) { | |
411 | ||
38ccb557 | 412 | return NSS_STATUS_NOTFOUND; |
c01ff965 LP |
413 | } |
414 | ||
415 | enum nss_status _nss_mymachines_getpwuid_r( | |
416 | uid_t uid, | |
417 | struct passwd *pwd, | |
418 | char *buffer, size_t buflen, | |
419 | int *errnop) { | |
420 | ||
38ccb557 | 421 | return NSS_STATUS_NOTFOUND; |
c01ff965 LP |
422 | } |
423 | ||
424 | enum nss_status _nss_mymachines_getgrnam_r( | |
425 | const char *name, | |
426 | struct group *gr, | |
427 | char *buffer, size_t buflen, | |
428 | int *errnop) { | |
429 | ||
38ccb557 | 430 | return NSS_STATUS_NOTFOUND; |
c01ff965 LP |
431 | } |
432 | ||
433 | enum nss_status _nss_mymachines_getgrgid_r( | |
434 | gid_t gid, | |
435 | struct group *gr, | |
436 | char *buffer, size_t buflen, | |
437 | int *errnop) { | |
438 | ||
38ccb557 | 439 | return NSS_STATUS_NOTFOUND; |
c01ff965 | 440 | } |