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