VERSION: Bump version up to Samba 4.17.5...
[Samba.git] / nsswitch / winbind_nss_aix.c
blobf1f00e92a761328eccb32baeeceadf55de08c814
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_request request = {
273 .wb_flags = WBFLAG_FROM_NSS,
275 struct winbindd_response response = {
276 .length = 0,
278 struct group *grp;
279 NSS_STATUS ret;
281 logit("getgrgid %d\n", gid);
283 request.data.gid = gid;
285 ret = winbindd_request_response(NULL, WINBINDD_GETGRGID,
286 &request, &response);
288 logit("getgrgid ret=%d\n", ret);
290 HANDLE_ERRORS(ret);
292 grp = fill_grent(&response.data.gr, response.extra_data.data);
294 winbindd_free_response(&response);
296 return grp;
299 /* take a group name and return a filled struct group */
300 static struct group *wb_aix_getgrnam(const char *name)
302 struct winbindd_request request = {
303 .wb_flags = WBFLAG_FROM_NSS,
305 struct winbindd_response response = {
306 .length = 0,
308 NSS_STATUS ret;
309 struct group *grp;
311 if (*name == WB_AIX_ENCODED) {
312 return wb_aix_getgrgid(decode_id(name));
315 logit("getgrnam '%s'\n", name);
317 STRCPY_RETNULL(request.data.groupname, name);
319 ret = winbindd_request_response(NULL, WINBINDD_GETGRNAM,
320 &request, &response);
322 HANDLE_ERRORS(ret);
324 grp = fill_grent(&response.data.gr, response.extra_data.data);
326 winbindd_free_response(&response);
328 return grp;
332 /* this call doesn't have to fill in the gr_mem, but we do anyway
333 for simplicity */
334 static struct group *wb_aix_getgracct(void *id, int type)
336 if (type == 1) {
337 return wb_aix_getgrnam((char *)id);
339 if (type == 0) {
340 return wb_aix_getgrgid(*(int *)id);
342 errno = EINVAL;
343 return NULL;
347 /* take a username and return a string containing a comma-separated
348 list of group id numbers to which the user belongs */
349 static char *wb_aix_getgrset(char *user)
351 struct winbindd_request request = {
352 .wb_flags = WBFLAG_FROM_NSS,
354 struct winbindd_response response = {
355 .length = 0,
357 NSS_STATUS ret;
358 int i, idx;
359 char *tmpbuf;
360 int num_gids;
361 gid_t *gid_list;
362 char *r_user = user;
364 if (*user == WB_AIX_ENCODED) {
365 r_user = decode_user(r_user);
366 if (!r_user) {
367 errno = ENOENT;
368 return NULL;
372 logit("getgrset '%s'\n", r_user);
374 STRCPY_RETNULL(request.data.username, r_user);
376 if (*user == WB_AIX_ENCODED) {
377 free(r_user);
380 ret = winbindd_request_response(NULL, WINBINDD_GETGROUPS,
381 &request, &response);
383 HANDLE_ERRORS(ret);
385 num_gids = response.data.num_entries;
386 gid_list = (gid_t *)response.extra_data.data;
388 /* allocate a space large enough to contruct the string */
389 tmpbuf = malloc(num_gids*12);
390 if (!tmpbuf) {
391 return NULL;
394 for (idx=i=0; i < num_gids-1; i++) {
395 idx += sprintf(tmpbuf+idx, "%u,", gid_list[i]);
397 idx += sprintf(tmpbuf+idx, "%u", gid_list[i]);
399 winbindd_free_response(&response);
401 return tmpbuf;
405 /* take a uid and return a filled struct passwd */
406 static struct passwd *wb_aix_getpwuid(uid_t uid)
408 struct winbindd_request request = {
409 .wb_flags = WBFLAG_FROM_NSS,
411 struct winbindd_response response = {
412 .length = 0,
414 NSS_STATUS ret;
415 struct passwd *pwd;
417 logit("getpwuid '%d'\n", uid);
419 request.data.uid = uid;
421 ret = winbindd_request_response(NULL, WINBINDD_GETPWUID,
422 &request, &response);
424 HANDLE_ERRORS(ret);
426 pwd = fill_pwent(&response.data.pw);
428 winbindd_free_response(&response);
430 logit("getpwuid gave ptr %p\n", pwd);
432 return pwd;
436 /* take a username and return a filled struct passwd */
437 static struct passwd *wb_aix_getpwnam(const char *name)
439 struct winbindd_request request = {
440 .wb_flags = WBFLAG_FROM_NSS,
442 struct winbindd_response response = {
443 .length = 0,
445 NSS_STATUS ret;
446 struct passwd *pwd;
448 if (*name == WB_AIX_ENCODED) {
449 return wb_aix_getpwuid(decode_id(name));
452 logit("getpwnam '%s'\n", name);
454 STRCPY_RETNULL(request.data.username, name);
456 ret = winbindd_request_response(NULL, WINBINDD_GETPWNAM,
457 &request, &response);
459 HANDLE_ERRORS(ret);
461 pwd = fill_pwent(&response.data.pw);
463 winbindd_free_response(&response);
465 logit("getpwnam gave ptr %p\n", pwd);
467 return pwd;
471 list users
473 static int wb_aix_lsuser(char *attributes[], attrval_t results[], int size)
475 NSS_STATUS ret;
476 struct winbindd_request request = {
477 .wb_flags = WBFLAG_FROM_NSS,
479 struct winbindd_response response = {
480 .length = 0,
482 int len;
483 char *s;
485 if (size != 1 || strcmp(attributes[0], S_USERS) != 0) {
486 logit("invalid lsuser op\n");
487 errno = EINVAL;
488 return -1;
491 ret = winbindd_request_response(NULL, WINBINDD_LIST_USERS,
492 &request, &response);
493 if (ret != 0) {
494 errno = EINVAL;
495 return -1;
498 len = strlen(response.extra_data.data);
500 s = malloc(len+2);
501 if (!s) {
502 winbindd_free_response(&response);
503 errno = ENOMEM;
504 return -1;
507 memcpy(s, response.extra_data.data, len+1);
509 replace_commas(s);
511 results[0].attr_un.au_char = s;
512 results[0].attr_flag = 0;
514 winbindd_free_response(&response);
516 return 0;
521 list groups
523 static int wb_aix_lsgroup(char *attributes[], attrval_t results[], int size)
525 NSS_STATUS ret;
526 struct winbindd_request request = {
527 .wb_flags = WBFLAG_FROM_NSS,
529 struct winbindd_response response = {
530 .length = 0,
532 int len;
533 char *s;
535 if (size != 1 || strcmp(attributes[0], S_GROUPS) != 0) {
536 logit("invalid lsgroup op\n");
537 errno = EINVAL;
538 return -1;
541 ret = winbindd_request_response(NULL, WINBINDD_LIST_GROUPS,
542 &request, &response);
543 if (ret != 0) {
544 errno = EINVAL;
545 return -1;
548 len = strlen(response.extra_data.data);
550 s = malloc(len+2);
551 if (!s) {
552 winbindd_free_response(&response);
553 errno = ENOMEM;
554 return -1;
557 memcpy(s, response.extra_data.data, len+1);
559 replace_commas(s);
561 results[0].attr_un.au_char = s;
562 results[0].attr_flag = 0;
564 winbindd_free_response(&response);
566 return 0;
570 static attrval_t pwd_to_group(struct passwd *pwd)
572 attrval_t r = {
573 .attr_flag = EINVAL,
575 struct group *grp = wb_aix_getgrgid(pwd->pw_gid);
577 if (grp != NULL) {
578 r.attr_flag = 0;
579 r.attr_un.au_char = strdup(grp->gr_name);
580 free_grp(grp);
583 return r;
586 static attrval_t pwd_to_groupsids(struct passwd *pwd)
588 attrval_t r = {
589 .attr_flag = EINVAL,
591 char *s, *p;
592 size_t mlen;
594 if ( (s = wb_aix_getgrset(pwd->pw_name)) == NULL ) {
595 r.attr_flag = EINVAL;
596 return r;
599 mlen = strlen(s)+2;
600 if ( (p = malloc(mlen)) == NULL ) {
601 r.attr_flag = ENOMEM;
602 return r;
605 strncpy(p, s, mlen);
606 p[mlen-1] = '\0';
607 replace_commas(p);
608 free(s);
610 r.attr_flag = 0;
611 r.attr_un.au_char = p;
613 return r;
616 static attrval_t pwd_to_sid(struct passwd *pwd)
618 char buf[(1 /* U/G */ + 10 /* 2^32 */ + 1 /* \n */) + 1] = { 0, };
619 int len;
620 struct winbindd_request request;
621 struct winbindd_response response;
622 NSS_STATUS result;
623 attrval_t r = {
624 .attr_flag = ENOENT,
627 len = snprintf(buf, sizeof(buf),
628 "U%"PRIu32"\n",
629 (uint32_t)pwd->pw_uid);
630 if (len >= sizeof(buf)) {
631 r = (attrval_t) {
632 .attr_flag = EINVAL,
634 return r;
637 request = (struct winbindd_request) {
638 .wb_flags = WBFLAG_FROM_NSS,
639 .extra_data.data = buf,
640 .extra_len = strlen(buf)+1,
642 response = (struct winbindd_response) {
643 .length = 0,
646 result = winbindd_request_response(NULL, WINBINDD_XIDS_TO_SIDS,
647 &request, &response);
648 if (result == NSS_STATUS_SUCCESS) {
649 r.attr_flag = 0;
650 r.attr_un.au_char = strdup(response.data.sid.sid);
653 return r;
656 static int wb_aix_user_attrib(const char *key, char *attributes[],
657 attrval_t results[], int size)
659 struct passwd *pwd;
660 int i;
662 pwd = wb_aix_getpwnam(key);
663 if (!pwd) {
664 errno = ENOENT;
665 return -1;
668 for (i=0;i<size;i++) {
669 results[i] = (attrval_t) {
670 .attr_flag = 0,
673 if (strcmp(attributes[i], S_ID) == 0) {
674 results[i].attr_un.au_int = pwd->pw_uid;
675 #ifdef _AIXVERSION_530
676 } else if (strcmp(attributes[i], S_PGID) == 0) {
677 results[i].attr_un.au_int = pwd->pw_gid;
678 #endif
679 } else if (strcmp(attributes[i], S_PWD) == 0) {
680 results[i].attr_un.au_char = strdup(pwd->pw_passwd);
681 } else if (strcmp(attributes[i], S_HOME) == 0) {
682 results[i].attr_un.au_char = strdup(pwd->pw_dir);
683 } else if (strcmp(attributes[i], S_SHELL) == 0) {
684 results[i].attr_un.au_char = strdup(pwd->pw_shell);
685 } else if (strcmp(attributes[i], S_REGISTRY) == 0) {
686 results[i].attr_un.au_char = strdup("WINBIND");
687 } else if (strcmp(attributes[i], S_GECOS) == 0) {
688 results[i].attr_un.au_char = strdup(pwd->pw_gecos);
689 } else if (strcmp(attributes[i], S_PGRP) == 0) {
690 results[i] = pwd_to_group(pwd);
691 } else if (strcmp(attributes[i], S_GROUPS) == 0) {
692 results[i] = pwd_to_groupsids(pwd);
693 } else if (strcmp(attributes[i], S_GROUPSIDS) == 0) {
694 results[i] = pwd_to_groupsids(pwd);
695 } else if (strcmp(attributes[i], "SID") == 0) {
696 results[i] = pwd_to_sid(pwd);
697 } else {
698 logit("Unknown user attribute '%s'\n", attributes[i]);
699 results[i].attr_flag = EINVAL;
703 free_pwd(pwd);
705 return 0;
708 static int wb_aix_group_attrib(const char *key, char *attributes[],
709 attrval_t results[], int size)
711 struct group *grp;
712 int i;
714 grp = wb_aix_getgrnam(key);
715 if (!grp) {
716 errno = ENOENT;
717 return -1;
720 for (i=0;i<size;i++) {
721 results[i].attr_flag = 0;
723 if (strcmp(attributes[i], S_PWD) == 0) {
724 results[i].attr_un.au_char = strdup(grp->gr_passwd);
725 } else if (strcmp(attributes[i], S_ID) == 0) {
726 results[i].attr_un.au_int = grp->gr_gid;
727 } else {
728 logit("Unknown group attribute '%s'\n", attributes[i]);
729 results[i].attr_flag = EINVAL;
733 free_grp(grp);
735 return 0;
740 called for user/group enumerations
742 static int wb_aix_getentry(char *key, char *table, char *attributes[],
743 attrval_t results[], int size)
745 logit("Got getentry with key='%s' table='%s' size=%d attributes[0]='%s'\n",
746 key, table, size, attributes[0]);
748 if (strcmp(key, "ALL") == 0 &&
749 strcmp(table, "user") == 0) {
750 return wb_aix_lsuser(attributes, results, size);
753 if (strcmp(key, "ALL") == 0 &&
754 strcmp(table, "group") == 0) {
755 return wb_aix_lsgroup(attributes, results, size);
758 if (strcmp(table, "user") == 0) {
759 return wb_aix_user_attrib(key, attributes, results, size);
762 if (strcmp(table, "group") == 0) {
763 return wb_aix_group_attrib(key, attributes, results, size);
766 logit("Unknown getentry operation key='%s' table='%s'\n", key, table);
768 errno = ENOSYS;
769 return -1;
775 called to start the backend
777 static void *wb_aix_open(const char *name, const char *domain, int mode, char *options)
779 if (strstr(options, "debug")) {
780 debug_enabled = 1;
782 logit("open name='%s' mode=%d domain='%s' options='%s'\n", name, domain,
783 mode, options);
784 return NULL;
787 static void wb_aix_close(void *token)
789 logit("close\n");
790 return;
793 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
795 return a list of additional attributes supported by the backend
797 static attrlist_t **wb_aix_attrlist(void)
799 /* pretty confusing but we are allocating the array of pointers
800 and the structures we'll be pointing to all at once. So
801 you need N+1 pointers and N structures. */
803 attrlist_t **ret = NULL;
804 attrlist_t *offset = NULL;
805 int i;
806 int n;
807 size_t size;
809 struct attr_types {
810 const char *name;
811 int flags;
812 int type;
813 } attr_list[] = {
814 /* user attributes */
815 {S_ID, AL_USERATTR, SEC_INT},
816 {S_PGRP, AL_USERATTR, SEC_CHAR},
817 {S_HOME, AL_USERATTR, SEC_CHAR},
818 {S_SHELL, AL_USERATTR, SEC_CHAR},
819 #ifdef _AIXVERSION_530
820 {S_PGID, AL_USERATTR, SEC_INT},
821 #endif
822 {S_GECOS, AL_USERATTR, SEC_CHAR},
823 {S_SHELL, AL_USERATTR, SEC_CHAR},
824 {S_PGRP, AL_USERATTR, SEC_CHAR},
825 {S_GROUPS, AL_USERATTR, SEC_LIST},
826 {S_GROUPSIDS, AL_USERATTR, SEC_LIST},
827 {"SID", AL_USERATTR, SEC_CHAR},
829 /* group attributes */
830 {S_ID, AL_GROUPATTR, SEC_INT}
833 logit("method attrlist called\n");
835 n = sizeof(attr_list) / sizeof(struct attr_types);
836 size = ((n + 1) * sizeof(attrlist_t *));
838 if ( (ret = malloc( size )) == NULL ) {
839 errno = ENOMEM;
840 return NULL;
843 /* offset to where the structures start in the buffer */
845 offset = (attrlist_t *)(ret + n);
847 /* now loop over the user_attr_list[] array and add
848 all the members */
850 for ( i=0; i<n; i++ ) {
851 attrlist_t *a = malloc(sizeof(attrlist_t));
853 if ( !a ) {
854 /* this is bad. Just bail */
855 return NULL;
858 a->al_name = strdup(attr_list[i].name);
859 a->al_flags = attr_list[i].flags;
860 a->al_type = attr_list[i].type;
862 ret[i] = a;
864 ret[n] = NULL;
866 return ret;
868 #endif
872 turn a long username into a short one. Needed to cope with the 8 char
873 username limit in AIX 5.2 and below
875 static int wb_aix_normalize(char *longname, char *shortname)
877 struct passwd *pwd;
879 logit("normalize '%s'\n", longname);
881 /* automatically cope with AIX 5.3 with longer usernames
882 when it comes out */
883 if (S_NAMELEN > strlen(longname)) {
884 strncpy(shortname, longname, S_NAMELEN);
885 shortname[S_NAMELEN-1] = '\0';
886 return 1;
889 pwd = wb_aix_getpwnam(longname);
890 if (!pwd) {
891 errno = ENOENT;
892 return 0;
895 sprintf(shortname, "%c%07u", WB_AIX_ENCODED, pwd->pw_uid);
897 free_pwd(pwd);
899 return 1;
904 authenticate a user
906 static int wb_aix_authenticate(char *user, char *pass,
907 int *reenter, char **message)
909 struct winbindd_request request = {
910 .wb_flags = WBFLAG_FROM_NSS,
912 struct winbindd_response response = {
913 .length = 0,
915 NSS_STATUS result;
916 char *r_user = user;
918 logit("authenticate '%s' response='%s'\n", user, pass);
920 *reenter = 0;
921 *message = NULL;
923 /* Send off request */
924 if (*user == WB_AIX_ENCODED) {
925 r_user = decode_user(r_user);
926 if (!r_user) {
927 return AUTH_NOTFOUND;
931 STRCPY_RET(request.data.auth.user, r_user);
932 STRCPY_RET(request.data.auth.pass, pass);
934 if (*user == WB_AIX_ENCODED) {
935 free(r_user);
938 result = winbindd_request_response(NULL, WINBINDD_PAM_AUTH,
939 &request, &response);
941 winbindd_free_response(&response);
943 logit("auth result %d for '%s'\n", result, user);
945 if (result == NSS_STATUS_SUCCESS) {
946 errno = 0;
947 return AUTH_SUCCESS;
950 return AUTH_FAILURE;
955 change a user password
957 static int wb_aix_chpass(char *user, char *oldpass, char *newpass, char **message)
959 struct winbindd_request request = {
960 .wb_flags = WBFLAG_FROM_NSS,
962 struct winbindd_response response = {
963 .length = 0,
965 NSS_STATUS result;
966 char *r_user = user;
968 if (*user == WB_AIX_ENCODED) {
969 r_user = decode_user(r_user);
970 if (!r_user) {
971 errno = ENOENT;
972 return -1;
976 logit("chpass '%s' old='%s' new='%s'\n", r_user, oldpass, newpass);
978 *message = NULL;
980 /* Send off request */
981 STRCPY_RET(request.data.chauthtok.user, r_user);
982 STRCPY_RET(request.data.chauthtok.oldpass, oldpass);
983 STRCPY_RET(request.data.chauthtok.newpass, newpass);
985 if (*user == WB_AIX_ENCODED) {
986 free(r_user);
989 result = winbindd_request_response(NULL, WINBINDD_PAM_CHAUTHTOK,
990 &request, &response);
992 winbindd_free_response(&response);
994 if (result == NSS_STATUS_SUCCESS) {
995 errno = 0;
996 return 0;
999 errno = EINVAL;
1000 return -1;
1004 don't do any password strength testing for now
1006 static int wb_aix_passwdrestrictions(char *user, char *newpass, char *oldpass,
1007 char **message)
1009 logit("passwdresrictions called for '%s'\n", user);
1010 return 0;
1014 static int wb_aix_passwdexpired(char *user, char **message)
1016 logit("passwdexpired '%s'\n", user);
1017 /* we should check the account bits here */
1018 return 0;
1023 we can't return a crypt() password
1025 static char *wb_aix_getpasswd(char *user)
1027 logit("getpasswd '%s'\n", user);
1028 errno = ENOSYS;
1029 return NULL;
1033 this is called to update things like the last login time. We don't
1034 currently pass this onto the DC
1036 static int wb_aix_putentry(char *key, char *table, char *attributes[],
1037 attrval_t values[], int size)
1039 logit("putentry key='%s' table='%s' attrib='%s'\n",
1040 key, table, size>=1?attributes[0]:"<null>");
1041 errno = ENOSYS;
1042 return -1;
1045 static int wb_aix_commit(char *key, char *table)
1047 logit("commit key='%s' table='%s'\n");
1048 errno = ENOSYS;
1049 return -1;
1052 static int wb_aix_getgrusers(char *group, void *result, int type, int *size)
1054 logit("getgrusers group='%s'\n", group);
1055 errno = ENOSYS;
1056 return -1;
1060 #define DECL_METHOD(x) \
1061 int method_ ## x(void) \
1063 logit("UNIMPLEMENTED METHOD '%s'\n", #x); \
1064 errno = EINVAL; \
1065 return -1; \
1068 #if LOG_UNIMPLEMENTED_CALLS
1069 DECL_METHOD(delgroup);
1070 DECL_METHOD(deluser);
1071 DECL_METHOD(newgroup);
1072 DECL_METHOD(newuser);
1073 DECL_METHOD(putgrent);
1074 DECL_METHOD(putgrusers);
1075 DECL_METHOD(putpwent);
1076 DECL_METHOD(lock);
1077 DECL_METHOD(unlock);
1078 DECL_METHOD(getcred);
1079 DECL_METHOD(setcred);
1080 DECL_METHOD(deletecred);
1081 #endif
1083 int wb_aix_init(struct secmethod_table *methods)
1085 ZERO_STRUCTP(methods);
1087 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_VERSION
1088 methods->method_version = SECMETHOD_VERSION_520;
1089 #endif
1091 methods->method_getgrgid = wb_aix_getgrgid;
1092 methods->method_getgrnam = wb_aix_getgrnam;
1093 methods->method_getgrset = wb_aix_getgrset;
1094 methods->method_getpwnam = wb_aix_getpwnam;
1095 methods->method_getpwuid = wb_aix_getpwuid;
1096 methods->method_getentry = wb_aix_getentry;
1097 methods->method_open = wb_aix_open;
1098 methods->method_close = wb_aix_close;
1099 methods->method_normalize = wb_aix_normalize;
1100 methods->method_passwdexpired = wb_aix_passwdexpired;
1101 methods->method_putentry = wb_aix_putentry;
1102 methods->method_getpasswd = wb_aix_getpasswd;
1103 methods->method_authenticate = wb_aix_authenticate;
1104 methods->method_commit = wb_aix_commit;
1105 methods->method_chpass = wb_aix_chpass;
1106 methods->method_passwdrestrictions = wb_aix_passwdrestrictions;
1107 methods->method_getgracct = wb_aix_getgracct;
1108 methods->method_getgrusers = wb_aix_getgrusers;
1109 #ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST
1110 methods->method_attrlist = wb_aix_attrlist;
1111 #endif
1113 #if LOG_UNIMPLEMENTED_CALLS
1114 methods->method_delgroup = method_delgroup;
1115 methods->method_deluser = method_deluser;
1116 methods->method_newgroup = method_newgroup;
1117 methods->method_newuser = method_newuser;
1118 methods->method_putgrent = method_putgrent;
1119 methods->method_putgrusers = method_putgrusers;
1120 methods->method_putpwent = method_putpwent;
1121 methods->method_lock = method_lock;
1122 methods->method_unlock = method_unlock;
1123 methods->method_getcred = method_getcred;
1124 methods->method_setcred = method_setcred;
1125 methods->method_deletecred = method_deletecred;
1126 #endif
1128 return AUTH_SUCCESS;