*/
#include "includes.h"
+#include "rpc_server/dcerpc_server.h"
/*
startup the cryptographic side of an authenticated dcerpc server
{
NTSTATUS status;
if (auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_INTEGRITY &&
- auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+ auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY &&
+ auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_CONNECT) {
DEBUG(2,("auth_level %d not supported in dcesrv auth\n",
auth->auth_info->auth_level));
return NT_STATUS_INVALID_PARAMETER;
*/
}
- status = gensec_server_start(&auth->gensec_security);
+ status = gensec_server_start(dce_conn, &auth->gensec_security);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
return status;
return True;
}
- dce_conn->auth_state.auth_info = talloc_p(dce_conn->mem_ctx, struct dcerpc_auth);
+ dce_conn->auth_state.auth_info = talloc_p(dce_conn, struct dcerpc_auth);
if (!dce_conn->auth_state.auth_info) {
return False;
}
status = ndr_pull_struct_blob(&pkt->u.bind.auth_info,
- call->mem_ctx,
+ call,
dce_conn->auth_state.auth_info,
(ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
if (!NT_STATUS_IS_OK(status)) {
}
status = gensec_update(dce_conn->auth_state.gensec_security,
- call->mem_ctx,
+ call,
dce_conn->auth_state.auth_info->credentials,
&dce_conn->auth_state.auth_info->credentials);
DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
return False;
}
+
+ /* Now that we are authenticated, got back to the generic session key... */
+ dce_conn->auth_state.session_key = dcesrv_generic_session_key;
return True;
} else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
dce_conn->auth_state.auth_info->auth_pad_length = 0;
/* We can't work without an existing gensec state, and an new blob to feed it */
if (!dce_conn->auth_state.auth_info ||
!dce_conn->auth_state.gensec_security ||
- pkt->u.auth.auth_info.length == 0) {
+ pkt->u.auth3.auth_info.length == 0) {
return False;
}
- status = ndr_pull_struct_blob(&pkt->u.auth.auth_info,
- call->mem_ctx,
+ status = ndr_pull_struct_blob(&pkt->u.auth3.auth_info,
+ call,
dce_conn->auth_state.auth_info,
(ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
if (!NT_STATUS_IS_OK(status)) {
/* Pass the extra data we got from the client down to gensec for processing */
status = gensec_update(dce_conn->auth_state.gensec_security,
- call->mem_ctx,
+ call,
dce_conn->auth_state.auth_info->credentials,
&dce_conn->auth_state.auth_info->credentials);
if (NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
return False;
}
+ /* Now that we are authenticated, got back to the generic session key... */
+ dce_conn->auth_state.session_key = dcesrv_generic_session_key;
return True;
} else {
DEBUG(4, ("dcesrv_auth_auth3: failed to authenticate: %s\n",
return True;
}
+/*
+ parse any auth information from a dcerpc alter request
+ return False if we can't handle the auth request for some
+ reason (in which case we send a bind_nak (is this true for here?))
+*/
+BOOL dcesrv_auth_alter(struct dcesrv_call_state *call)
+{
+ struct dcerpc_packet *pkt = &call->pkt;
+ struct dcesrv_connection *dce_conn = call->conn;
+ NTSTATUS status;
+
+ /* on a pure interface change there is no auth blob */
+ if (pkt->u.alter.auth_info.length == 0) {
+ return True;
+ }
+
+ /* We can't work without an existing gensec state */
+ if (!dce_conn->auth_state.gensec_security) {
+ return False;
+ }
+
+ dce_conn->auth_state.auth_info = talloc_p(dce_conn, struct dcerpc_auth);
+ if (!dce_conn->auth_state.auth_info) {
+ return False;
+ }
+
+ status = ndr_pull_struct_blob(&pkt->u.alter.auth_info,
+ call,
+ dce_conn->auth_state.auth_info,
+ (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ return True;
+}
+
+/*
+ add any auth information needed in a alter ack, and process the authentication
+ information found in the alter.
+*/
+BOOL dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct dcerpc_packet *pkt)
+{
+ struct dcesrv_connection *dce_conn = call->conn;
+ NTSTATUS status;
+
+ /* on a pure interface change there is no auth_info structure
+ setup */
+ if (!call->conn->auth_state.auth_info) {
+ return True;
+ }
+
+ if (!call->conn->auth_state.gensec_security) {
+ return False;
+ }
+
+ status = gensec_update(dce_conn->auth_state.gensec_security,
+ call,
+ dce_conn->auth_state.auth_info->credentials,
+ &dce_conn->auth_state.auth_info->credentials);
+
+ if (NT_STATUS_IS_OK(status)) {
+ status = gensec_session_info(dce_conn->auth_state.gensec_security,
+ &dce_conn->auth_state.session_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
+ return False;
+ }
+
+ /* Now that we are authenticated, got back to the generic session key... */
+ dce_conn->auth_state.session_key = dcesrv_generic_session_key;
+ return True;
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ dce_conn->auth_state.auth_info->auth_pad_length = 0;
+ dce_conn->auth_state.auth_info->auth_reserved = 0;
+ return True;
+ } else {
+ DEBUG(2, ("Failed to finish dcesrv auth alter_ack: %s\n", nt_errstr(status)));
+ return True;
+ }
+}
+
+/*
+ generate a CONNECT level verifier
+*/
+static NTSTATUS dcesrv_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
+{
+ *blob = data_blob_talloc(mem_ctx, NULL, 16);
+ if (blob->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ SIVAL(blob->data, 0, 1);
+ memset(blob->data+4, 0, 12);
+ return NT_STATUS_OK;
+}
+
+/*
+ generate a CONNECT level verifier
+*/
+static NTSTATUS dcesrv_check_connect_verifier(DATA_BLOB *blob)
+{
+ if (blob->length != 16 ||
+ IVAL(blob->data, 0) != 1) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ return NT_STATUS_OK;
+}
+
+
/*
check credentials on a request
*/
pkt->u.request.stub_and_verifier.length -= auth_blob.length;
/* pull the auth structure */
- ndr = ndr_pull_init_blob(&auth_blob, call->mem_ctx);
+ ndr = ndr_pull_init_blob(&auth_blob, call);
if (!ndr) {
return False;
}
status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(ndr);
return False;
}
switch (dce_conn->auth_state.auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
status = gensec_unseal_packet(dce_conn->auth_state.gensec_security,
- call->mem_ctx,
- pkt->u.request.stub_and_verifier.data,
+ call,
+ full_packet->data + DCERPC_REQUEST_LENGTH,
pkt->u.request.stub_and_verifier.length,
full_packet->data,
full_packet->length-auth.credentials.length,
&auth.credentials);
+ memcpy(pkt->u.request.stub_and_verifier.data,
+ full_packet->data + DCERPC_REQUEST_LENGTH,
+ pkt->u.request.stub_and_verifier.length);
break;
case DCERPC_AUTH_LEVEL_INTEGRITY:
status = gensec_check_packet(dce_conn->auth_state.gensec_security,
- call->mem_ctx,
+ call,
pkt->u.request.stub_and_verifier.data,
pkt->u.request.stub_and_verifier.length,
full_packet->data,
&auth.credentials);
break;
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ status = dcesrv_check_connect_verifier(&auth.credentials);
+ break;
+
default:
status = NT_STATUS_INVALID_LEVEL;
break;
/* remove the indicated amount of padding */
if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) {
+ talloc_free(ndr);
return False;
}
pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length;
+ talloc_free(ndr);
return NT_STATUS_IS_OK(status);
}
struct dcesrv_connection *dce_conn = call->conn;
NTSTATUS status;
struct ndr_push *ndr;
+ uint32_t payload_length;
/* non-signed packets are simple */
if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.gensec_security) {
- status = dcerpc_push_auth(blob, call->mem_ctx, pkt, NULL);
+ status = dcerpc_push_auth(blob, call, pkt, NULL);
return NT_STATUS_IS_OK(status);
}
- ndr = ndr_push_init_ctx(call->mem_ctx);
+ ndr = ndr_push_init_ctx(call);
if (!ndr) {
return False;
}
dce_conn->auth_state.auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
ndr_push_zero(ndr, dce_conn->auth_state.auth_info->auth_pad_length);
-
- dce_conn->auth_state.auth_info->credentials
- = data_blob_talloc(call->mem_ctx, NULL,
- gensec_sig_size(dce_conn->auth_state.gensec_security));
+ payload_length = ndr->offset - DCERPC_REQUEST_LENGTH;
+
+ if (dce_conn->auth_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
+ status = dcesrv_connect_verifier(call,
+ &dce_conn->auth_state.auth_info->credentials);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+ } else {
+ dce_conn->auth_state.auth_info->credentials
+ = data_blob_talloc(call, NULL,
+ gensec_sig_size(dce_conn->auth_state.gensec_security));
+ }
/* add the auth verifier */
status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, dce_conn->auth_state.auth_info);
switch (dce_conn->auth_state.auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
status = gensec_seal_packet(dce_conn->auth_state.gensec_security,
- call->mem_ctx,
+ call,
ndr->data + DCERPC_REQUEST_LENGTH,
- ndr->offset - DCERPC_REQUEST_LENGTH,
+ payload_length,
blob->data,
blob->length - dce_conn->auth_state.auth_info->credentials.length,
- &dce_conn->auth_state.auth_info->credentials);
+ &dce_conn->auth_state.auth_info->credentials);
break;
case DCERPC_AUTH_LEVEL_INTEGRITY:
status = gensec_sign_packet(dce_conn->auth_state.gensec_security,
- call->mem_ctx,
+ call,
ndr->data + DCERPC_REQUEST_LENGTH,
- ndr->offset - DCERPC_REQUEST_LENGTH,
+ payload_length,
blob->data,
blob->length - dce_conn->auth_state.auth_info->credentials.length,
&dce_conn->auth_state.auth_info->credentials);
break;
+
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ break;
+
default:
status = NT_STATUS_INVALID_LEVEL;
break;