rpcrt4: Add support for server-side authentication.
This commit is contained in:
parent
ceb7fda374
commit
e27e61db71
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue