r11804: Asyncify the anonymous bind, convert the calls in xplogin.c.
authorVolker Lendecke <vlendec@samba.org>
Sat, 19 Nov 2005 22:31:26 +0000 (22:31 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:46:30 +0000 (13:46 -0500)
Tridge et al, please take a close look at this. It survives my basic rpc-login
test as well as rpc-lsa, but this is critical I think.

Volker

source/librpc/rpc/dcerpc.c
source/librpc/rpc/dcerpc_auth.c
source/torture/rpc/xplogin.c

index 9b7d5bb47dafb6797b0d6597e81ead85cde76600..0728b977682ceaae6d6cd00b5f707825f6fe1b9d 100644 (file)
@@ -27,6 +27,7 @@
 #include "librpc/gen_ndr/ndr_epmapper.h"
 #include "librpc/gen_ndr/ndr_dcerpc.h"
 #include "librpc/gen_ndr/ndr_misc.h"
+#include "libcli/composite/composite.h"
 
 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
 
@@ -612,87 +613,183 @@ static NTSTATUS dcerpc_map_reason(uint16_t reason)
        return NT_STATUS_UNSUCCESSFUL;
 }
 
-
-/* 
-   perform a bind using the given syntax 
-
-   the auth_info structure is updated with the reply authentication info
-   on success
-*/
-NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, 
-                    TALLOC_CTX *mem_ctx,
-                    const struct dcerpc_syntax_id *syntax,
-                    const struct dcerpc_syntax_id *transfer_syntax)
-{
+struct dcerpc_bind_state {
+       struct dcerpc_pipe *pipe;
        struct ncacn_packet pkt;
-       NTSTATUS status;
        DATA_BLOB blob;
+};
 
-       p->syntax = *syntax;
-       p->transfer_syntax = *transfer_syntax;
-
-       init_ncacn_hdr(p->conn, &pkt);
+/*
+  Receive a bind reply from the transport
+*/
 
-       pkt.ptype = DCERPC_PKT_BIND;
-       pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
-       pkt.call_id = p->conn->call_id;
-       pkt.auth_length = 0;
+static void bind_request_recv(struct dcerpc_connection *conn, DATA_BLOB *blob,
+                             NTSTATUS status)
+{
+       struct composite_context *c;
+       struct dcerpc_bind_state *state;
 
-       pkt.u.bind.max_xmit_frag = 5840;
-       pkt.u.bind.max_recv_frag = 5840;
-       pkt.u.bind.assoc_group_id = 0;
-       pkt.u.bind.num_contexts = 1;
-       pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
-       if (!pkt.u.bind.ctx_list) {
-               return NT_STATUS_NO_MEMORY;
+       if (conn->full_request_private == NULL) {
+               /* it timed out earlier */
+               return;
        }
-       pkt.u.bind.ctx_list[0].context_id = p->context_id;
-       pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
-       pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
-       pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
-       pkt.u.bind.auth_info = data_blob(NULL, 0);
+       c = talloc_get_type(conn->full_request_private,
+                           struct composite_context);
+       state = talloc_get_type(c->private_data, struct dcerpc_bind_state);
 
-       /* construct the NDR form of the packet */
-       status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               composite_error(c, status);
+               return;
        }
 
-       /* send it on its way */
-       status = full_request(p->conn, mem_ctx, &blob, &blob);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       c->status = ncacn_pull(conn, blob, state, &state->pkt);
+       if (!composite_is_ok(c)) return;
+
+       if (state->pkt.ptype == DCERPC_PKT_BIND_NAK) {
+               DEBUG(2,("dcerpc: bind_nak reason %d\n",
+                        state->pkt.u.bind_nak.reject_reason));
+               composite_error(c, dcerpc_map_reason(state->pkt.u.bind_nak.
+                                                    reject_reason));
+               return;
        }
 
-       /* unmarshall the NDR */
-       status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       if ((state->pkt.ptype != DCERPC_PKT_BIND_ACK) ||
+           (state->pkt.u.bind_ack.num_results == 0) ||
+           (state->pkt.u.bind_ack.ctx_list[0].result != 0)) {
+               composite_error(c, NT_STATUS_UNSUCCESSFUL);
+               return;
        }
 
-       if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
-               DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
-               return dcerpc_map_reason(pkt.u.bind_nak.reject_reason);
+       conn->srv_max_xmit_frag = state->pkt.u.bind_ack.max_xmit_frag;
+       conn->srv_max_recv_frag = state->pkt.u.bind_ack.max_recv_frag;
+
+       /* the bind_ack might contain a reply set of credentials */
+       if (conn->security_state.auth_info &&
+           state->pkt.u.bind_ack.auth_info.length) {
+               c->status = ndr_pull_struct_blob(
+                       &state->pkt.u.bind_ack.auth_info, state,
+                       conn->security_state.auth_info,
+                       (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
+               if (!composite_is_ok(c)) return;
        }
 
-       if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
-           pkt.u.bind_ack.num_results == 0 ||
-           pkt.u.bind_ack.ctx_list[0].result != 0) {
-               return NT_STATUS_UNSUCCESSFUL;
+       composite_done(c);
+}
+
+/*
+  handle timeouts of full dcerpc requests
+*/
+static void bind_timeout_handler(struct event_context *ev,
+                                struct timed_event *te, 
+                                struct timeval t, void *private)
+{
+       struct composite_context *ctx =
+               talloc_get_type(private, struct composite_context);
+       struct dcerpc_bind_state *state =
+               talloc_get_type(ctx->private_data, struct dcerpc_bind_state);
+
+       SMB_ASSERT(state->pipe->conn->full_request_private != NULL);
+       state->pipe->conn->full_request_private = NULL;
+       composite_error(ctx, NT_STATUS_IO_TIMEOUT);
+}
+
+struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
+                                          TALLOC_CTX *mem_ctx,
+                                          const struct dcerpc_syntax_id *syntax,
+                                          const struct dcerpc_syntax_id *transfer_syntax)
+{
+       struct composite_context *c;
+       struct dcerpc_bind_state *state;
+
+       c = talloc_zero(mem_ctx, struct composite_context);
+       if (c == NULL) return NULL;
+
+       state = talloc(c, struct dcerpc_bind_state);
+       if (state == NULL) {
+               c->status = NT_STATUS_NO_MEMORY;
+               goto failed;
        }
 
-       p->conn->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
-       p->conn->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
+       c->state = COMPOSITE_STATE_IN_PROGRESS;
+       c->private_data = state;
+       c->event_ctx = p->conn->event_ctx;
 
-       /* the bind_ack might contain a reply set of credentials */
-       if (p->conn->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
-               status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
-                                             mem_ctx,
-                                             p->conn->security_state.auth_info,
-                                             (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
+       state->pipe = p;
+
+       p->syntax = *syntax;
+       p->transfer_syntax = *transfer_syntax;
+
+       init_ncacn_hdr(p->conn, &state->pkt);
+
+       state->pkt.ptype = DCERPC_PKT_BIND;
+       state->pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+       state->pkt.call_id = p->conn->call_id;
+       state->pkt.auth_length = 0;
+
+       state->pkt.u.bind.max_xmit_frag = 5840;
+       state->pkt.u.bind.max_recv_frag = 5840;
+       state->pkt.u.bind.assoc_group_id = 0;
+       state->pkt.u.bind.num_contexts = 1;
+       state->pkt.u.bind.ctx_list =
+               talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
+       if (state->pkt.u.bind.ctx_list == NULL) {
+               c->status = NT_STATUS_NO_MEMORY;
+               goto failed;
+       }
+       state->pkt.u.bind.ctx_list[0].context_id = p->context_id;
+       state->pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
+       state->pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
+       state->pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
+       state->pkt.u.bind.auth_info = data_blob(NULL, 0);
+
+       /* construct the NDR form of the packet */
+       c->status = ncacn_push_auth(&state->blob, mem_ctx, &state->pkt,
+                                   p->conn->security_state.auth_info);
+       if (!NT_STATUS_IS_OK(c->status)) {
+               goto failed;
        }
 
-       return status;  
+       p->conn->transport.recv_data = bind_request_recv;
+       p->conn->full_request_private = c;
+
+       c->status = p->conn->transport.send_request(p->conn, &state->blob,
+                                                   True);
+       if (!NT_STATUS_IS_OK(c->status)) {
+               goto failed;
+       }
+
+       event_add_timed(c->event_ctx, c,
+                       timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
+                       bind_timeout_handler, c);
+
+       return c;
+
+ failed:
+       composite_trigger_error(c);
+       return c;
+}
+
+NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
+{
+       NTSTATUS result = composite_wait(ctx);
+       talloc_free(ctx);
+       return result;
+}
+
+/* 
+   perform a bind using the given syntax 
+
+   the auth_info structure is updated with the reply authentication info
+   on success
+*/
+NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, 
+                    TALLOC_CTX *mem_ctx,
+                    const struct dcerpc_syntax_id *syntax,
+                    const struct dcerpc_syntax_id *transfer_syntax)
+{
+       struct composite_context *creq;
+       creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
+       return dcerpc_bind_recv(creq);
 }
 
 /* 
@@ -730,6 +827,26 @@ NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
 }
 
 
+NTSTATUS dcerpc_init_syntaxes(const char *uuid,
+                             struct dcerpc_syntax_id *syntax,
+                             struct dcerpc_syntax_id *transfer_syntax,
+                             uint_t version)
+{
+       NTSTATUS status;
+
+       status = GUID_from_string(uuid, &syntax->uuid);
+       if (!NT_STATUS_IS_OK(status)) return status;
+
+       syntax->if_version = version;
+
+       status = GUID_from_string(NDR_GUID, &transfer_syntax->uuid);
+       if (!NT_STATUS_IS_OK(status)) return status;
+
+       transfer_syntax->if_version = NDR_GUID_VERSION;
+
+       return NT_STATUS_OK;
+}
+
 /* perform a dcerpc bind, using the uuid as the key */
 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p, 
                            TALLOC_CTX *mem_ctx,
@@ -739,22 +856,17 @@ NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
        struct dcerpc_syntax_id transfer_syntax;
        NTSTATUS status;
 
-       status = GUID_from_string(uuid, &syntax.uuid);
+       status = dcerpc_init_syntaxes(uuid, &syntax, &transfer_syntax,
+                                     version);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
                return status;
        }
-       syntax.if_version = version;
-
-       status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-       transfer_syntax.if_version = NDR_GUID_VERSION;
 
        return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
 }
 
+
 /*
   process a fragment received from the transport layer during a
   request
index 8ad3be4ecd257b2c43acfa8014627e0b280a8694..4c22b615195a6d1da4072f22aa5068246a289abe 100644 (file)
 */
 
 #include "includes.h"
+#include "libcli/composite/composite.h"
 
 /*
   do a non-athenticated dcerpc bind
 */
-NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
-                              const char *uuid, uint_t version)
+
+struct composite_context *dcerpc_bind_auth_none_send(TALLOC_CTX *mem_ctx,
+                                                    struct dcerpc_pipe *p,
+                                                    const char *uuid,
+                                                    uint_t version)
 {
-       TALLOC_CTX *tmp_ctx = talloc_new(p);
-       NTSTATUS status;
+       struct dcerpc_syntax_id syntax;
+       struct dcerpc_syntax_id transfer_syntax;
 
-       status = dcerpc_bind_byuuid(p, tmp_ctx, uuid, version);
-       talloc_free(tmp_ctx);
+       struct composite_context *c;
 
-       return status;
+       c = talloc_zero(mem_ctx, struct composite_context);
+       if (c == NULL) return NULL;
+
+       c->status = dcerpc_init_syntaxes(uuid, &syntax, &transfer_syntax,
+                                        version);
+       if (!NT_STATUS_IS_OK(c->status)) {
+               DEBUG(2,("Invalid uuid string in "
+                        "dcerpc_bind_auth_none_send\n"));
+               goto failed;
+       }
+
+       /* c was only allocated as a container for a possible error */
+       talloc_free(c);
+
+       return dcerpc_bind_send(p, mem_ctx, &syntax, &transfer_syntax);
+
+ failed:
+       composite_trigger_error(c);
+       return c;
+}
+
+NTSTATUS dcerpc_bind_auth_none_recv(struct composite_context *ctx)
+{
+       return dcerpc_bind_recv(ctx);
+}
+
+NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
+                              const char *uuid, uint_t version)
+{
+       struct composite_context *ctx;
+       ctx = dcerpc_bind_auth_none_send(p, p, uuid, version);
+       return dcerpc_bind_auth_none_recv(ctx);
 }
 
 /*
index c87190cfe0491da1b346887c36c2b4726b7cc739..9c15f7566bca71a690bb8be2f8bd62adf0c51272 100644 (file)
@@ -42,6 +42,7 @@ struct get_schannel_creds_state {
        struct netr_ServerAuthenticate2 a;
 };
 
+static void get_schannel_creds_recv_bind(struct composite_context *ctx);
 static void get_schannel_creds_recv_auth(struct rpc_request *req);
 static void get_schannel_creds_recv_chal(struct rpc_request *req);
 static void get_schannel_creds_recv_pipe(struct composite_context *ctx);
@@ -87,14 +88,25 @@ static void get_schannel_creds_recv_pipe(struct composite_context *ctx)
        struct get_schannel_creds_state *state =
                talloc_get_type(ctx->async.private_data,
                                struct get_schannel_creds_state);
-       struct rpc_request *req;
 
        state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
        if (!composite_is_ok(state->ctx)) return;
 
-       state->ctx->status = dcerpc_bind_auth_none(state->p,
-                                                  DCERPC_NETLOGON_UUID,
-                                                  DCERPC_NETLOGON_VERSION);
+       ctx = dcerpc_bind_auth_none_send(state, state->p, 
+                                        DCERPC_NETLOGON_UUID,
+                                        DCERPC_NETLOGON_VERSION);
+       composite_continue(state->ctx, ctx, get_schannel_creds_recv_bind,
+                          state);
+}
+
+static void get_schannel_creds_recv_bind(struct composite_context *ctx)
+{
+       struct get_schannel_creds_state *state =
+               talloc_get_type(ctx->async.private_data,
+                               struct get_schannel_creds_state);
+       struct rpc_request *req;
+
+       state->ctx->status = dcerpc_bind_auth_none_recv(ctx);
        if (!composite_is_ok(state->ctx)) return;
 
        state->r.in.computer_name =
@@ -279,7 +291,7 @@ static void lsa_enumtrust_recvpol(struct rpc_request *req)
        composite_continue_rpc(c, req, lsa_enumtrust_recvtrust, c);
 }
 
-static void lsa_enumtrust_recvsmb(struct composite_context *creq)
+static void lsa_enumtrust_recvbind(struct composite_context *creq)
 {
        struct composite_context *c =
                talloc_get_type(creq->async.private_data,
@@ -288,12 +300,7 @@ static void lsa_enumtrust_recvsmb(struct composite_context *creq)
                talloc_get_type(c->private_data, struct lsa_enumtrust_state);
        struct rpc_request *req;
 
-       c->status = dcerpc_pipe_open_smb_recv(creq);
-       if (!composite_is_ok(c)) return;
-
-       c->status = dcerpc_bind_auth_none(state->lsa_pipe,
-                                         DCERPC_LSARPC_UUID,
-                                         DCERPC_LSARPC_VERSION);
+       c->status = dcerpc_bind_auth_none_recv(creq);
        if (!composite_is_ok(c)) return;
 
        ZERO_STRUCT(state->attr);
@@ -308,6 +315,23 @@ static void lsa_enumtrust_recvsmb(struct composite_context *creq)
        composite_continue_rpc(c, req, lsa_enumtrust_recvpol, c);
 }
 
+static void lsa_enumtrust_recvsmb(struct composite_context *creq)
+{
+       struct composite_context *c =
+               talloc_get_type(creq->async.private_data,
+                               struct composite_context);
+       struct lsa_enumtrust_state *state =
+               talloc_get_type(c->private_data, struct lsa_enumtrust_state);
+
+       c->status = dcerpc_pipe_open_smb_recv(creq);
+       if (!composite_is_ok(c)) return;
+
+       creq = dcerpc_bind_auth_none_send(state, state->lsa_pipe,
+                                         DCERPC_LSARPC_UUID,
+                                         DCERPC_LSARPC_VERSION);
+       composite_continue(c, creq, lsa_enumtrust_recvbind, c);
+}
+
 static struct composite_context *lsa_enumtrust_send(TALLOC_CTX *mem_ctx,
                                                    struct smbcli_tree *tree)
 {