rpcrt4: Add support for server-side authentication.

This commit is contained in:
Rob Shearman 2009-12-13 21:35:39 +00:00 committed by Alexandre Julliard
parent ceb7fda374
commit e27e61db71
6 changed files with 383 additions and 150 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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;
}