From d918587f1d15437f42ad57086f637668a95754a9 Mon Sep 17 00:00:00 2001 From: Rob Shearman Date: Sun, 13 Dec 2009 21:36:01 +0000 Subject: [PATCH] rpcrt4: Implement client impersonation. --- dlls/rpcrt4/rpc_binding.c | 32 +++++++++++++++------ dlls/rpcrt4/rpc_binding.h | 14 ++++++++++ dlls/rpcrt4/rpc_message.c | 56 +++++++++++++++++++++++++++++++++++++ dlls/rpcrt4/rpc_message.h | 2 ++ dlls/rpcrt4/rpc_transport.c | 50 +++++++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 8 deletions(-) diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c index a4dff4a7fa..68ab461cba 100644 --- a/dlls/rpcrt4/rpc_binding.c +++ b/dlls/rpcrt4/rpc_binding.c @@ -1052,9 +1052,17 @@ RPC_STATUS RPC_ENTRY RpcBindingReset(RPC_BINDING_HANDLE Binding) */ RPC_STATUS WINAPI RpcImpersonateClient(RPC_BINDING_HANDLE BindingHandle) { - FIXME("(%p): stub\n", BindingHandle); - ImpersonateSelf(SecurityImpersonation); - return RPC_S_OK; + RpcBinding *bind; + + TRACE("(%p)\n", BindingHandle); + + if (!BindingHandle) BindingHandle = I_RpcGetCurrentCallHandle(); + if (!BindingHandle) return RPC_S_INVALID_BINDING; + + bind = BindingHandle; + if (bind->FromConn) + return rpcrt4_conn_impersonate_client(bind->FromConn); + return RPC_S_WRONG_KIND_OF_BINDING; } /*********************************************************************** @@ -1077,8 +1085,17 @@ RPC_STATUS WINAPI RpcImpersonateClient(RPC_BINDING_HANDLE BindingHandle) */ RPC_STATUS WINAPI RpcRevertToSelfEx(RPC_BINDING_HANDLE BindingHandle) { - FIXME("(%p): stub\n", BindingHandle); - return RPC_S_OK; + RpcBinding *bind; + + TRACE("(%p)\n", BindingHandle); + + if (!BindingHandle) BindingHandle = I_RpcGetCurrentCallHandle(); + if (!BindingHandle) return RPC_S_INVALID_BINDING; + + bind = BindingHandle; + if (bind->FromConn) + return rpcrt4_conn_revert_to_self(bind->FromConn); + return RPC_S_WRONG_KIND_OF_BINDING; } static inline BOOL has_nt_auth_identity(ULONG AuthnLevel) @@ -1431,9 +1448,8 @@ BOOL RpcQualityOfService_IsEqual(const RpcQualityOfService *qos1, const RpcQuali */ RPC_STATUS WINAPI RpcRevertToSelf(void) { - FIXME("stub\n"); - RevertToSelf(); - return RPC_S_OK; + TRACE("\n"); + return RpcRevertToSelfEx(NULL); } /*********************************************************************** diff --git a/dlls/rpcrt4/rpc_binding.h b/dlls/rpcrt4/rpc_binding.h index fc3fd7dd65..908967cb13 100644 --- a/dlls/rpcrt4/rpc_binding.h +++ b/dlls/rpcrt4/rpc_binding.h @@ -109,6 +109,8 @@ struct connection_ops { 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); + RPC_STATUS (*impersonate_client)(RpcConnection *conn); + RPC_STATUS (*revert_to_self)(RpcConnection *conn); }; /* don't know what MS's structure looks like */ @@ -216,6 +218,18 @@ static inline RPC_STATUS rpcrt4_conn_secure_packet( return conn->ops->secure_packet(conn, dir, hdr, hdr_size, stub_data, stub_data_size, auth_hdr, auth_value, auth_value_size); } +static inline RPC_STATUS rpcrt4_conn_impersonate_client( + RpcConnection *conn) +{ + return conn->ops->impersonate_client(conn); +} + +static inline RPC_STATUS rpcrt4_conn_revert_to_self( + RpcConnection *conn) +{ + return conn->ops->revert_to_self(conn); +} + /* 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_ParseTopOfTower(const unsigned char *tower_data, size_t tower_size, char **protseq, char **networkaddr, char **endpoint); diff --git a/dlls/rpcrt4/rpc_message.c b/dlls/rpcrt4/rpc_message.c index 0f4b61c27b..520f247534 100644 --- a/dlls/rpcrt4/rpc_message.c +++ b/dlls/rpcrt4/rpc_message.c @@ -1120,6 +1120,62 @@ BOOL RPCRT4_default_is_authorized(RpcConnection *Connection) return Connection->AuthInfo && SecIsValidHandle(&Connection->ctx); } +/*********************************************************************** + * RPCRT4_default_impersonate_client (internal) + * + */ +RPC_STATUS RPCRT4_default_impersonate_client(RpcConnection *conn) +{ + SECURITY_STATUS sec_status; + + TRACE("(%p)\n", conn); + + if (!conn->AuthInfo || !SecIsValidHandle(&conn->ctx)) + return RPC_S_NO_CONTEXT_AVAILABLE; + sec_status = ImpersonateSecurityContext(&conn->ctx); + if (sec_status != SEC_E_OK) + WARN("ImpersonateSecurityContext returned 0x%08x\n", sec_status); + switch (sec_status) + { + case SEC_E_UNSUPPORTED_FUNCTION: + return RPC_S_CANNOT_SUPPORT; + case SEC_E_NO_IMPERSONATION: + return RPC_S_NO_CONTEXT_AVAILABLE; + case SEC_E_OK: + return RPC_S_OK; + default: + return RPC_S_SEC_PKG_ERROR; + } +} + +/*********************************************************************** + * RPCRT4_default_revert_to_self (internal) + * + */ +RPC_STATUS RPCRT4_default_revert_to_self(RpcConnection *conn) +{ + SECURITY_STATUS sec_status; + + TRACE("(%p)\n", conn); + + if (!conn->AuthInfo || !SecIsValidHandle(&conn->ctx)) + return RPC_S_NO_CONTEXT_AVAILABLE; + sec_status = RevertSecurityContext(&conn->ctx); + if (sec_status != SEC_E_OK) + WARN("RevertSecurityContext returned 0x%08x\n", sec_status); + switch (sec_status) + { + case SEC_E_UNSUPPORTED_FUNCTION: + return RPC_S_CANNOT_SUPPORT; + case SEC_E_NO_IMPERSONATION: + return RPC_S_NO_CONTEXT_AVAILABLE; + case SEC_E_OK: + return RPC_S_OK; + default: + return RPC_S_SEC_PKG_ERROR; + } +} + /*********************************************************************** * RPCRT4_Send (internal) * diff --git a/dlls/rpcrt4/rpc_message.h b/dlls/rpcrt4/rpc_message.h index 07a25817c5..2a441d6f35 100644 --- a/dlls/rpcrt4/rpc_message.h +++ b/dlls/rpcrt4/rpc_message.h @@ -53,5 +53,7 @@ RPC_STATUS RPCRT4_ServerGetRegisteredAuthInfo(USHORT auth_type, CredHandle *cred 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); +RPC_STATUS RPCRT4_default_impersonate_client(RpcConnection *conn); +RPC_STATUS RPCRT4_default_revert_to_self(RpcConnection *conn); #endif diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c index f8c8d1f774..6dbac41458 100644 --- a/dlls/rpcrt4/rpc_transport.c +++ b/dlls/rpcrt4/rpc_transport.c @@ -586,6 +586,48 @@ static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_ return RPC_S_OK; } +static RPC_STATUS rpcrt4_conn_np_impersonate_client(RpcConnection *conn) +{ + RpcConnection_np *npc = (RpcConnection_np *)conn; + BOOL ret; + + TRACE("(%p)\n", conn); + + if (conn->AuthInfo && SecIsValidHandle(&conn->ctx)) + return RPCRT4_default_impersonate_client(conn); + + ret = ImpersonateNamedPipeClient(npc->pipe); + if (!ret) + { + DWORD error = GetLastError(); + WARN("ImpersonateNamedPipeClient failed with error %u\n", error); + switch (error) + { + case ERROR_CANNOT_IMPERSONATE: + return RPC_S_NO_CONTEXT_AVAILABLE; + } + } + return RPC_S_OK; +} + +static RPC_STATUS rpcrt4_conn_np_revert_to_self(RpcConnection *conn) +{ + BOOL ret; + + TRACE("(%p)\n", conn); + + if (conn->AuthInfo && SecIsValidHandle(&conn->ctx)) + return RPCRT4_default_revert_to_self(conn); + + ret = RevertToSelf(); + if (!ret) + { + WARN("RevertToSelf failed with error %u\n", GetLastError()); + return RPC_S_NO_CONTEXT_AVAILABLE; + } + return RPC_S_OK; +} + typedef struct _RpcServerProtseq_np { RpcServerProtseq common; @@ -2709,6 +2751,8 @@ static const struct connection_ops conn_protseq_list[] = { RPCRT4_default_is_authorized, RPCRT4_default_authorize, RPCRT4_default_secure_packet, + rpcrt4_conn_np_impersonate_client, + rpcrt4_conn_np_revert_to_self, }, { "ncalrpc", { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE }, @@ -2726,6 +2770,8 @@ static const struct connection_ops conn_protseq_list[] = { rpcrt4_ncalrpc_is_authorized, rpcrt4_ncalrpc_authorize, rpcrt4_ncalrpc_secure_packet, + rpcrt4_conn_np_impersonate_client, + rpcrt4_conn_np_revert_to_self, }, { "ncacn_ip_tcp", { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP }, @@ -2743,6 +2789,8 @@ static const struct connection_ops conn_protseq_list[] = { RPCRT4_default_is_authorized, RPCRT4_default_authorize, RPCRT4_default_secure_packet, + RPCRT4_default_impersonate_client, + RPCRT4_default_revert_to_self, }, { "ncacn_http", { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP }, @@ -2760,6 +2808,8 @@ static const struct connection_ops conn_protseq_list[] = { RPCRT4_default_is_authorized, RPCRT4_default_authorize, RPCRT4_default_secure_packet, + RPCRT4_default_impersonate_client, + RPCRT4_default_revert_to_self, }, }; -- 2.32.0.93.g670b81a890