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
copy_passwd(struct torture_context * tctx,const struct passwd * pwd,struct passwd * p)28 static bool copy_passwd(struct torture_context *tctx,
29 const struct passwd *pwd,
30 struct passwd *p)
31 {
32 p->pw_name = talloc_strdup(tctx, pwd->pw_name);
33 torture_assert(tctx, (p->pw_name != NULL || pwd->pw_name == NULL), __location__);
34 p->pw_passwd = talloc_strdup(tctx, pwd->pw_passwd);
35 torture_assert(tctx, (p->pw_passwd != NULL || pwd->pw_passwd == NULL), __location__);
36 p->pw_uid = pwd->pw_uid;
37 p->pw_gid = pwd->pw_gid;
38 p->pw_gecos = talloc_strdup(tctx, pwd->pw_gecos);
39 torture_assert(tctx, (p->pw_gecos != NULL || pwd->pw_gecos == NULL), __location__);
40 p->pw_dir = talloc_strdup(tctx, pwd->pw_dir);
41 torture_assert(tctx, (p->pw_dir != NULL || pwd->pw_dir == NULL), __location__);
42 p->pw_shell = talloc_strdup(tctx, pwd->pw_shell);
43 torture_assert(tctx, (p->pw_shell != NULL || pwd->pw_shell == NULL), __location__);
44
45 return true;
46 }
47
print_passwd(struct passwd * pwd)48 static void print_passwd(struct passwd *pwd)
49 {
50 printf("%s:%s:%lu:%lu:%s:%s:%s\n",
51 pwd->pw_name,
52 pwd->pw_passwd,
53 (unsigned long)pwd->pw_uid,
54 (unsigned long)pwd->pw_gid,
55 pwd->pw_gecos,
56 pwd->pw_dir,
57 pwd->pw_shell);
58 }
59
60
test_getpwnam(struct torture_context * tctx,const char * name,struct passwd * pwd_p)61 static bool test_getpwnam(struct torture_context *tctx,
62 const char *name,
63 struct passwd *pwd_p)
64 {
65 struct passwd *pwd;
66 int ret;
67
68 torture_comment(tctx, "Testing getpwnam: %s\n", name);
69
70 errno = 0;
71 pwd = getpwnam(name);
72 ret = errno;
73 torture_assert(tctx, (pwd != NULL), talloc_asprintf(tctx,
74 "getpwnam(%s) failed - %d - %s",
75 name, ret, strerror(ret)));
76
77 if (pwd_p != NULL) {
78 torture_assert(tctx, copy_passwd(tctx, pwd, pwd_p), __location__);
79 }
80
81 return true;
82 }
83
test_getpwnam_r(struct torture_context * tctx,const char * name,struct passwd * pwd_p)84 static bool test_getpwnam_r(struct torture_context *tctx,
85 const char *name,
86 struct passwd *pwd_p)
87 {
88 struct passwd pwd, *pwdp;
89 char buffer[4096];
90 int ret;
91
92 torture_comment(tctx, "Testing getpwnam_r: %s\n", name);
93
94 ret = getpwnam_r(name, &pwd, buffer, sizeof(buffer), &pwdp);
95 torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
96 "getpwnam_r(%s) failed - %d - %s",
97 name, ret, strerror(ret)));
98
99 print_passwd(&pwd);
100
101 if (pwd_p != NULL) {
102 torture_assert(tctx, copy_passwd(tctx, &pwd, pwd_p), __location__);
103 }
104
105 return true;
106 }
107
test_getpwuid(struct torture_context * tctx,uid_t uid,struct passwd * pwd_p)108 static bool test_getpwuid(struct torture_context *tctx,
109 uid_t uid,
110 struct passwd *pwd_p)
111 {
112 struct passwd *pwd;
113 int ret;
114
115 torture_comment(tctx, "Testing getpwuid: %lu\n", (unsigned long)uid);
116
117 errno = 0;
118 pwd = getpwuid(uid);
119 ret = errno;
120 torture_assert(tctx, (pwd != NULL), talloc_asprintf(tctx,
121 "getpwuid(%lu) failed - %d - %s",
122 (unsigned long)uid, ret, strerror(ret)));
123
124 print_passwd(pwd);
125
126 if (pwd_p != NULL) {
127 torture_assert(tctx, copy_passwd(tctx, pwd, pwd_p), __location__);
128 }
129
130 return true;
131 }
132
test_getpwuid_r(struct torture_context * tctx,uid_t uid,struct passwd * pwd_p)133 static bool test_getpwuid_r(struct torture_context *tctx,
134 uid_t uid,
135 struct passwd *pwd_p)
136 {
137 struct passwd pwd, *pwdp;
138 char buffer[4096];
139 int ret;
140
141 torture_comment(tctx, "Testing getpwuid_r: %lu\n", (unsigned long)uid);
142
143 ret = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &pwdp);
144 torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
145 "getpwuid_r(%lu) failed - %d - %s",
146 (unsigned long)uid, ret, strerror(ret)));
147
148 print_passwd(&pwd);
149
150 if (pwd_p != NULL) {
151 torture_assert(tctx, copy_passwd(tctx, &pwd, pwd_p), __location__);
152 }
153
154 return true;
155 }
156
157
copy_group(struct torture_context * tctx,const struct group * grp,struct group * g)158 static bool copy_group(struct torture_context *tctx,
159 const struct group *grp,
160 struct group *g)
161 {
162 int i;
163
164 g->gr_name = talloc_strdup(tctx, grp->gr_name);
165 torture_assert(tctx, (g->gr_name != NULL || grp->gr_name == NULL), __location__);
166 g->gr_passwd = talloc_strdup(tctx, grp->gr_passwd);
167 torture_assert(tctx, (g->gr_passwd != NULL || grp->gr_passwd == NULL), __location__);
168 g->gr_gid = grp->gr_gid;
169 g->gr_mem = NULL;
170
171 for (i=0; grp->gr_mem && grp->gr_mem[i]; i++) {
172 g->gr_mem = talloc_realloc(tctx, g->gr_mem, char *, i + 2);
173 torture_assert(tctx, (g->gr_mem != NULL), __location__);
174 g->gr_mem[i] = talloc_strdup(g->gr_mem, grp->gr_mem[i]);
175 torture_assert(tctx, (g->gr_mem[i] != NULL), __location__);
176 g->gr_mem[i+1] = NULL;
177 }
178
179 return true;
180 }
181
print_group(struct group * grp)182 static void print_group(struct group *grp)
183 {
184 int i;
185 printf("%s:%s:%lu:",
186 grp->gr_name,
187 grp->gr_passwd,
188 (unsigned long)grp->gr_gid);
189
190 if ((grp->gr_mem == NULL) || !grp->gr_mem[0]) {
191 printf("\n");
192 return;
193 }
194
195 for (i=0; grp->gr_mem[i+1]; i++) {
196 printf("%s,", grp->gr_mem[i]);
197 }
198 printf("%s\n", grp->gr_mem[i]);
199 }
200
test_getgrnam(struct torture_context * tctx,const char * name,struct group * grp_p)201 static bool test_getgrnam(struct torture_context *tctx,
202 const char *name,
203 struct group *grp_p)
204 {
205 struct group *grp;
206 int ret;
207
208 torture_comment(tctx, "Testing getgrnam: %s\n", name);
209
210 errno = 0;
211 grp = getgrnam(name);
212 ret = errno;
213 torture_assert(tctx, (grp != NULL), talloc_asprintf(tctx,
214 "getgrnam(%s) failed - %d - %s",
215 name, ret, strerror(ret)));
216
217 print_group(grp);
218
219 if (grp_p != NULL) {
220 torture_assert(tctx, copy_group(tctx, grp, grp_p), __location__);
221 }
222
223 return true;
224 }
225
test_getgrnam_r(struct torture_context * tctx,const char * name,struct group * grp_p)226 static bool test_getgrnam_r(struct torture_context *tctx,
227 const char *name,
228 struct group *grp_p)
229 {
230 struct group grp, *grpp;
231 char buffer[4096];
232 int ret;
233
234 torture_comment(tctx, "Testing getgrnam_r: %s\n", name);
235
236 ret = getgrnam_r(name, &grp, buffer, sizeof(buffer), &grpp);
237 torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
238 "getgrnam_r(%s) failed - %d - %s",
239 name, ret, strerror(ret)));
240
241 print_group(&grp);
242
243 if (grp_p != NULL) {
244 torture_assert(tctx, copy_group(tctx, &grp, grp_p), __location__);
245 }
246
247 return true;
248 }
249
250
test_getgrgid(struct torture_context * tctx,gid_t gid,struct group * grp_p)251 static bool test_getgrgid(struct torture_context *tctx,
252 gid_t gid,
253 struct group *grp_p)
254 {
255 struct group *grp;
256 int ret;
257
258 torture_comment(tctx, "Testing getgrgid: %lu\n", (unsigned long)gid);
259
260 errno = 0;
261 grp = getgrgid(gid);
262 ret = errno;
263 torture_assert(tctx, (grp != NULL), talloc_asprintf(tctx,
264 "getgrgid(%lu) failed - %d - %s",
265 (unsigned long)gid, ret, strerror(ret)));
266
267 print_group(grp);
268
269 if (grp_p != NULL) {
270 torture_assert(tctx, copy_group(tctx, grp, grp_p), __location__);
271 }
272
273 return true;
274 }
275
test_getgrgid_r(struct torture_context * tctx,gid_t gid,struct group * grp_p)276 static bool test_getgrgid_r(struct torture_context *tctx,
277 gid_t gid,
278 struct group *grp_p)
279 {
280 struct group grp, *grpp;
281 char buffer[4096];
282 int ret;
283
284 torture_comment(tctx, "Testing getgrgid_r: %lu\n", (unsigned long)gid);
285
286 ret = getgrgid_r(gid, &grp, buffer, sizeof(buffer), &grpp);
287 torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
288 "getgrgid_r(%lu) failed - %d - %s",
289 (unsigned long)gid, ret, strerror(ret)));
290
291 print_group(&grp);
292
293 if (grp_p != NULL) {
294 torture_assert(tctx, copy_group(tctx, &grp, grp_p), __location__);
295 }
296
297 return true;
298 }
299
test_enum_passwd(struct torture_context * tctx,struct passwd ** pwd_array_p,size_t * num_pwd_p)300 static bool test_enum_passwd(struct torture_context *tctx,
301 struct passwd **pwd_array_p,
302 size_t *num_pwd_p)
303 {
304 struct passwd *pwd;
305 struct passwd *pwd_array = NULL;
306 size_t num_pwd = 0;
307
308 torture_comment(tctx, "Testing setpwent\n");
309 setpwent();
310
311 while ((pwd = getpwent()) != NULL) {
312 torture_comment(tctx, "Testing getpwent\n");
313
314 print_passwd(pwd);
315 if (pwd_array_p && num_pwd_p) {
316 pwd_array = talloc_realloc(tctx, pwd_array, struct passwd, num_pwd+1);
317 torture_assert(tctx, pwd_array, "out of memory");
318 copy_passwd(tctx, pwd, &pwd_array[num_pwd]);
319 num_pwd++;
320 }
321 }
322
323 torture_comment(tctx, "Testing endpwent\n");
324 endpwent();
325
326 if (pwd_array_p) {
327 *pwd_array_p = pwd_array;
328 }
329 if (num_pwd_p) {
330 *num_pwd_p = num_pwd;
331 }
332
333 return true;
334 }
335
test_enum_r_passwd(struct torture_context * tctx,struct passwd ** pwd_array_p,size_t * num_pwd_p)336 static bool test_enum_r_passwd(struct torture_context *tctx,
337 struct passwd **pwd_array_p,
338 size_t *num_pwd_p)
339 {
340 struct passwd pwd, *pwdp;
341 struct passwd *pwd_array = NULL;
342 size_t num_pwd = 0;
343 char buffer[4096];
344 int ret;
345
346 torture_comment(tctx, "Testing setpwent\n");
347 setpwent();
348
349 #ifdef HAVE_GETPWENT_R /* getpwent_r not supported on macOS */
350 while (1) {
351 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 ret = getpwent_r(&pwd, buffer, sizeof(buffer), &pwdp);
357 #endif /* SOLARIS_GETPWENT_R */
358 if (ret != 0) {
359 if (ret != ENOENT) {
360 torture_comment(tctx, "got %d return code\n", ret);
361 }
362 break;
363 }
364 print_passwd(&pwd);
365 if (pwd_array_p && num_pwd_p) {
366 pwd_array = talloc_realloc(tctx, pwd_array, struct passwd, num_pwd+1);
367 torture_assert(tctx, pwd_array, "out of memory");
368 copy_passwd(tctx, &pwd, &pwd_array[num_pwd]);
369 num_pwd++;
370 }
371 }
372 #endif /* getpwent_r not supported on macOS */
373
374 torture_comment(tctx, "Testing endpwent\n");
375 endpwent();
376
377 if (pwd_array_p) {
378 *pwd_array_p = pwd_array;
379 }
380 if (num_pwd_p) {
381 *num_pwd_p = num_pwd;
382 }
383
384 return true;
385 }
386
torture_assert_passwd_equal(struct torture_context * tctx,const struct passwd * p1,const struct passwd * p2,const char * comment)387 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 torture_assert_str_equal(tctx, p1->pw_name, p2->pw_name, comment);
393 torture_assert_str_equal(tctx, p1->pw_passwd, p2->pw_passwd, comment);
394 torture_assert_int_equal(tctx, p1->pw_uid, p2->pw_uid, comment);
395 torture_assert_int_equal(tctx, p1->pw_gid, p2->pw_gid, comment);
396 torture_assert_str_equal(tctx, p1->pw_gecos, p2->pw_gecos, comment);
397 torture_assert_str_equal(tctx, p1->pw_dir, p2->pw_dir, comment);
398 torture_assert_str_equal(tctx, p1->pw_shell, p2->pw_shell, comment);
399
400 return true;
401 }
402
test_passwd(struct torture_context * tctx)403 static bool test_passwd(struct torture_context *tctx)
404 {
405 int i;
406 struct passwd *pwd, pwd1, pwd2;
407 size_t num_pwd;
408
409 torture_assert(tctx, test_enum_passwd(tctx, &pwd, &num_pwd),
410 "failed to enumerate passwd");
411
412 for (i=0; i < num_pwd; i++) {
413 torture_assert(tctx, test_getpwnam(tctx, pwd[i].pw_name, &pwd1),
414 "failed to call getpwnam for enumerated user");
415 torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
416 "getpwent and getpwnam gave different results"),
417 __location__);
418 torture_assert(tctx, test_getpwuid(tctx, pwd[i].pw_uid, &pwd2),
419 "failed to call getpwuid for enumerated user");
420 torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
421 "getpwent and getpwuid gave different results"),
422 __location__);
423 torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
424 "getpwnam and getpwuid gave different results"),
425 __location__);
426 }
427
428 return true;
429 }
430
test_passwd_r(struct torture_context * tctx)431 static bool test_passwd_r(struct torture_context *tctx)
432 {
433 int i;
434 struct passwd *pwd, pwd1, pwd2;
435 size_t num_pwd;
436
437 torture_assert(tctx, test_enum_r_passwd(tctx, &pwd, &num_pwd),
438 "failed to enumerate passwd");
439
440 for (i=0; i < num_pwd; i++) {
441 torture_assert(tctx, test_getpwnam_r(tctx, pwd[i].pw_name, &pwd1),
442 "failed to call getpwnam_r for enumerated user");
443 torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
444 "getpwent_r and getpwnam_r gave different results"),
445 __location__);
446 torture_assert(tctx, test_getpwuid_r(tctx, pwd[i].pw_uid, &pwd2),
447 "failed to call getpwuid_r for enumerated user");
448 torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
449 "getpwent_r and getpwuid_r gave different results"),
450 __location__);
451 torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
452 "getpwnam_r and getpwuid_r gave different results"),
453 __location__);
454 }
455
456 return true;
457 }
458
test_passwd_r_cross(struct torture_context * tctx)459 static bool test_passwd_r_cross(struct torture_context *tctx)
460 {
461 int i;
462 struct passwd *pwd, pwd1, pwd2, pwd3, pwd4;
463 size_t num_pwd;
464
465 torture_assert(tctx, test_enum_r_passwd(tctx, &pwd, &num_pwd),
466 "failed to enumerate passwd");
467
468 for (i=0; i < num_pwd; i++) {
469 torture_assert(tctx, test_getpwnam_r(tctx, pwd[i].pw_name, &pwd1),
470 "failed to call getpwnam_r for enumerated user");
471 torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
472 "getpwent_r and getpwnam_r gave different results"),
473 __location__);
474 torture_assert(tctx, test_getpwuid_r(tctx, pwd[i].pw_uid, &pwd2),
475 "failed to call getpwuid_r for enumerated user");
476 torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
477 "getpwent_r and getpwuid_r gave different results"),
478 __location__);
479 torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
480 "getpwnam_r and getpwuid_r gave different results"),
481 __location__);
482 torture_assert(tctx, test_getpwnam(tctx, pwd[i].pw_name, &pwd3),
483 "failed to call getpwnam for enumerated user");
484 torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd3,
485 "getpwent_r and getpwnam gave different results"),
486 __location__);
487 torture_assert(tctx, test_getpwuid(tctx, pwd[i].pw_uid, &pwd4),
488 "failed to call getpwuid for enumerated user");
489 torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd4,
490 "getpwent_r and getpwuid gave different results"),
491 __location__);
492 torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd3, &pwd4,
493 "getpwnam and getpwuid gave different results"),
494 __location__);
495 }
496
497 return true;
498 }
499
test_enum_group(struct torture_context * tctx,struct group ** grp_array_p,size_t * num_grp_p)500 static bool test_enum_group(struct torture_context *tctx,
501 struct group **grp_array_p,
502 size_t *num_grp_p)
503 {
504 struct group *grp;
505 struct group *grp_array = NULL;
506 size_t num_grp = 0;
507
508 torture_comment(tctx, "Testing setgrent\n");
509 setgrent();
510
511 while ((grp = getgrent()) != NULL) {
512 torture_comment(tctx, "Testing getgrent\n");
513
514 print_group(grp);
515 if (grp_array_p && num_grp_p) {
516 grp_array = talloc_realloc(tctx, grp_array, struct group, num_grp+1);
517 torture_assert(tctx, grp_array, "out of memory");
518 copy_group(tctx, grp, &grp_array[num_grp]);
519 num_grp++;
520 }
521 }
522
523 torture_comment(tctx, "Testing endgrent\n");
524 endgrent();
525
526 if (grp_array_p) {
527 *grp_array_p = grp_array;
528 }
529 if (num_grp_p) {
530 *num_grp_p = num_grp;
531 }
532
533 return true;
534 }
535
test_enum_r_group(struct torture_context * tctx,struct group ** grp_array_p,size_t * num_grp_p)536 static bool test_enum_r_group(struct torture_context *tctx,
537 struct group **grp_array_p,
538 size_t *num_grp_p)
539 {
540 struct group grp, *grpp;
541 struct group *grp_array = NULL;
542 size_t num_grp = 0;
543 char buffer[4096];
544 int ret;
545
546 torture_comment(tctx, "Testing setgrent\n");
547 setgrent();
548
549 #ifdef HAVE_GETGRENT_R /* getgrent_r not supported on macOS */
550 while (1) {
551 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 ret = getgrent_r(&grp, buffer, sizeof(buffer), &grpp);
557 #endif /* SOLARIS_GETGRENT_R */
558 if (ret != 0) {
559 if (ret != ENOENT) {
560 torture_comment(tctx, "got %d return code\n", ret);
561 }
562 break;
563 }
564 print_group(&grp);
565 if (grp_array_p && num_grp_p) {
566 grp_array = talloc_realloc(tctx, grp_array, struct group, num_grp+1);
567 torture_assert(tctx, grp_array, "out of memory");
568 copy_group(tctx, &grp, &grp_array[num_grp]);
569 num_grp++;
570 }
571 }
572 #endif /* getgrent_r not supported on macOS */
573
574 torture_comment(tctx, "Testing endgrent\n");
575 endgrent();
576
577 if (grp_array_p) {
578 *grp_array_p = grp_array;
579 }
580 if (num_grp_p) {
581 *num_grp_p = num_grp;
582 }
583
584 return true;
585 }
586
torture_assert_group_equal(struct torture_context * tctx,const struct group * g1,const struct group * g2,const char * comment)587 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 int i;
593 torture_assert_str_equal(tctx, g1->gr_name, g2->gr_name, comment);
594 torture_assert_str_equal(tctx, g1->gr_passwd, g2->gr_passwd, comment);
595 torture_assert_int_equal(tctx, g1->gr_gid, g2->gr_gid, comment);
596 torture_assert(tctx, !(g1->gr_mem && !g2->gr_mem), __location__);
597 torture_assert(tctx, !(!g1->gr_mem && g2->gr_mem), __location__);
598 if (!g1->gr_mem && !g2->gr_mem) {
599 return true;
600 }
601 for (i=0; g1->gr_mem[i] && g2->gr_mem[i]; i++) {
602 torture_assert_str_equal(tctx, g1->gr_mem[i], g2->gr_mem[i], comment);
603 }
604
605 return true;
606 }
607
test_group(struct torture_context * tctx)608 static bool test_group(struct torture_context *tctx)
609 {
610 int i;
611 struct group *grp, grp1, grp2;
612 size_t num_grp;
613
614 torture_assert(tctx, test_enum_group(tctx, &grp, &num_grp),
615 "failed to enumerate group");
616
617 for (i=0; i < num_grp; i++) {
618 torture_assert(tctx, test_getgrnam(tctx, grp[i].gr_name, &grp1),
619 "failed to call getgrnam for enumerated user");
620 torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp1,
621 "getgrent and getgrnam gave different results"),
622 __location__);
623 torture_assert(tctx, test_getgrgid(tctx, grp[i].gr_gid, &grp2),
624 "failed to call getgrgid for enumerated user");
625 torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp2,
626 "getgrent and getgrgid gave different results"),
627 __location__);
628 torture_assert(tctx, torture_assert_group_equal(tctx, &grp1, &grp2,
629 "getgrnam and getgrgid gave different results"),
630 __location__);
631 }
632
633 return true;
634 }
635
test_group_r(struct torture_context * tctx)636 static bool test_group_r(struct torture_context *tctx)
637 {
638 int i;
639 struct group *grp, grp1, grp2;
640 size_t num_grp;
641
642 torture_assert(tctx, test_enum_r_group(tctx, &grp, &num_grp),
643 "failed to enumerate group");
644
645 for (i=0; i < num_grp; i++) {
646 torture_assert(tctx, test_getgrnam_r(tctx, grp[i].gr_name, &grp1),
647 "failed to call getgrnam_r for enumerated user");
648 torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp1,
649 "getgrent_r and getgrnam_r gave different results"),
650 __location__);
651 torture_assert(tctx, test_getgrgid_r(tctx, grp[i].gr_gid, &grp2),
652 "failed to call getgrgid_r for enumerated user");
653 torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp2,
654 "getgrent_r and getgrgid_r gave different results"),
655 __location__);
656 torture_assert(tctx, torture_assert_group_equal(tctx, &grp1, &grp2,
657 "getgrnam_r and getgrgid_r gave different results"),
658 __location__);
659 }
660
661 return true;
662 }
663
test_group_r_cross(struct torture_context * tctx)664 static bool test_group_r_cross(struct torture_context *tctx)
665 {
666 int i;
667 struct group *grp, grp1, grp2, grp3, grp4;
668 size_t num_grp;
669
670 torture_assert(tctx, test_enum_r_group(tctx, &grp, &num_grp),
671 "failed to enumerate group");
672
673 for (i=0; i < num_grp; i++) {
674 torture_assert(tctx, test_getgrnam_r(tctx, grp[i].gr_name, &grp1),
675 "failed to call getgrnam_r for enumerated user");
676 torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp1,
677 "getgrent_r and getgrnam_r gave different results"),
678 __location__);
679 torture_assert(tctx, test_getgrgid_r(tctx, grp[i].gr_gid, &grp2),
680 "failed to call getgrgid_r for enumerated user");
681 torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp2,
682 "getgrent_r and getgrgid_r gave different results"),
683 __location__);
684 torture_assert(tctx, torture_assert_group_equal(tctx, &grp1, &grp2,
685 "getgrnam_r and getgrgid_r gave different results"),
686 __location__);
687 torture_assert(tctx, test_getgrnam(tctx, grp[i].gr_name, &grp3),
688 "failed to call getgrnam for enumerated user");
689 torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp3,
690 "getgrent_r and getgrnam gave different results"),
691 __location__);
692 torture_assert(tctx, test_getgrgid(tctx, grp[i].gr_gid, &grp4),
693 "failed to call getgrgid for enumerated user");
694 torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp4,
695 "getgrent_r and getgrgid gave different results"),
696 __location__);
697 torture_assert(tctx, torture_assert_group_equal(tctx, &grp3, &grp4,
698 "getgrnam and getgrgid gave different results"),
699 __location__);
700 }
701
702 return true;
703 }
704
705 #ifdef HAVE_GETGROUPLIST
test_getgrouplist(struct torture_context * tctx,const char * user,gid_t gid,gid_t ** gids_p,int * num_gids_p)706 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 int ret;
713 int num_groups = 0;
714 gid_t *groups = NULL;
715
716 torture_comment(tctx, "Testing getgrouplist: %s\n", user);
717
718 ret = getgrouplist(user, gid, NULL, &num_groups);
719 if (ret == -1 || num_groups != 0) {
720
721 groups = talloc_array(tctx, gid_t, num_groups);
722 torture_assert(tctx, groups, "out of memory\n");
723
724 ret = getgrouplist(user, gid, groups, &num_groups);
725 }
726
727 torture_assert(tctx, (ret != -1), "failed to call getgrouplist");
728
729 torture_comment(tctx, "%s is member in %d groups\n", user, num_groups);
730
731 if (gids_p) {
732 *gids_p = groups;
733 }
734 if (num_gids_p) {
735 *num_gids_p = num_groups;
736 }
737
738 return true;
739 }
740 #endif /* HAVE_GETGROUPLIST */
741
test_user_in_group(struct torture_context * tctx,const struct passwd * pwd,const struct group * grp)742 static bool test_user_in_group(struct torture_context *tctx,
743 const struct passwd *pwd,
744 const struct group *grp)
745 {
746 int i;
747
748 for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
749 if (strequal(grp->gr_mem[i], pwd->pw_name)) {
750 return true;
751 }
752 }
753
754 return false;
755 }
756
test_membership_user(struct torture_context * tctx,const struct passwd * pwd,struct group * grp_array,size_t num_grp)757 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 int num_user_groups = 0;
763 int num_user_groups_from_enum = 0;
764 gid_t *user_groups = NULL;
765 int g, i;
766 bool primary_group_had_user_member = false;
767
768 #ifdef HAVE_GETGROUPLIST
769 torture_assert(tctx, test_getgrouplist(tctx,
770 pwd->pw_name,
771 pwd->pw_gid,
772 &user_groups,
773 &num_user_groups),
774 "failed to test getgrouplist");
775 #endif /* HAVE_GETGROUPLIST */
776
777 for (g=0; g < num_user_groups; g++) {
778 torture_assert(tctx, test_getgrgid(tctx, user_groups[g], NULL),
779 "failed to find the group the user is a member of");
780 }
781
782
783 for (i=0; i < num_grp; i++) {
784
785 struct group grp = grp_array[i];
786
787 if (test_user_in_group(tctx, pwd, &grp)) {
788
789 struct group current_grp;
790 num_user_groups_from_enum++;
791
792 torture_assert(tctx, test_getgrnam(tctx, grp.gr_name, ¤t_grp),
793 "failed to find the group the user is a member of");
794
795 if (current_grp.gr_gid == pwd->pw_gid) {
796 torture_comment(tctx, "primary group %s of user %s lists user as member\n",
797 current_grp.gr_name,
798 pwd->pw_name);
799 primary_group_had_user_member = true;
800 }
801
802 continue;
803 }
804 }
805
806 if (!primary_group_had_user_member) {
807 num_user_groups_from_enum++;
808 }
809
810 torture_assert_int_equal(tctx, num_user_groups, num_user_groups_from_enum,
811 "getgrouplist and real inspection of grouplist gave different results\n");
812
813 return true;
814 }
815
test_membership(struct torture_context * tctx)816 static bool test_membership(struct torture_context *tctx)
817 {
818 const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
819 const char *old_group = getenv("NSS_WRAPPER_GROUP");
820 struct passwd *pwd;
821 size_t num_pwd;
822 struct group *grp;
823 size_t num_grp;
824 int i;
825
826 if (!old_pwd || !old_group) {
827 torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
828 torture_skip(tctx, "nothing to test\n");
829 }
830
831 torture_assert(tctx, test_enum_passwd(tctx, &pwd, &num_pwd),
832 "failed to enumerate passwd");
833 torture_assert(tctx, test_enum_group(tctx, &grp, &num_grp),
834 "failed to enumerate group");
835
836 for (i=0; i < num_pwd; i++) {
837
838 torture_assert(tctx, test_membership_user(tctx, &pwd[i], grp, num_grp),
839 "failed to test membership for user");
840
841 }
842
843 return true;
844 }
845
test_enumeration(struct torture_context * tctx)846 static bool test_enumeration(struct torture_context *tctx)
847 {
848 const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
849 const char *old_group = getenv("NSS_WRAPPER_GROUP");
850
851 if (!old_pwd || !old_group) {
852 torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
853 torture_skip(tctx, "nothing to test\n");
854 }
855
856 torture_assert(tctx, test_passwd(tctx),
857 "failed to test users");
858 torture_assert(tctx, test_group(tctx),
859 "failed to test groups");
860
861 return true;
862 }
863
test_reentrant_enumeration(struct torture_context * tctx)864 static bool test_reentrant_enumeration(struct torture_context *tctx)
865 {
866 const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
867 const char *old_group = getenv("NSS_WRAPPER_GROUP");
868
869 if (!old_pwd || !old_group) {
870 torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
871 torture_skip(tctx, "nothing to test\n");
872 }
873
874 torture_comment(tctx, "Testing re-entrant calls\n");
875
876 torture_assert(tctx, test_passwd_r(tctx),
877 "failed to test users");
878 torture_assert(tctx, test_group_r(tctx),
879 "failed to test groups");
880
881 return true;
882 }
883
test_reentrant_enumeration_crosschecks(struct torture_context * tctx)884 static bool test_reentrant_enumeration_crosschecks(struct torture_context *tctx)
885 {
886 const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
887 const char *old_group = getenv("NSS_WRAPPER_GROUP");
888
889 if (!old_pwd || !old_group) {
890 torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
891 torture_skip(tctx, "nothing to test\n");
892 }
893
894 torture_comment(tctx, "Testing re-entrant calls with cross checks\n");
895
896 torture_assert(tctx, test_passwd_r_cross(tctx),
897 "failed to test users");
898 torture_assert(tctx, test_group_r_cross(tctx),
899 "failed to test groups");
900
901 return true;
902 }
903
test_passwd_duplicates(struct torture_context * tctx)904 static bool test_passwd_duplicates(struct torture_context *tctx)
905 {
906 size_t i, d;
907 struct passwd *pwd;
908 size_t num_pwd;
909 int duplicates = 0;
910
911 torture_assert(tctx, test_enum_passwd(tctx, &pwd, &num_pwd),
912 "failed to enumerate passwd");
913
914 for (i=0; i < num_pwd; i++) {
915 const char *current_name = pwd[i].pw_name;
916 for (d=0; d < num_pwd; d++) {
917 const char *dup_name = pwd[d].pw_name;
918 if (d == i) {
919 continue;
920 }
921 if (!strequal(current_name, dup_name)) {
922 continue;
923 }
924
925 torture_warning(tctx, "found duplicate names:");
926 print_passwd(&pwd[d]);
927 print_passwd(&pwd[i]);
928 duplicates++;
929 }
930 }
931
932 if (duplicates) {
933 torture_fail(tctx, talloc_asprintf(tctx, "found %d duplicate names", duplicates));
934 }
935
936 return true;
937 }
938
test_group_duplicates(struct torture_context * tctx)939 static bool test_group_duplicates(struct torture_context *tctx)
940 {
941 size_t i, d;
942 struct group *grp;
943 size_t num_grp;
944 int duplicates = 0;
945
946 torture_assert(tctx, test_enum_group(tctx, &grp, &num_grp),
947 "failed to enumerate group");
948
949 for (i=0; i < num_grp; i++) {
950 const char *current_name = grp[i].gr_name;
951 for (d=0; d < num_grp; d++) {
952 const char *dup_name = grp[d].gr_name;
953 if (d == i) {
954 continue;
955 }
956 if (!strequal(current_name, dup_name)) {
957 continue;
958 }
959
960 torture_warning(tctx, "found duplicate names:");
961 print_group(&grp[d]);
962 print_group(&grp[i]);
963 duplicates++;
964 }
965 }
966
967 if (duplicates) {
968 torture_fail(tctx, talloc_asprintf(tctx, "found %d duplicate names", duplicates));
969 }
970
971 return true;
972 }
973
974
test_duplicates(struct torture_context * tctx)975 static bool test_duplicates(struct torture_context *tctx)
976 {
977 const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
978 const char *old_group = getenv("NSS_WRAPPER_GROUP");
979
980 if (!old_pwd || !old_group) {
981 torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
982 torture_skip(tctx, "nothing to test\n");
983 }
984
985 torture_assert(tctx, test_passwd_duplicates(tctx),
986 "failed to test users");
987 torture_assert(tctx, test_group_duplicates(tctx),
988 "failed to test groups");
989
990 return true;
991 }
992
993
torture_local_nss(TALLOC_CTX * mem_ctx)994 struct torture_suite *torture_local_nss(TALLOC_CTX *mem_ctx)
995 {
996 struct torture_suite *suite = torture_suite_create(mem_ctx, "nss");
997
998 torture_suite_add_simple_test(suite, "enumeration", test_enumeration);
999 torture_suite_add_simple_test(suite, "reentrant enumeration", test_reentrant_enumeration);
1000 torture_suite_add_simple_test(suite, "reentrant enumeration crosschecks", test_reentrant_enumeration_crosschecks);
1001 torture_suite_add_simple_test(suite, "membership", test_membership);
1002 torture_suite_add_simple_test(suite, "duplicates", test_duplicates);
1003
1004 return suite;
1005 }
1006