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