summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/winbind/config.mk1
-rw-r--r--source4/winbind/wb_cmd_getgroups.c215
-rw-r--r--source4/winbind/wb_samba3_cmd.c74
3 files changed, 273 insertions, 17 deletions
diff --git a/source4/winbind/config.mk b/source4/winbind/config.mk
index 45164d349a..0bee89c93b 100644
--- a/source4/winbind/config.mk
+++ b/source4/winbind/config.mk
@@ -52,6 +52,7 @@ WINBIND_OBJ_FILES = $(addprefix $(winbindsrcdir)/, \
wb_cmd_getpwent.o \
wb_cmd_getgrent.o \
wb_cmd_setgrent.o \
+ wb_cmd_getgroups.o \
wb_pam_auth.o \
wb_sam_logon.o)
diff --git a/source4/winbind/wb_cmd_getgroups.c b/source4/winbind/wb_cmd_getgroups.c
new file mode 100644
index 0000000000..de70b0b911
--- /dev/null
+++ b/source4/winbind/wb_cmd_getgroups.c
@@ -0,0 +1,215 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Backend for getgroups
+
+ Copyright (C) Matthieu Patou 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "libcli/security/dom_sid.h"
+
+struct cmd_getgroups_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ char* username;
+ uint32_t num_groups;
+ uint32_t current_group;
+ struct dom_sid **sids;
+
+ gid_t *gids;
+};
+
+/* The idea is to get the groups for a user
+ We receive one user from this we search for his uid
+ From the uid we search for his SID
+ From the SID we search for the list of groups
+ And with the list of groups we search for each group its gid
+*/
+static void cmd_getgroups_recv_pwnam(struct composite_context *ctx);
+static void wb_getgroups_uid2sid_recv(struct composite_context *ctx);
+static void wb_getgroups_userdomsgroups_recv(struct composite_context *ctx);
+static void cmd_getgroups_recv_gid(struct composite_context *ctx);
+
+/*
+ Ask for the uid from the username
+*/
+struct composite_context *wb_cmd_getgroups_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const char* username)
+{
+ struct composite_context *ctx, *result;
+ struct cmd_getgroups_state *state;
+
+ DEBUG(5, ("wb_cmd_getgroups_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(mem_ctx, struct cmd_getgroups_state);
+ if (composite_nomem(state, result)) return result;
+
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+ state->num_groups = 0;
+
+ state->username = talloc_strdup(state,username);
+ if (composite_nomem(ctx, result)) return result;
+
+ ctx = wb_cmd_getpwnam_send(state, service, username);
+ if (composite_nomem(ctx, result)) return result;
+
+ composite_continue(result, ctx, cmd_getgroups_recv_pwnam, state);
+ return result;
+}
+
+/*
+ Receive the uid and send request for SID
+*/
+static void cmd_getgroups_recv_pwnam(struct composite_context *ctx)
+{
+ struct composite_context *res;
+ struct cmd_getgroups_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_getgroups_state);
+ struct winbindd_pw *pw;
+ struct wbsrv_service *service = state->service;
+
+ DEBUG(5, ("cmd_getgroups_recv_pwnam called\n"));
+
+ state->ctx->status = wb_cmd_getpwnam_recv(ctx, state, &pw);
+ if (composite_is_ok(state->ctx)) {
+ res = wb_uid2sid_send(state, service, pw->pw_uid);
+ NT_STATUS_HAVE_NO_MEMORY(res);
+ DEBUG(6, ("cmd_getgroups_recv_pwnam uid %d\n",pw->pw_uid));
+
+ composite_continue(ctx, res, wb_getgroups_uid2sid_recv, state);
+ }
+}
+
+/*
+ Receive the SID and request groups through the userdomgroups helper
+*/
+static void wb_getgroups_uid2sid_recv(struct composite_context *ctx)
+{
+ struct composite_context *res;
+ struct cmd_getgroups_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_getgroups_state);
+ NTSTATUS status;
+ struct dom_sid *sid;
+ char *sid_str;
+
+ DEBUG(5, ("wb_getgroups_uid2sid_recv called\n"));
+
+ status = wb_uid2sid_recv(ctx, state, &sid);
+ if(NT_STATUS_IS_OK(status)) {
+ sid_str = dom_sid_string(state, sid);
+
+ /* If the conversion failed, bail out with a failure. */
+ if (sid_str != NULL) {
+ DEBUG(7, ("wb_getgroups_uid2sid_recv SID = %s\n",sid_str));
+ /* Ok got the SID now get the groups */
+ res = wb_cmd_userdomgroups_send(state, state->service, sid);
+ NT_STATUS_HAVE_NO_MEMORY(res);
+
+ composite_continue(ctx, res, wb_getgroups_userdomsgroups_recv, state);
+ } else {
+ composite_error(state->ctx, NT_STATUS_UNSUCCESSFUL);
+ }
+ }
+}
+
+/*
+ Receive groups and search for uid for the first group
+*/
+static void wb_getgroups_userdomsgroups_recv(struct composite_context *ctx) {
+ struct cmd_getgroups_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_getgroups_state);
+ int num_sids;
+ struct dom_sid **sids;
+
+ DEBUG(5, ("wb_getgroups_userdomsgroups_recv called\n"));
+ state->ctx->status = wb_cmd_userdomgroups_recv(ctx,state,&num_sids,&sids);
+ if (!composite_is_ok(state->ctx)) return;
+
+ DEBUG(5, ("wb_getgroups_userdomsgroups_recv %d groups\n",num_sids));
+
+ state->sids=sids;
+ state->num_groups=num_sids;
+ state->current_group=0;
+
+ if(num_sids > 0) {
+ state->gids = talloc_array(state, struct gid_t *, state->num_groups);
+ ctx = wb_sid2gid_send(state, state->service, state->sids[state->current_group]);
+ composite_continue(state->ctx, ctx, cmd_getgroups_recv_gid, state);
+ } else {
+ composite_done(state->ctx);
+ }
+}
+
+/*
+ Receive and uid the previous searched group and request the uid for the next one
+*/
+static void cmd_getgroups_recv_gid(struct composite_context *ctx)
+{
+ struct cmd_getgroups_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_getgroups_state);
+ gid_t gid;
+ char* sid_str;
+
+ DEBUG(5, ("cmd_getgroups_recv_gid called\n"));
+
+ state->ctx->status = wb_sid2gid_recv(ctx, &gid);
+ if(!composite_is_ok(state->ctx)) return;
+
+ state->gids[state->current_group] = gid;
+ DEBUG(5, ("cmd_getgroups_recv_gid group %d \n",state->current_group));
+
+ state->current_group++;
+ if(state->current_group < state->num_groups ) {
+ ctx = wb_sid2gid_send(state, state->service, state->sids[state->current_group]);
+ composite_continue(state->ctx, ctx, cmd_getgroups_recv_gid, state);
+ } else {
+ composite_done(state->ctx);
+ }
+}
+
+/*
+ Return list of uids when finished
+*/
+NTSTATUS wb_cmd_getgroups_recv(struct composite_context *ctx,TALLOC_CTX *mem_ctx,gid_t **groups,uint32_t *num_groups)
+{
+ NTSTATUS status = composite_wait(ctx);
+
+ DEBUG(5, ("wb_cmd_getgroups_recv called\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ struct cmd_getgroups_state *state =
+ talloc_get_type(ctx->private_data,
+ struct cmd_getgroups_state);
+ *groups = talloc_steal(mem_ctx, state->gids);
+ *num_groups = state->num_groups;
+ }
+ talloc_free(ctx);
+ return status;
+}
diff --git a/source4/winbind/wb_samba3_cmd.c b/source4/winbind/wb_samba3_cmd.c
index 2c846c4f15..99980d27a7 100644
--- a/source4/winbind/wb_samba3_cmd.c
+++ b/source4/winbind/wb_samba3_cmd.c
@@ -1183,31 +1183,51 @@ static void getgrgid_recv(struct composite_context *ctx)
wbsrv_samba3_async_epilogue(status, s3call);
}
+static void getgroups_recv(struct composite_context *ctx);
+
NTSTATUS wbsrv_samba3_getgroups(struct wbsrv_samba3_call *s3call)
{
+ struct composite_context *ctx;
+ struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
+
DEBUG(5, ("wbsrv_samba3_getgroups called\n"));
- s3call->response.result = WINBINDD_ERROR;
+ /* S3 code do the same so why not ... */
+ s3call->request.data.username[sizeof(s3call->request.data.username)-1]='\0';
+ ctx = wb_cmd_getgroups_send(s3call, service, s3call->request.data.username);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = getgroups_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
return NT_STATUS_OK;
}
-static void setgrent_recv(struct composite_context *ctx)
+static void getgroups_recv(struct composite_context *ctx)
{
struct wbsrv_samba3_call *s3call =
talloc_get_type(ctx->async.private_data,
struct wbsrv_samba3_call);
+ gid_t *gids;
+ uint32_t num_groups;
NTSTATUS status;
- struct wbsrv_grent *grent;
+ DEBUG(5, ("getgroups_recv called\n"));
- DEBUG(5, ("setpwent_recv called\n"));
-
- status = wb_cmd_setgrent_recv(ctx, s3call->wbconn, &grent);
+ status = wb_cmd_getgroups_recv(ctx, s3call, &gids, &num_groups);
if (NT_STATUS_IS_OK(status)) {
- s3call->wbconn->protocol_private_data = grent;
+ uint32_t extra_len = sizeof(gid_t) * num_groups;
+
+ s3call->response.data.num_entries = num_groups;
+ s3call->response.extra_data.data = gids;
+ s3call->response.length += extra_len;
+ } else {
+ s3call->response.result = WINBINDD_ERROR;
}
wbsrv_samba3_async_epilogue(status, s3call);
}
+static void setgrent_recv(struct composite_context *ctx);
+
NTSTATUS wbsrv_samba3_setgrent(struct wbsrv_samba3_call *s3call)
{
struct composite_context *ctx;
@@ -1224,29 +1244,26 @@ NTSTATUS wbsrv_samba3_setgrent(struct wbsrv_samba3_call *s3call)
return NT_STATUS_OK;
}
-static void getgrent_recv(struct composite_context *ctx)
+static void setgrent_recv(struct composite_context *ctx)
{
struct wbsrv_samba3_call *s3call =
talloc_get_type(ctx->async.private_data,
struct wbsrv_samba3_call);
NTSTATUS status;
- struct winbindd_gr *gr;
- uint32_t num_groups;
+ struct wbsrv_grent *grent;
- DEBUG(5, ("getgrent_recv called\n"));
+ DEBUG(5, ("setpwent_recv called\n"));
- status = wb_cmd_getgrent_recv(ctx, s3call, &gr, &num_groups);
+ status = wb_cmd_setgrent_recv(ctx, s3call->wbconn, &grent);
if (NT_STATUS_IS_OK(status)) {
- uint32_t extra_len = sizeof(struct winbindd_gr) * num_groups;
-
- s3call->response.data.num_entries = num_groups;
- s3call->response.extra_data.data = gr;
- s3call->response.length += extra_len;
+ s3call->wbconn->protocol_private_data = grent;
}
wbsrv_samba3_async_epilogue(status, s3call);
}
+static void getgrent_recv(struct composite_context *ctx);
+
NTSTATUS wbsrv_samba3_getgrent(struct wbsrv_samba3_call *s3call)
{
struct composite_context *ctx;
@@ -1271,6 +1288,29 @@ NTSTATUS wbsrv_samba3_getgrent(struct wbsrv_samba3_call *s3call)
return NT_STATUS_OK;
}
+static void getgrent_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ NTSTATUS status;
+ struct winbindd_gr *gr;
+ uint32_t num_groups;
+
+ DEBUG(5, ("getgrent_recv called\n"));
+
+ status = wb_cmd_getgrent_recv(ctx, s3call, &gr, &num_groups);
+ if (NT_STATUS_IS_OK(status)) {
+ uint32_t extra_len = sizeof(struct winbindd_gr) * num_groups;
+
+ s3call->response.data.num_entries = num_groups;
+ s3call->response.extra_data.data = gr;
+ s3call->response.length += extra_len;
+ }
+
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
NTSTATUS wbsrv_samba3_endgrent(struct wbsrv_samba3_call *s3call)
{
DEBUG(5, ("wbsrv_samba3_endgrent called\n"));