libwbclient: Fix memleaks in tests
[ira/wip.git] / nsswitch / winbind_nss_aix.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    AIX loadable authentication module, providing identification and
5    authentication routines against Samba winbind/Windows NT Domain
6
7    Copyright (C) Tim Potter 2003
8    Copyright (C) Steve Roylance 2003
9    Copyright (C) Andrew Tridgell 2003-2004
10
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU Lesser General Public
13    License as published by the Free Software Foundation; either
14    version 3 of the License, or (at your option) any later version.
15
16    This library is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    Library General Public License for more details.
20
21    You should have received a copy of the GNU Lesser General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 /*
26
27   To install this module copy nsswitch/WINBIND to /usr/lib/security and add
28   "WINBIND" in /usr/lib/security/methods.cfg and /etc/security/user
29
30   Note that this module also provides authentication and password
31   changing routines, so you do not need to install the winbind PAM
32   module.
33
34   see
35   http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/aixprggd/kernextc/sec_load_mod.htm
36   for some information in the interface that this module implements
37
38   Many thanks to Julianne Haugh for explaining some of the finer
39   details of this interface.
40
41   To debug this module use uess_test.c (which you can get from tridge)
42   or set "options=debug" in /usr/lib/security/methods.cfg
43
44 */
45
46 #include "winbind_client.h"
47 #include <usersec.h>
48
49 /* enable this to log which entry points have not been
50   completed yet */
51 #define LOG_UNIMPLEMENTED_CALLS 0
52
53
54 #define WB_AIX_ENCODED '_'
55
56 static int debug_enabled;
57
58
59 static void logit(const char *format, ...)
60 {
61         va_list ap;
62         FILE *f;
63         if (!debug_enabled) {
64                 return;
65         }
66         f = fopen("/tmp/WINBIND_DEBUG.log", "a");
67         if (!f) return;
68         va_start(ap, format);
69         vfprintf(f, format, ap);
70         va_end(ap);
71         fclose(f);
72 }
73
74
75 #define HANDLE_ERRORS(ret) do { \
76         if ((ret) == NSS_STATUS_NOTFOUND) { \
77                 errno = ENOENT; \
78                 return NULL; \
79         } else if ((ret) != NSS_STATUS_SUCCESS) { \
80                 errno = EIO; \
81                 return NULL; \
82         } \
83 } while (0)
84
85 #define STRCPY_RET(dest, src) \
86 do { \
87         if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return -1; } \
88         strcpy(dest, src); \
89 } while (0)
90
91 #define STRCPY_RETNULL(dest, src) \
92 do { \
93         if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return NULL; } \
94         strcpy(dest, src); \
95 } while (0)
96
97
98 /* free a passwd structure */
99 static void free_pwd(struct passwd *pwd)
100 {
101         free(pwd->pw_name);
102         free(pwd->pw_passwd);
103         free(pwd->pw_gecos);
104         free(pwd->pw_dir);
105         free(pwd->pw_shell);
106         free(pwd);
107 }
108
109 /* free a group structure */
110 static void free_grp(struct group *grp)
111 {
112         int i;
113
114         free(grp->gr_name);
115         free(grp->gr_passwd);
116
117         if (!grp->gr_mem) {
118                 free(grp);
119                 return;
120         }
121
122         for (i=0; grp->gr_mem[i]; i++) {
123                 free(grp->gr_mem[i]);
124         }
125
126         free(grp->gr_mem);
127         free(grp);
128 }
129
130
131 /* replace commas with nulls, and null terminate */
132 static void replace_commas(char *s)
133 {
134         char *p, *p0=s;
135         for (p=strchr(s, ','); p; p = strchr(p+1, ',')) {
136                 *p=0;
137                 p0 = p+1;
138         }
139
140         p0[strlen(p0)+1] = 0;
141 }
142
143
144 /* the decode_*() routines are used to cope with the fact that AIX 5.2
145    and below cannot handle user or group names longer than 8
146    characters in some interfaces. We use the normalize method to
147    provide a mapping to a username that fits, by using the form '_UID'
148    or '_GID'.
149
150    this only works if you can guarantee that the WB_AIX_ENCODED char
151    is not used as the first char of any other username
152 */
153 static unsigned decode_id(const char *name)
154 {
155         unsigned id;
156         sscanf(name+1, "%u", &id);
157         return id;
158 }
159
160 static struct passwd *wb_aix_getpwuid(uid_t uid);
161
162 static char *decode_user(const char *name)
163 {
164         struct passwd *pwd;
165         unsigned id;
166         char *ret;
167
168         sscanf(name+1, "%u", &id);
169         pwd = wb_aix_getpwuid(id);
170         if (!pwd) {
171                 return NULL;
172         }
173         ret = strdup(pwd->pw_name);
174
175         free_pwd(pwd);
176
177         logit("decoded '%s' -> '%s'\n", name, ret);
178
179         return ret;
180 }
181
182
183 /*
184   fill a struct passwd from a winbindd_pw struct, allocating as a single block
185 */
186 static struct passwd *fill_pwent(struct winbindd_pw *pw)
187 {
188         struct passwd *result;
189
190         result = calloc(1, sizeof(struct passwd));
191         if (!result) {
192                 errno = ENOMEM;
193                 return NULL;
194         }
195
196         result->pw_uid = pw->pw_uid;
197         result->pw_gid = pw->pw_gid;
198         result->pw_name   = strdup(pw->pw_name);
199         result->pw_passwd = strdup(pw->pw_passwd);
200         result->pw_gecos  = strdup(pw->pw_gecos);
201         result->pw_dir    = strdup(pw->pw_dir);
202         result->pw_shell  = strdup(pw->pw_shell);
203
204         return result;
205 }
206
207
208 /*
209   fill a struct group from a winbindd_pw struct, allocating as a single block
210 */
211 static struct group *fill_grent(struct winbindd_gr *gr, char *gr_mem)
212 {
213         int i;
214         struct group *result;
215         char *p, *name;
216
217         result = calloc(1, sizeof(struct group));
218         if (!result) {
219                 errno = ENOMEM;
220                 return NULL;
221         }
222
223         result->gr_gid = gr->gr_gid;
224
225         result->gr_name   = strdup(gr->gr_name);
226         result->gr_passwd = strdup(gr->gr_passwd);
227
228         /* Group membership */
229         if ((gr->num_gr_mem < 0) || !gr_mem) {
230                 gr->num_gr_mem = 0;
231         }
232
233         if (gr->num_gr_mem == 0) {
234                 /* Group is empty */
235                 return result;
236         }
237
238         result->gr_mem = (char **)malloc(sizeof(char *) * (gr->num_gr_mem+1));
239         if (!result->gr_mem) {
240                 free(result->gr_name);
241                 free(result->gr_passwd);
242                 free(result);
243                 errno = ENOMEM;
244                 return NULL;
245         }
246
247         /* Start looking at extra data */
248         i=0;
249         for (name = strtok_r(gr_mem, ",", &p);
250              name;
251              name = strtok_r(NULL, ",", &p)) {
252                 if (i == gr->num_gr_mem) {
253                         break;
254                 }
255                 result->gr_mem[i] = strdup(name);
256                 i++;
257         }
258
259         /* Terminate list */
260         result->gr_mem[i] = NULL;
261
262         return result;
263 }
264
265
266
267 /* take a group id and return a filled struct group */
268 static struct group *wb_aix_getgrgid(gid_t gid)
269 {
270         struct winbindd_response response;
271         struct winbindd_request request;
272         struct group *grp;
273         NSS_STATUS ret;
274
275         logit("getgrgid %d\n", gid);
276
277         ZERO_STRUCT(response);
278         ZERO_STRUCT(request);
279
280         request.data.gid = gid;
281
282         ret = winbindd_request_response(WINBINDD_GETGRGID, &request, &response);
283
284         logit("getgrgid ret=%d\n", ret);
285
286         HANDLE_ERRORS(ret);
287
288         grp = fill_grent(&response.data.gr, response.extra_data.data);
289
290         winbindd_free_response(&response);
291
292         return grp;
293 }
294
295 /* take a group name and return a filled struct group */
296 static struct group *wb_aix_getgrnam(const char *name)
297 {
298         struct winbindd_response response;
299         struct winbindd_request request;
300         NSS_STATUS ret;
301         struct group *grp;
302
303         if (*name == WB_AIX_ENCODED) {
304                 return wb_aix_getgrgid(decode_id(name));
305         }
306
307         logit("getgrnam '%s'\n", name);
308
309         ZERO_STRUCT(response);
310         ZERO_STRUCT(request);
311
312         STRCPY_RETNULL(request.data.groupname, name);
313
314         ret = winbindd_request_response(WINBINDD_GETGRNAM, &request, &response);
315
316         HANDLE_ERRORS(ret);
317
318         grp = fill_grent(&response.data.gr, response.extra_data.data);
319
320         winbindd_free_response(&response);
321
322         return grp;
323 }
324
325
326 /* this call doesn't have to fill in the gr_mem, but we do anyway
327    for simplicity */
328 static struct group *wb_aix_getgracct(void *id, int type)
329 {
330         if (type == 1) {
331                 return wb_aix_getgrnam((char *)id);
332         }
333         if (type == 0) {
334                 return wb_aix_getgrgid(*(int *)id);
335         }
336         errno = EINVAL;
337         return NULL;
338 }
339
340
341 /* take a username and return a string containing a comma-separated
342    list of group id numbers to which the user belongs */
343 static char *wb_aix_getgrset(char *user)
344 {
345         struct winbindd_response response;
346         struct winbindd_request request;
347         NSS_STATUS ret;
348         int i, idx;
349         char *tmpbuf;
350         int num_gids;
351         gid_t *gid_list;
352         char *r_user = user;
353
354         if (*user == WB_AIX_ENCODED) {
355                 r_user = decode_user(r_user);
356                 if (!r_user) {
357                         errno = ENOENT;
358                         return NULL;
359                 }
360         }
361
362         logit("getgrset '%s'\n", r_user);
363
364         ZERO_STRUCT(response);
365         ZERO_STRUCT(request);
366
367         STRCPY_RETNULL(request.data.username, r_user);
368
369         if (*user == WB_AIX_ENCODED) {
370                 free(r_user);
371         }
372
373         ret = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
374
375         HANDLE_ERRORS(ret);
376
377         num_gids = response.data.num_entries;
378         gid_list = (gid_t *)response.extra_data.data;
379
380         /* allocate a space large enough to contruct the string */
381         tmpbuf = malloc(num_gids*12);
382         if (!tmpbuf) {
383                 return NULL;
384         }
385
386         for (idx=i=0; i < num_gids-1; i++) {
387                 idx += sprintf(tmpbuf+idx, "%u,", gid_list[i]);
388         }
389         idx += sprintf(tmpbuf+idx, "%u", gid_list[i]);
390
391         winbindd_free_response(&response);
392
393         return tmpbuf;
394 }
395
396
397 /* take a uid and return a filled struct passwd */
398 static struct passwd *wb_aix_getpwuid(uid_t uid)
399 {
400         struct winbindd_response response;
401         struct winbindd_request request;
402         NSS_STATUS ret;
403         struct passwd *pwd;
404
405         logit("getpwuid '%d'\n", uid);
406
407         ZERO_STRUCT(response);
408         ZERO_STRUCT(request);
409
410         request.data.uid = uid;
411
412         ret = winbindd_request_response(WINBINDD_GETPWUID, &request, &response);
413
414         HANDLE_ERRORS(ret);
415
416         pwd = fill_pwent(&response.data.pw);
417
418         winbindd_free_response(&response);
419
420         logit("getpwuid gave ptr %p\n", pwd);
421
422         return pwd;
423 }
424
425
426 /* take a username and return a filled struct passwd */
427 static struct passwd *wb_aix_getpwnam(const char *name)
428 {
429         struct winbindd_response response;
430         struct winbindd_request request;
431         NSS_STATUS ret;
432         struct passwd *pwd;
433
434         if (*name == WB_AIX_ENCODED) {
435                 return wb_aix_getpwuid(decode_id(name));
436         }
437
438         logit("getpwnam '%s'\n", name);
439
440         ZERO_STRUCT(response);
441         ZERO_STRUCT(request);
442
443         STRCPY_RETNULL(request.data.username, name);
444
445         ret = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response);
446
447         HANDLE_ERRORS(ret);
448
449         pwd = fill_pwent(&response.data.pw);
450
451         winbindd_free_response(&response);
452
453         logit("getpwnam gave ptr %p\n", pwd);
454
455         return pwd;
456 }
457
458 /*
459   list users
460 */
461 static int wb_aix_lsuser(char *attributes[], attrval_t results[], int size)
462 {
463         NSS_STATUS ret;
464         struct winbindd_request request;
465         struct winbindd_response response;
466         int len;
467         char *s;
468
469         if (size != 1 || strcmp(attributes[0], S_USERS) != 0) {
470                 logit("invalid lsuser op\n");
471                 errno = EINVAL;
472                 return -1;
473         }
474
475         ZERO_STRUCT(request);
476         ZERO_STRUCT(response);
477
478         ret = winbindd_request_response(WINBINDD_LIST_USERS, &request, &response);
479         if (ret != 0) {
480                 errno = EINVAL;
481                 return -1;
482         }
483
484         len = strlen(response.extra_data.data);
485
486         s = malloc(len+2);
487         if (!s) {
488                 winbindd_free_response(&response);
489                 errno = ENOMEM;
490                 return -1;
491         }
492
493         memcpy(s, response.extra_data.data, len+1);
494
495         replace_commas(s);
496
497         results[0].attr_un.au_char = s;
498         results[0].attr_flag = 0;
499
500         winbindd_free_response(&response);
501
502         return 0;
503 }
504
505
506 /*
507   list groups
508 */
509 static int wb_aix_lsgroup(char *attributes[], attrval_t results[], int size)
510 {
511         NSS_STATUS ret;
512         struct winbindd_request request;
513         struct winbindd_response response;
514         int len;
515         char *s;
516
517         if (size != 1 || strcmp(attributes[0], S_GROUPS) != 0) {
518                 logit("invalid lsgroup op\n");
519                 errno = EINVAL;
520                 return -1;
521         }
522
523         ZERO_STRUCT(request);
524         ZERO_STRUCT(response);
525
526         ret = winbindd_request_response(WINBINDD_LIST_GROUPS, &request, &response);
527         if (ret != 0) {
528                 errno = EINVAL;
529                 return -1;
530         }
531
532         len = strlen(response.extra_data.data);
533
534         s = malloc(len+2);
535         if (!s) {
536                 winbindd_free_response(&response);
537                 errno = ENOMEM;
538                 return -1;
539         }
540
541         memcpy(s, response.extra_data.data, len+1);
542
543         replace_commas(s);
544
545         results[0].attr_un.au_char = s;
546         results[0].attr_flag = 0;
547
548         winbindd_free_response(&response);
549
550         return 0;
551 }
552
553
554 static attrval_t pwd_to_group(struct passwd *pwd)
555 {
556         attrval_t r;
557         struct group *grp = wb_aix_getgrgid(pwd->pw_gid);
558
559         if (!grp) {
560                 r.attr_flag = EINVAL;
561         } else {
562                 r.attr_flag = 0;
563                 r.attr_un.au_char = strdup(grp->gr_name);
564                 free_grp(grp);
565         }
566
567         return r;
568 }
569
570 static attrval_t pwd_to_groupsids(struct passwd *pwd)
571 {
572         attrval_t r;
573         char *s, *p;
574
575         if ( (s = wb_aix_getgrset(pwd->pw_name)) == NULL ) {
576                 r.attr_flag = EINVAL;
577                 return r;
578         }
579
580         if ( (p = malloc(strlen(s)+2)) == NULL ) {
581                 r.attr_flag = ENOMEM;
582                 return r;
583         }
584
585         strcpy(p, s);
586         replace_commas(p);
587         free(s);
588
589         r.attr_un.au_char = p;
590
591         return r;
592 }
593
594 static attrval_t pwd_to_sid(struct passwd *pwd)
595 {
596         struct winbindd_request request;
597         struct winbindd_response response;
598         attrval_t r;
599
600         ZERO_STRUCT(request);
601         ZERO_STRUCT(response);
602
603         request.data.uid = pwd->pw_uid;
604
605         if (winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response) !=
606             NSS_STATUS_SUCCESS) {
607                 r.attr_flag = ENOENT;
608         } else {
609                 r.attr_flag = 0;
610                 r.attr_un.au_char = strdup(response.data.sid.sid);
611         }
612
613         return r;
614 }
615
616 static int wb_aix_user_attrib(const char *key, char *attributes[],
617                               attrval_t results[], int size)
618 {
619         struct passwd *pwd;
620         int i;
621
622         pwd = wb_aix_getpwnam(key);
623         if (!pwd) {
624                 errno = ENOENT;
625                 return -1;
626         }
627
628         for (i=0;i<size;i++) {
629                 results[i].attr_flag = 0;
630
631                 if (strcmp(attributes[i], S_ID) == 0) {
632                         results[i].attr_un.au_int = pwd->pw_uid;
633 #ifdef _AIXVERSION_530
634                 } else if (strcmp(attributes[i], S_PGID) == 0) {
635                         results[i].attr_un.au_int = pwd->pw_gid;
636 #endif
637                 } else if (strcmp(attributes[i], S_PWD) == 0) {
638                         results[i].attr_un.au_char = strdup(pwd->pw_passwd);
639                 } else if (strcmp(attributes[i], S_HOME) == 0) {
640                         results[i].attr_un.au_char = strdup(pwd->pw_dir);
641                 } else if (strcmp(attributes[i], S_SHELL) == 0) {
642                         results[i].attr_un.au_char = strdup(pwd->pw_shell);
643                 } else if (strcmp(attributes[i], S_REGISTRY) == 0) {
644                         results[i].attr_un.au_char = strdup("WINBIND");
645                 } else if (strcmp(attributes[i], S_GECOS) == 0) {
646                         results[i].attr_un.au_char = strdup(pwd->pw_gecos);
647                 } else if (strcmp(attributes[i], S_PGRP) == 0) {
648                         results[i] = pwd_to_group(pwd);
649                 } else if (strcmp(attributes[i], S_GROUPS) == 0) {
650                         results[i] = pwd_to_groupsids(pwd);
651                 } else if (strcmp(attributes[i], "SID") == 0) {
652                         results[i] = pwd_to_sid(pwd);
653                 } else {
654                         logit("Unknown user attribute '%s'\n", attributes[i]);
655                         results[i].attr_flag = EINVAL;
656                 }
657         }
658
659         free_pwd(pwd);
660
661         return 0;
662 }
663
664 static int wb_aix_group_attrib(const char *key, char *attributes[],
665                                attrval_t results[], int size)
666 {
667         struct group *grp;
668         int i;
669
670         grp = wb_aix_getgrnam(key);
671         if (!grp) {
672                 errno = ENOENT;
673                 return -1;
674         }
675
676         for (i=0;i<size;i++) {
677                 results[i].attr_flag = 0;
678
679                 if (strcmp(attributes[i], S_PWD) == 0) {
680                         results[i].attr_un.au_char = strdup(grp->gr_passwd);
681                 } else if (strcmp(attributes[i], S_ID) == 0) {
682                         results[i].attr_un.au_int = grp->gr_gid;
683                 } else {
684                         logit("Unknown group attribute '%s'\n", attributes[i]);
685                         results[i].attr_flag = EINVAL;
686                 }
687         }
688
689         free_grp(grp);
690
691         return 0;
692 }
693
694
695 /*
696   called for user/group enumerations
697 */
698 static int wb_aix_getentry(char *key, char *table, char *attributes[],
699                            attrval_t results[], int size)
700 {
701         logit("Got getentry with key='%s' table='%s' size=%d attributes[0]='%s'\n",
702               key, table, size, attributes[0]);
703
704         if (strcmp(key, "ALL") == 0 &&
705             strcmp(table, "user") == 0) {
706                 return wb_aix_lsuser(attributes, results, size);
707         }
708
709         if (strcmp(key, "ALL") == 0 &&
710             strcmp(table, "group") == 0) {
711                 return wb_aix_lsgroup(attributes, results, size);
712         }
713
714         if (strcmp(table, "user") == 0) {
715                 return wb_aix_user_attrib(key, attributes, results, size);
716         }
717
718         if (strcmp(table, "group") == 0) {
719                 return wb_aix_group_attrib(key, attributes, results, size);
720         }
721
722         logit("Unknown getentry operation key='%s' table='%s'\n", key, table);
723
724         errno = ENOSYS;
725         return -1;
726 }
727
728
729
730 /*
731   called to start the backend
732 */
733 static void *wb_aix_open(const char *name, const char *domain, int mode, char *options)
734 {
735         if (strstr(options, "debug")) {
736                 debug_enabled = 1;
737         }
738         logit("open name='%s' mode=%d domain='%s' options='%s'\n", name, domain,
739               mode, options);
740         return NULL;
741 }
742
743 static void wb_aix_close(void *token)
744 {
745         logit("close\n");
746         return;
747 }
748
749 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
750 /*
751    return a list of additional attributes supported by the backend
752 */
753 static attrlist_t **wb_aix_attrlist(void)
754 {
755         /* pretty confusing but we are allocating the array of pointers
756            and the structures we'll be pointing to all at once.  So
757            you need N+1 pointers and N structures. */
758
759         attrlist_t **ret = NULL;
760         attrlist_t *offset = NULL;
761         int i;
762         int n;
763         size_t size;
764
765         struct attr_types {
766                 const char *name;
767                 int flags;
768                 int type;
769         } attr_list[] = {
770                 /* user attributes */
771                 {S_ID,          AL_USERATTR,    SEC_INT},
772                 {S_PGRP,        AL_USERATTR,    SEC_CHAR},
773                 {S_HOME,        AL_USERATTR,    SEC_CHAR},
774                 {S_SHELL,       AL_USERATTR,    SEC_CHAR},
775 #ifdef _AIXVERSION_530
776                 {S_PGID,        AL_USERATTR,    SEC_INT},
777 #endif
778                 {S_GECOS,       AL_USERATTR,    SEC_CHAR},
779                 {S_SHELL,       AL_USERATTR,    SEC_CHAR},
780                 {S_PGRP,        AL_USERATTR,    SEC_CHAR},
781                 {S_GROUPS,      AL_USERATTR,    SEC_LIST},
782                 {"SID",         AL_USERATTR,    SEC_CHAR},
783
784                 /* group attributes */
785                 {S_ID,          AL_GROUPATTR,   SEC_INT}
786         };
787
788         logit("method attrlist called\n");
789
790         n = sizeof(attr_list) / sizeof(struct attr_types);
791         size = (n*sizeof(attrlist_t *));
792
793         if ( (ret = malloc( size )) == NULL ) {
794                 errno = ENOMEM;
795                 return NULL;
796         }
797
798         /* offset to where the structures start in the buffer */
799
800         offset = (attrlist_t *)(ret + n);
801
802         /* now loop over the user_attr_list[] array and add
803            all the members */
804
805         for ( i=0; i<n; i++ ) {
806                 attrlist_t *a = malloc(sizeof(attrlist_t));
807
808                 if ( !a ) {
809                         /* this is bad.  Just bail */
810                         return NULL;
811                 }
812
813                 a->al_name  = strdup(attr_list[i].name);
814                 a->al_flags = attr_list[i].flags;
815                 a->al_type  = attr_list[i].type;
816
817                 ret[i] = a;
818         }
819         ret[n] = NULL;
820
821         return ret;
822 }
823 #endif
824
825
826 /*
827   turn a long username into a short one. Needed to cope with the 8 char
828   username limit in AIX 5.2 and below
829 */
830 static int wb_aix_normalize(char *longname, char *shortname)
831 {
832         struct passwd *pwd;
833
834         logit("normalize '%s'\n", longname);
835
836         /* automatically cope with AIX 5.3 with longer usernames
837            when it comes out */
838         if (S_NAMELEN > strlen(longname)) {
839                 strcpy(shortname, longname);
840                 return 1;
841         }
842
843         pwd = wb_aix_getpwnam(longname);
844         if (!pwd) {
845                 errno = ENOENT;
846                 return 0;
847         }
848
849         sprintf(shortname, "%c%07u", WB_AIX_ENCODED, pwd->pw_uid);
850
851         free_pwd(pwd);
852
853         return 1;
854 }
855
856
857 /*
858   authenticate a user
859  */
860 static int wb_aix_authenticate(char *user, char *pass,
861                                int *reenter, char **message)
862 {
863         struct winbindd_request request;
864         struct winbindd_response response;
865         NSS_STATUS result;
866         char *r_user = user;
867
868         logit("authenticate '%s' response='%s'\n", user, pass);
869
870         *reenter = 0;
871         *message = NULL;
872
873         /* Send off request */
874         ZERO_STRUCT(request);
875         ZERO_STRUCT(response);
876
877         if (*user == WB_AIX_ENCODED) {
878                 r_user = decode_user(r_user);
879                 if (!r_user) {
880                         return AUTH_NOTFOUND;
881                 }
882         }
883
884         STRCPY_RET(request.data.auth.user, r_user);
885         STRCPY_RET(request.data.auth.pass, pass);
886
887         if (*user == WB_AIX_ENCODED) {
888                 free(r_user);
889         }
890
891         result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
892
893         winbindd_free_response(&response);
894
895         logit("auth result %d for '%s'\n", result, user);
896
897         if (result == NSS_STATUS_SUCCESS) {
898                 errno = 0;
899                 return AUTH_SUCCESS;
900         }
901
902         return AUTH_FAILURE;
903 }
904
905
906 /*
907   change a user password
908 */
909 static int wb_aix_chpass(char *user, char *oldpass, char *newpass, char **message)
910 {
911         struct winbindd_request request;
912         struct winbindd_response response;
913         NSS_STATUS result;
914         char *r_user = user;
915
916         if (*user == WB_AIX_ENCODED) {
917                 r_user = decode_user(r_user);
918                 if (!r_user) {
919                         errno = ENOENT;
920                         return -1;
921                 }
922         }
923
924         logit("chpass '%s' old='%s' new='%s'\n", r_user, oldpass, newpass);
925
926         *message = NULL;
927
928         /* Send off request */
929         ZERO_STRUCT(request);
930         ZERO_STRUCT(response);
931
932         STRCPY_RET(request.data.chauthtok.user, r_user);
933         STRCPY_RET(request.data.chauthtok.oldpass, oldpass);
934         STRCPY_RET(request.data.chauthtok.newpass, newpass);
935
936         if (*user == WB_AIX_ENCODED) {
937                 free(r_user);
938         }
939
940         result = winbindd_request_response(WINBINDD_PAM_CHAUTHTOK, &request, &response);
941
942         winbindd_free_response(&response);
943
944         if (result == NSS_STATUS_SUCCESS) {
945                 errno = 0;
946                 return 0;
947         }
948
949         errno = EINVAL;
950         return -1;
951 }
952
953 /*
954   don't do any password strength testing for now
955 */
956 static int wb_aix_passwdrestrictions(char *user, char *newpass, char *oldpass,
957                                      char **message)
958 {
959         logit("passwdresrictions called for '%s'\n", user);
960         return 0;
961 }
962
963
964 static int wb_aix_passwdexpired(char *user, char **message)
965 {
966         logit("passwdexpired '%s'\n", user);
967         /* we should check the account bits here */
968         return 0;
969 }
970
971
972 /*
973   we can't return a crypt() password
974 */
975 static char *wb_aix_getpasswd(char *user)
976 {
977         logit("getpasswd '%s'\n", user);
978         errno = ENOSYS;
979         return NULL;
980 }
981
982 /*
983   this is called to update things like the last login time. We don't
984   currently pass this onto the DC
985 */
986 static int wb_aix_putentry(char *key, char *table, char *attributes[],
987                            attrval_t values[], int size)
988 {
989         logit("putentry key='%s' table='%s' attrib='%s'\n",
990               key, table, size>=1?attributes[0]:"<null>");
991         errno = ENOSYS;
992         return -1;
993 }
994
995 static int wb_aix_commit(char *key, char *table)
996 {
997         logit("commit key='%s' table='%s'\n");
998         errno = ENOSYS;
999         return -1;
1000 }
1001
1002 static int wb_aix_getgrusers(char *group, void *result, int type, int *size)
1003 {
1004         logit("getgrusers group='%s'\n", group);
1005         errno = ENOSYS;
1006         return -1;
1007 }
1008
1009
1010 #define DECL_METHOD(x) \
1011 int method_ ## x(void) \
1012 { \
1013         logit("UNIMPLEMENTED METHOD '%s'\n", #x); \
1014         errno = EINVAL; \
1015         return -1; \
1016 }
1017
1018 #if LOG_UNIMPLEMENTED_CALLS
1019 DECL_METHOD(delgroup);
1020 DECL_METHOD(deluser);
1021 DECL_METHOD(newgroup);
1022 DECL_METHOD(newuser);
1023 DECL_METHOD(putgrent);
1024 DECL_METHOD(putgrusers);
1025 DECL_METHOD(putpwent);
1026 DECL_METHOD(lock);
1027 DECL_METHOD(unlock);
1028 DECL_METHOD(getcred);
1029 DECL_METHOD(setcred);
1030 DECL_METHOD(deletecred);
1031 #endif
1032
1033 int wb_aix_init(struct secmethod_table *methods)
1034 {
1035         ZERO_STRUCTP(methods);
1036
1037 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_VERSION
1038         methods->method_version = SECMETHOD_VERSION_520;
1039 #endif
1040
1041         methods->method_getgrgid           = wb_aix_getgrgid;
1042         methods->method_getgrnam           = wb_aix_getgrnam;
1043         methods->method_getgrset           = wb_aix_getgrset;
1044         methods->method_getpwnam           = wb_aix_getpwnam;
1045         methods->method_getpwuid           = wb_aix_getpwuid;
1046         methods->method_getentry           = wb_aix_getentry;
1047         methods->method_open               = wb_aix_open;
1048         methods->method_close              = wb_aix_close;
1049         methods->method_normalize          = wb_aix_normalize;
1050         methods->method_passwdexpired      = wb_aix_passwdexpired;
1051         methods->method_putentry           = wb_aix_putentry;
1052         methods->method_getpasswd          = wb_aix_getpasswd;
1053         methods->method_authenticate       = wb_aix_authenticate;
1054         methods->method_commit             = wb_aix_commit;
1055         methods->method_chpass             = wb_aix_chpass;
1056         methods->method_passwdrestrictions = wb_aix_passwdrestrictions;
1057         methods->method_getgracct          = wb_aix_getgracct;
1058         methods->method_getgrusers         = wb_aix_getgrusers;
1059 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
1060         methods->method_attrlist           = wb_aix_attrlist;
1061 #endif
1062
1063 #if LOG_UNIMPLEMENTED_CALLS
1064         methods->method_delgroup      = method_delgroup;
1065         methods->method_deluser       = method_deluser;
1066         methods->method_newgroup      = method_newgroup;
1067         methods->method_newuser       = method_newuser;
1068         methods->method_putgrent      = method_putgrent;
1069         methods->method_putgrusers    = method_putgrusers;
1070         methods->method_putpwent      = method_putpwent;
1071         methods->method_lock          = method_lock;
1072         methods->method_unlock        = method_unlock;
1073         methods->method_getcred       = method_getcred;
1074         methods->method_setcred       = method_setcred;
1075         methods->method_deletecred    = method_deletecred;
1076 #endif
1077
1078         return AUTH_SUCCESS;
1079 }