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