Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : local testing of the nss wrapper
5 :
6 : Copyright (C) Guenther Deschner 2009-2010
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 :
24 : #include "torture/torture.h"
25 : #include "torture/local/proto.h"
26 : #include "lib/replace/system/passwd.h"
27 :
28 9388 : static bool copy_passwd(struct torture_context *tctx,
29 : const struct passwd *pwd,
30 : struct passwd *p)
31 : {
32 9388 : p->pw_name = talloc_strdup(tctx, pwd->pw_name);
33 9388 : torture_assert(tctx, (p->pw_name != NULL || pwd->pw_name == NULL), __location__);
34 9388 : p->pw_passwd = talloc_strdup(tctx, pwd->pw_passwd);
35 9388 : torture_assert(tctx, (p->pw_passwd != NULL || pwd->pw_passwd == NULL), __location__);
36 9388 : p->pw_uid = pwd->pw_uid;
37 9388 : p->pw_gid = pwd->pw_gid;
38 9388 : p->pw_gecos = talloc_strdup(tctx, pwd->pw_gecos);
39 9388 : torture_assert(tctx, (p->pw_gecos != NULL || pwd->pw_gecos == NULL), __location__);
40 9388 : p->pw_dir = talloc_strdup(tctx, pwd->pw_dir);
41 9388 : torture_assert(tctx, (p->pw_dir != NULL || pwd->pw_dir == NULL), __location__);
42 9388 : p->pw_shell = talloc_strdup(tctx, pwd->pw_shell);
43 9388 : torture_assert(tctx, (p->pw_shell != NULL || pwd->pw_shell == NULL), __location__);
44 :
45 9388 : return true;
46 : }
47 :
48 7838 : static void print_passwd(struct passwd *pwd)
49 : {
50 7838 : printf("%s:%s:%lu:%lu:%s:%s:%s\n",
51 : pwd->pw_name,
52 : pwd->pw_passwd,
53 7838 : (unsigned long)pwd->pw_uid,
54 7838 : (unsigned long)pwd->pw_gid,
55 : pwd->pw_gecos,
56 : pwd->pw_dir,
57 : pwd->pw_shell);
58 7838 : }
59 :
60 :
61 1550 : static bool test_getpwnam(struct torture_context *tctx,
62 : const char *name,
63 : struct passwd *pwd_p)
64 : {
65 0 : struct passwd *pwd;
66 0 : int ret;
67 :
68 1550 : torture_comment(tctx, "Testing getpwnam: %s\n", name);
69 :
70 1550 : errno = 0;
71 1550 : pwd = getpwnam(name);
72 1550 : ret = errno;
73 1550 : torture_assert(tctx, (pwd != NULL), talloc_asprintf(tctx,
74 : "getpwnam(%s) failed - %d - %s",
75 : name, ret, strerror(ret)));
76 :
77 1550 : if (pwd_p != NULL) {
78 1550 : torture_assert(tctx, copy_passwd(tctx, pwd, pwd_p), __location__);
79 : }
80 :
81 1550 : return true;
82 : }
83 :
84 1552 : static bool test_getpwnam_r(struct torture_context *tctx,
85 : const char *name,
86 : struct passwd *pwd_p)
87 : {
88 0 : struct passwd pwd, *pwdp;
89 0 : char buffer[4096];
90 0 : int ret;
91 :
92 1552 : torture_comment(tctx, "Testing getpwnam_r: %s\n", name);
93 :
94 1552 : ret = getpwnam_r(name, &pwd, buffer, sizeof(buffer), &pwdp);
95 1552 : torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
96 : "getpwnam_r(%s) failed - %d - %s",
97 : name, ret, strerror(ret)));
98 :
99 1552 : print_passwd(&pwd);
100 :
101 1552 : if (pwd_p != NULL) {
102 1552 : torture_assert(tctx, copy_passwd(tctx, &pwd, pwd_p), __location__);
103 : }
104 :
105 1552 : return true;
106 : }
107 :
108 1550 : static bool test_getpwuid(struct torture_context *tctx,
109 : uid_t uid,
110 : struct passwd *pwd_p)
111 : {
112 0 : struct passwd *pwd;
113 0 : int ret;
114 :
115 1550 : torture_comment(tctx, "Testing getpwuid: %lu\n", (unsigned long)uid);
116 :
117 1550 : errno = 0;
118 1550 : pwd = getpwuid(uid);
119 1550 : ret = errno;
120 1550 : torture_assert(tctx, (pwd != NULL), talloc_asprintf(tctx,
121 : "getpwuid(%lu) failed - %d - %s",
122 : (unsigned long)uid, ret, strerror(ret)));
123 :
124 1550 : print_passwd(pwd);
125 :
126 1550 : if (pwd_p != NULL) {
127 1550 : torture_assert(tctx, copy_passwd(tctx, pwd, pwd_p), __location__);
128 : }
129 :
130 1550 : return true;
131 : }
132 :
133 1552 : static bool test_getpwuid_r(struct torture_context *tctx,
134 : uid_t uid,
135 : struct passwd *pwd_p)
136 : {
137 0 : struct passwd pwd, *pwdp;
138 0 : char buffer[4096];
139 0 : int ret;
140 :
141 1552 : torture_comment(tctx, "Testing getpwuid_r: %lu\n", (unsigned long)uid);
142 :
143 1552 : ret = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &pwdp);
144 1552 : torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
145 : "getpwuid_r(%lu) failed - %d - %s",
146 : (unsigned long)uid, ret, strerror(ret)));
147 :
148 1552 : print_passwd(&pwd);
149 :
150 1552 : if (pwd_p != NULL) {
151 1552 : torture_assert(tctx, copy_passwd(tctx, &pwd, pwd_p), __location__);
152 : }
153 :
154 1552 : return true;
155 : }
156 :
157 :
158 8706 : static bool copy_group(struct torture_context *tctx,
159 : const struct group *grp,
160 : struct group *g)
161 : {
162 0 : int i;
163 :
164 8706 : g->gr_name = talloc_strdup(tctx, grp->gr_name);
165 8706 : torture_assert(tctx, (g->gr_name != NULL || grp->gr_name == NULL), __location__);
166 8706 : g->gr_passwd = talloc_strdup(tctx, grp->gr_passwd);
167 8706 : torture_assert(tctx, (g->gr_passwd != NULL || grp->gr_passwd == NULL), __location__);
168 8706 : g->gr_gid = grp->gr_gid;
169 8706 : g->gr_mem = NULL;
170 :
171 8996 : for (i=0; grp->gr_mem && grp->gr_mem[i]; i++) {
172 290 : g->gr_mem = talloc_realloc(tctx, g->gr_mem, char *, i + 2);
173 290 : torture_assert(tctx, (g->gr_mem != NULL), __location__);
174 290 : g->gr_mem[i] = talloc_strdup(g->gr_mem, grp->gr_mem[i]);
175 290 : torture_assert(tctx, (g->gr_mem[i] != NULL), __location__);
176 290 : g->gr_mem[i+1] = NULL;
177 : }
178 :
179 8706 : return true;
180 : }
181 :
182 8706 : static void print_group(struct group *grp)
183 : {
184 0 : int i;
185 8706 : printf("%s:%s:%lu:",
186 : grp->gr_name,
187 : grp->gr_passwd,
188 8706 : (unsigned long)grp->gr_gid);
189 :
190 8706 : if ((grp->gr_mem == NULL) || !grp->gr_mem[0]) {
191 8416 : printf("\n");
192 8416 : return;
193 : }
194 :
195 290 : for (i=0; grp->gr_mem[i+1]; i++) {
196 0 : printf("%s,", grp->gr_mem[i]);
197 : }
198 290 : printf("%s\n", grp->gr_mem[i]);
199 : }
200 :
201 1436 : static bool test_getgrnam(struct torture_context *tctx,
202 : const char *name,
203 : struct group *grp_p)
204 : {
205 0 : struct group *grp;
206 0 : int ret;
207 :
208 1436 : torture_comment(tctx, "Testing getgrnam: %s\n", name);
209 :
210 1436 : errno = 0;
211 1436 : grp = getgrnam(name);
212 1436 : ret = errno;
213 1436 : torture_assert(tctx, (grp != NULL), talloc_asprintf(tctx,
214 : "getgrnam(%s) failed - %d - %s",
215 : name, ret, strerror(ret)));
216 :
217 1436 : print_group(grp);
218 :
219 1436 : if (grp_p != NULL) {
220 1436 : torture_assert(tctx, copy_group(tctx, grp, grp_p), __location__);
221 : }
222 :
223 1436 : return true;
224 : }
225 :
226 1436 : static bool test_getgrnam_r(struct torture_context *tctx,
227 : const char *name,
228 : struct group *grp_p)
229 : {
230 0 : struct group grp, *grpp;
231 0 : char buffer[4096];
232 0 : int ret;
233 :
234 1436 : torture_comment(tctx, "Testing getgrnam_r: %s\n", name);
235 :
236 1436 : ret = getgrnam_r(name, &grp, buffer, sizeof(buffer), &grpp);
237 1436 : torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
238 : "getgrnam_r(%s) failed - %d - %s",
239 : name, ret, strerror(ret)));
240 :
241 1436 : print_group(&grp);
242 :
243 1436 : if (grp_p != NULL) {
244 1436 : torture_assert(tctx, copy_group(tctx, &grp, grp_p), __location__);
245 : }
246 :
247 1436 : return true;
248 : }
249 :
250 :
251 1436 : static bool test_getgrgid(struct torture_context *tctx,
252 : gid_t gid,
253 : struct group *grp_p)
254 : {
255 0 : struct group *grp;
256 0 : int ret;
257 :
258 1436 : torture_comment(tctx, "Testing getgrgid: %lu\n", (unsigned long)gid);
259 :
260 1436 : errno = 0;
261 1436 : grp = getgrgid(gid);
262 1436 : ret = errno;
263 1436 : torture_assert(tctx, (grp != NULL), talloc_asprintf(tctx,
264 : "getgrgid(%lu) failed - %d - %s",
265 : (unsigned long)gid, ret, strerror(ret)));
266 :
267 1436 : print_group(grp);
268 :
269 1436 : if (grp_p != NULL) {
270 1436 : torture_assert(tctx, copy_group(tctx, grp, grp_p), __location__);
271 : }
272 :
273 1436 : return true;
274 : }
275 :
276 1436 : static bool test_getgrgid_r(struct torture_context *tctx,
277 : gid_t gid,
278 : struct group *grp_p)
279 : {
280 0 : struct group grp, *grpp;
281 0 : char buffer[4096];
282 0 : int ret;
283 :
284 1436 : torture_comment(tctx, "Testing getgrgid_r: %lu\n", (unsigned long)gid);
285 :
286 1436 : ret = getgrgid_r(gid, &grp, buffer, sizeof(buffer), &grpp);
287 1436 : torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
288 : "getgrgid_r(%lu) failed - %d - %s",
289 : (unsigned long)gid, ret, strerror(ret)));
290 :
291 1436 : print_group(&grp);
292 :
293 1436 : if (grp_p != NULL) {
294 1436 : torture_assert(tctx, copy_group(tctx, &grp, grp_p), __location__);
295 : }
296 :
297 1436 : return true;
298 : }
299 :
300 16 : static bool test_enum_passwd(struct torture_context *tctx,
301 : struct passwd **pwd_array_p,
302 : size_t *num_pwd_p)
303 : {
304 0 : struct passwd *pwd;
305 16 : struct passwd *pwd_array = NULL;
306 16 : size_t num_pwd = 0;
307 :
308 16 : torture_comment(tctx, "Testing setpwent\n");
309 16 : setpwent();
310 :
311 1608 : while ((pwd = getpwent()) != NULL) {
312 1592 : torture_comment(tctx, "Testing getpwent\n");
313 :
314 1592 : print_passwd(pwd);
315 1592 : if (pwd_array_p && num_pwd_p) {
316 1592 : pwd_array = talloc_realloc(tctx, pwd_array, struct passwd, num_pwd+1);
317 1592 : torture_assert(tctx, pwd_array, "out of memory");
318 1592 : copy_passwd(tctx, pwd, &pwd_array[num_pwd]);
319 1592 : num_pwd++;
320 : }
321 : }
322 :
323 16 : torture_comment(tctx, "Testing endpwent\n");
324 16 : endpwent();
325 :
326 16 : if (pwd_array_p) {
327 16 : *pwd_array_p = pwd_array;
328 : }
329 16 : if (num_pwd_p) {
330 16 : *num_pwd_p = num_pwd;
331 : }
332 :
333 16 : return true;
334 : }
335 :
336 16 : static bool test_enum_r_passwd(struct torture_context *tctx,
337 : struct passwd **pwd_array_p,
338 : size_t *num_pwd_p)
339 : {
340 0 : struct passwd pwd, *pwdp;
341 16 : struct passwd *pwd_array = NULL;
342 16 : size_t num_pwd = 0;
343 0 : char buffer[4096];
344 0 : int ret;
345 :
346 16 : torture_comment(tctx, "Testing setpwent\n");
347 16 : setpwent();
348 :
349 : #ifdef HAVE_GETPWENT_R /* getpwent_r not supported on macOS */
350 0 : while (1) {
351 1608 : torture_comment(tctx, "Testing getpwent_r\n");
352 :
353 : #ifdef SOLARIS_GETPWENT_R
354 : ret = getpwent_r(&pwd, buffer, sizeof(buffer));
355 : #else /* SOLARIS_GETPWENT_R */
356 1608 : ret = getpwent_r(&pwd, buffer, sizeof(buffer), &pwdp);
357 : #endif /* SOLARIS_GETPWENT_R */
358 1608 : if (ret != 0) {
359 16 : if (ret != ENOENT) {
360 0 : torture_comment(tctx, "got %d return code\n", ret);
361 : }
362 16 : break;
363 : }
364 1592 : print_passwd(&pwd);
365 1592 : if (pwd_array_p && num_pwd_p) {
366 1592 : pwd_array = talloc_realloc(tctx, pwd_array, struct passwd, num_pwd+1);
367 1592 : torture_assert(tctx, pwd_array, "out of memory");
368 1592 : copy_passwd(tctx, &pwd, &pwd_array[num_pwd]);
369 1592 : num_pwd++;
370 : }
371 : }
372 : #endif /* getpwent_r not supported on macOS */
373 :
374 16 : torture_comment(tctx, "Testing endpwent\n");
375 16 : endpwent();
376 :
377 16 : if (pwd_array_p) {
378 16 : *pwd_array_p = pwd_array;
379 : }
380 16 : if (num_pwd_p) {
381 16 : *num_pwd_p = num_pwd;
382 : }
383 :
384 16 : return true;
385 : }
386 :
387 9300 : static bool torture_assert_passwd_equal(struct torture_context *tctx,
388 : const struct passwd *p1,
389 : const struct passwd *p2,
390 : const char *comment)
391 : {
392 9300 : torture_assert_str_equal(tctx, p1->pw_name, p2->pw_name, comment);
393 9294 : torture_assert_str_equal(tctx, p1->pw_passwd, p2->pw_passwd, comment);
394 9294 : torture_assert_int_equal(tctx, p1->pw_uid, p2->pw_uid, comment);
395 9294 : torture_assert_int_equal(tctx, p1->pw_gid, p2->pw_gid, comment);
396 9294 : torture_assert_str_equal(tctx, p1->pw_gecos, p2->pw_gecos, comment);
397 9294 : torture_assert_str_equal(tctx, p1->pw_dir, p2->pw_dir, comment);
398 9294 : torture_assert_str_equal(tctx, p1->pw_shell, p2->pw_shell, comment);
399 :
400 9294 : return true;
401 : }
402 :
403 8 : static bool test_passwd(struct torture_context *tctx)
404 : {
405 0 : int i;
406 0 : struct passwd *pwd, pwd1, pwd2;
407 0 : size_t num_pwd;
408 :
409 8 : torture_assert(tctx, test_enum_passwd(tctx, &pwd, &num_pwd),
410 : "failed to enumerate passwd");
411 :
412 782 : for (i=0; i < num_pwd; i++) {
413 776 : torture_assert(tctx, test_getpwnam(tctx, pwd[i].pw_name, &pwd1),
414 : "failed to call getpwnam for enumerated user");
415 776 : torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
416 : "getpwent and getpwnam gave different results"),
417 : __location__);
418 776 : torture_assert(tctx, test_getpwuid(tctx, pwd[i].pw_uid, &pwd2),
419 : "failed to call getpwuid for enumerated user");
420 776 : torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
421 : "getpwent and getpwuid gave different results"),
422 : __location__);
423 774 : torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
424 : "getpwnam and getpwuid gave different results"),
425 : __location__);
426 : }
427 :
428 6 : return true;
429 : }
430 :
431 8 : static bool test_passwd_r(struct torture_context *tctx)
432 : {
433 0 : int i;
434 0 : struct passwd *pwd, pwd1, pwd2;
435 0 : size_t num_pwd;
436 :
437 8 : torture_assert(tctx, test_enum_r_passwd(tctx, &pwd, &num_pwd),
438 : "failed to enumerate passwd");
439 :
440 782 : for (i=0; i < num_pwd; i++) {
441 776 : torture_assert(tctx, test_getpwnam_r(tctx, pwd[i].pw_name, &pwd1),
442 : "failed to call getpwnam_r for enumerated user");
443 776 : torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
444 : "getpwent_r and getpwnam_r gave different results"),
445 : __location__);
446 776 : torture_assert(tctx, test_getpwuid_r(tctx, pwd[i].pw_uid, &pwd2),
447 : "failed to call getpwuid_r for enumerated user");
448 776 : torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
449 : "getpwent_r and getpwuid_r gave different results"),
450 : __location__);
451 774 : torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
452 : "getpwnam_r and getpwuid_r gave different results"),
453 : __location__);
454 : }
455 :
456 6 : return true;
457 : }
458 :
459 8 : static bool test_passwd_r_cross(struct torture_context *tctx)
460 : {
461 0 : int i;
462 0 : struct passwd *pwd, pwd1, pwd2, pwd3, pwd4;
463 0 : size_t num_pwd;
464 :
465 8 : torture_assert(tctx, test_enum_r_passwd(tctx, &pwd, &num_pwd),
466 : "failed to enumerate passwd");
467 :
468 782 : for (i=0; i < num_pwd; i++) {
469 776 : torture_assert(tctx, test_getpwnam_r(tctx, pwd[i].pw_name, &pwd1),
470 : "failed to call getpwnam_r for enumerated user");
471 776 : torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
472 : "getpwent_r and getpwnam_r gave different results"),
473 : __location__);
474 776 : torture_assert(tctx, test_getpwuid_r(tctx, pwd[i].pw_uid, &pwd2),
475 : "failed to call getpwuid_r for enumerated user");
476 776 : torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
477 : "getpwent_r and getpwuid_r gave different results"),
478 : __location__);
479 774 : torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
480 : "getpwnam_r and getpwuid_r gave different results"),
481 : __location__);
482 774 : torture_assert(tctx, test_getpwnam(tctx, pwd[i].pw_name, &pwd3),
483 : "failed to call getpwnam for enumerated user");
484 774 : torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd3,
485 : "getpwent_r and getpwnam gave different results"),
486 : __location__);
487 774 : torture_assert(tctx, test_getpwuid(tctx, pwd[i].pw_uid, &pwd4),
488 : "failed to call getpwuid for enumerated user");
489 774 : torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd4,
490 : "getpwent_r and getpwuid gave different results"),
491 : __location__);
492 774 : torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd3, &pwd4,
493 : "getpwnam and getpwuid gave different results"),
494 : __location__);
495 : }
496 :
497 6 : return true;
498 : }
499 :
500 14 : static bool test_enum_group(struct torture_context *tctx,
501 : struct group **grp_array_p,
502 : size_t *num_grp_p)
503 : {
504 0 : struct group *grp;
505 14 : struct group *grp_array = NULL;
506 14 : size_t num_grp = 0;
507 :
508 14 : torture_comment(tctx, "Testing setgrent\n");
509 14 : setgrent();
510 :
511 1540 : while ((grp = getgrent()) != NULL) {
512 1526 : torture_comment(tctx, "Testing getgrent\n");
513 :
514 1526 : print_group(grp);
515 1526 : if (grp_array_p && num_grp_p) {
516 1526 : grp_array = talloc_realloc(tctx, grp_array, struct group, num_grp+1);
517 1526 : torture_assert(tctx, grp_array, "out of memory");
518 1526 : copy_group(tctx, grp, &grp_array[num_grp]);
519 1526 : num_grp++;
520 : }
521 : }
522 :
523 14 : torture_comment(tctx, "Testing endgrent\n");
524 14 : endgrent();
525 :
526 14 : if (grp_array_p) {
527 14 : *grp_array_p = grp_array;
528 : }
529 14 : if (num_grp_p) {
530 14 : *num_grp_p = num_grp;
531 : }
532 :
533 14 : return true;
534 : }
535 :
536 12 : static bool test_enum_r_group(struct torture_context *tctx,
537 : struct group **grp_array_p,
538 : size_t *num_grp_p)
539 : {
540 0 : struct group grp, *grpp;
541 12 : struct group *grp_array = NULL;
542 12 : size_t num_grp = 0;
543 0 : char buffer[4096];
544 0 : int ret;
545 :
546 12 : torture_comment(tctx, "Testing setgrent\n");
547 12 : setgrent();
548 :
549 : #ifdef HAVE_GETGRENT_R /* getgrent_r not supported on macOS */
550 0 : while (1) {
551 1448 : torture_comment(tctx, "Testing getgrent_r\n");
552 :
553 : #ifdef SOLARIS_GETGRENT_R
554 : ret = getgrent_r(&grp, buffer, sizeof(buffer));
555 : #else /* SOLARIS_GETGRENT_R */
556 1448 : ret = getgrent_r(&grp, buffer, sizeof(buffer), &grpp);
557 : #endif /* SOLARIS_GETGRENT_R */
558 1448 : if (ret != 0) {
559 12 : if (ret != ENOENT) {
560 0 : torture_comment(tctx, "got %d return code\n", ret);
561 : }
562 12 : break;
563 : }
564 1436 : print_group(&grp);
565 1436 : if (grp_array_p && num_grp_p) {
566 1436 : grp_array = talloc_realloc(tctx, grp_array, struct group, num_grp+1);
567 1436 : torture_assert(tctx, grp_array, "out of memory");
568 1436 : copy_group(tctx, &grp, &grp_array[num_grp]);
569 1436 : num_grp++;
570 : }
571 : }
572 : #endif /* getgrent_r not supported on macOS */
573 :
574 12 : torture_comment(tctx, "Testing endgrent\n");
575 12 : endgrent();
576 :
577 12 : if (grp_array_p) {
578 12 : *grp_array_p = grp_array;
579 : }
580 12 : if (num_grp_p) {
581 12 : *num_grp_p = num_grp;
582 : }
583 :
584 12 : return true;
585 : }
586 :
587 8616 : static bool torture_assert_group_equal(struct torture_context *tctx,
588 : const struct group *g1,
589 : const struct group *g2,
590 : const char *comment)
591 : {
592 0 : int i;
593 8616 : torture_assert_str_equal(tctx, g1->gr_name, g2->gr_name, comment);
594 8616 : torture_assert_str_equal(tctx, g1->gr_passwd, g2->gr_passwd, comment);
595 8616 : torture_assert_int_equal(tctx, g1->gr_gid, g2->gr_gid, comment);
596 8616 : torture_assert(tctx, !(g1->gr_mem && !g2->gr_mem), __location__);
597 8616 : torture_assert(tctx, !(!g1->gr_mem && g2->gr_mem), __location__);
598 8616 : if (!g1->gr_mem && !g2->gr_mem) {
599 8328 : return true;
600 : }
601 576 : for (i=0; g1->gr_mem[i] && g2->gr_mem[i]; i++) {
602 288 : torture_assert_str_equal(tctx, g1->gr_mem[i], g2->gr_mem[i], comment);
603 : }
604 :
605 288 : return true;
606 : }
607 :
608 6 : static bool test_group(struct torture_context *tctx)
609 : {
610 0 : int i;
611 0 : struct group *grp, grp1, grp2;
612 0 : size_t num_grp;
613 :
614 6 : torture_assert(tctx, test_enum_group(tctx, &grp, &num_grp),
615 : "failed to enumerate group");
616 :
617 724 : for (i=0; i < num_grp; i++) {
618 718 : torture_assert(tctx, test_getgrnam(tctx, grp[i].gr_name, &grp1),
619 : "failed to call getgrnam for enumerated user");
620 718 : torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp1,
621 : "getgrent and getgrnam gave different results"),
622 : __location__);
623 718 : torture_assert(tctx, test_getgrgid(tctx, grp[i].gr_gid, &grp2),
624 : "failed to call getgrgid for enumerated user");
625 718 : torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp2,
626 : "getgrent and getgrgid gave different results"),
627 : __location__);
628 718 : torture_assert(tctx, torture_assert_group_equal(tctx, &grp1, &grp2,
629 : "getgrnam and getgrgid gave different results"),
630 : __location__);
631 : }
632 :
633 6 : return true;
634 : }
635 :
636 6 : static bool test_group_r(struct torture_context *tctx)
637 : {
638 0 : int i;
639 0 : struct group *grp, grp1, grp2;
640 0 : size_t num_grp;
641 :
642 6 : torture_assert(tctx, test_enum_r_group(tctx, &grp, &num_grp),
643 : "failed to enumerate group");
644 :
645 724 : for (i=0; i < num_grp; i++) {
646 718 : torture_assert(tctx, test_getgrnam_r(tctx, grp[i].gr_name, &grp1),
647 : "failed to call getgrnam_r for enumerated user");
648 718 : torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp1,
649 : "getgrent_r and getgrnam_r gave different results"),
650 : __location__);
651 718 : torture_assert(tctx, test_getgrgid_r(tctx, grp[i].gr_gid, &grp2),
652 : "failed to call getgrgid_r for enumerated user");
653 718 : torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp2,
654 : "getgrent_r and getgrgid_r gave different results"),
655 : __location__);
656 718 : torture_assert(tctx, torture_assert_group_equal(tctx, &grp1, &grp2,
657 : "getgrnam_r and getgrgid_r gave different results"),
658 : __location__);
659 : }
660 :
661 6 : return true;
662 : }
663 :
664 6 : static bool test_group_r_cross(struct torture_context *tctx)
665 : {
666 0 : int i;
667 0 : struct group *grp, grp1, grp2, grp3, grp4;
668 0 : size_t num_grp;
669 :
670 6 : torture_assert(tctx, test_enum_r_group(tctx, &grp, &num_grp),
671 : "failed to enumerate group");
672 :
673 724 : for (i=0; i < num_grp; i++) {
674 718 : torture_assert(tctx, test_getgrnam_r(tctx, grp[i].gr_name, &grp1),
675 : "failed to call getgrnam_r for enumerated user");
676 718 : torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp1,
677 : "getgrent_r and getgrnam_r gave different results"),
678 : __location__);
679 718 : torture_assert(tctx, test_getgrgid_r(tctx, grp[i].gr_gid, &grp2),
680 : "failed to call getgrgid_r for enumerated user");
681 718 : torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp2,
682 : "getgrent_r and getgrgid_r gave different results"),
683 : __location__);
684 718 : torture_assert(tctx, torture_assert_group_equal(tctx, &grp1, &grp2,
685 : "getgrnam_r and getgrgid_r gave different results"),
686 : __location__);
687 718 : torture_assert(tctx, test_getgrnam(tctx, grp[i].gr_name, &grp3),
688 : "failed to call getgrnam for enumerated user");
689 718 : torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp3,
690 : "getgrent_r and getgrnam gave different results"),
691 : __location__);
692 718 : torture_assert(tctx, test_getgrgid(tctx, grp[i].gr_gid, &grp4),
693 : "failed to call getgrgid for enumerated user");
694 718 : torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp4,
695 : "getgrent_r and getgrgid gave different results"),
696 : __location__);
697 718 : torture_assert(tctx, torture_assert_group_equal(tctx, &grp3, &grp4,
698 : "getgrnam and getgrgid gave different results"),
699 : __location__);
700 : }
701 :
702 6 : return true;
703 : }
704 :
705 : #ifdef HAVE_GETGROUPLIST
706 0 : static bool test_getgrouplist(struct torture_context *tctx,
707 : const char *user,
708 : gid_t gid,
709 : gid_t **gids_p,
710 : int *num_gids_p)
711 : {
712 0 : int ret;
713 0 : int num_groups = 0;
714 0 : gid_t *groups = NULL;
715 :
716 0 : torture_comment(tctx, "Testing getgrouplist: %s\n", user);
717 :
718 0 : ret = getgrouplist(user, gid, NULL, &num_groups);
719 0 : if (ret == -1 || num_groups != 0) {
720 :
721 0 : groups = talloc_array(tctx, gid_t, num_groups);
722 0 : torture_assert(tctx, groups, "out of memory\n");
723 :
724 0 : ret = getgrouplist(user, gid, groups, &num_groups);
725 : }
726 :
727 0 : torture_assert(tctx, (ret != -1), "failed to call getgrouplist");
728 :
729 0 : torture_comment(tctx, "%s is member in %d groups\n", user, num_groups);
730 :
731 0 : if (gids_p) {
732 0 : *gids_p = groups;
733 : }
734 0 : if (num_gids_p) {
735 0 : *num_gids_p = num_groups;
736 : }
737 :
738 0 : return true;
739 : }
740 : #endif /* HAVE_GETGROUPLIST */
741 :
742 0 : static bool test_user_in_group(struct torture_context *tctx,
743 : const struct passwd *pwd,
744 : const struct group *grp)
745 : {
746 0 : int i;
747 :
748 0 : for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
749 0 : if (strequal(grp->gr_mem[i], pwd->pw_name)) {
750 0 : return true;
751 : }
752 : }
753 :
754 0 : return false;
755 : }
756 :
757 0 : static bool test_membership_user(struct torture_context *tctx,
758 : const struct passwd *pwd,
759 : struct group *grp_array,
760 : size_t num_grp)
761 : {
762 0 : int num_user_groups = 0;
763 0 : int num_user_groups_from_enum = 0;
764 0 : gid_t *user_groups = NULL;
765 0 : int g, i;
766 0 : bool primary_group_had_user_member = false;
767 :
768 : /*
769 : * For the local users ('LOCALADMEMBER') below, the test fails.
770 : * wb_queryuser() wrongly defaults the group sid to RID 513 i.e.
771 : * 'LOCALADMEMBER/domusers', but those users have a different group sid.
772 : *
773 : * The fix for wb_queryuser() is not part of this MR. It is a complex
774 : * task that needs to fill samlogon cache using S4USelf and will come
775 : * sometime later. Once wb_queryuser() gets fixed, this can be removed.
776 : */
777 0 : if (strcmp(pwd->pw_name, "user1") == 0 ||
778 0 : strcmp(pwd->pw_name, "user2") == 0 ||
779 0 : strcmp(pwd->pw_name, "force_user") == 0 || pwd->pw_uid == 1000) {
780 0 : return true;
781 : }
782 :
783 : #ifdef HAVE_GETGROUPLIST
784 0 : torture_assert(tctx, test_getgrouplist(tctx,
785 : pwd->pw_name,
786 : pwd->pw_gid,
787 : &user_groups,
788 : &num_user_groups),
789 : "failed to test getgrouplist");
790 : #endif /* HAVE_GETGROUPLIST */
791 :
792 0 : for (g=0; g < num_user_groups; g++) {
793 0 : torture_assert(tctx, test_getgrgid(tctx, user_groups[g], NULL),
794 : "failed to find the group the user is a member of");
795 : }
796 :
797 :
798 0 : for (i=0; i < num_grp; i++) {
799 :
800 0 : struct group grp = grp_array[i];
801 :
802 0 : if (test_user_in_group(tctx, pwd, &grp)) {
803 :
804 0 : struct group current_grp;
805 0 : num_user_groups_from_enum++;
806 :
807 0 : torture_assert(tctx, test_getgrnam(tctx, grp.gr_name, ¤t_grp),
808 : "failed to find the group the user is a member of");
809 :
810 0 : if (current_grp.gr_gid == pwd->pw_gid) {
811 0 : torture_comment(tctx, "primary group %s of user %s lists user as member\n",
812 : current_grp.gr_name,
813 0 : pwd->pw_name);
814 0 : primary_group_had_user_member = true;
815 : }
816 :
817 0 : continue;
818 : }
819 : }
820 :
821 0 : if (!primary_group_had_user_member) {
822 0 : num_user_groups_from_enum++;
823 : }
824 :
825 0 : torture_assert_int_equal(tctx, num_user_groups, num_user_groups_from_enum,
826 : "getgrouplist and real inspection of grouplist gave different results\n");
827 :
828 0 : return true;
829 : }
830 :
831 9 : static bool test_membership(struct torture_context *tctx)
832 : {
833 9 : const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
834 9 : const char *old_group = getenv("NSS_WRAPPER_GROUP");
835 1 : struct passwd *pwd;
836 1 : size_t num_pwd;
837 1 : struct group *grp;
838 1 : size_t num_grp;
839 1 : int i;
840 9 : const char *env = getenv("ENVNAME");
841 :
842 9 : if (!old_pwd || !old_group) {
843 1 : torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
844 1 : torture_skip(tctx, "nothing to test\n");
845 : }
846 :
847 : /*
848 : * test_membership_user() fails for ad_dc with error like this:
849 : *
850 : * WARNING!: ../../source4/torture/local/nss_tests.c:823:
851 : * num_user_groups was 3 (0x3), expected 2 (0x2): getgrouplist
852 : * and real inspection of grouplist gave different results
853 :
854 : * There are at least 3 reasons:
855 :
856 : * 1. For each ADDOMAIN user, there is also a group with the same name:
857 :
858 : $ bin/wbinfo --user-info ADDOMAIN/alice
859 : ADDOMAIN/alice:*:3000015:65531::/home/ADDOMAIN/alice:/bin/false
860 :
861 : $ bin/wbinfo --group-info ADDOMAIN/alice
862 : ADDOMAIN/alice:x:3000015:ADDOMAIN/alice
863 :
864 : * 2. ADDOMAIN/joe is the only user of "ADDOMAIN/Domain Users"
865 : * e.g. alice is not there:
866 :
867 : $ bin/wbinfo --group-info "ADDOMAIN/Domain users"
868 : ADDOMAIN/domain users:x:65531:ADDOMAIN/joe
869 :
870 : * 3. getgrouplist() for joe returns also "ADDOMAIN/samba users"
871 : * but "ADDOMAIN/samba users" is an empty group:
872 :
873 : $ bin/wbinfo --group-info "ADDOMAIN/samba users"
874 : ADDOMAIN/samba users:x:3000051:
875 :
876 : */
877 :
878 : /* Only ad_member_idmap_rid sets 'winbind expand groups' */
879 8 : if (strcmp(env, "ad_member_idmap_rid:local") != 0) {
880 8 : torture_comment(tctx,
881 : "Testing in env '%s' is not supported.\n",
882 : env);
883 8 : torture_skip(tctx, "nothing to test\n");
884 : return true;
885 : }
886 :
887 0 : torture_assert(tctx, test_enum_passwd(tctx, &pwd, &num_pwd),
888 : "failed to enumerate passwd");
889 0 : torture_assert(tctx, test_enum_group(tctx, &grp, &num_grp),
890 : "failed to enumerate group");
891 :
892 0 : for (i=0; i < num_pwd; i++) {
893 :
894 0 : torture_assert(tctx, test_membership_user(tctx, &pwd[i], grp, num_grp),
895 : "failed to test membership for user");
896 :
897 : }
898 :
899 0 : return true;
900 : }
901 :
902 9 : static bool test_enumeration(struct torture_context *tctx)
903 : {
904 9 : const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
905 9 : const char *old_group = getenv("NSS_WRAPPER_GROUP");
906 :
907 9 : if (!old_pwd || !old_group) {
908 1 : torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
909 1 : torture_skip(tctx, "nothing to test\n");
910 : }
911 :
912 8 : torture_assert(tctx, test_passwd(tctx),
913 : "failed to test users");
914 6 : torture_assert(tctx, test_group(tctx),
915 : "failed to test groups");
916 :
917 6 : return true;
918 : }
919 :
920 9 : static bool test_reentrant_enumeration(struct torture_context *tctx)
921 : {
922 9 : const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
923 9 : const char *old_group = getenv("NSS_WRAPPER_GROUP");
924 :
925 9 : if (!old_pwd || !old_group) {
926 1 : torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
927 1 : torture_skip(tctx, "nothing to test\n");
928 : }
929 :
930 8 : torture_comment(tctx, "Testing re-entrant calls\n");
931 :
932 8 : torture_assert(tctx, test_passwd_r(tctx),
933 : "failed to test users");
934 6 : torture_assert(tctx, test_group_r(tctx),
935 : "failed to test groups");
936 :
937 6 : return true;
938 : }
939 :
940 9 : static bool test_reentrant_enumeration_crosschecks(struct torture_context *tctx)
941 : {
942 9 : const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
943 9 : const char *old_group = getenv("NSS_WRAPPER_GROUP");
944 :
945 9 : if (!old_pwd || !old_group) {
946 1 : torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
947 1 : torture_skip(tctx, "nothing to test\n");
948 : }
949 :
950 8 : torture_comment(tctx, "Testing re-entrant calls with cross checks\n");
951 :
952 8 : torture_assert(tctx, test_passwd_r_cross(tctx),
953 : "failed to test users");
954 6 : torture_assert(tctx, test_group_r_cross(tctx),
955 : "failed to test groups");
956 :
957 6 : return true;
958 : }
959 :
960 8 : static bool test_passwd_duplicates(struct torture_context *tctx)
961 : {
962 0 : size_t i, d;
963 0 : struct passwd *pwd;
964 0 : size_t num_pwd;
965 8 : int duplicates = 0;
966 :
967 8 : torture_assert(tctx, test_enum_passwd(tctx, &pwd, &num_pwd),
968 : "failed to enumerate passwd");
969 :
970 804 : for (i=0; i < num_pwd; i++) {
971 796 : const char *current_name = pwd[i].pw_name;
972 125248 : for (d=0; d < num_pwd; d++) {
973 124452 : const char *dup_name = pwd[d].pw_name;
974 124452 : if (d == i) {
975 796 : continue;
976 : }
977 123656 : if (!strequal(current_name, dup_name)) {
978 123656 : continue;
979 : }
980 :
981 0 : torture_warning(tctx, "found duplicate names:");
982 0 : print_passwd(&pwd[d]);
983 0 : print_passwd(&pwd[i]);
984 0 : duplicates++;
985 : }
986 : }
987 :
988 8 : if (duplicates) {
989 0 : torture_fail(tctx, talloc_asprintf(tctx, "found %d duplicate names", duplicates));
990 : }
991 :
992 8 : return true;
993 : }
994 :
995 8 : static bool test_group_duplicates(struct torture_context *tctx)
996 : {
997 0 : size_t i, d;
998 0 : struct group *grp;
999 0 : size_t num_grp;
1000 8 : int duplicates = 0;
1001 :
1002 8 : torture_assert(tctx, test_enum_group(tctx, &grp, &num_grp),
1003 : "failed to enumerate group");
1004 :
1005 816 : for (i=0; i < num_grp; i++) {
1006 808 : const char *current_name = grp[i].gr_name;
1007 113860 : for (d=0; d < num_grp; d++) {
1008 113052 : const char *dup_name = grp[d].gr_name;
1009 113052 : if (d == i) {
1010 808 : continue;
1011 : }
1012 112244 : if (!strequal(current_name, dup_name)) {
1013 112244 : continue;
1014 : }
1015 :
1016 0 : torture_warning(tctx, "found duplicate names:");
1017 0 : print_group(&grp[d]);
1018 0 : print_group(&grp[i]);
1019 0 : duplicates++;
1020 : }
1021 : }
1022 :
1023 8 : if (duplicates) {
1024 0 : torture_fail(tctx, talloc_asprintf(tctx, "found %d duplicate names", duplicates));
1025 : }
1026 :
1027 8 : return true;
1028 : }
1029 :
1030 :
1031 9 : static bool test_duplicates(struct torture_context *tctx)
1032 : {
1033 9 : const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
1034 9 : const char *old_group = getenv("NSS_WRAPPER_GROUP");
1035 :
1036 9 : if (!old_pwd || !old_group) {
1037 1 : torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
1038 1 : torture_skip(tctx, "nothing to test\n");
1039 : }
1040 :
1041 8 : torture_assert(tctx, test_passwd_duplicates(tctx),
1042 : "failed to test users");
1043 8 : torture_assert(tctx, test_group_duplicates(tctx),
1044 : "failed to test groups");
1045 :
1046 8 : return true;
1047 : }
1048 :
1049 :
1050 2354 : struct torture_suite *torture_local_nss(TALLOC_CTX *mem_ctx)
1051 : {
1052 2354 : struct torture_suite *suite = torture_suite_create(mem_ctx, "nss");
1053 :
1054 2354 : torture_suite_add_simple_test(suite, "enumeration", test_enumeration);
1055 2354 : torture_suite_add_simple_test(suite, "reentrant enumeration", test_reentrant_enumeration);
1056 2354 : torture_suite_add_simple_test(suite, "reentrant enumeration crosschecks", test_reentrant_enumeration_crosschecks);
1057 2354 : torture_suite_add_simple_test(suite, "membership", test_membership);
1058 2354 : torture_suite_add_simple_test(suite, "duplicates", test_duplicates);
1059 :
1060 2354 : return suite;
1061 : }
|