s4:torture: add a Maximum Access check with an Owner Rights ACE
[Samba.git] / nsswitch / winbind_nss_aix.c
blobdc44db40ef96127a2f8863a60b7a516de5f74a40
1 /*
2 Unix SMB/CIFS implementation.
4 AIX loadable authentication module, providing identification and
5 authentication routines against Samba winbind/Windows NT Domain
7 Copyright (C) Tim Potter 2003
8 Copyright (C) Steve Roylance 2003
9 Copyright (C) Andrew Tridgell 2003-2004
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.
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.
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/>.
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
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.
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
38 Many thanks to Julianne Haugh for explaining some of the finer
39 details of this interface.
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
46 #include "winbind_client.h"
47 #include <usersec.h>
49 /* enable this to log which entry points have not been
50 completed yet */
51 #define LOG_UNIMPLEMENTED_CALLS 0
54 #define WB_AIX_ENCODED '_'
56 static int debug_enabled;
59 static void logit(const char *format, ...)
61 va_list ap;
62 FILE *f;
63 if (!debug_enabled) {
64 return;
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);
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)
85 #define STRCPY_RET(dest, src) \
86 do { \
87 if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return -1; } \
88 strncpy(dest, src, sizeof(dest)); \
89 dest[sizeof(dest)-1] = '\0'; \
90 } while (0)
92 #define STRCPY_RETNULL(dest, src) \
93 do { \
94 if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return NULL; } \
95 strncpy(dest, src, sizeof(dest)); \
96 dest[sizeof(dest)-1] = '\0'; \
97 } while (0)
100 /* free a passwd structure */
101 static void free_pwd(struct passwd *pwd)
103 free(pwd->pw_name);
104 free(pwd->pw_passwd);
105 free(pwd->pw_gecos);
106 free(pwd->pw_dir);
107 free(pwd->pw_shell);
108 free(pwd);
111 /* free a group structure */
112 static void free_grp(struct group *grp)
114 int i;
116 free(grp->gr_name);
117 free(grp->gr_passwd);
119 if (!grp->gr_mem) {
120 free(grp);
121 return;
124 for (i=0; grp->gr_mem[i]; i++) {
125 free(grp->gr_mem[i]);
128 free(grp->gr_mem);
129 free(grp);
133 /* replace commas with nulls, and null terminate */
134 static void replace_commas(char *s)
136 char *p, *p0=s;
137 for (p=strchr(s, ','); p; p = strchr(p+1, ',')) {
138 *p=0;
139 p0 = p+1;
142 p0[strlen(p0)+1] = 0;
146 /* the decode_*() routines are used to cope with the fact that AIX 5.2
147 and below cannot handle user or group names longer than 8
148 characters in some interfaces. We use the normalize method to
149 provide a mapping to a username that fits, by using the form '_UID'
150 or '_GID'.
152 this only works if you can guarantee that the WB_AIX_ENCODED char
153 is not used as the first char of any other username
155 static unsigned decode_id(const char *name)
157 unsigned id;
158 sscanf(name+1, "%u", &id);
159 return id;
162 static struct passwd *wb_aix_getpwuid(uid_t uid);
164 static char *decode_user(const char *name)
166 struct passwd *pwd;
167 unsigned id;
168 char *ret;
170 sscanf(name+1, "%u", &id);
171 pwd = wb_aix_getpwuid(id);
172 if (!pwd) {
173 return NULL;
175 ret = strdup(pwd->pw_name);
177 free_pwd(pwd);
179 logit("decoded '%s' -> '%s'\n", name, ret);
181 return ret;
186 fill a struct passwd from a winbindd_pw struct, allocating as a single block
188 static struct passwd *fill_pwent(struct winbindd_pw *pw)
190 struct passwd *result;
192 result = calloc(1, sizeof(struct passwd));
193 if (!result) {
194 errno = ENOMEM;
195 return NULL;
198 result->pw_uid = pw->pw_uid;
199 result->pw_gid = pw->pw_gid;
200 result->pw_name = strdup(pw->pw_name);
201 result->pw_passwd = strdup(pw->pw_passwd);
202 result->pw_gecos = strdup(pw->pw_gecos);
203 result->pw_dir = strdup(pw->pw_dir);
204 result->pw_shell = strdup(pw->pw_shell);
206 return result;
211 fill a struct group from a winbindd_pw struct, allocating as a single block
213 static struct group *fill_grent(struct winbindd_gr *gr, char *gr_mem)
215 int i;
216 struct group *result;
217 char *p, *name;
219 result = calloc(1, sizeof(struct group));
220 if (!result) {
221 errno = ENOMEM;
222 return NULL;
225 result->gr_gid = gr->gr_gid;
227 result->gr_name = strdup(gr->gr_name);
228 result->gr_passwd = strdup(gr->gr_passwd);
230 /* Group membership */
231 if ((gr->num_gr_mem < 0) || !gr_mem) {
232 gr->num_gr_mem = 0;
235 if (gr->num_gr_mem == 0) {
236 /* Group is empty */
237 return result;
240 result->gr_mem = (char **)malloc(sizeof(char *) * (gr->num_gr_mem+1));
241 if (!result->gr_mem) {
242 free(result->gr_name);
243 free(result->gr_passwd);
244 free(result);
245 errno = ENOMEM;
246 return NULL;
249 /* Start looking at extra data */
250 i=0;
251 for (name = strtok_r(gr_mem, ",", &p);
252 name;
253 name = strtok_r(NULL, ",", &p)) {
254 if (i == gr->num_gr_mem) {
255 break;
257 result->gr_mem[i] = strdup(name);
258 i++;
261 /* Terminate list */
262 result->gr_mem[i] = NULL;
264 return result;
269 /* take a group id and return a filled struct group */
270 static struct group *wb_aix_getgrgid(gid_t gid)
272 struct winbindd_response response;
273 struct winbindd_request request;
274 struct group *grp;
275 NSS_STATUS ret;
277 logit("getgrgid %d\n", gid);
279 ZERO_STRUCT(response);
280 ZERO_STRUCT(request);
282 request.data.gid = gid;
284 ret = winbindd_request_response(NULL, WINBINDD_GETGRGID,
285 &request, &response);
287 logit("getgrgid ret=%d\n", ret);
289 HANDLE_ERRORS(ret);
291 grp = fill_grent(&response.data.gr, response.extra_data.data);
293 winbindd_free_response(&response);
295 return grp;
298 /* take a group name and return a filled struct group */
299 static struct group *wb_aix_getgrnam(const char *name)
301 struct winbindd_response response;
302 struct winbindd_request request;
303 NSS_STATUS ret;
304 struct group *grp;
306 if (*name == WB_AIX_ENCODED) {
307 return wb_aix_getgrgid(decode_id(name));
310 logit("getgrnam '%s'\n", name);
312 ZERO_STRUCT(response);
313 ZERO_STRUCT(request);
315 STRCPY_RETNULL(request.data.groupname, name);
317 ret = winbindd_request_response(NULL, WINBINDD_GETGRNAM,
318 &request, &response);
320 HANDLE_ERRORS(ret);
322 grp = fill_grent(&response.data.gr, response.extra_data.data);
324 winbindd_free_response(&response);
326 return grp;
330 /* this call doesn't have to fill in the gr_mem, but we do anyway
331 for simplicity */
332 static struct group *wb_aix_getgracct(void *id, int type)
334 if (type == 1) {
335 return wb_aix_getgrnam((char *)id);
337 if (type == 0) {
338 return wb_aix_getgrgid(*(int *)id);
340 errno = EINVAL;
341 return NULL;
345 /* take a username and return a string containing a comma-separated
346 list of group id numbers to which the user belongs */
347 static char *wb_aix_getgrset(char *user)
349 struct winbindd_response response;
350 struct winbindd_request request;
351 NSS_STATUS ret;
352 int i, idx;
353 char *tmpbuf;
354 int num_gids;
355 gid_t *gid_list;
356 char *r_user = user;
358 if (*user == WB_AIX_ENCODED) {
359 r_user = decode_user(r_user);
360 if (!r_user) {
361 errno = ENOENT;
362 return NULL;
366 logit("getgrset '%s'\n", r_user);
368 ZERO_STRUCT(response);
369 ZERO_STRUCT(request);
371 STRCPY_RETNULL(request.data.username, r_user);
373 if (*user == WB_AIX_ENCODED) {
374 free(r_user);
377 ret = winbindd_request_response(NULL, WINBINDD_GETGROUPS,
378 &request, &response);
380 HANDLE_ERRORS(ret);
382 num_gids = response.data.num_entries;
383 gid_list = (gid_t *)response.extra_data.data;
385 /* allocate a space large enough to contruct the string */
386 tmpbuf = malloc(num_gids*12);
387 if (!tmpbuf) {
388 return NULL;
391 for (idx=i=0; i < num_gids-1; i++) {
392 idx += sprintf(tmpbuf+idx, "%u,", gid_list[i]);
394 idx += sprintf(tmpbuf+idx, "%u", gid_list[i]);
396 winbindd_free_response(&response);
398 return tmpbuf;
402 /* take a uid and return a filled struct passwd */
403 static struct passwd *wb_aix_getpwuid(uid_t uid)
405 struct winbindd_response response;
406 struct winbindd_request request;
407 NSS_STATUS ret;
408 struct passwd *pwd;
410 logit("getpwuid '%d'\n", uid);
412 ZERO_STRUCT(response);
413 ZERO_STRUCT(request);
415 request.data.uid = uid;
417 ret = winbindd_request_response(NULL, WINBINDD_GETPWUID,
418 &request, &response);
420 HANDLE_ERRORS(ret);
422 pwd = fill_pwent(&response.data.pw);
424 winbindd_free_response(&response);
426 logit("getpwuid gave ptr %p\n", pwd);
428 return pwd;
432 /* take a username and return a filled struct passwd */
433 static struct passwd *wb_aix_getpwnam(const char *name)
435 struct winbindd_response response;
436 struct winbindd_request request;
437 NSS_STATUS ret;
438 struct passwd *pwd;
440 if (*name == WB_AIX_ENCODED) {
441 return wb_aix_getpwuid(decode_id(name));
444 logit("getpwnam '%s'\n", name);
446 ZERO_STRUCT(response);
447 ZERO_STRUCT(request);
449 STRCPY_RETNULL(request.data.username, name);
451 ret = winbindd_request_response(NULL, WINBINDD_GETPWNAM,
452 &request, &response);
454 HANDLE_ERRORS(ret);
456 pwd = fill_pwent(&response.data.pw);
458 winbindd_free_response(&response);
460 logit("getpwnam gave ptr %p\n", pwd);
462 return pwd;
466 list users
468 static int wb_aix_lsuser(char *attributes[], attrval_t results[], int size)
470 NSS_STATUS ret;
471 struct winbindd_request request;
472 struct winbindd_response response;
473 int len;
474 char *s;
476 if (size != 1 || strcmp(attributes[0], S_USERS) != 0) {
477 logit("invalid lsuser op\n");
478 errno = EINVAL;
479 return -1;
482 ZERO_STRUCT(request);
483 ZERO_STRUCT(response);
485 ret = winbindd_request_response(NULL, WINBINDD_LIST_USERS,
486 &request, &response);
487 if (ret != 0) {
488 errno = EINVAL;
489 return -1;
492 len = strlen(response.extra_data.data);
494 s = malloc(len+2);
495 if (!s) {
496 winbindd_free_response(&response);
497 errno = ENOMEM;
498 return -1;
501 memcpy(s, response.extra_data.data, len+1);
503 replace_commas(s);
505 results[0].attr_un.au_char = s;
506 results[0].attr_flag = 0;
508 winbindd_free_response(&response);
510 return 0;
515 list groups
517 static int wb_aix_lsgroup(char *attributes[], attrval_t results[], int size)
519 NSS_STATUS ret;
520 struct winbindd_request request;
521 struct winbindd_response response;
522 int len;
523 char *s;
525 if (size != 1 || strcmp(attributes[0], S_GROUPS) != 0) {
526 logit("invalid lsgroup op\n");
527 errno = EINVAL;
528 return -1;
531 ZERO_STRUCT(request);
532 ZERO_STRUCT(response);
534 ret = winbindd_request_response(NULL, WINBINDD_LIST_GROUPS,
535 &request, &response);
536 if (ret != 0) {
537 errno = EINVAL;
538 return -1;
541 len = strlen(response.extra_data.data);
543 s = malloc(len+2);
544 if (!s) {
545 winbindd_free_response(&response);
546 errno = ENOMEM;
547 return -1;
550 memcpy(s, response.extra_data.data, len+1);
552 replace_commas(s);
554 results[0].attr_un.au_char = s;
555 results[0].attr_flag = 0;
557 winbindd_free_response(&response);
559 return 0;
563 static attrval_t pwd_to_group(struct passwd *pwd)
565 attrval_t r;
566 struct group *grp = wb_aix_getgrgid(pwd->pw_gid);
568 if (!grp) {
569 r.attr_flag = EINVAL;
570 } else {
571 r.attr_flag = 0;
572 r.attr_un.au_char = strdup(grp->gr_name);
573 free_grp(grp);
576 return r;
579 static attrval_t pwd_to_groupsids(struct passwd *pwd)
581 attrval_t r;
582 char *s, *p;
583 size_t mlen;
585 if ( (s = wb_aix_getgrset(pwd->pw_name)) == NULL ) {
586 r.attr_flag = EINVAL;
587 return r;
590 mlen = strlen(s)+2;
591 if ( (p = malloc(mlen)) == NULL ) {
592 r.attr_flag = ENOMEM;
593 return r;
596 strncpy(p, s, mlen);
597 p[mlen-1] = '\0';
598 replace_commas(p);
599 free(s);
601 r.attr_un.au_char = p;
603 return r;
606 static attrval_t pwd_to_sid(struct passwd *pwd)
608 struct winbindd_request request;
609 struct winbindd_response response;
610 attrval_t r;
612 ZERO_STRUCT(request);
613 ZERO_STRUCT(response);
615 request.data.uid = pwd->pw_uid;
617 #if 0
619 * Removed because WINBINDD_UID_TO_SID is replaced by
620 * WINBINDD_XIDS_TO_SIDS. I don't have an AIX build
621 * environment around, so I did not convert this call. If
622 * someone stumbles over this, please contact me:
623 * vl@samba.org, I'll convert this.
625 if (winbindd_request_response(NULL, WINBINDD_UID_TO_SID,
626 &request, &response) !=
627 NSS_STATUS_SUCCESS) {
628 r.attr_flag = ENOENT;
629 } else {
630 r.attr_flag = 0;
631 r.attr_un.au_char = strdup(response.data.sid.sid);
633 #else
634 r.attr_flag = ENOENT;
635 #endif
637 return r;
640 static int wb_aix_user_attrib(const char *key, char *attributes[],
641 attrval_t results[], int size)
643 struct passwd *pwd;
644 int i;
646 pwd = wb_aix_getpwnam(key);
647 if (!pwd) {
648 errno = ENOENT;
649 return -1;
652 for (i=0;i<size;i++) {
653 results[i].attr_flag = 0;
655 if (strcmp(attributes[i], S_ID) == 0) {
656 results[i].attr_un.au_int = pwd->pw_uid;
657 #ifdef _AIXVERSION_530
658 } else if (strcmp(attributes[i], S_PGID) == 0) {
659 results[i].attr_un.au_int = pwd->pw_gid;
660 #endif
661 } else if (strcmp(attributes[i], S_PWD) == 0) {
662 results[i].attr_un.au_char = strdup(pwd->pw_passwd);
663 } else if (strcmp(attributes[i], S_HOME) == 0) {
664 results[i].attr_un.au_char = strdup(pwd->pw_dir);
665 } else if (strcmp(attributes[i], S_SHELL) == 0) {
666 results[i].attr_un.au_char = strdup(pwd->pw_shell);
667 } else if (strcmp(attributes[i], S_REGISTRY) == 0) {
668 results[i].attr_un.au_char = strdup("WINBIND");
669 } else if (strcmp(attributes[i], S_GECOS) == 0) {
670 results[i].attr_un.au_char = strdup(pwd->pw_gecos);
671 } else if (strcmp(attributes[i], S_PGRP) == 0) {
672 results[i] = pwd_to_group(pwd);
673 } else if (strcmp(attributes[i], S_GROUPS) == 0) {
674 results[i] = pwd_to_groupsids(pwd);
675 } else if (strcmp(attributes[i], "SID") == 0) {
676 results[i] = pwd_to_sid(pwd);
677 } else {
678 logit("Unknown user attribute '%s'\n", attributes[i]);
679 results[i].attr_flag = EINVAL;
683 free_pwd(pwd);
685 return 0;
688 static int wb_aix_group_attrib(const char *key, char *attributes[],
689 attrval_t results[], int size)
691 struct group *grp;
692 int i;
694 grp = wb_aix_getgrnam(key);
695 if (!grp) {
696 errno = ENOENT;
697 return -1;
700 for (i=0;i<size;i++) {
701 results[i].attr_flag = 0;
703 if (strcmp(attributes[i], S_PWD) == 0) {
704 results[i].attr_un.au_char = strdup(grp->gr_passwd);
705 } else if (strcmp(attributes[i], S_ID) == 0) {
706 results[i].attr_un.au_int = grp->gr_gid;
707 } else {
708 logit("Unknown group attribute '%s'\n", attributes[i]);
709 results[i].attr_flag = EINVAL;
713 free_grp(grp);
715 return 0;
720 called for user/group enumerations
722 static int wb_aix_getentry(char *key, char *table, char *attributes[],
723 attrval_t results[], int size)
725 logit("Got getentry with key='%s' table='%s' size=%d attributes[0]='%s'\n",
726 key, table, size, attributes[0]);
728 if (strcmp(key, "ALL") == 0 &&
729 strcmp(table, "user") == 0) {
730 return wb_aix_lsuser(attributes, results, size);
733 if (strcmp(key, "ALL") == 0 &&
734 strcmp(table, "group") == 0) {
735 return wb_aix_lsgroup(attributes, results, size);
738 if (strcmp(table, "user") == 0) {
739 return wb_aix_user_attrib(key, attributes, results, size);
742 if (strcmp(table, "group") == 0) {
743 return wb_aix_group_attrib(key, attributes, results, size);
746 logit("Unknown getentry operation key='%s' table='%s'\n", key, table);
748 errno = ENOSYS;
749 return -1;
755 called to start the backend
757 static void *wb_aix_open(const char *name, const char *domain, int mode, char *options)
759 if (strstr(options, "debug")) {
760 debug_enabled = 1;
762 logit("open name='%s' mode=%d domain='%s' options='%s'\n", name, domain,
763 mode, options);
764 return NULL;
767 static void wb_aix_close(void *token)
769 logit("close\n");
770 return;
773 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
775 return a list of additional attributes supported by the backend
777 static attrlist_t **wb_aix_attrlist(void)
779 /* pretty confusing but we are allocating the array of pointers
780 and the structures we'll be pointing to all at once. So
781 you need N+1 pointers and N structures. */
783 attrlist_t **ret = NULL;
784 attrlist_t *offset = NULL;
785 int i;
786 int n;
787 size_t size;
789 struct attr_types {
790 const char *name;
791 int flags;
792 int type;
793 } attr_list[] = {
794 /* user attributes */
795 {S_ID, AL_USERATTR, SEC_INT},
796 {S_PGRP, AL_USERATTR, SEC_CHAR},
797 {S_HOME, AL_USERATTR, SEC_CHAR},
798 {S_SHELL, AL_USERATTR, SEC_CHAR},
799 #ifdef _AIXVERSION_530
800 {S_PGID, AL_USERATTR, SEC_INT},
801 #endif
802 {S_GECOS, AL_USERATTR, SEC_CHAR},
803 {S_SHELL, AL_USERATTR, SEC_CHAR},
804 {S_PGRP, AL_USERATTR, SEC_CHAR},
805 {S_GROUPS, AL_USERATTR, SEC_LIST},
806 {"SID", AL_USERATTR, SEC_CHAR},
808 /* group attributes */
809 {S_ID, AL_GROUPATTR, SEC_INT}
812 logit("method attrlist called\n");
814 n = sizeof(attr_list) / sizeof(struct attr_types);
815 size = (n*sizeof(attrlist_t *));
817 if ( (ret = malloc( size )) == NULL ) {
818 errno = ENOMEM;
819 return NULL;
822 /* offset to where the structures start in the buffer */
824 offset = (attrlist_t *)(ret + n);
826 /* now loop over the user_attr_list[] array and add
827 all the members */
829 for ( i=0; i<n; i++ ) {
830 attrlist_t *a = malloc(sizeof(attrlist_t));
832 if ( !a ) {
833 /* this is bad. Just bail */
834 return NULL;
837 a->al_name = strdup(attr_list[i].name);
838 a->al_flags = attr_list[i].flags;
839 a->al_type = attr_list[i].type;
841 ret[i] = a;
843 ret[n] = NULL;
845 return ret;
847 #endif
851 turn a long username into a short one. Needed to cope with the 8 char
852 username limit in AIX 5.2 and below
854 static int wb_aix_normalize(char *longname, char *shortname)
856 struct passwd *pwd;
858 logit("normalize '%s'\n", longname);
860 /* automatically cope with AIX 5.3 with longer usernames
861 when it comes out */
862 if (S_NAMELEN > strlen(longname)) {
863 strncpy(shortname, longname, S_NAMELEN);
864 shortname[S_NAMELEN-1] = '\0';
865 return 1;
868 pwd = wb_aix_getpwnam(longname);
869 if (!pwd) {
870 errno = ENOENT;
871 return 0;
874 sprintf(shortname, "%c%07u", WB_AIX_ENCODED, pwd->pw_uid);
876 free_pwd(pwd);
878 return 1;
883 authenticate a user
885 static int wb_aix_authenticate(char *user, char *pass,
886 int *reenter, char **message)
888 struct winbindd_request request;
889 struct winbindd_response response;
890 NSS_STATUS result;
891 char *r_user = user;
893 logit("authenticate '%s' response='%s'\n", user, pass);
895 *reenter = 0;
896 *message = NULL;
898 /* Send off request */
899 ZERO_STRUCT(request);
900 ZERO_STRUCT(response);
902 if (*user == WB_AIX_ENCODED) {
903 r_user = decode_user(r_user);
904 if (!r_user) {
905 return AUTH_NOTFOUND;
909 STRCPY_RET(request.data.auth.user, r_user);
910 STRCPY_RET(request.data.auth.pass, pass);
912 if (*user == WB_AIX_ENCODED) {
913 free(r_user);
916 result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH,
917 &request, &response);
919 winbindd_free_response(&response);
921 logit("auth result %d for '%s'\n", result, user);
923 if (result == NSS_STATUS_SUCCESS) {
924 errno = 0;
925 return AUTH_SUCCESS;
928 return AUTH_FAILURE;
933 change a user password
935 static int wb_aix_chpass(char *user, char *oldpass, char *newpass, char **message)
937 struct winbindd_request request;
938 struct winbindd_response response;
939 NSS_STATUS result;
940 char *r_user = user;
942 if (*user == WB_AIX_ENCODED) {
943 r_user = decode_user(r_user);
944 if (!r_user) {
945 errno = ENOENT;
946 return -1;
950 logit("chpass '%s' old='%s' new='%s'\n", r_user, oldpass, newpass);
952 *message = NULL;
954 /* Send off request */
955 ZERO_STRUCT(request);
956 ZERO_STRUCT(response);
958 STRCPY_RET(request.data.chauthtok.user, r_user);
959 STRCPY_RET(request.data.chauthtok.oldpass, oldpass);
960 STRCPY_RET(request.data.chauthtok.newpass, newpass);
962 if (*user == WB_AIX_ENCODED) {
963 free(r_user);
966 result = winbindd_request_response(NULL, WINBINDD_PAM_CHAUTHTOK,
967 &request, &response);
969 winbindd_free_response(&response);
971 if (result == NSS_STATUS_SUCCESS) {
972 errno = 0;
973 return 0;
976 errno = EINVAL;
977 return -1;
981 don't do any password strength testing for now
983 static int wb_aix_passwdrestrictions(char *user, char *newpass, char *oldpass,
984 char **message)
986 logit("passwdresrictions called for '%s'\n", user);
987 return 0;
991 static int wb_aix_passwdexpired(char *user, char **message)
993 logit("passwdexpired '%s'\n", user);
994 /* we should check the account bits here */
995 return 0;
1000 we can't return a crypt() password
1002 static char *wb_aix_getpasswd(char *user)
1004 logit("getpasswd '%s'\n", user);
1005 errno = ENOSYS;
1006 return NULL;
1010 this is called to update things like the last login time. We don't
1011 currently pass this onto the DC
1013 static int wb_aix_putentry(char *key, char *table, char *attributes[],
1014 attrval_t values[], int size)
1016 logit("putentry key='%s' table='%s' attrib='%s'\n",
1017 key, table, size>=1?attributes[0]:"<null>");
1018 errno = ENOSYS;
1019 return -1;
1022 static int wb_aix_commit(char *key, char *table)
1024 logit("commit key='%s' table='%s'\n");
1025 errno = ENOSYS;
1026 return -1;
1029 static int wb_aix_getgrusers(char *group, void *result, int type, int *size)
1031 logit("getgrusers group='%s'\n", group);
1032 errno = ENOSYS;
1033 return -1;
1037 #define DECL_METHOD(x) \
1038 int method_ ## x(void) \
1040 logit("UNIMPLEMENTED METHOD '%s'\n", #x); \
1041 errno = EINVAL; \
1042 return -1; \
1045 #if LOG_UNIMPLEMENTED_CALLS
1046 DECL_METHOD(delgroup);
1047 DECL_METHOD(deluser);
1048 DECL_METHOD(newgroup);
1049 DECL_METHOD(newuser);
1050 DECL_METHOD(putgrent);
1051 DECL_METHOD(putgrusers);
1052 DECL_METHOD(putpwent);
1053 DECL_METHOD(lock);
1054 DECL_METHOD(unlock);
1055 DECL_METHOD(getcred);
1056 DECL_METHOD(setcred);
1057 DECL_METHOD(deletecred);
1058 #endif
1060 int wb_aix_init(struct secmethod_table *methods)
1062 ZERO_STRUCTP(methods);
1064 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_VERSION
1065 methods->method_version = SECMETHOD_VERSION_520;
1066 #endif
1068 methods->method_getgrgid = wb_aix_getgrgid;
1069 methods->method_getgrnam = wb_aix_getgrnam;
1070 methods->method_getgrset = wb_aix_getgrset;
1071 methods->method_getpwnam = wb_aix_getpwnam;
1072 methods->method_getpwuid = wb_aix_getpwuid;
1073 methods->method_getentry = wb_aix_getentry;
1074 methods->method_open = wb_aix_open;
1075 methods->method_close = wb_aix_close;
1076 methods->method_normalize = wb_aix_normalize;
1077 methods->method_passwdexpired = wb_aix_passwdexpired;
1078 methods->method_putentry = wb_aix_putentry;
1079 methods->method_getpasswd = wb_aix_getpasswd;
1080 methods->method_authenticate = wb_aix_authenticate;
1081 methods->method_commit = wb_aix_commit;
1082 methods->method_chpass = wb_aix_chpass;
1083 methods->method_passwdrestrictions = wb_aix_passwdrestrictions;
1084 methods->method_getgracct = wb_aix_getgracct;
1085 methods->method_getgrusers = wb_aix_getgrusers;
1086 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
1087 methods->method_attrlist = wb_aix_attrlist;
1088 #endif
1090 #if LOG_UNIMPLEMENTED_CALLS
1091 methods->method_delgroup = method_delgroup;
1092 methods->method_deluser = method_deluser;
1093 methods->method_newgroup = method_newgroup;
1094 methods->method_newuser = method_newuser;
1095 methods->method_putgrent = method_putgrent;
1096 methods->method_putgrusers = method_putgrusers;
1097 methods->method_putpwent = method_putpwent;
1098 methods->method_lock = method_lock;
1099 methods->method_unlock = method_unlock;
1100 methods->method_getcred = method_getcred;
1101 methods->method_setcred = method_setcred;
1102 methods->method_deletecred = method_deletecred;
1103 #endif
1105 return AUTH_SUCCESS;