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