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