r22069: BUG 4447: Fix compile failure on AIX 5.2 (patch from William Jojo <jojowil...
[samba.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 "winbind_client.h"
49 #include <usersec.h>
50
51 /* enable this to log which entry points have not been
52   completed yet */
53 #define LOG_UNIMPLEMENTED_CALLS 0
54
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.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.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         ZERO_STRUCT(response);
364         ZERO_STRUCT(request);
365
366         STRCPY_RETNULL(request.data.username, r_user);
367
368         if (*user == WB_AIX_ENCODED) {
369                 free(r_user);
370         }
371
372         ret = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
373
374         HANDLE_ERRORS(ret);
375
376         num_gids = response.data.num_entries;
377         gid_list = (gid_t *)response.extra_data.data;
378                 
379         /* allocate a space large enough to contruct the string */
380         tmpbuf = malloc(num_gids*12);
381         if (!tmpbuf) {
382                 return NULL;
383         }
384
385         for (idx=i=0; i < num_gids-1; i++) {
386                 idx += sprintf(tmpbuf+idx, "%u,", gid_list[i]); 
387         }
388         idx += sprintf(tmpbuf+idx, "%u", gid_list[i]);  
389
390         free_response(&response);
391
392         return tmpbuf;
393 }
394
395
396 /* take a uid and return a filled struct passwd */      
397 static struct passwd *wb_aix_getpwuid(uid_t uid)
398 {
399         struct winbindd_response response;
400         struct winbindd_request request;
401         NSS_STATUS ret;
402         struct passwd *pwd;
403
404         logit("getpwuid '%d'\n", uid);
405
406         ZERO_STRUCT(response);
407         ZERO_STRUCT(request);
408                 
409         request.data.uid = uid;
410         
411         ret = winbindd_request_response(WINBINDD_GETPWUID, &request, &response);
412
413         HANDLE_ERRORS(ret);
414
415         pwd = fill_pwent(&response.data.pw);
416
417         free_response(&response);
418
419         logit("getpwuid gave ptr %p\n", pwd);
420
421         return pwd;
422 }
423
424
425 /* take a username and return a filled struct passwd */
426 static struct passwd *wb_aix_getpwnam(const char *name)
427 {
428         struct winbindd_response response;
429         struct winbindd_request request;
430         NSS_STATUS ret;
431         struct passwd *pwd;
432
433         if (*name == WB_AIX_ENCODED) {
434                 return wb_aix_getpwuid(decode_id(name));
435         }
436
437         logit("getpwnam '%s'\n", name);
438
439         ZERO_STRUCT(response);
440         ZERO_STRUCT(request);
441
442         STRCPY_RETNULL(request.data.username, name);
443
444         ret = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response);
445
446         HANDLE_ERRORS(ret);
447         
448         pwd = fill_pwent(&response.data.pw);
449
450         free_response(&response);
451
452         logit("getpwnam gave ptr %p\n", pwd);
453
454         return pwd;
455 }
456
457 /*
458   list users
459 */
460 static int wb_aix_lsuser(char *attributes[], attrval_t results[], int size)
461 {
462         NSS_STATUS ret;
463         struct winbindd_request request;
464         struct winbindd_response response;
465         int len;
466         char *s;
467
468         if (size != 1 || strcmp(attributes[0], S_USERS) != 0) {
469                 logit("invalid lsuser op\n");
470                 errno = EINVAL;
471                 return -1;
472         }
473
474         ZERO_STRUCT(request);
475         ZERO_STRUCT(response);
476         
477         ret = winbindd_request_response(WINBINDD_LIST_USERS, &request, &response);
478         if (ret != 0) {
479                 errno = EINVAL;
480                 return -1;
481         }
482
483         len = strlen(response.extra_data.data);
484
485         s = malloc(len+2);
486         if (!s) {
487                 free_response(&response);
488                 errno = ENOMEM;
489                 return -1;
490         }
491         
492         memcpy(s, response.extra_data.data, len+1);
493
494         replace_commas(s);
495
496         results[0].attr_un.au_char = s;
497         results[0].attr_flag = 0;
498
499         free_response(&response);
500         
501         return 0;
502 }
503
504
505 /*
506   list groups
507 */
508 static int wb_aix_lsgroup(char *attributes[], attrval_t results[], int size)
509 {
510         NSS_STATUS ret;
511         struct winbindd_request request;
512         struct winbindd_response response;
513         int len;
514         char *s;
515
516         if (size != 1 || strcmp(attributes[0], S_GROUPS) != 0) {
517                 logit("invalid lsgroup op\n");
518                 errno = EINVAL;
519                 return -1;
520         }
521
522         ZERO_STRUCT(request);
523         ZERO_STRUCT(response);
524         
525         ret = winbindd_request_response(WINBINDD_LIST_GROUPS, &request, &response);
526         if (ret != 0) {
527                 errno = EINVAL;
528                 return -1;
529         }
530
531         len = strlen(response.extra_data.data);
532
533         s = malloc(len+2);
534         if (!s) {
535                 free_response(&response);
536                 errno = ENOMEM;
537                 return -1;
538         }
539         
540         memcpy(s, response.extra_data.data, len+1);
541
542         replace_commas(s);
543
544         results[0].attr_un.au_char = s;
545         results[0].attr_flag = 0;
546
547         free_response(&response);
548         
549         return 0;
550 }
551
552
553 static attrval_t pwd_to_group(struct passwd *pwd)
554 {
555         attrval_t r;
556         struct group *grp = wb_aix_getgrgid(pwd->pw_gid);
557         
558         if (!grp) {
559                 r.attr_flag = EINVAL;                           
560         } else {
561                 r.attr_flag = 0;
562                 r.attr_un.au_char = strdup(grp->gr_name);
563                 free_grp(grp);
564         }
565
566         return r;
567 }
568
569 static attrval_t pwd_to_groupsids(struct passwd *pwd)
570 {
571         attrval_t r;
572         char *s, *p;
573
574         if ( (s = wb_aix_getgrset(pwd->pw_name)) == NULL ) {
575                 r.attr_flag = EINVAL;
576                 return r;
577         }
578
579         if ( (p = malloc(strlen(s)+2)) == NULL ) {
580                 r.attr_flag = ENOMEM;
581                 return r;
582         }
583
584         strcpy(p, s);
585         replace_commas(p);
586         free(s);
587
588         r.attr_un.au_char = p;
589
590         return r;
591 }
592
593 static attrval_t pwd_to_sid(struct passwd *pwd)
594 {
595         struct winbindd_request request;
596         struct winbindd_response response;
597         attrval_t r;
598
599         ZERO_STRUCT(request);
600         ZERO_STRUCT(response);
601
602         request.data.uid = pwd->pw_uid;
603
604         if (winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response) !=
605             NSS_STATUS_SUCCESS) {
606                 r.attr_flag = ENOENT;
607         } else {
608                 r.attr_flag = 0;
609                 r.attr_un.au_char = strdup(response.data.sid.sid);
610         }
611
612         return r;
613 }
614
615 static int wb_aix_user_attrib(const char *key, char *attributes[],
616                               attrval_t results[], int size)
617 {
618         struct passwd *pwd;
619         int i;
620
621         pwd = wb_aix_getpwnam(key);
622         if (!pwd) {
623                 errno = ENOENT;
624                 return -1;
625         }
626
627         for (i=0;i<size;i++) {
628                 results[i].attr_flag = 0;
629
630                 if (strcmp(attributes[i], S_ID) == 0) {
631                         results[i].attr_un.au_int = pwd->pw_uid;
632 #ifdef _AIXVERSION_530
633                 } else if (strcmp(attributes[i], S_PGID) == 0) {
634                         results[i].attr_un.au_int = pwd->pw_gid;
635 #endif
636                 } else if (strcmp(attributes[i], S_PWD) == 0) {
637                         results[i].attr_un.au_char = strdup(pwd->pw_passwd);
638                 } else if (strcmp(attributes[i], S_HOME) == 0) {
639                         results[i].attr_un.au_char = strdup(pwd->pw_dir);
640                 } else if (strcmp(attributes[i], S_SHELL) == 0) {
641                         results[i].attr_un.au_char = strdup(pwd->pw_shell);
642                 } else if (strcmp(attributes[i], S_REGISTRY) == 0) {
643                         results[i].attr_un.au_char = strdup("WINBIND");
644                 } else if (strcmp(attributes[i], S_GECOS) == 0) {
645                         results[i].attr_un.au_char = strdup(pwd->pw_gecos);
646                 } else if (strcmp(attributes[i], S_PGRP) == 0) {
647                         results[i] = pwd_to_group(pwd);
648                 } else if (strcmp(attributes[i], S_GROUPS) == 0) {
649                         results[i] = pwd_to_groupsids(pwd);
650                 } else if (strcmp(attributes[i], "SID") == 0) {
651                         results[i] = pwd_to_sid(pwd);
652                 } else {
653                         logit("Unknown user attribute '%s'\n", attributes[i]);
654                         results[i].attr_flag = EINVAL;
655                 }
656         }
657
658         free_pwd(pwd);
659
660         return 0;
661 }
662
663 static int wb_aix_group_attrib(const char *key, char *attributes[],
664                                attrval_t results[], int size)
665 {
666         struct group *grp;
667         int i;
668
669         grp = wb_aix_getgrnam(key);
670         if (!grp) {
671                 errno = ENOENT;
672                 return -1;
673         }
674
675         for (i=0;i<size;i++) {
676                 results[i].attr_flag = 0;
677
678                 if (strcmp(attributes[i], S_PWD) == 0) {
679                         results[i].attr_un.au_char = strdup(grp->gr_passwd);
680                 } else if (strcmp(attributes[i], S_ID) == 0) {
681                         results[i].attr_un.au_int = grp->gr_gid;
682                 } else {
683                         logit("Unknown group attribute '%s'\n", attributes[i]);
684                         results[i].attr_flag = EINVAL;
685                 }
686         }
687
688         free_grp(grp);
689
690         return 0;
691 }
692
693
694 /*
695   called for user/group enumerations
696 */
697 static int wb_aix_getentry(char *key, char *table, char *attributes[], 
698                            attrval_t results[], int size)
699 {
700         logit("Got getentry with key='%s' table='%s' size=%d attributes[0]='%s'\n", 
701               key, table, size, attributes[0]);
702
703         if (strcmp(key, "ALL") == 0 && 
704             strcmp(table, "user") == 0) {
705                 return wb_aix_lsuser(attributes, results, size);
706         }
707
708         if (strcmp(key, "ALL") == 0 && 
709             strcmp(table, "group") == 0) {
710                 return wb_aix_lsgroup(attributes, results, size);
711         }
712
713         if (strcmp(table, "user") == 0) {
714                 return wb_aix_user_attrib(key, attributes, results, size);
715         }
716
717         if (strcmp(table, "group") == 0) {
718                 return wb_aix_group_attrib(key, attributes, results, size);
719         }
720
721         logit("Unknown getentry operation key='%s' table='%s'\n", key, table);
722
723         errno = ENOSYS;
724         return -1;
725 }
726
727
728
729 /*
730   called to start the backend
731 */
732 static void *wb_aix_open(const char *name, const char *domain, int mode, char *options)
733 {
734         if (strstr(options, "debug")) {
735                 debug_enabled = 1;
736         }
737         logit("open name='%s' mode=%d domain='%s' options='%s'\n", name, domain, 
738               mode, options);
739         return NULL;
740 }
741
742 static void wb_aix_close(void *token)
743 {
744         logit("close\n");
745         return;
746 }
747
748 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
749 /* 
750    return a list of additional attributes supported by the backend 
751 */
752 static attrlist_t **wb_aix_attrlist(void)
753 {
754         /* pretty confusing but we are allocating the array of pointers
755            and the structures we'll be pointing to all at once.  So
756            you need N+1 pointers and N structures. */
757
758         attrlist_t **ret = NULL;
759         attrlist_t *offset = NULL;
760         int i;
761         int n;
762         size_t size;
763
764         struct attr_types {
765                 const char *name;
766                 int flags;
767                 int type;
768         } attr_list[] = {
769                 /* user attributes */
770                 {S_ID,          AL_USERATTR,    SEC_INT},
771                 {S_PGRP,        AL_USERATTR,    SEC_CHAR},
772                 {S_HOME,        AL_USERATTR,    SEC_CHAR},
773                 {S_SHELL,       AL_USERATTR,    SEC_CHAR},
774 #ifdef _AIXVERSION_530
775                 {S_PGID,        AL_USERATTR,    SEC_INT},
776 #endif
777                 {S_GECOS,       AL_USERATTR,    SEC_CHAR},
778                 {S_SHELL,       AL_USERATTR,    SEC_CHAR},
779                 {S_PGRP,        AL_USERATTR,    SEC_CHAR},
780                 {S_GROUPS,      AL_USERATTR,    SEC_LIST},
781                 {"SID",         AL_USERATTR,    SEC_CHAR},
782
783                 /* group attributes */
784                 {S_ID,          AL_GROUPATTR,   SEC_INT}
785         };
786
787         logit("method attrlist called\n");
788
789         n = sizeof(attr_list) / sizeof(struct attr_types);
790         size = (n*sizeof(attrlist_t *));
791
792         if ( (ret = malloc( size )) == NULL ) {
793                 errno = ENOMEM;
794                 return NULL;
795         }
796
797         /* offset to where the structures start in the buffer */
798
799         offset = (attrlist_t *)(ret + n);
800
801         /* now loop over the user_attr_list[] array and add
802            all the members */
803
804         for ( i=0; i<n; i++ ) {
805                 attrlist_t *a = malloc(sizeof(attrlist_t));
806
807                 if ( !a ) {
808                         /* this is bad.  Just bail */
809                         return NULL;
810                 }
811
812                 a->al_name  = strdup(attr_list[i].name);
813                 a->al_flags = attr_list[i].flags;
814                 a->al_type  = attr_list[i].type;
815
816                 ret[i] = a;
817         }
818         ret[n] = NULL;
819
820         return ret;
821 }
822 #endif
823
824
825 /*
826   turn a long username into a short one. Needed to cope with the 8 char 
827   username limit in AIX 5.2 and below
828 */
829 static int wb_aix_normalize(char *longname, char *shortname)
830 {
831         struct passwd *pwd;
832
833         logit("normalize '%s'\n", longname);
834
835         /* automatically cope with AIX 5.3 with longer usernames
836            when it comes out */
837         if (S_NAMELEN > strlen(longname)) {
838                 strcpy(shortname, longname);
839                 return 1;
840         }
841
842         pwd = wb_aix_getpwnam(longname);
843         if (!pwd) {
844                 errno = ENOENT;
845                 return 0;
846         }
847
848         sprintf(shortname, "%c%07u", WB_AIX_ENCODED, pwd->pw_uid);
849
850         free_pwd(pwd);
851
852         return 1;
853 }
854
855
856 /*
857   authenticate a user
858  */
859 static int wb_aix_authenticate(char *user, char *pass, 
860                                int *reenter, char **message)
861 {
862         struct winbindd_request request;
863         struct winbindd_response response;
864         NSS_STATUS result;
865         char *r_user = user;
866
867         logit("authenticate '%s' response='%s'\n", user, pass);
868
869         *reenter = 0;
870         *message = NULL;
871
872         /* Send off request */
873         ZERO_STRUCT(request);
874         ZERO_STRUCT(response);
875
876         if (*user == WB_AIX_ENCODED) {
877                 r_user = decode_user(r_user);
878                 if (!r_user) {
879                         return AUTH_NOTFOUND;
880                 }
881         }
882
883         STRCPY_RET(request.data.auth.user, r_user);
884         STRCPY_RET(request.data.auth.pass, pass);
885
886         if (*user == WB_AIX_ENCODED) {
887                 free(r_user);
888         }
889
890         result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response);
891
892         free_response(&response);
893
894         logit("auth result %d for '%s'\n", result, user);
895
896         if (result == NSS_STATUS_SUCCESS) {
897                 errno = 0;
898                 return AUTH_SUCCESS;
899         }
900
901         return AUTH_FAILURE;
902 }
903
904
905 /*
906   change a user password
907 */
908 static int wb_aix_chpass(char *user, char *oldpass, char *newpass, char **message)
909 {
910         struct winbindd_request request;
911         struct winbindd_response response;
912         NSS_STATUS result;
913         char *r_user = user;
914
915         if (*user == WB_AIX_ENCODED) {
916                 r_user = decode_user(r_user);
917                 if (!r_user) {
918                         errno = ENOENT;
919                         return -1;
920                 }
921         }
922
923         logit("chpass '%s' old='%s' new='%s'\n", r_user, oldpass, newpass);
924
925         *message = NULL;
926
927         /* Send off request */
928         ZERO_STRUCT(request);
929         ZERO_STRUCT(response);
930
931         STRCPY_RET(request.data.chauthtok.user, r_user);
932         STRCPY_RET(request.data.chauthtok.oldpass, oldpass);
933         STRCPY_RET(request.data.chauthtok.newpass, newpass);
934
935         if (*user == WB_AIX_ENCODED) {
936                 free(r_user);
937         }
938
939         result = winbindd_request_response(WINBINDD_PAM_CHAUTHTOK, &request, &response);
940
941         free_response(&response);
942
943         if (result == NSS_STATUS_SUCCESS) {
944                 errno = 0;
945                 return 0;
946         }
947
948         errno = EINVAL;
949         return -1;
950 }
951
952 /*
953   don't do any password strength testing for now
954 */
955 static int wb_aix_passwdrestrictions(char *user, char *newpass, char *oldpass, 
956                                      char **message)
957 {
958         logit("passwdresrictions called for '%s'\n", user);
959         return 0;
960 }
961
962
963 static int wb_aix_passwdexpired(char *user, char **message)
964 {
965         logit("passwdexpired '%s'\n", user);
966         /* we should check the account bits here */
967         return 0;
968 }
969
970
971 /*
972   we can't return a crypt() password
973 */
974 static char *wb_aix_getpasswd(char *user)
975 {
976         logit("getpasswd '%s'\n", user);
977         errno = ENOSYS;
978         return NULL;
979 }
980
981 /*
982   this is called to update things like the last login time. We don't 
983   currently pass this onto the DC
984 */
985 static int wb_aix_putentry(char *key, char *table, char *attributes[], 
986                            attrval_t values[], int size)
987 {
988         logit("putentry key='%s' table='%s' attrib='%s'\n", 
989               key, table, size>=1?attributes[0]:"<null>");
990         errno = ENOSYS;
991         return -1;
992 }
993
994 static int wb_aix_commit(char *key, char *table)
995 {
996         logit("commit key='%s' table='%s'\n");
997         errno = ENOSYS;
998         return -1;
999 }
1000
1001 static int wb_aix_getgrusers(char *group, void *result, int type, int *size)
1002 {
1003         logit("getgrusers group='%s'\n", group);
1004         errno = ENOSYS;
1005         return -1;
1006 }
1007
1008
1009 #define DECL_METHOD(x) \
1010 int method_ ## x(void) \
1011 { \
1012         logit("UNIMPLEMENTED METHOD '%s'\n", #x); \
1013         errno = EINVAL; \
1014         return -1; \
1015 }
1016
1017 #if LOG_UNIMPLEMENTED_CALLS
1018 DECL_METHOD(delgroup);
1019 DECL_METHOD(deluser);
1020 DECL_METHOD(newgroup);
1021 DECL_METHOD(newuser);
1022 DECL_METHOD(putgrent);
1023 DECL_METHOD(putgrusers);
1024 DECL_METHOD(putpwent);
1025 DECL_METHOD(lock);
1026 DECL_METHOD(unlock);
1027 DECL_METHOD(getcred);
1028 DECL_METHOD(setcred);
1029 DECL_METHOD(deletecred);
1030 #endif
1031
1032 int wb_aix_init(struct secmethod_table *methods)
1033 {
1034         ZERO_STRUCTP(methods);
1035
1036 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_VERSION
1037         methods->method_version = SECMETHOD_VERSION_520;
1038 #endif
1039
1040         methods->method_getgrgid           = wb_aix_getgrgid;
1041         methods->method_getgrnam           = wb_aix_getgrnam;
1042         methods->method_getgrset           = wb_aix_getgrset;
1043         methods->method_getpwnam           = wb_aix_getpwnam;
1044         methods->method_getpwuid           = wb_aix_getpwuid;
1045         methods->method_getentry           = wb_aix_getentry;
1046         methods->method_open               = wb_aix_open;
1047         methods->method_close              = wb_aix_close;
1048         methods->method_normalize          = wb_aix_normalize;
1049         methods->method_passwdexpired      = wb_aix_passwdexpired;
1050         methods->method_putentry           = wb_aix_putentry;
1051         methods->method_getpasswd          = wb_aix_getpasswd;
1052         methods->method_authenticate       = wb_aix_authenticate;       
1053         methods->method_commit             = wb_aix_commit;
1054         methods->method_chpass             = wb_aix_chpass;
1055         methods->method_passwdrestrictions = wb_aix_passwdrestrictions;
1056         methods->method_getgracct          = wb_aix_getgracct;
1057         methods->method_getgrusers         = wb_aix_getgrusers;
1058 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
1059         methods->method_attrlist           = wb_aix_attrlist;
1060 #endif
1061
1062 #if LOG_UNIMPLEMENTED_CALLS
1063         methods->method_delgroup      = method_delgroup;
1064         methods->method_deluser       = method_deluser;
1065         methods->method_newgroup      = method_newgroup;
1066         methods->method_newuser       = method_newuser;
1067         methods->method_putgrent      = method_putgrent;
1068         methods->method_putgrusers    = method_putgrusers;
1069         methods->method_putpwent      = method_putpwent;
1070         methods->method_lock          = method_lock;
1071         methods->method_unlock        = method_unlock;
1072         methods->method_getcred       = method_getcred;
1073         methods->method_setcred       = method_setcred;
1074         methods->method_deletecred    = method_deletecred;
1075 #endif
1076
1077         return AUTH_SUCCESS;
1078 }
1079