r15500: Add support for interactive prompting on bad passwords to the RPC libraries.
authorAndrew Bartlett <abartlet@samba.org>
Sun, 7 May 2006 18:11:47 +0000 (18:11 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:05:42 +0000 (14:05 -0500)
This support requires that the bind_ack and alter_ack recv functions
also be send the DCE/RPC fault.  This would be best done by having the
ack run as a normal RPC reply callback, but this isn't easily possible
for now.

Andrew Bartlett
(This used to be commit be6dde22fe728d64d47875699d3421c6d8d872a4)

source4/libnet/libnet_join.c
source4/librpc/rpc/dcerpc.c
source4/librpc/rpc/dcerpc_connect.c
source4/librpc/rpc/dcerpc_util.c
source4/torture/rpc/bind.c

index fb28eaed2f3c37f2fabad40d2685ca16c4e92d1a..608568bc53e642b1dc417463664e18d612ec2e52 100644 (file)
@@ -482,7 +482,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
 
        samr_pipe = connect_with_info->out.dcerpc_pipe;
 
-       status = dcerpc_pipe_auth(tmp_ctx, &samr_pipe,
+       status = dcerpc_pipe_auth(&samr_pipe,
                                  connect_with_info->out.dcerpc_pipe->binding, 
                                  &dcerpc_table_samr, ctx->cred);
        if (!NT_STATUS_IS_OK(status)) {
index cd33d3d14b1c16a4901b44060f19522fde69925a..adf67a7ba1c5c4cebd3fffa4d4b4d0c5dce32585 100644 (file)
@@ -489,6 +489,20 @@ static NTSTATUS dcerpc_map_reason(uint16_t reason)
        return NT_STATUS_UNSUCCESSFUL;
 }
 
+/*
+  map a fault reason to a NTSTATUS
+*/
+static NTSTATUS dcerpc_map_fault(uint32_t status)
+{
+       switch (status) {
+       case DCERPC_FAULT_OP_RNG_ERROR:
+               return NT_STATUS_ILLEGAL_FUNCTION;
+       case DCERPC_FAULT_ACCESS_DENIED:
+               return NT_STATUS_ACCESS_DENIED;
+       }
+       return NT_STATUS_NET_WRITE_FAULT;
+}
+
 /*
   mark the dcerpc connection dead. All outstanding requests get an error
 */
@@ -555,27 +569,19 @@ static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NT
                dcerpc_connection_dead(conn, status);
        }
 
-       switch (pkt.ptype) {
-       case DCERPC_PKT_BIND_NAK:
-       case DCERPC_PKT_BIND_ACK:
-               if (conn->bind_private) {
-                       talloc_steal(conn->bind_private, blob->data);
-                       dcerpc_bind_recv_data(conn, &pkt);
-               }
-               break;
-
-       case DCERPC_PKT_ALTER_RESP:
-               if (conn->alter_private) {
-                       talloc_steal(conn->alter_private, blob->data);
-                       dcerpc_alter_recv_data(conn, &pkt);
-               }
-               break;
-
-       default:
-               /* assume its an ordinary request */
-               dcerpc_request_recv_data(conn, blob, &pkt);
-               break;
+       if (conn->bind_private) {
+               talloc_steal(conn->bind_private, blob->data);
+               dcerpc_bind_recv_data(conn, &pkt);
+               return;
        }
+       if (conn->alter_private) {
+               talloc_steal(conn->alter_private, blob->data);
+               dcerpc_alter_recv_data(conn, &pkt);
+               return;
+       }
+
+       /* assume its an ordinary request */
+       dcerpc_request_recv_data(conn, blob, &pkt);
 }
 
 
@@ -591,6 +597,13 @@ static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_p
        /* mark the connection as not waiting for a bind reply */
        conn->bind_private = NULL;
 
+       if (pkt->ptype == DCERPC_PKT_FAULT) {
+               DEBUG(2,("dcerpc: bind faulted: reason %s\n",
+                        dcerpc_errstr(c, pkt->u.fault.status)));
+               composite_error(c, dcerpc_map_fault(pkt->u.fault.status));
+               return;
+       }
+
        if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
                DEBUG(2,("dcerpc: bind_nak reason %d\n",
                         pkt->u.bind_nak.reject_reason));
@@ -1528,6 +1541,13 @@ static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_
        /* mark the connection as not waiting for a alter context reply */
        conn->alter_private = NULL;
 
+       if (pkt->ptype == DCERPC_PKT_FAULT) {
+               DEBUG(2,("dcerpc: alter context faulted: reason %s\n",
+                        dcerpc_errstr(c, pkt->u.fault.status)));
+               composite_error(c, dcerpc_map_fault(pkt->u.fault.status));
+               return;
+       }
+
        if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
            pkt->u.alter_resp.num_results == 1 &&
            pkt->u.alter_resp.ctx_list[0].result != 0) {
index d69db51eb46b2e493eabadd5ba3695427b64a1f7..66b0af178bceb93a9aea7b1ee1f2e1d73e55bbb0 100644 (file)
@@ -764,7 +764,7 @@ static void continue_pipe_auth(struct composite_context *ctx)
                                                      struct composite_context);
        struct pipe_connect_state *s = talloc_get_type(c->private_data, struct pipe_connect_state);
 
-       c->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe);
+       c->status = dcerpc_pipe_auth_recv(s, &s->pipe);
        if (!composite_is_ok(c)) return;
 
        composite_done(c);
@@ -1170,7 +1170,8 @@ NTSTATUS dcerpc_secondary_connection_recv(struct composite_context *c,
        s = talloc_get_type(c->private_data, struct sec_conn_state);
 
        if (NT_STATUS_IS_OK(status)) {
-               *p2 = talloc_steal(s->pipe, s->pipe2);
+               talloc_steal(s->pipe, s->pipe2);
+               *p2 = s->pipe2;
        }
 
        talloc_free(c);
index 6c8ed7ecd8abd04f8d54c780c51c39e1321d0085..158c5e3fe0c47a41f417ddd095e21138a639c441 100644 (file)
@@ -976,14 +976,12 @@ struct pipe_auth_state {
        struct dcerpc_binding *binding;
        const struct dcerpc_interface_table *table;
        struct cli_credentials *credentials;
+       uint8_t next_auth_type;
+       BOOL try_ntlm_fallback;
 };
 
 
-static void continue_auth_schannel(struct composite_context *ctx);
-static void continue_auth(struct composite_context *ctx);
-static void continue_auth_none(struct composite_context *ctx);
-static void continue_ntlmssp_connection(struct composite_context *ctx);
-static void continue_spnego_after_wrong_pass(struct composite_context *ctx);
+static void continue_new_auth_bind(struct composite_context *ctx);
 
 
 /*
@@ -1001,53 +999,45 @@ static void continue_auth_schannel(struct composite_context *ctx)
 }
 
 
-/*
-  Stage 2 of pipe_auth: Receive result of authenticated bind request
-*/
-static void continue_auth(struct composite_context *ctx)
-{
-       struct composite_context *c = talloc_get_type(ctx->async.private_data,
-                                                     struct composite_context);
-
-       c->status = dcerpc_bind_auth_recv(ctx);
-       if (!composite_is_ok(c)) return;
-       
-       composite_done(c);
-}
 /*
   Stage 2 of pipe_auth: Receive result of authenticated bind request, but handle fallbacks:
   SPNEGO -> NTLMSSP
 */
-static void continue_auth_auto(struct composite_context *ctx)
+static void continue_recv_bind(struct composite_context *ctx)
 {
+       NTSTATUS status;
        struct composite_context *c = talloc_get_type(ctx->async.private_data,
                                                      struct composite_context);
+       struct pipe_auth_state *s = talloc_get_type(c->private_data, struct pipe_auth_state);
 
-       c->status = dcerpc_bind_auth_recv(ctx);
-       if (NT_STATUS_EQUAL(c->status, NT_STATUS_INVALID_PARAMETER)) {
-               struct pipe_auth_state *s = talloc_get_type(c->private_data, struct pipe_auth_state);
+       status = dcerpc_bind_auth_recv(ctx);
+       if (s->try_ntlm_fallback && NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
                struct composite_context *sec_conn_req;
-
+               s->try_ntlm_fallback = False;
+               s->next_auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
                /* send a request for secondary rpc connection */
                sec_conn_req = dcerpc_secondary_connection_send(s->pipe,
                                                                s->binding);
                if (composite_nomem(sec_conn_req, c)) return;
                
-               composite_continue(c, sec_conn_req, continue_ntlmssp_connection, c);
+               composite_continue(c, sec_conn_req, continue_new_auth_bind, c);
                
                return;
-       } else if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
-               struct pipe_auth_state *s = talloc_get_type(c->private_data, struct pipe_auth_state);
+       } else if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
                struct composite_context *sec_conn_req;
                if (cli_credentials_wrong_password(s->credentials)) {
+                       s->next_auth_type = DCERPC_AUTH_TYPE_SPNEGO;
                        /* send a request for secondary rpc connection */
                        sec_conn_req = dcerpc_secondary_connection_send(s->pipe,
                                                                        s->binding);
                        if (composite_nomem(sec_conn_req, c)) return;
                        
-                       composite_continue(c, sec_conn_req, continue_spnego_after_wrong_pass, c);
+                       composite_continue(c, sec_conn_req, continue_new_auth_bind, c);
+
+                       return;
                }
        }
+       c->status = status;
 
        if (!composite_is_ok(c)) return;
        
@@ -1055,44 +1045,14 @@ static void continue_auth_auto(struct composite_context *ctx)
 }
 
 /*
-  Stage 3 of pipe_auth (fallback to NTLMSSP case): Receive secondary
-  rpc connection (the first one can't be used any more, due to the
-  bind nak) and perform authenticated bind request
-*/
-static void continue_ntlmssp_connection(struct composite_context *ctx)
-{
-       struct composite_context *c;
-       struct pipe_auth_state *s;
-       struct composite_context *auth_req;
-       struct dcerpc_pipe *p2;
-
-       c = talloc_get_type(ctx->async.private_data, struct composite_context);
-       s = talloc_get_type(c->private_data, struct pipe_auth_state);
-
-       /* receive secondary rpc connection */
-       c->status = dcerpc_secondary_connection_recv(ctx, &p2);
-       talloc_steal(s, p2);
-       talloc_steal(p2, s->pipe);
-       s->pipe = p2;
+  Stage 3 of pipe_auth (fallback to NTLMSSP case/SPNEGO password retry case): 
+  
+  Receive secondary rpc connection (the first one can't be used any
+  more, due to the bind nak) and perform authenticated bind request
 
-       if (!composite_is_ok(c)) return;
-
-       /* initiate a authenticated bind */
-       auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
-                                        s->credentials, DCERPC_AUTH_TYPE_NTLMSSP,
-                                        dcerpc_auth_level(s->pipe->conn),
-                                        s->table->authservices->names[0]);
-       if (composite_nomem(auth_req, c)) return;
-               
-       composite_continue(c, auth_req, continue_auth, c);
-}
-
-/*
-  Stage 3 of pipe_auth (retry on wrong password): Receive secondary
-  rpc connection (the first one can't be used any more, due to the
-  bind nak) and perform authenticated bind request
+  Calls back to stage 2 to process the response.
 */
-static void continue_spnego_after_wrong_pass(struct composite_context *ctx)
+static void continue_new_auth_bind(struct composite_context *ctx)
 {
        struct composite_context *c;
        struct pipe_auth_state *s;
@@ -1104,27 +1064,25 @@ static void continue_spnego_after_wrong_pass(struct composite_context *ctx)
 
        /* receive secondary rpc connection */
        c->status = dcerpc_secondary_connection_recv(ctx, &p2);
-       talloc_steal(s, p2);
-       talloc_steal(p2, s->pipe);
        s->pipe = p2;
 
        if (!composite_is_ok(c)) return;
 
        /* initiate a authenticated bind */
        auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
-                                        s->credentials, DCERPC_AUTH_TYPE_SPNEGO,
+                                        s->credentials, s->next_auth_type,
                                         dcerpc_auth_level(s->pipe->conn),
                                         s->table->authservices->names[0]);
        if (composite_nomem(auth_req, c)) return;
                
-       composite_continue(c, auth_req, continue_auth, c);
+       composite_continue(c, auth_req, continue_recv_bind, c);
 }
 
 
 /*
   Stage 2 of pipe_auth: Receive result of non-authenticated bind request
 */
-static void continue_auth_none(struct composite_context *ctx)
+static void continue_auth_recv_none(struct composite_context *ctx)
 {
        struct composite_context *c = talloc_get_type(ctx->async.private_data,
                                                      struct composite_context);
@@ -1225,29 +1183,23 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
                } else if (s->binding->flags & DCERPC_AUTH_NTLM) {
                        auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
                } else {
-                       auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
-                                                        s->credentials, DCERPC_AUTH_TYPE_SPNEGO,
-                                                        dcerpc_auth_level(conn),
-                                                        s->table->authservices->names[0]);
-                       if (composite_nomem(auth_req, c)) return c;
-                       
-                       composite_continue(c, auth_req, continue_auth_auto, c);
-                       return c;
+                       auth_type = DCERPC_AUTH_TYPE_SPNEGO;
+                       s->try_ntlm_fallback = True;
                }
-               
+
                auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table,
-                                                s->credentials, auth_type,
+                                                s->credentials, DCERPC_AUTH_TYPE_SPNEGO,
                                                 dcerpc_auth_level(conn),
                                                 s->table->authservices->names[0]);
                if (composite_nomem(auth_req, c)) return c;
                
-               composite_continue(c, auth_req, continue_auth, c);
+               composite_continue(c, auth_req, continue_recv_bind, c);
 
        } else {
                auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe, s->table);
                if (composite_nomem(auth_none_req, c)) return c;
 
-               composite_continue(c, auth_none_req, continue_auth_none, c);
+               composite_continue(c, auth_none_req, continue_auth_recv_none, c);
        }
 
        return c;
@@ -1261,7 +1213,7 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
   supllied, as it rebinds to a new pipe due to authentication fallback
 
 */
-NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, 
+NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, 
                               struct dcerpc_pipe **p)
 {
        NTSTATUS status;
@@ -1274,7 +1226,6 @@ NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
                DEBUG(0, ("Failed to bind to uuid %s - %s\n", uuid_str, nt_errstr(status)));
                talloc_free(uuid_str);
        } else {
-               talloc_steal(mem_ctx, s->pipe);
                *p = s->pipe;
        }
 
@@ -1288,8 +1239,7 @@ NTSTATUS dcerpc_pipe_auth_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
 
    This may change *p, as it rebinds to a new pipe due to authentication fallback
 */
-NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx,
-                         struct dcerpc_pipe **p, 
+NTSTATUS dcerpc_pipe_auth(struct dcerpc_pipe **p, 
                          struct dcerpc_binding *binding,
                          const struct dcerpc_interface_table *table,
                          struct cli_credentials *credentials)
@@ -1297,7 +1247,7 @@ NTSTATUS dcerpc_pipe_auth(TALLOC_CTX *mem_ctx,
        struct composite_context *c;
 
        c = dcerpc_pipe_auth_send(*p, binding, table, credentials);
-       return dcerpc_pipe_auth_recv(c, mem_ctx, p);
+       return dcerpc_pipe_auth_recv(c, p);
 }
 
 
index 17580737f88b2acec9934f2c1e1318d08cfd9344..9467ad3d38e3c6b522ee870973ee2c2a2958de37 100644 (file)
@@ -63,7 +63,7 @@ BOOL torture_multi_bind(struct torture_context *torture)
                return False;
        }
 
-       status = dcerpc_pipe_auth(mem_ctx, &p, binding, &dcerpc_table_lsarpc, cmdline_credentials);
+       status = dcerpc_pipe_auth(&p, binding, &dcerpc_table_lsarpc, cmdline_credentials);
 
        if (NT_STATUS_IS_OK(status)) {
                printf("(incorrectly) allowed re-bind to uuid %s - %s\n",