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