]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-nss.c
Merge pull request #12487 from mschiu77/acer-series-hwdb
[thirdparty/systemd.git] / src / test / test-nss.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
2abb5b3b
ZJS
2
3#include <dlfcn.h>
2abb5b3b 4#include <net/if.h>
eb43e8a7 5#include <stdlib.h>
ca78ad1d 6#include <unistd.h>
2abb5b3b 7
eb43e8a7
YW
8#include "af-list.h"
9#include "alloc-util.h"
10#include "errno-list.h"
11#include "hexdecoct.h"
12#include "hostname-util.h"
13#include "in-addr-util.h"
14#include "local-addresses.h"
2abb5b3b 15#include "log.h"
f68a2622 16#include "main-func.h"
2abb5b3b
ZJS
17#include "nss-util.h"
18#include "path-util.h"
2abb5b3b 19#include "stdio-util.h"
eb43e8a7 20#include "string-util.h"
2abb5b3b 21#include "strv.h"
f68a2622 22#include "tests.h"
2abb5b3b
ZJS
23
24static const char* nss_status_to_string(enum nss_status status, char *buf, size_t buf_len) {
25 switch (status) {
26 case NSS_STATUS_TRYAGAIN:
27 return "NSS_STATUS_TRYAGAIN";
28 case NSS_STATUS_UNAVAIL:
29 return "NSS_STATUS_UNAVAIL";
30 case NSS_STATUS_NOTFOUND:
31 return "NSS_STATUS_NOTFOUND";
32 case NSS_STATUS_SUCCESS:
33 return "NSS_STATUS_SUCCESS";
34 case NSS_STATUS_RETURN:
35 return "NSS_STATUS_RETURN";
36 default:
37 snprintf(buf, buf_len, "%i", status);
38 return buf;
39 }
40};
41
42static const char* af_to_string(int family, char *buf, size_t buf_len) {
43 const char *name;
44
45 if (family == AF_UNSPEC)
46 return "*";
47
48 name = af_to_name(family);
49 if (name)
50 return name;
51
52 snprintf(buf, buf_len, "%i", family);
53 return buf;
54}
55
56static void* open_handle(const char* dir, const char* module, int flags) {
8d732e2f 57 const char *path = NULL;
2abb5b3b
ZJS
58 void *handle;
59
8d732e2f 60 if (dir)
3762b672 61 path = strjoina(dir, "/libnss_", module, ".so.2");
8d732e2f 62 if (!path || access(path, F_OK) < 0)
2abb5b3b
ZJS
63 path = strjoina("libnss_", module, ".so.2");
64
65 handle = dlopen(path, flags);
9f7672b3
ZJS
66 if (!handle)
67 log_error("Failed to load module %s: %s", module, dlerror());
2abb5b3b
ZJS
68 return handle;
69}
70
71static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) {
72 const struct gaih_addrtuple *it;
73 int n = 0;
74
75 for (it = tuples; it; it = it->next) {
76 _cleanup_free_ char *a = NULL;
77 union in_addr_union u;
78 int r;
79 char family_name[DECIMAL_STR_MAX(int)];
80 char ifname[IF_NAMESIZE];
81
82 memcpy(&u, it->addr, 16);
83 r = in_addr_to_string(it->family, &u, &a);
4c701096 84 assert_se(IN_SET(r, 0, -EAFNOSUPPORT));
2abb5b3b 85 if (r == -EAFNOSUPPORT)
dcd6361e 86 assert_se(a = hexmem(it->addr, 16));
2abb5b3b
ZJS
87
88 if (it->scopeid == 0)
89 goto numerical_index;
90
4e361acc 91 if (!if_indextoname(it->scopeid, ifname)) {
25f027c5 92 log_warning_errno(errno, "if_indextoname(%d) failed: %m", it->scopeid);
2abb5b3b
ZJS
93 numerical_index:
94 xsprintf(ifname, "%i", it->scopeid);
95 };
96
97 log_info(" \"%s\" %s %s %%%s",
98 it->name,
99 af_to_string(it->family, family_name, sizeof family_name),
100 a,
101 ifname);
102 n ++;
103 }
104 return n;
105}
106
107static void print_struct_hostent(struct hostent *host, const char *canon) {
108 char **s;
109
110 log_info(" \"%s\"", host->h_name);
111 STRV_FOREACH(s, host->h_aliases)
112 log_info(" alias \"%s\"", *s);
113 STRV_FOREACH(s, host->h_addr_list) {
114 union in_addr_union u;
115 _cleanup_free_ char *a = NULL;
116 char family_name[DECIMAL_STR_MAX(int)];
117 int r;
118
119 assert_se((unsigned) host->h_length == FAMILY_ADDRESS_SIZE(host->h_addrtype));
120 memcpy(&u, *s, host->h_length);
121 r = in_addr_to_string(host->h_addrtype, &u, &a);
122 assert_se(r == 0);
123 log_info(" %s %s",
124 af_to_string(host->h_addrtype, family_name, sizeof family_name),
125 a);
126 }
127 if (canon)
128 log_info(" canonical: \"%s\"", canon);
129}
130
131static void test_gethostbyname4_r(void *handle, const char *module, const char *name) {
132 const char *fname;
133 _nss_gethostbyname4_r_t f;
134 char buffer[2000];
135 struct gaih_addrtuple *pat = NULL;
136 int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
137 int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl,
138 and will access this variable through *ttlp,
139 so we need to set it to something.
140 I'm not sure if this is a bug in nss-dns
141 or not. */
142 enum nss_status status;
143 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
144 int n;
145
146 fname = strjoina("_nss_", module, "_gethostbyname4_r");
147 f = dlsym(handle, fname);
148 log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
149 assert_se(f);
150
151 status = f(name, &pat, buffer, sizeof buffer, &errno1, &errno2, &ttl);
152 if (status == NSS_STATUS_SUCCESS) {
153 log_info("%s(\"%s\") → status=%s%-20spat=buffer+0x%tx errno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
154 fname, name,
155 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
156 pat ? (char*) pat - buffer : 0,
157 errno1, errno_to_name(errno1) ?: "---",
158 errno2, hstrerror(errno2),
159 ttl);
160 n = print_gaih_addrtuples(pat);
161 } else {
162 log_info("%s(\"%s\") → status=%s%-20spat=0x%p errno=%d/%s h_errno=%d/%s",
163 fname, name,
164 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
165 pat,
166 errno1, errno_to_name(errno1) ?: "---",
167 errno2, hstrerror(errno2));
168 n = 0;
169 }
170
171 if (STR_IN_SET(module, "resolve", "mymachines") && status == NSS_STATUS_UNAVAIL)
172 return;
173
174 if (STR_IN_SET(module, "myhostname", "resolve") && streq(name, "localhost")) {
175 assert_se(status == NSS_STATUS_SUCCESS);
176 assert_se(n == 2);
177 }
178}
179
2abb5b3b
ZJS
180static void test_gethostbyname3_r(void *handle, const char *module, const char *name, int af) {
181 const char *fname;
182 _nss_gethostbyname3_r_t f;
183 char buffer[2000];
184 int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
185 int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl,
186 and will access this variable through *ttlp,
187 so we need to set it to something.
188 I'm not sure if this is a bug in nss-dns
189 or not. */
190 enum nss_status status;
191 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
192 struct hostent host;
193 char *canon;
194 char family_name[DECIMAL_STR_MAX(int)];
195
196 fname = strjoina("_nss_", module, "_gethostbyname3_r");
197 f = dlsym(handle, fname);
198 log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
199 assert_se(f);
200
201 status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl, &canon);
202 log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
203 fname, name, af_to_string(af, family_name, sizeof family_name),
204 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
205 errno1, errno_to_name(errno1) ?: "---",
206 errno2, hstrerror(errno2),
207 ttl);
208 if (status == NSS_STATUS_SUCCESS)
209 print_struct_hostent(&host, canon);
210}
211
212static void test_gethostbyname2_r(void *handle, const char *module, const char *name, int af) {
213 const char *fname;
214 _nss_gethostbyname2_r_t f;
215 char buffer[2000];
216 int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
217 enum nss_status status;
218 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
219 struct hostent host;
220 char family_name[DECIMAL_STR_MAX(int)];
221
222 fname = strjoina("_nss_", module, "_gethostbyname2_r");
223 f = dlsym(handle, fname);
224 log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
225 assert_se(f);
226
227 status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2);
228 log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s",
229 fname, name, af_to_string(af, family_name, sizeof family_name),
230 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
231 errno1, errno_to_name(errno1) ?: "---",
232 errno2, hstrerror(errno2));
233 if (status == NSS_STATUS_SUCCESS)
234 print_struct_hostent(&host, NULL);
235}
236
237static void test_gethostbyname_r(void *handle, const char *module, const char *name) {
238 const char *fname;
239 _nss_gethostbyname_r_t f;
240 char buffer[2000];
241 int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
242 enum nss_status status;
243 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
244 struct hostent host;
245
246 fname = strjoina("_nss_", module, "_gethostbyname_r");
247 f = dlsym(handle, fname);
248 log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
249 assert_se(f);
250
251 status = f(name, &host, buffer, sizeof buffer, &errno1, &errno2);
252 log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s",
253 fname, name,
254 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
255 errno1, errno_to_name(errno1) ?: "---",
256 errno2, hstrerror(errno2));
257 if (status == NSS_STATUS_SUCCESS)
258 print_struct_hostent(&host, NULL);
259}
260
261static void test_gethostbyaddr2_r(void *handle,
262 const char *module,
263 const void* addr, socklen_t len,
264 int af) {
265
266 const char *fname;
267 _nss_gethostbyaddr2_r_t f;
268 char buffer[2000];
269 int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
270 enum nss_status status;
271 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
272 struct hostent host;
273 int32_t ttl = INT32_MAX;
274 _cleanup_free_ char *addr_pretty = NULL;
275
276 fname = strjoina("_nss_", module, "_gethostbyaddr2_r");
277 f = dlsym(handle, fname);
278
279 log_full_errno(f ? LOG_DEBUG : LOG_INFO, errno,
280 "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f);
281 if (!f)
282 return;
283
284 assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0);
285
286 status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl);
287 log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
288 fname, addr_pretty,
289 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
290 errno1, errno_to_name(errno1) ?: "---",
291 errno2, hstrerror(errno2),
292 ttl);
293 if (status == NSS_STATUS_SUCCESS)
294 print_struct_hostent(&host, NULL);
295}
296
297static void test_gethostbyaddr_r(void *handle,
298 const char *module,
299 const void* addr, socklen_t len,
300 int af) {
301
302 const char *fname;
303 _nss_gethostbyaddr_r_t f;
304 char buffer[2000];
305 int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
306 enum nss_status status;
307 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
308 struct hostent host;
309 _cleanup_free_ char *addr_pretty = NULL;
310
311 fname = strjoina("_nss_", module, "_gethostbyaddr_r");
312 f = dlsym(handle, fname);
313
314 log_full_errno(f ? LOG_DEBUG : LOG_INFO, errno,
315 "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f);
316 if (!f)
317 return;
318
319 assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0);
320
321 status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2);
322 log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s",
323 fname, addr_pretty,
324 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
325 errno1, errno_to_name(errno1) ?: "---",
326 errno2, hstrerror(errno2));
327 if (status == NSS_STATUS_SUCCESS)
328 print_struct_hostent(&host, NULL);
329}
330
331static void test_byname(void *handle, const char *module, const char *name) {
332 test_gethostbyname4_r(handle, module, name);
333 puts("");
334
335 test_gethostbyname3_r(handle, module, name, AF_INET);
336 puts("");
337 test_gethostbyname3_r(handle, module, name, AF_INET6);
338 puts("");
339 test_gethostbyname3_r(handle, module, name, AF_UNSPEC);
340 puts("");
341 test_gethostbyname3_r(handle, module, name, AF_LOCAL);
342 puts("");
343
344 test_gethostbyname2_r(handle, module, name, AF_INET);
345 puts("");
346 test_gethostbyname2_r(handle, module, name, AF_INET6);
347 puts("");
348 test_gethostbyname2_r(handle, module, name, AF_UNSPEC);
349 puts("");
350 test_gethostbyname2_r(handle, module, name, AF_LOCAL);
351 puts("");
352
353 test_gethostbyname_r(handle, module, name);
354 puts("");
355}
356
357static void test_byaddr(void *handle,
358 const char *module,
359 const void* addr, socklen_t len,
360 int af) {
361 test_gethostbyaddr2_r(handle, module, addr, len, af);
362 puts("");
363
364 test_gethostbyaddr_r(handle, module, addr, len, af);
365 puts("");
366}
367
9f7672b3
ZJS
368static int make_addresses(struct local_address **addresses) {
369 int n;
370 size_t n_alloc;
371 _cleanup_free_ struct local_address *addrs = NULL;
372
373 n = local_addresses(NULL, 0, AF_UNSPEC, &addrs);
374 if (n < 0)
375 log_info_errno(n, "Failed to query local addresses: %m");
376
377 n_alloc = n; /* we _can_ do that */
378 if (!GREEDY_REALLOC(addrs, n_alloc, n + 3))
379 return log_oom();
380
381 addrs[n++] = (struct local_address) { .family = AF_INET,
382 .address.in = { htobe32(0x7F000001) } };
383 addrs[n++] = (struct local_address) { .family = AF_INET,
384 .address.in = { htobe32(0x7F000002) } };
385 addrs[n++] = (struct local_address) { .family = AF_INET6,
386 .address.in6 = in6addr_loopback };
387 return 0;
388}
389
390static int test_one_module(const char* dir,
391 const char *module,
392 char **names,
393 struct local_address *addresses,
394 int n_addresses) {
395 void *handle;
396 char **name;
397 int i;
398
9f7672b3
ZJS
399 log_info("======== %s ========", module);
400
8d732e2f 401 handle = open_handle(dir, module, RTLD_LAZY|RTLD_NODELETE);
9f7672b3
ZJS
402 if (!handle)
403 return -EINVAL;
404
405 STRV_FOREACH(name, names)
406 test_byname(handle, module, *name);
407
408 for (i = 0; i < n_addresses; i++)
409 test_byaddr(handle, module,
410 &addresses[i].address,
411 FAMILY_ADDRESS_SIZE(addresses[i].family),
412 addresses[i].family);
413
414 log_info(" ");
415 dlclose(handle);
416 return 0;
417}
418
419static int parse_argv(int argc, char **argv,
420 char ***the_modules,
421 char ***the_names,
422 struct local_address **the_addresses, int *n_addresses) {
423
424 int r, n = 0;
425 _cleanup_strv_free_ char **modules = NULL, **names = NULL;
426 _cleanup_free_ struct local_address *addrs = NULL;
427 size_t n_allocated = 0;
428
429 if (argc > 1)
bea1a013 430 modules = strv_new(argv[1]);
9f7672b3
ZJS
431 else
432 modules = strv_new(
08540a95 433#if ENABLE_NSS_MYHOSTNAME
9f7672b3 434 "myhostname",
2abb5b3b 435#endif
08540a95 436#if ENABLE_NSS_RESOLVE
9f7672b3 437 "resolve",
2abb5b3b 438#endif
08540a95 439#if ENABLE_NSS_MYMACHINES
9f7672b3 440 "mymachines",
2abb5b3b 441#endif
bea1a013 442 "dns");
9f7672b3
ZJS
443 if (!modules)
444 return -ENOMEM;
445
446 if (argc > 2) {
447 char **name;
448 int family;
449 union in_addr_union address;
450
451 STRV_FOREACH(name, argv + 2) {
452 r = in_addr_from_string_auto(*name, &family, &address);
453 if (r < 0) {
454 /* assume this is a name */
455 r = strv_extend(&names, *name);
456 if (r < 0)
457 return r;
458 } else {
459 if (!GREEDY_REALLOC0(addrs, n_allocated, n + 1))
460 return -ENOMEM;
461
462 addrs[n++] = (struct local_address) { .family = family,
463 .address = address };
464 }
465 }
466 } else {
467 _cleanup_free_ char *hostname;
2abb5b3b 468
9f7672b3
ZJS
469 hostname = gethostname_malloc();
470 if (!hostname)
471 return -ENOMEM;
2abb5b3b 472
bea1a013 473 names = strv_new("localhost", "_gateway", "foo_no_such_host", hostname);
9f7672b3
ZJS
474 if (!names)
475 return -ENOMEM;
476
477 n = make_addresses(&addrs);
478 if (n < 0)
479 return n;
480 }
481
482 *the_modules = modules;
483 *the_names = names;
484 modules = names = NULL;
485 *the_addresses = addrs;
486 *n_addresses = n;
487 addrs = NULL;
488 return 0;
489}
490
f68a2622 491static int run(int argc, char **argv) {
9f7672b3
ZJS
492 _cleanup_free_ char *dir = NULL;
493 _cleanup_strv_free_ char **modules = NULL, **names = NULL;
2abb5b3b 494 _cleanup_free_ struct local_address *addresses = NULL;
6a909d41 495 int n_addresses = 0;
9f7672b3
ZJS
496 char **module;
497 int r;
2abb5b3b 498
f68a2622 499 test_setup_logging(LOG_INFO);
2abb5b3b 500
9f7672b3
ZJS
501 r = parse_argv(argc, argv, &modules, &names, &addresses, &n_addresses);
502 if (r < 0) {
503 log_error_errno(r, "Failed to parse arguments: %m");
504 return EXIT_FAILURE;
2abb5b3b
ZJS
505 }
506
9f7672b3
ZJS
507 dir = dirname_malloc(argv[0]);
508 if (!dir)
f68a2622 509 return log_oom();
2abb5b3b 510
9f7672b3
ZJS
511 STRV_FOREACH(module, modules) {
512 r = test_one_module(dir, *module, names, addresses, n_addresses);
513 if (r < 0)
f68a2622 514 return r;
2abb5b3b
ZJS
515 }
516
f68a2622 517 return 0;
2abb5b3b 518}
f68a2622
ZJS
519
520DEFINE_MAIN_FUNCTION(run);