]>
Commit | Line | Data |
---|---|---|
ae5c498d | 1 | /* Template generic NSS service provider. See nss_test.h for usage. |
d614a753 | 2 | Copyright (C) 2017-2020 Free Software Foundation, Inc. |
ae5c498d DD |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, see | |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
ae5c498d | 18 | |
c3e2f19b UD |
19 | #include <errno.h> |
20 | #include <nss.h> | |
21 | #include <pthread.h> | |
22 | #include <string.h> | |
ae5c498d DD |
23 | #include <stdio.h> |
24 | #include <alloc_buffer.h> | |
c3e2f19b UD |
25 | |
26 | ||
ae5c498d DD |
27 | /* We need to be able to handle NULLs "properly" within the testsuite, |
28 | to test known bad data. */ | |
29 | #define alloc_buffer_maybe_copy_string(b,s) s ? alloc_buffer_copy_string (b, s) : NULL; | |
c3e2f19b | 30 | |
ae5c498d DD |
31 | /* This file is the master template. Other instances of this test |
32 | module should define NAME(x) to have their name instead of "test1", | |
33 | then include this file. | |
34 | */ | |
35 | #define NAME_(x,n) _nss_##n##_##x | |
36 | #ifndef NAME | |
37 | #define NAME(x) NAME_(x,test1) | |
38 | #endif | |
39 | #define NAMESTR__(x) #x | |
40 | #define NAMESTR_(x) NAMESTR__(x) | |
41 | #define NAMESTR(x) NAMESTR_(NAME(x)) | |
c3e2f19b | 42 | |
ae5c498d DD |
43 | #include "nss_test.h" |
44 | ||
45 | /* -------------------------------------------------- */ | |
46 | /* Default Data. */ | |
c3e2f19b | 47 | |
ae5c498d | 48 | static struct passwd default_pwd_data[] = |
c3e2f19b UD |
49 | { |
50 | #define PWD(u) \ | |
51 | { .pw_name = (char *) "name" #u, .pw_passwd = (char *) "*", .pw_uid = u, \ | |
52 | .pw_gid = 100, .pw_gecos = (char *) "*", .pw_dir = (char *) "*", \ | |
53 | .pw_shell = (char *) "*" } | |
c3e2f19b | 54 | PWD (30), |
ae5c498d | 55 | PWD (100), |
c3e2f19b UD |
56 | PWD (200), |
57 | PWD (60), | |
58 | PWD (20000) | |
59 | }; | |
cb62108e SE |
60 | #define default_npwd_data \ |
61 | (sizeof (default_pwd_data) / sizeof (default_pwd_data[0])) | |
ae5c498d DD |
62 | |
63 | static struct passwd *pwd_data = default_pwd_data; | |
64 | static int npwd_data = default_npwd_data; | |
65 | ||
66 | static struct group *grp_data = NULL; | |
67 | static int ngrp_data = 0; | |
68 | ||
6eceded9 DD |
69 | static struct hostent *host_data = NULL; |
70 | static int nhost_data = 0; | |
71 | ||
ae5c498d DD |
72 | /* This function will get called, and once per session, look back into |
73 | the test case's executable for an init hook function, and call | |
74 | it. */ | |
75 | ||
76 | static int initted = 0; | |
77 | static void | |
78 | init(void) | |
79 | { | |
80 | test_tables t; | |
81 | int i; | |
82 | ||
83 | if (initted) | |
84 | return; | |
85 | if (NAME(init_hook)) | |
86 | { | |
c4f50205 | 87 | memset (&t, 0, sizeof (t)); |
ae5c498d DD |
88 | NAME(init_hook)(&t); |
89 | ||
90 | if (t.pwd_table) | |
91 | { | |
92 | pwd_data = t.pwd_table; | |
93 | for (i=0; ! PWD_ISLAST(& pwd_data[i]); i++) | |
94 | ; | |
95 | npwd_data = i; | |
96 | } | |
97 | ||
98 | if (t.grp_table) | |
99 | { | |
100 | grp_data = t.grp_table; | |
101 | for (i=0; ! GRP_ISLAST(& grp_data[i]); i++) | |
102 | ; | |
103 | ngrp_data = i; | |
104 | } | |
6eceded9 DD |
105 | if (t.host_table) |
106 | { | |
107 | host_data = t.host_table; | |
108 | for (i=0; ! HOST_ISLAST(& host_data[i]); i++) | |
109 | ; | |
110 | nhost_data = i; | |
111 | } | |
ae5c498d DD |
112 | } |
113 | initted = 1; | |
114 | } | |
115 | ||
116 | /* -------------------------------------------------- */ | |
117 | /* Password handling. */ | |
c3e2f19b UD |
118 | |
119 | static size_t pwd_iter; | |
120 | #define CURPWD pwd_data[pwd_iter] | |
121 | ||
122 | static pthread_mutex_t pwd_lock = PTHREAD_MUTEX_INITIALIZER; | |
123 | ||
c3e2f19b | 124 | enum nss_status |
ae5c498d | 125 | NAME(setpwent) (int stayopen) |
c3e2f19b | 126 | { |
ae5c498d | 127 | init(); |
c3e2f19b UD |
128 | pwd_iter = 0; |
129 | return NSS_STATUS_SUCCESS; | |
130 | } | |
131 | ||
132 | ||
133 | enum nss_status | |
ae5c498d | 134 | NAME(endpwent) (void) |
c3e2f19b | 135 | { |
ae5c498d | 136 | init(); |
c3e2f19b UD |
137 | return NSS_STATUS_SUCCESS; |
138 | } | |
139 | ||
ae5c498d DD |
140 | static enum nss_status |
141 | copy_passwd (struct passwd *result, struct passwd *local, | |
142 | char *buffer, size_t buflen, int *errnop) | |
143 | { | |
144 | struct alloc_buffer buf = alloc_buffer_create (buffer, buflen); | |
145 | ||
146 | result->pw_name = alloc_buffer_maybe_copy_string (&buf, local->pw_name); | |
147 | result->pw_passwd = alloc_buffer_maybe_copy_string (&buf, local->pw_passwd); | |
148 | result->pw_uid = local->pw_uid; | |
149 | result->pw_gid = local->pw_gid; | |
150 | result->pw_gecos = alloc_buffer_maybe_copy_string (&buf, local->pw_gecos); | |
151 | result->pw_dir = alloc_buffer_maybe_copy_string (&buf, local->pw_dir); | |
152 | result->pw_shell = alloc_buffer_maybe_copy_string (&buf, local->pw_shell); | |
153 | ||
154 | if (alloc_buffer_has_failed (&buf)) | |
155 | { | |
156 | *errnop = ERANGE; | |
157 | return NSS_STATUS_TRYAGAIN; | |
158 | } | |
159 | ||
160 | return NSS_STATUS_SUCCESS; | |
161 | } | |
c3e2f19b UD |
162 | |
163 | enum nss_status | |
ae5c498d | 164 | NAME(getpwent_r) (struct passwd *result, char *buffer, size_t buflen, |
c3e2f19b UD |
165 | int *errnop) |
166 | { | |
c3e2f19b UD |
167 | int res = NSS_STATUS_SUCCESS; |
168 | ||
ae5c498d | 169 | init(); |
c3e2f19b UD |
170 | pthread_mutex_lock (&pwd_lock); |
171 | ||
172 | if (pwd_iter >= npwd_data) | |
173 | res = NSS_STATUS_NOTFOUND; | |
174 | else | |
175 | { | |
ae5c498d | 176 | res = copy_passwd (result, &CURPWD, buffer, buflen, errnop); |
c3e2f19b UD |
177 | ++pwd_iter; |
178 | } | |
179 | ||
180 | pthread_mutex_unlock (&pwd_lock); | |
181 | ||
182 | return res; | |
183 | } | |
184 | ||
185 | ||
186 | enum nss_status | |
ae5c498d | 187 | NAME(getpwuid_r) (uid_t uid, struct passwd *result, char *buffer, |
c3e2f19b UD |
188 | size_t buflen, int *errnop) |
189 | { | |
ae5c498d | 190 | init(); |
c3e2f19b UD |
191 | for (size_t idx = 0; idx < npwd_data; ++idx) |
192 | if (pwd_data[idx].pw_uid == uid) | |
ae5c498d | 193 | return copy_passwd (result, &pwd_data[idx], buffer, buflen, errnop); |
c3e2f19b UD |
194 | |
195 | return NSS_STATUS_NOTFOUND; | |
196 | } | |
197 | ||
198 | ||
199 | enum nss_status | |
ae5c498d | 200 | NAME(getpwnam_r) (const char *name, struct passwd *result, char *buffer, |
c3e2f19b UD |
201 | size_t buflen, int *errnop) |
202 | { | |
ae5c498d | 203 | init(); |
c3e2f19b | 204 | for (size_t idx = 0; idx < npwd_data; ++idx) |
ae5c498d DD |
205 | if (strcmp (pwd_data[idx].pw_name, name) == 0) |
206 | return copy_passwd (result, &pwd_data[idx], buffer, buflen, errnop); | |
207 | ||
208 | return NSS_STATUS_NOTFOUND; | |
209 | } | |
210 | ||
211 | /* -------------------------------------------------- */ | |
212 | /* Group handling. */ | |
213 | ||
214 | static size_t grp_iter; | |
215 | #define CURGRP grp_data[grp_iter] | |
216 | ||
217 | static pthread_mutex_t grp_lock = PTHREAD_MUTEX_INITIALIZER; | |
218 | ||
219 | enum nss_status | |
220 | NAME(setgrent) (int stayopen) | |
221 | { | |
222 | init(); | |
223 | grp_iter = 0; | |
224 | return NSS_STATUS_SUCCESS; | |
225 | } | |
226 | ||
227 | ||
228 | enum nss_status | |
229 | NAME(endgrent) (void) | |
230 | { | |
231 | init(); | |
232 | return NSS_STATUS_SUCCESS; | |
233 | } | |
234 | ||
235 | static enum nss_status | |
236 | copy_group (struct group *result, struct group *local, | |
237 | char *buffer, size_t buflen, int *errnop) | |
238 | { | |
239 | struct alloc_buffer buf = alloc_buffer_create (buffer, buflen); | |
240 | char **memlist; | |
241 | int i; | |
242 | ||
243 | if (local->gr_mem) | |
244 | { | |
245 | i = 0; | |
246 | while (local->gr_mem[i]) | |
247 | ++i; | |
248 | ||
249 | memlist = alloc_buffer_alloc_array (&buf, char *, i + 1); | |
250 | ||
251 | if (memlist) { | |
252 | for (i = 0; local->gr_mem[i]; ++i) | |
253 | memlist[i] = alloc_buffer_maybe_copy_string (&buf, local->gr_mem[i]); | |
254 | memlist[i] = NULL; | |
255 | } | |
256 | ||
257 | result->gr_mem = memlist; | |
258 | } | |
259 | else | |
260 | result->gr_mem = NULL; | |
261 | ||
262 | result->gr_name = alloc_buffer_maybe_copy_string (&buf, local->gr_name); | |
263 | result->gr_passwd = alloc_buffer_maybe_copy_string (&buf, local->gr_passwd); | |
264 | result->gr_gid = local->gr_gid; | |
265 | ||
266 | if (alloc_buffer_has_failed (&buf)) | |
267 | { | |
268 | *errnop = ERANGE; | |
269 | return NSS_STATUS_TRYAGAIN; | |
270 | } | |
271 | ||
272 | return NSS_STATUS_SUCCESS; | |
273 | } | |
274 | ||
275 | ||
276 | enum nss_status | |
277 | NAME(getgrent_r) (struct group *result, char *buffer, size_t buflen, | |
278 | int *errnop) | |
279 | { | |
280 | int res = NSS_STATUS_SUCCESS; | |
281 | ||
282 | init(); | |
283 | pthread_mutex_lock (&grp_lock); | |
284 | ||
285 | if (grp_iter >= ngrp_data) | |
286 | res = NSS_STATUS_NOTFOUND; | |
287 | else | |
288 | { | |
289 | res = copy_group (result, &CURGRP, buffer, buflen, errnop); | |
290 | ++grp_iter; | |
291 | } | |
292 | ||
6eceded9 | 293 | pthread_mutex_unlock (&grp_lock); |
ae5c498d DD |
294 | |
295 | return res; | |
296 | } | |
297 | ||
298 | ||
299 | enum nss_status | |
300 | NAME(getgrgid_r) (gid_t gid, struct group *result, char *buffer, | |
301 | size_t buflen, int *errnop) | |
302 | { | |
303 | init(); | |
304 | for (size_t idx = 0; idx < ngrp_data; ++idx) | |
305 | if (grp_data[idx].gr_gid == gid) | |
306 | return copy_group (result, &grp_data[idx], buffer, buflen, errnop); | |
307 | ||
308 | return NSS_STATUS_NOTFOUND; | |
309 | } | |
310 | ||
311 | ||
312 | enum nss_status | |
313 | NAME(getgrnam_r) (const char *name, struct group *result, char *buffer, | |
314 | size_t buflen, int *errnop) | |
315 | { | |
316 | init(); | |
317 | for (size_t idx = 0; idx < ngrp_data; ++idx) | |
c3e2f19b UD |
318 | if (strcmp (pwd_data[idx].pw_name, name) == 0) |
319 | { | |
ae5c498d | 320 | return copy_group (result, &grp_data[idx], buffer, buflen, errnop); |
c3e2f19b UD |
321 | } |
322 | ||
323 | return NSS_STATUS_NOTFOUND; | |
324 | } | |
6eceded9 DD |
325 | |
326 | /* -------------------------------------------------- */ | |
327 | /* Host handling. */ | |
328 | ||
329 | static size_t host_iter; | |
330 | #define CURHOST host_data[host_iter] | |
331 | ||
332 | static pthread_mutex_t host_lock = PTHREAD_MUTEX_INITIALIZER; | |
333 | ||
334 | enum nss_status | |
335 | NAME(sethostent) (int stayopen) | |
336 | { | |
337 | init(); | |
338 | host_iter = 0; | |
339 | return NSS_STATUS_SUCCESS; | |
340 | } | |
341 | ||
342 | ||
343 | enum nss_status | |
344 | NAME(endhostent) (void) | |
345 | { | |
346 | init(); | |
347 | return NSS_STATUS_SUCCESS; | |
348 | } | |
349 | ||
350 | static enum nss_status | |
351 | copy_host (struct hostent *result, struct hostent *local, | |
352 | char *buffer, size_t buflen, int *errnop) | |
353 | { | |
354 | struct alloc_buffer buf = alloc_buffer_create (buffer, buflen); | |
355 | char **memlist; | |
356 | int i, j; | |
357 | ||
358 | if (local->h_addr_list) | |
359 | { | |
360 | i = 0; | |
361 | while (local->h_addr_list[i]) | |
362 | ++i; | |
363 | ||
364 | memlist = alloc_buffer_alloc_array (&buf, char *, i + 1); | |
365 | ||
366 | if (memlist) { | |
367 | for (j = 0; j < i; ++j) | |
368 | memlist[j] = alloc_buffer_maybe_copy_string (&buf, local->h_addr_list[j]); | |
369 | memlist[j] = NULL; | |
370 | } | |
371 | ||
372 | result->h_addr_list = memlist; | |
373 | } | |
374 | else | |
375 | { | |
376 | result->h_addr_list = NULL; | |
377 | } | |
378 | ||
379 | result->h_aliases = NULL; | |
380 | result->h_addrtype = AF_INET; | |
381 | result->h_length = 4; | |
382 | result->h_name = alloc_buffer_maybe_copy_string (&buf, local->h_name); | |
383 | ||
384 | if (alloc_buffer_has_failed (&buf)) | |
385 | { | |
386 | *errnop = ERANGE; | |
387 | return NSS_STATUS_TRYAGAIN; | |
388 | } | |
389 | ||
390 | return NSS_STATUS_SUCCESS; | |
391 | } | |
392 | ||
393 | ||
394 | enum nss_status | |
395 | NAME(gethostent_r) (struct hostent *ret, char *buffer, size_t buflen, | |
396 | struct hostent **result, int *errnop) | |
397 | { | |
398 | int res = NSS_STATUS_SUCCESS; | |
399 | ||
400 | init(); | |
401 | pthread_mutex_lock (&host_lock); | |
402 | ||
403 | if (host_iter >= nhost_data) | |
404 | { | |
405 | res = NSS_STATUS_NOTFOUND; | |
406 | *result = NULL; | |
407 | } | |
408 | else | |
409 | { | |
410 | res = copy_host (ret, &CURHOST, buffer, buflen, errnop); | |
411 | *result = ret; | |
412 | ++host_iter; | |
413 | } | |
414 | ||
415 | pthread_mutex_unlock (&host_lock); | |
416 | ||
417 | return res; | |
418 | } | |
419 | ||
420 | enum nss_status | |
421 | NAME(gethostbyname3_r) (const char *name, int af, struct hostent *ret, | |
422 | char *buffer, size_t buflen, int *errnop, | |
423 | int *h_errnop, int32_t *ttlp, char **canonp) | |
424 | { | |
425 | init(); | |
426 | ||
427 | for (size_t idx = 0; idx < nhost_data; ++idx) | |
428 | if (strcmp (host_data[idx].h_name, name) == 0) | |
429 | return copy_host (ret, & host_data[idx], buffer, buflen, h_errnop); | |
430 | ||
431 | return NSS_STATUS_NOTFOUND; | |
432 | } | |
433 | ||
434 | enum nss_status | |
435 | NAME(gethostbyname_r) (const char *name, struct hostent *result, | |
436 | char *buffer, size_t buflen, | |
437 | int *errnop, int *h_errnop) | |
438 | { | |
439 | return NAME(gethostbyname3_r) (name, AF_INET, result, buffer, buflen, | |
440 | errnop, h_errnop, NULL, NULL); | |
441 | } | |
442 | ||
443 | enum nss_status | |
444 | NAME(gethostbyname2_r) (const char *name, int af, struct hostent *result, | |
445 | char *buffer, size_t buflen, | |
446 | int *errnop, int *h_errnop) | |
447 | { | |
448 | return NAME(gethostbyname3_r) (name, af, result, buffer, buflen, | |
449 | errnop, h_errnop, NULL, NULL); | |
450 | } | |
451 | ||
452 | enum nss_status | |
453 | NAME(gethostbyaddr2_r) (const void *addr, socklen_t len, int af, | |
454 | struct hostent *result, char *buffer, size_t buflen, | |
455 | int *errnop, int *h_errnop, int32_t *ttlp) | |
456 | { | |
457 | init(); | |
458 | ||
459 | /* Support this later. */ | |
460 | if (len != 4) | |
461 | return NSS_STATUS_NOTFOUND; | |
462 | ||
463 | for (size_t idx = 0; idx < nhost_data; ++idx) | |
464 | if (memcmp (host_data[idx].h_addr, addr, len) == 0) | |
465 | return copy_host (result, & host_data[idx], buffer, buflen, h_errnop); | |
466 | ||
467 | return NSS_STATUS_NOTFOUND; | |
468 | } | |
469 | ||
470 | /* Note: only the first address is supported, intentionally. */ | |
471 | enum nss_status | |
472 | NAME(gethostbyaddr_r) (const void *addr, socklen_t len, int af, | |
473 | struct hostent *result, char *buffer, size_t buflen, | |
474 | int *errnop, int *h_errnop) | |
475 | { | |
476 | return NAME(gethostbyaddr2_r) (addr, len, af, result, buffer, buflen, | |
477 | errnop, h_errnop, NULL); | |
478 | } |