Commit 59ba6d25 authored by Rob Shearman's avatar Rob Shearman Committed by Alexandre Julliard

rpcrt4: Support multiple interfaces and transfer syntaxes in bind and bind ack messages.

parent 7e52896b
......@@ -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)
{
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment