summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/Makefile.in4
-rw-r--r--source3/nsswitch/wb_common.c7
-rw-r--r--source3/nsswitch/wbinfo.c9
-rw-r--r--source3/nsswitch/winbind_nss.c889
-rw-r--r--source3/nsswitch/winbind_nss_config.h62
5 files changed, 702 insertions, 269 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index d3c0c185a0..e8c649ac66 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -384,9 +384,9 @@ WINBINDD_OBJ = \
$(LIBNMB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
$(NSSWINS_OBJ) $(SIDDB_OBJ) $(LIBSMB_OBJ)
-WBINFO_OBJ = nsswitch/wbinfo.o nsswitch/wb_common.o
+WBINFO_OBJ = nsswitch/wbinfo.o
-WINBIND_NSS_OBJ = nsswitch/winbind.o nsswitch/wb_common.o
+WINBIND_NSS_OBJ = nsswitch/winbind_nss.o nsswitch/wb_common.o
WINBIND_NSS_PICOBJS = $(WINBIND_NSS_OBJ:.o=.po)
diff --git a/source3/nsswitch/wb_common.c b/source3/nsswitch/wb_common.c
index 98a4b6758b..4040e1cff2 100644
--- a/source3/nsswitch/wb_common.c
+++ b/source3/nsswitch/wb_common.c
@@ -37,7 +37,7 @@ void init_request(struct winbindd_request *request, int request_type)
static char *domain_env;
static BOOL initialised;
- request->cmd = (enum winbindd_cmd)request_type;
+ request->cmd = request_type;
request->pid = getpid();
request->domain[0] = '\0';
@@ -59,7 +59,7 @@ void init_response(struct winbindd_response *response)
{
/* Initialise return value */
- response->result = (enum winbindd_result)NSS_STATUS_UNAVAIL;
+ response->result = WINBINDD_ERROR;
}
/* Close established socket */
@@ -141,6 +141,7 @@ static int open_pipe_sock(void)
if (connect(established_socket, (struct sockaddr *)&sunaddr,
sizeof(sunaddr)) == -1) {
close_sock();
+ established_socket = -1;
return -1;
}
@@ -304,7 +305,7 @@ void free_response(struct winbindd_response *response)
/* Handle simple types of requests */
-enum nss_status winbindd_request(int req_type,
+NSS_STATUS winbindd_request(int req_type,
struct winbindd_request *request,
struct winbindd_response *response)
{
diff --git a/source3/nsswitch/wbinfo.c b/source3/nsswitch/wbinfo.c
index cff2b8b69a..1a51a5b610 100644
--- a/source3/nsswitch/wbinfo.c
+++ b/source3/nsswitch/wbinfo.c
@@ -101,10 +101,11 @@ static BOOL wbinfo_check_secret(void)
if (result) {
- if (response.data.num_entries) {
+ if (response.data.num_entries == 0) {
printf("Secret is good\n");
} else {
- printf("Secret is bad\n");
+ printf("Secret is bad\n0x%08x\n",
+ response.data.num_entries);
}
return True;
@@ -447,8 +448,8 @@ int main(int argc, char **argv)
return 1;
}
break;
-
- /* Invalid option */
+
+ /* Invalid option */
default:
usage();
diff --git a/source3/nsswitch/winbind_nss.c b/source3/nsswitch/winbind_nss.c
index 78485aa05e..04b576a7a5 100644
--- a/source3/nsswitch/winbind_nss.c
+++ b/source3/nsswitch/winbind_nss.c
@@ -25,11 +25,15 @@
#include "winbind_nss_config.h"
#include "winbindd_nss.h"
-/* prototypes from common.c */
+/* Prototypes from common.c */
+
void init_request(struct winbindd_request *req,int rq_type);
+NSS_STATUS winbindd_request(int req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response);
int write_sock(void *buffer, int count);
int read_reply(struct winbindd_response *response);
-
+void free_response(struct winbindd_response *response);
/* Allocate some space from the nss static buffer. The buffer and buflen
are the pointers passed in by the C library to the _nss_ntdom_*
@@ -37,429 +41,810 @@ int read_reply(struct winbindd_response *response);
static char *get_static(char **buffer, int *buflen, int len)
{
- char *result;
+ char *result;
- /* Error check. We return false if things aren't set up right, or
- there isn't enough buffer space left. */
+ /* Error check. We return false if things aren't set up right, or
+ there isn't enough buffer space left. */
+
+ if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
+ return NULL;
+ }
- if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
- return NULL;
- }
+ /* Some architectures, like Sparc, need pointers aligned on
+ boundaries */
+#if _ALIGNMENT_REQUIRED
+ {
+ int mod = len % _MAX_ALIGNMENT;
+ if(mod != 0)
+ len += _MAX_ALIGNMENT - mod;
+ }
+#endif
- /* Return an index into the static buffer */
+ /* Return an index into the static buffer */
- result = *buffer;
- *buffer += len;
- *buflen -= len;
+ result = *buffer;
+ *buffer += len;
+ *buflen -= len;
- return result;
+ return result;
}
/* I've copied the strtok() replacement function next_token() from
lib/util_str.c as I really don't want to have to link in any other
objects if I can possibly avoid it. */
-#ifdef strchr /* Aargh! This points at multibyte_strchr(). )-: */
-#undef strchr
-#endif
-
static char *last_ptr = NULL;
BOOL next_token(char **ptr, char *buff, char *sep, size_t bufsize)
{
- char *s;
- BOOL quoted;
- size_t len=1;
+ char *s;
+ BOOL quoted;
+ size_t len=1;
- if (!ptr) ptr = &last_ptr;
- if (!ptr) return(False);
+ if (!ptr) ptr = &last_ptr;
+ if (!ptr) return(False);
- s = *ptr;
+ s = *ptr;
- /* default to simple separators */
- if (!sep) sep = " \t\n\r";
+ /* default to simple separators */
+ if (!sep) sep = " \t\n\r";
- /* find the first non sep char */
- while(*s && strchr(sep,*s)) s++;
+ /* find the first non sep char */
+ while(*s && strchr(sep,*s)) s++;
- /* nothing left? */
- if (! *s) return(False);
+ /* 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;
- }
- }
+ /* copy over the token */
+ for (quoted = False;
+ len < bufsize && *s && (quoted || !strchr(sep,*s));
+ s++) {
+
+ if (*s == '\"') {
+ quoted = !quoted;
+ } else {
+ len++;
+ *buff++ = *s;
+ }
+ }
- *ptr = (*s) ? s+1 : s;
- *buff = 0;
- last_ptr = *ptr;
+ *ptr = (*s) ? s+1 : s;
+ *buff = 0;
+ last_ptr = *ptr;
- return(True);
-}
-
-
-/* handle simple types of requests */
-static enum nss_status generic_request(int req_type,
- struct winbindd_request *request,
- struct winbindd_response *response)
-{
- struct winbindd_request lrequest;
- struct winbindd_response lresponse;
-
- if (!response) response = &lresponse;
- if (!request) request = &lrequest;
-
- /* Fill in request and send down pipe */
- init_request(request, req_type);
-
- if (write_sock(request, sizeof(*request)) == -1) {
- return NSS_STATUS_UNAVAIL;
- }
-
- /* Wait for reply */
- if (read_reply(response) == -1) {
- return NSS_STATUS_UNAVAIL;
- }
-
- /* Copy reply data from socket */
- if (response->result != WINBINDD_OK) {
- return NSS_STATUS_NOTFOUND;
- }
-
- return NSS_STATUS_SUCCESS;
+ return(True);
}
/* Fill a pwent structure from a winbindd_response structure. We use
the static data passed to us by libc to put strings and stuff in.
- Return errno = ERANGE and NSS_STATUS_TRYAGAIN if we run out of
- memory. */
+ Return NSS_STATUS_TRYAGAIN if we run out of memory. */
-static enum nss_status fill_pwent(struct passwd *result,
- struct winbindd_response *response,
- char **buffer, int *buflen, int *errnop)
+static NSS_STATUS fill_pwent(struct passwd *result,
+ struct winbindd_pw *pw,
+ char **buffer, int *buflen)
{
- struct winbindd_pw *pw = &response->data.pw;
-
- /* User name */
+ /* User name */
- if ((result->pw_name =
- get_static(buffer, buflen, strlen(pw->pw_name) + 1)) == NULL) {
+ if ((result->pw_name =
+ get_static(buffer, buflen, strlen(pw->pw_name) + 1)) == NULL) {
- /* Out of memory */
+ /* Out of memory */
- *errnop = ERANGE;
- return NSS_STATUS_TRYAGAIN;
- }
+ return NSS_STATUS_TRYAGAIN;
+ }
- strcpy(result->pw_name, pw->pw_name);
+ strcpy(result->pw_name, pw->pw_name);
- /* Password */
+ /* Password */
- if ((result->pw_passwd =
- get_static(buffer, buflen, strlen(pw->pw_passwd) + 1)) == NULL) {
+ if ((result->pw_passwd =
+ get_static(buffer, buflen, strlen(pw->pw_passwd) + 1)) == NULL) {
- /* Out of memory */
+ /* Out of memory */
- *errnop = ERANGE;
- return NSS_STATUS_TRYAGAIN;
- }
+ return NSS_STATUS_TRYAGAIN;
+ }
- strcpy(result->pw_passwd, pw->pw_passwd);
+ strcpy(result->pw_passwd, pw->pw_passwd);
- /* [ug]id */
-
- result->pw_uid = pw->pw_uid;
- result->pw_gid = pw->pw_gid;
-
- /* GECOS */
+ /* [ug]id */
- if ((result->pw_gecos =
- get_static(buffer, buflen, strlen(pw->pw_gecos) + 1)) == NULL) {
+ result->pw_uid = pw->pw_uid;
+ result->pw_gid = pw->pw_gid;
- /* Out of memory */
+ /* GECOS */
- *errnop = ERANGE;
- return NSS_STATUS_TRYAGAIN;
- }
+ if ((result->pw_gecos =
+ get_static(buffer, buflen, strlen(pw->pw_gecos) + 1)) == NULL) {
- strcpy(result->pw_gecos, pw->pw_gecos);
+ /* Out of memory */
- /* Home directory */
-
- if ((result->pw_dir =
- get_static(buffer, buflen, strlen(pw->pw_dir) + 1)) == NULL) {
-
- /* Out of memory */
+ return NSS_STATUS_TRYAGAIN;
+ }
- *errnop = ERANGE;
- return NSS_STATUS_TRYAGAIN;
- }
+ strcpy(result->pw_gecos, pw->pw_gecos);
+
+ /* Home directory */
+
+ if ((result->pw_dir =
+ get_static(buffer, buflen, strlen(pw->pw_dir) + 1)) == NULL) {
- strcpy(result->pw_dir, pw->pw_dir);
+ /* Out of memory */
- /* Logon shell */
+ return NSS_STATUS_TRYAGAIN;
+ }
- if ((result->pw_shell =
- get_static(buffer, buflen, strlen(pw->pw_shell) + 1)) == NULL) {
+ strcpy(result->pw_dir, pw->pw_dir);
- /* Out of memory */
+ /* Logon shell */
+
+ if ((result->pw_shell =
+ get_static(buffer, buflen, strlen(pw->pw_shell) + 1)) == NULL) {
+
+ /* Out of memory */
- *errnop = ERANGE;
- return NSS_STATUS_TRYAGAIN;
- }
+ return NSS_STATUS_TRYAGAIN;
+ }
- strcpy(result->pw_shell, pw->pw_shell);
+ strcpy(result->pw_shell, pw->pw_shell);
- return NSS_STATUS_SUCCESS;
+ return NSS_STATUS_SUCCESS;
}
/* Fill a grent structure from a winbindd_response structure. We use
the static data passed to us by libc to put strings and stuff in.
- Return errno = ERANGE and NSS_STATUS_TRYAGAIN if we run out of
- memory. */
+ Return NSS_STATUS_TRYAGAIN if we run out of memory. */
-static int fill_grent(struct group *result,
- struct winbindd_response *response,
- char **buffer, int *buflen, int *errnop)
+static int fill_grent(struct group *result, struct winbindd_gr *gr,
+ char *gr_mem, char **buffer, int *buflen)
{
- struct winbindd_gr *gr = &response->data.gr;
- fstring name;
- int i;
+ fstring name;
+ int i;
- /* Group name */
+ /* Group name */
- if ((result->gr_name =
- get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) {
+ if ((result->gr_name =
+ get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) {
- /* Out of memory */
+ /* Out of memory */
- *errnop = ERANGE;
- return NSS_STATUS_TRYAGAIN;
- }
-
- strcpy(result->gr_name, gr->gr_name);
+ return NSS_STATUS_TRYAGAIN;
+ }
- /* Password */
+ strcpy(result->gr_name, gr->gr_name);
- if ((result->gr_passwd =
- get_static(buffer, buflen, strlen(gr->gr_passwd) + 1)) == NULL) {
+ /* Password */
- /* Out of memory */
+ if ((result->gr_passwd =
+ get_static(buffer, buflen, strlen(gr->gr_passwd) + 1)) == NULL) {
- *errnop = ERANGE;
- return NSS_STATUS_TRYAGAIN;
- }
+ /* Out of memory */
+
+ return NSS_STATUS_TRYAGAIN;
+ }
- strcpy(result->gr_passwd, gr->gr_passwd);
+ strcpy(result->gr_passwd, gr->gr_passwd);
- /* gid */
+ /* gid */
- result->gr_gid = gr->gr_gid;
+ result->gr_gid = gr->gr_gid;
- /* Group membership */
+ /* Group membership */
- if ((gr->num_gr_mem < 0) || !response->extra_data) {
- gr->num_gr_mem = 0;
- }
+ if ((gr->num_gr_mem < 0) || !gr_mem) {
+ gr->num_gr_mem = 0;
+ }
- if ((result->gr_mem =
- (char **)get_static(buffer, buflen, (gr->num_gr_mem + 1) *
- sizeof(char *))) == NULL) {
+ if ((result->gr_mem =
+ (char **)get_static(buffer, buflen, (gr->num_gr_mem + 1) *
+ sizeof(char *))) == NULL) {
- /* Out of memory */
+ /* Out of memory */
- *errnop = ERANGE;
- return NSS_STATUS_TRYAGAIN;
- }
+ return NSS_STATUS_TRYAGAIN;
+ }
- if (gr->num_gr_mem == 0) {
+ if (gr->num_gr_mem == 0) {
- /* Group is empty */
+ /* Group is empty */
- *(result->gr_mem) = NULL;
- return NSS_STATUS_SUCCESS;
- }
+ *(result->gr_mem) = NULL;
+ return NSS_STATUS_SUCCESS;
+ }
- /* Start looking at extra data */
+ /* Start looking at extra data */
- i = 0;
+ i = 0;
- while(next_token(&response->extra_data, name, ",", sizeof(fstring))) {
+ while(next_token((char **)&gr_mem, name, ",", sizeof(fstring))) {
- /* Allocate space for member */
+ /* Allocate space for member */
- if (((result->gr_mem)[i] =
- get_static(buffer, buflen, strlen(name) + 1)) == NULL) {
+ if (((result->gr_mem)[i] =
+ get_static(buffer, buflen, strlen(name) + 1)) == NULL) {
- /* Out of memory */
+ /* Out of memory */
- *errnop = ERANGE;
- return NSS_STATUS_TRYAGAIN;
- }
+ return NSS_STATUS_TRYAGAIN;
+ }
- strcpy((result->gr_mem)[i], name);
- i++;
- }
+ strcpy((result->gr_mem)[i], name);
+ i++;
+ }
- /* Terminate list */
+ /* Terminate list */
- (result->gr_mem)[i] = NULL;
-
- return NSS_STATUS_SUCCESS;
+ (result->gr_mem)[i] = NULL;
+
+ return NSS_STATUS_SUCCESS;
}
/*
* NSS user functions
*/
+static struct winbindd_response getpwent_response;
+
+static int ndx_pw_cache; /* Current index into pwd cache */
+static int num_pw_cache; /* Current size of pwd cache */
+
/* Rewind "file pointer" to start of ntdom password database */
-enum nss_status
+NSS_STATUS
_nss_winbind_setpwent(void)
{
- return generic_request(WINBINDD_SETPWENT, NULL, NULL);
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: setpwent\n", getpid());
+#endif
+
+ if (num_pw_cache > 0) {
+ ndx_pw_cache = num_pw_cache = 0;
+ free_response(&getpwent_response);
+ }
+
+ return winbindd_request(WINBINDD_SETPWENT, NULL, NULL);
}
/* Close ntdom password database "file pointer" */
-enum nss_status
+NSS_STATUS
_nss_winbind_endpwent(void)
{
- return generic_request(WINBINDD_ENDPWENT, NULL, NULL);
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: endpwent\n", getpid());
+#endif
+
+ if (num_pw_cache > 0) {
+ ndx_pw_cache = num_pw_cache = 0;
+ free_response(&getpwent_response);
+ }
+
+ return winbindd_request(WINBINDD_ENDPWENT, NULL, NULL);
}
/* Fetch the next password entry from ntdom password database */
-enum nss_status
+#define MAX_GETPWENT_USERS 250
+
+NSS_STATUS
_nss_winbind_getpwent_r(struct passwd *result, char *buffer,
- size_t buflen, int *errnop)
+ size_t buflen, int *errnop)
{
- enum nss_status ret;
- struct winbindd_response response;
+ NSS_STATUS ret;
+ struct winbindd_request request;
+ static int called_again;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getpwent\n", getpid());
+#endif
+
+ /* Return an entry from the cache if we have one, or if we are
+ called again because we exceeded our static buffer. */
+
+ if ((ndx_pw_cache < num_pw_cache) || called_again) {
+ goto return_result;
+ }
+
+ /* Else call winbindd to get a bunch of entries */
+
+ if (num_pw_cache > 0) {
+ free_response(&getpwent_response);
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(getpwent_response);
+
+ request.data.num_entries = MAX_GETPWENT_USERS;
+
+ ret = winbindd_request(WINBINDD_GETPWENT, &request,
+ &getpwent_response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ struct winbindd_pw *pw_cache;
+
+ /* Fill cache */
+
+ ndx_pw_cache = 0;
+ num_pw_cache = getpwent_response.data.num_entries;
- ret = generic_request(WINBINDD_GETPWENT, NULL, &response);
- if (ret != NSS_STATUS_SUCCESS) return ret;
+ /* Return a result */
- return fill_pwent(result, &response, &buffer, &buflen, errnop);
+ return_result:
+
+ pw_cache = getpwent_response.extra_data;
+
+ /* Check data is valid */
+
+ if (pw_cache == NULL) {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ ret = fill_pwent(result, &pw_cache[ndx_pw_cache],
+ &buffer, &buflen);
+
+ /* Out of memory - try again */
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ called_again = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+
+ *errnop = errno = 0;
+ called_again = False;
+ ndx_pw_cache++;
+
+ /* If we've finished with this lot of results free cache */
+
+ if (ndx_pw_cache == num_pw_cache) {
+ ndx_pw_cache = num_pw_cache = 0;
+ free_response(&getpwent_response);
+ }
+ }
+
+ return ret;
}
/* Return passwd struct from uid */
-enum nss_status
+NSS_STATUS
_nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
- size_t buflen, int *errnop)
+ size_t buflen, int *errnop)
{
- enum nss_status ret;
- struct winbindd_response response;
+ NSS_STATUS ret;
+ static struct winbindd_response response;
struct winbindd_request request;
+ static int keep_response=0;
+
+ /* If our static buffer needs to be expanded we are called again */
+ if (!keep_response) {
- request.data.uid = uid;
+ /* Call for the first time */
- ret = generic_request(WINBINDD_GETPWNAM_FROM_UID, &request, &response);
- if (ret != NSS_STATUS_SUCCESS) return ret;
+ ZERO_STRUCT(response);
+ ZERO_STRUCT(request);
- return fill_pwent(result, &response, &buffer, &buflen, errnop);
+ request.data.uid = uid;
+
+ ret = winbindd_request(WINBINDD_GETPWNAM_FROM_UID, &request,
+ &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ ret = fill_pwent(result, &response.data.pw,
+ &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+ }
+
+ } else {
+
+ /* We've been called again */
+
+ ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+
+ keep_response = False;
+ *errnop = errno = 0;
+ }
+
+ free_response(&response);
+ return ret;
}
/* Return passwd struct from username */
-enum nss_status
+NSS_STATUS
_nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer,
- size_t buflen, int *errnop)
+ size_t buflen, int *errnop)
{
- enum nss_status ret;
- struct winbindd_response response;
+ NSS_STATUS ret;
+ static struct winbindd_response response;
struct winbindd_request request;
+ static int keep_response;
- strncpy(request.data.username, name, sizeof(request.data.username) - 1);
- request.data.username[sizeof(request.data.username) - 1] = '\0';
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getpwnam %s\n", getpid(), name);
+#endif
- ret = generic_request(WINBINDD_GETPWNAM_FROM_USER, &request, &response);
- if (ret != NSS_STATUS_SUCCESS) return ret;
+ /* If our static buffer needs to be expanded we are called again */
- return fill_pwent(result, &response, &buffer, &buflen, errnop);
+ if (!keep_response) {
+
+ /* Call for the first time */
+
+ 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';
+
+ ret = winbindd_request(WINBINDD_GETPWNAM_FROM_USER, &request,
+ &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ ret = fill_pwent(result, &response.data.pw, &buffer,
+ &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+ }
+
+ } else {
+
+ /* We've been called again */
+
+ ret = fill_pwent(result, &response.data.pw, &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+
+ keep_response = False;
+ *errnop = errno = 0;
+ }
+
+ free_response(&response);
+ return ret;
}
/*
* NSS group functions
*/
+static struct winbindd_response getgrent_response;
+
+static int ndx_gr_cache; /* Current index into grp cache */
+static int num_gr_cache; /* Current size of grp cache */
+
/* Rewind "file pointer" to start of ntdom group database */
-enum nss_status
+NSS_STATUS
_nss_winbind_setgrent(void)
{
- return generic_request(WINBINDD_SETGRENT, NULL, NULL);
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: setgrent\n", getpid());
+#endif
+
+ if (num_gr_cache > 0) {
+ ndx_gr_cache = num_gr_cache = 0;
+ free_response(&getgrent_response);
+ }
+
+ return winbindd_request(WINBINDD_SETGRENT, NULL, NULL);
}
/* Close "file pointer" for ntdom group database */
-enum nss_status
+NSS_STATUS
_nss_winbind_endgrent(void)
{
- return generic_request(WINBINDD_ENDGRENT, NULL, NULL);
-}
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: endgrent\n", getpid());
+#endif
+ if (num_gr_cache > 0) {
+ ndx_gr_cache = num_gr_cache = 0;
+ free_response(&getgrent_response);
+ }
+ return winbindd_request(WINBINDD_ENDGRENT, NULL, NULL);
+}
/* Get next entry from ntdom group database */
-enum nss_status
+#define MAX_GETGRENT_USERS 250
+
+NSS_STATUS
_nss_winbind_getgrent_r(struct group *result,
- char *buffer, size_t buflen, int *errnop)
+ char *buffer, size_t buflen, int *errnop)
{
- enum nss_status ret;
- struct winbindd_response response;
+ NSS_STATUS ret;
+ static struct winbindd_request request;
+ static int called_again;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getgrent\n", getpid());
+#endif
+
+ /* Return an entry from the cache if we have one, or if we are
+ called again because we exceeded our static buffer. */
+
+ if ((ndx_gr_cache < num_gr_cache) || called_again) {
+ goto return_result;
+ }
+
+ /* Else call winbindd to get a bunch of entries */
+
+ if (num_gr_cache > 0) {
+ free_response(&getgrent_response);
+ }
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(getgrent_response);
+
+ request.data.num_entries = MAX_GETGRENT_USERS;
+
+ ret = winbindd_request(WINBINDD_GETGRENT, &request,
+ &getgrent_response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ struct winbindd_gr *gr_cache;
+ int mem_ofs;
+
+ /* Fill cache */
+
+ ndx_gr_cache = 0;
+ num_gr_cache = getgrent_response.data.num_entries;
+
+ /* Return a result */
+
+ return_result:
+
+ gr_cache = getgrent_response.extra_data;
+
+ /* Check data is valid */
+
+ if (gr_cache == NULL) {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* Fill group membership. The offset into the extra data
+ for the group membership is the reported offset plus the
+ size of all the winbindd_gr records returned. */
+
+ mem_ofs = gr_cache[ndx_gr_cache].gr_mem_ofs +
+ num_gr_cache * sizeof(struct winbindd_gr);
+
+ ret = fill_grent(result, &gr_cache[ndx_gr_cache],
+ (char *)(getgrent_response.extra_data +
+ mem_ofs), &buffer, &buflen);
+
+ /* Out of memory - try again */
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ called_again = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+
+ *errnop = 0;
+ called_again = False;
+ ndx_gr_cache++;
- ret = generic_request(WINBINDD_GETGRENT, NULL, &response);
- if (ret != NSS_STATUS_SUCCESS) return ret;
+ /* If we've finished with this lot of results free cache */
- return fill_grent(result, &response, &buffer, &buflen, errnop);
+ if (ndx_gr_cache == num_gr_cache) {
+ ndx_gr_cache = num_gr_cache = 0;
+ free_response(&getgrent_response);
+ }
+ }
+
+ return ret;
}
/* Return group struct from group name */
-enum nss_status
+NSS_STATUS
_nss_winbind_getgrnam_r(const char *name,
- struct group *result, char *buffer,
- size_t buflen, int *errnop)
+ struct group *result, char *buffer,
+ size_t buflen, int *errnop)
{
- enum nss_status ret;
- struct winbindd_response response;
+ NSS_STATUS ret;
+ static struct winbindd_response response;
struct winbindd_request request;
+ static int keep_response;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getgrnam %s\n", getpid(), name);
+#endif
- strncpy(request.data.groupname, name, sizeof(request.data.groupname));
- request.data.groupname[sizeof(request.data.groupname) - 1] = '\0';
-
- ret = generic_request(WINBINDD_GETGRNAM_FROM_GROUP, &request, &response);
- if (ret != NSS_STATUS_SUCCESS) return ret;
+ /* If our static buffer needs to be expanded we are called again */
+
+ if (!keep_response) {
+
+ /* Call for the first time */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ strncpy(request.data.groupname, name,
+ sizeof(request.data.groupname));
+ request.data.groupname
+ [sizeof(request.data.groupname) - 1] = '\0';
+
+ ret = winbindd_request(WINBINDD_GETGRNAM_FROM_GROUP,
+ &request, &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ ret = fill_grent(result, &response.data.gr,
+ response.extra_data,
+ &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+ }
+
+ } else {
+
+ /* We've been called again */
+
+ ret = fill_grent(result, &response.data.gr,
+ response.extra_data, &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+
+ keep_response = False;
+ *errnop = 0;
+ }
- return fill_grent(result, &response, &buffer, &buflen, errnop);
+ free_response(&response);
+ return ret;
}
/* Return group struct from gid */
-enum nss_status
+NSS_STATUS
_nss_winbind_getgrgid_r(gid_t gid,
- struct group *result, char *buffer,
- size_t buflen, int *errnop)
+ struct group *result, char *buffer,
+ size_t buflen, int *errnop)
{
- enum nss_status ret;
- struct winbindd_response response;
+ NSS_STATUS ret;
+ static struct winbindd_response response;
+ struct winbindd_request request;
+ static int keep_response;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: getgrgid %d\n", getpid(), gid);
+#endif
+
+ /* If our static buffer needs to be expanded we are called again */
+
+ if (!keep_response) {
+
+ /* Call for the first time */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ request.data.gid = gid;
+
+ ret = winbindd_request(WINBINDD_GETGRNAM_FROM_GID, &request,
+ &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+
+ ret = fill_grent(result, &response.data.gr,
+ response.extra_data,
+ &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+ }
+
+ } else {
+
+ /* We've been called again */
+
+ ret = fill_grent(result, &response.data.gr,
+ response.extra_data, &buffer, &buflen);
+
+ if (ret == NSS_STATUS_TRYAGAIN) {
+ keep_response = True;
+ *errnop = errno = ERANGE;
+ return ret;
+ }
+
+ keep_response = False;
+ *errnop = 0;
+ }
+
+ free_response(&response);
+ return ret;
+}
+
+/* Initialise supplementary groups */
+
+NSS_STATUS
+_nss_winbind_initgroups(char *user, gid_t group, long int *start,
+ long int *size, gid_t *groups, long int limit,
+ int *errnop)
+{
+ NSS_STATUS ret;
struct winbindd_request request;
+ struct winbindd_response response;
+ int i;
+
+#ifdef DEBUG_NSS
+ fprintf(stderr, "[%5d]: initgroups %s (%d)\n", getpid(),
+ user, group);
+#endif
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
- request.data.gid = gid;
+ strncpy(request.data.username, user,
+ sizeof(request.data.username) - 1);
- ret = generic_request(WINBINDD_GETGRNAM_FROM_GID, &request, &response);
- if (ret != NSS_STATUS_SUCCESS) return ret;
+ ret = winbindd_request(WINBINDD_GETGROUPS, &request, &response);
+
+ if (ret == NSS_STATUS_SUCCESS) {
+ int num_gids = response.data.num_entries;
+ gid_t *gid_list = (gid_t *)response.extra_data;
+
+ /* Copy group list to client */
+
+ for (i = 0; i < num_gids; i++) {
+
+ /* Skip primary group */
+
+ if (gid_list[i] == group) continue;
+
+ /* Add to buffer */
+
+ if (*start == *size && limit <= 0) {
+ groups = realloc(
+ groups, 2 * (*size) * sizeof(*groups));
+ if (!groups) goto done;
+ *size *= 2;
+ }
+
+ groups[*start] = gid_list[i];
+ *start += 1;
+
+ /* Filled buffer? */
+
+ if (*start == limit) goto done;
+ }
+ }
+
+ /* Back to your regularly scheduled programming */
- return fill_grent(result, &response, &buffer, &buflen, errnop);
+ done:
+ return ret;
}
diff --git a/source3/nsswitch/winbind_nss_config.h b/source3/nsswitch/winbind_nss_config.h
index c663842a81..5c09a5dd1b 100644
--- a/source3/nsswitch/winbind_nss_config.h
+++ b/source3/nsswitch/winbind_nss_config.h
@@ -70,17 +70,62 @@
#include <errno.h>
#include <pwd.h>
-#ifdef HAVE_NSS_H
+#ifdef HAVE_NSS_COMMON_H
+/* Sun Solaris */
+
+#include <nss_common.h>
+#include <nss_dbdefs.h>
+#include <nsswitch.h>
+
+typedef nss_status_t NSS_STATUS;
+
+#define NSS_STATUS_SUCCESS NSS_SUCCESS
+#define NSS_STATUS_NOTFOUND NSS_NOTFOUND
+#define NSS_STATUS_UNAVAIL NSS_UNAVAIL
+#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN
+
+#elif HAVE_NSS_H
+/* GNU */
+
#include <nss.h>
-#else
-/* Minimal needed to compile.. */
-enum nss_status {
-NSS_STATUS_SUCCESS,
-NSS_STATUS_NOTFOUND,
-NSS_STATUS_UNAVAIL
-};
+
+typedef enum nss_status NSS_STATUS;
+
+#else /* Nothing's defined. Neither gnu nor sun */
+
+typedef enum
+{
+ NSS_STATUS_SUCCESS,
+ NSS_STATUS_NOTFOUND,
+ NSS_STATUS_UNAVAIL,
+ NSS_STATUS_TRYAGAIN
+} NSS_STATUS;
+
#endif
+/* Declarations for functions in winbind_nss.c
+ needed in winbind_nss_solaris.c (solaris wrapper to nss) */
+
+NSS_STATUS _nss_winbind_setpwent(void);
+NSS_STATUS _nss_winbind_endpwent(void);
+NSS_STATUS _nss_winbind_getpwent_r(struct passwd* result, char* buffer,
+ size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getpwuid_r(uid_t, struct passwd*, char* buffer,
+ size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getpwnam_r(const char* name, struct passwd* result,
+ char* buffer, size_t buflen, int* errnop);
+
+NSS_STATUS _nss_winbind_setgrent(void);
+NSS_STATUS _nss_winbind_endgrent(void);
+NSS_STATUS _nss_winbind_getgrent_r(struct group* result, char* buffer,
+ size_t buflen, int* errnop);
+NSS_STATUS _nss_winbind_getgrnam_r(const char *name,
+ struct group *result, char *buffer,
+ size_t buflen, int *errnop);
+NSS_STATUS _nss_winbind_getgrgid_r(gid_t gid,
+ struct group *result, char *buffer,
+ size_t buflen, int *errnop);
+
/* I'm trying really hard not to include anything from smb.h with the
result of some silly looking redeclaration of structures. */
@@ -127,6 +172,7 @@ typedef int BOOL;
/* zero a structure given a pointer to the structure */
#define ZERO_STRUCTP(x) { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); }
+
/* Some systems (SCO) treat UNIX domain sockets as FIFOs */
#ifndef S_IFSOCK