diff options
Diffstat (limited to 'source4/librpc')
-rw-r--r-- | source4/librpc/rpc/dcerpc.c | 126 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc.h | 5 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_auth.c | 8 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_schannel.c | 7 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_smb.c | 5 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_tcp.c | 21 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_util.c | 17 |
7 files changed, 109 insertions, 80 deletions
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 0595d5eade..c2f691aa09 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -36,6 +36,7 @@ struct dcerpc_pipe *dcerpc_pipe_init(void) p->reference_count = 0; p->call_id = 1; p->security_state.auth_info = NULL; + p->security_state.session_key = dcerpc_generic_session_key; p->security_state.generic_state = NULL; p->binding_string = NULL; p->flags = 0; @@ -206,8 +207,8 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, if (!NT_STATUS_IS_OK(status)) { return status; } - - + + /* check signature or unseal the packet */ switch (p->security_state.auth_info->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: @@ -215,6 +216,8 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, mem_ctx, pkt->u.response.stub_and_verifier.data, pkt->u.response.stub_and_verifier.length, + blob->data, + blob->length - auth.credentials.length, &auth.credentials); break; @@ -223,9 +226,11 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, mem_ctx, pkt->u.response.stub_and_verifier.data, pkt->u.response.stub_and_verifier.length, + blob->data, + blob->length - auth.credentials.length, &auth.credentials); break; - + case DCERPC_AUTH_LEVEL_NONE: break; @@ -233,7 +238,7 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, status = NT_STATUS_INVALID_LEVEL; break; } - + /* remove the indicated amount of paddiing */ if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) { return NT_STATUS_INFO_LENGTH_MISMATCH; @@ -253,6 +258,7 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, { NTSTATUS status; struct ndr_push *ndr; + DATA_BLOB creds2; /* non-signed packets are simpler */ if (!p->security_state.auth_info || !p->security_state.generic_state) { @@ -282,30 +288,21 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, /* sign or seal the packet */ switch (p->security_state.auth_info->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: - status = gensec_seal_packet(p->security_state.generic_state, - mem_ctx, - ndr->data + DCERPC_REQUEST_LENGTH, - ndr->offset - DCERPC_REQUEST_LENGTH, - &p->security_state.auth_info->credentials); - break; - case DCERPC_AUTH_LEVEL_INTEGRITY: - status = gensec_sign_packet(p->security_state.generic_state, - mem_ctx, - ndr->data + DCERPC_REQUEST_LENGTH, - ndr->offset - DCERPC_REQUEST_LENGTH, - &p->security_state.auth_info->credentials); + p->security_state.auth_info->credentials + = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state)); + data_blob_clear(&p->security_state.auth_info->credentials); break; case DCERPC_AUTH_LEVEL_NONE: p->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; } @@ -325,6 +322,41 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, dcerpc_set_frag_length(blob, blob->length); dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length); + /* sign or seal the packet */ + switch (p->security_state.auth_info->auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + status = gensec_seal_packet(p->security_state.generic_state, + mem_ctx, + ndr->data + DCERPC_REQUEST_LENGTH, + ndr->offset - DCERPC_REQUEST_LENGTH, + blob->data, + blob->length - + p->security_state.auth_info->credentials.length, + &creds2); + memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length); + break; + + case DCERPC_AUTH_LEVEL_INTEGRITY: + status = gensec_sign_packet(p->security_state.generic_state, + mem_ctx, + ndr->data + DCERPC_REQUEST_LENGTH, + ndr->offset - DCERPC_REQUEST_LENGTH, + blob->data, + blob->length - + p->security_state.auth_info->credentials.length, + &creds2); + memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length); + break; + + case DCERPC_AUTH_LEVEL_NONE: + p->security_state.auth_info->credentials = data_blob(NULL, 0); + break; + + default: + status = NT_STATUS_INVALID_LEVEL; + break; + } + data_blob_free(&p->security_state.auth_info->credentials); return NT_STATUS_OK; @@ -433,8 +465,8 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, pkt.call_id = p->call_id; pkt.auth_length = 0; - pkt.u.bind.max_xmit_frag = 0x2000; - pkt.u.bind.max_recv_frag = 0x2000; + pkt.u.bind.max_xmit_frag = 5840; + pkt.u.bind.max_recv_frag = 5840; pkt.u.bind.assoc_group_id = 0; pkt.u.bind.num_contexts = 1; pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0])); @@ -782,60 +814,44 @@ struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, pkt.u.request.context_id = 0; pkt.u.request.opnum = opnum; - /* we send a series of pdus without waiting for a reply until - the last pdu */ - while (remaining > chunk_size) { + DLIST_ADD(p->pending, req); + + /* we send a series of pdus without waiting for a reply */ + while (remaining > 0) { + uint32_t chunk = MIN(chunk_size, remaining); + BOOL last_frag = False; + + pkt.pfc_flags = 0; + if (remaining == stub_data->length) { - pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST; - } else { - pkt.pfc_flags = 0; + pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST; + } + if (chunk == remaining) { + pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST; + last_frag = True; } pkt.u.request.stub_and_verifier.data = stub_data->data + (stub_data->length - remaining); - pkt.u.request.stub_and_verifier.length = chunk_size; + pkt.u.request.stub_and_verifier.length = chunk; req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt); if (!NT_STATUS_IS_OK(req->status)) { req->state = RPC_REQUEST_DONE; + DLIST_REMOVE(p->pending, req); return req; } - req->status = p->transport.send_request(p, &blob, False); + req->status = p->transport.send_request(p, &blob, last_frag); if (!NT_STATUS_IS_OK(req->status)) { req->state = RPC_REQUEST_DONE; + DLIST_REMOVE(p->pending, req); return req; } - remaining -= chunk_size; - } - - /* now we send a pdu with LAST_FRAG sent and get the first - part of the reply */ - if (remaining == stub_data->length) { - pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; - } else { - pkt.pfc_flags = DCERPC_PFC_FLAG_LAST; - } - pkt.u.request.stub_and_verifier.data = stub_data->data + - (stub_data->length - remaining); - pkt.u.request.stub_and_verifier.length = remaining; - - req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt); - if (!NT_STATUS_IS_OK(req->status)) { - req->state = RPC_REQUEST_DONE; - return req; - } - - /* send the final pdu */ - req->status = p->transport.send_request(p, &blob, True); - - if (!NT_STATUS_IS_OK(req->status)) { - req->state = RPC_REQUEST_DONE; + remaining -= chunk; } - DLIST_ADD(p->pending, req); - return req; } diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h index 16bf52cec2..242a18368f 100644 --- a/source4/librpc/rpc/dcerpc.h +++ b/source4/librpc/rpc/dcerpc.h @@ -29,6 +29,9 @@ struct dcerpc_pipe; struct dcerpc_security { struct dcerpc_auth *auth_info; struct gensec_security *generic_state; + + /* get the session key */ + NTSTATUS (*session_key)(struct dcerpc_pipe *, DATA_BLOB *); }; struct dcerpc_pipe { @@ -64,8 +67,6 @@ struct dcerpc_pipe { has been received */ void (*recv_data)(struct dcerpc_pipe *, DATA_BLOB *, NTSTATUS status); - /* get the transport level session key */ - NTSTATUS (*session_key)(struct dcerpc_pipe *, DATA_BLOB *); } transport; /* the last fault code from a DCERPC fault */ diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c index 9587fb9390..0966b70338 100644 --- a/source4/librpc/rpc/dcerpc_auth.c +++ b/source4/librpc/rpc/dcerpc_auth.c @@ -107,13 +107,16 @@ NTSTATUS dcerpc_bind_auth3(struct dcerpc_pipe *p, uint8_t auth_type, uint8_t aut } p->security_state.auth_info->credentials = credentials; - + status = dcerpc_auth3(p, mem_ctx); done: talloc_destroy(mem_ctx); if (!NT_STATUS_IS_OK(status)) { ZERO_STRUCT(p->security_state); + } else { + /* Authenticated connections use the generic session key */ + p->security_state.session_key = dcerpc_generic_session_key; } return status; @@ -196,6 +199,9 @@ done: if (!NT_STATUS_IS_OK(status)) { ZERO_STRUCT(p->security_state); + } else { + /* Authenticated connections use the generic session key */ + p->security_state.session_key = dcerpc_generic_session_key; } return status; diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c index efe609f9a3..9aa2b0c88d 100644 --- a/source4/librpc/rpc/dcerpc_schannel.c +++ b/source4/librpc/rpc/dcerpc_schannel.c @@ -50,7 +50,9 @@ static NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p, */ static NTSTATUS dcerpc_schannel_unseal_packet(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, - uint8_t *data, size_t length, DATA_BLOB *sig) + uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + DATA_BLOB *sig) { struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; @@ -60,6 +62,7 @@ static NTSTATUS dcerpc_schannel_unseal_packet(struct gensec_security *gensec_sec static NTSTATUS dcerpc_schannel_check_packet(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, const uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, const DATA_BLOB *sig) { struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; @@ -70,6 +73,7 @@ static NTSTATUS dcerpc_schannel_check_packet(struct gensec_security *gensec_secu static NTSTATUS dcerpc_schannel_seal_packet(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, DATA_BLOB *sig) { struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; @@ -80,6 +84,7 @@ static NTSTATUS dcerpc_schannel_seal_packet(struct gensec_security *gensec_secur static NTSTATUS dcerpc_schannel_sign_packet(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, const uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, DATA_BLOB *sig) { struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data; diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c index fa9101bbd6..eece07c678 100644 --- a/source4/librpc/rpc/dcerpc_smb.c +++ b/source4/librpc/rpc/dcerpc_smb.c @@ -359,7 +359,6 @@ NTSTATUS smb_session_key(struct dcerpc_pipe *p, DATA_BLOB *session_key) *session_key = smb->tree->session->user_session_key; return NT_STATUS_OK; } - return NT_STATUS_NO_USER_SESSION_KEY; } @@ -425,13 +424,15 @@ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe **p, (*p)->transport.private = NULL; (*p)->transport.shutdown_pipe = smb_shutdown_pipe; (*p)->transport.peer_name = smb_peer_name; - (*p)->transport.session_key = smb_session_key; (*p)->transport.send_request = smb_send_request; (*p)->transport.send_read = send_read_request; (*p)->transport.event_context = smb_event_context; (*p)->transport.recv_data = NULL; + /* Over-ride the default session key with the SMB session key */ + (*p)->security_state.session_key = smb_session_key; + smb = talloc((*p), sizeof(*smb)); if (!smb) { dcerpc_pipe_close(*p); diff --git a/source4/librpc/rpc/dcerpc_tcp.c b/source4/librpc/rpc/dcerpc_tcp.c index c290891b61..2152c4c5d0 100644 --- a/source4/librpc/rpc/dcerpc_tcp.c +++ b/source4/librpc/rpc/dcerpc_tcp.c @@ -87,6 +87,10 @@ static void tcp_process_send(struct dcerpc_pipe *p) } break; } + if (ret == 0) { + tcp_sock_dead(p, NT_STATUS_NET_WRITE_FAULT); + break; + } blob->data.data += ret; blob->data.length -= ret; @@ -271,19 +275,6 @@ static const char *tcp_peer_name(struct dcerpc_pipe *p) return tcp->server_name; } - -/* - fetch the user session key -*/ -NTSTATUS tcp_session_key(struct dcerpc_pipe *p, DATA_BLOB *session_key) -{ - /* this took quite a few CPU cycles to find ... */ - session_key->data = "SystemLibraryDTC"; - session_key->length = 16; - - return NT_STATUS_OK; -} - /* open a rpc connection to a named pipe */ @@ -331,7 +322,6 @@ NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, (*p)->transport.shutdown_pipe = tcp_shutdown_pipe; (*p)->transport.peer_name = tcp_peer_name; - (*p)->transport.session_key = tcp_session_key; tcp = talloc((*p), sizeof(*tcp)); if (!tcp) { @@ -356,5 +346,8 @@ NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, (*p)->transport.private = tcp; + /* ensure we don't get SIGPIPE */ + BlockSignals(True,SIGPIPE); + return NT_STATUS_OK; } diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index fc9f6c847d..1898575003 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -458,8 +458,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p, pipe_name += 6; } - if ((binding->flags & (DCERPC_SCHANNEL_ANY | DCERPC_SIGN | DCERPC_SEAL)) - || !username || !username[0]) { + if (!username || !username[0]) { status = smbcli_full_connection(&cli, lp_netbios_name(), binding->host, NULL, "ipc$", "?????", @@ -500,6 +499,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p, status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password); } else { status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version); + } if (!NT_STATUS_IS_OK(status)) { @@ -691,15 +691,22 @@ NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe * return NT_STATUS_OK; } +NTSTATUS dcerpc_generic_session_key(struct dcerpc_pipe *p, + DATA_BLOB *session_key) +{ + /* this took quite a few CPU cycles to find ... */ + session_key->data = "SystemLibraryDTC"; + session_key->length = 16; + return NT_STATUS_OK; +} /* - fetch the user session key for the underlying transport. Currently - only works for the ncacn_np transport + fetch the user session key - may be default (above) or the SMB session key */ NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p, DATA_BLOB *session_key) { - return p->transport.session_key(p, session_key); + return p->security_state.session_key(p, session_key); } |