test structure too
[tridge/junkcode.git] / uess_test.c
1 /*
2   a simple UESS test harness for AIX
3
4   Andrew Tridgell <tridge@au.ibm.com> 
5   January 2004
6
7
8   Usage:
9       uess_test <MODULE_NAME> <nloops>
10
11   for example "uess_test LDAP" will load the LDAP module using methods.cfg
12   and will call directly into the supplied methods
13
14   If nloops is not supplied then 1 is assumed. Note that the built-in
15   memory leak checking can only be performed with nloops > 1
16
17
18   You can force uess_test not to free the gr_passwd entry in struct group by setting the
19   environment variable "DONT_FREE_GR_PASSWD". This is needed for the AIX 5.2 LDAP module,
20   as it incorrectly returns a constant string in that field.
21
22
23   I also strongly recommend you run this test program with the following malloc debug options set:
24
25     MALLOCDEBUG=validate_ptrs,report_allocations,record_allocations
26     MALLOCTYPE=debug
27
28
29   Thanks to Julianne Haugh for assistance in understanding the UESS interface.
30
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <pwd.h>
36 #include <grp.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <usersec.h>
41 #include <malloc.h>
42
43
44 static struct secmethod_table *methods;
45 static int err_count;
46
47 #define INVALID_STRING "INVALID"
48 #define INVALID_INT    123456
49
50 /*
51   test method_attrlist 
52  */
53 static void test_attrlist(void)
54 {
55         attrlist_t **a;
56         int i;
57
58         if (!methods->method_attrlist) {
59                 printf("WARNING: module has no method_attrlist\n");
60                 return;
61         }
62
63         printf("\ntesting method_attrlist\n");
64
65         a = methods->method_attrlist();
66         if (!a) {
67                 printf("ERROR: attrlist failed - %s\n", strerror(errno));
68                 err_count++;
69                 return;
70         }
71
72         for (i=0;a[i];i++) {
73                 printf("\tattrib '%s' flags=0x%x type=%d\n", 
74                        a[i]->al_name, a[i]->al_flags, a[i]->al_type);
75                 free(a[i]->al_name);
76         }
77         free(a);
78 }
79
80
81 /*
82   test listing users
83 */
84 static void test_userlist(void)
85 {
86         int ret;
87         attrval_t a;
88         char *attribs = "users";
89         char *s;
90
91         if (!methods->method_getentry) {
92                 printf("WARNING: module has no method_getentry\n");
93                 return;
94         }
95
96         printf("\ntesting method_getentry(ALL, user)\n");
97
98         ret = methods->method_getentry("ALL", "user", &attribs, &a, 1);
99         if (ret != 0) {
100                 printf("ERROR: method_getentry failed ret=%d - %s\n", ret, strerror(errno));
101                 err_count++;
102                 return;
103         }
104
105         printf("\tattr_flag=%d ptr=%p\n", a.attr_flag, a.attr_un.au_char);
106         for (s=a.attr_un.au_char; s && *s; s += strlen(s) + 1) {
107                 printf("\t'%s'\n", s);
108         }
109
110         free(a.attr_un.au_char);
111
112         /* try an invalid table */
113         printf("Trying an invalid table\n");
114         ret = methods->method_getentry("ALL", INVALID_STRING, &attribs, &a, 1);
115         if (ret == 0 || errno != ENOSYS) {              
116                 printf("ERROR: method_getentry expected\n\t%d/%s\n", -1, strerror(ENOSYS));
117                 printf("got\t%d/%s\n", ret, strerror(errno));
118                 err_count++;
119         }
120
121         printf("Trying an invalid user\n");
122         ret = methods->method_getentry(INVALID_STRING, "user", &attribs, &a, 1);
123         if (ret == 0 || errno != ENOENT) {              
124                 printf("ERROR: method_getentry expected\n\t%d/%s\n", -1, strerror(ENOENT));
125                 printf("got\t%d/%s\n", ret, strerror(errno));
126                 err_count++;
127         }
128         
129 }
130
131 /*
132   test listing groups
133 */
134 static void test_grouplist(void)
135 {
136         int ret;
137         attrval_t a;
138         char *attribs = "groups";
139         char *s;
140
141         if (!methods->method_getentry) {
142                 printf("WARNING: module has no method_getentry\n");
143                 return;
144         }
145
146         printf("\ntesting method_getentry(ALL, group)\n");
147
148         ret = methods->method_getentry("ALL", "group", &attribs, &a, 1);
149         if (ret != 0) {
150                 printf("ERROR: method_getentry failed ret=%d - %s\n", ret, strerror(errno));
151                 err_count++;
152                 return;
153         }
154
155         printf("\tattr_flag=%d ptr=%p\n", a.attr_flag, a.attr_un.au_char);
156         for (s=a.attr_un.au_char; s && *s; s += strlen(s) + 1) {
157                 printf("\t'%s'\n", s);
158         }
159
160         free(a.attr_un.au_char);
161
162
163         printf("Trying an invalid group\n");
164         ret = methods->method_getentry(INVALID_STRING, "group", &attribs, &a, 1);
165         if (ret == 0 || errno != ENOENT) {              
166                 printf("ERROR: method_getentry expected\n\t%d/%s\n", -1, strerror(ENOENT));
167                 printf("got\t%d/%s\n", ret, strerror(errno));
168                 err_count++;
169         }
170 }
171
172
173 static void show_pwd(struct passwd *pwd)
174 {
175         printf("\t%s:%s:%d:%d:%s:%s:%s\n", 
176                pwd->pw_name,
177                pwd->pw_passwd,
178                pwd->pw_uid,
179                pwd->pw_gid,
180                pwd->pw_gecos,
181                pwd->pw_dir,
182                pwd->pw_shell);
183 }
184
185 static void free_pwd(struct passwd *pwd)
186 {
187         free(pwd->pw_name);
188         free(pwd->pw_passwd);
189         free(pwd->pw_gecos);
190         free(pwd->pw_dir);
191         free(pwd->pw_shell);
192         free(pwd);
193 }
194
195
196 static void show_grp(struct group *grp)
197 {
198         int i;
199
200         printf("\t%s:%s:%d: ", 
201                grp->gr_name,
202                grp->gr_passwd,
203                grp->gr_gid);
204         
205         if (!grp->gr_mem[0]) {
206                 printf("\n");
207                 return;
208         }
209         
210         for (i=0; grp->gr_mem[i+1]; i++) {
211                 printf("%s, ", grp->gr_mem[i]);
212         }
213         printf("%s\n", grp->gr_mem[i]);
214 }
215
216 static void free_grp(struct group *grp)
217 {
218         int i;
219
220         free(grp->gr_name);
221         if (!getenv("DONT_FREE_GR_PASSWD")) {
222                 free(grp->gr_passwd);
223         }
224         
225         if (!grp->gr_mem) {
226                 free(grp);
227                 return;
228         }
229         
230         for (i=0; grp->gr_mem[i]; i++) {
231                 free(grp->gr_mem[i]);
232         }
233
234         free(grp->gr_mem);
235         free(grp);
236 }
237
238
239 /*
240   test method_getpwnam
241 */
242 static void test_getpwnam(char *name)
243 {
244         struct passwd *pwd;
245
246         printf("\ntesting method_getpwnam for user '%s'\n", name);
247
248         pwd = methods->method_getpwnam(name);
249
250         if (strcmp(name, INVALID_STRING) == 0) {
251                 if (pwd || errno != ENOENT) {
252                         printf("ERROR: method_getpwnam expected\n\t%p/%s\n", 0, strerror(ENOENT));
253                         printf("got\t%p/%s\n", pwd, strerror(errno));
254                         err_count++;
255                 }
256                 return;
257         }
258         
259         if (!pwd) {
260                 printf("ERROR: method_getpwnam failed - %s\n", strerror(errno));
261                 err_count++;
262                 return;
263         }
264
265         show_pwd(pwd);
266         free_pwd(pwd);
267 }
268
269 /*
270   test method_getpwuid
271 */
272 static void test_getpwuid(int uid)
273 {
274         struct passwd *pwd;
275
276         printf("\ntesting method_getpwuid for uid %d\n", uid);
277
278         pwd = methods->method_getpwuid(uid);
279
280         if (uid == INVALID_INT) {
281                 if (pwd || errno != ENOENT) {
282                         printf("ERROR: method_getpwuid expected\n\t%p/%s\n", 0, strerror(ENOENT));
283                         printf("got\t%p/%s\n", pwd, strerror(errno));
284                         err_count++;
285                 }
286                 return;
287         }       
288
289         if (!pwd) {
290                 printf("ERROR: method_getpwuid failed - %s\n", strerror(errno));
291                 err_count++;
292                 return;
293         }
294
295         show_pwd(pwd);
296         free_pwd(pwd);
297 }
298
299
300 /*
301   test method_getgrnam
302 */
303 static void test_getgrnam(char *name)
304 {
305         struct group *grp;
306
307         printf("\ntesting method_getgrnam for group '%s'\n", name);
308
309         grp = methods->method_getgrnam(name);
310         if (strcmp(name, INVALID_STRING) == 0) {
311                 if (grp || errno != ENOENT) {
312                         printf("ERROR: method_getgrnam expected\n\t%p/%s\n", 0, strerror(ENOENT));
313                         printf("got\t%p/%s\n", grp, strerror(errno));
314                         err_count++;
315                 }
316                 return;
317         }
318
319
320         if (!grp) {
321                 printf("ERROR: method_getgrnam failed - %s\n", strerror(errno));
322                 err_count++;
323                 return;
324         }
325
326         show_grp(grp);
327         free_grp(grp);
328 }
329
330 /*
331   test method_getgracct
332 */
333 static void test_getgracct(char *name)
334 {
335         struct group *grp;
336         int gid;
337
338         printf("\ntesting method_getgracct for group '%s'\n", name);
339
340         grp = methods->method_getgracct((void *)name, 1);
341
342         if (strcmp(name, INVALID_STRING) == 0) {
343                 if (grp || errno != ENOENT) {
344                         printf("ERROR: method_getgracct expected\n\t%p/%s\n", 0, strerror(ENOENT));
345                         printf("got\t%p/%s\n", grp, strerror(errno));
346                         err_count++;
347                 }
348                 return;
349         }
350
351         if (!grp) {
352                 printf("ERROR: method_getgracct(name, 1) failed - %s\n", strerror(errno));
353                 err_count++;
354                 return;
355         }
356
357         gid = grp->gr_gid;
358         show_grp(grp);
359         free_grp(grp);
360
361         grp = methods->method_getgracct((void *)&gid, 0);
362         if (!grp) {
363                 printf("ERROR: method_getgracct(gid, 0) failed - %s\n", strerror(errno));
364                 err_count++;
365                 return;
366         }
367
368         show_grp(grp);
369         free_grp(grp);
370 }
371
372 /*
373   test method_getgrset
374 */
375 static void test_getgrset(char *name)
376 {
377         char *grps;
378
379         printf("\ntesting method_getgrset for user '%s'\n", name);
380
381         grps = methods->method_getgrset(name);
382
383         if (strcmp(name, INVALID_STRING) == 0) {
384                 if (grps || errno != ENOENT) {
385                         printf("ERROR: method_getgrset expected\n\t%p/%s\n", 0, strerror(ENOENT));
386                         printf("got\t%p/%s\n", grps, strerror(errno));
387                         err_count++;
388                 }
389                 return;
390         }
391
392         if (!grps) {
393                 printf("ERROR: method_getgrset failed - %s\n", strerror(errno));
394                 err_count++;
395                 return;
396         }
397
398         printf("\t%s\n", grps);
399
400         free(grps);
401 }
402
403 /*
404   test method_normalize
405 */
406 static void test_normalize(char *name)
407 {
408         int ret;
409         char shortname[S_NAMELEN];
410
411         printf("\ntesting method_normalize for user '%s' (namelen=%d)\n", 
412                name, S_NAMELEN);
413
414         ret = methods->method_normalize(name, shortname);
415
416         if (strcmp(name, INVALID_STRING) == 0) {
417                 /* there seems to be no defined behaviour for this?! */
418                 return;
419         }
420
421         if (ret == 0) {
422                 printf("ERROR: method_normalize failed - %s\n", strerror(errno));
423                 err_count++;
424                 return;
425         }
426
427         printf("\t%s\n", shortname);
428 }
429
430 /*
431   test method_getgrgid
432 */
433 static void test_getgrgid(int gid)
434 {
435         struct group *grp;
436
437         printf("\ntesting method_getgrgid for gid %d\n", gid);
438
439         grp = methods->method_getgrgid(gid);
440         if (gid == INVALID_INT) {
441                 if (grp || errno != ENOENT) {
442                         printf("ERROR: method_getgrgid expected\n\t%p/%s\n", 0, strerror(ENOENT));
443                         printf("got\t%p/%s\n", grp, strerror(errno));
444                         err_count++;
445                 }
446                 return;
447         }
448
449         if (!grp) {
450                 printf("ERROR: method_getgrgid failed - %s\n", strerror(errno));
451                 err_count++;
452                 return;
453         }
454
455         show_grp(grp);
456         free_grp(grp);
457 }
458
459
460 /*
461   loop over all users
462 */
463 static void forallusers(void (*fn)(char *name))
464 {
465         int ret;
466         attrval_t a;
467         char *attribs = "users";
468         char *s;
469
470         if (!methods->method_getentry) {
471                 return;
472         }
473         ret = methods->method_getentry("ALL", "user", &attribs, &a, 1);
474         if (ret != 0) {
475                 return;
476         }
477         for (s=a.attr_un.au_char; s && *s; s += strlen(s) + 1) {
478                 fn(s);
479         }
480
481         free(a.attr_un.au_char);
482
483         fn(INVALID_STRING);
484 }
485
486
487 /*
488   loop over all groups
489 */
490 static void forallgroups(void (*fn)(char *name))
491 {
492         int ret;
493         attrval_t a;
494         char *attribs = "groups";
495         char *s;
496
497         if (!methods->method_getentry) {
498                 return;
499         }
500         ret = methods->method_getentry("ALL", "group", &attribs, &a, 1);
501         if (ret != 0) {
502                 return;
503         }
504         for (s=a.attr_un.au_char; s && *s; s += strlen(s) + 1) {
505                 fn(s);
506         }
507
508         free(a.attr_un.au_char);
509
510         fn(INVALID_STRING);
511 }
512
513 /*
514   loop over all uids
515 */
516 static void foralluids(void (*fn)(int uid))
517 {
518         int ret;
519         attrval_t a;
520         char *attribs = "users";
521         char *s;
522
523         if (!methods->method_getentry) {
524                 return;
525         }
526         ret = methods->method_getentry("ALL", "user", &attribs, &a, 1);
527         if (ret != 0) {
528                 return;
529         }
530         for (s=a.attr_un.au_char; s && *s; s += strlen(s) + 1) {
531                 attrval_t a2;
532                 char *id_attribs = S_ID;
533                 ret = methods->method_getentry(s, "user", &id_attribs, &a2, 1);
534                 if (ret != 0) {
535                         printf("ERROR: failed to get S_ID for '%s' - ret=%d - %s\n", 
536                                s, ret, strerror(errno));
537                         err_count++;
538                 }
539                 fn(a2.attr_un.au_int);
540         }
541
542         free(a.attr_un.au_char);
543
544         fn(INVALID_INT);
545 }
546
547 /*
548   loop over all gids
549 */
550 static void forallgids(void (*fn)(int gid))
551 {
552         int ret;
553         attrval_t a;
554         char *attribs = "groups";
555         char *s;
556
557         if (!methods->method_getentry) {
558                 return;
559         }
560         ret = methods->method_getentry("ALL", "group", &attribs, &a, 1);
561         if (ret != 0) {
562                 return;
563         }
564         for (s=a.attr_un.au_char; s && *s; s += strlen(s) + 1) {
565                 attrval_t a2;
566                 char *id_attribs = S_ID;
567                 ret = methods->method_getentry(s, "group", &id_attribs, &a2, 1);
568                 if (ret != 0) {
569                         printf("ERROR: failed to get S_ID for '%s' - ret=%d - %s\n", 
570                                s, ret, strerror(errno));
571                         err_count++;
572                 }
573                 fn(a2.attr_un.au_int);
574         }
575
576         free(a.attr_un.au_char);
577
578         fn(INVALID_INT);
579 }
580
581
582 /*
583   the main test harness 
584 */
585 static void uess_test(void)
586 {
587         test_attrlist();
588
589         test_userlist();
590
591         test_grouplist();
592
593         if (methods->method_getpwnam) {
594                 forallusers(test_getpwnam);
595         }
596         if (methods->method_getpwuid) {
597                 foralluids(test_getpwuid);
598         }
599         if (methods->method_getgrset) {
600                 forallusers(test_getgrset);
601         }
602         if (methods->method_normalize) {
603                 forallusers(test_normalize);
604         }
605         if (methods->method_getgrnam) {
606                 forallgroups(test_getgrnam);
607         }
608         if (methods->method_getgracct) {
609                 forallgroups(test_getgracct);
610         }
611         if (methods->method_getgrgid) {
612                 forallgids(test_getgrgid);
613         }
614 }
615
616
617 /*
618   return the current size of the heap (in blocks)
619 */
620 static unsigned long heap_size(void)
621 {
622         struct mallinfo m = mallinfo();
623         return m.ordblks + m.smblks;
624 }
625
626
627 struct secmethod_desc {
628         char *name;
629         char *module_path;
630         struct secmethod_table *methods;
631 };
632
633 extern struct secmethod_desc *_load_secmethod(const char *name);
634
635 int main(int argc, const char *argv[])
636 {
637         const char *name;
638         struct secmethod_desc *r;
639         int i, nloops = 1;
640         unsigned long prev_alloc = 0;
641
642         if (argc < 2) {
643                 printf("Usage: uess_test <MODULE_NAME> <nloops>\n");
644                 exit(1);
645         }
646
647         name = argv[1];
648
649         if (argc > 2) {
650                 nloops = atoi(argv[2]);
651         }
652
653         errno = 0;
654
655         r = _load_secmethod(name);
656
657         if (!r) {
658                 printf("Unable to load module '%s'\n", name);
659                 exit(1);
660         }
661
662         printf("Loaded '%s' with path '%s'\n", r->name, r->module_path);
663         printf("method_version=%d\n", r->methods->method_version);
664
665         methods = r->methods;
666
667         for (i=0;i<nloops; i++) {
668                 unsigned long hsize;
669
670                 printf("Test loop %d\n", i);
671
672                 uess_test();
673
674                 hsize = heap_size();
675
676                 if (prev_alloc && hsize > prev_alloc) {
677                         printf("ERROR: heap grew by %d blocks. Probable memory leak\n", 
678                                hsize - prev_alloc);
679                         err_count++;
680                 }
681                 prev_alloc = hsize;
682         }
683
684         if (err_count != 0) {
685                 printf("WARNING: %d errors detected\n", err_count);
686         }
687
688         return err_count;
689 }