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