summaryrefslogtreecommitdiff
path: root/source4/librpc/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'source4/librpc/rpc')
-rw-r--r--source4/librpc/rpc/dcerpc.c9
-rw-r--r--source4/librpc/rpc/dcerpc_auth.c332
-rw-r--r--source4/librpc/rpc/dcerpc_schannel.c6
-rw-r--r--source4/librpc/rpc/dcerpc_util.c6
4 files changed, 203 insertions, 150 deletions
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index c7f337de99..ee06d6e2be 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -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;
diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c
index 117112c197..29ab80da7a 100644
--- a/source4/librpc/rpc/dcerpc_auth.c
+++ b/source4/librpc/rpc/dcerpc_auth.c
@@ -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);
}
diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c
index ae4ce94269..e9e31f294f 100644
--- a/source4/librpc/rpc/dcerpc_schannel.c
+++ b/source4/librpc/rpc/dcerpc_schannel.c
@@ -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);
}
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index ef510f4afc..400a8b5e21 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -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);
}