diff options
Diffstat (limited to '')
-rw-r--r-- | nsswitch/libwbclient/wbc_pwd.c | 722 |
1 files changed, 722 insertions, 0 deletions
diff --git a/nsswitch/libwbclient/wbc_pwd.c b/nsswitch/libwbclient/wbc_pwd.c new file mode 100644 index 0000000..4e83fbf --- /dev/null +++ b/nsswitch/libwbclient/wbc_pwd.c @@ -0,0 +1,722 @@ +/* + Unix SMB/CIFS implementation. + + Winbind client API + + Copyright (C) Gerald (Jerry) Carter 2007 + Copyright (C) Matthew Newton 2015 + + + 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/>. +*/ + +/* Required Headers */ + +#include "replace.h" +#include "libwbclient.h" +#include "../winbind_client.h" + +/** @brief The maximum number of pwent structs to get from winbindd + * + */ +#define MAX_GETPWENT_USERS 500 + +/** @brief The maximum number of grent structs to get from winbindd + * + */ +#define MAX_GETGRENT_GROUPS 500 + +/** + * + **/ + +static void wbcPasswdDestructor(void *ptr) +{ + struct passwd *pw = (struct passwd *)ptr; + free(pw->pw_name); + free(pw->pw_passwd); + free(pw->pw_gecos); + free(pw->pw_shell); + free(pw->pw_dir); +} + +static struct passwd *copy_passwd_entry(struct winbindd_pw *p) +{ + struct passwd *pw = NULL; + + pw = (struct passwd *)wbcAllocateMemory(1, sizeof(struct passwd), + wbcPasswdDestructor); + if (pw == NULL) { + return NULL; + } + pw->pw_name = strdup(p->pw_name); + if (pw->pw_name == NULL) { + goto fail; + } + pw->pw_passwd = strdup(p->pw_passwd); + if (pw->pw_passwd == NULL) { + goto fail; + } + pw->pw_gecos = strdup(p->pw_gecos); + if (pw->pw_gecos == NULL) { + goto fail; + } + pw->pw_shell = strdup(p->pw_shell); + if (pw->pw_shell == NULL) { + goto fail; + } + pw->pw_dir = strdup(p->pw_dir); + if (pw->pw_dir == NULL) { + goto fail; + } + pw->pw_uid = p->pw_uid; + pw->pw_gid = p->pw_gid; + return pw; + +fail: + wbcFreeMemory(pw); + return NULL; +} + +/** + * + **/ + +static void wbcGroupDestructor(void *ptr) +{ + struct group *gr = (struct group *)ptr; + int i; + + free(gr->gr_name); + free(gr->gr_passwd); + + /* if the array was partly created this can be NULL */ + if (gr->gr_mem == NULL) { + return; + } + + for (i=0; gr->gr_mem[i] != NULL; i++) { + free(gr->gr_mem[i]); + } + free(gr->gr_mem); +} + +static struct group *copy_group_entry(struct winbindd_gr *g, + char *mem_buf) +{ + struct group *gr = NULL; + int i; + char *mem_p, *mem_q; + + gr = (struct group *)wbcAllocateMemory( + 1, sizeof(struct group), wbcGroupDestructor); + if (gr == NULL) { + return NULL; + } + + gr->gr_name = strdup(g->gr_name); + if (gr->gr_name == NULL) { + goto fail; + } + gr->gr_passwd = strdup(g->gr_passwd); + if (gr->gr_passwd == NULL) { + goto fail; + } + gr->gr_gid = g->gr_gid; + + gr->gr_mem = (char **)calloc(g->num_gr_mem+1, sizeof(char *)); + if (gr->gr_mem == NULL) { + goto fail; + } + + mem_p = mem_q = mem_buf; + for (i=0; i<g->num_gr_mem && mem_p; i++) { + mem_q = strchr(mem_p, ','); + if (mem_q != NULL) { + *mem_q = '\0'; + } + + gr->gr_mem[i] = strdup(mem_p); + if (gr->gr_mem[i] == NULL) { + goto fail; + } + + if (mem_q == NULL) { + i += 1; + break; + } + mem_p = mem_q + 1; + } + gr->gr_mem[i] = NULL; + + return gr; + +fail: + wbcFreeMemory(gr); + return NULL; +} + +/* Fill in a struct passwd* for a domain user based on username */ +_PUBLIC_ +wbcErr wbcCtxGetpwnam(struct wbcContext *ctx, + const char *name, struct passwd **pwd) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct winbindd_request request; + struct winbindd_response response; + + if (!name || !pwd) { + wbc_status = WBC_ERR_INVALID_PARAM; + BAIL_ON_WBC_ERROR(wbc_status); + } + + /* Initialize request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + /* dst is already null terminated from the memset above */ + + strncpy(request.data.username, name, sizeof(request.data.username)-1); + + wbc_status = wbcRequestResponse(ctx, WINBINDD_GETPWNAM, + &request, + &response); + BAIL_ON_WBC_ERROR(wbc_status); + + *pwd = copy_passwd_entry(&response.data.pw); + BAIL_ON_PTR_ERROR(*pwd, wbc_status); + + done: + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcGetpwnam(const char *name, struct passwd **pwd) +{ + return wbcCtxGetpwnam(NULL, name, pwd); +} + +/* Fill in a struct passwd* for a domain user based on uid */ +_PUBLIC_ +wbcErr wbcCtxGetpwuid(struct wbcContext *ctx, uid_t uid, struct passwd **pwd) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct winbindd_request request; + struct winbindd_response response; + + if (!pwd) { + wbc_status = WBC_ERR_INVALID_PARAM; + BAIL_ON_WBC_ERROR(wbc_status); + } + + /* Initialize request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + request.data.uid = uid; + + wbc_status = wbcRequestResponse(ctx, WINBINDD_GETPWUID, + &request, + &response); + BAIL_ON_WBC_ERROR(wbc_status); + + *pwd = copy_passwd_entry(&response.data.pw); + BAIL_ON_PTR_ERROR(*pwd, wbc_status); + + done: + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcGetpwuid(uid_t uid, struct passwd **pwd) +{ + return wbcCtxGetpwuid(NULL, uid, pwd); +} + +/* Fill in a struct passwd* for a domain user based on sid */ +_PUBLIC_ +wbcErr wbcCtxGetpwsid(struct wbcContext *ctx, + struct wbcDomainSid *sid, struct passwd **pwd) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct winbindd_request request; + struct winbindd_response response; + + if (!pwd) { + wbc_status = WBC_ERR_INVALID_PARAM; + BAIL_ON_WBC_ERROR(wbc_status); + } + + /* Initialize request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid)); + + wbc_status = wbcRequestResponse(ctx, WINBINDD_GETPWSID, + &request, + &response); + BAIL_ON_WBC_ERROR(wbc_status); + + *pwd = copy_passwd_entry(&response.data.pw); + BAIL_ON_PTR_ERROR(*pwd, wbc_status); + + done: + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcGetpwsid(struct wbcDomainSid *sid, struct passwd **pwd) +{ + return wbcCtxGetpwsid(NULL, sid, pwd); +} + +/* Fill in a struct passwd* for a domain user based on username */ +_PUBLIC_ +wbcErr wbcCtxGetgrnam(struct wbcContext *ctx, + const char *name, struct group **grp) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct winbindd_request request; + struct winbindd_response response; + + /* Initialize request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + if (!name || !grp) { + wbc_status = WBC_ERR_INVALID_PARAM; + BAIL_ON_WBC_ERROR(wbc_status); + } + + /* dst is already null terminated from the memset above */ + + strncpy(request.data.groupname, name, sizeof(request.data.groupname)-1); + + wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGRNAM, + &request, + &response); + BAIL_ON_WBC_ERROR(wbc_status); + + *grp = copy_group_entry(&response.data.gr, + (char*)response.extra_data.data); + BAIL_ON_PTR_ERROR(*grp, wbc_status); + + done: + winbindd_free_response(&response); + + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcGetgrnam(const char *name, struct group **grp) +{ + return wbcCtxGetgrnam(NULL, name, grp); +} + +/* Fill in a struct passwd* for a domain user based on uid */ +_PUBLIC_ +wbcErr wbcCtxGetgrgid(struct wbcContext *ctx, gid_t gid, struct group **grp) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct winbindd_request request; + struct winbindd_response response; + + /* Initialize request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + if (!grp) { + wbc_status = WBC_ERR_INVALID_PARAM; + BAIL_ON_WBC_ERROR(wbc_status); + } + + request.data.gid = gid; + + wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGRGID, + &request, + &response); + BAIL_ON_WBC_ERROR(wbc_status); + + *grp = copy_group_entry(&response.data.gr, + (char*)response.extra_data.data); + BAIL_ON_PTR_ERROR(*grp, wbc_status); + + done: + winbindd_free_response(&response); + + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcGetgrgid(gid_t gid, struct group **grp) +{ + return wbcCtxGetgrgid(NULL, gid, grp); +} + +/** @brief Winbindd response containing the passwd structs + * + */ +static struct winbindd_response pw_response; + +/* Reset the passwd iterator */ +_PUBLIC_ +wbcErr wbcCtxSetpwent(struct wbcContext *ctx) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + + if (!ctx) { + ctx = wbcGetGlobalCtx(); + } + + if (ctx->pw_cache_size > 0) { + ctx->pw_cache_idx = ctx->pw_cache_size = 0; + winbindd_free_response(&pw_response); + } + + ZERO_STRUCT(pw_response); + + wbc_status = wbcRequestResponse(ctx, WINBINDD_SETPWENT, + NULL, NULL); + BAIL_ON_WBC_ERROR(wbc_status); + + done: + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcSetpwent(void) +{ + return wbcCtxSetpwent(NULL); +} + +/* Close the passwd iterator */ +_PUBLIC_ +wbcErr wbcCtxEndpwent(struct wbcContext *ctx) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + + if (!ctx) { + ctx = wbcGetGlobalCtx(); + } + + if (ctx->pw_cache_size > 0) { + ctx->pw_cache_idx = ctx->pw_cache_size = 0; + winbindd_free_response(&pw_response); + } + + wbc_status = wbcRequestResponse(ctx, WINBINDD_ENDPWENT, + NULL, NULL); + BAIL_ON_WBC_ERROR(wbc_status); + + done: + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcEndpwent(void) +{ + return wbcCtxEndpwent(NULL); +} + +/* Return the next struct passwd* entry from the pwent iterator */ +_PUBLIC_ +wbcErr wbcCtxGetpwent(struct wbcContext *ctx, struct passwd **pwd) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct winbindd_request request; + struct winbindd_pw *wb_pw; + + if (!ctx) { + ctx = wbcGetGlobalCtx(); + } + + /* If there's a cached result, return that. */ + if (ctx->pw_cache_idx < ctx->pw_cache_size) { + goto return_result; + } + + /* Otherwise, query winbindd for some entries. */ + + ctx->pw_cache_idx = 0; + + winbindd_free_response(&pw_response); + + ZERO_STRUCT(request); + request.data.num_entries = MAX_GETPWENT_USERS; + + wbc_status = wbcRequestResponse(ctx, WINBINDD_GETPWENT, &request, + &pw_response); + + BAIL_ON_WBC_ERROR(wbc_status); + + ctx->pw_cache_size = pw_response.data.num_entries; + +return_result: + + wb_pw = (struct winbindd_pw *) pw_response.extra_data.data; + + *pwd = copy_passwd_entry(&wb_pw[ctx->pw_cache_idx]); + + BAIL_ON_PTR_ERROR(*pwd, wbc_status); + + ctx->pw_cache_idx++; + +done: + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcGetpwent(struct passwd **pwd) +{ + return wbcCtxGetpwent(NULL, pwd); +} + +/** @brief Winbindd response containing the group structs + * + */ +static struct winbindd_response gr_response; + +/* Reset the group iterator */ +_PUBLIC_ +wbcErr wbcCtxSetgrent(struct wbcContext *ctx) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + + if (!ctx) { + ctx = wbcGetGlobalCtx(); + } + + if (ctx->gr_cache_size > 0) { + ctx->gr_cache_idx = ctx->gr_cache_size = 0; + winbindd_free_response(&gr_response); + } + + ZERO_STRUCT(gr_response); + + wbc_status = wbcRequestResponse(ctx, WINBINDD_SETGRENT, + NULL, NULL); + BAIL_ON_WBC_ERROR(wbc_status); + + done: + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcSetgrent(void) +{ + return wbcCtxSetgrent(NULL); +} + +/* Close the group iterator */ +_PUBLIC_ +wbcErr wbcCtxEndgrent(struct wbcContext *ctx) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + + if (!ctx) { + ctx = wbcGetGlobalCtx(); + } + + if (ctx->gr_cache_size > 0) { + ctx->gr_cache_idx = ctx->gr_cache_size = 0; + winbindd_free_response(&gr_response); + } + + wbc_status = wbcRequestResponse(ctx, WINBINDD_ENDGRENT, + NULL, NULL); + BAIL_ON_WBC_ERROR(wbc_status); + + done: + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcEndgrent(void) +{ + return wbcCtxEndgrent(NULL); +} + +/* Return the next struct group* entry from the pwent iterator */ +_PUBLIC_ +wbcErr wbcCtxGetgrent(struct wbcContext *ctx, struct group **grp) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct winbindd_request request; + struct winbindd_gr *wb_gr; + uint32_t mem_ofs; + + if (!ctx) { + ctx = wbcGetGlobalCtx(); + } + + /* If there's a cached result, return that. */ + if (ctx->gr_cache_idx < ctx->gr_cache_size) { + goto return_result; + } + + /* Otherwise, query winbindd for some entries. */ + + ctx->gr_cache_idx = 0; + + winbindd_free_response(&gr_response); + + ZERO_STRUCT(request); + request.data.num_entries = MAX_GETGRENT_GROUPS; + + wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGRENT, + &request, &gr_response); + + BAIL_ON_WBC_ERROR(wbc_status); + + ctx->gr_cache_size = gr_response.data.num_entries; + +return_result: + + wb_gr = (struct winbindd_gr *) gr_response.extra_data.data; + + mem_ofs = wb_gr[ctx->gr_cache_idx].gr_mem_ofs + + ctx->gr_cache_size * sizeof(struct winbindd_gr); + + *grp = copy_group_entry(&wb_gr[ctx->gr_cache_idx], + ((char *)gr_response.extra_data.data)+mem_ofs); + + BAIL_ON_PTR_ERROR(*grp, wbc_status); + + ctx->gr_cache_idx++; + +done: + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcGetgrent(struct group **grp) +{ + return wbcCtxGetgrent(NULL, grp); +} + +/* Return the next struct group* entry from the pwent iterator */ +_PUBLIC_ +wbcErr wbcCtxGetgrlist(struct wbcContext *ctx, struct group **grp) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct winbindd_request request; + struct winbindd_gr *wb_gr; + + if (!ctx) { + ctx = wbcGetGlobalCtx(); + } + + /* If there's a cached result, return that. */ + if (ctx->gr_cache_idx < ctx->gr_cache_size) { + goto return_result; + } + + /* Otherwise, query winbindd for some entries. */ + + ctx->gr_cache_idx = 0; + + winbindd_free_response(&gr_response); + ZERO_STRUCT(gr_response); + + ZERO_STRUCT(request); + request.data.num_entries = MAX_GETGRENT_GROUPS; + + wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGRLST, + &request, &gr_response); + + BAIL_ON_WBC_ERROR(wbc_status); + + ctx->gr_cache_size = gr_response.data.num_entries; + +return_result: + + wb_gr = (struct winbindd_gr *) gr_response.extra_data.data; + + *grp = copy_group_entry(&wb_gr[ctx->gr_cache_idx], NULL); + + BAIL_ON_PTR_ERROR(*grp, wbc_status); + + ctx->gr_cache_idx++; + +done: + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcGetgrlist(struct group **grp) +{ + return wbcCtxGetgrlist(NULL, grp); +} + +/* Return the unix group array belonging to the given user */ +_PUBLIC_ +wbcErr wbcCtxGetGroups(struct wbcContext *ctx, const char *account, + uint32_t *num_groups, gid_t **_groups) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct winbindd_request request; + struct winbindd_response response; + uint32_t i; + gid_t *groups = NULL; + + /* Initialize request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + if (!account) { + wbc_status = WBC_ERR_INVALID_PARAM; + BAIL_ON_WBC_ERROR(wbc_status); + } + + /* Send request */ + + strncpy(request.data.username, account, sizeof(request.data.username)-1); + + wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGROUPS, + &request, + &response); + BAIL_ON_WBC_ERROR(wbc_status); + + groups = (gid_t *)wbcAllocateMemory( + response.data.num_entries, sizeof(gid_t), NULL); + BAIL_ON_PTR_ERROR(groups, wbc_status); + + for (i = 0; i < response.data.num_entries; i++) { + groups[i] = ((gid_t *)response.extra_data.data)[i]; + } + + *num_groups = response.data.num_entries; + *_groups = groups; + groups = NULL; + + wbc_status = WBC_ERR_SUCCESS; + + done: + winbindd_free_response(&response); + wbcFreeMemory(groups); + return wbc_status; +} + +_PUBLIC_ +wbcErr wbcGetGroups(const char *account, uint32_t *num_groups, gid_t **_groups) +{ + return wbcCtxGetGroups(NULL, account, num_groups, _groups); +} |