From 467a58af346b30291b69b5d8da7f1b21d518fc1d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 29 Jan 2004 06:28:27 +0000 Subject: [PATCH] updated the head branch as well --- source/nsswitch/winbind_nss_aix.c | 926 ++++++++++++++++++++++++++++++++------ 1 file changed, 778 insertions(+), 148 deletions(-) diff --git a/source/nsswitch/winbind_nss_aix.c b/source/nsswitch/winbind_nss_aix.c index 3d2f01b93c6..3e00e54e5c4 100644 --- a/source/nsswitch/winbind_nss_aix.c +++ b/source/nsswitch/winbind_nss_aix.c @@ -1,12 +1,12 @@ /* Unix SMB/CIFS implementation. - AIX loadable authentication module, providing identification - routines against Samba winbind/Windows NT Domain + AIX loadable authentication module, providing identification and + authentication routines against Samba winbind/Windows NT Domain Copyright (C) Tim Potter 2003 Copyright (C) Steve Roylance 2003 - Copyright (C) Andrew Tridgell 2003 + Copyright (C) Andrew Tridgell 2003-2004 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -25,9 +25,24 @@ */ /* + + To install this module copy nsswitch/WINBIND to /usr/lib/security and add + "WINBIND" in /usr/lib/security/methods.cfg and /etc/security/user + + Note that this module also provides authentication and password + changing routines, so you do not need to install the winbind PAM + module. + see http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/aixprggd/kernextc/sec_load_mod.htm - for information in the interface that this module implements + for some information in the interface that this module implements + + Many thanks to Julianne Haugh for explaining some of the finer + details of this interface. + + To debug this module use uess_test.c (which you can get from tridge) + or set "options=debug" in /usr/lib/security/methods.cfg + */ #include @@ -38,79 +53,24 @@ #include "winbind_client.h" -/* - the documentation doesn't say so, but experimentation shows that all - of the functions need to return static data, and the area can be - freed only when the same function is called again, or the close - method is called on the module. Note that this matches the standard - behaviour of functions like getpwnam(). - - The most puzzling thing about this AIX interface is that it seems to - offer no way of providing a user or group enumeration method. You - can find out any amount of detail about a user or group once you - know the name, but you can't obtain a list of those names. If anyone - does find out how to do this then please let me know (yes, I should - be able to find out as I work for IBM, and this is an IBM interface, - but finding the right person to ask is a mammoth task!) - - tridge@samba.org October 2003 -*/ - +#define WB_AIX_ENCODED '_' -/* - each function uses one of the following lists of memory, declared - static in each backend method. This allows the function to destroy - the memory when that backend is called next time -*/ -struct mem_list { - struct mem_list *next, *prev; - void *p; -}; +static int debug_enabled; -/* allocate some memory on a mem_list */ -static void *list_alloc(struct mem_list **list, size_t size) +static void logit(const char *format, ...) { - struct mem_list *m; - m = malloc(sizeof(*m)); - if (!m) { - errno = ENOMEM; - return NULL; - } - m->p = malloc(size); - if (!m->p) { - errno = ENOMEM; - free(m); - return NULL; - } - m->next = *list; - m->prev = NULL; - if (*list) { - (*list)->prev = m; + va_list ap; + FILE *f; + if (!debug_enabled) { + return; } - (*list) = m; - return m->p; -} - -/* duplicate a string using list_alloc() */ -static char *list_strdup(struct mem_list **list, const char *s) -{ - char *ret = list_alloc(list, strlen(s)+1); - if (!ret) return NULL; - strcpy(ret, s); - return ret; -} - -/* destroy a mem_list */ -static void list_destory(struct mem_list **list) -{ - struct mem_list *m, *next; - for (m=*list; m; m=next) { - next = m->next; - free(m->p); - free(m); - } - (*list) = NULL; + f = fopen("/tmp/WINBIND_DEBUG.log", "a"); + if (!f) return; + va_start(ap, format); + vfprintf(f, format, ap); + va_end(ap); + fclose(f); } @@ -124,58 +84,147 @@ static void list_destory(struct mem_list **list) } \ } while (0) -/* - fill a struct passwd from a winbindd_pw struct, using memory from a mem_list +#define STRCPY_RET(dest, src) \ +do { \ + if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return -1; } \ + strcpy(dest, src); \ +} while (0) + +#define STRCPY_RETNULL(dest, src) \ +do { \ + if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return NULL; } \ + strcpy(dest, src); \ +} while (0) + + +/* free a passwd structure */ +static void free_pwd(struct passwd *pwd) +{ + free(pwd->pw_name); + free(pwd->pw_passwd); + free(pwd->pw_gecos); + free(pwd->pw_dir); + free(pwd->pw_shell); + free(pwd); +} + +/* free a group structure */ +static void free_grp(struct group *grp) +{ + int i; + + free(grp->gr_name); + free(grp->gr_passwd); + + if (!grp->gr_mem) { + free(grp); + return; + } + + for (i=0; grp->gr_mem[i]; i++) { + free(grp->gr_mem[i]); + } + + free(grp->gr_mem); + free(grp); +} + + +/* replace commas with nulls, and null terminate */ +static void replace_commas(char *s) +{ + char *p, *p0=s; + for (p=strchr(s, ','); p; p = strchr(p+1, ',')) { + *p=0; + p0 = p+1; + } + + p0[strlen(p0)+1] = 0; +} + + +/* the decode_*() routines are used to cope with the fact that AIX 5.2 + and below cannot handle user or group names longer than 8 + characters in some interfaces. We use the normalize method to + provide a mapping to a username that fits, by using the form '_UID' + or '_GID'. + + this only works if you can guarantee that the WB_AIX_ENCODED char + is not used as the first char of any other username */ -static struct passwd *fill_pwent(struct mem_list **list, struct winbindd_pw *pw) +static unsigned decode_id(const char *name) { - struct passwd *result; + unsigned id; + sscanf(name+1, "%u", &id); + return id; +} - if (!(result = list_alloc(list, sizeof(struct passwd)))) { +static char *decode_user(const char *name) +{ + struct passwd *pwd; + unsigned id; + char *ret; + static struct passwd *wb_aix_getpwuid(uid_t uid); + + sscanf(name+1, "%u", &id); + pwd = wb_aix_getpwuid(id); + if (!pwd) { return NULL; } + ret = strdup(pwd->pw_name); - ZERO_STRUCTP(result); + free_pwd(pwd); + + logit("decoded '%s' -> '%s'\n", name, ret); + + return ret; +} - result->pw_uid = pw->pw_uid; - result->pw_gid = pw->pw_gid; - /* strings */ - if ((result->pw_name = list_strdup(list, pw->pw_name)) == NULL || - (result->pw_passwd = list_strdup(list, pw->pw_passwd)) == NULL || - (result->pw_gecos = list_strdup(list, pw->pw_gecos)) == NULL || - (result->pw_dir = list_strdup(list, pw->pw_dir)) == NULL || - (result->pw_shell = list_strdup(list, pw->pw_shell)) == NULL) { +/* + fill a struct passwd from a winbindd_pw struct, allocating as a single block +*/ +static struct passwd *fill_pwent(struct winbindd_pw *pw) +{ + struct passwd *result; + + result = calloc(1, sizeof(struct passwd)); + if (!result) { + errno = ENOMEM; return NULL; } + + result->pw_uid = pw->pw_uid; + result->pw_gid = pw->pw_gid; + result->pw_name = strdup(pw->pw_name); + result->pw_passwd = strdup(pw->pw_passwd); + result->pw_gecos = strdup(pw->pw_gecos); + result->pw_dir = strdup(pw->pw_dir); + result->pw_shell = strdup(pw->pw_shell); return result; } /* - fill a struct group from a winbindd_pw struct, using memory from a mem_list + fill a struct group from a winbindd_pw struct, allocating as a single block */ -static struct group *fill_grent(struct mem_list **list, struct winbindd_gr *gr, char *gr_mem) +static struct group *fill_grent(struct winbindd_gr *gr, char *gr_mem) { int i; - char *tst; struct group *result; - char *name, *p; + char *p, *name; - if (!(result = list_alloc(list, sizeof(struct group)))) { + result = calloc(1, sizeof(struct group)); + if (!result) { + errno = ENOMEM; return NULL; } - ZERO_STRUCTP(result); - result->gr_gid = gr->gr_gid; - /* Group name */ - if ((result->gr_name = list_strdup(list, gr->gr_name)) == NULL || - (result->gr_passwd = list_strdup(list, gr->gr_passwd)) == NULL) { - return NULL; - } + result->gr_name = strdup(gr->gr_name); + result->gr_passwd = strdup(gr->gr_passwd); /* Group membership */ if ((gr->num_gr_mem < 0) || !gr_mem) { @@ -187,30 +236,26 @@ static struct group *fill_grent(struct mem_list **list, struct winbindd_gr *gr, return result; } - tst = list_alloc(list, (gr->num_gr_mem + 1) * sizeof(char *)); - if (!tst) { + result->gr_mem = (char **)malloc(sizeof(char *) * (gr->num_gr_mem+1)); + if (!result->gr_mem) { + errno = ENOMEM; return NULL; } - - result->gr_mem = (char **)tst; /* Start looking at extra data */ i=0; for (name = strtok_r(gr_mem, ",", &p); name; name = strtok_r(NULL, ",", &p)) { - if (i >= gr->num_gr_mem) { - return NULL; - } - (result->gr_mem)[i] = list_strdup(list, name); - if ((result->gr_mem)[i] == NULL) { - return NULL; + if (i == gr->num_gr_mem) { + break; } + result->gr_mem[i] = strdup(name); i++; } /* Terminate list */ - (result->gr_mem)[i] = NULL; + result->gr_mem[i] = NULL; return result; } @@ -220,13 +265,12 @@ static struct group *fill_grent(struct mem_list **list, struct winbindd_gr *gr, /* take a group id and return a filled struct group */ static struct group *wb_aix_getgrgid(gid_t gid) { - static struct mem_list *list; struct winbindd_response response; struct winbindd_request request; struct group *grp; NSS_STATUS ret; - list_destory(&list); + logit("getgrgid %d\n", gid); ZERO_STRUCT(response); ZERO_STRUCT(request); @@ -235,9 +279,11 @@ static struct group *wb_aix_getgrgid(gid_t gid) ret = winbindd_request(WINBINDD_GETGRGID, &request, &response); + logit("getgrgid ret=%d\n", ret); + HANDLE_ERRORS(ret); - grp = fill_grent(&list, &response.data.gr, response.extra_data); + grp = fill_grent(&response.data.gr, response.extra_data); free_response(&response); @@ -247,28 +293,27 @@ static struct group *wb_aix_getgrgid(gid_t gid) /* take a group name and return a filled struct group */ static struct group *wb_aix_getgrnam(const char *name) { - static struct mem_list *list; struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; struct group *grp; - list_destory(&list); + if (*name == WB_AIX_ENCODED) { + return wb_aix_getgrgid(decode_id(name)); + } + + logit("getgrnam '%s'\n", name); ZERO_STRUCT(response); ZERO_STRUCT(request); - if (strlen(name)+1 > sizeof(request.data.groupname)) { - errno = EINVAL; - return NULL; - } - strcpy(request.data.groupname, name); + STRCPY_RETNULL(request.data.groupname, name); ret = winbindd_request(WINBINDD_GETGRNAM, &request, &response); HANDLE_ERRORS(ret); - grp = fill_grent(&list, &response.data.gr, response.extra_data); + grp = fill_grent(&response.data.gr, response.extra_data); free_response(&response); @@ -276,11 +321,25 @@ static struct group *wb_aix_getgrnam(const char *name) } +/* this call doesn't have to fill in the gr_mem, but we do anyway + for simplicity */ +static struct group *wb_aix_getgracct(void *id, int type) +{ + if (type == 1) { + return wb_aix_getgrnam((char *)id); + } + if (type == 0) { + return wb_aix_getgrgid(*(int *)id); + } + errno = EINVAL; + return NULL; +} + + /* take a username and return a string containing a comma-separated list of group id numbers to which the user belongs */ static char *wb_aix_getgrset(char *user) { - static struct mem_list *list; struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; @@ -288,14 +347,23 @@ static char *wb_aix_getgrset(char *user) char *tmpbuf; int num_gids; gid_t *gid_list; + char *r_user = user; - list_destory(&list); + if (*user == WB_AIX_ENCODED) { + r_user = decode_user(r_user); + if (!r_user) { + errno = ENOENT; + return NULL; + } + } - if (strlen(user)+1 > sizeof(request.data.username)) { - errno = EINVAL; - return NULL; + logit("getgrset '%s'\n", r_user); + + STRCPY_RETNULL(request.data.username, r_user); + + if (*user == WB_AIX_ENCODED) { + free(r_user); } - strcpy(request.data.username, user); ret = winbindd_request(WINBINDD_GETGROUPS, &request, &response); @@ -305,7 +373,7 @@ static char *wb_aix_getgrset(char *user) gid_list = (gid_t *)response.extra_data; /* allocate a space large enough to contruct the string */ - tmpbuf = list_alloc(&list, num_gids*12); + tmpbuf = malloc(num_gids*12); if (!tmpbuf) { return NULL; } @@ -324,13 +392,13 @@ static char *wb_aix_getgrset(char *user) /* take a uid and return a filled struct passwd */ static struct passwd *wb_aix_getpwuid(uid_t uid) { - static struct mem_list *list; struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; + struct passwd *pwd; + + logit("getpwuid '%d'\n", uid); - list_destory(&list); - ZERO_STRUCT(response); ZERO_STRUCT(request); @@ -340,49 +408,611 @@ static struct passwd *wb_aix_getpwuid(uid_t uid) HANDLE_ERRORS(ret); - return fill_pwent(&list, &response.data.pw); + pwd = fill_pwent(&response.data.pw); + + free_response(&response); + + logit("getpwuid gave ptr %p\n", pwd); + + return pwd; } /* take a username and return a filled struct passwd */ static struct passwd *wb_aix_getpwnam(const char *name) { - static struct mem_list *list; struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; + struct passwd *pwd; + + if (*name == WB_AIX_ENCODED) { + return wb_aix_getpwuid(decode_id(name)); + } + + logit("getpwnam '%s'\n", name); - list_destory(&list); - ZERO_STRUCT(response); ZERO_STRUCT(request); - if (strlen(name)+1 > sizeof(request.data.username)) { + STRCPY_RETNULL(request.data.username, name); + + ret = winbindd_request(WINBINDD_GETPWNAM, &request, &response); + + HANDLE_ERRORS(ret); + + pwd = fill_pwent(&response.data.pw); + + free_response(&response); + + logit("getpwnam gave ptr %p\n", pwd); + + return pwd; +} + +/* + list users +*/ +static int wb_aix_lsuser(char *attributes[], attrval_t results[], int size) +{ + NSS_STATUS ret; + struct winbindd_request request; + struct winbindd_response response; + int len; + char *s; + + if (size != 1 || strcmp(attributes[0], S_USERS) != 0) { + logit("invalid lsuser op\n"); errno = EINVAL; - return NULL; + return -1; } - strcpy(request.data.username, name); + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + ret = winbindd_request(WINBINDD_LIST_USERS, &request, &response); + if (ret != 0) { + errno = EINVAL; + return -1; + } - ret = winbindd_request(WINBINDD_GETPWNAM, &request, &response); + len = strlen(response.extra_data); - HANDLE_ERRORS(ret); + s = malloc(len+2); + if (!s) { + free_response(&response); + errno = ENOMEM; + return -1; + } + + memcpy(s, response.extra_data, len+1); + + replace_commas(s); + + results[0].attr_un.au_char = s; + results[0].attr_flag = 0; + + free_response(&response); + + return 0; +} + + +/* + list groups +*/ +static int wb_aix_lsgroup(char *attributes[], attrval_t results[], int size) +{ + NSS_STATUS ret; + struct winbindd_request request; + struct winbindd_response response; + int len; + char *s; + + if (size != 1 || strcmp(attributes[0], S_GROUPS) != 0) { + logit("invalid lsgroup op\n"); + errno = EINVAL; + return -1; + } + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + ret = winbindd_request(WINBINDD_LIST_GROUPS, &request, &response); + if (ret != 0) { + errno = EINVAL; + return -1; + } + + len = strlen(response.extra_data); + + s = malloc(len+2); + if (!s) { + free_response(&response); + errno = ENOMEM; + return -1; + } + + memcpy(s, response.extra_data, len+1); + + replace_commas(s); + + results[0].attr_un.au_char = s; + results[0].attr_flag = 0; + + free_response(&response); - return fill_pwent(&list, &response.data.pw); + return 0; +} + + +static attrval_t pwd_to_group(struct passwd *pwd) +{ + attrval_t r; + struct group *grp = wb_aix_getgrgid(pwd->pw_gid); + + if (!grp) { + r.attr_flag = EINVAL; + } else { + r.attr_flag = 0; + r.attr_un.au_char = strdup(grp->gr_name); + free_grp(grp); + } + + return r; +} + +static attrval_t pwd_to_groupsids(struct passwd *pwd) +{ + attrval_t r; + char *s, *p; + + s = wb_aix_getgrset(pwd->pw_name); + if (!s) { + r.attr_flag = EINVAL; + return r; + } + + p = malloc(strlen(s)+2); + if (!p) { + r.attr_flag = ENOMEM; + return r; + } + + strcpy(p, s); + replace_commas(p); + free(s); + + r.attr_un.au_char = p; + + return r; +} + +static attrval_t pwd_to_sid(struct passwd *pwd) +{ + struct winbindd_request request; + struct winbindd_response response; + attrval_t r; + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + request.data.uid = pwd->pw_uid; + + if (winbindd_request(WINBINDD_UID_TO_SID, &request, &response) != + NSS_STATUS_SUCCESS) { + r.attr_flag = ENOENT; + } else { + r.attr_flag = 0; + r.attr_un.au_char = strdup(response.data.sid.sid); + } + + return r; +} + +static int wb_aix_user_attrib(const char *key, char *attributes[], + attrval_t results[], int size) +{ + struct passwd *pwd; + int i; + + pwd = wb_aix_getpwnam(key); + if (!pwd) { + errno = ENOENT; + return -1; + } + + for (i=0;ipw_uid; + } else if (strcmp(attributes[i], S_PWD) == 0) { + results[i].attr_un.au_char = strdup(pwd->pw_passwd); + } else if (strcmp(attributes[i], S_HOME) == 0) { + results[i].attr_un.au_char = strdup(pwd->pw_dir); + } else if (strcmp(attributes[0], S_SHELL) == 0) { + results[i].attr_un.au_char = strdup(pwd->pw_shell); + } else if (strcmp(attributes[0], S_REGISTRY) == 0) { + results[i].attr_un.au_char = strdup("WINBIND"); + } else if (strcmp(attributes[0], S_GECOS) == 0) { + results[i].attr_un.au_char = strdup(pwd->pw_gecos); + } else if (strcmp(attributes[0], S_PGRP) == 0) { + results[i] = pwd_to_group(pwd); + } else if (strcmp(attributes[0], S_GECOS) == 0) { + results[i].attr_un.au_char = strdup(pwd->pw_gecos); + } else if (strcmp(attributes[0], S_GROUPSIDS) == 0) { + results[i] = pwd_to_groupsids(pwd); + } else if (strcmp(attributes[0], "SID") == 0) { + results[i] = pwd_to_sid(pwd); + } else { + logit("Unknown user attribute '%s'\n", attributes[i]); + results[i].attr_flag = EINVAL; + } + } + + free_pwd(pwd); + + return 0; +} + +static int wb_aix_group_attrib(const char *key, char *attributes[], + attrval_t results[], int size) +{ + struct group *grp; + int i; + + grp = wb_aix_getgrnam(key); + if (!grp) { + errno = ENOENT; + return -1; + } + + for (i=0;igr_passwd); + } else if (strcmp(attributes[i], S_ID) == 0) { + results[i].attr_un.au_int = grp->gr_gid; + } else { + logit("Unknown group attribute '%s'\n", attributes[i]); + results[i].attr_flag = EINVAL; + } + } + + free_grp(grp); + + return 0; } + +/* + called for user/group enumerations +*/ +static int wb_aix_getentry(char *key, char *table, char *attributes[], + attrval_t results[], int size) +{ + logit("Got getentry with key='%s' table='%s' size=%d attributes[0]='%s'\n", + key, table, size, attributes[0]); + + if (strcmp(key, "ALL") == 0 && + strcmp(table, "user") == 0) { + return wb_aix_lsuser(attributes, results, size); + } + + if (strcmp(key, "ALL") == 0 && + strcmp(table, "group") == 0) { + return wb_aix_lsgroup(attributes, results, size); + } + + if (strcmp(table, "user") == 0) { + return wb_aix_user_attrib(key, attributes, results, size); + } + + if (strcmp(table, "group") == 0) { + return wb_aix_group_attrib(key, attributes, results, size); + } + + logit("Unknown getentry operation key='%s' table='%s'\n", key, table); + + errno = ENOSYS; + return -1; +} + + + +/* + called to start the backend +*/ +static void *wb_aix_open(const char *name, const char *domain, int mode, char *options) +{ + if (strstr(options, "debug")) { + debug_enabled = 1; + } + logit("open name='%s' mode=%d domain='%s' options='%s'\n", name, domain, + mode, options); + return NULL; +} + +static void wb_aix_close(void *token) +{ + logit("close\n"); + return; +} + +/* + return a list of additional attributes supported by the backend +*/ +static attrlist_t **wb_aix_attrlist(void) +{ + attrlist_t **ret; + logit("method attrlist called\n"); + ret = malloc(2*sizeof(attrlist_t *) + sizeof(attrlist_t)); + if (!ret) { + errno = ENOMEM; + return NULL; + } + + ret[0] = (attrlist_t *)(ret+2); + + /* just one extra attribute - the windows SID */ + ret[0]->al_name = strdup("SID"); + ret[0]->al_flags = AL_USERATTR; + ret[0]->al_type = SEC_CHAR; + ret[1] = NULL; + + return ret; +} + + +/* + turn a long username into a short one. Needed to cope with the 8 char + username limit in AIX 5.2 and below +*/ +static int wb_aix_normalize(char *longname, char *shortname) +{ + struct passwd *pwd; + + logit("normalize '%s'\n", longname); + + /* automatically cope with AIX 5.3 with longer usernames + when it comes out */ + if (S_NAMELEN > strlen(longname)) { + strcpy(shortname, longname); + return 1; + } + + pwd = wb_aix_getpwnam(longname); + if (!pwd) { + errno = ENOENT; + return 0; + } + + sprintf(shortname, "%c%07u", WB_AIX_ENCODED, pwd->pw_uid); + + free_pwd(pwd); + + return 1; +} + + +/* + authenticate a user + */ +static int wb_aix_authenticate(char *user, char *pass, + int *reenter, char **message) +{ + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS result; + char *r_user = user; + + logit("authenticate '%s' response='%s'\n", user, pass); + + *reenter = 0; + *message = NULL; + + /* Send off request */ + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + if (*user == WB_AIX_ENCODED) { + r_user = decode_user(r_user); + if (!r_user) { + return AUTH_NOTFOUND; + } + } + + STRCPY_RET(request.data.auth.user, r_user); + STRCPY_RET(request.data.auth.pass, pass); + + if (*user == WB_AIX_ENCODED) { + free(r_user); + } + + result = winbindd_request(WINBINDD_PAM_AUTH, &request, &response); + + free_response(&response); + + logit("auth result %d for '%s'\n", result, user); + + if (result == NSS_STATUS_SUCCESS) { + errno = 0; + return AUTH_SUCCESS; + } + + return AUTH_FAILURE; +} + + +/* + change a user password +*/ +static int wb_aix_chpass(char *user, char *oldpass, char *newpass, char **message) +{ + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS result; + char *r_user = user; + + if (*user == WB_AIX_ENCODED) { + r_user = decode_user(r_user); + if (!r_user) { + errno = ENOENT; + return -1; + } + } + + logit("chpass '%s' old='%s' new='%s'\n", r_user, oldpass, newpass); + + *message = NULL; + + /* Send off request */ + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + STRCPY_RET(request.data.chauthtok.user, r_user); + STRCPY_RET(request.data.chauthtok.oldpass, oldpass); + STRCPY_RET(request.data.chauthtok.newpass, newpass); + + if (*user == WB_AIX_ENCODED) { + free(r_user); + } + + result = winbindd_request(WINBINDD_PAM_CHAUTHTOK, &request, &response); + + free_response(&response); + + if (result == NSS_STATUS_SUCCESS) { + errno = 0; + return 0; + } + + errno = EINVAL; + return -1; +} + +/* + don't do any password strength testing for now +*/ +static int wb_aix_passwdrestrictions(char *user, char *newpass, char *oldpass, + char **message) +{ + logit("passwdresrictions called for '%s'\n", user); + return 0; +} + + +static int wb_aix_passwdexpired(char *user, char **message) +{ + logit("passwdexpired '%s'\n", user); + /* we should check the account bits here */ + return 0; +} + + +/* + we can't return a crypt() password +*/ +static char *wb_aix_getpasswd(char *user) +{ + logit("getpasswd '%s'\n", user); + errno = ENOSYS; + return NULL; +} + +/* + this is called to update things like the last login time. We don't + currently pass this onto the DC +*/ +static int wb_aix_putentry(char *key, char *table, char *attributes[], + attrval_t values[], int size) +{ + logit("putentry key='%s' table='%s' attrib='%s'\n", + key, table, size>=1?attributes[0]:""); + errno = ENOSYS; + return -1; +} + +static int wb_aix_commit(char *key, char *table) +{ + logit("commit key='%s' table='%s'\n"); + errno = ENOSYS; + return -1; +} + +static int wb_aix_getgrusers(char *group, void *result, int type, int *size) +{ + logit("getgrusers group='%s'\n", group); + errno = ENOSYS; + return -1; +} + + +#define DECL_METHOD(x) \ +int method_ ## x(void) \ +{ \ + logit("UNIMPLEMENTED METHOD '%s'\n", #x); \ + errno = EINVAL; \ + return -1; \ +} + +#if LOG_UNIMPLEMENTED_CALLS +DECL_METHOD(delgroup); +DECL_METHOD(deluser); +DECL_METHOD(newgroup); +DECL_METHOD(newuser); +DECL_METHOD(putgrent); +DECL_METHOD(putgrusers); +DECL_METHOD(putpwent); +DECL_METHOD(lock); +DECL_METHOD(unlock); +DECL_METHOD(getcred); +DECL_METHOD(setcred); +DECL_METHOD(deletecred); +#endif + int wb_aix_init(struct secmethod_table *methods) { ZERO_STRUCTP(methods); - /* identification methods, this is the minimum requried for a - working module */ - - methods->method_getgrgid = wb_aix_getgrgid; - methods->method_getgrnam = wb_aix_getgrnam; - methods->method_getgrset = wb_aix_getgrset; - methods->method_getpwnam = wb_aix_getpwnam; - methods->method_getpwuid = wb_aix_getpwuid; + methods->method_version = SECMETHOD_VERSION_520; + + methods->method_getgrgid = wb_aix_getgrgid; + methods->method_getgrnam = wb_aix_getgrnam; + methods->method_getgrset = wb_aix_getgrset; + methods->method_getpwnam = wb_aix_getpwnam; + methods->method_getpwuid = wb_aix_getpwuid; + methods->method_getentry = wb_aix_getentry; + methods->method_open = wb_aix_open; + methods->method_close = wb_aix_close; + methods->method_normalize = wb_aix_normalize; + methods->method_passwdexpired = wb_aix_passwdexpired; + methods->method_putentry = wb_aix_putentry; + methods->method_getpasswd = wb_aix_getpasswd; + methods->method_authenticate = wb_aix_authenticate; + methods->method_commit = wb_aix_commit; + methods->method_chpass = wb_aix_chpass; + methods->method_passwdrestrictions = wb_aix_passwdrestrictions; + methods->method_getgracct = wb_aix_getgracct; + methods->method_getgrusers = wb_aix_getgrusers; + methods->method_attrlist = wb_aix_attrlist; + +#if LOG_UNIMPLEMENTED_CALLS + methods->method_delgroup = method_delgroup; + methods->method_deluser = method_deluser; + methods->method_newgroup = method_newgroup; + methods->method_newuser = method_newuser; + methods->method_putgrent = method_putgrent; + methods->method_putgrusers = method_putgrusers; + methods->method_putpwent = method_putpwent; + methods->method_lock = method_lock; + methods->method_unlock = method_unlock; + methods->method_getcred = method_getcred; + methods->method_setcred = method_setcred; + methods->method_deletecred = method_deletecred; +#endif return AUTH_SUCCESS; } -- 2.11.4.GIT