From 7c6c6b66280d717a8c8efd9fa2a7aa39240b151f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 21 Oct 2003 12:18:08 +0000 Subject: fixed a number of bugs and memory leaks in the AIX winbind shim (This used to be commit f0a0771c02404c91cd64961f85622022a4e56b2f) --- source3/nsswitch/winbind_nss_aix.c | 480 ++++++++++++++++++------------------- 1 file changed, 231 insertions(+), 249 deletions(-) (limited to 'source3/nsswitch') diff --git a/source3/nsswitch/winbind_nss_aix.c b/source3/nsswitch/winbind_nss_aix.c index 8b5bc7a50c..3d2f01b93c 100644 --- a/source3/nsswitch/winbind_nss_aix.c +++ b/source3/nsswitch/winbind_nss_aix.c @@ -6,6 +6,7 @@ Copyright (C) Tim Potter 2003 Copyright (C) Steve Roylance 2003 + Copyright (C) Andrew Tridgell 2003 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -23,182 +24,188 @@ Boston, MA 02111-1307, USA. */ +/* + 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 +*/ + #include #include #include #include +#include #include "winbind_client.h" -#define MAX_GETPWENT_USERS 250 -#define MAX_GETGRENT_USERS 250 - -static struct passwd *fill_pwent(struct winbindd_pw *pw) -{ - struct passwd *result; - - if (!(result = malloc(sizeof(struct passwd)))) - goto out; - - ZERO_STRUCTP(result); - - /* User name */ +/* + 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 +*/ - if ((result->pw_name = malloc(strlen(pw->pw_name) + 1)) == NULL) - goto out; - - strcpy(result->pw_name, pw->pw_name); - /* Password */ +/* + 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; +}; - if ((result->pw_passwd = malloc(strlen(pw->pw_passwd) + 1)) == NULL) - goto out; - - strcpy(result->pw_passwd, pw->pw_passwd); - - /* [ug]id */ - result->pw_uid = pw->pw_uid; - result->pw_gid = pw->pw_gid; +/* allocate some memory on a mem_list */ +static void *list_alloc(struct mem_list **list, size_t size) +{ + 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; + } + (*list) = m; + return m->p; +} - /* GECOS */ +/* 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; +} - if ((result->pw_gecos = malloc(strlen(pw->pw_gecos) + 1)) == NULL) - goto out; +/* 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; +} - strcpy(result->pw_gecos, pw->pw_gecos); - - /* Home directory */ - - if ((result->pw_dir = malloc(strlen(pw->pw_dir) + 1)) == NULL) - goto out; - strcpy(result->pw_dir, pw->pw_dir); +#define HANDLE_ERRORS(ret) do { \ + if ((ret) == NSS_STATUS_NOTFOUND) { \ + errno = ENOENT; \ + return NULL; \ + } else if ((ret) != NSS_STATUS_SUCCESS) { \ + errno = EIO; \ + return NULL; \ + } \ +} while (0) - /* Logon shell */ - - if ((result->pw_shell = malloc(strlen(pw->pw_shell) + 1)) == NULL) - goto out; - - strcpy(result->pw_shell, pw->pw_shell); - - return result; - - /* A memory allocation failed, undo succesfull allocations and - return NULL */ - -out: - errno = ENOMEM; - SAFE_FREE(result->pw_dir); - SAFE_FREE(result->pw_gecos); - SAFE_FREE(result->pw_passwd); - SAFE_FREE(result->pw_name); - SAFE_FREE(result); - - return NULL; -} - -static BOOL next_token(char **ptr,char *buff,char *sep, size_t bufsize) +/* + fill a struct passwd from a winbindd_pw struct, using memory from a mem_list +*/ +static struct passwd *fill_pwent(struct mem_list **list, struct winbindd_pw *pw) { - char *s; - BOOL quoted; - size_t len=1; + struct passwd *result; - if (!ptr) return(False); + if (!(result = list_alloc(list, sizeof(struct passwd)))) { + return NULL; + } - s = *ptr; + ZERO_STRUCTP(result); - /* default to simple separators */ - if (!sep) sep = " \t\n\r"; + result->pw_uid = pw->pw_uid; + result->pw_gid = pw->pw_gid; - /* find the first non sep char */ - while (*s && strchr(sep,*s)) s++; - - /* nothing left? */ - if (! *s) return(False); - - /* copy over the token */ - for (quoted = False; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++) { - if (*s == '\"') { - quoted = !quoted; - } else { - len++; - *buff++ = *s; - } + /* 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) { + return NULL; } - *ptr = (*s) ? s+1 : s; - *buff = 0; - - return(True); + return result; } -static struct group *fill_grent(struct winbindd_gr *gr, char *gr_mem) + +/* + fill a struct group from a winbindd_pw struct, using memory from a mem_list +*/ +static struct group *fill_grent(struct mem_list **list, struct winbindd_gr *gr, char *gr_mem) { - fstring name; int i; char *tst; struct group *result; - - if (!(result = malloc(sizeof(struct group)))) - goto out; + char *name, *p; - ZERO_STRUCTP(result); - - /* Group name */ - - if ((result->gr_name = malloc(strlen(gr->gr_name) + 1)) == NULL) - goto out; - - strcpy(result->gr_name, gr->gr_name); - - /* Password */ - - if ((result->gr_passwd = malloc(strlen(gr->gr_passwd) + 1)) == NULL) - goto out; - - strcpy(result->gr_passwd, gr->gr_passwd); + if (!(result = list_alloc(list, sizeof(struct group)))) { + return NULL; + } - /* gid */ + ZERO_STRUCTP(result); result->gr_gid = gr->gr_gid; - /* Group membership */ + /* 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; + } + /* Group membership */ if ((gr->num_gr_mem < 0) || !gr_mem) { gr->num_gr_mem = 0; } if (gr->num_gr_mem == 0) { - - /* Group is empty */ - - *(result->gr_mem) = NULL; + /* Group is empty */ return result; } - if ((tst = malloc(((gr->num_gr_mem + 1) * sizeof(char *)))) == NULL) - goto out; + tst = list_alloc(list, (gr->num_gr_mem + 1) * sizeof(char *)); + if (!tst) { + return NULL; + } result->gr_mem = (char **)tst; /* Start looking at extra data */ - - i = 0; - - while(next_token((char **)&gr_mem, name, ",", sizeof(fstring))) { - - /* Allocate space for member */ - - if (((result->gr_mem)[i] = - malloc(strlen(name) + 1)) == NULL) { - for ( i -= 1; i >= 0; i--) - SAFE_FREE((result->gr_mem)[i]); - goto out; - - } - - strcpy((result->gr_mem)[i], name); + 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; + } i++; } @@ -206,140 +213,123 @@ static struct group *fill_grent(struct winbindd_gr *gr, char *gr_mem) (result->gr_mem)[i] = NULL; return result; - - /* A memory allocation failed, undo succesfull allocations and - return NULL */ - -out: - errno = ENOMEM; - SAFE_FREE(tst); - SAFE_FREE(result->gr_passwd); - SAFE_FREE(result->gr_name); - SAFE_FREE(result); - - return NULL; } -static struct group * -wb_aix_getgrgid (gid_t gid) +/* take a group id and return a filled struct group */ +static struct group *wb_aix_getgrgid(gid_t gid) { -/* take a group id and return a filled struct group */ - + static struct mem_list *list; struct winbindd_response response; struct winbindd_request request; + struct group *grp; NSS_STATUS ret; + list_destory(&list); + ZERO_STRUCT(response); ZERO_STRUCT(request); request.data.gid = gid; ret = winbindd_request(WINBINDD_GETGRGID, &request, &response); - - if (ret == NSS_STATUS_SUCCESS) { - return fill_grent(&response.data.gr, response.extra_data); - } else if (ret == NSS_STATUS_NOTFOUND) { - errno = ENOENT; - } else { - errno = EIO; - } - - return NULL; + + HANDLE_ERRORS(ret); + + grp = fill_grent(&list, &response.data.gr, response.extra_data); + + free_response(&response); + + return grp; } -static struct group * -wb_aix_getgrnam (const char *name) -{ /* 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); + ZERO_STRUCT(response); ZERO_STRUCT(request); - strncpy(request.data.groupname, name, - sizeof(request.data.groupname)); - request.data.groupname - [sizeof(request.data.groupname) - 1] = '\0'; + if (strlen(name)+1 > sizeof(request.data.groupname)) { + errno = EINVAL; + return NULL; + } + strcpy(request.data.groupname, name); ret = winbindd_request(WINBINDD_GETGRNAM, &request, &response); - if (ret == NSS_STATUS_SUCCESS) { - return fill_grent(&response.data.gr, response.extra_data); - } else if (ret == NSS_STATUS_NOTFOUND) { - errno = ENOENT; - } else { - errno = EIO; - } - - return NULL; + HANDLE_ERRORS(ret); + + grp = fill_grent(&list, &response.data.gr, response.extra_data); + + free_response(&response); + + return grp; } -static char * -wb_aix_getgrset (const char *user) + +/* 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) { -/* take a username and return a string containing a comma-separated list of - group id numbers to which the user belongs */ - + static struct mem_list *list; struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; + int i, idx; + char *tmpbuf; + int num_gids; + gid_t *gid_list; - strncpy(request.data.username, user, - sizeof(request.data.username) - 1); - request.data.username - [sizeof(request.data.username) - 1] = '\0'; + list_destory(&list); + + if (strlen(user)+1 > sizeof(request.data.username)) { + errno = EINVAL; + return NULL; + } + strcpy(request.data.username, user); ret = winbindd_request(WINBINDD_GETGROUPS, &request, &response); - if (ret == NSS_STATUS_SUCCESS ) { - int i, idx = 0; - char *tmpbuf, *result; - - int num_gids = response.data.num_entries; - gid_t *gid_list = (gid_t *)response.extra_data; + HANDLE_ERRORS(ret); + + num_gids = response.data.num_entries; + gid_list = (gid_t *)response.extra_data; - /* allocate a space large enough to contruct the string */ - if (!(tmpbuf = malloc(num_gids*12))) { - errno = ENOMEM; - return NULL; - } - idx += sprintf(tmpbuf, "%d", gid_list[0]); - for (i = 1; i < num_gids; i++) { - tmpbuf[idx++] = ','; - idx += sprintf(tmpbuf+idx, "%d", gid_list[i]); - } - tmpbuf[idx] = '\0'; - if (!(result = malloc(idx+1))) { - /* allocate a string the right size to return, but - if that fails may as well return our working buffer - because it contains the same thing */ - return tmpbuf; - } - strcpy(result, tmpbuf); - SAFE_FREE(tmpbuf); - return result; - } else if (ret == NSS_STATUS_NOTFOUND) { - errno = ENOENT; - } else { - errno = EIO; + /* allocate a space large enough to contruct the string */ + tmpbuf = list_alloc(&list, num_gids*12); + if (!tmpbuf) { + return NULL; } - - return NULL; + + for (idx=i=0; i < num_gids-1; i++) { + idx += sprintf(tmpbuf+idx, "%u,", gid_list[i]); + } + idx += sprintf(tmpbuf+idx, "%u", gid_list[i]); + + free_response(&response); + + return tmpbuf; } -static struct passwd * -wb_aix_getpwuid (uid_t uid) + +/* take a uid and return a filled struct passwd */ +static struct passwd *wb_aix_getpwuid(uid_t uid) { -/* take a uid and return a filled struct passwd */ - + static struct mem_list *list; struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; + + list_destory(&list); ZERO_STRUCT(response); ZERO_STRUCT(request); @@ -347,55 +337,46 @@ wb_aix_getpwuid (uid_t uid) request.data.uid = uid; ret = winbindd_request(WINBINDD_GETPWUID, &request, &response); - - if (ret == NSS_STATUS_SUCCESS) { - return fill_pwent(&response.data.pw); - } else if (ret == NSS_STATUS_NOTFOUND ) { - errno = ENOENT; - } else { - errno = EIO; - } - - return NULL; + + HANDLE_ERRORS(ret); + + return fill_pwent(&list, &response.data.pw); } -static struct passwd * -wb_aix_getpwnam (const char *name) -{ -/* take a username and return a filled struct passwd */ +/* 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; + + list_destory(&list); ZERO_STRUCT(response); ZERO_STRUCT(request); - strncpy(request.data.username, name, - sizeof(request.data.username) - 1); - request.data.username - [sizeof(request.data.username) - 1] = '\0'; + if (strlen(name)+1 > sizeof(request.data.username)) { + errno = EINVAL; + return NULL; + } + + strcpy(request.data.username, name); ret = winbindd_request(WINBINDD_GETPWNAM, &request, &response); + + HANDLE_ERRORS(ret); - if (ret == NSS_STATUS_SUCCESS ) { - return fill_pwent(&response.data.pw); - } else if (ret == NSS_STATUS_NOTFOUND) { - errno = ENOENT; - } else { - errno = EIO; - } - - return NULL; + return fill_pwent(&list, &response.data.pw); } -int -wb_aix_init (struct secmethod_table *methods) +int wb_aix_init(struct secmethod_table *methods) { - memset(methods, 0, sizeof(*methods)); + ZERO_STRUCTP(methods); /* identification methods, this is the minimum requried for a - working module */ + working module */ methods->method_getgrgid = wb_aix_getgrgid; methods->method_getgrnam = wb_aix_getgrnam; @@ -405,3 +386,4 @@ wb_aix_init (struct secmethod_table *methods) return AUTH_SUCCESS; } + -- cgit