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