summaryrefslogtreecommitdiffstats
path: root/nsswitch/libwbclient/wbc_pwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'nsswitch/libwbclient/wbc_pwd.c')
-rw-r--r--nsswitch/libwbclient/wbc_pwd.c722
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);
+}