summaryrefslogtreecommitdiff
path: root/source3/nsswitch
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2003-10-21 12:18:08 +0000
committerAndrew Tridgell <tridge@samba.org>2003-10-21 12:18:08 +0000
commit7c6c6b66280d717a8c8efd9fa2a7aa39240b151f (patch)
tree8f92ddf860a613e33d4224fa16d03e276a5447bf /source3/nsswitch
parentbafcc8497d0a77d2aadb3da4f2a945e56c78a246 (diff)
downloadsamba-7c6c6b66280d717a8c8efd9fa2a7aa39240b151f.tar.gz
samba-7c6c6b66280d717a8c8efd9fa2a7aa39240b151f.tar.bz2
samba-7c6c6b66280d717a8c8efd9fa2a7aa39240b151f.zip
fixed a number of bugs and memory leaks in the AIX winbind shim
(This used to be commit f0a0771c02404c91cd64961f85622022a4e56b2f)
Diffstat (limited to 'source3/nsswitch')
-rw-r--r--source3/nsswitch/winbind_nss_aix.c480
1 files changed, 231 insertions, 249 deletions
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 <stdlib.h>
#include <string.h>
#include <usersec.h>
#include <errno.h>
+#include <stdarg.h>
#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;
}
+