r11095: Implement wb_getuserdomgroups.
authorVolker Lendecke <vlendec@samba.org>
Sun, 16 Oct 2005 12:43:09 +0000 (12:43 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:44:48 +0000 (13:44 -0500)
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
source4/winbind/config.mk
source4/winbind/wb_async_helpers.c
source4/winbind/wb_cmd_userdomgroups.c [new file with mode: 0644]
source4/winbind/wb_samba3_cmd.c
source4/winbind/wb_samba3_protocol.c

index f5eed77300f1da75554df2c38ac9b2cf08665fdd..c78d039905f22b756e97b1664c6b9950d82fe006 100644 (file)
@@ -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
index 530aa83b80e1a08c7b5256adfcb82424675ee898..d071dd160476f6e0f7a12ef3e256154922101cc8 100644 (file)
@@ -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
index eeed108719663e084812b12d94cc402ddac78cf1..c8749896df5159b0286fba0ad679a81ebe67b764 100644 (file)
@@ -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 (file)
index 0000000..ea2db98
--- /dev/null
@@ -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);
+}
index fb43eacb5cfb0e2d11e2350353163d4db73cb212..a53b06ae4eced37fe1f5d01d2ff3d0893adf3cb1 100644 (file)
@@ -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)
index 135d9a3d1fe30a3cdb70664775e93c175df181b0..2c99aa63c9d84552b17d7772ce3993fcacd4bdae 100644 (file)
@@ -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;