summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/libcli/composite/composite.c7
-rw-r--r--source4/winbind/config.mk1
-rw-r--r--source4/winbind/wb_async_helpers.c138
-rw-r--r--source4/winbind/wb_cmd_userdomgroups.c164
-rw-r--r--source4/winbind/wb_samba3_cmd.c78
-rw-r--r--source4/winbind/wb_samba3_protocol.c3
6 files changed, 391 insertions, 0 deletions
diff --git a/source4/libcli/composite/composite.c b/source4/libcli/composite/composite.c
index f5eed77300..c78d039905 100644
--- a/source4/libcli/composite/composite.c
+++ b/source4/libcli/composite/composite.c
@@ -69,6 +69,13 @@ void composite_trigger_done(struct composite_context *c)
event_add_timed(c->event_ctx, c, timeval_zero(), composite_trigger, c);
}
+void composite_trigger_error(struct composite_context *c)
+{
+ c->state = COMPOSITE_STATE_ERROR;
+ /* a zero timeout means immediate */
+ event_add_timed(c->event_ctx, c, timeval_zero(), composite_trigger, c);
+}
+
/*
* Some composite helpers that are handy if you write larger composite
diff --git a/source4/winbind/config.mk b/source4/winbind/config.mk
index 530aa83b80..d071dd1604 100644
--- a/source4/winbind/config.mk
+++ b/source4/winbind/config.mk
@@ -14,6 +14,7 @@ INIT_OBJ_FILES = \
winbind/wb_connect_sam.o \
winbind/wb_cmd_lookupname.o \
winbind/wb_cmd_getdcname.o \
+ winbind/wb_cmd_userdomgroups.o \
winbind/wb_pam_auth.o \
winbind/wb_async_helpers.o
REQUIRED_SUBSYSTEMS = RPC_NDR_LSA
diff --git a/source4/winbind/wb_async_helpers.c b/source4/winbind/wb_async_helpers.c
index eeed108719..c8749896df 100644
--- a/source4/winbind/wb_async_helpers.c
+++ b/source4/winbind/wb_async_helpers.c
@@ -610,3 +610,141 @@ NTSTATUS composite_netr_LogonSamLogon_recv(struct composite_context *ctx)
return status;
}
+struct samr_getuserdomgroups_state {
+ struct composite_context *ctx;
+ struct dcerpc_pipe *samr_pipe;
+
+ int num_rids;
+ uint32_t *rids;
+
+ struct policy_handle *user_handle;
+ struct samr_OpenUser o;
+ struct samr_GetGroupsForUser g;
+ struct samr_Close c;
+};
+
+static void samr_usergroups_recv_open(struct rpc_request *req);
+static void samr_usergroups_recv_groups(struct rpc_request *req);
+static void samr_usergroups_recv_close(struct rpc_request *req);
+
+struct composite_context *wb_samr_userdomgroups_send(struct dcerpc_pipe *samr_pipe,
+ struct policy_handle *domain_handle,
+ uint32_t rid)
+{
+ struct composite_context *result;
+ struct rpc_request *req;
+ struct samr_getuserdomgroups_state *state;
+
+ result = talloc_zero(NULL, struct composite_context);
+ if (result == NULL) goto failed;
+ result->state = COMPOSITE_STATE_IN_PROGRESS;
+ result->async.fn = NULL;
+ result->event_ctx = samr_pipe->conn->event_ctx;
+
+ state = talloc(result, struct samr_getuserdomgroups_state);
+ if (state == NULL) goto failed;
+ result->private_data = state;
+ state->ctx = result;
+
+ state->samr_pipe = samr_pipe;
+
+ state->user_handle = talloc(state, struct policy_handle);
+ if (state->user_handle == NULL) goto failed;
+
+ state->o.in.domain_handle = domain_handle;
+ state->o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ state->o.in.rid = rid;
+ state->o.out.user_handle = state->user_handle;
+
+ req = dcerpc_samr_OpenUser_send(state->samr_pipe, state, &state->o);
+ if (req == NULL) goto failed;
+
+ req->async.callback = samr_usergroups_recv_open;
+ req->async.private = state;
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void samr_usergroups_recv_open(struct rpc_request *req)
+{
+ struct samr_getuserdomgroups_state *state =
+ talloc_get_type(req->async.private,
+ struct samr_getuserdomgroups_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->o.out.result;
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->g.in.user_handle = state->user_handle;
+
+ req = dcerpc_samr_GetGroupsForUser_send(state->samr_pipe, state,
+ &state->g);
+ composite_continue_rpc(state->ctx, req, samr_usergroups_recv_groups,
+ state);
+}
+
+static void samr_usergroups_recv_groups(struct rpc_request *req)
+{
+ struct samr_getuserdomgroups_state *state =
+ talloc_get_type(req->async.private,
+ struct samr_getuserdomgroups_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->g.out.result;
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->c.in.handle = state->user_handle;
+ state->c.out.handle = state->user_handle;
+
+ req = dcerpc_samr_Close_send(state->samr_pipe, state, &state->c);
+ composite_continue_rpc(state->ctx, req, samr_usergroups_recv_close,
+ state);
+}
+
+static void samr_usergroups_recv_close(struct rpc_request *req)
+{
+ struct samr_getuserdomgroups_state *state =
+ talloc_get_type(req->async.private,
+ struct samr_getuserdomgroups_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->c.out.result;
+ if (!composite_is_ok(state->ctx)) return;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_samr_userdomgroups_recv(struct composite_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ int *num_rids, uint32_t **rids)
+{
+ struct samr_getuserdomgroups_state *state =
+ talloc_get_type(ctx->private_data,
+ struct samr_getuserdomgroups_state);
+
+ int i;
+ NTSTATUS status = composite_wait(ctx);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ *num_rids = state->g.out.rids->count;
+ *rids = talloc_array(mem_ctx, uint32_t, *num_rids);
+ if (*rids == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i<*num_rids; i++) {
+ (*rids)[i] = state->g.out.rids->rids[i].rid;
+ }
+
+ done:
+ talloc_free(ctx);
+ return status;
+}
+
diff --git a/source4/winbind/wb_cmd_userdomgroups.c b/source4/winbind/wb_cmd_userdomgroups.c
new file mode 100644
index 0000000000..ea2db9877f
--- /dev/null
+++ b/source4/winbind/wb_cmd_userdomgroups.c
@@ -0,0 +1,164 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for wbinfo --user-domgroups
+
+ Copyright (C) Volker Lendecke 2005
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_stream.h"
+#include "lib/events/events.h"
+#include "librpc/gen_ndr/ndr_security.h"
+
+struct cmd_userdomgroups_state {
+ struct composite_context *ctx;
+ struct wbsrv_domain *domain;
+ uint32_t user_rid;
+ int num_rids;
+ uint32_t *rids;
+};
+
+static void composite_trigger_now(struct event_context *ev,
+ struct timed_event *te,
+ struct timeval t, void *ptr)
+{
+ struct composite_context *c =
+ talloc_get_type(ptr, struct composite_context);
+ if (NT_STATUS_IS_OK(c->status)) {
+ c->state = COMPOSITE_STATE_ERROR;
+ } else {
+ c->state = COMPOSITE_STATE_DONE;
+ }
+
+ if (c->async.fn) {
+ c->async.fn(c);
+ }
+}
+
+
+static struct composite_context *userdomgroups_send_req(void *p);
+static NTSTATUS userdomgroups_recv_req(struct composite_context *ctx, void *p);
+
+struct composite_context *wb_cmd_userdomgroups_send(struct wbsrv_call *call,
+ const struct dom_sid *sid)
+{
+ struct cmd_userdomgroups_state *state;
+ struct wbsrv_service *service = call->wbconn->listen_socket->service;
+
+ state = talloc(NULL, struct cmd_userdomgroups_state);
+ state->domain = service->domains;
+
+ if (dom_sid_in_domain(state->domain->sid, sid)) {
+ state->user_rid = sid->sub_auths[sid->num_auths-1];
+ state->ctx = wb_queue_domain_send(state, state->domain,
+ call->event_ctx,
+ call->wbconn->conn->msg_ctx,
+ userdomgroups_send_req,
+ userdomgroups_recv_req,
+ state);
+ if (state->ctx == NULL) goto failed;
+ state->ctx->private_data = state;
+ return state->ctx;
+ }
+
+ state->ctx = talloc(state, struct composite_context);
+ if (state->ctx == NULL) goto failed;
+ state->ctx->state = COMPOSITE_STATE_IN_PROGRESS;
+ state->ctx->async.fn = NULL;
+ state->ctx->event_ctx = call->event_ctx;
+ state->ctx->status = NT_STATUS_NO_SUCH_USER;
+ state->ctx->private_data = state;
+
+ /* Using composite_trigger_error here causes problems with the client
+ * socket. Linux 2.6.8 gives me a ECONNRESET on the next read after
+ * writing the reply when I don't wait the 100 milliseconds. */
+
+ event_add_timed(state->ctx->event_ctx, state->ctx,
+ timeval_current_ofs(0, 100000),
+ composite_trigger_now, state->ctx);
+ return state->ctx;
+
+ failed:
+ talloc_free(state);
+ return NULL;
+}
+
+static struct composite_context *userdomgroups_send_req(void *p)
+{
+ struct cmd_userdomgroups_state *state =
+ talloc_get_type(p, struct cmd_userdomgroups_state);
+
+ return wb_samr_userdomgroups_send(state->domain->samr_pipe,
+ state->domain->domain_handle,
+ state->user_rid);
+}
+
+static NTSTATUS userdomgroups_recv_req(struct composite_context *ctx, void *p)
+{
+ struct cmd_userdomgroups_state *state =
+ talloc_get_type(p, struct cmd_userdomgroups_state);
+
+ return wb_samr_userdomgroups_recv(ctx, state, &state->num_rids,
+ &state->rids);
+}
+
+NTSTATUS wb_cmd_userdomgroups_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx,
+ int *num_sids, struct dom_sid ***sids)
+{
+ struct cmd_userdomgroups_state *state =
+ talloc_get_type(c->private_data,
+ struct cmd_userdomgroups_state);
+ int i;
+ NTSTATUS status;
+
+ status = composite_wait(c);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ *num_sids = state->num_rids;
+ *sids = talloc_array(mem_ctx, struct dom_sid *, state->num_rids);
+ if (*sids == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i<state->num_rids; i++) {
+ (*sids)[i] = dom_sid_add_rid((*sids), state->domain->sid,
+ state->rids[i]);
+ if ((*sids)[i] == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+
+done:
+ talloc_free(state);
+ return status;
+}
+
+NTSTATUS wb_cmd_userdomgroups(struct wbsrv_call *call,
+ const struct dom_sid *sid,
+ TALLOC_CTX *mem_ctx, int *num_sids,
+ struct dom_sid ***sids)
+{
+ struct composite_context *c =
+ wb_cmd_userdomgroups_send(call, sid);
+ return wb_cmd_userdomgroups_recv(c, mem_ctx, num_sids, sids);
+}
diff --git a/source4/winbind/wb_samba3_cmd.c b/source4/winbind/wb_samba3_cmd.c
index fb43eacb5c..a53b06ae4e 100644
--- a/source4/winbind/wb_samba3_cmd.c
+++ b/source4/winbind/wb_samba3_cmd.c
@@ -174,6 +174,84 @@ static void getdcname_recv_dc(struct composite_context *ctx)
}
}
+static void userdomgroups_recv_groups(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct dom_sid *sid;
+
+ DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
+
+ sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
+ if (sid == NULL) {
+ DEBUG(5, ("Could not parse sid %s\n",
+ s3call->request.data.sid));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ctx = wb_cmd_userdomgroups_send(s3call->call, sid);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = userdomgroups_recv_groups;
+ ctx->async.private_data = s3call;
+ s3call->call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void userdomgroups_recv_groups(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ int i, num_sids;
+ struct dom_sid **sids;
+ char *sids_string;
+ NTSTATUS status;
+
+ status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ sids_string = talloc_strdup(s3call, "");
+ if (sids_string == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i<num_sids; i++) {
+ sids_string = talloc_asprintf_append(
+ sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
+ }
+
+ if (sids_string == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ s3call->response.result = WINBINDD_OK;
+ s3call->response.extra_data = sids_string;
+ s3call->response.length += strlen(sids_string)+1;
+ s3call->response.data.num_entries = num_sids;
+
+ done:
+ if (!NT_STATUS_IS_OK(status)) {
+ struct winbindd_response *resp = &s3call->response;
+ resp->result = WINBINDD_ERROR;
+ WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
+ nt_errstr(status));
+ WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
+ nt_errstr(status));
+ resp->data.auth.pam_error = nt_status_to_pam(status);
+ }
+
+ status = wbsrv_send_reply(s3call->call);
+ if (!NT_STATUS_IS_OK(status)) {
+ wbsrv_terminate_connection(s3call->call->wbconn,
+ "wbsrv_queue_reply() failed");
+ return;
+ }
+}
+
static void lookupname_recv_sid(struct composite_context *ctx);
NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
diff --git a/source4/winbind/wb_samba3_protocol.c b/source4/winbind/wb_samba3_protocol.c
index 135d9a3d1f..2c99aa63c9 100644
--- a/source4/winbind/wb_samba3_protocol.c
+++ b/source4/winbind/wb_samba3_protocol.c
@@ -102,6 +102,9 @@ NTSTATUS wbsrv_samba3_handle_call(struct wbsrv_call *call)
case WINBINDD_GETDCNAME:
return wbsrv_samba3_getdcname(s3call);
+
+ case WINBINDD_GETUSERDOMGROUPS:
+ return wbsrv_samba3_userdomgroups(s3call);
}
s3call->response.result = WINBINDD_ERROR;