r11809: Make dcerpc_bind_auth async.
authorVolker Lendecke <vlendec@samba.org>
Sun, 20 Nov 2005 16:28:39 +0000 (16:28 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:46:31 +0000 (13:46 -0500)
This also removes dcerpc_bind_auth_password, the only user of
dcerpc_bind_auth. And this was not only passwords anyway.

Andrew Bartlett, as usual: Please take a close look.

Thanks,

Volker
(This used to be commit 2ff2dae3d035af6cb0c131573cfd983fc9a58eee)

source4/librpc/rpc/dcerpc.c
source4/librpc/rpc/dcerpc_auth.c
source4/librpc/rpc/dcerpc_schannel.c
source4/librpc/rpc/dcerpc_util.c
source4/torture/rpc/schannel.c
source4/winbind/wb_connect_lsa.c
source4/winbind/wb_connect_sam.c
source4/winbind/wb_init_domain.c

index c7f337de9956ced844a4f13c2851432e31b40785..ee06d6e2bef336a7cbcbcdd2b96db6b895b8b914 100644 (file)
@@ -743,10 +743,9 @@ NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
 }
 
 
-NTSTATUS dcerpc_init_syntaxes(const char *uuid,
+NTSTATUS dcerpc_init_syntaxes(const char *uuid, uint_t version,
                              struct dcerpc_syntax_id *syntax,
-                             struct dcerpc_syntax_id *transfer_syntax,
-                             uint_t version)
+                             struct dcerpc_syntax_id *transfer_syntax)
 {
        NTSTATUS status;
 
@@ -772,8 +771,8 @@ NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
        struct dcerpc_syntax_id transfer_syntax;
        NTSTATUS status;
 
-       status = dcerpc_init_syntaxes(uuid, &syntax, &transfer_syntax,
-                                     version);
+       status = dcerpc_init_syntaxes(uuid, version,
+                                     &syntax, &transfer_syntax);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
                return status;
index 117112c197c7ad08f65ecfcd6d07674d08e4223b..29ab80da7ab11bf35e0f20c1a5c8165026f3b590 100644 (file)
@@ -42,8 +42,8 @@ struct composite_context *dcerpc_bind_auth_none_send(TALLOC_CTX *mem_ctx,
        c = talloc_zero(mem_ctx, struct composite_context);
        if (c == NULL) return NULL;
 
-       c->status = dcerpc_init_syntaxes(uuid, &syntax, &transfer_syntax,
-                                        version);
+       c->status = dcerpc_init_syntaxes(uuid, version,
+                                        &syntax, &transfer_syntax);
        if (!NT_STATUS_IS_OK(c->status)) {
                DEBUG(2,("Invalid uuid string in "
                         "dcerpc_bind_auth_none_send\n"));
@@ -70,173 +70,227 @@ NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
        return dcerpc_bind_auth_none_recv(ctx);
 }
 
-/*
-  perform a multi-part authenticated bind
-*/
-static NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p, uint8_t auth_type, uint8_t auth_level,
-                                const char *uuid, uint_t version)
-{
-       NTSTATUS status;
-       TALLOC_CTX *tmp_ctx = talloc_new(p);
+struct bind_auth_state {
+       struct dcerpc_pipe *pipe;
        DATA_BLOB credentials;
-       DATA_BLOB null_data_blob = data_blob(NULL, 0);
+       BOOL more_processing;
+};
 
-       int num_passes = 0;
+static void bind_auth_recv_alter(struct composite_context *creq);
 
-       if (!p->conn->security_state.generic_state) {
-               status = gensec_client_start(p, &p->conn->security_state.generic_state,
-                                            p->conn->event_ctx);
-               if (!NT_STATUS_IS_OK(status)) goto done;
+static void bind_auth_next_step(struct composite_context *c)
+{
+       struct bind_auth_state *state =
+               talloc_get_type(c->private_data, struct bind_auth_state);
+       struct dcerpc_security *sec = &state->pipe->conn->security_state;
+       struct composite_context *creq;
+       BOOL more_processing = False;
+
+       c->status = gensec_update(sec->generic_state, state,
+                                 sec->auth_info->credentials,
+                                 &state->credentials);
+
+       if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               more_processing = True;
+               c->status = NT_STATUS_OK;
+       }
+
+       if (!composite_is_ok(c)) return;
 
-               status = gensec_start_mech_by_authtype(p->conn->security_state.generic_state, 
-                                                      auth_type, auth_level);
-               if (!NT_STATUS_IS_OK(status)) goto done;
+       if (state->credentials.length == 0) {
+               composite_done(c);
+               return;
        }
 
-       p->conn->security_state.auth_info = talloc(p, struct dcerpc_auth);
-       if (!p->conn->security_state.auth_info) {
-               status = NT_STATUS_NO_MEMORY;
-               goto done;
+       sec->auth_info->credentials = state->credentials;
+
+       if (!more_processing) {
+               /* NO reply expected, so just send it */
+               c->status = dcerpc_auth3(state->pipe->conn, state);
+               if (!composite_is_ok(c)) return;
+               composite_done(c);
+               return;
        }
 
-       p->conn->security_state.auth_info->auth_type = auth_type;
-       p->conn->security_state.auth_info->auth_level = auth_level;
-       p->conn->security_state.auth_info->auth_pad_length = 0;
-       p->conn->security_state.auth_info->auth_reserved = 0;
-       p->conn->security_state.auth_info->auth_context_id = random();
-       p->conn->security_state.auth_info->credentials = null_data_blob;
-
-       while (1) {
-               num_passes++;
-               status = gensec_update(p->conn->security_state.generic_state, tmp_ctx,
-                                      p->conn->security_state.auth_info->credentials,
-                                      &credentials);
-
-               /* The status value here, from GENSEC is vital to the security
-                * of the system.  Even if the other end accepts, if GENSEC
-                * claims 'MORE_PROCESSING_REQUIRED' then you must keep
-                * feeding it blobs, or else the remote host/attacker might
-                * avoid mutal authentication requirements.
-                *
-                * Likewise, you must not feed GENSEC too much (after the OK),
-                * it doesn't like that either
-                */
-
-               if (!NT_STATUS_IS_OK(status) 
-                   && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-                       DEBUG(1, ("Failed DCERPC client gensec_update with mechanism %s: %s\n",
-                                 gensec_get_name_by_authtype(auth_type), nt_errstr(status)));
-
-                       break;
-               }
+       creq = dcerpc_alter_context_send(state->pipe, state,
+                                        &state->pipe->syntax,
+                                        &state->pipe->transfer_syntax);
+       composite_continue(c, creq, bind_auth_recv_alter, c);
+}
 
-               if (!credentials.length) {
-                       break;
-               }
+static void bind_auth_recv_alter(struct composite_context *creq)
+{
+       struct composite_context *c =
+               talloc_get_type(creq->async.private_data,
+                               struct composite_context);
 
-               p->conn->security_state.auth_info->credentials = credentials;
-               
-               if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-                       if (num_passes == 1) {
-                               status = dcerpc_bind_byuuid(p, tmp_ctx, uuid, version);
-                       } else {
-                               /* We are demanding a reply, so use a request that will get us one */
-                               status = dcerpc_alter_context(p, tmp_ctx, &p->syntax, &p->transfer_syntax);
-                       }
-                       if (!NT_STATUS_IS_OK(status)) {
-                               break;
-                       }
-               } else if (NT_STATUS_IS_OK(status)) {
-                       /* NO reply expected, so just send it */
-                       if (num_passes == 1) {
-                               status = dcerpc_bind_byuuid(p, tmp_ctx, uuid, version);
-                       } else {
-                               status = dcerpc_auth3(p->conn, tmp_ctx);
-                       }
-                       break;
-               } else {
-                       break;
-               }
-       };
+       c->status = dcerpc_alter_context_recv(creq);
+       if (!composite_is_ok(c)) return;
 
-done:
-       talloc_free(tmp_ctx);
+       bind_auth_next_step(c);
+}
 
-       if (!NT_STATUS_IS_OK(status)) {
-               talloc_free(p->conn->security_state.generic_state);
-               ZERO_STRUCT(p->conn->security_state);
-       } else {
-               /* Authenticated connections use the generic session key */
-               p->conn->security_state.session_key = dcerpc_generic_session_key;
+static void bind_auth_recv_bindreply(struct composite_context *creq)
+{
+       struct composite_context *c =
+               talloc_get_type(creq->async.private_data,
+                               struct composite_context);
+       struct bind_auth_state *state =
+               talloc_get_type(c->private_data, struct bind_auth_state);
+
+       c->status = dcerpc_bind_recv(creq);
+       if (!composite_is_ok(c)) return;
+
+       if (!state->more_processing) {
+               composite_done(c);
+               return;
        }
 
-       return status;
+       bind_auth_next_step(c);
 }
 
-/*
-  setup GENSEC on a DCE-RPC pipe
-*/
-NTSTATUS dcerpc_bind_auth_password(struct dcerpc_pipe *p,
-                                  const char *uuid, uint_t version,
-                                  struct cli_credentials *credentials,
-                                  uint8_t auth_type,
-                                  const char *service)
+static struct composite_context *dcerpc_bind_auth_send(struct dcerpc_pipe *p,
+                                                      TALLOC_CTX *mem_ctx,
+                                                      const char *uuid, uint_t version,
+                                                      struct cli_credentials *credentials,
+                                                      uint8_t auth_type,
+                                                      const char *service)
 {
-       NTSTATUS status;
+       struct composite_context *c, *creq;
+       struct bind_auth_state *state;
+       struct dcerpc_security *sec;
+
+       struct dcerpc_syntax_id syntax, transfer_syntax;
+
+       c = talloc_zero(mem_ctx, struct composite_context);
+       if (c == NULL) return NULL;
 
-       if (!(p->conn->flags & (DCERPC_SIGN | DCERPC_SEAL))) {
-               p->conn->flags |= DCERPC_CONNECT;
+       state = talloc(c, struct bind_auth_state);
+       if (state == NULL) {
+               c->status = NT_STATUS_NO_MEMORY;
+               goto failed;
        }
 
-       status = gensec_client_start(p, &p->conn->security_state.generic_state,
-                                    p->conn->event_ctx);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status)));
-               return status;
+       c->state = COMPOSITE_STATE_IN_PROGRESS;
+       c->private_data = state;
+       c->event_ctx = p->conn->event_ctx;
+
+       state->pipe = p;
+
+       c->status = dcerpc_init_syntaxes(uuid, version,
+                                        &syntax,
+                                        &transfer_syntax);
+       if (!NT_STATUS_IS_OK(c->status)) goto failed;
+
+       sec = &p->conn->security_state;
+
+       c->status = gensec_client_start(p, &sec->generic_state,
+                                       p->conn->event_ctx);
+       if (!NT_STATUS_IS_OK(c->status)) {
+               DEBUG(1, ("Failed to start GENSEC client mode: %s\n",
+                         nt_errstr(c->status)));
+               goto failed;
        }
 
-       status = gensec_set_credentials(p->conn->security_state.generic_state, 
-                                       credentials);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start set GENSEC client credentails: %s\n", 
-                         nt_errstr(status)));
-               return status;
+       c->status = gensec_set_credentials(sec->generic_state, credentials);
+       if (!NT_STATUS_IS_OK(c->status)) {
+               DEBUG(1, ("Failed to set GENSEC client credentails: %s\n",
+                         nt_errstr(c->status)));
+               goto failed;
        }
 
-       status = gensec_set_target_hostname(p->conn->security_state.generic_state, 
-                                           p->conn->transport.peer_name(p->conn));
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
-                         nt_errstr(status)));
-               return status;
+       c->status = gensec_set_target_hostname(
+               sec->generic_state, p->conn->transport.peer_name(p->conn));
+       if (!NT_STATUS_IS_OK(c->status)) {
+               DEBUG(1, ("Failed to set GENSEC target hostname: %s\n", 
+                         nt_errstr(c->status)));
+               goto failed;
        }
 
-       if (service) {
-               status = gensec_set_target_service(p->conn->security_state.generic_state, service);
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(1, ("Failed to start set GENSEC target service: %s\n", 
-                                 nt_errstr(status)));
-                       return status;
+       if (service != NULL) {
+               c->status = gensec_set_target_service(sec->generic_state,
+                                                     service);
+               if (!NT_STATUS_IS_OK(c->status)) {
+                       DEBUG(1, ("Failed to set GENSEC target service: %s\n",
+                                 nt_errstr(c->status)));
+                       goto failed;
                }
        }
 
-       status = gensec_start_mech_by_authtype(p->conn->security_state.generic_state, 
-                                              auth_type,
-                                              dcerpc_auth_level(p->conn));
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
-                         gensec_get_name_by_authtype(auth_type), nt_errstr(status)));
-               return status;
+       c->status = gensec_start_mech_by_authtype(sec->generic_state,
+                                                 auth_type,
+                                                 dcerpc_auth_level(p->conn));
+       if (!NT_STATUS_IS_OK(c->status)) {
+               DEBUG(1, ("Failed to start GENSEC client mechanism %s: %s\n",
+                         gensec_get_name_by_authtype(auth_type),
+                         nt_errstr(c->status)));
+               goto failed;
+       }
+
+       sec->auth_info = talloc(p, struct dcerpc_auth);
+       if (sec->auth_info == NULL) {
+               c->status = NT_STATUS_NO_MEMORY;
+               goto failed;
+       }
+
+       sec->auth_info->auth_type = auth_type;
+       sec->auth_info->auth_level = dcerpc_auth_level(p->conn);
+       sec->auth_info->auth_pad_length = 0;
+       sec->auth_info->auth_reserved = 0;
+       sec->auth_info->auth_context_id = random();
+       sec->auth_info->credentials = data_blob(NULL, 0);
+
+       c->status = gensec_update(sec->generic_state, state,
+                                 sec->auth_info->credentials,
+                                 &state->credentials);
+       if (!NT_STATUS_IS_OK(c->status) &&
+           !NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               goto failed;
+       }
+
+       state->more_processing =
+               NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED);
+
+       if (state->credentials.length == 0) {
+               composite_trigger_done(c);
+               return c;
        }
-       
-       status = dcerpc_bind_auth(p, auth_type,
-                                 dcerpc_auth_level(p->conn),
-                                 uuid, version);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(2, ("Failed to bind to pipe with %s: %s\n", 
-                         gensec_get_name_by_authtype(auth_type), nt_errstr(status)));
-               return status;
+
+       sec->auth_info->credentials = state->credentials;
+
+       creq = dcerpc_bind_send(p, state, &syntax, &transfer_syntax);
+       if (creq == NULL) {
+               c->status = NT_STATUS_NO_MEMORY;
+               goto failed;
        }
 
-       return status;
+       creq->async.fn = bind_auth_recv_bindreply;
+       creq->async.private_data = c;
+       return c;
+
+ failed:
+       composite_trigger_error(c);
+       return c;
+}
+
+static NTSTATUS dcerpc_bind_auth_recv(struct composite_context *creq)
+{
+       NTSTATUS result = composite_wait(creq);
+       talloc_free(creq);
+       return result;
+}
+
+/*
+  setup GENSEC on a DCE-RPC pipe
+*/
+NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p,
+                         const char *uuid, uint_t version,
+                         struct cli_credentials *credentials,
+                         uint8_t auth_type,
+                         const char *service)
+{
+       struct composite_context *creq;
+       creq = dcerpc_bind_auth_send(p, p, uuid, version, credentials,
+                                    auth_type, service);
+       return dcerpc_bind_auth_recv(creq);
 }
index ae4ce9426923319bce86ec5ba0e76c36a5fd22fa..e9e31f294f5c7d193d1282500db765524bdcb05b 100644 (file)
@@ -158,8 +158,8 @@ NTSTATUS dcerpc_bind_auth_schannel(TALLOC_CTX *tmp_ctx,
                return status;
        }
 
-       return dcerpc_bind_auth_password(p, uuid, version, 
-                                        credentials, DCERPC_AUTH_TYPE_SCHANNEL,
-                                        NULL);
+       return dcerpc_bind_auth(p, uuid, version, 
+                               credentials, DCERPC_AUTH_TYPE_SCHANNEL,
+                               NULL);
 }
 
index ef510f4afcf07f9492b7c9128c43e9836c532101..400a8b5e21666085c7b95dd7cb2ce6fb6d0f4e0e 100644 (file)
@@ -985,9 +985,9 @@ NTSTATUS dcerpc_pipe_auth(struct dcerpc_pipe *p,
                        auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
                }
 
-               status = dcerpc_bind_auth_password(p, pipe_uuid, pipe_version, 
-                                                  credentials, auth_type,
-                                                  binding->authservice);
+               status = dcerpc_bind_auth(p, pipe_uuid, pipe_version, 
+                                         credentials, auth_type,
+                                         binding->authservice);
        } else {
                status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version);
        }
index 4b9c4a82357c20b804680a6fc3684eb7544ca291..338a71d27b1e7a98036e29c1fa7b3311bc5e1799 100644 (file)
@@ -214,11 +214,11 @@ static BOOL test_schannel(TALLOC_CTX *mem_ctx,
                goto failed;
        }
 
-       status = dcerpc_bind_auth_password(p_netlogon, 
-                                          DCERPC_NETLOGON_UUID,
-                                          DCERPC_NETLOGON_VERSION, 
-                                          credentials, DCERPC_AUTH_TYPE_SCHANNEL,
-                                          NULL);
+       status = dcerpc_bind_auth(p_netlogon, 
+                                 DCERPC_NETLOGON_UUID,
+                                 DCERPC_NETLOGON_VERSION, 
+                                 credentials, DCERPC_AUTH_TYPE_SCHANNEL,
+                                 NULL);
 
        if (!NT_STATUS_IS_OK(status)) {
                goto failed;
@@ -249,11 +249,11 @@ static BOOL test_schannel(TALLOC_CTX *mem_ctx,
                goto failed;
        }
 
-       status = dcerpc_bind_auth_password(p_lsa, 
-                                          DCERPC_LSARPC_UUID,
-                                          DCERPC_LSARPC_VERSION, 
-                                          credentials, DCERPC_AUTH_TYPE_SCHANNEL,
-                                          NULL);
+       status = dcerpc_bind_auth(p_lsa, 
+                                 DCERPC_LSARPC_UUID,
+                                 DCERPC_LSARPC_VERSION, 
+                                 credentials, DCERPC_AUTH_TYPE_SCHANNEL,
+                                 NULL);
 
        if (!NT_STATUS_IS_OK(status)) {
                goto failed;
index 779bcb60a2c836afa6fde8ca91e2f9d23bbae886..d5222a685460dff5bc66821b061f1e35594e5261 100644 (file)
@@ -106,12 +106,11 @@ static void init_lsa_recv_pipe(struct composite_context *ctx)
                }
                state->lsa_pipe->conn->flags |= (DCERPC_SIGN | DCERPC_SEAL);
                state->ctx->status =
-                       dcerpc_bind_auth_password(state->lsa_pipe,
-                                                 DCERPC_LSARPC_UUID,
-                                                 DCERPC_LSARPC_VERSION,
-                                                 state->creds,
-                                                 state->auth_type,
-                                                 NULL);
+                       dcerpc_bind_auth(state->lsa_pipe,
+                                        DCERPC_LSARPC_UUID,
+                                        DCERPC_LSARPC_VERSION,
+                                        state->creds, state->auth_type,
+                                        NULL);
                break;
        default:
                state->ctx->status = NT_STATUS_INTERNAL_ERROR;
index 2ce189a5c7fae6fc5ee9e08f2abf9fc1ce933e7e..c806a6688b71d5aee1bc5a95a353f9e71cb1db03 100644 (file)
@@ -113,12 +113,11 @@ static void connect_samr_recv_pipe(struct composite_context *ctx)
                }
                state->samr_pipe->conn->flags |= (DCERPC_SIGN | DCERPC_SEAL);
                state->ctx->status =
-                       dcerpc_bind_auth_password(state->samr_pipe,
-                                                 DCERPC_SAMR_UUID,
-                                                 DCERPC_SAMR_VERSION,
-                                                 state->creds,
-                                                 state->auth_type,
-                                                 NULL);
+                       dcerpc_bind_auth(state->samr_pipe,
+                                        DCERPC_SAMR_UUID,
+                                        DCERPC_SAMR_VERSION,
+                                        state->creds, state->auth_type,
+                                        NULL);
                break;
        default:
                state->ctx->status = NT_STATUS_INTERNAL_ERROR;
index 21ea668043bb572b9976682d2e10f98083886365..fff3212cd93badef6268eb3e8a3c09a43a6a7048 100644 (file)
@@ -215,12 +215,12 @@ static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
        state->domain->netlogon_pipe->conn->flags |=
                (DCERPC_SIGN | DCERPC_SEAL);
        state->ctx->status =
-               dcerpc_bind_auth_password(state->domain->netlogon_pipe,
-                                         DCERPC_NETLOGON_UUID,
-                                         DCERPC_NETLOGON_VERSION, 
-                                         state->domain->schannel_creds,
-                                         DCERPC_AUTH_TYPE_SCHANNEL,
-                                         NULL);
+               dcerpc_bind_auth(state->domain->netlogon_pipe,
+                                DCERPC_NETLOGON_UUID,
+                                DCERPC_NETLOGON_VERSION, 
+                                state->domain->schannel_creds,
+                                DCERPC_AUTH_TYPE_SCHANNEL,
+                                NULL);
        if (!composite_is_ok(state->ctx)) return;
 
        ctx = wb_connect_lsa_send(state, state->conn.out.tree,