From d68319431e62e43c0ecb23328e3162128d823958 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 16 Oct 2005 12:43:09 +0000 Subject: r11095: Implement wb_getuserdomgroups. Tridge, if you have the time, you might want to look at a problem I'm having with unix domain stream sockets. From a comment in this commit: /* 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. */ This is in winbind/wb_cmd_userdomgroups.c:93. The problem I have is that I can not *immediately* send an error reply to the client because the next receive fails. Waiting 100 milliseconds helps. It might also be a problem with epoll(), I don't really know. I'd appreciate if you took a brief look at this, maybe I'm doing something wrong. Thanks, Volker (This used to be commit 3e535cce743710a68a4264e4f66e9c0c4d6770c6) --- source4/libcli/composite/composite.c | 7 ++ source4/winbind/config.mk | 1 + source4/winbind/wb_async_helpers.c | 138 +++++++++++++++++++++++++++ source4/winbind/wb_cmd_userdomgroups.c | 164 +++++++++++++++++++++++++++++++++ source4/winbind/wb_samba3_cmd.c | 78 ++++++++++++++++ source4/winbind/wb_samba3_protocol.c | 3 + 6 files changed, 391 insertions(+) create mode 100644 source4/winbind/wb_cmd_userdomgroups.c (limited to 'source4') 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; inum_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; iresponse.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; -- cgit