]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-nss-users.c
strv: make iterator in STRV_FOREACH() declaread in the loop
[thirdparty/systemd.git] / src / test / test-nss-users.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <pwd.h>
4 #include <stdlib.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7
8 #include "alloc-util.h"
9 #include "dlfcn-util.h"
10 #include "errno-list.h"
11 #include "format-util.h"
12 #include "log.h"
13 #include "main-func.h"
14 #include "nss-test-util.h"
15 #include "nss-util.h"
16 #include "path-util.h"
17 #include "parse-util.h"
18 #include "stdio-util.h"
19 #include "string-util.h"
20 #include "strv.h"
21 #include "tests.h"
22 #include "user-util.h"
23
24 static size_t arg_bufsize = 1024;
25
26 static void print_struct_passwd(const struct passwd *pwd) {
27 log_info(" \"%s\" / "UID_FMT":"GID_FMT,
28 pwd->pw_name, pwd->pw_uid, pwd->pw_gid);
29 log_info(" passwd=\"%s\"", pwd->pw_passwd);
30 log_info(" gecos=\"%s\"", pwd->pw_gecos);
31 log_info(" dir=\"%s\"", pwd->pw_dir);
32 log_info(" shell=\"%s\"", pwd->pw_shell);
33 }
34
35 static void print_struct_group(const struct group *gr) {
36 _cleanup_free_ char *members = NULL;
37
38 log_info(" \"%s\" / "GID_FMT,
39 gr->gr_name, gr->gr_gid);
40 log_info(" passwd=\"%s\"", gr->gr_passwd);
41
42 assert_se(members = strv_join(gr->gr_mem, ", "));
43 // FIXME: use shell_maybe_quote(SHELL_ESCAPE_EMPTY) when it becomes available
44 log_info(" members=%s", members);
45 }
46
47 static void test_getpwnam_r(void *handle, const char *module, const char *name) {
48 const char *fname;
49 _nss_getpwnam_r_t f;
50 char buffer[arg_bufsize];
51 int errno1 = 999; /* nss-dns doesn't set those */
52 enum nss_status status;
53 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
54 struct passwd pwd;
55
56 fname = strjoina("_nss_", module, "_getpwnam_r");
57 f = dlsym(handle, fname);
58 log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
59 if (!f) {
60 log_info("%s not defined", fname);
61 return;
62 }
63
64 status = f(name, &pwd, buffer, sizeof buffer, &errno1);
65 log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s",
66 fname, name,
67 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
68 errno1, errno_to_name(errno1) ?: "---");
69 if (status == NSS_STATUS_SUCCESS)
70 print_struct_passwd(&pwd);
71 }
72
73 static void test_getgrnam_r(void *handle, const char *module, const char *name) {
74 const char *fname;
75 _nss_getgrnam_r_t f;
76 char buffer[arg_bufsize];
77 int errno1 = 999; /* nss-dns doesn't set those */
78 enum nss_status status;
79 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
80 struct group gr;
81
82 fname = strjoina("_nss_", module, "_getgrnam_r");
83 f = dlsym(handle, fname);
84 log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
85 if (!f) {
86 log_info("%s not defined", fname);
87 return;
88 }
89
90 status = f(name, &gr, buffer, sizeof buffer, &errno1);
91 log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s",
92 fname, name,
93 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
94 errno1, errno_to_name(errno1) ?: "---");
95 if (status == NSS_STATUS_SUCCESS)
96 print_struct_group(&gr);
97 }
98
99 static void test_getpwuid_r(void *handle, const char *module, uid_t uid) {
100 const char *fname;
101 _nss_getpwuid_r_t f;
102 char buffer[arg_bufsize];
103 int errno1 = 999; /* nss-dns doesn't set those */
104 enum nss_status status;
105 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
106 struct passwd pwd;
107
108 fname = strjoina("_nss_", module, "_getpwuid_r");
109 f = dlsym(handle, fname);
110 log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
111 if (!f) {
112 log_info("%s not defined", fname);
113 return;
114 }
115
116 status = f(uid, &pwd, buffer, sizeof buffer, &errno1);
117 log_info("%s("UID_FMT") → status=%s%-20serrno=%d/%s",
118 fname, uid,
119 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
120 errno1, errno_to_name(errno1) ?: "---");
121 if (status == NSS_STATUS_SUCCESS)
122 print_struct_passwd(&pwd);
123 }
124
125 static void test_getgrgid_r(void *handle, const char *module, gid_t gid) {
126 const char *fname;
127 _nss_getgrgid_r_t f;
128 char buffer[arg_bufsize];
129 int errno1 = 999; /* nss-dns doesn't set those */
130 enum nss_status status;
131 char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
132 struct group gr;
133
134 fname = strjoina("_nss_", module, "_getgrgid_r");
135 f = dlsym(handle, fname);
136 log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
137 if (!f) {
138 log_info("%s not defined", fname);
139 return;
140 }
141
142 status = f(gid, &gr, buffer, sizeof buffer, &errno1);
143 log_info("%s("GID_FMT") → status=%s%-20serrno=%d/%s",
144 fname, gid,
145 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
146 errno1, errno_to_name(errno1) ?: "---");
147 if (status == NSS_STATUS_SUCCESS)
148 print_struct_group(&gr);
149 }
150
151 static void test_byname(void *handle, const char *module, const char *name) {
152 test_getpwnam_r(handle, module, name);
153 test_getgrnam_r(handle, module, name);
154 puts("");
155 }
156
157 static void test_byuid(void *handle, const char *module, uid_t uid) {
158 test_getpwuid_r(handle, module, uid);
159 test_getgrgid_r(handle, module, uid);
160 puts("");
161 }
162
163 static int test_one_module(const char *dir,
164 const char *module,
165 char **names) {
166
167 log_info("======== %s ========", module);
168
169 _cleanup_(dlclosep) void *handle = nss_open_handle(dir, module, RTLD_LAZY|RTLD_NODELETE);
170 if (!handle)
171 return -EINVAL;
172
173 STRV_FOREACH(name, names)
174 test_byname(handle, module, *name);
175
176 STRV_FOREACH(name, names) {
177 uid_t uid;
178
179 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
180 /* We use safe_atou32 because we don't want to refuse invalid uids. */
181 if (safe_atou32(*name, &uid) < 0)
182 continue;
183
184 test_byuid(handle, module, uid);
185 }
186
187 log_info(" ");
188 return 0;
189 }
190
191 static int parse_argv(int argc, char **argv,
192 char ***the_modules,
193 char ***the_names) {
194
195 _cleanup_strv_free_ char **modules = NULL, **names = NULL;
196 const char *p;
197 int r;
198
199 p = getenv("SYSTEMD_TEST_NSS_BUFSIZE");
200 if (p) {
201 r = safe_atozu(p, &arg_bufsize);
202 if (r < 0)
203 return log_error_errno(r, "Failed to parse $SYSTEMD_TEST_NSS_BUFSIZE");
204 }
205
206 if (argc > 1)
207 modules = strv_new(argv[1]);
208 else
209 modules = strv_new(
210 #if ENABLE_NSS_SYSTEMD
211 "systemd",
212 #endif
213 #if ENABLE_NSS_MYMACHINES
214 "mymachines",
215 #endif
216 NULL);
217 assert_se(modules);
218
219 if (argc > 2)
220 names = strv_copy(strv_skip(argv, 2));
221 else
222 names = strv_new("root",
223 NOBODY_USER_NAME,
224 "foo_no_such_user",
225 "0",
226 "65534");
227 assert_se(names);
228
229 *the_modules = TAKE_PTR(modules);
230 *the_names = TAKE_PTR(names);
231 return 0;
232 }
233
234 static int run(int argc, char **argv) {
235 _cleanup_free_ char *dir = NULL;
236 _cleanup_strv_free_ char **modules = NULL, **names = NULL;
237 int r;
238
239 test_setup_logging(LOG_INFO);
240
241 r = parse_argv(argc, argv, &modules, &names);
242 if (r < 0)
243 return log_error_errno(r, "Failed to parse arguments: %m");
244
245 assert_se(path_extract_directory(argv[0], &dir) >= 0);
246
247 STRV_FOREACH(module, modules) {
248 r = test_one_module(dir, *module, names);
249 if (r < 0)
250 return r;
251 }
252
253 return 0;
254 }
255
256 DEFINE_MAIN_FUNCTION(run);