rpcrt4: Allow the connection to override the authentication mechanism for a connection type.

This commit is contained in:
Rob Shearman 2009-12-13 21:35:47 +00:00 committed by Alexandre Julliard
parent a65f7b637a
commit deae193ac8
4 changed files with 136 additions and 54 deletions

View File

@ -27,6 +27,12 @@
#include "rpc_defs.h" #include "rpc_defs.h"
enum secure_packet_direction
{
SECURE_PACKET_SEND,
SECURE_PACKET_RECEIVE
};
typedef struct _RpcAuthInfo typedef struct _RpcAuthInfo
{ {
LONG refs; LONG refs;
@ -100,6 +106,9 @@ struct connection_ops {
size_t (*get_top_of_tower)(unsigned char *tower_data, const char *networkaddr, const char *endpoint); size_t (*get_top_of_tower)(unsigned char *tower_data, const char *networkaddr, const char *endpoint);
RPC_STATUS (*parse_top_of_tower)(const unsigned char *tower_data, size_t tower_size, char **networkaddr, char **endpoint); RPC_STATUS (*parse_top_of_tower)(const unsigned char *tower_data, size_t tower_size, char **networkaddr, char **endpoint);
RPC_STATUS (*receive_fragment)(RpcConnection *conn, RpcPktHdr **Header, void **Payload); RPC_STATUS (*receive_fragment)(RpcConnection *conn, RpcPktHdr **Header, void **Payload);
BOOL (*is_authorized)(RpcConnection *conn);
RPC_STATUS (*authorize)(RpcConnection *conn, BOOL first_time, unsigned char *in_buffer, unsigned int in_len, unsigned char *out_buffer, unsigned int *out_len);
RPC_STATUS (*secure_packet)(RpcConnection *Connection, enum secure_packet_direction dir, RpcPktHdr *hdr, unsigned int hdr_size, unsigned char *stub_data, unsigned int stub_data_size, RpcAuthVerifier *auth_hdr, unsigned char *auth_value, unsigned int auth_value_size);
}; };
/* don't know what MS's structure looks like */ /* don't know what MS's structure looks like */
@ -186,6 +195,27 @@ static inline RPC_STATUS rpcrt4_conn_handoff(RpcConnection *old_conn, RpcConnect
return old_conn->ops->handoff(old_conn, new_conn); return old_conn->ops->handoff(old_conn, new_conn);
} }
static inline BOOL rpcrt4_conn_is_authorized(RpcConnection *Connection)
{
return Connection->ops->is_authorized(Connection);
}
static inline RPC_STATUS rpcrt4_conn_authorize(
RpcConnection *conn, BOOL first_time, unsigned char *in_buffer,
unsigned int in_len, unsigned char *out_buffer, unsigned int *out_len)
{
return conn->ops->authorize(conn, first_time, in_buffer, in_len, out_buffer, out_len);
}
static inline RPC_STATUS rpcrt4_conn_secure_packet(
RpcConnection *conn, enum secure_packet_direction dir,
RpcPktHdr *hdr, unsigned int hdr_size, unsigned char *stub_data,
unsigned int stub_data_size, RpcAuthVerifier *auth_hdr,
unsigned char *auth_value, unsigned int auth_value_size)
{
return conn->ops->secure_packet(conn, dir, hdr, hdr_size, stub_data, stub_data_size, auth_hdr, auth_value, auth_value_size);
}
/* floors 3 and up */ /* floors 3 and up */
RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data, size_t *tower_size, const char *protseq, const char *networkaddr, const char *endpoint); RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data, size_t *tower_size, const char *protseq, const char *networkaddr, const char *endpoint);
RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data, size_t tower_size, char **protseq, char **networkaddr, char **endpoint); RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data, size_t tower_size, char **protseq, char **networkaddr, char **endpoint);

View File

@ -51,12 +51,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(rpc);
(((alignment) - (((value) % (alignment)))) % (alignment)) (((alignment) - (((value) % (alignment)))) % (alignment))
#define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1)) #define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1))
enum secure_packet_direction
{
SECURE_PACKET_SEND,
SECURE_PACKET_RECEIVE
};
static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg); static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg);
DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header) DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header)
@ -684,7 +678,7 @@ RPC_STATUS RPCRT4_ParseHttpFlowControlHeader(RpcPktHdr *header,
} }
static RPC_STATUS RPCRT4_SecurePacket(RpcConnection *Connection, RPC_STATUS RPCRT4_default_secure_packet(RpcConnection *Connection,
enum secure_packet_direction dir, enum secure_packet_direction dir,
RpcPktHdr *hdr, unsigned int hdr_size, RpcPktHdr *hdr, unsigned int hdr_size,
unsigned char *stub_data, unsigned int stub_data_size, unsigned char *stub_data, unsigned int stub_data_size,
@ -837,7 +831,7 @@ RPC_STATUS RPCRT4_SendWithAuth(RpcConnection *Connection, RpcPktHdr *Header,
memcpy(auth_hdr + 1, Auth, AuthLength); memcpy(auth_hdr + 1, Auth, AuthLength);
else else
{ {
status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_SEND, status = rpcrt4_conn_secure_packet(Connection, SECURE_PACKET_SEND,
(RpcPktHdr *)pkt, hdr_size, (RpcPktHdr *)pkt, hdr_size,
pkt + hdr_size, Header->common.frag_len - hdr_size - alen, pkt + hdr_size, Header->common.frag_len - hdr_size - alen,
auth_hdr, auth_hdr,
@ -870,12 +864,15 @@ write:
} }
/*********************************************************************** /***********************************************************************
* RPCRT4_Authorize (internal) * RPCRT4_default_authorize (internal)
* *
* Authorize a client connection. * Authorize a client connection.
*/ */
static RPC_STATUS RPCRT4_Authorize(RpcConnection *conn, BOOL first_time, RPC_STATUS RPCRT4_default_authorize(RpcConnection *conn, BOOL first_time,
SecBuffer *in, SecBuffer *out) unsigned char *in_buffer,
unsigned int in_size,
unsigned char *out_buffer,
unsigned int *out_size)
{ {
SECURITY_STATUS r; SECURITY_STATUS r;
SecBufferDesc out_desc; SecBufferDesc out_desc;
@ -883,19 +880,29 @@ static RPC_STATUS RPCRT4_Authorize(RpcConnection *conn, BOOL first_time,
SecPkgContext_Sizes secctx_sizes; SecPkgContext_Sizes secctx_sizes;
BOOL continue_needed; BOOL continue_needed;
ULONG context_req; ULONG context_req;
SecBuffer in, out;
out->BufferType = SECBUFFER_TOKEN; if (!out_buffer)
out->cbBuffer = conn->AuthInfo->cbMaxToken; {
out->pvBuffer = HeapAlloc(GetProcessHeap(), 0, out->cbBuffer); *out_size = conn->AuthInfo->cbMaxToken;
if (!out->pvBuffer) return ERROR_OUTOFMEMORY; return RPC_S_OK;
}
in.BufferType = SECBUFFER_TOKEN;
in.pvBuffer = in_buffer;
in.cbBuffer = in_size;
out.BufferType = SECBUFFER_TOKEN;
out.pvBuffer = out_buffer;
out.cbBuffer = *out_size;
out_desc.ulVersion = 0; out_desc.ulVersion = 0;
out_desc.cBuffers = 1; out_desc.cBuffers = 1;
out_desc.pBuffers = out; out_desc.pBuffers = &out;
inp_desc.cBuffers = 1;
inp_desc.pBuffers = in;
inp_desc.ulVersion = 0; inp_desc.ulVersion = 0;
inp_desc.cBuffers = 1;
inp_desc.pBuffers = ∈
if (conn->server) if (conn->server)
{ {
@ -915,8 +922,7 @@ static RPC_STATUS RPCRT4_Authorize(RpcConnection *conn, BOOL first_time,
if (r == SEC_E_OK || r == SEC_I_COMPLETE_NEEDED) if (r == SEC_E_OK || r == SEC_I_COMPLETE_NEEDED)
{ {
/* authorisation done, so nothing more to send */ /* authorisation done, so nothing more to send */
HeapFree(GetProcessHeap(), 0, out->pvBuffer); out.cbBuffer = 0;
out->cbBuffer = 0;
} }
} }
else else
@ -933,7 +939,7 @@ static RPC_STATUS RPCRT4_Authorize(RpcConnection *conn, BOOL first_time,
first_time ? NULL: &conn->ctx, first_time ? NULL: &conn->ctx,
first_time ? conn->AuthInfo->server_principal_name : NULL, first_time ? conn->AuthInfo->server_principal_name : NULL,
context_req, 0, SECURITY_NETWORK_DREP, context_req, 0, SECURITY_NETWORK_DREP,
in ? &inp_desc : NULL, 0, &conn->ctx, first_time ? NULL : &inp_desc, 0, &conn->ctx,
&out_desc, &conn->attr, &conn->exp); &out_desc, &conn->attr, &conn->exp);
} }
if (FAILED(r)) if (FAILED(r))
@ -957,7 +963,7 @@ static RPC_STATUS RPCRT4_Authorize(RpcConnection *conn, BOOL first_time,
} }
} }
TRACE("cbBuffer = %d\n", out->cbBuffer); TRACE("cbBuffer = %d\n", out.cbBuffer);
if (!continue_needed) if (!continue_needed)
{ {
@ -971,11 +977,11 @@ static RPC_STATUS RPCRT4_Authorize(RpcConnection *conn, BOOL first_time,
conn->encryption_auth_len = secctx_sizes.cbSecurityTrailer; conn->encryption_auth_len = secctx_sizes.cbSecurityTrailer;
} }
*out_size = out.cbBuffer;
return RPC_S_OK; return RPC_S_OK;
failed: failed:
HeapFree(GetProcessHeap(), 0, out->pvBuffer); *out_size = 0;
out->pvBuffer = NULL;
return ERROR_ACCESS_DENIED; /* FIXME: is this correct? */ return ERROR_ACCESS_DENIED; /* FIXME: is this correct? */
} }
@ -985,26 +991,28 @@ failed:
RPC_STATUS RPCRT4_ClientConnectionAuth(RpcConnection* conn, BYTE *challenge, RPC_STATUS RPCRT4_ClientConnectionAuth(RpcConnection* conn, BYTE *challenge,
ULONG count) ULONG count)
{ {
SecBuffer inp, out;
RpcPktHdr *resp_hdr; RpcPktHdr *resp_hdr;
RPC_STATUS status; RPC_STATUS status;
unsigned char *out_buffer;
unsigned int out_len = 0;
TRACE("challenge %s, %d bytes\n", challenge, count); TRACE("challenge %s, %d bytes\n", challenge, count);
inp.BufferType = SECBUFFER_TOKEN; status = rpcrt4_conn_authorize(conn, FALSE, challenge, count, NULL, &out_len);
inp.pvBuffer = challenge; if (status) return status;
inp.cbBuffer = count; out_buffer = HeapAlloc(GetProcessHeap(), 0, out_len);
if (!out_buffer) return RPC_S_OUT_OF_RESOURCES;
status = RPCRT4_Authorize(conn, FALSE, &inp, &out); status = rpcrt4_conn_authorize(conn, FALSE, challenge, count, out_buffer, &out_len);
if (status) return status; if (status) return status;
resp_hdr = RPCRT4_BuildAuthHeader(NDR_LOCAL_DATA_REPRESENTATION); resp_hdr = RPCRT4_BuildAuthHeader(NDR_LOCAL_DATA_REPRESENTATION);
if (!resp_hdr)
return E_OUTOFMEMORY;
status = RPCRT4_SendWithAuth(conn, resp_hdr, NULL, 0, out.pvBuffer, out.cbBuffer); if (resp_hdr)
status = RPCRT4_SendWithAuth(conn, resp_hdr, NULL, 0, out_buffer, out_len);
else
status = RPC_S_OUT_OF_RESOURCES;
HeapFree(GetProcessHeap(), 0, out.pvBuffer); HeapFree(GetProcessHeap(), 0, out_buffer);
RPCRT4_FreeHeader(resp_hdr); RPCRT4_FreeHeader(resp_hdr);
return status; return status;
@ -1020,7 +1028,8 @@ RPC_STATUS RPCRT4_ServerConnectionAuth(RpcConnection* conn,
unsigned char **auth_data_out, unsigned char **auth_data_out,
ULONG *auth_length_out) ULONG *auth_length_out)
{ {
SecBuffer inp, out; unsigned char *out_buffer;
unsigned int out_size;
RPC_STATUS status; RPC_STATUS status;
if (start) if (start)
@ -1068,29 +1077,49 @@ RPC_STATUS RPCRT4_ServerConnectionAuth(RpcConnection* conn,
/* should have filled in authentication info by now */ /* should have filled in authentication info by now */
return RPC_S_PROTOCOL_ERROR; return RPC_S_PROTOCOL_ERROR;
inp.BufferType = SECBUFFER_TOKEN; status = rpcrt4_conn_authorize(
inp.pvBuffer = auth_data_in + 1; conn, start, (unsigned char *)(auth_data_in + 1),
inp.cbBuffer = auth_length_in - sizeof(RpcAuthVerifier); auth_length_in - sizeof(RpcAuthVerifier), NULL, &out_size);
status = RPCRT4_Authorize(conn, start, &inp, &out);
if (status) return status; if (status) return status;
if (out.cbBuffer && !auth_length_out) out_buffer = HeapAlloc(GetProcessHeap(), 0, out_size);
if (!out_buffer) return RPC_S_OUT_OF_RESOURCES;
status = rpcrt4_conn_authorize(
conn, start, (unsigned char *)(auth_data_in + 1),
auth_length_in - sizeof(RpcAuthVerifier), out_buffer, &out_size);
if (status != RPC_S_OK)
{
HeapFree(GetProcessHeap(), 0, out_buffer);
return status;
}
if (out_size && !auth_length_out)
{ {
ERR("expected authentication to be complete but SSP returned data of " ERR("expected authentication to be complete but SSP returned data of "
"%u bytes to be sent back to client\n", out.cbBuffer); "%u bytes to be sent back to client\n", out_size);
HeapFree(GetProcessHeap(), 0, out.pvBuffer); HeapFree(GetProcessHeap(), 0, out_buffer);
return RPC_S_SEC_PKG_ERROR; return RPC_S_SEC_PKG_ERROR;
} }
else else
{ {
*auth_data_out = out.pvBuffer; *auth_data_out = out_buffer;
*auth_length_out = out.cbBuffer; *auth_length_out = out_size;
} }
return status; return status;
} }
/***********************************************************************
* RPCRT4_default_is_authorized (internal)
*
* Has a connection started the process of authorizing with the server?
*/
BOOL RPCRT4_default_is_authorized(RpcConnection *Connection)
{
return Connection->AuthInfo && SecIsValidHandle(&Connection->ctx);
}
/*********************************************************************** /***********************************************************************
* RPCRT4_Send (internal) * RPCRT4_Send (internal)
* *
@ -1100,18 +1129,26 @@ RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header,
void *Buffer, unsigned int BufferLength) void *Buffer, unsigned int BufferLength)
{ {
RPC_STATUS r; RPC_STATUS r;
SecBuffer out;
if (packet_does_auth_negotiation(Header) && if (packet_does_auth_negotiation(Header) &&
Connection->AuthInfo && !SecIsValidHandle(&Connection->ctx)) Connection->AuthInfo &&
!rpcrt4_conn_is_authorized(Connection))
{ {
unsigned int out_size = 0;
unsigned char *out_buffer;
r = rpcrt4_conn_authorize(Connection, TRUE, NULL, 0, NULL, &out_size);
if (r != RPC_S_OK) return r;
out_buffer = HeapAlloc(GetProcessHeap(), 0, out_size);
if (!out_buffer) return RPC_S_OUT_OF_RESOURCES;
/* tack on a negotiate packet */ /* tack on a negotiate packet */
r = RPCRT4_Authorize(Connection, TRUE, NULL, &out); r = rpcrt4_conn_authorize(Connection, TRUE, NULL, 0, out_buffer, &out_size);
if (r == RPC_S_OK) if (r == RPC_S_OK)
{ r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, out_buffer, out_size);
r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, out.pvBuffer, out.cbBuffer);
HeapFree(GetProcessHeap(), 0, out.pvBuffer); HeapFree(GetProcessHeap(), 0, out_buffer);
}
} }
else else
r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, NULL, 0); r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, NULL, 0);
@ -1357,9 +1394,9 @@ 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 (!packet_does_auth_negotiation(*Header) && SecIsValidHandle(&Connection->ctx)) if (!packet_does_auth_negotiation(*Header) && rpcrt4_conn_is_authorized(Connection))
{ {
status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_RECEIVE, status = rpcrt4_conn_secure_packet(Connection, SECURE_PACKET_RECEIVE,
CurrentHeader, hdr_length, CurrentHeader, hdr_length,
(unsigned char *)pMsg->Buffer + buffer_length, data_length, (unsigned char *)pMsg->Buffer + buffer_length, data_length,
(RpcAuthVerifier *)auth_data, (RpcAuthVerifier *)auth_data,

View File

@ -50,5 +50,8 @@ RPC_STATUS RPCRT4_ClientConnectionAuth(RpcConnection* conn, BYTE *challenge, ULO
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_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); RPC_STATUS RPCRT4_ServerGetRegisteredAuthInfo(USHORT auth_type, CredHandle *cred, TimeStamp *exp, ULONG *max_token);
RPC_STATUS RPCRT4_default_authorize(RpcConnection *conn, BOOL first_time, unsigned char *in_buffer, unsigned int in_size, unsigned char *out_buffer, unsigned int *out_size);
BOOL RPCRT4_default_is_authorized(RpcConnection *Connection);
RPC_STATUS RPCRT4_default_secure_packet(RpcConnection *Connection, enum secure_packet_direction dir, RpcPktHdr *hdr, unsigned int hdr_size, unsigned char *stub_data, unsigned int stub_data_size, RpcAuthVerifier *auth_hdr, unsigned char *auth_value, unsigned int auth_value_size);
#endif #endif

View File

@ -2677,6 +2677,9 @@ static const struct connection_ops conn_protseq_list[] = {
rpcrt4_ncacn_np_get_top_of_tower, rpcrt4_ncacn_np_get_top_of_tower,
rpcrt4_ncacn_np_parse_top_of_tower, rpcrt4_ncacn_np_parse_top_of_tower,
NULL, NULL,
RPCRT4_default_is_authorized,
RPCRT4_default_authorize,
RPCRT4_default_secure_packet,
}, },
{ "ncalrpc", { "ncalrpc",
{ EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE }, { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
@ -2691,6 +2694,9 @@ static const struct connection_ops conn_protseq_list[] = {
rpcrt4_ncalrpc_get_top_of_tower, rpcrt4_ncalrpc_get_top_of_tower,
rpcrt4_ncalrpc_parse_top_of_tower, rpcrt4_ncalrpc_parse_top_of_tower,
NULL, NULL,
RPCRT4_default_is_authorized,
RPCRT4_default_authorize,
RPCRT4_default_secure_packet,
}, },
{ "ncacn_ip_tcp", { "ncacn_ip_tcp",
{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP }, { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
@ -2705,6 +2711,9 @@ static const struct connection_ops conn_protseq_list[] = {
rpcrt4_ncacn_ip_tcp_get_top_of_tower, rpcrt4_ncacn_ip_tcp_get_top_of_tower,
rpcrt4_ncacn_ip_tcp_parse_top_of_tower, rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
NULL, NULL,
RPCRT4_default_is_authorized,
RPCRT4_default_authorize,
RPCRT4_default_secure_packet,
}, },
{ "ncacn_http", { "ncacn_http",
{ EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP }, { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP },
@ -2719,6 +2728,9 @@ static const struct connection_ops conn_protseq_list[] = {
rpcrt4_ncacn_http_get_top_of_tower, rpcrt4_ncacn_http_get_top_of_tower,
rpcrt4_ncacn_http_parse_top_of_tower, rpcrt4_ncacn_http_parse_top_of_tower,
rpcrt4_ncacn_http_receive_fragment, rpcrt4_ncacn_http_receive_fragment,
RPCRT4_default_is_authorized,
RPCRT4_default_authorize,
RPCRT4_default_secure_packet,
}, },
}; };