rpcrt4: Add support for server-side authentication.
This commit is contained in:
parent
ceb7fda374
commit
e27e61db71
|
@ -273,7 +273,7 @@ static RPC_STATUS RpcAssoc_BindConnection(const RpcAssoc *assoc, RpcConnection *
|
||||||
case RESULT_ACCEPT:
|
case RESULT_ACCEPT:
|
||||||
/* respond to authorization request */
|
/* respond to authorization request */
|
||||||
if (auth_length > sizeof(RpcAuthVerifier))
|
if (auth_length > sizeof(RpcAuthVerifier))
|
||||||
status = RPCRT4_AuthorizeConnection(conn,
|
status = RPCRT4_ClientConnectionAuth(conn,
|
||||||
auth_data + sizeof(RpcAuthVerifier),
|
auth_data + sizeof(RpcAuthVerifier),
|
||||||
auth_length);
|
auth_length);
|
||||||
if (status == RPC_S_OK)
|
if (status == RPC_S_OK)
|
||||||
|
|
|
@ -1094,7 +1094,7 @@ static inline BOOL has_nt_auth_identity(ULONG AuthnLevel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static RPC_STATUS RpcAuthInfo_Create(ULONG AuthnLevel, ULONG AuthnSvc,
|
RPC_STATUS RpcAuthInfo_Create(ULONG AuthnLevel, ULONG AuthnSvc,
|
||||||
CredHandle cred, TimeStamp exp,
|
CredHandle cred, TimeStamp exp,
|
||||||
ULONG cbMaxToken,
|
ULONG cbMaxToken,
|
||||||
RPC_AUTH_IDENTITY_HANDLE identity,
|
RPC_AUTH_IDENTITY_HANDLE identity,
|
||||||
|
|
|
@ -132,6 +132,7 @@ void RPCRT4_strfree(LPSTR src);
|
||||||
#define RPCRT4_strdupA(x) RPCRT4_strndupA((x),-1)
|
#define RPCRT4_strdupA(x) RPCRT4_strndupA((x),-1)
|
||||||
#define RPCRT4_strdupW(x) RPCRT4_strndupW((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_AddRef(RpcAuthInfo *AuthInfo);
|
||||||
ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo);
|
ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo);
|
||||||
BOOL RpcAuthInfo_IsEqual(const RpcAuthInfo *AuthInfo1, const RpcAuthInfo *AuthInfo2);
|
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->request), 0, sizeof(Header->response),
|
||||||
sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind),
|
sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind),
|
||||||
sizeof(Header->bind_ack), sizeof(Header->bind_nack),
|
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;
|
ULONG ret = 0;
|
||||||
|
|
||||||
if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) {
|
if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) {
|
||||||
ret = header_sizes[Header->common.ptype];
|
ret = header_sizes[Header->common.ptype];
|
||||||
if (ret == 0)
|
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)
|
if (Header->common.flags & RPC_FLG_OBJECT_UUID)
|
||||||
ret += sizeof(UUID);
|
ret += sizeof(UUID);
|
||||||
} else {
|
} else {
|
||||||
|
@ -95,6 +95,21 @@ static int packet_has_auth_verifier(const RpcPktHdr *Header)
|
||||||
!(Header->common.ptype == PKT_SHUTDOWN);
|
!(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,
|
static VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType,
|
||||||
ULONG DataRepresentation)
|
ULONG DataRepresentation)
|
||||||
{
|
{
|
||||||
|
@ -208,13 +223,12 @@ static RpcPktHdr *RPCRT4_BuildAuthHeader(ULONG DataRepresentation)
|
||||||
RpcPktHdr *header;
|
RpcPktHdr *header;
|
||||||
|
|
||||||
header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||||
sizeof(header->common) + 12);
|
sizeof(header->common));
|
||||||
if (header == NULL)
|
if (header == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
RPCRT4_BuildCommonHeader(header, PKT_AUTH3, DataRepresentation);
|
RPCRT4_BuildCommonHeader(header, PKT_AUTH3, DataRepresentation);
|
||||||
header->common.frag_len = 0x14;
|
header->common.frag_len = sizeof(header->common);
|
||||||
header->common.auth_len = 0;
|
|
||||||
|
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
@ -749,7 +763,7 @@ static RPC_STATUS RPCRT4_SecurePacket(RpcConnection *Connection,
|
||||||
*
|
*
|
||||||
* Transmit a packet with authorization data over connection in acceptable fragments.
|
* Transmit a packet with authorization data over connection in acceptable fragments.
|
||||||
*/
|
*/
|
||||||
static RPC_STATUS RPCRT4_SendWithAuth(RpcConnection *Connection, RpcPktHdr *Header,
|
RPC_STATUS RPCRT4_SendWithAuth(RpcConnection *Connection, RpcPktHdr *Header,
|
||||||
void *Buffer, unsigned int BufferLength,
|
void *Buffer, unsigned int BufferLength,
|
||||||
const void *Auth, unsigned int AuthLength)
|
const void *Auth, unsigned int AuthLength)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
memcpy(pkt + hdr_size, buffer_pos, Header->common.frag_len - hdr_size - auth_pad_len - alen);
|
||||||
|
|
||||||
/* add the authorization info */
|
/* 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];
|
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,
|
static RPC_STATUS RPCRT4_Authorize(RpcConnection *conn, BOOL first_time,
|
||||||
SecBuffer *out)
|
SecBuffer *in, SecBuffer *out)
|
||||||
{
|
{
|
||||||
SECURITY_STATUS r;
|
SECURITY_STATUS r;
|
||||||
SecBufferDesc out_desc;
|
SecBufferDesc out_desc;
|
||||||
SecBufferDesc inp_desc;
|
SecBufferDesc inp_desc;
|
||||||
SecPkgContext_Sizes secctx_sizes;
|
SecPkgContext_Sizes secctx_sizes;
|
||||||
BOOL continue_needed;
|
BOOL continue_needed;
|
||||||
ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
|
ULONG context_req;
|
||||||
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;
|
|
||||||
|
|
||||||
out->BufferType = SECBUFFER_TOKEN;
|
out->BufferType = SECBUFFER_TOKEN;
|
||||||
out->cbBuffer = conn->AuthInfo->cbMaxToken;
|
out->cbBuffer = conn->AuthInfo->cbMaxToken;
|
||||||
|
@ -889,10 +897,45 @@ static RPC_STATUS RPCRT4_ClientAuthorize(RpcConnection *conn, SecBuffer *in,
|
||||||
inp_desc.pBuffers = in;
|
inp_desc.pBuffers = in;
|
||||||
inp_desc.ulVersion = 0;
|
inp_desc.ulVersion = 0;
|
||||||
|
|
||||||
r = InitializeSecurityContextW(&conn->AuthInfo->cred, in ? &conn->ctx : NULL,
|
if (conn->server)
|
||||||
in ? NULL : conn->AuthInfo->server_principal_name, context_req, 0,
|
{
|
||||||
SECURITY_NETWORK_DREP, in ? &inp_desc : NULL, 0, &conn->ctx,
|
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);
|
&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))
|
if (FAILED(r))
|
||||||
{
|
{
|
||||||
WARN("InitializeSecurityContext failed with error 0x%08x\n", r);
|
WARN("InitializeSecurityContext failed with error 0x%08x\n", r);
|
||||||
|
@ -937,9 +980,9 @@ failed:
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* RPCRT4_AuthorizeBinding (internal)
|
* RPCRT4_ClientConnectionAuth (internal)
|
||||||
*/
|
*/
|
||||||
RPC_STATUS RPCRT4_AuthorizeConnection(RpcConnection* conn, BYTE *challenge,
|
RPC_STATUS RPCRT4_ClientConnectionAuth(RpcConnection* conn, BYTE *challenge,
|
||||||
ULONG count)
|
ULONG count)
|
||||||
{
|
{
|
||||||
SecBuffer inp, out;
|
SecBuffer inp, out;
|
||||||
|
@ -952,7 +995,7 @@ RPC_STATUS RPCRT4_AuthorizeConnection(RpcConnection* conn, BYTE *challenge,
|
||||||
inp.pvBuffer = challenge;
|
inp.pvBuffer = challenge;
|
||||||
inp.cbBuffer = count;
|
inp.cbBuffer = count;
|
||||||
|
|
||||||
status = RPCRT4_ClientAuthorize(conn, &inp, &out);
|
status = RPCRT4_Authorize(conn, FALSE, &inp, &out);
|
||||||
if (status) return status;
|
if (status) return status;
|
||||||
|
|
||||||
resp_hdr = RPCRT4_BuildAuthHeader(NDR_LOCAL_DATA_REPRESENTATION);
|
resp_hdr = RPCRT4_BuildAuthHeader(NDR_LOCAL_DATA_REPRESENTATION);
|
||||||
|
@ -967,6 +1010,87 @@ RPC_STATUS RPCRT4_AuthorizeConnection(RpcConnection* conn, BYTE *challenge,
|
||||||
return status;
|
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)
|
* RPCRT4_Send (internal)
|
||||||
*
|
*
|
||||||
|
@ -978,18 +1102,19 @@ RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header,
|
||||||
RPC_STATUS r;
|
RPC_STATUS r;
|
||||||
SecBuffer out;
|
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 */
|
/* tack on a negotiate packet */
|
||||||
r = RPCRT4_ClientAuthorize(Connection, NULL, &out);
|
r = RPCRT4_Authorize(Connection, TRUE, NULL, &out);
|
||||||
if (r == RPC_S_OK)
|
if (r == RPC_S_OK)
|
||||||
{
|
{
|
||||||
r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, out.pvBuffer, out.cbBuffer);
|
r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, out.pvBuffer, out.cbBuffer);
|
||||||
HeapFree(GetProcessHeap(), 0, out.pvBuffer);
|
HeapFree(GetProcessHeap(), 0, out.pvBuffer);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, NULL, 0);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -1133,6 +1258,8 @@ RPC_STATUS RPCRT4_ReceiveWithAuth(RpcConnection *Connection, RpcPktHdr **Header,
|
||||||
|
|
||||||
*Header = NULL;
|
*Header = NULL;
|
||||||
pMsg->Buffer = 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);
|
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
|
/* these packets are handled specially, not by the generic SecurePacket
|
||||||
* function */
|
* function */
|
||||||
if (!auth_data_out && SecIsValidHandle(&Connection->ctx))
|
if (!packet_does_auth_negotiation(*Header) && SecIsValidHandle(&Connection->ctx))
|
||||||
{
|
{
|
||||||
status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_RECEIVE,
|
status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_RECEIVE,
|
||||||
CurrentHeader, hdr_length,
|
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);
|
RpcPktHdr *RPCRT4_BuildHttpFlowControlHeader(BOOL server, ULONG bytes_transmitted, ULONG flow_control_increment, const UUID *pipe_uuid);
|
||||||
VOID RPCRT4_FreeHeader(RpcPktHdr *Header);
|
VOID RPCRT4_FreeHeader(RpcPktHdr *Header);
|
||||||
RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, void *Buffer, unsigned int BufferLength);
|
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_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);
|
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);
|
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_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);
|
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);
|
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_AuthorizeConnection(RpcConnection* conn, BYTE *challenge, ULONG count);
|
||||||
|
RPC_STATUS RPCRT4_ServerGetRegisteredAuthInfo(USHORT auth_type, CredHandle *cred, TimeStamp *exp, ULONG *max_token);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -52,6 +52,8 @@ typedef struct _RpcPacket
|
||||||
struct _RpcConnection* conn;
|
struct _RpcConnection* conn;
|
||||||
RpcPktHdr* hdr;
|
RpcPktHdr* hdr;
|
||||||
RPC_MESSAGE* msg;
|
RPC_MESSAGE* msg;
|
||||||
|
unsigned char *auth_data;
|
||||||
|
ULONG auth_length;
|
||||||
} RpcPacket;
|
} RpcPacket;
|
||||||
|
|
||||||
typedef struct _RpcObjTypeMap
|
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;
|
RPC_STATUS status;
|
||||||
RpcPktHdr *response;
|
|
||||||
RpcContextElement *ctxt_elem;
|
RpcContextElement *ctxt_elem;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
RpcResult *results;
|
||||||
|
|
||||||
|
/* validate data */
|
||||||
for (i = 0, ctxt_elem = msg->Buffer;
|
for (i = 0, ctxt_elem = msg->Buffer;
|
||||||
i < hdr->num_elements;
|
i < hdr->num_elements;
|
||||||
i++, ctxt_elem = (RpcContextElement *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes])
|
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",
|
ERR("inconsistent data in packet - packet length %d, num elements %d\n",
|
||||||
msg->BufferLength, hdr->num_elements);
|
msg->BufferLength, hdr->num_elements);
|
||||||
/* Report failure to client. */
|
return RPC_S_INVALID_BOUND;
|
||||||
response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
|
|
||||||
RPC_VER_MAJOR, RPC_VER_MINOR,
|
|
||||||
REJECT_REASON_NOT_SPECIFIED);
|
|
||||||
goto send;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,23 +233,13 @@ 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");
|
TRACE("packet size less than min size, or active interface syntax guid non-null\n");
|
||||||
|
|
||||||
/* Report failure to client. */
|
return RPC_S_INVALID_BOUND;
|
||||||
response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
|
|
||||||
RPC_VER_MAJOR, RPC_VER_MINOR,
|
|
||||||
REJECT_REASON_NOT_SPECIFIED);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
results = HeapAlloc(GetProcessHeap(), 0,
|
||||||
RpcResult *results = HeapAlloc(GetProcessHeap(), 0,
|
|
||||||
hdr->num_elements * sizeof(*results));
|
hdr->num_elements * sizeof(*results));
|
||||||
if (!results)
|
if (!results)
|
||||||
{
|
return RPC_S_OUT_OF_RESOURCES;
|
||||||
/* Report failure to client. */
|
|
||||||
response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
|
|
||||||
RPC_VER_MAJOR, RPC_VER_MINOR,
|
|
||||||
REJECT_LOCAL_LIMIT_EXCEEDED);
|
|
||||||
goto send;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0, ctxt_elem = (RpcContextElement *)msg->Buffer;
|
for (i = 0, ctxt_elem = (RpcContextElement *)msg->Buffer;
|
||||||
i < hdr->num_elements;
|
i < hdr->num_elements;
|
||||||
|
@ -230,7 +255,6 @@ static RPC_STATUS process_bind_packet(RpcConnection *conn, RpcPktBindHdr *hdr, R
|
||||||
if (sif)
|
if (sif)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sif)
|
if (sif)
|
||||||
{
|
{
|
||||||
RPCRT4_release_server_interface(sif);
|
RPCRT4_release_server_interface(sif);
|
||||||
|
@ -265,35 +289,70 @@ static RPC_STATUS process_bind_packet(RpcConnection *conn, RpcPktBindHdr *hdr, R
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create temporary binding */
|
/* create temporary binding */
|
||||||
if (RPCRT4_MakeBinding(&conn->server_binding, conn) == RPC_S_OK &&
|
status = RPCRT4_MakeBinding(&conn->server_binding, conn);
|
||||||
RpcServerAssoc_GetAssociation(rpcrt4_conn_get_name(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->NetworkAddr, conn->Endpoint,
|
||||||
conn->NetworkOptions,
|
conn->NetworkOptions,
|
||||||
hdr->assoc_gid,
|
hdr->assoc_gid,
|
||||||
&conn->server_binding->Assoc) == RPC_S_OK)
|
&conn->server_binding->Assoc);
|
||||||
|
if (status != RPC_S_OK)
|
||||||
{
|
{
|
||||||
response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION,
|
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,
|
||||||
RPC_MAX_PACKET_SIZE,
|
RPC_MAX_PACKET_SIZE,
|
||||||
conn->server_binding->Assoc->assoc_group_id,
|
conn->server_binding->Assoc->assoc_group_id,
|
||||||
conn->Endpoint, hdr->num_elements,
|
conn->Endpoint, hdr->num_elements,
|
||||||
results);
|
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);
|
HeapFree(GetProcessHeap(), 0, results);
|
||||||
}
|
|
||||||
|
|
||||||
send:
|
if (*ack_response)
|
||||||
|
conn->MaxTransmissionSize = hdr->max_tsize;
|
||||||
|
else
|
||||||
|
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)
|
if (response)
|
||||||
status = RPCRT4_Send(conn, response, NULL, 0);
|
status = RPCRT4_SendWithAuth(conn, response, NULL, 0, auth_data_out, auth_length_out);
|
||||||
else
|
else
|
||||||
status = ERROR_OUTOFMEMORY;
|
status = ERROR_OUTOFMEMORY;
|
||||||
RPCRT4_FreeHeader(response);
|
RPCRT4_FreeHeader(response);
|
||||||
|
@ -301,6 +360,7 @@ send:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static RPC_STATUS process_request_packet(RpcConnection *conn, RpcPktRequestHdr *hdr, RPC_MESSAGE *msg)
|
static RPC_STATUS process_request_packet(RpcConnection *conn, RpcPktRequestHdr *hdr, RPC_MESSAGE *msg)
|
||||||
{
|
{
|
||||||
RPC_STATUS status;
|
RPC_STATUS status;
|
||||||
|
@ -414,7 +474,34 @@ static RPC_STATUS process_request_packet(RpcConnection *conn, RpcPktRequestHdr *
|
||||||
return status;
|
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;
|
RPC_STATUS status;
|
||||||
|
|
||||||
|
@ -424,7 +511,8 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA
|
||||||
case PKT_BIND:
|
case PKT_BIND:
|
||||||
TRACE("got bind packet\n");
|
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;
|
break;
|
||||||
|
|
||||||
case PKT_REQUEST:
|
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);
|
status = process_request_packet(conn, &hdr->request, msg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PKT_AUTH3:
|
||||||
|
TRACE("got auth3 packet\n");
|
||||||
|
|
||||||
|
status = process_auth3_packet(conn, &hdr->common, msg, auth_data,
|
||||||
|
auth_length);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
FIXME("unhandled packet type %u\n", hdr->common.ptype);
|
FIXME("unhandled packet type %u\n", hdr->common.ptype);
|
||||||
break;
|
break;
|
||||||
|
@ -442,12 +536,14 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA
|
||||||
I_RpcFree(msg->Buffer);
|
I_RpcFree(msg->Buffer);
|
||||||
RPCRT4_FreeHeader(hdr);
|
RPCRT4_FreeHeader(hdr);
|
||||||
HeapFree(GetProcessHeap(), 0, msg);
|
HeapFree(GetProcessHeap(), 0, msg);
|
||||||
|
HeapFree(GetProcessHeap(), 0, auth_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg)
|
static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg)
|
||||||
{
|
{
|
||||||
RpcPacket *pkt = 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);
|
HeapFree(GetProcessHeap(), 0, pkt);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -459,13 +555,15 @@ static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
|
||||||
RPC_MESSAGE *msg;
|
RPC_MESSAGE *msg;
|
||||||
RPC_STATUS status;
|
RPC_STATUS status;
|
||||||
RpcPacket *packet;
|
RpcPacket *packet;
|
||||||
|
unsigned char *auth_data;
|
||||||
|
ULONG auth_length;
|
||||||
|
|
||||||
TRACE("(%p)\n", conn);
|
TRACE("(%p)\n", conn);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE));
|
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) {
|
if (status != RPC_S_OK) {
|
||||||
WARN("receive failed with error %x\n", status);
|
WARN("receive failed with error %x\n", status);
|
||||||
HeapFree(GetProcessHeap(), 0, msg);
|
HeapFree(GetProcessHeap(), 0, msg);
|
||||||
|
@ -482,12 +580,15 @@ static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
|
||||||
packet->conn = conn;
|
packet->conn = conn;
|
||||||
packet->hdr = hdr;
|
packet->hdr = hdr;
|
||||||
packet->msg = msg;
|
packet->msg = msg;
|
||||||
|
packet->auth_data = auth_data;
|
||||||
|
packet->auth_length = auth_length;
|
||||||
if (!QueueUserWorkItem(RPCRT4_worker_thread, packet, WT_EXECUTELONGFUNCTION)) {
|
if (!QueueUserWorkItem(RPCRT4_worker_thread, packet, WT_EXECUTELONGFUNCTION)) {
|
||||||
ERR("couldn't queue work item for worker thread, error was %d\n", GetLastError());
|
ERR("couldn't queue work item for worker thread, error was %d\n", GetLastError());
|
||||||
I_RpcFree(msg->Buffer);
|
I_RpcFree(msg->Buffer);
|
||||||
RPCRT4_FreeHeader(hdr);
|
RPCRT4_FreeHeader(hdr);
|
||||||
HeapFree(GetProcessHeap(), 0, msg);
|
HeapFree(GetProcessHeap(), 0, msg);
|
||||||
HeapFree(GetProcessHeap(), 0, packet);
|
HeapFree(GetProcessHeap(), 0, packet);
|
||||||
|
HeapFree(GetProcessHeap(), 0, auth_data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue