diff --git a/dlls/rpcrt4/rpc_message.c b/dlls/rpcrt4/rpc_message.c index dee69a0dedc..abc3d2fcf78 100644 --- a/dlls/rpcrt4/rpc_message.c +++ b/dlls/rpcrt4/rpc_message.c @@ -51,6 +51,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(rpc); (((alignment) - (((value) % (alignment)))) % (alignment)) #define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1)) +enum secure_packet_direction +{ + SECURE_PACKET_SEND, + SECURE_PACKET_RECEIVE +}; + static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg); static DWORD RPCRT4_GetHeaderSize(RpcPktHdr *Header) @@ -76,6 +82,19 @@ static DWORD RPCRT4_GetHeaderSize(RpcPktHdr *Header) return ret; } +static int packet_has_body(RpcPktHdr *Header) +{ + return (Header->common.ptype == PKT_FAULT) || + (Header->common.ptype == PKT_REQUEST) || + (Header->common.ptype == PKT_RESPONSE); +} + +static int packet_has_auth_verifier(RpcPktHdr *Header) +{ + return !(Header->common.ptype == PKT_BIND_NACK) && + !(Header->common.ptype == PKT_SHUTDOWN); +} + static VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType, unsigned long DataRepresentation) { @@ -264,6 +283,80 @@ VOID RPCRT4_FreeHeader(RpcPktHdr *Header) HeapFree(GetProcessHeap(), 0, Header); } +static RPC_STATUS RPCRT4_SecurePacket(RpcConnection *Connection, + enum secure_packet_direction dir, + RpcPktHdr *hdr, unsigned int hdr_size, + unsigned char *stub_data, unsigned int stub_data_size, + RpcAuthVerifier *auth_hdr, + unsigned char *auth_value, unsigned int auth_value_size) +{ + SecBufferDesc message; + SecBuffer buffers[4]; + SECURITY_STATUS sec_status; + + message.ulVersion = SECBUFFER_VERSION; + message.cBuffers = sizeof(buffers)/sizeof(buffers[0]); + message.pBuffers = buffers; + + buffers[0].cbBuffer = hdr_size; + buffers[0].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM; + buffers[0].pvBuffer = hdr; + buffers[1].cbBuffer = stub_data_size; + buffers[1].BufferType = SECBUFFER_DATA; + buffers[1].pvBuffer = stub_data; + buffers[2].cbBuffer = sizeof(*auth_hdr); + buffers[2].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM; + buffers[2].pvBuffer = auth_hdr; + buffers[3].cbBuffer = auth_value_size; + buffers[3].BufferType = SECBUFFER_TOKEN; + buffers[3].pvBuffer = auth_value; + + if (dir == SECURE_PACKET_SEND) + { + if ((auth_hdr->auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(hdr)) + { + sec_status = EncryptMessage(&Connection->ctx, 0, &message, 0 /* FIXME */); + if (sec_status != SEC_E_OK) + { + ERR("EncryptMessage failed with 0x%08x\n", sec_status); + return RPC_S_SEC_PKG_ERROR; + } + } + else if (auth_hdr->auth_level != RPC_C_AUTHN_LEVEL_NONE) + { + sec_status = MakeSignature(&Connection->ctx, 0, &message, 0 /* FIXME */); + if (sec_status != SEC_E_OK) + { + ERR("MakeSignature failed with 0x%08x\n", sec_status); + return RPC_S_SEC_PKG_ERROR; + } + } + } + else if (dir == SECURE_PACKET_RECEIVE) + { + if ((auth_hdr->auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(hdr)) + { + sec_status = DecryptMessage(&Connection->ctx, &message, 0 /* FIXME */, 0); + if (sec_status != SEC_E_OK) + { + ERR("EncryptMessage failed with 0x%08x\n", sec_status); + return RPC_S_SEC_PKG_ERROR; + } + } + else if (auth_hdr->auth_level != RPC_C_AUTHN_LEVEL_NONE) + { + sec_status = VerifySignature(&Connection->ctx, &message, 0 /* FIXME */, NULL); + if (sec_status != SEC_E_OK) + { + ERR("VerifySignature failed with 0x%08x\n", sec_status); + return RPC_S_SEC_PKG_ERROR; + } + } + } + + return RPC_S_OK; +} + /*********************************************************************** * RPCRT4_SendAuth (internal) * @@ -277,16 +370,25 @@ static RPC_STATUS RPCRT4_SendAuth(RpcConnection *Connection, RpcPktHdr *Header, DWORD hdr_size; LONG count; unsigned char *pkt; - LONG alen = AuthLength ? (AuthLength + sizeof(RpcAuthVerifier)) : 0; + LONG alen; + RPC_STATUS status; buffer_pos = Buffer; /* The packet building functions save the packet header size, so we can use it. */ hdr_size = Header->common.frag_len; - Header->common.auth_len = AuthLength; + if (AuthLength) + Header->common.auth_len = AuthLength; + else if (Connection->AuthInfo && packet_has_auth_verifier(Header)) + Header->common.auth_len = 16 /* FIXME */; + else + Header->common.auth_len = 0; Header->common.flags |= RPC_FLG_FIRST; Header->common.flags &= ~RPC_FLG_LAST; + + alen = RPC_AUTH_VERIFIER_LEN(&Header->common); + while (!(Header->common.flags & RPC_FLG_LAST)) { - unsigned char auth_pad_len = AuthLength ? ROUND_UP_AMOUNT(BufferLength, AUTH_ALIGNMENT) : 0; + unsigned char auth_pad_len = Header->common.auth_len ? ROUND_UP_AMOUNT(BufferLength, AUTH_ALIGNMENT) : 0; unsigned int pkt_size = BufferLength + hdr_size + alen + auth_pad_len; /* decide if we need to split the packet into fragments */ @@ -312,7 +414,7 @@ static RPC_STATUS RPCRT4_SendAuth(RpcConnection *Connection, RpcPktHdr *Header, memcpy(pkt + hdr_size, buffer_pos, Header->common.frag_len - hdr_size - auth_pad_len - alen); /* add the authorization info */ - if (Connection->AuthInfo && AuthLength) + if (Connection->AuthInfo && packet_has_auth_verifier(Header)) { RpcAuthVerifier *auth_hdr = (RpcAuthVerifier *)&pkt[Header->common.frag_len - alen]; @@ -323,7 +425,21 @@ static RPC_STATUS RPCRT4_SendAuth(RpcConnection *Connection, RpcPktHdr *Header, /* a unique number... */ auth_hdr->auth_context_id = (unsigned long)Connection; - memcpy(auth_hdr + 1, Auth, AuthLength); + if (AuthLength) + memcpy(auth_hdr + 1, Auth, AuthLength); + else + { + status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_SEND, + (RpcPktHdr *)pkt, hdr_size, + pkt + hdr_size, Header->common.frag_len - hdr_size - alen, + auth_hdr, + (unsigned char *)(auth_hdr + 1), Header->common.auth_len); + if (status != RPC_S_OK) + { + HeapFree(GetProcessHeap(), 0, pkt); + return status; + } + } } write: @@ -350,6 +466,13 @@ static void RPCRT4_AuthNegotiate(RpcConnection *conn, SecBuffer *out) SECURITY_STATUS r; SecBufferDesc out_desc; unsigned char *buffer; + ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE | + ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE; + + if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) + context_req |= ISC_REQ_INTEGRITY; + else if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) + context_req |= ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY; buffer = HeapAlloc(GetProcessHeap(), 0, 0x100); @@ -366,8 +489,7 @@ static void RPCRT4_AuthNegotiate(RpcConnection *conn, SecBuffer *out) conn->ctx.dwUpper = 0; r = InitializeSecurityContextA(&conn->AuthInfo->cred, NULL, NULL, - ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE | ISC_REQ_MUTUAL_AUTH | - ISC_REQ_DELEGATE, 0, SECURITY_NETWORK_DREP, + context_req, 0, SECURITY_NETWORK_DREP, NULL, 0, &conn->ctx, &out_desc, &conn->attr, &conn->exp); TRACE("r = %08x cbBuffer = %ld attr = %08x\n", r, out->cbBuffer, conn->attr); @@ -385,9 +507,16 @@ static RPC_STATUS RPCRT_AuthorizeConnection(RpcConnection* conn, unsigned char buffer[0x100]; RpcPktHdr *resp_hdr; RPC_STATUS status; + ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE | + ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE; TRACE("challenge %s, %d bytes\n", challenge, count); + if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) + context_req |= ISC_REQ_INTEGRITY; + else if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) + context_req |= ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY; + out.BufferType = SECBUFFER_TOKEN; out.cbBuffer = sizeof buffer; out.pvBuffer = buffer; @@ -405,8 +534,7 @@ static RPC_STATUS RPCRT_AuthorizeConnection(RpcConnection* conn, inp_desc.ulVersion = 0; r = InitializeSecurityContextA(&conn->AuthInfo->cred, &conn->ctx, NULL, - ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE | ISC_REQ_MUTUAL_AUTH | - ISC_REQ_DELEGATE, 0, SECURITY_NETWORK_DREP, + context_req, 0, SECURITY_NETWORK_DREP, &inp_desc, 0, &conn->ctx, &out_desc, &conn->attr, &conn->exp); if (r) { @@ -436,20 +564,10 @@ RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, RPC_STATUS r; SecBuffer out; - /* if we've already authenticated, just send the context */ - if (Connection->ctx.dwUpper || Connection->ctx.dwLower) - { - unsigned char buffer[0x10]; - - memset(buffer, 0, sizeof buffer); - buffer[0] = 1; /* version number lsb */ - - return RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, buffer, sizeof buffer); - } - if (!Connection->AuthInfo || Connection->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_DEFAULT || - Connection->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_NONE) + Connection->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_NONE || + (Connection->ctx.dwUpper || Connection->ctx.dwLower)) { return RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, NULL, 0); } @@ -595,6 +713,12 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, } if (header_auth_len) { + if (header_auth_len < sizeof(RpcAuthVerifier)) { + WARN("bad auth verifier length %d\n", header_auth_len); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + /* FIXME: we should accumulate authentication data for the bind, * bind_ack, alter_context and alter_context_response if necessary. * however, the details of how this is done is very sketchy in the @@ -607,6 +731,18 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, status = RPC_S_PROTOCOL_ERROR; goto fail; } + + /* these packets are handled specially, not by the generic SecurePacket + * function */ + if ((common_hdr.ptype != PKT_BIND) && + (common_hdr.ptype != PKT_BIND_ACK) && + (common_hdr.ptype != PKT_AUTH3)) + status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_RECEIVE, + *Header, hdr_length, + (unsigned char *)pMsg->Buffer + buffer_length, data_length, + (RpcAuthVerifier *)auth_data, + (unsigned char *)auth_data + sizeof(RpcAuthVerifier), + header_auth_len - sizeof(RpcAuthVerifier)); } buffer_length += data_length;