From 59ba6d2573532c15e2487bbc86f6bb93022c1d38 Mon Sep 17 00:00:00 2001 From: Rob Shearman Date: Tue, 10 Nov 2009 23:05:07 +0000 Subject: [PATCH] rpcrt4: Support multiple interfaces and transfer syntaxes in bind and bind ack messages. --- dlls/rpcrt4/rpc_assoc.c | 7 ++- dlls/rpcrt4/rpc_defs.h | 87 ++++++++++++++++------------ dlls/rpcrt4/rpc_message.c | 38 ++++++------- dlls/rpcrt4/rpc_message.h | 4 +- dlls/rpcrt4/rpc_server.c | 140 +++++++++++++++++++++++++++++++++++----------- 5 files changed, 181 insertions(+), 95 deletions(-) diff --git a/dlls/rpcrt4/rpc_assoc.c b/dlls/rpcrt4/rpc_assoc.c index 4030d3d8f47..a74e66088bd 100644 --- a/dlls/rpcrt4/rpc_assoc.c +++ b/dlls/rpcrt4/rpc_assoc.c @@ -263,9 +263,10 @@ static RPC_STATUS RpcAssoc_BindConnection(const RpcAssoc *assoc, RpcConnection * { unsigned short remaining = msg.BufferLength - ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4); - RpcResults *results = (RpcResults*)((ULONG_PTR)server_address + - ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)); - if ((results->num_results == 1) && (remaining >= sizeof(*results))) + RpcResultList *results = (RpcResultList*)((ULONG_PTR)server_address + + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)); + if ((results->num_results == 1) && + (remaining >= FIELD_OFFSET(RpcResultList, results[results->num_results]))) { switch (results->results[0].result) { diff --git a/dlls/rpcrt4/rpc_defs.h b/dlls/rpcrt4/rpc_defs.h index e70731a3818..8514967a9c9 100644 --- a/dlls/rpcrt4/rpc_defs.h +++ b/dlls/rpcrt4/rpc_defs.h @@ -22,6 +22,7 @@ #ifndef __WINE_RPC_DEFS_H #define __WINE_RPC_DEFS_H +#include "pshpack1.h" typedef struct { unsigned char rpc_ver; /* RPC major version (5) */ @@ -64,35 +65,46 @@ typedef struct typedef struct { + unsigned short context_id; /* Presentation context identifier */ + unsigned char num_syntaxes; /* Number of syntaxes */ + unsigned char reserved; /* For alignment */ + RPC_SYNTAX_IDENTIFIER abstract_syntax; + RPC_SYNTAX_IDENTIFIER transfer_syntaxes[ANYSIZE_ARRAY]; /* size_is(num_syntaxes) */ +} RpcContextElement; + +typedef struct +{ RpcPktCommonHdr common; unsigned short max_tsize; /* Maximum transmission fragment size */ unsigned short max_rsize; /* Maximum receive fragment size */ unsigned int assoc_gid; /* Associated group id */ unsigned char num_elements; /* Number of elements */ unsigned char padding[3]; /* Force alignment! */ - unsigned short context_id; /* Presentation context identifier */ - unsigned char num_syntaxes; /* Number of syntaxes */ - RPC_SYNTAX_IDENTIFIER abstract; - RPC_SYNTAX_IDENTIFIER transfer; + /* + * Following this header are these fields: + * RpcContextElement context_elements[num_elements] + */ } RpcPktBindHdr; -#include "pshpack1.h" typedef struct { unsigned short length; /* Length of the string including null terminator */ - char string[1]; /* String data in single byte, null terminated form */ + char string[ANYSIZE_ARRAY]; /* String data in single byte, null terminated form */ } RpcAddressString; -#include "poppack.h" + +typedef struct +{ + unsigned short result; + unsigned short reason; + RPC_SYNTAX_IDENTIFIER transfer_syntax; +} RpcResult; typedef struct { unsigned char num_results; /* Number of results */ unsigned char reserved[3]; /* Force alignment! */ - struct { - unsigned short result; - unsigned short reason; - } results[1]; -} RpcResults; + RpcResult results[ANYSIZE_ARRAY]; /* size_is(num_results) */ +} RpcResultList; typedef struct { @@ -104,8 +116,7 @@ typedef struct * Following this header are these fields: * RpcAddressString server_address; * [0 - 3 bytes of padding so that results is 4-byte aligned] - * RpcResults results; - * RPC_SYNTAX_IDENTIFIER transfer; + * RpcResultList results; */ } RpcPktBindAckHdr; @@ -117,7 +128,7 @@ typedef struct struct { unsigned char rpc_ver; unsigned char rpc_ver_minor; - } protocols[1]; + } protocols[ANYSIZE_ARRAY]; } RpcPktBindNAckHdr; /* undocumented packet sent during RPC over HTTP */ @@ -149,6 +160,7 @@ typedef struct unsigned char auth_reserved; /* reserved, must be zero */ unsigned int auth_context_id; /* unique value for the authenticated connection */ } RpcAuthVerifier; +#include "poppack.h" #define RPC_AUTH_VERIFIER_LEN(common_hdr) \ ((common_hdr)->auth_len ? (common_hdr)->auth_len + sizeof(RpcAuthVerifier) : 0) @@ -163,27 +175,30 @@ typedef struct #define RPC_MIN_PACKET_SIZE 0x1000 #define RPC_MAX_PACKET_SIZE 0x16D0 -#define PKT_REQUEST 0 -#define PKT_PING 1 -#define PKT_RESPONSE 2 -#define PKT_FAULT 3 -#define PKT_WORKING 4 -#define PKT_NOCALL 5 -#define PKT_REJECT 6 -#define PKT_ACK 7 -#define PKT_CL_CANCEL 8 -#define PKT_FACK 9 -#define PKT_CANCEL_ACK 10 -#define PKT_BIND 11 -#define PKT_BIND_ACK 12 -#define PKT_BIND_NACK 13 -#define PKT_ALTER_CONTEXT 14 -#define PKT_ALTER_CONTEXT_RESP 15 -#define PKT_AUTH3 16 -#define PKT_SHUTDOWN 17 -#define PKT_CO_CANCEL 18 -#define PKT_ORPHANED 19 -#define PKT_HTTP 20 +enum rpc_packet_type +{ + PKT_REQUEST = 0, + PKT_PING = 1, + PKT_RESPONSE = 2, + PKT_FAULT = 3, + PKT_WORKING = 4, + PKT_NOCALL = 5, + PKT_REJECT = 6, + PKT_ACK = 7, + PKT_CL_CANCEL = 8, + PKT_FACK = 9, + PKT_CANCEL_ACK = 10, + PKT_BIND = 11, + PKT_BIND_ACK = 12, + PKT_BIND_NACK = 13, + PKT_ALTER_CONTEXT = 14, + PKT_ALTER_CONTEXT_RESP = 15, + PKT_AUTH3 = 16, + PKT_SHUTDOWN = 17, + PKT_CO_CANCEL = 18, + PKT_ORPHANED = 19, + PKT_HTTP = 20, +}; #define RESULT_ACCEPT 0 #define RESULT_USER_REJECTION 1 diff --git a/dlls/rpcrt4/rpc_message.c b/dlls/rpcrt4/rpc_message.c index 5e7c857acdd..50db20c54ff 100644 --- a/dlls/rpcrt4/rpc_message.c +++ b/dlls/rpcrt4/rpc_message.c @@ -181,21 +181,24 @@ RpcPktHdr *RPCRT4_BuildBindHeader(ULONG DataRepresentation, const RPC_SYNTAX_IDENTIFIER *TransferId) { RpcPktHdr *header; + RpcContextElement *ctxt_elem; - header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind)); + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(header->bind) + FIELD_OFFSET(RpcContextElement, transfer_syntaxes[1])); if (header == NULL) { return NULL; } + ctxt_elem = (RpcContextElement *)(&header->bind + 1); RPCRT4_BuildCommonHeader(header, PKT_BIND, DataRepresentation); - header->common.frag_len = sizeof(header->bind); + header->common.frag_len = sizeof(header->bind) + FIELD_OFFSET(RpcContextElement, transfer_syntaxes[1]); header->bind.max_tsize = MaxTransmissionSize; header->bind.max_rsize = MaxReceiveSize; header->bind.assoc_gid = AssocGroupId; header->bind.num_elements = 1; - header->bind.num_syntaxes = 1; - header->bind.abstract = *AbstractId; - header->bind.transfer = *TransferId; + ctxt_elem->num_syntaxes = 1; + ctxt_elem->abstract_syntax = *AbstractId; + ctxt_elem->transfer_syntaxes[0] = *TransferId; return header; } @@ -218,7 +221,8 @@ static RpcPktHdr *RPCRT4_BuildAuthHeader(ULONG DataRepresentation) RpcPktHdr *RPCRT4_BuildBindNackHeader(ULONG DataRepresentation, unsigned char RpcVersion, - unsigned char RpcVersionMinor) + unsigned char RpcVersionMinor, + unsigned short RejectReason) { RpcPktHdr *header; @@ -229,7 +233,7 @@ RpcPktHdr *RPCRT4_BuildBindNackHeader(ULONG DataRepresentation, RPCRT4_BuildCommonHeader(header, PKT_BIND_NACK, DataRepresentation); header->common.frag_len = sizeof(header->bind_nack); - header->bind_nack.reject_reason = REJECT_REASON_NOT_SPECIFIED; + header->bind_nack.reject_reason = RejectReason; header->bind_nack.protocols_count = 1; header->bind_nack.protocols[0].rpc_ver = RpcVersion; header->bind_nack.protocols[0].rpc_ver_minor = RpcVersionMinor; @@ -242,20 +246,17 @@ RpcPktHdr *RPCRT4_BuildBindAckHeader(ULONG DataRepresentation, unsigned short MaxReceiveSize, ULONG AssocGroupId, LPCSTR ServerAddress, - unsigned short Result, - unsigned short Reason, - const RPC_SYNTAX_IDENTIFIER *TransferId) + unsigned char ResultCount, + const RpcResult *Results) { RpcPktHdr *header; ULONG header_size; RpcAddressString *server_address; - RpcResults *results; - RPC_SYNTAX_IDENTIFIER *transfer_id; + RpcResultList *results; header_size = sizeof(header->bind_ack) + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[strlen(ServerAddress) + 1]), 4) + - sizeof(RpcResults) + - sizeof(RPC_SYNTAX_IDENTIFIER); + FIELD_OFFSET(RpcResultList, results[ResultCount]); header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, header_size); if (header == NULL) { @@ -271,12 +272,9 @@ RpcPktHdr *RPCRT4_BuildBindAckHeader(ULONG DataRepresentation, server_address->length = strlen(ServerAddress) + 1; strcpy(server_address->string, ServerAddress); /* results is 4-byte aligned */ - results = (RpcResults*)((ULONG_PTR)server_address + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)); - results->num_results = 1; - results->results[0].result = Result; - results->results[0].reason = Reason; - transfer_id = (RPC_SYNTAX_IDENTIFIER*)(results + 1); - *transfer_id = *TransferId; + results = (RpcResultList*)((ULONG_PTR)server_address + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)); + results->num_results = ResultCount; + memcpy(&results->results[0], Results, ResultCount * sizeof(*Results)); return header; } diff --git a/dlls/rpcrt4/rpc_message.h b/dlls/rpcrt4/rpc_message.h index aeeef0773e5..dd62f2dfb69 100644 --- a/dlls/rpcrt4/rpc_message.h +++ b/dlls/rpcrt4/rpc_message.h @@ -28,8 +28,8 @@ typedef unsigned int NCA_STATUS; RpcPktHdr *RPCRT4_BuildFaultHeader(ULONG DataRepresentation, RPC_STATUS Status); RpcPktHdr *RPCRT4_BuildResponseHeader(ULONG DataRepresentation, ULONG BufferLength); RpcPktHdr *RPCRT4_BuildBindHeader(ULONG DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, ULONG AssocGroupId, const RPC_SYNTAX_IDENTIFIER *AbstractId, const RPC_SYNTAX_IDENTIFIER *TransferId); -RpcPktHdr *RPCRT4_BuildBindNackHeader(ULONG DataRepresentation, unsigned char RpcVersion, unsigned char RpcVersionMinor); -RpcPktHdr *RPCRT4_BuildBindAckHeader(ULONG DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, ULONG AssocGroupId, LPCSTR ServerAddress, unsigned short Result, unsigned short Reason, const RPC_SYNTAX_IDENTIFIER *TransferId); +RpcPktHdr *RPCRT4_BuildBindNackHeader(ULONG DataRepresentation, unsigned char RpcVersion, unsigned char RpcVersionMinor, unsigned short RejectReason); +RpcPktHdr *RPCRT4_BuildBindAckHeader(ULONG DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, ULONG AssocGroupId, LPCSTR ServerAddress, unsigned char ResultCount, const RpcResult *Results); RpcPktHdr *RPCRT4_BuildHttpHeader(ULONG DataRepresentation, unsigned short flags, unsigned short num_data_items, unsigned int payload_size); RpcPktHdr *RPCRT4_BuildHttpConnectHeader(unsigned short flags, int out_pipe, const UUID *connection_uuid, const UUID *pipe_uuid, const UUID *association_uuid); RpcPktHdr *RPCRT4_BuildHttpFlowControlHeader(BOOL server, ULONG bytes_transmitted, ULONG flow_control_increment, const UUID *pipe_uuid); diff --git a/dlls/rpcrt4/rpc_server.c b/dlls/rpcrt4/rpc_server.c index 621496590f7..eb31e8b854c 100644 --- a/dlls/rpcrt4/rpc_server.c +++ b/dlls/rpcrt4/rpc_server.c @@ -118,7 +118,8 @@ static inline UUID *LookupObjType(UUID *ObjUuid) } static RpcServerInterface* RPCRT4_find_interface(UUID* object, - const RPC_SYNTAX_IDENTIFIER* if_id, + const RPC_SYNTAX_IDENTIFIER *if_id, + const RPC_SYNTAX_IDENTIFIER *transfer_syntax, BOOL check_object) { UUID* MgrType = NULL; @@ -130,6 +131,7 @@ static RpcServerInterface* RPCRT4_find_interface(UUID* object, EnterCriticalSection(&server_cs); LIST_FOR_EACH_ENTRY(cif, &server_interfaces, RpcServerInterface, entry) { if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) && + (!transfer_syntax || !memcmp(transfer_syntax, &cif->If->TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER))) && (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) && std_listen) { InterlockedIncrement(&cif->CurrentCalls); @@ -159,16 +161,94 @@ static void RPCRT4_release_server_interface(RpcServerInterface *sif) static RPC_STATUS process_bind_packet(RpcConnection *conn, RpcPktBindHdr *hdr, RPC_MESSAGE *msg) { RPC_STATUS status; - RpcServerInterface* sif; - RpcPktHdr *response = NULL; + RpcPktHdr *response; + RpcContextElement *ctxt_elem; + unsigned int i; + + for (i = 0, ctxt_elem = msg->Buffer; + i < hdr->num_elements; + i++, ctxt_elem = (RpcContextElement *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes]) + { + if (((char *)ctxt_elem - (char *)msg->Buffer) > msg->BufferLength || + ((char *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes] - (char *)msg->Buffer) > msg->BufferLength) + { + 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; + } + } - /* FIXME: do more checks! */ if (hdr->max_tsize < RPC_MIN_PACKET_SIZE || !UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status) || - conn->server_binding) { + conn->server_binding) + { TRACE("packet size less than min size, or active interface syntax guid non-null\n"); - sif = NULL; - } else { + + /* Report failure to client. */ + response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_VER_MAJOR, RPC_VER_MINOR, + REJECT_REASON_NOT_SPECIFIED); + } + else + { + 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); + } + + 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) + { + 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), @@ -176,35 +256,27 @@ static RPC_STATUS process_bind_packet(RpcConnection *conn, RpcPktBindHdr *hdr, R conn->NetworkOptions, hdr->assoc_gid, &conn->server_binding->Assoc) == RPC_S_OK) - sif = RPCRT4_find_interface(NULL, &hdr->abstract, FALSE); + { + 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 - sif = NULL; - } - if (sif == NULL) { - TRACE("rejecting bind request on connection %p\n", conn); - /* Report failure to client. */ - response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, - RPC_VER_MAJOR, RPC_VER_MINOR); - } else { - TRACE("accepting bind request on connection %p for %s\n", conn, - debugstr_guid(&hdr->abstract.SyntaxGUID)); - - /* accept. */ - response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION, - RPC_MAX_PACKET_SIZE, - RPC_MAX_PACKET_SIZE, - conn->server_binding->Assoc->assoc_group_id, - conn->Endpoint, - RESULT_ACCEPT, REASON_NONE, - &sif->If->TransferSyntax); - - /* save the interface for later use */ - conn->ActiveInterface = hdr->abstract; - conn->MaxTransmissionSize = hdr->max_tsize; - - RPCRT4_release_server_interface(sif); + { + /* 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); } +send: if (response) status = RPCRT4_Send(conn, response, NULL, 0); else @@ -242,7 +314,7 @@ static RPC_STATUS process_request_packet(RpcConnection *conn, RpcPktRequestHdr * object_uuid = NULL; } - sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, TRUE); + sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, NULL, TRUE); if (!sif) { WARN("interface %s no longer registered, returning fault packet\n", debugstr_guid(&conn->ActiveInterface.SyntaxGUID)); response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION, -- 2.11.4.GIT