r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[abartlet/samba.git/.git] / source3 / torture / nsstest.c
1 /* 
2    Unix SMB/CIFS implementation.
3    nss tester for winbindd
4    Copyright (C) Andrew Tridgell 2001
5    Copyright (C) Tim Potter 2003
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23 static const char *so_path = "/lib/libnss_winbind.so";
24 static const char *nss_name = "winbind";
25 static int nss_errno;
26 static NSS_STATUS last_error;
27 static int total_errors;
28
29 static void *find_fn(const char *name)
30 {
31         pstring s;
32         static void *h;
33         void *res;
34
35         pstr_sprintf(s, "_nss_%s_%s", nss_name, name);
36
37         if (!h) {
38                 h = sys_dlopen(so_path, RTLD_LAZY);
39         }
40         if (!h) {
41                 printf("Can't open shared library %s\n", so_path);
42                 exit(1);
43         }
44         res = sys_dlsym(h, s);
45         if (!res) {
46                 printf("Can't find function %s\n", s);
47                 total_errors++;
48                 return NULL;
49         }
50         return res;
51 }
52
53 static void report_nss_error(const char *who, NSS_STATUS status)
54 {
55         last_error = status;
56         total_errors++;
57         printf("ERROR %s: NSS_STATUS=%d  %d (nss_errno=%d)\n", 
58                who, status, NSS_STATUS_SUCCESS, nss_errno);
59 }
60
61 static struct passwd *nss_getpwent(void)
62 {
63         NSS_STATUS (*_nss_getpwent_r)(struct passwd *, char *, 
64                                       size_t , int *) =
65                 (NSS_STATUS (*)(struct passwd *, char *,
66                                 size_t, int *))find_fn("getpwent_r");
67         static struct passwd pwd;
68         static char buf[1000];
69         NSS_STATUS status;
70
71         if (!_nss_getpwent_r)
72                 return NULL;
73
74         status = _nss_getpwent_r(&pwd, buf, sizeof(buf), &nss_errno);
75         if (status == NSS_STATUS_NOTFOUND) {
76                 return NULL;
77         }
78         if (status != NSS_STATUS_SUCCESS) {
79                 report_nss_error("getpwent", status);
80                 return NULL;
81         }
82         return &pwd;
83 }
84
85 static struct passwd *nss_getpwnam(const char *name)
86 {
87         NSS_STATUS (*_nss_getpwnam_r)(const char *, struct passwd *, char *, 
88                                       size_t , int *) =
89                 (NSS_STATUS (*)(const char *, struct passwd *, char *,
90                                 size_t, int *))find_fn("getpwnam_r");
91         static struct passwd pwd;
92         static char buf[1000];
93         NSS_STATUS status;
94
95         if (!_nss_getpwnam_r)
96                 return NULL;
97         
98         status = _nss_getpwnam_r(name, &pwd, buf, sizeof(buf), &nss_errno);
99         if (status == NSS_STATUS_NOTFOUND) {
100                 return NULL;
101         }
102         if (status != NSS_STATUS_SUCCESS) {
103                 report_nss_error("getpwnam", status);
104                 return NULL;
105         }
106         return &pwd;
107 }
108
109 static struct passwd *nss_getpwuid(uid_t uid)
110 {
111         NSS_STATUS (*_nss_getpwuid_r)(uid_t , struct passwd *, char *, 
112                                       size_t , int *) =
113                 (NSS_STATUS (*)(uid_t, struct passwd *, char *,
114                                 size_t, int *))find_fn("getpwuid_r");
115         static struct passwd pwd;
116         static char buf[1000];
117         NSS_STATUS status;
118
119         if (!_nss_getpwuid_r)
120                 return NULL;
121         
122         status = _nss_getpwuid_r(uid, &pwd, buf, sizeof(buf), &nss_errno);
123         if (status == NSS_STATUS_NOTFOUND) {
124                 return NULL;
125         }
126         if (status != NSS_STATUS_SUCCESS) {
127                 report_nss_error("getpwuid", status);
128                 return NULL;
129         }
130         return &pwd;
131 }
132
133 static void nss_setpwent(void)
134 {
135         NSS_STATUS (*_nss_setpwent)(void) =
136                 (NSS_STATUS(*)(void))find_fn("setpwent");
137         NSS_STATUS status;
138         
139         if (!_nss_setpwent)
140                 return;
141
142         status = _nss_setpwent();
143         if (status != NSS_STATUS_SUCCESS) {
144                 report_nss_error("setpwent", status);
145         }
146 }
147
148 static void nss_endpwent(void)
149 {
150         NSS_STATUS (*_nss_endpwent)(void) =
151                 (NSS_STATUS (*)(void))find_fn("endpwent");
152         NSS_STATUS status;
153
154         if (!_nss_endpwent)
155                 return;
156
157         status = _nss_endpwent();
158         if (status != NSS_STATUS_SUCCESS) {
159                 report_nss_error("endpwent", status);
160         }
161 }
162
163
164 static struct group *nss_getgrent(void)
165 {
166         NSS_STATUS (*_nss_getgrent_r)(struct group *, char *, 
167                                       size_t , int *) =
168                 (NSS_STATUS (*)(struct group *, char *,
169                                 size_t, int *))find_fn("getgrent_r");
170         static struct group grp;
171         static char *buf;
172         static int buflen = 1024;
173         NSS_STATUS status;
174
175         if (!_nss_getgrent_r)
176                 return NULL;
177
178         if (!buf) 
179                 buf = SMB_MALLOC_ARRAY(char, buflen);
180
181 again:  
182         status = _nss_getgrent_r(&grp, buf, buflen, &nss_errno);
183         if (status == NSS_STATUS_TRYAGAIN) {
184                 buflen *= 2;
185                 buf = SMB_REALLOC_ARRAY(buf, char, buflen);
186                 if (!buf) {
187                         return NULL;
188                 }
189                 goto again;
190         }
191         if (status == NSS_STATUS_NOTFOUND) {
192                 SAFE_FREE(buf);
193                 return NULL;
194         }
195         if (status != NSS_STATUS_SUCCESS) {
196                 report_nss_error("getgrent", status);
197                 SAFE_FREE(buf);
198                 return NULL;
199         }
200         SAFE_FREE(buf);
201         return &grp;
202 }
203
204 static struct group *nss_getgrnam(const char *name)
205 {
206         NSS_STATUS (*_nss_getgrnam_r)(const char *, struct group *, char *, 
207                                       size_t , int *) =
208                 (NSS_STATUS (*)(const char *, struct group *, char *,
209                                 size_t, int *))find_fn("getgrnam_r");
210         static struct group grp;
211         static char *buf;
212         static int buflen = 1000;
213         NSS_STATUS status;
214
215         if (!_nss_getgrnam_r)
216                 return NULL;
217
218         if (!buf) 
219                 buf = SMB_MALLOC_ARRAY(char, buflen);
220 again:  
221         status = _nss_getgrnam_r(name, &grp, buf, buflen, &nss_errno);
222         if (status == NSS_STATUS_TRYAGAIN) {
223                 buflen *= 2;
224                 buf = SMB_REALLOC_ARRAY(buf, char, buflen);
225                 if (!buf) {
226                         return NULL;
227                 }
228                 goto again;
229         }
230         if (status == NSS_STATUS_NOTFOUND) {
231                 SAFE_FREE(buf);
232                 return NULL;
233         }
234         if (status != NSS_STATUS_SUCCESS) {
235                 report_nss_error("getgrnam", status);
236                 SAFE_FREE(buf);
237                 return NULL;
238         }
239         SAFE_FREE(buf);
240         return &grp;
241 }
242
243 static struct group *nss_getgrgid(gid_t gid)
244 {
245         NSS_STATUS (*_nss_getgrgid_r)(gid_t , struct group *, char *, 
246                                       size_t , int *) =
247                 (NSS_STATUS (*)(gid_t, struct group *, char *,
248                                 size_t, int *))find_fn("getgrgid_r");
249         static struct group grp;
250         static char *buf;
251         static int buflen = 1000;
252         NSS_STATUS status;
253         
254         if (!_nss_getgrgid_r)
255                 return NULL;
256
257         if (!buf) 
258                 buf = SMB_MALLOC_ARRAY(char, buflen);
259
260 again:  
261         status = _nss_getgrgid_r(gid, &grp, buf, buflen, &nss_errno);
262         if (status == NSS_STATUS_TRYAGAIN) {
263                 buflen *= 2;
264                 buf = SMB_REALLOC_ARRAY(buf, char, buflen);
265                 if (!buf) {
266                         return NULL;
267                 }
268                 goto again;
269         }
270         if (status == NSS_STATUS_NOTFOUND) {
271                 SAFE_FREE(buf);
272                 return NULL;
273         }
274         if (status != NSS_STATUS_SUCCESS) {
275                 report_nss_error("getgrgid", status);
276                 SAFE_FREE(buf);
277                 return NULL;
278         }
279         SAFE_FREE(buf);
280         return &grp;
281 }
282
283 static void nss_setgrent(void)
284 {
285         NSS_STATUS (*_nss_setgrent)(void) =
286                 (NSS_STATUS (*)(void))find_fn("setgrent");
287         NSS_STATUS status;
288
289         if (!_nss_setgrent)
290                 return;
291
292         status = _nss_setgrent();
293         if (status != NSS_STATUS_SUCCESS) {
294                 report_nss_error("setgrent", status);
295         }
296 }
297
298 static void nss_endgrent(void)
299 {
300         NSS_STATUS (*_nss_endgrent)(void) =
301                 (NSS_STATUS (*)(void))find_fn("endgrent");
302         NSS_STATUS status;
303
304         if (!_nss_endgrent)
305                 return;
306
307         status = _nss_endgrent();
308         if (status != NSS_STATUS_SUCCESS) {
309                 report_nss_error("endgrent", status);
310         }
311 }
312
313 static int nss_initgroups(char *user, gid_t group, gid_t **groups, long int *start, long int *size)
314 {
315         NSS_STATUS (*_nss_initgroups)(char *, gid_t , long int *,
316                                       long int *, gid_t **, long int , int *) = 
317                 (NSS_STATUS (*)(char *, gid_t, long int *,
318                                 long int *, gid_t **,
319                                 long int, int *))find_fn("initgroups_dyn");
320         NSS_STATUS status;
321
322         if (!_nss_initgroups) 
323                 return NSS_STATUS_UNAVAIL;
324
325         status = _nss_initgroups(user, group, start, size, groups, 0, &nss_errno);
326         if (status != NSS_STATUS_SUCCESS) {
327                 report_nss_error("initgroups", status);
328         }
329         return status;
330 }
331
332 static void print_passwd(struct passwd *pwd)
333 {
334         printf("%s:%s:%lu:%lu:%s:%s:%s\n", 
335                pwd->pw_name,
336                pwd->pw_passwd,
337                (unsigned long)pwd->pw_uid,
338                (unsigned long)pwd->pw_gid,
339                pwd->pw_gecos,
340                pwd->pw_dir,
341                pwd->pw_shell);
342 }
343
344 static void print_group(struct group *grp)
345 {
346         int i;
347         printf("%s:%s:%lu: ", 
348                grp->gr_name,
349                grp->gr_passwd,
350                (unsigned long)grp->gr_gid);
351         
352         if (!grp->gr_mem[0]) {
353                 printf("\n");
354                 return;
355         }
356         
357         for (i=0; grp->gr_mem[i+1]; i++) {
358                 printf("%s, ", grp->gr_mem[i]);
359         }
360         printf("%s\n", grp->gr_mem[i]);
361 }
362
363 static void nss_test_initgroups(char *name, gid_t gid)
364 {
365         long int size = 16;
366         long int start = 1;
367         gid_t *groups = NULL;
368         int i;
369         NSS_STATUS status;
370
371         groups = SMB_MALLOC_ARRAY(gid_t, size);
372         groups[0] = gid;
373
374         status = nss_initgroups(name, gid, &groups, &start, &size);
375         if (status == NSS_STATUS_UNAVAIL) {
376                 printf("No initgroups fn\n");
377                 return;
378         }
379
380         for (i=0; i<start-1; i++) {
381                 printf("%lu, ", (unsigned long)groups[i]);
382         }
383         printf("%lu\n", (unsigned long)groups[i]);
384 }
385
386
387 static void nss_test_users(void)
388 {
389         struct passwd *pwd;
390
391         nss_setpwent();
392         /* loop over all users */
393         while ((pwd = nss_getpwent())) {
394                 printf("Testing user %s\n", pwd->pw_name);
395                 printf("getpwent:   "); print_passwd(pwd);
396                 pwd = nss_getpwuid(pwd->pw_uid);
397                 if (!pwd) {
398                         total_errors++;
399                         printf("ERROR: can't getpwuid\n");
400                         continue;
401                 }
402                 printf("getpwuid:   "); print_passwd(pwd);
403                 pwd = nss_getpwnam(pwd->pw_name);
404                 if (!pwd) {
405                         total_errors++;
406                         printf("ERROR: can't getpwnam\n");
407                         continue;
408                 }
409                 printf("getpwnam:   "); print_passwd(pwd);
410                 printf("initgroups: "); nss_test_initgroups(pwd->pw_name, pwd->pw_gid);
411                 printf("\n");
412         }
413         nss_endpwent();
414 }
415
416 static void nss_test_groups(void)
417 {
418         struct group *grp;
419
420         nss_setgrent();
421         /* loop over all groups */
422         while ((grp = nss_getgrent())) {
423                 printf("Testing group %s\n", grp->gr_name);
424                 printf("getgrent: "); print_group(grp);
425                 grp = nss_getgrnam(grp->gr_name);
426                 if (!grp) {
427                         total_errors++;
428                         printf("ERROR: can't getgrnam\n");
429                         continue;
430                 }
431                 printf("getgrnam: "); print_group(grp);
432                 grp = nss_getgrgid(grp->gr_gid);
433                 if (!grp) {
434                         total_errors++;
435                         printf("ERROR: can't getgrgid\n");
436                         continue;
437                 }
438                 printf("getgrgid: "); print_group(grp);
439                 printf("\n");
440         }
441         nss_endgrent();
442 }
443
444 static void nss_test_errors(void)
445 {
446         struct passwd *pwd;
447         struct group *grp;
448
449         pwd = getpwnam("nosuchname");
450         if (pwd || last_error != NSS_STATUS_NOTFOUND) {
451                 total_errors++;
452                 printf("ERROR Non existant user gave error %d\n", last_error);
453         }
454
455         pwd = getpwuid(0xFFF0);
456         if (pwd || last_error != NSS_STATUS_NOTFOUND) {
457                 total_errors++;
458                 printf("ERROR Non existant uid gave error %d\n", last_error);
459         }
460
461         grp = getgrnam("nosuchgroup");
462         if (grp || last_error != NSS_STATUS_NOTFOUND) {
463                 total_errors++;
464                 printf("ERROR Non existant group gave error %d\n", last_error);
465         }
466
467         grp = getgrgid(0xFFF0);
468         if (grp || last_error != NSS_STATUS_NOTFOUND) {
469                 total_errors++;
470                 printf("ERROR Non existant gid gave error %d\n", last_error);
471         }
472 }
473
474  int main(int argc, char *argv[])
475 {       
476         if (argc > 1) so_path = argv[1];
477         if (argc > 2) nss_name = argv[2];
478
479         nss_test_users();
480         nss_test_groups();
481         nss_test_errors();
482
483         printf("total_errors=%d\n", total_errors);
484
485         return total_errors;
486 }