nss_wrapper: add tests for getpwent_r to testsuite.
[abartlet/samba.git/.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_getgrgid(struct torture_context *tctx,
210                                 gid_t gid,
211                                 struct group *grp_p)
212 {
213         struct group *grp;
214
215         torture_comment(tctx, "Testing getgrgid: %lu\n", (unsigned long)gid);
216
217         grp = getgrgid(gid);
218         if (grp) {
219                 print_group(grp);
220         }
221
222         if (grp_p) {
223                 copy_group(tctx, grp, grp_p);
224         }
225
226         return grp ? true : false;
227 }
228
229 static bool test_nwrap_enum_passwd(struct torture_context *tctx,
230                                    struct passwd **pwd_array_p,
231                                    size_t *num_pwd_p)
232 {
233         struct passwd *pwd;
234         struct passwd *pwd_array = NULL;
235         size_t num_pwd = 0;
236
237         torture_comment(tctx, "Testing setpwent\n");
238         setpwent();
239
240         while ((pwd = getpwent()) != NULL) {
241                 torture_comment(tctx, "Testing getpwent\n");
242
243                 print_passwd(pwd);
244                 if (pwd_array_p && num_pwd_p) {
245                         pwd_array = talloc_realloc(tctx, pwd_array, struct passwd, num_pwd+1);
246                         torture_assert(tctx, pwd_array, "out of memory");
247                         copy_passwd(tctx, pwd, &pwd_array[num_pwd]);
248                         num_pwd++;
249                 }
250         }
251
252         torture_comment(tctx, "Testing endpwent\n");
253         endpwent();
254
255         if (pwd_array_p) {
256                 *pwd_array_p = pwd_array;
257         }
258         if (num_pwd_p) {
259                 *num_pwd_p = num_pwd;
260         }
261
262         return true;
263 }
264
265 static bool test_nwrap_enum_r_passwd(struct torture_context *tctx,
266                                      struct passwd **pwd_array_p,
267                                      size_t *num_pwd_p)
268 {
269         struct passwd pwd, *pwdp;
270         struct passwd *pwd_array = NULL;
271         size_t num_pwd = 0;
272         char buffer[4096];
273         int ret;
274
275         torture_comment(tctx, "Testing setpwent\n");
276         setpwent();
277
278         while (1) {
279                 torture_comment(tctx, "Testing getpwent_r\n");
280
281                 ret = getpwent_r(&pwd, buffer, sizeof(buffer), &pwdp);
282                 if (ret != 0) {
283                         if (ret != ENOENT) {
284                                 torture_comment(tctx, "got %d return code\n", ret);
285                         }
286                         break;
287                 }
288                 print_passwd(&pwd);
289                 if (pwd_array_p && num_pwd_p) {
290                         pwd_array = talloc_realloc(tctx, pwd_array, struct passwd, num_pwd+1);
291                         torture_assert(tctx, pwd_array, "out of memory");
292                         copy_passwd(tctx, &pwd, &pwd_array[num_pwd]);
293                         num_pwd++;
294                 }
295         }
296
297         torture_comment(tctx, "Testing endpwent\n");
298         endpwent();
299
300         if (pwd_array_p) {
301                 *pwd_array_p = pwd_array;
302         }
303         if (num_pwd_p) {
304                 *num_pwd_p = num_pwd;
305         }
306
307         return true;
308 }
309
310 static bool torture_assert_passwd_equal(struct torture_context *tctx,
311                                         const struct passwd *p1,
312                                         const struct passwd *p2,
313                                         const char *comment)
314 {
315         torture_assert_str_equal(tctx, p1->pw_name, p2->pw_name, comment);
316         torture_assert_str_equal(tctx, p1->pw_passwd, p2->pw_passwd, comment);
317         torture_assert_int_equal(tctx, p1->pw_uid, p2->pw_uid, comment);
318         torture_assert_int_equal(tctx, p1->pw_gid, p2->pw_gid, comment);
319         torture_assert_str_equal(tctx, p1->pw_gecos, p2->pw_gecos, comment);
320         torture_assert_str_equal(tctx, p1->pw_dir, p2->pw_dir, comment);
321         torture_assert_str_equal(tctx, p1->pw_shell, p2->pw_shell, comment);
322
323         return true;
324 }
325
326 static bool test_nwrap_passwd(struct torture_context *tctx)
327 {
328         int i;
329         struct passwd *pwd, pwd1, pwd2;
330         size_t num_pwd;
331
332         torture_assert(tctx, test_nwrap_enum_passwd(tctx, &pwd, &num_pwd),
333                                                     "failed to enumerate passwd");
334
335         for (i=0; i < num_pwd; i++) {
336                 torture_assert(tctx, test_nwrap_getpwnam(tctx, pwd[i].pw_name, &pwd1),
337                         "failed to call getpwnam for enumerated user");
338                 torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
339                         "getpwent and getpwnam gave different results");
340                 torture_assert(tctx, test_nwrap_getpwuid(tctx, pwd[i].pw_uid, &pwd2),
341                         "failed to call getpwuid for enumerated user");
342                 torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
343                         "getpwent and getpwuid gave different results");
344                 torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
345                         "getpwnam and getpwuid gave different results");
346         }
347
348         return true;
349 }
350
351 static bool test_nwrap_passwd_r(struct torture_context *tctx)
352 {
353         int i;
354         struct passwd *pwd, pwd1, pwd2;
355         size_t num_pwd;
356
357         torture_assert(tctx, test_nwrap_enum_r_passwd(tctx, &pwd, &num_pwd),
358                                                       "failed to enumerate passwd");
359
360         for (i=0; i < num_pwd; i++) {
361                 torture_assert(tctx, test_nwrap_getpwnam_r(tctx, pwd[i].pw_name, &pwd1),
362                         "failed to call getpwnam_r for enumerated user");
363                 torture_assert(tctx, test_nwrap_getpwuid_r(tctx, pwd[i].pw_uid, &pwd2),
364                         "failed to call getpwuid_r for enumerated user");
365                 torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
366                         "getpwnam_r and getpwuid_r gave different results");
367         }
368
369         return true;
370 }
371
372 static bool test_nwrap_enum_group(struct torture_context *tctx,
373                                   struct group **grp_array_p,
374                                   size_t *num_grp_p)
375 {
376         struct group *grp;
377         struct group *grp_array = NULL;
378         size_t num_grp = 0;
379
380         torture_comment(tctx, "Testing setgrent\n");
381         setgrent();
382
383         while ((grp = getgrent()) != NULL) {
384                 torture_comment(tctx, "Testing getgrent\n");
385
386                 print_group(grp);
387                 if (grp_array_p && num_grp_p) {
388                         grp_array = talloc_realloc(tctx, grp_array, struct group, num_grp+1);
389                         torture_assert(tctx, grp_array, "out of memory");
390                         copy_group(tctx, grp, &grp_array[num_grp]);
391                         num_grp++;
392                 }
393         }
394
395         torture_comment(tctx, "Testing endgrent\n");
396         endgrent();
397
398         if (grp_array_p) {
399                 *grp_array_p = grp_array;
400         }
401         if (num_grp_p) {
402                 *num_grp_p = num_grp;
403         }
404
405         return true;
406 }
407
408 static bool torture_assert_group_equal(struct torture_context *tctx,
409                                        const struct group *g1,
410                                        const struct group *g2,
411                                        const char *comment)
412 {
413         int i;
414         torture_assert_str_equal(tctx, g1->gr_name, g2->gr_name, comment);
415         torture_assert_str_equal(tctx, g1->gr_passwd, g2->gr_passwd, comment);
416         torture_assert_int_equal(tctx, g1->gr_gid, g2->gr_gid, comment);
417         if (g1->gr_mem && !g2->gr_mem) {
418                 return false;
419         }
420         if (!g1->gr_mem && g2->gr_mem) {
421                 return false;
422         }
423         if (!g1->gr_mem && !g2->gr_mem) {
424                 return true;
425         }
426         for (i=0; g1->gr_mem[i] && g2->gr_mem[i]; i++) {
427                 torture_assert_str_equal(tctx, g1->gr_mem[i], g2->gr_mem[i], comment);
428         }
429
430         return true;
431 }
432
433 static bool test_nwrap_group(struct torture_context *tctx)
434 {
435         int i;
436         struct group *grp, grp1, grp2;
437         size_t num_grp;
438
439         torture_assert(tctx, test_nwrap_enum_group(tctx, &grp, &num_grp),
440                                                    "failed to enumerate group");
441
442         for (i=0; i < num_grp; i++) {
443                 torture_assert(tctx, test_nwrap_getgrnam(tctx, grp[i].gr_name, &grp1),
444                         "failed to call getgrnam for enumerated user");
445                 torture_assert_group_equal(tctx, &grp[i], &grp1,
446                         "getgrent and getgrnam gave different results");
447                 torture_assert(tctx, test_nwrap_getgrgid(tctx, grp[i].gr_gid, &grp2),
448                         "failed to call getgrgid for enumerated user");
449                 torture_assert_group_equal(tctx, &grp[i], &grp2,
450                         "getgrent and getgruid gave different results");
451                 torture_assert_group_equal(tctx, &grp1, &grp2,
452                         "getgrnam and getgrgid gave different results");
453         }
454
455         return true;
456 }
457
458 static bool test_nwrap_getgrouplist(struct torture_context *tctx,
459                                     const char *user,
460                                     gid_t gid,
461                                     gid_t **gids_p,
462                                     int *num_gids_p)
463 {
464         int ret;
465         int num_groups = 0;
466         gid_t *groups = NULL;
467
468         torture_comment(tctx, "Testing getgrouplist: %s\n", user);
469
470         ret = getgrouplist(user, gid, NULL, &num_groups);
471         if (ret == -1 || num_groups != 0) {
472
473                 groups = talloc_array(tctx, gid_t, num_groups);
474                 torture_assert(tctx, groups, "out of memory\n");
475
476                 ret = getgrouplist(user, gid, groups, &num_groups);
477         }
478
479         torture_assert(tctx, (ret != -1), "failed to call getgrouplist");
480
481         torture_comment(tctx, "%s is member in %d groups\n", user, num_groups);
482
483         if (gids_p) {
484                 *gids_p = groups;
485         }
486         if (num_gids_p) {
487                 *num_gids_p = num_groups;
488         }
489
490         return true;
491 }
492
493 static bool test_nwrap_user_in_group(struct torture_context *tctx,
494                                      const struct passwd *pwd,
495                                      const struct group *grp)
496 {
497         int i;
498
499         for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
500                 if (strequal(grp->gr_mem[i], pwd->pw_name)) {
501                         return true;
502                 }
503         }
504
505         return false;
506 }
507
508 static bool test_nwrap_membership_user(struct torture_context *tctx,
509                                        const struct passwd *pwd,
510                                        struct group *grp_array,
511                                        size_t num_grp)
512 {
513         int num_user_groups = 0;
514         int num_user_groups_from_enum = 0;
515         gid_t *user_groups = NULL;
516         int g, i;
517         bool primary_group_had_user_member = false;
518
519         torture_assert(tctx, test_nwrap_getgrouplist(tctx,
520                                                      pwd->pw_name,
521                                                      pwd->pw_gid,
522                                                      &user_groups,
523                                                      &num_user_groups),
524                                                      "failed to test getgrouplist");
525
526         for (g=0; g < num_user_groups; g++) {
527                 torture_assert(tctx, test_nwrap_getgrgid(tctx, user_groups[g], NULL),
528                         "failed to find the group the user is a member of");
529         }
530
531
532         for (i=0; i < num_grp; i++) {
533
534                 struct group grp = grp_array[i];
535
536                 if (test_nwrap_user_in_group(tctx, pwd, &grp)) {
537
538                         struct group current_grp;
539                         num_user_groups_from_enum++;
540
541                         torture_assert(tctx, test_nwrap_getgrnam(tctx, grp.gr_name, &current_grp),
542                                         "failed to find the group the user is a member of");
543
544                         if (current_grp.gr_gid == pwd->pw_gid) {
545                                 torture_comment(tctx, "primary group %s of user %s lists user as member\n",
546                                                 current_grp.gr_name,
547                                                 pwd->pw_name);
548                                 primary_group_had_user_member = true;
549                         }
550
551                         continue;
552                 }
553         }
554
555         if (!primary_group_had_user_member) {
556                 num_user_groups_from_enum++;
557         }
558
559         torture_assert_int_equal(tctx, num_user_groups, num_user_groups_from_enum,
560                 "getgrouplist and real inspection of grouplist gave different results\n");
561
562         return true;
563 }
564
565 static bool test_nwrap_membership(struct torture_context *tctx)
566 {
567         const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
568         const char *old_group = getenv("NSS_WRAPPER_GROUP");
569         struct passwd *pwd;
570         size_t num_pwd;
571         struct group *grp;
572         size_t num_grp;
573         int i;
574
575         if (!old_pwd || !old_group) {
576                 torture_skip(tctx, "nothing to test\n");
577                 return true;
578         }
579
580         torture_assert(tctx, test_nwrap_enum_passwd(tctx, &pwd, &num_pwd),
581                                                     "failed to enumerate passwd");
582         torture_assert(tctx, test_nwrap_enum_group(tctx, &grp, &num_grp),
583                                                     "failed to enumerate group");
584
585         for (i=0; i < num_pwd; i++) {
586
587                 torture_assert(tctx, test_nwrap_membership_user(tctx, &pwd[i], grp, num_grp),
588                         "failed to test membership for user");
589
590         }
591
592         return true;
593 }
594
595 static bool test_nwrap_enumeration(struct torture_context *tctx)
596 {
597         const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
598         const char *old_group = getenv("NSS_WRAPPER_GROUP");
599
600         if (!old_pwd || !old_group) {
601                 torture_skip(tctx, "nothing to test\n");
602                 return true;
603         }
604
605         torture_assert(tctx, test_nwrap_passwd(tctx),
606                         "failed to test users");
607         torture_assert(tctx, test_nwrap_group(tctx),
608                         "failed to test groups");
609
610         return true;
611 }
612
613 static bool test_nwrap_reentrant_enumeration(struct torture_context *tctx)
614 {
615         const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
616         const char *old_group = getenv("NSS_WRAPPER_GROUP");
617
618         if (!old_pwd || !old_group) {
619                 torture_skip(tctx, "nothing to test\n");
620                 return true;
621         }
622
623         torture_comment(tctx, "Testing re-entrant calls\n");
624
625         torture_assert(tctx, test_nwrap_passwd_r(tctx),
626                         "failed to test users");
627
628         return true;
629 }
630
631
632 struct torture_suite *torture_local_nss_wrapper(TALLOC_CTX *mem_ctx)
633 {
634         struct torture_suite *suite = torture_suite_create(mem_ctx, "NSS-WRAPPER");
635
636         torture_suite_add_simple_test(suite, "enumeration", test_nwrap_enumeration);
637         torture_suite_add_simple_test(suite, "reentrant enumeration", test_nwrap_reentrant_enumeration);
638         torture_suite_add_simple_test(suite, "membership", test_nwrap_membership);
639
640         return suite;
641 }