diff options
Diffstat (limited to 'source3/nsswitch/winbind_nss.c')
-rw-r--r-- | source3/nsswitch/winbind_nss.c | 465 |
1 files changed, 465 insertions, 0 deletions
diff --git a/source3/nsswitch/winbind_nss.c b/source3/nsswitch/winbind_nss.c new file mode 100644 index 0000000000..48dc1882b3 --- /dev/null +++ b/source3/nsswitch/winbind_nss.c @@ -0,0 +1,465 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + Windows NT Domain nsswitch module + + Copyright (C) Tim Potter 2000 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "ntdom_config.h" +#include "winbindd_ntdom.h" + +/* prototypes from common.c */ +void init_request(struct winbindd_request *req,int rq_type); +int write_sock(void *buffer, int count); +int read_reply(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_* + functions. */ + +static char *get_static(char **buffer, int *buflen, int len) +{ + char *result; + + /* 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; + } + + /* Return an index into the static buffer */ + + result = *buffer; + *buffer += len; + *buflen -= len; + + 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; + + if (!ptr) ptr = &last_ptr; + 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; + } + } + + *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; +} + +/* 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. */ + +static enum nss_status fill_pwent(struct passwd *result, + struct winbindd_response *response, + char **buffer, int *buflen, int *errnop) +{ + struct winbindd_pw *pw = &response->data.pw; + + /* User name */ + + if ((result->pw_name = + get_static(buffer, buflen, strlen(pw->pw_name) + 1)) == NULL) { + + /* Out of memory */ + + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + strcpy(result->pw_name, pw->pw_name); + + /* Password */ + + if ((result->pw_passwd = + get_static(buffer, buflen, strlen(pw->pw_passwd) + 1)) == NULL) { + + /* Out of memory */ + + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + 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 = + get_static(buffer, buflen, strlen(pw->pw_gecos) + 1)) == NULL) { + + /* Out of memory */ + + *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) { + + /* Out of memory */ + + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + strcpy(result->pw_dir, pw->pw_dir); + + /* 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; + } + + strcpy(result->pw_shell, pw->pw_shell); + + 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. */ + +static int fill_grent(struct group *result, + struct winbindd_response *response, + char **buffer, int *buflen, int *errnop) +{ + struct winbindd_gr *gr = &response->data.gr; + fstring name; + int i; + + /* Group name */ + + if ((result->gr_name = + get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) { + + /* Out of memory */ + + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + strcpy(result->gr_name, gr->gr_name); + + /* Password */ + + if ((result->gr_passwd = + get_static(buffer, buflen, strlen(gr->gr_passwd) + 1)) == NULL) { + + /* Out of memory */ + + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + strcpy(result->gr_passwd, gr->gr_passwd); + + /* gid */ + + result->gr_gid = gr->gr_gid; + + /* Group membership */ + + if ((gr->num_gr_mem < 0) || !response->extra_data) { + gr->num_gr_mem = 0; + } + + if ((result->gr_mem = + (char **)get_static(buffer, buflen, (gr->num_gr_mem + 1) * + sizeof(char *))) == NULL) { + + /* Out of memory */ + + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + if (gr->num_gr_mem == 0) { + + /* Group is empty */ + + *(result->gr_mem) = NULL; + return NSS_STATUS_SUCCESS; + } + + /* Start looking at extra data */ + + i = 0; + + while(next_token(&response->extra_data, name, ",", sizeof(fstring))) { + + /* Allocate space for member */ + + if (((result->gr_mem)[i] = + get_static(buffer, buflen, strlen(name) + 1)) == NULL) { + + /* Out of memory */ + + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + strcpy((result->gr_mem)[i], name); + i++; + } + + /* Terminate list */ + + (result->gr_mem)[i] = NULL; + + return NSS_STATUS_SUCCESS; +} + +/* + * NSS user functions + */ + +/* Rewind "file pointer" to start of ntdom password database */ + +enum nss_status +_nss_ntdom_setpwent(void) +{ + return generic_request(WINBINDD_SETPWENT, NULL, NULL); +} + +/* Close ntdom password database "file pointer" */ + +enum nss_status +_nss_ntdom_endpwent(void) +{ + return generic_request(WINBINDD_ENDPWENT, NULL, NULL); +} + +/* Fetch the next password entry from ntdom password database */ + +enum nss_status +_nss_ntdom_getpwent_r(struct passwd *result, char *buffer, + size_t buflen, int *errnop) +{ + enum nss_status ret; + struct winbindd_response response; + + ret = generic_request(WINBINDD_GETPWENT, NULL, &response); + if (ret != NSS_STATUS_SUCCESS) return ret; + + return fill_pwent(result, &response, &buffer, &buflen, errnop); +} + +/* Return passwd struct from uid */ + +enum nss_status +_nss_ntdom_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, + size_t buflen, int *errnop) +{ + enum nss_status ret; + struct winbindd_response response; + struct winbindd_request request; + + request.data.uid = uid; + + ret = generic_request(WINBINDD_GETPWNAM_FROM_UID, &request, &response); + if (ret != NSS_STATUS_SUCCESS) return ret; + + return fill_pwent(result, &response, &buffer, &buflen, errnop); +} + +/* Return passwd struct from username */ + +enum nss_status +_nss_ntdom_getpwnam_r(const char *name, struct passwd *result, char *buffer, + size_t buflen, int *errnop) +{ + enum nss_status ret; + struct winbindd_response response; + struct winbindd_request request; + + strncpy(request.data.username, name, sizeof(request.data.username) - 1); + request.data.username[sizeof(request.data.username) - 1] = '\0'; + + ret = generic_request(WINBINDD_GETPWNAM_FROM_USER, &request, &response); + if (ret != NSS_STATUS_SUCCESS) return ret; + + return fill_pwent(result, &response, &buffer, &buflen, errnop); +} + +/* + * NSS group functions + */ + +/* Rewind "file pointer" to start of ntdom group database */ + +enum nss_status +_nss_ntdom_setgrent(void) +{ + return generic_request(WINBINDD_SETGRENT, NULL, NULL); +} + +/* Close "file pointer" for ntdom group database */ + +enum nss_status +_nss_ntdom_endgrent(void) +{ + return generic_request(WINBINDD_ENDGRENT, NULL, NULL); +} + + + +/* Get next entry from ntdom group database */ + +enum nss_status +_nss_ntdom_getgrent_r(struct group *result, + char *buffer, size_t buflen, int *errnop) +{ + enum nss_status ret; + struct winbindd_response response; + + ret = generic_request(WINBINDD_GETGRENT, NULL, &response); + if (ret != NSS_STATUS_SUCCESS) return ret; + + return fill_grent(result, &response, &buffer, &buflen, errnop); +} + +/* Return group struct from group name */ + +enum nss_status +_nss_ntdom_getgrnam_r(const char *name, + struct group *result, char *buffer, + size_t buflen, int *errnop) +{ + enum nss_status ret; + struct winbindd_response response; + struct winbindd_request request; + + 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; + + return fill_grent(result, &response, &buffer, &buflen, errnop); +} + +/* Return group struct from gid */ + +enum nss_status +_nss_ntdom_getgrgid_r(gid_t gid, + struct group *result, char *buffer, + size_t buflen, int *errnop) +{ + enum nss_status ret; + struct winbindd_response response; + struct winbindd_request request; + + request.data.gid = gid; + + ret = generic_request(WINBINDD_GETGRNAM_FROM_GID, &request, &response); + if (ret != NSS_STATUS_SUCCESS) return ret; + + return fill_grent(result, &response, &buffer, &buflen, errnop); +} |