The branch, v4-0-test has been updated via 2e3629719790e7631d9de383b565dc8a0997bcfb (commit) via eca0502b8620f2110a303b84def4f0bf48cc4ea5 (commit) via e82468a8f538aa0cf6d477fb54cc0178c0d64574 (commit) via d982b69df638f17da6af398e2613986240031064 (commit) from 2bf9074c7751324483744f55b02cfb044bb0b2dd (commit)
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v4-0-test - Log ----------------------------------------------------------------- commit 2e3629719790e7631d9de383b565dc8a0997bcfb Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Fri Sep 12 15:47:02 2008 +0200 rpc_server: don't send auth trailers in level connect Also ignore auth trailers in level connect on receive. This fixes [krb5,connect] against windows. TODO: maybe the gensec mech need to decide if signatures are needed in level connect. metze commit eca0502b8620f2110a303b84def4f0bf48cc4ea5 Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Fri Sep 12 14:39:57 2008 +0200 librpc/rpc: don't send auth trailers in level connect Also ignore auth trailers in level connect on receive. This fixes [krb5,connect] against windows. TODO: maybe the gensec mech need to decide if signatures are needed in level connect. metze commit e82468a8f538aa0cf6d477fb54cc0178c0d64574 Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Sat Sep 13 10:22:39 2008 +0200 rpc_server: correctly calculate the auth padding metze commit d982b69df638f17da6af398e2613986240031064 Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Sat Sep 13 18:49:03 2008 +0200 client free credentials when not needed anymore ----------------------------------------------------------------------- Summary of changes: source/librpc/rpc/dcerpc.c | 190 +++++++++++++++---------------------- source/librpc/rpc/dcerpc_auth.c | 7 ++ source/rpc_server/dcerpc_server.c | 11 ++- source/rpc_server/dcesrv_auth.c | 169 ++++++++++++++++----------------- 4 files changed, 172 insertions(+), 205 deletions(-) Changeset truncated at 500 lines: diff --git a/source/librpc/rpc/dcerpc.c b/source/librpc/rpc/dcerpc.c index 28b5cd6..5bbcc5e 100644 --- a/source/librpc/rpc/dcerpc.c +++ b/source/librpc/rpc/dcerpc.c @@ -210,32 +210,6 @@ static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_ return NT_STATUS_OK; } -/* - generate a CONNECT level verifier -*/ -static NTSTATUS dcerpc_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; -} - -/* - check a CONNECT level verifier -*/ -static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob) -{ - if (blob->length != 16 || - IVAL(blob->data, 0) != 1) { - return NT_STATUS_ACCESS_DENIED; - } - return NT_STATUS_OK; -} - /* parse the authentication information on a dcerpc response packet */ @@ -249,9 +223,29 @@ static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX DATA_BLOB auth_blob; enum ndr_err_code ndr_err; - if (pkt->auth_length == 0 && - c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) { + if (!c->security_state.auth_info || + !c->security_state.generic_state) { + return NT_STATUS_OK; + } + + switch (c->security_state.auth_info->auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + case DCERPC_AUTH_LEVEL_INTEGRITY: + break; + + case DCERPC_AUTH_LEVEL_CONNECT: + if (pkt->auth_length != 0) { + break; + } return NT_STATUS_OK; + case DCERPC_AUTH_LEVEL_NONE: + if (pkt->auth_length != 0) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + return NT_STATUS_OK; + + default: + return NT_STATUS_INVALID_LEVEL; } auth_blob.length = 8 + pkt->auth_length; @@ -308,10 +302,8 @@ static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX break; case DCERPC_AUTH_LEVEL_CONNECT: - status = dcerpc_check_connect_verifier(&auth.credentials); - break; - - case DCERPC_AUTH_LEVEL_NONE: + /* for now we ignore possible signatures here */ + status = NT_STATUS_OK; break; default: @@ -344,9 +336,24 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, enum ndr_err_code ndr_err; /* non-signed packets are simpler */ - if (!c->security_state.auth_info || - !c->security_state.generic_state) { - return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, c->security_state.auth_info); + if (sig_size == 0) { + return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL); + } + + switch (c->security_state.auth_info->auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + case DCERPC_AUTH_LEVEL_INTEGRITY: + break; + + case DCERPC_AUTH_LEVEL_CONNECT: + /* TODO: let the gensec mech decide if it wants to generate a signature */ + return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL); + + case DCERPC_AUTH_LEVEL_NONE: + return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL); + + default: + return NT_STATUS_INVALID_LEVEL; } ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience); @@ -372,39 +379,17 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, packet. This matches what w2k3 does */ c->security_state.auth_info->auth_pad_length = (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15; - ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length); + ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + status = NT_STATUS_OK; payload_length = pkt->u.request.stub_and_verifier.length + c->security_state.auth_info->auth_pad_length; - /* sign or seal the packet */ - switch (c->security_state.auth_info->auth_level) { - case DCERPC_AUTH_LEVEL_PRIVACY: - case DCERPC_AUTH_LEVEL_INTEGRITY: - /* We hope this length is accruate. If must be if the - * GENSEC mech does AEAD signing of the packet - * headers */ - c->security_state.auth_info->credentials - = data_blob_talloc(mem_ctx, NULL, sig_size); - data_blob_clear(&c->security_state.auth_info->credentials); - break; - - case DCERPC_AUTH_LEVEL_CONNECT: - status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials); - break; - - case DCERPC_AUTH_LEVEL_NONE: - c->security_state.auth_info->credentials = data_blob(NULL, 0); - break; - - default: - status = NT_STATUS_INVALID_LEVEL; - break; - } - - if (!NT_STATUS_IS_OK(status)) { - return status; - } + /* we start without signature, it will appended later */ + c->security_state.auth_info->credentials = data_blob(NULL,0); /* add the auth verifier */ ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info); @@ -416,13 +401,14 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, /* extract the whole packet as a blob */ *blob = ndr_push_blob(ndr); - /* fill in the fragment length and auth_length, we can't fill - in these earlier as we don't know the signature length (it - could be variable length) */ - dcerpc_set_frag_length(blob, blob->length); - /* We hope this value is accruate. If must be if the GENSEC - * mech does AEAD signing of the packet headers */ - dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length); + /* + * Setup the frag and auth length in the packet buffer. + * This is needed if the GENSEC mech does AEAD signing + * of the packet headers. The signature itself will be + * appended later. + */ + dcerpc_set_frag_length(blob, blob->length + sig_size); + dcerpc_set_auth_length(blob, sig_size); /* sign or seal the packet */ switch (c->security_state.auth_info->auth_level) { @@ -432,25 +418,11 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, blob->data + DCERPC_REQUEST_LENGTH, payload_length, blob->data, - blob->length - - c->security_state.auth_info->credentials.length, + blob->length, &creds2); if (!NT_STATUS_IS_OK(status)) { return status; } - blob->length -= c->security_state.auth_info->credentials.length; - if (!data_blob_append(mem_ctx, blob, - creds2.data, creds2.length)) { - return NT_STATUS_NO_MEMORY; - } - dcerpc_set_auth_length(blob, creds2.length); - if (c->security_state.auth_info->credentials.length == 0) { - /* this is needed for krb5 only, to correct the total packet - length */ - dcerpc_set_frag_length(blob, - dcerpc_get_frag_length(blob) - +creds2.length); - } break; case DCERPC_AUTH_LEVEL_INTEGRITY: @@ -459,32 +431,11 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, blob->data + DCERPC_REQUEST_LENGTH, payload_length, blob->data, - blob->length - - c->security_state.auth_info->credentials.length, + blob->length, &creds2); if (!NT_STATUS_IS_OK(status)) { return status; } - blob->length -= c->security_state.auth_info->credentials.length; - if (!data_blob_append(mem_ctx, blob, - creds2.data, creds2.length)) { - return NT_STATUS_NO_MEMORY; - } - dcerpc_set_auth_length(blob, creds2.length); - if (c->security_state.auth_info->credentials.length == 0) { - /* this is needed for krb5 only, to correct the total packet - length */ - dcerpc_set_frag_length(blob, - dcerpc_get_frag_length(blob) - +creds2.length); - } - break; - - case DCERPC_AUTH_LEVEL_CONNECT: - break; - - case DCERPC_AUTH_LEVEL_NONE: - c->security_state.auth_info->credentials = data_blob(NULL, 0); break; default: @@ -492,7 +443,17 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, break; } - data_blob_free(&c->security_state.auth_info->credentials); + if (creds2.length != sig_size) { + DEBUG(0,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n", + creds2.length, (uint32_t)sig_size, + c->security_state.auth_info->auth_pad_length, + pkt->u.request.stub_and_verifier.length)); + return NT_STATUS_INTERNAL_ERROR; + } + + if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) { + return NT_STATUS_NO_MEMORY; + } return NT_STATUS_OK; } @@ -1068,13 +1029,16 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c) request header size */ chunk_size = p->conn->srv_max_recv_frag; chunk_size -= DCERPC_REQUEST_LENGTH; - if (c->security_state.generic_state) { - chunk_size -= DCERPC_AUTH_TRAILER_LENGTH; + if (c->security_state.auth_info && + c->security_state.generic_state) { sig_size = gensec_sig_size(c->security_state.generic_state, p->conn->srv_max_recv_frag); - chunk_size -= sig_size; - chunk_size -= (chunk_size % 16); + if (sig_size) { + chunk_size -= DCERPC_AUTH_TRAILER_LENGTH; + chunk_size -= sig_size; + } } + chunk_size -= (chunk_size % 16); pkt.ptype = DCERPC_PKT_REQUEST; pkt.call_id = req->call_id; diff --git a/source/librpc/rpc/dcerpc_auth.c b/source/librpc/rpc/dcerpc_auth.c index 49fc3d9..2eced55 100644 --- a/source/librpc/rpc/dcerpc_auth.c +++ b/source/librpc/rpc/dcerpc_auth.c @@ -129,6 +129,7 @@ static void bind_auth_next_step(struct composite_context *c) c->status = gensec_update(sec->generic_state, state, sec->auth_info->credentials, &state->credentials); + data_blob_free(&sec->auth_info->credentials); if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { more_processing = true; @@ -151,6 +152,8 @@ static void bind_auth_next_step(struct composite_context *c) if (!more_processing) { /* NO reply expected, so just send it */ c->status = dcerpc_auth3(state->pipe, state); + data_blob_free(&state->credentials); + sec->auth_info->credentials = data_blob(NULL, 0); if (!composite_is_ok(c)) return; composite_done(c); @@ -162,6 +165,8 @@ static void bind_auth_next_step(struct composite_context *c) creq = dcerpc_alter_context_send(state->pipe, state, &state->pipe->syntax, &state->pipe->transfer_syntax); + data_blob_free(&state->credentials); + sec->auth_info->credentials = data_blob(NULL, 0); if (composite_nomem(creq, c)) return; composite_continue(c, creq, bind_auth_recv_alter, c); @@ -334,6 +339,8 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx, /* The first request always is a dcerpc_bind. The subsequent ones * depend on gensec results */ creq = dcerpc_bind_send(p, state, &syntax, &transfer_syntax); + data_blob_free(&state->credentials); + sec->auth_info->credentials = data_blob(NULL, 0); if (composite_nomem(creq, c)) return c; composite_continue(c, creq, bind_auth_recv_bindreply, c); diff --git a/source/rpc_server/dcerpc_server.c b/source/rpc_server/dcerpc_server.c index fa7b8d2..e5f59d0 100644 --- a/source/rpc_server/dcerpc_server.c +++ b/source/rpc_server/dcerpc_server.c @@ -951,13 +951,16 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call) request header size */ chunk_size = call->conn->cli_max_recv_frag; chunk_size -= DCERPC_REQUEST_LENGTH; - if (call->conn->auth_state.gensec_security) { - chunk_size -= DCERPC_AUTH_TRAILER_LENGTH; + if (call->conn->auth_state.auth_info && + call->conn->auth_state.gensec_security) { sig_size = gensec_sig_size(call->conn->auth_state.gensec_security, call->conn->cli_max_recv_frag); - chunk_size -= sig_size; - chunk_size -= (chunk_size % 16); + if (sig_size) { + chunk_size -= DCERPC_AUTH_TRAILER_LENGTH; + chunk_size -= sig_size; + } } + chunk_size -= (chunk_size % 16); do { uint32_t length; diff --git a/source/rpc_server/dcesrv_auth.c b/source/rpc_server/dcesrv_auth.c index 0aad377..16bf4eb 100644 --- a/source/rpc_server/dcesrv_auth.c +++ b/source/rpc_server/dcesrv_auth.c @@ -276,33 +276,6 @@ NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_pack } /* - 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 */ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet) @@ -320,6 +293,26 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet) return true; } + switch (dce_conn->auth_state.auth_info->auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + case DCERPC_AUTH_LEVEL_INTEGRITY: + break; + + case DCERPC_AUTH_LEVEL_CONNECT: + if (pkt->auth_length != 0) { + break; + } + return true; + case DCERPC_AUTH_LEVEL_NONE: + if (pkt->auth_length != 0) { + return false; + } + return true; + + default: + return false; + } + auth_blob.length = 8 + pkt->auth_length; /* check for a valid length */ @@ -374,7 +367,8 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet) break; case DCERPC_AUTH_LEVEL_CONNECT: - status = dcesrv_check_connect_verifier(&auth.credentials); + /* for now we ignore possible signatures here */ + status = NT_STATUS_OK; break; default: @@ -409,11 +403,32 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call, DATA_BLOB creds2; /* non-signed packets are simple */ - if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.gensec_security) { + if (sig_size == 0) { status = ncacn_push_auth(blob, call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx), pkt, NULL); return NT_STATUS_IS_OK(status); } + switch (dce_conn->auth_state.auth_info->auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + case DCERPC_AUTH_LEVEL_INTEGRITY: + break; + + case DCERPC_AUTH_LEVEL_CONNECT: + /* + * TODO: let the gensec mech decide if it wants to generate a signature + * that might be needed for schannel... + */ + status = ncacn_push_auth(blob, call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx), pkt, NULL); + return NT_STATUS_IS_OK(status); + + case DCERPC_AUTH_LEVEL_NONE: + status = ncacn_push_auth(blob, call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx), pkt, NULL); + return NT_STATUS_IS_OK(status); + + default: + return false; + } + ndr = ndr_push_init_ctx(call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx)); if (!ndr) { return false; @@ -429,26 +444,18 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call, } /* pad to 16 byte multiple, match win2k3 */ - dce_conn->auth_state.auth_info->auth_pad_length = NDR_ALIGN(ndr, 16); - ndr_push_zero(ndr, dce_conn->auth_state.auth_info->auth_pad_length); - - payload_length = ndr->offset - DCERPC_REQUEST_LENGTH; + dce_conn->auth_state.auth_info->auth_pad_length = + (16 - (pkt->u.response.stub_and_verifier.length & 15)) & 15; + ndr_err = ndr_push_zero(ndr, dce_conn->auth_state.auth_info->auth_pad_length); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return false; + } - 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 { + payload_length = pkt->u.response.stub_and_verifier.length + + dce_conn->auth_state.auth_info->auth_pad_length; - /* We hope this length is accruate. If must be if the - * GENSEC mech does AEAD signing of the packet - * headers */ - dce_conn->auth_state.auth_info->credentials - = data_blob_talloc(call, NULL, sig_size); - data_blob_clear(&dce_conn->auth_state.auth_info->credentials); - } + /* we start without signature, it will appended later */ + dce_conn->auth_state.auth_info->credentials = data_blob(NULL, 0); /* add the auth verifier */ ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, @@ -460,14 +467,14 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call, /* extract the whole packet as a blob */ *blob = ndr_push_blob(ndr); - /* fill in the fragment length and auth_length, we can't fill - in these earlier as we don't know the signature length (it - could be variable length) */ - dcerpc_set_frag_length(blob, blob->length); - - /* We hope this value is accruate. If must be if the GENSEC -- Samba Shared Repository