mirror of
https://github.com/samba-team/samba.git
synced 2025-02-02 09:47:23 +03:00
fixed a number of bugs and memory leaks in the AIX winbind shim
(This used to be commit f0a0771c02404c91cd64961f85622022a4e56b2f)
This commit is contained in:
parent
bafcc8497d
commit
7c6c6b6628
@ -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
|
||||
/*
|
||||
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().
|
||||
|
||||
static struct passwd *fill_pwent(struct winbindd_pw *pw)
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
#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)
|
||||
|
||||
/*
|
||||
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)
|
||||
{
|
||||
struct passwd *result;
|
||||
|
||||
if (!(result = malloc(sizeof(struct passwd))))
|
||||
goto out;
|
||||
|
||||
if (!(result = list_alloc(list, sizeof(struct passwd)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZERO_STRUCTP(result);
|
||||
|
||||
/* User name */
|
||||
|
||||
if ((result->pw_name = malloc(strlen(pw->pw_name) + 1)) == NULL)
|
||||
goto out;
|
||||
|
||||
strcpy(result->pw_name, pw->pw_name);
|
||||
|
||||
/* Password */
|
||||
|
||||
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;
|
||||
|
||||
/* GECOS */
|
||||
|
||||
if ((result->pw_gecos = malloc(strlen(pw->pw_gecos) + 1)) == NULL)
|
||||
goto out;
|
||||
|
||||
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);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
char *s;
|
||||
BOOL quoted;
|
||||
size_t len=1;
|
||||
|
||||
if (!ptr) return(False);
|
||||
|
||||
s = *ptr;
|
||||
|
||||
/* default to simple separators */
|
||||
if (!sep) sep = " \t\n\r";
|
||||
|
||||
/* 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;
|
||||
|
||||
if (!(result = list_alloc(list, sizeof(struct group)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* gid */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user