📄 winbind_nss_linux.c
字号:
/* Unix SMB/CIFS implementation. 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 Lesser General Public License as published by the Free Software Foundation; either version 3 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 Lesser General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/#include "winbind_client.h"/* Maximum number of users to pass back over the unix domain socket per call. This is not a static limit on the total number of users or groups returned in total. */#define MAX_GETPWENT_USERS 250#define MAX_GETGRENT_USERS 250NSS_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 uid, struct passwd *result, 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_getgrlst_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);NSS_STATUS _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start, long int *size, gid_t **groups, long int limit, int *errnop);NSS_STATUS _nss_winbind_getusersids(const char *user_sid, char **group_sids, int *num_groups, char *buffer, size_t buf_size, int *errnop);NSS_STATUS _nss_winbind_nametosid(const char *name, char **sid, char *buffer, size_t buflen, int *errnop);NSS_STATUS _nss_winbind_sidtoname(const char *sid, char **name, char *buffer, size_t buflen, int *errnop);NSS_STATUS _nss_winbind_sidtouid(const char *sid, uid_t *uid, int *errnop);NSS_STATUS _nss_winbind_sidtogid(const char *sid, gid_t *gid, int *errnop);NSS_STATUS _nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer, size_t buflen, int *errnop);NSS_STATUS _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer, size_t buflen, int *errnop);/* Prototypes from wb_common.c */extern int winbindd_fd;/* 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, size_t *buflen, size_t 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. */static bool next_token(char **ptr,char *buff,const 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; } } *ptr = (*s) ? s+1 : s; *buff = 0; 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 NSS_STATUS_TRYAGAIN if we run out of memory. */static NSS_STATUS fill_pwent(struct passwd *result, struct winbindd_pw *pw, char **buffer, size_t *buflen){ /* User name */ if ((result->pw_name = get_static(buffer, buflen, strlen(pw->pw_name) + 1)) == NULL) { /* Out of memory */ 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 */ 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 */ 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 */ 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 */ return NSS_STATUS_TRYAGAIN; } strcpy(result->pw_shell, pw->pw_shell); /* The struct passwd for Solaris has some extra fields which must be initialised or nscd crashes. */#if HAVE_PASSWD_PW_COMMENT result->pw_comment = "";#endif#if HAVE_PASSWD_PW_AGE result->pw_age = "";#endif 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 NSS_STATUS_TRYAGAIN if we run out of memory. */static NSS_STATUS fill_grent(struct group *result, struct winbindd_gr *gr, char *gr_mem, char **buffer, size_t *buflen){ fstring name; int i; char *tst; /* Group name */ if ((result->gr_name = get_static(buffer, buflen, strlen(gr->gr_name) + 1)) == NULL) { /* Out of memory */ 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 */ 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) || !gr_mem) { gr->num_gr_mem = 0; } /* this next value is a pointer to a pointer so let's align it */ /* Calculate number of extra bytes needed to align on pointer size boundry */ if ((i = (unsigned long)(*buffer) % sizeof(char*)) != 0) i = sizeof(char*) - i; if ((tst = get_static(buffer, buflen, ((gr->num_gr_mem + 1) * sizeof(char *)+i))) == NULL) { /* Out of memory */ return NSS_STATUS_TRYAGAIN; } result->gr_mem = (char **)(tst + i); 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((char **)&gr_mem, name, ",", sizeof(fstring))) { /* Allocate space for member */ if (((result->gr_mem)[i] = get_static(buffer, buflen, strlen(name) + 1)) == NULL) { /* Out of memory */ 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 */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 */NSS_STATUS_nss_winbind_setpwent(void){ NSS_STATUS ret;#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: setpwent\n", getpid());#endif if (num_pw_cache > 0) { ndx_pw_cache = num_pw_cache = 0; winbindd_free_response(&getpwent_response); } ret = winbindd_request_response(WINBINDD_SETPWENT, NULL, NULL);#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: setpwent returns %s (%d)\n", getpid(), nss_err_str(ret), ret);#endif return ret;}/* Close ntdom password database "file pointer" */NSS_STATUS_nss_winbind_endpwent(void){ NSS_STATUS ret;#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: endpwent\n", getpid());#endif if (num_pw_cache > 0) { ndx_pw_cache = num_pw_cache = 0; winbindd_free_response(&getpwent_response); } ret = winbindd_request_response(WINBINDD_ENDPWENT, NULL, NULL);#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: endpwent returns %s (%d)\n", getpid(), nss_err_str(ret), ret);#endif return ret;}/* Fetch the next password entry from ntdom password database */NSS_STATUS_nss_winbind_getpwent_r(struct passwd *result, char *buffer, size_t buflen, int *errnop){ 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) { winbindd_free_response(&getpwent_response); } ZERO_STRUCT(request); ZERO_STRUCT(getpwent_response); request.data.num_entries = MAX_GETPWENT_USERS; ret = winbindd_request_response(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; /* Return a result */ return_result: pw_cache = (struct winbindd_pw *) getpwent_response.extra_data.data; /* Check data is valid */ if (pw_cache == NULL) { ret = NSS_STATUS_NOTFOUND; goto done; } 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; goto done; } *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; winbindd_free_response(&getpwent_response); } } done:#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getpwent returns %s (%d)\n", getpid(), nss_err_str(ret), ret);#endif return ret;}/* Return passwd struct from uid */NSS_STATUS_nss_winbind_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, size_t buflen, int *errnop){ NSS_STATUS ret; static struct winbindd_response response; struct winbindd_request request; static int keep_response=0;#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getpwuid %d\n", getpid(), (unsigned int)uid);#endif /* If our static buffer needs to be expanded we are called again */ if (!keep_response) { /* Call for the first time */ ZERO_STRUCT(response); ZERO_STRUCT(request); request.data.uid = uid; ret = winbindd_request_response(WINBINDD_GETPWUID, &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; goto done; } } } 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; goto done; } keep_response = false; *errnop = errno = 0; } winbindd_free_response(&response); done:#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getpwuid %d returns %s (%d)\n", getpid(), (unsigned int)uid, nss_err_str(ret), ret);#endif return ret;}/* Return passwd struct from username */NSS_STATUS_nss_winbind_getpwnam_r(const char *name, struct passwd *result, char *buffer, size_t buflen, int *errnop){ NSS_STATUS ret; static struct winbindd_response response; struct winbindd_request request; static int keep_response;#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getpwnam %s\n", getpid(), name);#endif /* If our static buffer needs to be expanded we are called again */ 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_response(WINBINDD_GETPWNAM, &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; goto done; } } } 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; goto done; } keep_response = false; *errnop = errno = 0; } winbindd_free_response(&response); done:#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: getpwnam %s returns %s (%d)\n", getpid(), name, nss_err_str(ret), ret);#endif 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 */NSS_STATUS_nss_winbind_setgrent(void){ NSS_STATUS ret;#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: setgrent\n", getpid());#endif if (num_gr_cache > 0) { ndx_gr_cache = num_gr_cache = 0; winbindd_free_response(&getgrent_response); } ret = winbindd_request_response(WINBINDD_SETGRENT, NULL, NULL);#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: setgrent returns %s (%d)\n", getpid(), nss_err_str(ret), ret);#endif return ret;}/* Close "file pointer" for ntdom group database */NSS_STATUS_nss_winbind_endgrent(void){ NSS_STATUS ret;#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: endgrent\n", getpid());#endif if (num_gr_cache > 0) { ndx_gr_cache = num_gr_cache = 0; winbindd_free_response(&getgrent_response); } ret = winbindd_request_response(WINBINDD_ENDGRENT, NULL, NULL);#ifdef DEBUG_NSS fprintf(stderr, "[%5d]: endgrent returns %s (%d)\n", getpid(), nss_err_str(ret), ret);#endif return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -