From e27e61db71e8f0279e3cbc09e32d8f85acde3159 Mon Sep 17 00:00:00 2001 From: Rob Shearman Date: Sun, 13 Dec 2009 21:35:39 +0000 Subject: [PATCH] rpcrt4: Add support for server-side authentication. --- dlls/rpcrt4/rpc_assoc.c | 6 +- dlls/rpcrt4/rpc_binding.c | 10 +- dlls/rpcrt4/rpc_binding.h | 1 + dlls/rpcrt4/rpc_message.c | 205 ++++++++++++++++++++----- dlls/rpcrt4/rpc_message.h | 4 + dlls/rpcrt4/rpc_server.c | 307 +++++++++++++++++++++++++------------- 6 files changed, 383 insertions(+), 150 deletions(-) diff --git a/dlls/rpcrt4/rpc_assoc.c b/dlls/rpcrt4/rpc_assoc.c index a74e66088bd..8364a9a4f36 100644 --- a/dlls/rpcrt4/rpc_assoc.c +++ b/dlls/rpcrt4/rpc_assoc.c @@ -273,9 +273,9 @@ static RPC_STATUS RpcAssoc_BindConnection(const RpcAssoc *assoc, RpcConnection * case RESULT_ACCEPT: /* respond to authorization request */ if (auth_length > sizeof(RpcAuthVerifier)) - status = RPCRT4_AuthorizeConnection(conn, - auth_data + sizeof(RpcAuthVerifier), - auth_length); + status = RPCRT4_ClientConnectionAuth(conn, + auth_data + sizeof(RpcAuthVerifier), + auth_length); if (status == RPC_S_OK) { conn->assoc_group_id = response_hdr->bind_ack.assoc_gid; diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c index 212e201dbbb..a4dff4a7fa8 100644 --- a/dlls/rpcrt4/rpc_binding.c +++ b/dlls/rpcrt4/rpc_binding.c @@ -1094,11 +1094,11 @@ static inline BOOL has_nt_auth_identity(ULONG AuthnLevel) } } -static RPC_STATUS RpcAuthInfo_Create(ULONG AuthnLevel, ULONG AuthnSvc, - CredHandle cred, TimeStamp exp, - ULONG cbMaxToken, - RPC_AUTH_IDENTITY_HANDLE identity, - RpcAuthInfo **ret) +RPC_STATUS RpcAuthInfo_Create(ULONG AuthnLevel, ULONG AuthnSvc, + CredHandle cred, TimeStamp exp, + ULONG cbMaxToken, + RPC_AUTH_IDENTITY_HANDLE identity, + RpcAuthInfo **ret) { RpcAuthInfo *AuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*AuthInfo)); if (!AuthInfo) diff --git a/dlls/rpcrt4/rpc_binding.h b/dlls/rpcrt4/rpc_binding.h index 036b59a5567..0681b403a05 100644 --- a/dlls/rpcrt4/rpc_binding.h +++ b/dlls/rpcrt4/rpc_binding.h @@ -132,6 +132,7 @@ void RPCRT4_strfree(LPSTR src); #define RPCRT4_strdupA(x) RPCRT4_strndupA((x),-1) #define RPCRT4_strdupW(x) RPCRT4_strndupW((x),-1) +RPC_STATUS RpcAuthInfo_Create(ULONG AuthnLevel, ULONG AuthnSvc, CredHandle cred, TimeStamp exp, ULONG cbMaxToken, RPC_AUTH_IDENTITY_HANDLE identity, RpcAuthInfo **ret); ULONG RpcAuthInfo_AddRef(RpcAuthInfo *AuthInfo); ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo); BOOL RpcAuthInfo_IsEqual(const RpcAuthInfo *AuthInfo1, const RpcAuthInfo *AuthInfo2); diff --git a/dlls/rpcrt4/rpc_message.c b/dlls/rpcrt4/rpc_message.c index 535d1732909..bb1e79c432b 100644 --- a/dlls/rpcrt4/rpc_message.c +++ b/dlls/rpcrt4/rpc_message.c @@ -65,14 +65,14 @@ DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header) sizeof(Header->request), 0, sizeof(Header->response), sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind), sizeof(Header->bind_ack), sizeof(Header->bind_nack), - 0, 0, 0, 0, 0, 0, sizeof(Header->http) + 0, 0, sizeof(Header->common), 0, 0, 0, sizeof(Header->http) }; ULONG ret = 0; if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) { ret = header_sizes[Header->common.ptype]; if (ret == 0) - FIXME("unhandled packet type\n"); + FIXME("unhandled packet type %u\n", Header->common.ptype); if (Header->common.flags & RPC_FLG_OBJECT_UUID) ret += sizeof(UUID); } else { @@ -95,6 +95,21 @@ static int packet_has_auth_verifier(const RpcPktHdr *Header) !(Header->common.ptype == PKT_SHUTDOWN); } +static int packet_does_auth_negotiation(const RpcPktHdr *Header) +{ + switch (Header->common.ptype) + { + case PKT_BIND: + case PKT_BIND_ACK: + case PKT_AUTH3: + case PKT_ALTER_CONTEXT: + case PKT_ALTER_CONTEXT_RESP: + return TRUE; + default: + return FALSE; + } +} + static VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType, ULONG DataRepresentation) { @@ -208,13 +223,12 @@ static RpcPktHdr *RPCRT4_BuildAuthHeader(ULONG DataRepresentation) RpcPktHdr *header; header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(header->common) + 12); + sizeof(header->common)); if (header == NULL) return NULL; RPCRT4_BuildCommonHeader(header, PKT_AUTH3, DataRepresentation); - header->common.frag_len = 0x14; - header->common.auth_len = 0; + header->common.frag_len = sizeof(header->common); return header; } @@ -749,9 +763,9 @@ static RPC_STATUS RPCRT4_SecurePacket(RpcConnection *Connection, * * Transmit a packet with authorization data over connection in acceptable fragments. */ -static RPC_STATUS RPCRT4_SendWithAuth(RpcConnection *Connection, RpcPktHdr *Header, - void *Buffer, unsigned int BufferLength, - const void *Auth, unsigned int AuthLength) +RPC_STATUS RPCRT4_SendWithAuth(RpcConnection *Connection, RpcPktHdr *Header, + void *Buffer, unsigned int BufferLength, + const void *Auth, unsigned int AuthLength) { PUCHAR buffer_pos; DWORD hdr_size; @@ -808,7 +822,7 @@ static RPC_STATUS RPCRT4_SendWithAuth(RpcConnection *Connection, RpcPktHdr *Head memcpy(pkt + hdr_size, buffer_pos, Header->common.frag_len - hdr_size - auth_pad_len - alen); /* add the authorization info */ - if (Connection->AuthInfo && packet_has_auth_verifier(Header)) + if (Header->common.auth_len) { RpcAuthVerifier *auth_hdr = (RpcAuthVerifier *)&pkt[Header->common.frag_len - alen]; @@ -856,25 +870,19 @@ write: } /*********************************************************************** - * RPCRT4_ClientAuthorize (internal) + * RPCRT4_Authorize (internal) * - * Authorize a client connection. A NULL in param signifies a new connection. + * Authorize a client connection. */ -static RPC_STATUS RPCRT4_ClientAuthorize(RpcConnection *conn, SecBuffer *in, - SecBuffer *out) +static RPC_STATUS RPCRT4_Authorize(RpcConnection *conn, BOOL first_time, + SecBuffer *in, SecBuffer *out) { SECURITY_STATUS r; SecBufferDesc out_desc; SecBufferDesc inp_desc; SecPkgContext_Sizes secctx_sizes; BOOL continue_needed; - 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; + ULONG context_req; out->BufferType = SECBUFFER_TOKEN; out->cbBuffer = conn->AuthInfo->cbMaxToken; @@ -889,10 +897,45 @@ static RPC_STATUS RPCRT4_ClientAuthorize(RpcConnection *conn, SecBuffer *in, inp_desc.pBuffers = in; inp_desc.ulVersion = 0; - r = InitializeSecurityContextW(&conn->AuthInfo->cred, in ? &conn->ctx : NULL, - in ? NULL : conn->AuthInfo->server_principal_name, context_req, 0, - SECURITY_NETWORK_DREP, in ? &inp_desc : NULL, 0, &conn->ctx, - &out_desc, &conn->attr, &conn->exp); + if (conn->server) + { + context_req = ASC_REQ_CONNECTION | ASC_REQ_USE_DCE_STYLE | + ASC_REQ_DELEGATE; + + if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) + context_req |= ASC_REQ_INTEGRITY; + else if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) + context_req |= ASC_REQ_CONFIDENTIALITY | ASC_REQ_INTEGRITY; + + r = AcceptSecurityContext(&conn->AuthInfo->cred, + first_time ? NULL : &conn->ctx, + &inp_desc, context_req, SECURITY_NETWORK_DREP, + &conn->ctx, + &out_desc, &conn->attr, &conn->exp); + if (r == SEC_E_OK || r == SEC_I_COMPLETE_NEEDED) + { + /* authorisation done, so nothing more to send */ + HeapFree(GetProcessHeap(), 0, out->pvBuffer); + out->cbBuffer = 0; + } + } + else + { + 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; + + r = InitializeSecurityContextW(&conn->AuthInfo->cred, + first_time ? NULL: &conn->ctx, + first_time ? conn->AuthInfo->server_principal_name : NULL, + context_req, 0, SECURITY_NETWORK_DREP, + in ? &inp_desc : NULL, 0, &conn->ctx, + &out_desc, &conn->attr, &conn->exp); + } if (FAILED(r)) { WARN("InitializeSecurityContext failed with error 0x%08x\n", r); @@ -937,10 +980,10 @@ failed: } /*********************************************************************** - * RPCRT4_AuthorizeBinding (internal) + * RPCRT4_ClientConnectionAuth (internal) */ -RPC_STATUS RPCRT4_AuthorizeConnection(RpcConnection* conn, BYTE *challenge, - ULONG count) +RPC_STATUS RPCRT4_ClientConnectionAuth(RpcConnection* conn, BYTE *challenge, + ULONG count) { SecBuffer inp, out; RpcPktHdr *resp_hdr; @@ -952,7 +995,7 @@ RPC_STATUS RPCRT4_AuthorizeConnection(RpcConnection* conn, BYTE *challenge, inp.pvBuffer = challenge; inp.cbBuffer = count; - status = RPCRT4_ClientAuthorize(conn, &inp, &out); + status = RPCRT4_Authorize(conn, FALSE, &inp, &out); if (status) return status; resp_hdr = RPCRT4_BuildAuthHeader(NDR_LOCAL_DATA_REPRESENTATION); @@ -967,6 +1010,87 @@ RPC_STATUS RPCRT4_AuthorizeConnection(RpcConnection* conn, BYTE *challenge, return status; } +/*********************************************************************** + * RPCRT4_ServerConnectionAuth (internal) + */ +RPC_STATUS RPCRT4_ServerConnectionAuth(RpcConnection* conn, + BOOL start, + RpcAuthVerifier *auth_data_in, + ULONG auth_length_in, + unsigned char **auth_data_out, + ULONG *auth_length_out) +{ + SecBuffer inp, out; + RPC_STATUS status; + + if (start) + { + /* remove any existing authentication information */ + if (conn->AuthInfo) + { + RpcAuthInfo_Release(conn->AuthInfo); + conn->AuthInfo = NULL; + } + if (SecIsValidHandle(&conn->ctx)) + { + DeleteSecurityContext(&conn->ctx); + SecInvalidateHandle(&conn->ctx); + } + if (auth_length_in >= sizeof(RpcAuthVerifier)) + { + CredHandle cred; + TimeStamp exp; + ULONG max_token; + + status = RPCRT4_ServerGetRegisteredAuthInfo( + auth_data_in->auth_type, &cred, &exp, &max_token); + if (status != RPC_S_OK) + { + ERR("unknown authentication service %u\n", auth_data_in->auth_type); + return status; + } + + status = RpcAuthInfo_Create(auth_data_in->auth_level, + auth_data_in->auth_type, cred, exp, + max_token, NULL, &conn->AuthInfo); + if (status != RPC_S_OK) + return status; + + /* FIXME: should auth_data_in->auth_context_id be checked in the !start case? */ + conn->auth_context_id = auth_data_in->auth_context_id; + } + } + + if (auth_length_in < sizeof(RpcAuthVerifier)) + return RPC_S_OK; + + if (!conn->AuthInfo) + /* should have filled in authentication info by now */ + return RPC_S_PROTOCOL_ERROR; + + inp.BufferType = SECBUFFER_TOKEN; + inp.pvBuffer = auth_data_in + 1; + inp.cbBuffer = auth_length_in - sizeof(RpcAuthVerifier); + + status = RPCRT4_Authorize(conn, start, &inp, &out); + if (status) return status; + + if (out.cbBuffer && !auth_length_out) + { + ERR("expected authentication to be complete but SSP returned data of " + "%u bytes to be sent back to client\n", out.cbBuffer); + HeapFree(GetProcessHeap(), 0, out.pvBuffer); + return RPC_S_SEC_PKG_ERROR; + } + else + { + *auth_data_out = out.pvBuffer; + *auth_length_out = out.cbBuffer; + } + + return status; +} + /*********************************************************************** * RPCRT4_Send (internal) * @@ -978,18 +1102,19 @@ RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, RPC_STATUS r; SecBuffer out; - if (!Connection->AuthInfo || SecIsValidHandle(&Connection->ctx)) + if (packet_does_auth_negotiation(Header) && + Connection->AuthInfo && !SecIsValidHandle(&Connection->ctx)) { - return RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, NULL, 0); - } - - /* tack on a negotiate packet */ - r = RPCRT4_ClientAuthorize(Connection, NULL, &out); - if (r == RPC_S_OK) - { - r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, out.pvBuffer, out.cbBuffer); - HeapFree(GetProcessHeap(), 0, out.pvBuffer); + /* tack on a negotiate packet */ + r = RPCRT4_Authorize(Connection, TRUE, NULL, &out); + if (r == RPC_S_OK) + { + r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, out.pvBuffer, out.cbBuffer); + HeapFree(GetProcessHeap(), 0, out.pvBuffer); + } } + else + r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, NULL, 0); return r; } @@ -1133,6 +1258,8 @@ RPC_STATUS RPCRT4_ReceiveWithAuth(RpcConnection *Connection, RpcPktHdr **Header, *Header = NULL; pMsg->Buffer = NULL; + if (auth_data_out) *auth_data_out = NULL; + if (auth_length_out) *auth_length_out = 0; TRACE("(%p, %p, %p, %p)\n", Connection, Header, pMsg, auth_data_out); @@ -1230,7 +1357,7 @@ RPC_STATUS RPCRT4_ReceiveWithAuth(RpcConnection *Connection, RpcPktHdr **Header, /* these packets are handled specially, not by the generic SecurePacket * function */ - if (!auth_data_out && SecIsValidHandle(&Connection->ctx)) + if (!packet_does_auth_negotiation(*Header) && SecIsValidHandle(&Connection->ctx)) { status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_RECEIVE, CurrentHeader, hdr_length, diff --git a/dlls/rpcrt4/rpc_message.h b/dlls/rpcrt4/rpc_message.h index dd62f2dfb69..896bd95f92c 100644 --- a/dlls/rpcrt4/rpc_message.h +++ b/dlls/rpcrt4/rpc_message.h @@ -35,6 +35,7 @@ RpcPktHdr *RPCRT4_BuildHttpConnectHeader(unsigned short flags, int out_pipe, con RpcPktHdr *RPCRT4_BuildHttpFlowControlHeader(BOOL server, ULONG bytes_transmitted, ULONG flow_control_increment, const UUID *pipe_uuid); VOID RPCRT4_FreeHeader(RpcPktHdr *Header); RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, void *Buffer, unsigned int BufferLength); +RPC_STATUS RPCRT4_SendWithAuth(RpcConnection *Connection, RpcPktHdr *Header, void *Buffer, unsigned int BufferLength, const void *Auth, unsigned int AuthLength); RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, PRPC_MESSAGE pMsg); RPC_STATUS RPCRT4_ReceiveWithAuth(RpcConnection *Connection, RpcPktHdr **Header, PRPC_MESSAGE pMsg, unsigned char **auth_data_out, ULONG *auth_length_out); DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header); @@ -45,6 +46,9 @@ RPC_STATUS RPCRT4_ParseHttpPrepareHeader1(RpcPktHdr *header, unsigned char *data RPC_STATUS RPCRT4_ParseHttpPrepareHeader2(RpcPktHdr *header, unsigned char *data, ULONG *field1, ULONG *bytes_until_next_packet, ULONG *field3); RPC_STATUS RPCRT4_ParseHttpFlowControlHeader(RpcPktHdr *header, unsigned char *data, BOOL server, ULONG *bytes_transmitted, ULONG *flow_control_increment, UUID *pipe_uuid); NCA_STATUS RPC2NCA_STATUS(RPC_STATUS status); +RPC_STATUS RPCRT4_ClientConnectionAuth(RpcConnection* conn, BYTE *challenge, ULONG count); +RPC_STATUS RPCRT4_ServerConnectionAuth(RpcConnection* conn, BOOL start, RpcAuthVerifier *auth_data_in, ULONG auth_length_in, unsigned char **auth_data_out, ULONG *auth_length_out); RPC_STATUS RPCRT4_AuthorizeConnection(RpcConnection* conn, BYTE *challenge, ULONG count); +RPC_STATUS RPCRT4_ServerGetRegisteredAuthInfo(USHORT auth_type, CredHandle *cred, TimeStamp *exp, ULONG *max_token); #endif diff --git a/dlls/rpcrt4/rpc_server.c b/dlls/rpcrt4/rpc_server.c index 4778a5eb403..55d97836e69 100644 --- a/dlls/rpcrt4/rpc_server.c +++ b/dlls/rpcrt4/rpc_server.c @@ -52,6 +52,8 @@ typedef struct _RpcPacket struct _RpcConnection* conn; RpcPktHdr* hdr; RPC_MESSAGE* msg; + unsigned char *auth_data; + ULONG auth_length; } RpcPacket; typedef struct _RpcObjTypeMap @@ -168,13 +170,50 @@ static void RPCRT4_release_server_interface(RpcServerInterface *sif) } } -static RPC_STATUS process_bind_packet(RpcConnection *conn, RpcPktBindHdr *hdr, RPC_MESSAGE *msg) +static RpcPktHdr *handle_bind_error(RpcConnection *conn, RPC_STATUS error) +{ + unsigned int reject_reason; + switch (error) + { + case RPC_S_SERVER_TOO_BUSY: + reject_reason = REJECT_TEMPORARY_CONGESTION; + break; + case ERROR_OUTOFMEMORY: + case RPC_S_OUT_OF_RESOURCES: + reject_reason = REJECT_LOCAL_LIMIT_EXCEEDED; + break; + case RPC_S_PROTOCOL_ERROR: + reject_reason = REJECT_PROTOCOL_VERSION_NOT_SUPPORTED; + break; + case RPC_S_UNKNOWN_AUTHN_SERVICE: + reject_reason = REJECT_UNKNOWN_AUTHN_SERVICE; + break; + case ERROR_ACCESS_DENIED: + reject_reason = REJECT_INVALID_CHECKSUM; + break; + default: + FIXME("unexpected status value %d\n", error); + /* fall through */ + case RPC_S_INVALID_BOUND: + reject_reason = REJECT_REASON_NOT_SPECIFIED; + break; + } + return RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_VER_MAJOR, RPC_VER_MINOR, + reject_reason); +} + +static RPC_STATUS process_bind_packet_no_send( + RpcConnection *conn, RpcPktBindHdr *hdr, RPC_MESSAGE *msg, + unsigned char *auth_data, ULONG auth_length, RpcPktHdr **ack_response, + unsigned char **auth_data_out, ULONG *auth_length_out) { RPC_STATUS status; - RpcPktHdr *response; RpcContextElement *ctxt_elem; unsigned int i; + RpcResult *results; + /* validate data */ for (i = 0, ctxt_elem = msg->Buffer; i < hdr->num_elements; i++, ctxt_elem = (RpcContextElement *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes]) @@ -184,11 +223,7 @@ static RPC_STATUS process_bind_packet(RpcConnection *conn, RpcPktBindHdr *hdr, R { ERR("inconsistent data in packet - packet length %d, num elements %d\n", msg->BufferLength, hdr->num_elements); - /* Report failure to client. */ - response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, - RPC_VER_MAJOR, RPC_VER_MINOR, - REJECT_REASON_NOT_SPECIFIED); - goto send; + return RPC_S_INVALID_BOUND; } } @@ -198,109 +233,134 @@ static RPC_STATUS process_bind_packet(RpcConnection *conn, RpcPktBindHdr *hdr, R { TRACE("packet size less than min size, or active interface syntax guid non-null\n"); - /* Report failure to client. */ - response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, - RPC_VER_MAJOR, RPC_VER_MINOR, - REJECT_REASON_NOT_SPECIFIED); + return RPC_S_INVALID_BOUND; } - else + + results = HeapAlloc(GetProcessHeap(), 0, + hdr->num_elements * sizeof(*results)); + if (!results) + return RPC_S_OUT_OF_RESOURCES; + + for (i = 0, ctxt_elem = (RpcContextElement *)msg->Buffer; + i < hdr->num_elements; + i++, ctxt_elem = (RpcContextElement *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes]) { - RpcResult *results = HeapAlloc(GetProcessHeap(), 0, - hdr->num_elements * sizeof(*results)); - if (!results) - { - /* Report failure to client. */ - response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, - RPC_VER_MAJOR, RPC_VER_MINOR, - REJECT_LOCAL_LIMIT_EXCEEDED); - goto send; - } + RpcServerInterface* sif = NULL; + unsigned int j; - for (i = 0, ctxt_elem = (RpcContextElement *)msg->Buffer; - i < hdr->num_elements; - i++, ctxt_elem = (RpcContextElement *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes]) - { - RpcServerInterface* sif = NULL; - unsigned int j; + for (j = 0; !sif && j < ctxt_elem->num_syntaxes; j++) + { + sif = RPCRT4_find_interface(NULL, &ctxt_elem->abstract_syntax, + &ctxt_elem->transfer_syntaxes[j], FALSE); + if (sif) + break; + } + if (sif) + { + RPCRT4_release_server_interface(sif); + TRACE("accepting bind request on connection %p for %s\n", conn, + debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID)); + results[i].result = RESULT_ACCEPT; + results[i].reason = REASON_NONE; + results[i].transfer_syntax = ctxt_elem->transfer_syntaxes[j]; - for (j = 0; !sif && j < ctxt_elem->num_syntaxes; j++) - { - sif = RPCRT4_find_interface(NULL, &ctxt_elem->abstract_syntax, - &ctxt_elem->transfer_syntaxes[j], FALSE); - if (sif) - break; - } - - if (sif) - { - RPCRT4_release_server_interface(sif); - TRACE("accepting bind request on connection %p for %s\n", conn, - debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID)); - results[i].result = RESULT_ACCEPT; - results[i].reason = REASON_NONE; - results[i].transfer_syntax = ctxt_elem->transfer_syntaxes[j]; - - /* save the interface for later use */ - /* FIXME: save linked list */ - conn->ActiveInterface = ctxt_elem->abstract_syntax; - } - else if ((sif = RPCRT4_find_interface(NULL, &ctxt_elem->abstract_syntax, - NULL, FALSE)) != NULL) - { - RPCRT4_release_server_interface(sif); - TRACE("not accepting bind request on connection %p for %s - no transfer syntaxes supported\n", - conn, debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID)); - results[i].result = RESULT_PROVIDER_REJECTION; - results[i].reason = REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED; - memset(&results[i].transfer_syntax, 0, sizeof(results[i].transfer_syntax)); - } - else - { - TRACE("not accepting bind request on connection %p for %s - abstract syntax not supported\n", - conn, debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID)); - results[i].result = RESULT_PROVIDER_REJECTION; - results[i].reason = REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED; - memset(&results[i].transfer_syntax, 0, sizeof(results[i].transfer_syntax)); - } - } - - /* create temporary binding */ - if (RPCRT4_MakeBinding(&conn->server_binding, conn) == RPC_S_OK && - RpcServerAssoc_GetAssociation(rpcrt4_conn_get_name(conn), - conn->NetworkAddr, conn->Endpoint, - conn->NetworkOptions, - hdr->assoc_gid, - &conn->server_binding->Assoc) == RPC_S_OK) - { - response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION, - RPC_MAX_PACKET_SIZE, - RPC_MAX_PACKET_SIZE, - conn->server_binding->Assoc->assoc_group_id, - conn->Endpoint, hdr->num_elements, - results); - - conn->MaxTransmissionSize = hdr->max_tsize; - } - else - { - /* Report failure to client. */ - response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, - RPC_VER_MAJOR, RPC_VER_MINOR, - REJECT_LOCAL_LIMIT_EXCEEDED); - } - HeapFree(GetProcessHeap(), 0, results); + /* save the interface for later use */ + /* FIXME: save linked list */ + conn->ActiveInterface = ctxt_elem->abstract_syntax; + } + else if ((sif = RPCRT4_find_interface(NULL, &ctxt_elem->abstract_syntax, + NULL, FALSE)) != NULL) + { + RPCRT4_release_server_interface(sif); + TRACE("not accepting bind request on connection %p for %s - no transfer syntaxes supported\n", + conn, debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID)); + results[i].result = RESULT_PROVIDER_REJECTION; + results[i].reason = REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED; + memset(&results[i].transfer_syntax, 0, sizeof(results[i].transfer_syntax)); + } + else + { + TRACE("not accepting bind request on connection %p for %s - abstract syntax not supported\n", + conn, debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID)); + results[i].result = RESULT_PROVIDER_REJECTION; + results[i].reason = REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED; + memset(&results[i].transfer_syntax, 0, sizeof(results[i].transfer_syntax)); + } } -send: - if (response) - status = RPCRT4_Send(conn, response, NULL, 0); + /* create temporary binding */ + status = RPCRT4_MakeBinding(&conn->server_binding, conn); + if (status != RPC_S_OK) + { + HeapFree(GetProcessHeap(), 0, results); + return status; + } + + status = RpcServerAssoc_GetAssociation(rpcrt4_conn_get_name(conn), + conn->NetworkAddr, conn->Endpoint, + conn->NetworkOptions, + hdr->assoc_gid, + &conn->server_binding->Assoc); + if (status != RPC_S_OK) + { + HeapFree(GetProcessHeap(), 0, results); + return status; + } + + if (auth_length) + { + status = RPCRT4_ServerConnectionAuth(conn, TRUE, + (RpcAuthVerifier *)auth_data, + auth_length, auth_data_out, + auth_length_out); + if (status != RPC_S_OK) + { + HeapFree(GetProcessHeap(), 0, results); + return status; + } + } + + *ack_response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_MAX_PACKET_SIZE, + RPC_MAX_PACKET_SIZE, + conn->server_binding->Assoc->assoc_group_id, + conn->Endpoint, hdr->num_elements, + results); + HeapFree(GetProcessHeap(), 0, results); + + if (*ack_response) + conn->MaxTransmissionSize = hdr->max_tsize; else - status = ERROR_OUTOFMEMORY; - RPCRT4_FreeHeader(response); + status = RPC_S_OUT_OF_RESOURCES; return status; } +static RPC_STATUS process_bind_packet(RpcConnection *conn, RpcPktBindHdr *hdr, + RPC_MESSAGE *msg, + unsigned char *auth_data, + ULONG auth_length) +{ + RPC_STATUS status; + RpcPktHdr *response = NULL; + unsigned char *auth_data_out = NULL; + ULONG auth_length_out = 0; + + status = process_bind_packet_no_send(conn, hdr, msg, auth_data, auth_length, + &response, &auth_data_out, + &auth_length_out); + if (status != RPC_S_OK) + response = handle_bind_error(conn, status); + if (response) + status = RPCRT4_SendWithAuth(conn, response, NULL, 0, auth_data_out, auth_length_out); + else + status = ERROR_OUTOFMEMORY; + RPCRT4_FreeHeader(response); + + return status; +} + + static RPC_STATUS process_request_packet(RpcConnection *conn, RpcPktRequestHdr *hdr, RPC_MESSAGE *msg) { RPC_STATUS status; @@ -414,7 +474,34 @@ static RPC_STATUS process_request_packet(RpcConnection *conn, RpcPktRequestHdr * return status; } -static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSAGE* msg) +static RPC_STATUS process_auth3_packet(RpcConnection *conn, + RpcPktCommonHdr *hdr, + RPC_MESSAGE *msg, + unsigned char *auth_data, + ULONG auth_length) +{ + RPC_STATUS status; + + if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status) || + !auth_length || msg->BufferLength != 0) + status = RPC_S_PROTOCOL_ERROR; + else + { + status = RPCRT4_ServerConnectionAuth(conn, FALSE, + (RpcAuthVerifier *)auth_data, + auth_length, NULL, NULL); + } + + /* FIXME: client doesn't expect a response to this message so must store + * status in connection so that fault packet can be returned when next + * packet is received */ + + return RPC_S_OK; +} + +static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, + RPC_MESSAGE* msg, unsigned char *auth_data, + ULONG auth_length) { RPC_STATUS status; @@ -424,7 +511,8 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA case PKT_BIND: TRACE("got bind packet\n"); - status = process_bind_packet(conn, &hdr->bind, msg); + status = process_bind_packet(conn, &hdr->bind, msg, auth_data, + auth_length); break; case PKT_REQUEST: @@ -433,6 +521,12 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA status = process_request_packet(conn, &hdr->request, msg); break; + case PKT_AUTH3: + TRACE("got auth3 packet\n"); + + status = process_auth3_packet(conn, &hdr->common, msg, auth_data, + auth_length); + break; default: FIXME("unhandled packet type %u\n", hdr->common.ptype); break; @@ -442,12 +536,14 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA I_RpcFree(msg->Buffer); RPCRT4_FreeHeader(hdr); HeapFree(GetProcessHeap(), 0, msg); + HeapFree(GetProcessHeap(), 0, auth_data); } static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg) { RpcPacket *pkt = the_arg; - RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg); + RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg, pkt->auth_data, + pkt->auth_length); HeapFree(GetProcessHeap(), 0, pkt); return 0; } @@ -459,13 +555,15 @@ static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg) RPC_MESSAGE *msg; RPC_STATUS status; RpcPacket *packet; + unsigned char *auth_data; + ULONG auth_length; TRACE("(%p)\n", conn); for (;;) { msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE)); - status = RPCRT4_Receive(conn, &hdr, msg); + status = RPCRT4_ReceiveWithAuth(conn, &hdr, msg, &auth_data, &auth_length); if (status != RPC_S_OK) { WARN("receive failed with error %x\n", status); HeapFree(GetProcessHeap(), 0, msg); @@ -482,12 +580,15 @@ static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg) packet->conn = conn; packet->hdr = hdr; packet->msg = msg; + packet->auth_data = auth_data; + packet->auth_length = auth_length; if (!QueueUserWorkItem(RPCRT4_worker_thread, packet, WT_EXECUTELONGFUNCTION)) { ERR("couldn't queue work item for worker thread, error was %d\n", GetLastError()); I_RpcFree(msg->Buffer); RPCRT4_FreeHeader(hdr); HeapFree(GetProcessHeap(), 0, msg); HeapFree(GetProcessHeap(), 0, packet); + HeapFree(GetProcessHeap(), 0, auth_data); break; }