selftest: Add tests for expected output of wbinfo -i and wbinfo --uid-info
[samba.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 (winbindd_request_response(NULL, WINBINDD_UID_TO_SID,
613                                       &request, &response) !=
614             NSS_STATUS_SUCCESS) {
615                 r.attr_flag = ENOENT;
616         } else {
617                 r.attr_flag = 0;
618                 r.attr_un.au_char = strdup(response.data.sid.sid);
619         }
620
621         return r;
622 }
623
624 static int wb_aix_user_attrib(const char *key, char *attributes[],
625                               attrval_t results[], int size)
626 {
627         struct passwd *pwd;
628         int i;
629
630         pwd = wb_aix_getpwnam(key);
631         if (!pwd) {
632                 errno = ENOENT;
633                 return -1;
634         }
635
636         for (i=0;i<size;i++) {
637                 results[i].attr_flag = 0;
638
639                 if (strcmp(attributes[i], S_ID) == 0) {
640                         results[i].attr_un.au_int = pwd->pw_uid;
641 #ifdef _AIXVERSION_530
642                 } else if (strcmp(attributes[i], S_PGID) == 0) {
643                         results[i].attr_un.au_int = pwd->pw_gid;
644 #endif
645                 } else if (strcmp(attributes[i], S_PWD) == 0) {
646                         results[i].attr_un.au_char = strdup(pwd->pw_passwd);
647                 } else if (strcmp(attributes[i], S_HOME) == 0) {
648                         results[i].attr_un.au_char = strdup(pwd->pw_dir);
649                 } else if (strcmp(attributes[i], S_SHELL) == 0) {
650                         results[i].attr_un.au_char = strdup(pwd->pw_shell);
651                 } else if (strcmp(attributes[i], S_REGISTRY) == 0) {
652                         results[i].attr_un.au_char = strdup("WINBIND");
653                 } else if (strcmp(attributes[i], S_GECOS) == 0) {
654                         results[i].attr_un.au_char = strdup(pwd->pw_gecos);
655                 } else if (strcmp(attributes[i], S_PGRP) == 0) {
656                         results[i] = pwd_to_group(pwd);
657                 } else if (strcmp(attributes[i], S_GROUPS) == 0) {
658                         results[i] = pwd_to_groupsids(pwd);
659                 } else if (strcmp(attributes[i], "SID") == 0) {
660                         results[i] = pwd_to_sid(pwd);
661                 } else {
662                         logit("Unknown user attribute '%s'\n", attributes[i]);
663                         results[i].attr_flag = EINVAL;
664                 }
665         }
666
667         free_pwd(pwd);
668
669         return 0;
670 }
671
672 static int wb_aix_group_attrib(const char *key, char *attributes[],
673                                attrval_t results[], int size)
674 {
675         struct group *grp;
676         int i;
677
678         grp = wb_aix_getgrnam(key);
679         if (!grp) {
680                 errno = ENOENT;
681                 return -1;
682         }
683
684         for (i=0;i<size;i++) {
685                 results[i].attr_flag = 0;
686
687                 if (strcmp(attributes[i], S_PWD) == 0) {
688                         results[i].attr_un.au_char = strdup(grp->gr_passwd);
689                 } else if (strcmp(attributes[i], S_ID) == 0) {
690                         results[i].attr_un.au_int = grp->gr_gid;
691                 } else {
692                         logit("Unknown group attribute '%s'\n", attributes[i]);
693                         results[i].attr_flag = EINVAL;
694                 }
695         }
696
697         free_grp(grp);
698
699         return 0;
700 }
701
702
703 /*
704   called for user/group enumerations
705 */
706 static int wb_aix_getentry(char *key, char *table, char *attributes[],
707                            attrval_t results[], int size)
708 {
709         logit("Got getentry with key='%s' table='%s' size=%d attributes[0]='%s'\n",
710               key, table, size, attributes[0]);
711
712         if (strcmp(key, "ALL") == 0 &&
713             strcmp(table, "user") == 0) {
714                 return wb_aix_lsuser(attributes, results, size);
715         }
716
717         if (strcmp(key, "ALL") == 0 &&
718             strcmp(table, "group") == 0) {
719                 return wb_aix_lsgroup(attributes, results, size);
720         }
721
722         if (strcmp(table, "user") == 0) {
723                 return wb_aix_user_attrib(key, attributes, results, size);
724         }
725
726         if (strcmp(table, "group") == 0) {
727                 return wb_aix_group_attrib(key, attributes, results, size);
728         }
729
730         logit("Unknown getentry operation key='%s' table='%s'\n", key, table);
731
732         errno = ENOSYS;
733         return -1;
734 }
735
736
737
738 /*
739   called to start the backend
740 */
741 static void *wb_aix_open(const char *name, const char *domain, int mode, char *options)
742 {
743         if (strstr(options, "debug")) {
744                 debug_enabled = 1;
745         }
746         logit("open name='%s' mode=%d domain='%s' options='%s'\n", name, domain,
747               mode, options);
748         return NULL;
749 }
750
751 static void wb_aix_close(void *token)
752 {
753         logit("close\n");
754         return;
755 }
756
757 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
758 /*
759    return a list of additional attributes supported by the backend
760 */
761 static attrlist_t **wb_aix_attrlist(void)
762 {
763         /* pretty confusing but we are allocating the array of pointers
764            and the structures we'll be pointing to all at once.  So
765            you need N+1 pointers and N structures. */
766
767         attrlist_t **ret = NULL;
768         attrlist_t *offset = NULL;
769         int i;
770         int n;
771         size_t size;
772
773         struct attr_types {
774                 const char *name;
775                 int flags;
776                 int type;
777         } attr_list[] = {
778                 /* user attributes */
779                 {S_ID,          AL_USERATTR,    SEC_INT},
780                 {S_PGRP,        AL_USERATTR,    SEC_CHAR},
781                 {S_HOME,        AL_USERATTR,    SEC_CHAR},
782                 {S_SHELL,       AL_USERATTR,    SEC_CHAR},
783 #ifdef _AIXVERSION_530
784                 {S_PGID,        AL_USERATTR,    SEC_INT},
785 #endif
786                 {S_GECOS,       AL_USERATTR,    SEC_CHAR},
787                 {S_SHELL,       AL_USERATTR,    SEC_CHAR},
788                 {S_PGRP,        AL_USERATTR,    SEC_CHAR},
789                 {S_GROUPS,      AL_USERATTR,    SEC_LIST},
790                 {"SID",         AL_USERATTR,    SEC_CHAR},
791
792                 /* group attributes */
793                 {S_ID,          AL_GROUPATTR,   SEC_INT}
794         };
795
796         logit("method attrlist called\n");
797
798         n = sizeof(attr_list) / sizeof(struct attr_types);
799         size = (n*sizeof(attrlist_t *));
800
801         if ( (ret = malloc( size )) == NULL ) {
802                 errno = ENOMEM;
803                 return NULL;
804         }
805
806         /* offset to where the structures start in the buffer */
807
808         offset = (attrlist_t *)(ret + n);
809
810         /* now loop over the user_attr_list[] array and add
811            all the members */
812
813         for ( i=0; i<n; i++ ) {
814                 attrlist_t *a = malloc(sizeof(attrlist_t));
815
816                 if ( !a ) {
817                         /* this is bad.  Just bail */
818                         return NULL;
819                 }
820
821                 a->al_name  = strdup(attr_list[i].name);
822                 a->al_flags = attr_list[i].flags;
823                 a->al_type  = attr_list[i].type;
824
825                 ret[i] = a;
826         }
827         ret[n] = NULL;
828
829         return ret;
830 }
831 #endif
832
833
834 /*
835   turn a long username into a short one. Needed to cope with the 8 char
836   username limit in AIX 5.2 and below
837 */
838 static int wb_aix_normalize(char *longname, char *shortname)
839 {
840         struct passwd *pwd;
841
842         logit("normalize '%s'\n", longname);
843
844         /* automatically cope with AIX 5.3 with longer usernames
845            when it comes out */
846         if (S_NAMELEN > strlen(longname)) {
847                 strcpy(shortname, longname);
848                 return 1;
849         }
850
851         pwd = wb_aix_getpwnam(longname);
852         if (!pwd) {
853                 errno = ENOENT;
854                 return 0;
855         }
856
857         sprintf(shortname, "%c%07u", WB_AIX_ENCODED, pwd->pw_uid);
858
859         free_pwd(pwd);
860
861         return 1;
862 }
863
864
865 /*
866   authenticate a user
867  */
868 static int wb_aix_authenticate(char *user, char *pass,
869                                int *reenter, char **message)
870 {
871         struct winbindd_request request;
872         struct winbindd_response response;
873         NSS_STATUS result;
874         char *r_user = user;
875
876         logit("authenticate '%s' response='%s'\n", user, pass);
877
878         *reenter = 0;
879         *message = NULL;
880
881         /* Send off request */
882         ZERO_STRUCT(request);
883         ZERO_STRUCT(response);
884
885         if (*user == WB_AIX_ENCODED) {
886                 r_user = decode_user(r_user);
887                 if (!r_user) {
888                         return AUTH_NOTFOUND;
889                 }
890         }
891
892         STRCPY_RET(request.data.auth.user, r_user);
893         STRCPY_RET(request.data.auth.pass, pass);
894
895         if (*user == WB_AIX_ENCODED) {
896                 free(r_user);
897         }
898
899         result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH,
900                                            &request, &response);
901
902         winbindd_free_response(&response);
903
904         logit("auth result %d for '%s'\n", result, user);
905
906         if (result == NSS_STATUS_SUCCESS) {
907                 errno = 0;
908                 return AUTH_SUCCESS;
909         }
910
911         return AUTH_FAILURE;
912 }
913
914
915 /*
916   change a user password
917 */
918 static int wb_aix_chpass(char *user, char *oldpass, char *newpass, char **message)
919 {
920         struct winbindd_request request;
921         struct winbindd_response response;
922         NSS_STATUS result;
923         char *r_user = user;
924
925         if (*user == WB_AIX_ENCODED) {
926                 r_user = decode_user(r_user);
927                 if (!r_user) {
928                         errno = ENOENT;
929                         return -1;
930                 }
931         }
932
933         logit("chpass '%s' old='%s' new='%s'\n", r_user, oldpass, newpass);
934
935         *message = NULL;
936
937         /* Send off request */
938         ZERO_STRUCT(request);
939         ZERO_STRUCT(response);
940
941         STRCPY_RET(request.data.chauthtok.user, r_user);
942         STRCPY_RET(request.data.chauthtok.oldpass, oldpass);
943         STRCPY_RET(request.data.chauthtok.newpass, newpass);
944
945         if (*user == WB_AIX_ENCODED) {
946                 free(r_user);
947         }
948
949         result = winbindd_request_response(NULL, WINBINDD_PAM_CHAUTHTOK,
950                                            &request, &response);
951
952         winbindd_free_response(&response);
953
954         if (result == NSS_STATUS_SUCCESS) {
955                 errno = 0;
956                 return 0;
957         }
958
959         errno = EINVAL;
960         return -1;
961 }
962
963 /*
964   don't do any password strength testing for now
965 */
966 static int wb_aix_passwdrestrictions(char *user, char *newpass, char *oldpass,
967                                      char **message)
968 {
969         logit("passwdresrictions called for '%s'\n", user);
970         return 0;
971 }
972
973
974 static int wb_aix_passwdexpired(char *user, char **message)
975 {
976         logit("passwdexpired '%s'\n", user);
977         /* we should check the account bits here */
978         return 0;
979 }
980
981
982 /*
983   we can't return a crypt() password
984 */
985 static char *wb_aix_getpasswd(char *user)
986 {
987         logit("getpasswd '%s'\n", user);
988         errno = ENOSYS;
989         return NULL;
990 }
991
992 /*
993   this is called to update things like the last login time. We don't
994   currently pass this onto the DC
995 */
996 static int wb_aix_putentry(char *key, char *table, char *attributes[],
997                            attrval_t values[], int size)
998 {
999         logit("putentry key='%s' table='%s' attrib='%s'\n",
1000               key, table, size>=1?attributes[0]:"<null>");
1001         errno = ENOSYS;
1002         return -1;
1003 }
1004
1005 static int wb_aix_commit(char *key, char *table)
1006 {
1007         logit("commit key='%s' table='%s'\n");
1008         errno = ENOSYS;
1009         return -1;
1010 }
1011
1012 static int wb_aix_getgrusers(char *group, void *result, int type, int *size)
1013 {
1014         logit("getgrusers group='%s'\n", group);
1015         errno = ENOSYS;
1016         return -1;
1017 }
1018
1019
1020 #define DECL_METHOD(x) \
1021 int method_ ## x(void) \
1022 { \
1023         logit("UNIMPLEMENTED METHOD '%s'\n", #x); \
1024         errno = EINVAL; \
1025         return -1; \
1026 }
1027
1028 #if LOG_UNIMPLEMENTED_CALLS
1029 DECL_METHOD(delgroup);
1030 DECL_METHOD(deluser);
1031 DECL_METHOD(newgroup);
1032 DECL_METHOD(newuser);
1033 DECL_METHOD(putgrent);
1034 DECL_METHOD(putgrusers);
1035 DECL_METHOD(putpwent);
1036 DECL_METHOD(lock);
1037 DECL_METHOD(unlock);
1038 DECL_METHOD(getcred);
1039 DECL_METHOD(setcred);
1040 DECL_METHOD(deletecred);
1041 #endif
1042
1043 int wb_aix_init(struct secmethod_table *methods)
1044 {
1045         ZERO_STRUCTP(methods);
1046
1047 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_VERSION
1048         methods->method_version = SECMETHOD_VERSION_520;
1049 #endif
1050
1051         methods->method_getgrgid           = wb_aix_getgrgid;
1052         methods->method_getgrnam           = wb_aix_getgrnam;
1053         methods->method_getgrset           = wb_aix_getgrset;
1054         methods->method_getpwnam           = wb_aix_getpwnam;
1055         methods->method_getpwuid           = wb_aix_getpwuid;
1056         methods->method_getentry           = wb_aix_getentry;
1057         methods->method_open               = wb_aix_open;
1058         methods->method_close              = wb_aix_close;
1059         methods->method_normalize          = wb_aix_normalize;
1060         methods->method_passwdexpired      = wb_aix_passwdexpired;
1061         methods->method_putentry           = wb_aix_putentry;
1062         methods->method_getpasswd          = wb_aix_getpasswd;
1063         methods->method_authenticate       = wb_aix_authenticate;
1064         methods->method_commit             = wb_aix_commit;
1065         methods->method_chpass             = wb_aix_chpass;
1066         methods->method_passwdrestrictions = wb_aix_passwdrestrictions;
1067         methods->method_getgracct          = wb_aix_getgracct;
1068         methods->method_getgrusers         = wb_aix_getgrusers;
1069 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
1070         methods->method_attrlist           = wb_aix_attrlist;
1071 #endif
1072
1073 #if LOG_UNIMPLEMENTED_CALLS
1074         methods->method_delgroup      = method_delgroup;
1075         methods->method_deluser       = method_deluser;
1076         methods->method_newgroup      = method_newgroup;
1077         methods->method_newuser       = method_newuser;
1078         methods->method_putgrent      = method_putgrent;
1079         methods->method_putgrusers    = method_putgrusers;
1080         methods->method_putpwent      = method_putpwent;
1081         methods->method_lock          = method_lock;
1082         methods->method_unlock        = method_unlock;
1083         methods->method_getcred       = method_getcred;
1084         methods->method_setcred       = method_setcred;
1085         methods->method_deletecred    = method_deletecred;
1086 #endif
1087
1088         return AUTH_SUCCESS;
1089 }