From 5f9dca64daea8bf910a66e1178ad0336628fdc9f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 25 Apr 2001 05:47:50 +0000 Subject: merge some of the nsswitch code from tng to head the libnss_winbind.so from head now works with the winbindd from tng (This used to be commit 67ccfd2826548a6ca22562f9fb3ae156a57bd7db) --- source3/nsswitch/winbind_nss.c | 889 +++++++++++++++++++++++++++++------------ 1 file changed, 637 insertions(+), 252 deletions(-) (limited to 'source3/nsswitch/winbind_nss.c') 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; } -- cgit