From 4b79a0252a67d8085700524cfcca45e7420da234 Mon Sep 17 00:00:00 2001 From: Rob Shearman Date: Fri, 19 Jan 2007 06:59:35 -0600 Subject: [PATCH] rpcrt4: Track the security quality of service settings for bindings and connections. --- dlls/rpcrt4/rpc_binding.c | 164 +++++++++++++++++++++++++++++++++++- dlls/rpcrt4/rpc_binding.h | 15 +++- dlls/rpcrt4/rpc_transport.c | 19 +++-- 3 files changed, 188 insertions(+), 10 deletions(-) diff --git a/dlls/rpcrt4/rpc_binding.c b/dlls/rpcrt4/rpc_binding.c index 7b55f21837d..691f3786e11 100644 --- a/dlls/rpcrt4/rpc_binding.c +++ b/dlls/rpcrt4/rpc_binding.c @@ -224,6 +224,8 @@ RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding) RPCRT4_strfree(Binding->Endpoint); RPCRT4_strfree(Binding->NetworkAddr); RPCRT4_strfree(Binding->Protseq); + if (Binding->AuthInfo) RpcAuthInfo_Release(Binding->AuthInfo); + if (Binding->QOS) RpcQualityOfService_Release(Binding->QOS); HeapFree(GetProcessHeap(), 0, Binding); return RPC_S_OK; } @@ -241,7 +243,7 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, /* try to find a compatible connection from the connection pool */ NewConnection = RPCRT4_GetIdleConnection(InterfaceId, TransferSyntax, Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint, - Binding->AuthInfo); + Binding->AuthInfo, Binding->QOS); if (NewConnection) { *Connection = NewConnection; return RPC_S_OK; @@ -258,7 +260,7 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, status = RPCRT4_CreateConnection(&NewConnection, Binding->server, Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint, NULL, Binding->AuthInfo, - Binding); + Binding->QOS, Binding); if (status != RPC_S_OK) return status; @@ -874,6 +876,8 @@ RPC_STATUS RPC_ENTRY RpcBindingCopy( if (SrcBinding->AuthInfo) RpcAuthInfo_AddRef(SrcBinding->AuthInfo); DestBinding->AuthInfo = SrcBinding->AuthInfo; + if (SrcBinding->QOS) RpcQualityOfService_AddRef(SrcBinding->QOS); + DestBinding->QOS = SrcBinding->QOS; *DestinationBinding = DestBinding; return RPC_S_OK; @@ -934,6 +938,7 @@ static RPC_STATUS RpcAuthInfo_Create(unsigned long AuthnLevel, unsigned long Aut if (!AuthInfo) return ERROR_OUTOFMEMORY; + AuthInfo->refs = 1; AuthInfo->AuthnLevel = AuthnLevel; AuthInfo->AuthnSvc = AuthnSvc; AuthInfo->cred = cred; @@ -960,6 +965,101 @@ ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo) return refs; } +static RPC_STATUS RpcQualityOfService_Create(const RPC_SECURITY_QOS *qos_src, BOOL unicode, RpcQualityOfService **qos_dst) +{ + RpcQualityOfService *qos = HeapAlloc(GetProcessHeap(), 0, sizeof(*qos)); + + if (!qos) + return RPC_S_OUT_OF_RESOURCES; + + qos->refs = 1; + qos->qos = HeapAlloc(GetProcessHeap(), 0, sizeof(*qos->qos)); + if (!qos->qos) goto error; + qos->qos->Version = qos_src->Version; + qos->qos->Capabilities = qos_src->Capabilities; + qos->qos->IdentityTracking = qos_src->IdentityTracking; + qos->qos->ImpersonationType = qos_src->ImpersonationType; + qos->qos->AdditionalSecurityInfoType = 0; + + if (qos_src->Version >= 2) + { + const RPC_SECURITY_QOS_V2_W *qos_src2 = (const RPC_SECURITY_QOS_V2_W *)qos_src; + qos->qos->AdditionalSecurityInfoType = qos_src2->AdditionalSecurityInfoType; + if (qos_src2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + { + const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials_src = qos_src2->u.HttpCredentials; + RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials_dst; + + http_credentials_dst = HeapAlloc(GetProcessHeap(), 0, sizeof(*http_credentials_dst)); + qos->qos->u.HttpCredentials = http_credentials_dst; + if (!http_credentials_dst) goto error; + http_credentials_dst->TransportCredentials = http_credentials_src->TransportCredentials; + http_credentials_dst->Flags = http_credentials_src->Flags; + http_credentials_dst->AuthenticationTarget = http_credentials_src->AuthenticationTarget; + http_credentials_dst->NumberOfAuthnSchemes = http_credentials_src->NumberOfAuthnSchemes; + http_credentials_dst->AuthnSchemes = NULL; + http_credentials_dst->ServerCertificateSubject = NULL; + if (http_credentials_src->NumberOfAuthnSchemes) + { + http_credentials_dst->AuthnSchemes = HeapAlloc(GetProcessHeap(), 0, http_credentials_src->NumberOfAuthnSchemes * sizeof(*http_credentials_dst->AuthnSchemes)); + if (!http_credentials_dst->AuthnSchemes) goto error; + memcpy(http_credentials_dst->AuthnSchemes, http_credentials_src->AuthnSchemes, http_credentials_src->NumberOfAuthnSchemes * sizeof(*http_credentials_dst->AuthnSchemes)); + } + if (http_credentials_src->ServerCertificateSubject) + { + if (unicode) + http_credentials_dst->ServerCertificateSubject = + RPCRT4_strndupW(http_credentials_src->ServerCertificateSubject, + strlenW(http_credentials_src->ServerCertificateSubject)); + else + http_credentials_dst->ServerCertificateSubject = + RPCRT4_strdupAtoW((char *)http_credentials_src->ServerCertificateSubject); + if (!http_credentials_dst->ServerCertificateSubject) goto error; + } + } + } + *qos_dst = qos; + return RPC_S_OK; + +error: + if (qos->qos) + { + if (qos->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP && + qos->qos->u.HttpCredentials) + { + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->AuthnSchemes); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->ServerCertificateSubject); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials); + } + HeapFree(GetProcessHeap(), 0, qos->qos); + } + HeapFree(GetProcessHeap(), 0, qos); + return RPC_S_OUT_OF_RESOURCES; +} + +ULONG RpcQualityOfService_AddRef(RpcQualityOfService *qos) +{ + return InterlockedIncrement(&qos->refs); +} + +ULONG RpcQualityOfService_Release(RpcQualityOfService *qos) +{ + ULONG refs = InterlockedDecrement(&qos->refs); + + if (!refs) + { + if (qos->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + { + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->AuthnSchemes); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->ServerCertificateSubject); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials); + } + HeapFree(GetProcessHeap(), 0, qos->qos); + HeapFree(GetProcessHeap(), 0, qos); + } + return refs; +} + /*********************************************************************** * RpcRevertToSelf (RPCRT4.@) */ @@ -1049,6 +1149,36 @@ RpcBindingSetAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName, TRACE("%p %s %lu %lu %p %lu %p\n", Binding, debugstr_a((const char*)ServerPrincName), AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos); + if (SecurityQos) + { + RPC_STATUS status; + + TRACE("SecurityQos { Version=%ld, Capabilties=0x%lx, IdentityTracking=%ld, ImpersonationLevel=%ld", + SecurityQos->Version, SecurityQos->Capabilities, SecurityQos->IdentityTracking, SecurityQos->ImpersonationType); + if (SecurityQos->Version >= 2) + { + const RPC_SECURITY_QOS_V2_A *SecurityQos2 = (const RPC_SECURITY_QOS_V2_A *)SecurityQos; + TRACE(", AdditionalSecurityInfoType=%ld", SecurityQos2->AdditionalSecurityInfoType); + if (SecurityQos2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + TRACE(", { %p, 0x%lx, %ld, %ld, %p, %s }", + SecurityQos2->u.HttpCredentials->TransportCredentials, + SecurityQos2->u.HttpCredentials->Flags, + SecurityQos2->u.HttpCredentials->AuthenticationTarget, + SecurityQos2->u.HttpCredentials->NumberOfAuthnSchemes, + SecurityQos2->u.HttpCredentials->AuthnSchemes, + SecurityQos2->u.HttpCredentials->ServerCertificateSubject); + } + TRACE("}\n"); + status = RpcQualityOfService_Create(SecurityQos, FALSE, &bind->QOS); + if (status != RPC_S_OK) + return status; + } + else + { + if (bind->QOS) RpcQualityOfService_Release(bind->QOS); + bind->QOS = NULL; + } + if (AuthnSvc == RPC_C_AUTHN_DEFAULT) AuthnSvc = RPC_C_AUTHN_WINNT; @@ -1135,6 +1265,36 @@ RpcBindingSetAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, TRACE("%p %s %lu %lu %p %lu %p\n", Binding, debugstr_w((const WCHAR*)ServerPrincName), AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos); + if (SecurityQos) + { + RPC_STATUS status; + + TRACE("SecurityQos { Version=%ld, Capabilties=0x%lx, IdentityTracking=%ld, ImpersonationLevel=%ld", + SecurityQos->Version, SecurityQos->Capabilities, SecurityQos->IdentityTracking, SecurityQos->ImpersonationType); + if (SecurityQos->Version >= 2) + { + const RPC_SECURITY_QOS_V2_W *SecurityQos2 = (const RPC_SECURITY_QOS_V2_W *)SecurityQos; + TRACE(", AdditionalSecurityInfoType=%ld", SecurityQos2->AdditionalSecurityInfoType); + if (SecurityQos2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + TRACE(", { %p, 0x%lx, %ld, %ld, %p, %s }", + SecurityQos2->u.HttpCredentials->TransportCredentials, + SecurityQos2->u.HttpCredentials->Flags, + SecurityQos2->u.HttpCredentials->AuthenticationTarget, + SecurityQos2->u.HttpCredentials->NumberOfAuthnSchemes, + SecurityQos2->u.HttpCredentials->AuthnSchemes, + debugstr_w(SecurityQos2->u.HttpCredentials->ServerCertificateSubject)); + } + TRACE("}\n"); + status = RpcQualityOfService_Create(SecurityQos, TRUE, &bind->QOS); + if (status != RPC_S_OK) + return status; + } + else + { + if (bind->QOS) RpcQualityOfService_Release(bind->QOS); + bind->QOS = NULL; + } + if (AuthnSvc == RPC_C_AUTHN_DEFAULT) AuthnSvc = RPC_C_AUTHN_WINNT; diff --git a/dlls/rpcrt4/rpc_binding.h b/dlls/rpcrt4/rpc_binding.h index 4df3d7326dc..6b5ca216584 100644 --- a/dlls/rpcrt4/rpc_binding.h +++ b/dlls/rpcrt4/rpc_binding.h @@ -36,6 +36,13 @@ typedef struct _RpcAuthInfo TimeStamp exp; } RpcAuthInfo; +typedef struct _RpcQualityOfService +{ + LONG refs; + + RPC_SECURITY_QOS_V2_W *qos; +} RpcQualityOfService; + struct connection_ops; typedef struct _RpcConnection @@ -56,6 +63,7 @@ typedef struct _RpcConnection TimeStamp exp; ULONG attr; RpcAuthInfo *AuthInfo; + RpcQualityOfService *QOS; /* client-only */ struct list conn_pool_entry; @@ -90,6 +98,7 @@ typedef struct _RpcBinding /* authentication */ RpcAuthInfo *AuthInfo; + RpcQualityOfService *QOS; } RpcBinding; LPSTR RPCRT4_strndupA(LPCSTR src, INT len); @@ -103,10 +112,12 @@ void RPCRT4_strfree(LPSTR src); ULONG RpcAuthInfo_AddRef(RpcAuthInfo *AuthInfo); ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo); +ULONG RpcQualityOfService_AddRef(RpcQualityOfService *qos); +ULONG RpcQualityOfService_Release(RpcQualityOfService *qos); -RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, RpcAuthInfo* AuthInfo); +RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, const RpcAuthInfo* AuthInfo, const RpcQualityOfService *QOS); void RPCRT4_ReleaseIdleConnection(RpcConnection *Connection); -RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcBinding* Binding); +RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, RpcBinding* Binding); RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection); RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection); RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection); diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c index ceae31d60ee..7f6d8a254b1 100644 --- a/dlls/rpcrt4/rpc_transport.c +++ b/dlls/rpcrt4/rpc_transport.c @@ -219,7 +219,7 @@ static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq RpcConnection *Connection; r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, - endpoint, NULL, NULL, NULL); + endpoint, NULL, NULL, NULL, NULL); if (r != RPC_S_OK) return r; @@ -266,7 +266,7 @@ static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protse RpcConnection *Connection; r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, - endpoint, NULL, NULL, NULL); + endpoint, NULL, NULL, NULL, NULL); if (r != RPC_S_OK) return r; @@ -795,7 +795,8 @@ static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *pr } create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE, protseq->Protseq, NULL, - endpoint, NULL, NULL, NULL); + endpoint, NULL, NULL, NULL, + NULL); if (create_status != RPC_S_OK) { close(sock); @@ -1291,7 +1292,8 @@ RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection) RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, - LPCSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcBinding* Binding) + LPCSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, + RpcBinding* Binding) { const struct connection_ops *ops; RpcConnection* NewConnection; @@ -1317,6 +1319,8 @@ RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, SecInvalidateHandle(&NewConnection->ctx); if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo); NewConnection->AuthInfo = AuthInfo; + if (QOS) RpcQualityOfService_AddRef(QOS); + NewConnection->QOS = QOS; list_init(&NewConnection->conn_pool_entry); TRACE("connection: %p\n", NewConnection); @@ -1327,13 +1331,14 @@ RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, RpcConnection *RPCRT4_GetIdleConnection(const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, LPCSTR Protseq, LPCSTR NetworkAddr, - LPCSTR Endpoint, RpcAuthInfo* AuthInfo) + LPCSTR Endpoint, const RpcAuthInfo* AuthInfo, const RpcQualityOfService *QOS) { RpcConnection *Connection; /* try to find a compatible connection from the connection pool */ EnterCriticalSection(&connection_pool_cs); LIST_FOR_EACH_ENTRY(Connection, &connection_pool, RpcConnection, conn_pool_entry) if ((Connection->AuthInfo == AuthInfo) && + (Connection->QOS == QOS) && !memcmp(&Connection->ActiveInterface, InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) && !strcmp(rpcrt4_conn_get_name(Connection), Protseq) && @@ -1367,7 +1372,8 @@ RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* Old rpcrt4_conn_get_name(OldConnection), OldConnection->NetworkAddr, OldConnection->Endpoint, NULL, - OldConnection->AuthInfo, NULL); + OldConnection->AuthInfo, OldConnection->QOS, + NULL); if (err == RPC_S_OK) rpcrt4_conn_handoff(OldConnection, *Connection); return err; @@ -1381,6 +1387,7 @@ RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection) RPCRT4_strfree(Connection->Endpoint); RPCRT4_strfree(Connection->NetworkAddr); if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo); + if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS); HeapFree(GetProcessHeap(), 0, Connection); return RPC_S_OK; }