2954 lines
79 KiB
C++
2954 lines
79 KiB
C++
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||
|
||
Module Name:
|
||
|
||
secclnt.cxx
|
||
|
||
Abstract:
|
||
|
||
Implementation of security objects.
|
||
|
||
Author:
|
||
|
||
Michael Montague (mikemon) 11-Apr-1992
|
||
|
||
Revision History:
|
||
|
||
21-Feb-1997 jroberts Added some SSL support.
|
||
|
||
--*/
|
||
|
||
|
||
#include <precomp.hxx>
|
||
#include <wincrypt.h>
|
||
#include <rpcssl.h>
|
||
#include <cryptimp.hxx>
|
||
#include <rpccfg.h>
|
||
#include <spseal.h>
|
||
#include <schnlsp.h>
|
||
#include <hndlsvr.hxx>
|
||
|
||
int SecuritySupportLoaded = 0;
|
||
int FailedToLoad = 0;
|
||
|
||
unsigned long NumberOfProviders = 0;
|
||
unsigned long LoadedProviders = 0;
|
||
unsigned long AvailableProviders = 0;
|
||
SECURITY_PROVIDER_INFO PAPI * ProviderList = 0;
|
||
MUTEX * SecurityCritSect; // Mutex for the Server credentials cache.
|
||
|
||
// Incremented each time we leak SECURITY_CONTEXT::SecurityContext
|
||
// due to RpcSecurityInterface->DeleteSecurityContext
|
||
// returning SEC_E_INSUFFICIENT_MEMORY.
|
||
unsigned int nSecurityContextsLeaked = 0;
|
||
|
||
struct PACKAGE_LEG_INFO
|
||
{
|
||
DWORD Package;
|
||
PACKAGE_LEG_COUNT Legs;
|
||
};
|
||
|
||
const PACKAGE_LEG_INFO PredefinedPackageLegInfo[] =
|
||
{
|
||
{ RPC_C_AUTHN_WINNT, ThreeLegs },
|
||
{ RPC_C_AUTHN_GSS_NEGOTIATE,EvenNumberOfLegs },
|
||
{ RPC_C_AUTHN_GSS_KERBEROS, EvenNumberOfLegs },
|
||
{ RPC_C_AUTHN_GSS_SCHANNEL, EvenNumberOfLegs },
|
||
{ RPC_C_AUTHN_DPA, ThreeLegs },
|
||
{ RPC_C_AUTHN_DCE_PRIVATE, ThreeLegs },
|
||
{ 0x44, ThreeLegs }, // RPC_C_AUTHN_NETLOGON from net\svcdlls\logonsrv\nlbind.h
|
||
{ 0, LegsUnknown }
|
||
};
|
||
|
||
// defined in principal.cxx
|
||
//
|
||
extern
|
||
DWORD
|
||
RpcCertMatchPrincipalName(
|
||
PCCERT_CONTEXT Context,
|
||
RPC_CHAR PrincipalName[]
|
||
);
|
||
|
||
#ifdef UNICODE
|
||
#define SEC_TCHAR SEC_WCHAR
|
||
#else
|
||
#define SEC_TCHAR SEC_CHAR
|
||
#endif
|
||
|
||
|
||
RPC_STATUS
|
||
FindSecurityPackage (
|
||
IN unsigned long AuthenticationService,
|
||
IN unsigned long AuthenticationLevel,
|
||
OUT unsigned int __RPC_FAR * ProviderIndex,
|
||
OUT unsigned int __RPC_FAR * PackageIndex
|
||
);
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
InsureSecuritySupportLoaded (
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine insures that the security support is loaded; if it is not
|
||
loaded, then we go ahead and load it.
|
||
|
||
Return Value:
|
||
|
||
A zero result indicates that security support has successfully been
|
||
loaded, and is ready to go.
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
|
||
if ( SecuritySupportLoaded != 0 )
|
||
{
|
||
return(0);
|
||
}
|
||
|
||
RequestGlobalMutex();
|
||
if ( SecuritySupportLoaded != 0 )
|
||
{
|
||
ClearGlobalMutex();
|
||
return(0);
|
||
}
|
||
|
||
SecurityCritSect = new MUTEX(&Status,
|
||
TRUE // pre-allocate semaphore
|
||
);
|
||
|
||
if (SecurityCritSect == 0)
|
||
{
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
if (Status == RPC_S_OK)
|
||
{
|
||
SecuritySupportLoaded = 1;
|
||
}
|
||
|
||
ClearGlobalMutex();
|
||
return (Status);
|
||
}
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
IsAuthenticationServiceSupported (
|
||
IN unsigned long AuthenticationService
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to determine whether or not an authentication
|
||
service is supported by the current configuration.
|
||
|
||
Arguments:
|
||
|
||
AuthenticationService - Supplies a proposed authentication service.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - The supplied authentication service is supported by the
|
||
current configuration.
|
||
|
||
RPC_S_UNKNOWN_AUTHN_SERVICE - The supplied authentication service
|
||
is unknown, and not supported by the current configuration.
|
||
|
||
--*/
|
||
{
|
||
unsigned int PackageIndex, ProviderIndex;
|
||
|
||
// First make sure that the security support has been loaded.
|
||
|
||
if ( InsureSecuritySupportLoaded() != RPC_S_OK )
|
||
{
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
|
||
|
||
return ( FindSecurityPackage(
|
||
AuthenticationService,
|
||
RPC_C_AUTHN_LEVEL_CONNECT,
|
||
&ProviderIndex,
|
||
&PackageIndex
|
||
) );
|
||
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
FindSecurityPackage (
|
||
IN unsigned long AuthenticationService,
|
||
IN unsigned long AuthenticationLevel,
|
||
OUT unsigned int __RPC_FAR * ProviderIndex,
|
||
OUT unsigned int __RPC_FAR * PackageIndex
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The methods used to acquire credentials for the client and the server use
|
||
this routine to find a security package, given the an authentication
|
||
service.
|
||
|
||
Arguments:
|
||
|
||
AuthenticationService - Supplies the authentication service to be used
|
||
(for the credentials and for the context).
|
||
|
||
AuthenticationLevel - Supplies the authentication level to be used by
|
||
these credentials. It will already have been mapped by the protocol
|
||
module into the final level.
|
||
|
||
RpcStatus - Returns the status of the operation. It will be one of the
|
||
following values.
|
||
|
||
RPC_S_OK - The return value from this routine is the index of
|
||
the appropriate security package.
|
||
|
||
RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
|
||
not supported by the current configuration.
|
||
|
||
RPC_S_UNKNOWN_AUTHN_LEVEL - The specified authentication level is not
|
||
supported by the requested authentication service.
|
||
|
||
Return Value:
|
||
|
||
If RpcStatus contains RPC_S_OK, then the index of the appropriate
|
||
security package will be returned.
|
||
|
||
--*/
|
||
{
|
||
unsigned int Index, i;
|
||
INIT_SECURITY_INTERFACE InitSecurityInterface;
|
||
PSecurityFunctionTable SecurityInterface = 0;
|
||
SecPkgInfo PAPI * tmpPkgList;
|
||
SECURITY_PACKAGE_INFO * SecurityPackages;
|
||
SECURITY_PROVIDER_INFO PAPI * List;
|
||
unsigned long NumberOfPackages, Total;
|
||
RPC_CHAR * DllName = NULL;
|
||
DLL * ProviderDll;
|
||
RPC_STATUS Status = RPC_S_UNKNOWN_AUTHN_SERVICE;
|
||
|
||
// First make sure that the security support has been loaded.
|
||
|
||
if ( InsureSecuritySupportLoaded() != RPC_S_OK )
|
||
{
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
|
||
// 0xFFFF ia a "not-an-RPC-ID", indicating that the protocol
|
||
// is not for use by RPC.
|
||
if (AuthenticationService == 0xFFFF)
|
||
{
|
||
return(RPC_S_UNKNOWN_AUTHN_SERVICE);
|
||
}
|
||
|
||
SecurityCritSect->Request();
|
||
|
||
List = ProviderList;
|
||
for (i = 0; i < LoadedProviders; i ++)
|
||
{
|
||
|
||
SecurityPackages = List->SecurityPackages;
|
||
NumberOfPackages = List->Count;
|
||
|
||
for (Index = 0;Index < (unsigned int) NumberOfPackages;Index++)
|
||
{
|
||
if ( SecurityPackages[Index].PackageInfo.wRPCID == AuthenticationService )
|
||
{
|
||
if ( (AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
|
||
|| ( AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT) )
|
||
{
|
||
if ( (SecurityPackages[Index].PackageInfo.fCapabilities
|
||
& SECPKG_FLAG_INTEGRITY) == 0 )
|
||
{
|
||
Status = RPC_S_UNKNOWN_AUTHN_LEVEL;
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
if ( AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY )
|
||
{
|
||
if ( (SecurityPackages[Index].PackageInfo.fCapabilities
|
||
& SECPKG_FLAG_PRIVACY) == 0 )
|
||
{
|
||
Status = RPC_S_UNKNOWN_AUTHN_LEVEL;
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
Status = RPC_S_OK;
|
||
*ProviderIndex = i;
|
||
*PackageIndex = Index;
|
||
break;
|
||
}
|
||
} //For over all packages in one provider(dll)
|
||
|
||
if (Status == RPC_S_OK)
|
||
{
|
||
SecurityCritSect->Clear();
|
||
return(Status);
|
||
}
|
||
List++;
|
||
} //For over all providers(dll)
|
||
|
||
if ((LoadedProviders == AvailableProviders) && (LoadedProviders != 0))
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = RpcGetSecurityProviderInfo (
|
||
AuthenticationService, &DllName, &Total);
|
||
|
||
ASSERT(!RpcpCheckHeap());
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
if (ProviderList == 0)
|
||
{
|
||
ProviderList = (SECURITY_PROVIDER_INFO PAPI *)
|
||
new char [sizeof(SECURITY_PROVIDER_INFO) * Total];
|
||
if (ProviderList == 0)
|
||
{
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
AvailableProviders = Total;
|
||
}
|
||
else
|
||
{
|
||
List = ProviderList;
|
||
for (i = 0; i < LoadedProviders; i ++)
|
||
{
|
||
if (RpcpStringCompare(DllName, List->ProviderDllName) == 0)
|
||
{
|
||
delete DllName;
|
||
Status = RPC_S_UNKNOWN_AUTHN_SERVICE;
|
||
goto Cleanup;
|
||
}
|
||
List++;
|
||
}
|
||
}
|
||
|
||
ProviderDll = new DLL(DllName, &Status);
|
||
|
||
if ((ProviderDll == NULL) && (Status == RPC_S_INVALID_ARG))
|
||
{
|
||
Status = RPC_S_UNKNOWN_AUTHN_SERVICE;
|
||
}
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
ASSERT(!RpcpCheckHeap());
|
||
|
||
InitSecurityInterface = (INIT_SECURITY_INTERFACE_W)
|
||
ProviderDll->GetEntryPoint(SECURITY_ENTRYPOINT_ANSIW);
|
||
|
||
if ( InitSecurityInterface == 0 )
|
||
{
|
||
delete ProviderDll;
|
||
Status = RPC_S_UNKNOWN_AUTHN_SERVICE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
SecurityInterface = (*InitSecurityInterface)();
|
||
if ( (SecurityInterface == 0)
|
||
|| (SecurityInterface->dwVersion
|
||
< SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION) )
|
||
{
|
||
delete ProviderDll;
|
||
Status = RPC_S_UNKNOWN_AUTHN_SERVICE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = (*SecurityInterface->EnumerateSecurityPackages)(
|
||
&NumberOfPackages, &tmpPkgList);
|
||
|
||
if ( Status != SEC_E_OK)
|
||
{
|
||
delete ProviderDll;
|
||
|
||
if (Status == SEC_E_INSUFFICIENT_MEMORY)
|
||
{
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
else
|
||
{
|
||
VALIDATE(Status) {
|
||
SEC_E_SECPKG_NOT_FOUND
|
||
} END_VALIDATE;
|
||
Status = RPC_S_UNKNOWN_AUTHN_SERVICE;
|
||
}
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
ProviderList[LoadedProviders].Count = NumberOfPackages;
|
||
ProviderList[LoadedProviders].RpcSecurityInterface = SecurityInterface;
|
||
ProviderList[LoadedProviders].ProviderDll = ProviderDll;
|
||
ProviderList[LoadedProviders].ProviderDllName = DllName;
|
||
*ProviderIndex = LoadedProviders;
|
||
|
||
//
|
||
// Fill in the SecurityPackages member for this Provider.
|
||
//
|
||
ProviderList[LoadedProviders].SecurityPackages =
|
||
(SECURITY_PACKAGE_INFO *) new char
|
||
[sizeof(SECURITY_PACKAGE_INFO) * NumberOfPackages];
|
||
if (ProviderList[LoadedProviders].SecurityPackages == NULL)
|
||
{
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Save the SecPkgInfo array to the SecurityPackages structure.
|
||
//
|
||
for (i = 0; i < NumberOfPackages; i++)
|
||
{
|
||
ProviderList[LoadedProviders].
|
||
SecurityPackages[i].
|
||
PackageInfo = tmpPkgList[i];
|
||
|
||
ProviderList[LoadedProviders].
|
||
SecurityPackages[i].
|
||
ServerSecurityCredentials = NULL;
|
||
}
|
||
|
||
|
||
SecurityPackages = ProviderList[LoadedProviders].SecurityPackages;
|
||
Status = RPC_S_UNKNOWN_AUTHN_SERVICE;
|
||
for (i = 0; i < NumberOfPackages; i++)
|
||
{
|
||
if ( SecurityPackages[i].PackageInfo.wRPCID == AuthenticationService )
|
||
{
|
||
if ( ( AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY )
|
||
||( AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT) )
|
||
{
|
||
if ( (SecurityPackages[i].PackageInfo.fCapabilities
|
||
& SECPKG_FLAG_INTEGRITY) == 0 )
|
||
{
|
||
Status = RPC_S_UNKNOWN_AUTHN_LEVEL;
|
||
continue;
|
||
}
|
||
}
|
||
if ( AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY )
|
||
{
|
||
if ( (SecurityPackages[i].PackageInfo.fCapabilities
|
||
& SECPKG_FLAG_PRIVACY) == 0 )
|
||
{
|
||
Status = RPC_S_UNKNOWN_AUTHN_LEVEL;
|
||
continue;
|
||
}
|
||
}
|
||
*PackageIndex = i;
|
||
Status = RPC_S_OK;
|
||
break;
|
||
}
|
||
}
|
||
LoadedProviders++;
|
||
|
||
Cleanup:
|
||
SecurityCritSect->Clear();
|
||
return(Status);
|
||
}
|
||
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
FindServerCredentials (
|
||
IN RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
|
||
IN void __RPC_FAR * Arg,
|
||
IN unsigned long AuthenticationService,
|
||
IN unsigned long AuthenticationLevel,
|
||
IN RPC_CHAR __RPC_FAR * Principal,
|
||
IN OUT SECURITY_CREDENTIALS ** SecurityCredentials
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The method is used to find cached server credentials for use by the
|
||
server.
|
||
|
||
Arguments:
|
||
|
||
AuthenticationService - Supplies the authentication service to be used
|
||
(for the credentials and for the context).
|
||
|
||
AuthenticationLevel - Supplies the authentication level to be used by
|
||
these credentials. It will already have been mapped by the protocol
|
||
module into the final level.
|
||
|
||
SecurityCredentials - TBS
|
||
|
||
RpcStatus - Returns the status of the operation. It will be one of the
|
||
following values.
|
||
|
||
RPC_S_OK - The return value from this routine is the index of
|
||
the appropriate security package.
|
||
|
||
RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
|
||
not supported by the current configuration.
|
||
|
||
RPC_S_UNKNOWN_AUTHN_LEVEL - The specified authentication level is not
|
||
supported by the requested authentication service.
|
||
|
||
Return Value:
|
||
|
||
If RpcStatus contains RPC_S_OK, then valid credentials are passed
|
||
back.
|
||
|
||
--*/
|
||
{
|
||
|
||
SECURITY_STATUS SecurityStatus;
|
||
TimeStamp TimeStamp;
|
||
RPC_STATUS RpcStatus, CredStatus = RPC_S_OK;
|
||
PSecurityFunctionTable RpcSecurityInterface;
|
||
SECURITY_PACKAGE_INFO *pPackageInfo = 0;
|
||
SECURITY_CREDENTIALS *pSecCredentials = 0;
|
||
CredHandle tmpCredHandle;
|
||
unsigned int ProviderIndex;
|
||
unsigned int PackageIndex;
|
||
|
||
//
|
||
// NULL out the OUT parameters.
|
||
//
|
||
*SecurityCredentials = NULL;
|
||
|
||
//
|
||
// Find the right security package
|
||
//
|
||
RpcStatus = FindSecurityPackage(
|
||
AuthenticationService,
|
||
AuthenticationLevel,
|
||
&ProviderIndex,
|
||
&PackageIndex
|
||
);
|
||
if (RpcStatus != RPC_S_OK)
|
||
{
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
RpcStatus,
|
||
EEInfoDLFindServerCredentials10,
|
||
AuthenticationService,
|
||
AuthenticationLevel);
|
||
|
||
return (RpcStatus);
|
||
}
|
||
|
||
//
|
||
// Now, get the server-credentials for this security package.
|
||
//
|
||
pPackageInfo = &(ProviderList[ProviderIndex].
|
||
SecurityPackages[PackageIndex]
|
||
);
|
||
|
||
|
||
// Protect the access
|
||
SecurityCritSect->Request();
|
||
|
||
//
|
||
// Check to see if credentials have already been acquired for this
|
||
// package. If yes, return them.
|
||
//
|
||
if (pPackageInfo->ServerSecurityCredentials)
|
||
{
|
||
*SecurityCredentials = pPackageInfo->ServerSecurityCredentials;
|
||
// Add a reference for the caller.
|
||
pPackageInfo->ServerSecurityCredentials->ReferenceCredentials();
|
||
SecurityCritSect->Clear();
|
||
return (RPC_S_OK);
|
||
}
|
||
|
||
//
|
||
// Allocate a new set of credentials. Ref count is 1, if successful.
|
||
//
|
||
pSecCredentials = new SECURITY_CREDENTIALS(&CredStatus);
|
||
if (pSecCredentials == NULL)
|
||
{
|
||
SecurityCritSect->Clear();
|
||
return (RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
if (CredStatus != RPC_S_OK)
|
||
{
|
||
delete pSecCredentials;
|
||
SecurityCritSect->Clear();
|
||
return (CredStatus);
|
||
}
|
||
|
||
//
|
||
// This is the first time Credentials are being acquired for this
|
||
// package. Acquire them now.
|
||
//
|
||
RpcSecurityInterface = ProviderList[ProviderIndex].RpcSecurityInterface;
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->AcquireCredentialsHandle)(
|
||
(SEC_TCHAR __SEC_FAR *) Principal,
|
||
pPackageInfo->PackageInfo.Name,
|
||
SECPKG_CRED_INBOUND,
|
||
0,
|
||
Arg,
|
||
(SEC_GET_KEY_FN) GetKeyFn,
|
||
Arg,
|
||
&(pSecCredentials->CredentialsHandle),
|
||
&TimeStamp
|
||
);
|
||
|
||
if (SecurityStatus != SEC_E_OK)
|
||
{
|
||
SetExtendedError(SecurityStatus);
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
SecurityStatus,
|
||
EEInfoDLFindServerCredentials20,
|
||
Principal,
|
||
pPackageInfo->PackageInfo.Name);
|
||
|
||
SecurityCritSect->Clear();
|
||
delete pSecCredentials;
|
||
|
||
switch (SecurityStatus)
|
||
{
|
||
case SEC_E_INSUFFICIENT_MEMORY:
|
||
RpcStatus = RPC_S_OUT_OF_MEMORY;
|
||
break;
|
||
|
||
case SEC_E_SHUTDOWN_IN_PROGRESS:
|
||
RpcStatus = ERROR_SHUTDOWN_IN_PROGRESS;
|
||
break;
|
||
|
||
case SEC_E_SECPKG_NOT_FOUND:
|
||
RpcStatus = RPC_S_UNKNOWN_AUTHN_SERVICE;
|
||
break;
|
||
|
||
case SEC_E_NO_SPM:
|
||
RpcStatus = RPC_S_SEC_PKG_ERROR;
|
||
break;
|
||
|
||
default:
|
||
{
|
||
#if DBG
|
||
if ((SecurityStatus != SEC_E_NO_CREDENTIALS) &&
|
||
(SecurityStatus != SEC_E_UNKNOWN_CREDENTIALS))
|
||
{
|
||
PrintToDebugger("RPC SEC: AcquireCredentialsForServer "
|
||
"Returned 0x%x\n", SecurityStatus);
|
||
}
|
||
#endif
|
||
RpcStatus = RPC_S_INVALID_AUTH_IDENTITY;
|
||
}
|
||
} // end of switch
|
||
|
||
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
RpcStatus,
|
||
EEInfoDLFindServerCredentials30,
|
||
SecurityStatus);
|
||
|
||
return RpcStatus;
|
||
}
|
||
|
||
//
|
||
// Setup the new Credentials.
|
||
//
|
||
pSecCredentials->Valid = TRUE;
|
||
pSecCredentials->bServerCredentials = TRUE;
|
||
pSecCredentials->AuthenticationService = AuthenticationService;
|
||
pSecCredentials->ProviderIndex = ProviderIndex;
|
||
pSecCredentials->PackageIndex = PackageIndex;
|
||
|
||
//
|
||
// Cache the new credentials.
|
||
//
|
||
pPackageInfo->ServerSecurityCredentials = pSecCredentials;
|
||
|
||
// Add a reference for the Cache.
|
||
pPackageInfo->ServerSecurityCredentials->ReferenceCredentials();
|
||
|
||
*SecurityCredentials = pSecCredentials;
|
||
|
||
SecurityCritSect->Clear();
|
||
|
||
return (RPC_S_OK);
|
||
}
|
||
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
RemoveCredentialsFromCache (
|
||
IN unsigned long AuthenticationService
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
An RPC server can call RpcRegisterAuthInfo() a second time on the same
|
||
Authentication Service to update the GetKeyFunction and Arg values.
|
||
In this case, we need to flush our credentials cache so that when
|
||
the server tries to acquires credentials again, the credentials can
|
||
be acquired using the new values.
|
||
|
||
Arguments:
|
||
|
||
AuthenticationService - Supplies the authentication service to be used
|
||
(for the credentials and for the context).
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK, If Cache has been successfully flushed.
|
||
Return Value from FindSecurityPackage(), if not
|
||
|
||
--*/
|
||
{
|
||
unsigned int ProviderIndex;
|
||
unsigned int PackageIndex;
|
||
SECURITY_PACKAGE_INFO *pPackageInfo = 0;
|
||
RPC_STATUS RpcStatus;
|
||
|
||
//
|
||
// First, find the right security package
|
||
//
|
||
RpcStatus = FindSecurityPackage(
|
||
AuthenticationService,
|
||
RPC_C_AUTHN_LEVEL_DEFAULT, // Doesn't matter
|
||
&ProviderIndex,
|
||
&PackageIndex
|
||
);
|
||
|
||
ASSERT(RpcStatus == RPC_S_OK);
|
||
|
||
if (RpcStatus != RPC_S_OK)
|
||
{
|
||
return (RpcStatus);
|
||
}
|
||
|
||
pPackageInfo = &(ProviderList[ProviderIndex].SecurityPackages[PackageIndex]);
|
||
|
||
//
|
||
// Flush the credentials.
|
||
//
|
||
SecurityCritSect->Request();
|
||
|
||
if (pPackageInfo->ServerSecurityCredentials)
|
||
{
|
||
// Remove the reference maintained by the cache.
|
||
pPackageInfo->ServerSecurityCredentials->DereferenceCredentials(TRUE);
|
||
pPackageInfo->ServerSecurityCredentials = NULL;
|
||
}
|
||
|
||
SecurityCritSect->Clear();
|
||
|
||
return (RPC_S_OK);
|
||
}
|
||
|
||
|
||
#define INVALID_INDEX 0xFFFF
|
||
|
||
|
||
SECURITY_CREDENTIALS::SECURITY_CREDENTIALS (
|
||
IN OUT RPC_STATUS PAPI * Status
|
||
) : CredentialsMutex(Status)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We need this here to keep the compiler happy.
|
||
|
||
--*/
|
||
{
|
||
DefaultPrincName = NULL;
|
||
|
||
ReferenceCount = 1;
|
||
Valid = FALSE;
|
||
|
||
bServerCredentials = FALSE;
|
||
fDeleted = FALSE;
|
||
|
||
// Initialize to invalid values.
|
||
ProviderIndex = INVALID_INDEX;
|
||
PackageIndex = INVALID_INDEX;
|
||
}
|
||
|
||
SECURITY_CREDENTIALS::~SECURITY_CREDENTIALS (
|
||
)
|
||
{
|
||
PSecurityFunctionTable RpcSecurityInterface;
|
||
|
||
if (DefaultPrincName != NULL)
|
||
{
|
||
RpcSecurityInterface = InquireProviderFunctionTable();
|
||
|
||
ASSERT(RpcSecurityInterface != NULL);
|
||
|
||
(*RpcSecurityInterface->FreeContextBuffer)(DefaultPrincName);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void
|
||
SECURITY_CREDENTIALS::ReferenceCredentials(
|
||
)
|
||
{
|
||
|
||
CredentialsMutex.Request();
|
||
ReferenceCount++;
|
||
CredentialsMutex.Clear();
|
||
|
||
}
|
||
|
||
|
||
void
|
||
SECURITY_CREDENTIALS::DereferenceCredentials(
|
||
BOOL fRemoveIt OPTIONAL
|
||
)
|
||
{
|
||
CredentialsMutex.Request();
|
||
ReferenceCount--;
|
||
|
||
ASSERT(((long)ReferenceCount) >= 0);
|
||
|
||
if (fRemoveIt)
|
||
{
|
||
fDeleted = TRUE;
|
||
}
|
||
|
||
if (ReferenceCount == 0)
|
||
{
|
||
//
|
||
// Server side SCENARIOS when (ReferenceCount == 0)
|
||
//
|
||
// a. RemoveCredentialsFromCache() removes the extra reference
|
||
// held by the cache. It does so holding the cache Mutex ie.,
|
||
// SecurityCritSect. So, no other thread can get a reference
|
||
// on the credentials in the cache.
|
||
//
|
||
// b. DereferenceCredentials() has been called by one of the
|
||
// threads possessing the cached credentials AND the cache
|
||
// has already removed it's reference. Cache will remove it's
|
||
// reference only when it removes this credential from the
|
||
// cache. This implies no other thread could have gotten a
|
||
// reference on the credentials in the cache, in the meantime.
|
||
//
|
||
// These two imply that ReferenceCount cannot change here. Also,
|
||
// in case (a), credentials will soon be removed from the cache.
|
||
// In case (b), credentials have already been removed.
|
||
//
|
||
|
||
if (bServerCredentials)
|
||
{
|
||
ASSERT(fDeleted);
|
||
}
|
||
|
||
CredentialsMutex.Clear();
|
||
FreeCredentials();
|
||
delete this;
|
||
} // if (ReferenceCount == 0)
|
||
else
|
||
{
|
||
CredentialsMutex.Clear();
|
||
}
|
||
}
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
SECURITY_CREDENTIALS::AcquireCredentialsForClient (
|
||
IN RPC_AUTH_IDENTITY_HANDLE AuthIdentity,
|
||
IN unsigned long AuthenticationService,
|
||
IN unsigned long AuthenticationLevel
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We need to use this method in order to acquire security credentials. We
|
||
need the security credentials so that we (as a client) can initialize
|
||
a security context with a server. This method, with
|
||
SECURITY_CREDENTIALS::FreeCredentials may cache security credentials,
|
||
but that is transparent to clients of this class.
|
||
|
||
Arguments:
|
||
|
||
AuthIdentity - Supplies the security identity for which we wish to obtain
|
||
credentials. If this argument is not supplied, then we use the
|
||
security identity of this process.
|
||
|
||
AuthenticationService - Supplies the authentication service to be used
|
||
(for the credentials and for the context).
|
||
|
||
AuthenticationLevel - Supplies the authentication level to be used by
|
||
these credentials. It will already have been mapped by the protocol
|
||
module into the final level.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - We now have security credentials for the requested
|
||
authentication service.
|
||
|
||
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
|
||
operation.
|
||
|
||
RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
|
||
not supported by the current configuration.
|
||
|
||
RPC_S_INVALID_AUTH_IDENTITY - The specified identity is not known to
|
||
the requested authentication service.
|
||
|
||
RPC_S_UNKNOWN_AUTHN_LEVEL - The specified authentication level is not
|
||
supported by the requested authentication service.
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
TimeStamp TimeStamp;
|
||
RPC_STATUS RpcStatus;
|
||
PSecurityFunctionTable RpcSecurityInterface;
|
||
|
||
unsigned Flags = SCH_CRED_USE_DEFAULT_CREDS;
|
||
|
||
RpcStatus = FindSecurityPackage(
|
||
AuthenticationService,
|
||
AuthenticationLevel,
|
||
&ProviderIndex,
|
||
&PackageIndex
|
||
);
|
||
|
||
if ( RpcStatus != RPC_S_OK )
|
||
{
|
||
RpcpErrorAddRecord(EEInfoGCRuntime,
|
||
RpcStatus,
|
||
EEInfoDLAcquireCredentialsForClient20,
|
||
AuthenticationService,
|
||
AuthenticationLevel);
|
||
|
||
return(RpcStatus);
|
||
}
|
||
|
||
RpcSecurityInterface = ProviderList[ProviderIndex].RpcSecurityInterface;
|
||
|
||
if (AuthIdentity == RPC_C_NO_CREDENTIALS)
|
||
{
|
||
Flags = 0;
|
||
AuthIdentity = 0;
|
||
}
|
||
|
||
//
|
||
// RPC does its own name checking using msstd or fullsic names.
|
||
// This requires the ability to disable schannel's name checking,
|
||
// a feature available only with credentials version-4 or better.
|
||
//
|
||
#define MINIMUM_SCHANNEL_CRED_VERSION 4
|
||
|
||
if (AuthenticationService == RPC_C_AUTHN_GSS_SCHANNEL &&
|
||
AuthIdentity != NULL)
|
||
{
|
||
SCHANNEL_CRED * cred = (SCHANNEL_CRED *) AuthIdentity;
|
||
|
||
Flags |= SCH_CRED_NO_SERVERNAME_CHECK;
|
||
|
||
if (cred->dwVersion < MINIMUM_SCHANNEL_CRED_VERSION)
|
||
{
|
||
RpcpErrorAddRecord(EEInfoGCRuntime,
|
||
ERROR_INVALID_PARAMETER,
|
||
EEInfoDLAcquireCredentialsForClient30,
|
||
AuthenticationService,
|
||
AuthenticationLevel);
|
||
|
||
return RPC_S_INVALID_AUTH_IDENTITY;
|
||
}
|
||
|
||
cred->dwFlags |= Flags;
|
||
}
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->AcquireCredentialsHandle)(
|
||
0,
|
||
ProviderList[ProviderIndex].SecurityPackages[PackageIndex].PackageInfo.Name,
|
||
SECPKG_CRED_OUTBOUND,
|
||
0,
|
||
AuthIdentity, 0, 0, &CredentialsHandle, &TimeStamp);
|
||
|
||
if ( SecurityStatus != SEC_E_OK )
|
||
{
|
||
RpcpErrorAddRecord(EEInfoGCSecurityProvider,
|
||
SecurityStatus,
|
||
EEInfoDLAcquireCredentialsForClient10,
|
||
AuthenticationService,
|
||
AuthenticationLevel);
|
||
}
|
||
|
||
if (SecurityStatus != SEC_E_OK)
|
||
{
|
||
if ( SecurityStatus == SEC_E_INSUFFICIENT_MEMORY )
|
||
{
|
||
RpcStatus = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
else if ( SecurityStatus == SEC_E_SECPKG_NOT_FOUND )
|
||
{
|
||
RpcStatus = RPC_S_UNKNOWN_AUTHN_SERVICE;
|
||
}
|
||
else if ( SecurityStatus == SEC_E_SHUTDOWN_IN_PROGRESS )
|
||
{
|
||
RpcStatus = ERROR_SHUTDOWN_IN_PROGRESS;
|
||
}
|
||
else if ( SecurityStatus == SEC_E_NO_SPM)
|
||
{
|
||
RpcStatus = RPC_S_SEC_PKG_ERROR;
|
||
}
|
||
else
|
||
{
|
||
|
||
VALIDATE(SecurityStatus)
|
||
{
|
||
SEC_E_NO_CREDENTIALS,
|
||
SEC_E_UNKNOWN_CREDENTIALS,
|
||
SEC_E_NO_AUTHENTICATING_AUTHORITY,
|
||
SEC_E_INVALID_TOKEN
|
||
}
|
||
END_VALIDATE;
|
||
|
||
RpcStatus = RPC_S_INVALID_AUTH_IDENTITY;
|
||
}
|
||
|
||
RpcpErrorAddRecord(EEInfoGCRuntime,
|
||
RpcStatus,
|
||
EEInfoDLAcquireCredentialsForClient30,
|
||
SecurityStatus);
|
||
|
||
return RpcStatus;
|
||
}
|
||
|
||
this->AuthenticationService = AuthenticationService;
|
||
Valid = TRUE;
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
SECURITY_CREDENTIALS::InquireDefaultPrincName(
|
||
OUT SEC_CHAR __SEC_FAR **MyDefaultPrincName
|
||
)
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
SecPkgCredentials_NamesA CredentialsNames;
|
||
PSecurityFunctionTable RpcSecurityInterface;
|
||
RPC_STATUS Status;
|
||
|
||
if (DefaultPrincName == NULL)
|
||
{
|
||
RpcSecurityInterface = InquireProviderFunctionTable();
|
||
if (RpcSecurityInterface == NULL) {
|
||
return (RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
if (RpcSecurityInterface->QueryCredentialsAttributes == NULL) {
|
||
return (RPC_S_CANNOT_SUPPORT);
|
||
}
|
||
SecurityStatus = (*RpcSecurityInterface->QueryCredentialsAttributes)(
|
||
InquireCredHandle(), SECPKG_CRED_ATTR_NAMES, &CredentialsNames);
|
||
|
||
if (SecurityStatus != SEC_E_OK)
|
||
{
|
||
SetExtendedError(SecurityStatus);
|
||
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
SecurityStatus,
|
||
EEInfoDLInquireDefaultPrincName10,
|
||
AuthenticationService);
|
||
|
||
if (SecurityStatus == SEC_E_INSUFFICIENT_MEMORY)
|
||
{
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
else if ( SecurityStatus == SEC_E_SHUTDOWN_IN_PROGRESS )
|
||
{
|
||
Status = ERROR_SHUTDOWN_IN_PROGRESS;
|
||
}
|
||
else
|
||
{
|
||
Status = RPC_S_SEC_PKG_ERROR;
|
||
}
|
||
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
Status,
|
||
EEInfoDLInquireDefaultPrincName20,
|
||
SecurityStatus);
|
||
|
||
return Status;
|
||
}
|
||
|
||
if (CredentialsNames.sUserName == NULL)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
DefaultPrincName = CredentialsNames.sUserName;
|
||
}
|
||
|
||
*MyDefaultPrincName = DefaultPrincName;
|
||
|
||
return (RPC_S_OK);
|
||
}
|
||
|
||
|
||
|
||
void
|
||
SECURITY_CREDENTIALS::FreeCredentials (
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
When we are done using the credentials, we call this routine to free
|
||
them.
|
||
|
||
--*/
|
||
{
|
||
if (Valid)
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
|
||
PSecurityFunctionTable RpcSecurityInterface
|
||
= ProviderList[ProviderIndex].RpcSecurityInterface;
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->FreeCredentialHandle)(
|
||
&CredentialsHandle);
|
||
ASSERT( SecurityStatus == SEC_E_OK ||
|
||
SecurityStatus == SEC_E_SECPKG_NOT_FOUND ||
|
||
SecurityStatus == SEC_E_SHUTDOWN_IN_PROGRESS );
|
||
}
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
SECURITY_CONTEXT::SetMaximumLengths (
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the maximum header length and maximum signature
|
||
length fields of this object.
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
SecPkgContext_Sizes ContextSizes;
|
||
RPC_STATUS Status;
|
||
|
||
if (FailedContext != 0)
|
||
{
|
||
// We cheat if 3rd Leg Failed as we dont really have a true Context
|
||
// Provider is going to really complain if we call QueryContextAttr()
|
||
// .. we get around that by picking large values.
|
||
// The rest of the code prevents these values to be really used
|
||
// We do this because we do not want to block 3rd Leg, rather fail the
|
||
// first request!
|
||
|
||
MaxSignatureLength = 256;
|
||
MaxHeaderLength = 256;
|
||
cbBlockSize = 64;
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
ASSERT( FullyConstructed() );
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->QueryContextAttributes)(
|
||
&SecurityContext, SECPKG_ATTR_SIZES, &ContextSizes);
|
||
|
||
if (SecurityStatus != SEC_E_OK)
|
||
{
|
||
#ifdef DEBUGRPC
|
||
PrintToDebugger("RPC: secclnt.cxx: QueryContextAttributes returned: %lx\n",
|
||
SecurityStatus);
|
||
#endif
|
||
Status = GetLastError();
|
||
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
RPC_S_OUT_OF_MEMORY,
|
||
EEInfoDLSetMaximumLengths10,
|
||
SecurityStatus,
|
||
Status,
|
||
AuthenticationService,
|
||
(ULONGLONG)&SecurityContext
|
||
);
|
||
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
MaxSignatureLength = (unsigned int) ContextSizes.cbMaxSignature;
|
||
MaxHeaderLength = (unsigned int) ContextSizes.cbSecurityTrailer;
|
||
cbBlockSize = (unsigned int) ContextSizes.cbBlockSize;
|
||
|
||
ASSERT(ContextSizes.cbBlockSize <= MAXIMUM_SECURITY_BLOCK_SIZE );
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
SECURITY_CONTEXT::SECURITY_CONTEXT (
|
||
CLIENT_AUTH_INFO *myAuthInfo,
|
||
unsigned myAuthContextId,
|
||
BOOL fUseDatagram,
|
||
RPC_STATUS __RPC_FAR * pStatus
|
||
)
|
||
: CLIENT_AUTH_INFO (myAuthInfo, pStatus),
|
||
AuthContextId (myAuthContextId),
|
||
fDatagram ((boolean) fUseDatagram),
|
||
fFullyConstructed (FALSE),
|
||
Legs (LegsUnknown),
|
||
ContextAttributes (0)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
We need to set the flag indicating that there is no security context
|
||
to be deleted.
|
||
|
||
--*/
|
||
{
|
||
ASSERT( AuthenticationLevel != 0 );
|
||
|
||
DontForgetToDelete = 0;
|
||
FailedContext = 0;
|
||
FailedContextEEInfo = NULL;
|
||
AuthzClientContext = NULL;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
SECURITY_CONTEXT::CompleteSecurityToken (
|
||
IN OUT SECURITY_BUFFER_DESCRIPTOR PAPI * BufferDescriptor
|
||
)
|
||
/*++
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
RPC_STATUS Status;
|
||
|
||
ASSERT( ( SecuritySupportLoaded != 0 )
|
||
&& ( FailedToLoad == 0 ) );
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->CompleteAuthToken)(
|
||
&SecurityContext, BufferDescriptor);
|
||
if (SecurityStatus == SEC_E_OK)
|
||
{
|
||
return (RPC_S_OK);
|
||
}
|
||
|
||
SetExtendedError(SecurityStatus);
|
||
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
SecurityStatus,
|
||
EEInfoDLCompleteSecurityToken10,
|
||
AuthenticationService,
|
||
AuthenticationLevel);
|
||
|
||
if ( (SecurityStatus == SEC_E_NO_CREDENTIALS)
|
||
|| (SecurityStatus == SEC_E_LOGON_DENIED)
|
||
|| (SecurityStatus == SEC_E_INVALID_TOKEN)
|
||
|| (SecurityStatus == SEC_E_UNKNOWN_CREDENTIALS)
|
||
|| (SecurityStatus == SEC_E_WRONG_PRINCIPAL)
|
||
|| (SecurityStatus == SEC_E_TIME_SKEW))
|
||
{
|
||
Status = RPC_S_ACCESS_DENIED;
|
||
}
|
||
else if ( SecurityStatus == SEC_E_INSUFFICIENT_MEMORY )
|
||
{
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
else if ( SecurityStatus == SEC_E_SHUTDOWN_IN_PROGRESS )
|
||
{
|
||
Status = ERROR_SHUTDOWN_IN_PROGRESS;
|
||
}
|
||
else
|
||
{
|
||
#if DBG
|
||
PrintToDebugger("RPC: CompleteSecurityContext Returned %lx\n",
|
||
SecurityStatus);
|
||
#endif
|
||
Status = RPC_S_SEC_PKG_ERROR;
|
||
}
|
||
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
Status,
|
||
EEInfoDLCompleteSecurityToken20,
|
||
SecurityStatus);
|
||
return Status;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
SECURITY_CONTEXT::SignOrSeal (
|
||
IN unsigned long Sequence,
|
||
IN unsigned int SignNotSealFlag,
|
||
IN OUT SECURITY_BUFFER_DESCRIPTOR PAPI * BufferDescriptor
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A protocol module will use this routine to prepare a message to be
|
||
sent so that it can be verified that the message has not been tampered
|
||
with, and that it has not been exchanged out of sequence. The sender
|
||
will use this routine to prepare the message; the receiver will use
|
||
SECURITY_CONTEXT::VerifyOrUnseal to verify the message. Typically,
|
||
the security package will generate a cryptographic checksum of the
|
||
message and include sequencing information.
|
||
|
||
Arguments:
|
||
|
||
SignNotSealFlag - Supplies a flag indicating that MakeSignature should
|
||
be called rather than SealMessage.
|
||
|
||
BufferDescriptor - Supplies the message to to signed or sealed and returns
|
||
the resulting message (after being signed or sealed).
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - This routine will always succeed.
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
SEAL_MESSAGE_FN SealMessage;
|
||
|
||
{
|
||
DWORD Status = 0;
|
||
|
||
CallTestHook( TH_SECURITY_FN_SIGN, this, &Status );
|
||
|
||
if (Status)
|
||
{
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
if ( SignNotSealFlag == 0 )
|
||
{
|
||
SealMessage = (SEAL_MESSAGE_FN) RpcSecurityInterface->Reserved3;
|
||
SecurityStatus = (*SealMessage)(&SecurityContext,
|
||
0, BufferDescriptor, Sequence);
|
||
}
|
||
else
|
||
{
|
||
SecurityStatus = (*RpcSecurityInterface->MakeSignature)(
|
||
&SecurityContext, 0, BufferDescriptor, Sequence);
|
||
}
|
||
|
||
#if DBG
|
||
if ( (SecurityStatus != SEC_E_OK)
|
||
&&(SecurityStatus != SEC_E_CONTEXT_EXPIRED)
|
||
&&(SecurityStatus != SEC_E_QOP_NOT_SUPPORTED) )
|
||
{
|
||
PrintToDebugger("Sign/Seal Returned [%lx]\n", SecurityStatus);
|
||
}
|
||
#endif
|
||
|
||
if ( SecurityStatus == SEC_E_SHUTDOWN_IN_PROGRESS )
|
||
{
|
||
SecurityStatus = ERROR_SHUTDOWN_IN_PROGRESS;
|
||
}
|
||
|
||
if (SecurityStatus != SEC_E_OK)
|
||
{
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
SecurityStatus,
|
||
EEInfoDLSignOrSeal10,
|
||
AuthenticationService,
|
||
AuthenticationLevel);
|
||
}
|
||
|
||
return(SecurityStatus);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
SECURITY_CONTEXT::VerifyOrUnseal (
|
||
IN unsigned long Sequence,
|
||
IN unsigned int VerifyNotUnsealFlag,
|
||
IN OUT SECURITY_BUFFER_DESCRIPTOR PAPI * BufferDescriptor
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine works with SECURITY_CONTEXT::SignOrSeal. A sender will
|
||
prepare a message using SignOrSeal, and then the receiver will use
|
||
this routine to verify that the message has not been tampered with, and
|
||
that it has not been exchanged out of sequence.
|
||
|
||
Arguments:
|
||
|
||
VerifyNotUnsealFlag - Supplies a flag indicating that VerifySignature
|
||
should be called rather than UnsealMessage.
|
||
|
||
BufferDescriptor - Supplies the message to be verified or unsealed.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - The message has not been tampered with, and it is from the
|
||
expected client.
|
||
|
||
RPC_S_ACCESS_DENIED - A security violation occured.
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
unsigned long QualityOfProtection;
|
||
UNSEAL_MESSAGE_FN UnsealMessage;
|
||
|
||
{
|
||
DWORD Status = 0;
|
||
|
||
CallTestHook( TH_SECURITY_FN_VERIFY, this, &Status );
|
||
|
||
if (Status)
|
||
{
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the context had failed previously..
|
||
// Just go ahead and return an error..
|
||
// This is only for connetion-oriented RPC.
|
||
//
|
||
if (FailedContext != 0 || !FullyConstructed() )
|
||
{
|
||
RpcpSetEEInfo(FailedContextEEInfo);
|
||
FailedContextEEInfo = NULL;
|
||
SetLastError(FailedContext);
|
||
|
||
if ((FailedContext == ERROR_PASSWORD_MUST_CHANGE)
|
||
|| (FailedContext == ERROR_PASSWORD_EXPIRED)
|
||
|| (FailedContext == ERROR_ACCOUNT_DISABLED)
|
||
|| (FailedContext == ERROR_INVALID_LOGON_HOURS))
|
||
{
|
||
return FailedContext;
|
||
}
|
||
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
RPC_S_ACCESS_DENIED,
|
||
EEInfoDLVerifyOrUnseal20,
|
||
FailedContext);
|
||
|
||
return (RPC_S_ACCESS_DENIED);
|
||
}
|
||
|
||
if ( VerifyNotUnsealFlag == 0 )
|
||
{
|
||
UnsealMessage = (UNSEAL_MESSAGE_FN) RpcSecurityInterface->Reserved4;
|
||
SecurityStatus = (*UnsealMessage)(
|
||
&SecurityContext, BufferDescriptor, Sequence,
|
||
&QualityOfProtection);
|
||
}
|
||
else
|
||
{
|
||
SecurityStatus = (*RpcSecurityInterface->VerifySignature)(
|
||
&SecurityContext, BufferDescriptor, Sequence,
|
||
&QualityOfProtection);
|
||
}
|
||
|
||
if ( SecurityStatus != SEC_E_OK )
|
||
{
|
||
|
||
#if DBG
|
||
if ((SecurityStatus != SEC_E_MESSAGE_ALTERED)
|
||
&&(SecurityStatus != SEC_E_OUT_OF_SEQUENCE)
|
||
&&(SecurityStatus != SEC_E_SECPKG_NOT_FOUND)) // on system shutdown, if the security
|
||
{ // package is already uninitialized, we may get this error
|
||
PrintToDebugger("Verify/UnSeal Returned Unexp. Code [%lx]\n",
|
||
SecurityStatus);
|
||
}
|
||
#endif
|
||
|
||
SetExtendedError(SecurityStatus);
|
||
|
||
if ( SecurityStatus == SEC_E_SHUTDOWN_IN_PROGRESS )
|
||
{
|
||
SecurityStatus = ERROR_SHUTDOWN_IN_PROGRESS;
|
||
}
|
||
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
RPC_S_ACCESS_DENIED,
|
||
EEInfoDLVerifyOrUnseal10,
|
||
SecurityStatus,
|
||
AuthenticationService,
|
||
AuthenticationLevel);
|
||
|
||
ASSERT( (SecurityStatus == SEC_E_MESSAGE_ALTERED) ||
|
||
(SecurityStatus == SEC_E_OUT_OF_SEQUENCE) ||
|
||
(SecurityStatus == SEC_E_SECPKG_NOT_FOUND) );
|
||
SetLastError(RPC_S_ACCESS_DENIED);
|
||
|
||
return(RPC_S_ACCESS_DENIED);
|
||
}
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
SECURITY_CONTEXT::InitializeFirstTime (
|
||
IN SECURITY_CREDENTIALS * Credentials,
|
||
IN RPC_CHAR * ServerPrincipalName,
|
||
IN unsigned long AuthenticationLevel,
|
||
IN OUT SECURITY_BUFFER_DESCRIPTOR PAPI * BufferDescriptor,
|
||
IN OUT unsigned char *NewAuthType
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - Send the token to the server; everything worked fine so
|
||
far.
|
||
|
||
RPC_P_CONTINUE_NEEDED - Indicates that that everything is ok, but that
|
||
we need to call into the security package again when we have
|
||
received a token back from the server.
|
||
|
||
RPC_P_COMPLETE_NEEDED - Indicates that everyting is ok, but that we
|
||
need to call CompleteAuthToken before sending the message.
|
||
|
||
RPC_P_COMPLETE_AND_CONTINUE - Needs both a complete and a continue.
|
||
|
||
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
|
||
operation.
|
||
|
||
RPC_S_ACCESS_DENIED - Access is denied.
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
TimeStamp TimeStamp;
|
||
unsigned long ContextRequirements;
|
||
RPC_STATUS Status;
|
||
RPC_STATUS Status2;
|
||
unsigned char RetrievedAuthType;
|
||
BOOL fDone;
|
||
|
||
ASSERT( ( SecuritySupportLoaded != 0 )
|
||
&& ( FailedToLoad == 0 ) );
|
||
|
||
RpcSecurityInterface = Credentials->InquireProviderFunctionTable();
|
||
|
||
switch ( AuthenticationLevel )
|
||
{
|
||
case RPC_C_AUTHN_LEVEL_CONNECT :
|
||
ContextRequirements = 0;
|
||
break;
|
||
|
||
case RPC_C_AUTHN_LEVEL_PKT :
|
||
ContextRequirements = ISC_REQ_REPLAY_DETECT;
|
||
break;
|
||
|
||
case RPC_C_AUTHN_LEVEL_PKT_INTEGRITY :
|
||
ContextRequirements = ISC_REQ_REPLAY_DETECT
|
||
| ISC_REQ_SEQUENCE_DETECT
|
||
| ISC_REQ_INTEGRITY;
|
||
break;
|
||
|
||
case RPC_C_AUTHN_LEVEL_PKT_PRIVACY :
|
||
ContextRequirements = ISC_REQ_REPLAY_DETECT
|
||
| ISC_REQ_SEQUENCE_DETECT
|
||
| ISC_REQ_CONFIDENTIALITY
|
||
| ISC_REQ_INTEGRITY;
|
||
break;
|
||
|
||
default :
|
||
ASSERT( ( AuthenticationLevel == RPC_C_AUTHN_LEVEL_CONNECT )
|
||
|| ( AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT )
|
||
|| ( AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY )
|
||
|| ( AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY ) );
|
||
return RPC_S_INTERNAL_ERROR;
|
||
}
|
||
|
||
|
||
if (fDatagram)
|
||
{
|
||
ContextRequirements |= ISC_REQ_DATAGRAM;
|
||
}
|
||
else
|
||
{
|
||
ContextRequirements |= ISC_REQ_CONNECTION;
|
||
}
|
||
|
||
switch(ImpersonationType)
|
||
{
|
||
case RPC_C_IMP_LEVEL_IDENTIFY:
|
||
ContextRequirements |= ISC_REQ_IDENTIFY;
|
||
break;
|
||
|
||
case RPC_C_IMP_LEVEL_IMPERSONATE:
|
||
break;
|
||
|
||
case RPC_C_IMP_LEVEL_DELEGATE:
|
||
ContextRequirements |= ISC_REQ_DELEGATE;
|
||
break;
|
||
|
||
default:
|
||
ASSERT( ImpersonationType == RPC_C_IMP_LEVEL_ANONYMOUS
|
||
|| ImpersonationType == RPC_C_IMP_LEVEL_IDENTIFY
|
||
|| ImpersonationType == RPC_C_IMP_LEVEL_IMPERSONATE
|
||
|| ImpersonationType == RPC_C_IMP_LEVEL_DELEGATE );
|
||
ContextRequirements |= ISC_REQ_IDENTIFY;
|
||
break;
|
||
}
|
||
|
||
if (Capabilities == RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH)
|
||
{
|
||
ContextRequirements |= ISC_REQ_MUTUAL_AUTH;
|
||
}
|
||
|
||
if (Credentials->AuthenticationService == RPC_C_AUTHN_GSS_SCHANNEL)
|
||
{
|
||
#if MANUAL_CERT_CHECK
|
||
ContextRequirements |= ISC_REQ_MANUAL_CRED_VALIDATION;
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
ContextRequirements |= ISC_REQ_USE_DCE_STYLE;
|
||
}
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->InitializeSecurityContext)(
|
||
Credentials->InquireCredHandle(),
|
||
0,
|
||
(SEC_TCHAR __SEC_FAR *) ServerPrincipalName,
|
||
ContextRequirements,
|
||
0,
|
||
0,
|
||
(fDatagram ? BufferDescriptor : 0),
|
||
0,
|
||
&SecurityContext,
|
||
(fDatagram ? 0 : BufferDescriptor),
|
||
&ContextAttributes,
|
||
&TimeStamp
|
||
);
|
||
|
||
if ( ( SecurityStatus != SEC_E_OK )
|
||
&& ( SecurityStatus != SEC_I_CONTINUE_NEEDED )
|
||
&& ( SecurityStatus != SEC_I_COMPLETE_NEEDED )
|
||
&& ( SecurityStatus != SEC_I_COMPLETE_AND_CONTINUE ) )
|
||
{
|
||
SetExtendedError(SecurityStatus);
|
||
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
SecurityStatus,
|
||
EEInfoDLInitializeFirstTime10,
|
||
AuthenticationService,
|
||
AuthenticationLevel,
|
||
ServerPrincipalName,
|
||
ContextRequirements);
|
||
|
||
if ((SecurityStatus == SEC_E_NO_CREDENTIALS)
|
||
|| (SecurityStatus == SEC_E_LOGON_DENIED)
|
||
|| (SecurityStatus == SEC_E_INVALID_TOKEN)
|
||
|| (SecurityStatus == SEC_E_UNKNOWN_CREDENTIALS)
|
||
|| (SecurityStatus == SEC_E_NO_KERB_KEY)
|
||
|| (SecurityStatus == SEC_E_TIME_SKEW) )
|
||
{
|
||
Status = RPC_S_ACCESS_DENIED;
|
||
}
|
||
else if ( SecurityStatus == SEC_E_SHUTDOWN_IN_PROGRESS )
|
||
{
|
||
Status = ERROR_SHUTDOWN_IN_PROGRESS;
|
||
}
|
||
else if (SecurityStatus == SEC_E_SECPKG_NOT_FOUND)
|
||
{
|
||
Status = RPC_S_UNKNOWN_AUTHN_SERVICE;
|
||
}
|
||
else if ( SecurityStatus == SEC_E_INSUFFICIENT_MEMORY )
|
||
{
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
else
|
||
{
|
||
#if DBG
|
||
PrintToDebugger("RPC: InitializeFirstTime Returned %lx\n", SecurityStatus);
|
||
#endif
|
||
//
|
||
// Originally the default for all providers was SEC_PKG_ERROR. This seems less
|
||
// helpful than ACCESS_DENIED, but we can't change it for NTLM and Kerberos because
|
||
// it might break old app code.
|
||
//
|
||
// SCHANNEL is new, so we can return ACCESS_DENIED.
|
||
//
|
||
if (AuthenticationService == RPC_C_AUTHN_GSS_SCHANNEL)
|
||
{
|
||
Status = RPC_S_ACCESS_DENIED;
|
||
}
|
||
else
|
||
{
|
||
Status = RPC_S_SEC_PKG_ERROR;
|
||
}
|
||
}
|
||
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
Status,
|
||
EEInfoDLInitializeFirstTime20,
|
||
SecurityStatus);
|
||
|
||
return Status;
|
||
}
|
||
|
||
RetrievedAuthType = 0;
|
||
|
||
DontForgetToDelete = 1;
|
||
|
||
if (NewAuthType)
|
||
{
|
||
ASSERT(*NewAuthType == this->AuthenticationService);
|
||
|
||
if (*NewAuthType == RPC_C_AUTHN_GSS_NEGOTIATE)
|
||
{
|
||
SecPkgContext_NegotiationInfo NegoInfo;
|
||
SECURITY_STATUS Status;
|
||
|
||
Status = (*RpcSecurityInterface->QueryContextAttributes)(
|
||
&SecurityContext,
|
||
SECPKG_ATTR_NEGOTIATION_INFO,
|
||
&NegoInfo);
|
||
if (Status == SEC_E_OK)
|
||
{
|
||
if (NegoInfo.NegotiationState == SECPKG_NEGOTIATION_COMPLETE)
|
||
{
|
||
RetrievedAuthType = (unsigned char) NegoInfo.PackageInfo->wRPCID;
|
||
}
|
||
(*RpcSecurityInterface->FreeContextBuffer)(NegoInfo.PackageInfo);
|
||
}
|
||
else
|
||
{
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
RPC_S_OUT_OF_MEMORY,
|
||
EEInfoDLInitializeFirstTime30,
|
||
Status,
|
||
(ULONG)AuthenticationService,
|
||
AuthenticationLevel,
|
||
(ULONG)ContextRequirements);
|
||
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
}
|
||
}
|
||
|
||
Flags = ContextRequirements;
|
||
|
||
fDone = TRUE;
|
||
|
||
if ( SecurityStatus == SEC_I_CONTINUE_NEEDED )
|
||
{
|
||
if (!fDatagram)
|
||
{
|
||
fDone = FALSE;
|
||
}
|
||
Status = RPC_P_CONTINUE_NEEDED;
|
||
}
|
||
|
||
else if ( SecurityStatus == SEC_I_COMPLETE_NEEDED )
|
||
{
|
||
// Can't set the maximum lengths on a partly completed connection.
|
||
|
||
Status = RPC_P_COMPLETE_NEEDED;
|
||
}
|
||
else if ( SecurityStatus == SEC_I_COMPLETE_AND_CONTINUE )
|
||
{
|
||
if (!fDatagram)
|
||
{
|
||
fDone = FALSE;
|
||
}
|
||
Status = RPC_P_COMPLETE_AND_CONTINUE;
|
||
}
|
||
else
|
||
{
|
||
Status = RPC_S_OK;
|
||
}
|
||
|
||
if (fDone)
|
||
{
|
||
fFullyConstructed = TRUE;
|
||
|
||
Status2 = SetMaximumLengths();
|
||
if (Status2 != RPC_S_OK)
|
||
{
|
||
return Status2;
|
||
}
|
||
}
|
||
|
||
if (RetrievedAuthType)
|
||
*NewAuthType = RetrievedAuthType;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
SECURITY_CONTEXT::InitializeThirdLeg (
|
||
IN SECURITY_CREDENTIALS * Credentials,
|
||
IN unsigned long DataRepresentation,
|
||
IN SECURITY_BUFFER_DESCRIPTOR PAPI * InputBufferDescriptor,
|
||
IN OUT SECURITY_BUFFER_DESCRIPTOR PAPI * OutputBufferDescriptor
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - Send the token to the server; everything worked fine so
|
||
far.
|
||
|
||
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
|
||
operation.
|
||
|
||
RPC_S_ACCESS_DENIED - Access is denied.
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
TimeStamp TimeStamp;
|
||
RPC_STATUS Status;
|
||
|
||
ASSERT( (SecuritySupportLoaded != 0)
|
||
&& (FailedToLoad == 0) );
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->InitializeSecurityContext)(
|
||
Credentials->InquireCredHandle(),
|
||
&SecurityContext,
|
||
0,
|
||
Flags,
|
||
0,
|
||
DataRepresentation,
|
||
InputBufferDescriptor,
|
||
0,
|
||
&SecurityContext,
|
||
OutputBufferDescriptor,
|
||
&ContextAttributes,
|
||
&TimeStamp
|
||
);
|
||
|
||
if ( ( SecurityStatus != SEC_E_OK )
|
||
&& ( SecurityStatus != SEC_I_CONTINUE_NEEDED )
|
||
&& ( SecurityStatus != SEC_I_COMPLETE_NEEDED )
|
||
&& ( SecurityStatus != SEC_I_COMPLETE_AND_CONTINUE ) )
|
||
{
|
||
SetExtendedError(SecurityStatus);
|
||
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
SecurityStatus,
|
||
EEInfoDLInitializeThirdLeg10,
|
||
AuthenticationService,
|
||
AuthenticationLevel,
|
||
ContextAttributes);
|
||
|
||
if ( (SecurityStatus == SEC_E_NO_CREDENTIALS)
|
||
|| (SecurityStatus == SEC_E_LOGON_DENIED)
|
||
|| (SecurityStatus == SEC_E_INVALID_TOKEN)
|
||
|| (SecurityStatus == SEC_E_UNKNOWN_CREDENTIALS)
|
||
|| (SecurityStatus == SEC_E_NO_KERB_KEY)
|
||
|| (SecurityStatus == SEC_E_TIME_SKEW) )
|
||
{
|
||
Status = RPC_S_ACCESS_DENIED;
|
||
}
|
||
else if ( SecurityStatus == SEC_E_SHUTDOWN_IN_PROGRESS )
|
||
{
|
||
Status = ERROR_SHUTDOWN_IN_PROGRESS;
|
||
}
|
||
else if (SecurityStatus == SEC_E_SECPKG_NOT_FOUND)
|
||
{
|
||
Status = RPC_S_UNKNOWN_AUTHN_SERVICE;
|
||
}
|
||
else if ( SecurityStatus == SEC_E_INSUFFICIENT_MEMORY )
|
||
{
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
else
|
||
{
|
||
#if DBG
|
||
PrintToDebugger("RPC: InitializeThirdLeg Returned %lx\n",
|
||
SecurityStatus );
|
||
#endif
|
||
//
|
||
// Originally the default for all connection-oriented providers
|
||
// was SEC_PKG_ERROR. This seems less helpful than ACESS_DENIED,
|
||
// but we can't change it for NTLM and Kerberos because it might
|
||
// break old app code. SCHANNEL is new, so we can return ACCESS_DENIED.
|
||
//
|
||
// Datagram returns the bare error code.
|
||
//
|
||
if (AuthenticationService == RPC_C_AUTHN_GSS_SCHANNEL)
|
||
{
|
||
Status = RPC_S_ACCESS_DENIED;
|
||
}
|
||
else if (fDatagram)
|
||
{
|
||
// leave the error code alone
|
||
}
|
||
else
|
||
{
|
||
Status = RPC_S_SEC_PKG_ERROR;
|
||
}
|
||
}
|
||
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
Status,
|
||
EEInfoDLInitializeThirdLeg20,
|
||
SecurityStatus);
|
||
|
||
return Status;
|
||
}
|
||
|
||
if ( SecurityStatus == SEC_I_CONTINUE_NEEDED )
|
||
{
|
||
return(RPC_P_CONTINUE_NEEDED);
|
||
}
|
||
|
||
if ( SecurityStatus == SEC_I_COMPLETE_AND_CONTINUE )
|
||
{
|
||
return(RPC_P_COMPLETE_AND_CONTINUE);
|
||
}
|
||
|
||
ASSERT(SecurityStatus == SEC_E_OK
|
||
|| SecurityStatus == SEC_I_COMPLETE_NEEDED);
|
||
|
||
if ( (ImpersonationType == RPC_C_IMP_LEVEL_IDENTIFY) &&
|
||
(!(ContextAttributes & ISC_RET_IDENTIFY)) )
|
||
{
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
RPC_S_SEC_PKG_ERROR,
|
||
EEInfoDLInitializeThirdLeg30,
|
||
SEC_E_SECURITY_QOS_FAILED,
|
||
ImpersonationType,
|
||
ContextAttributes);
|
||
SetExtendedError(SEC_E_SECURITY_QOS_FAILED);
|
||
return (RPC_S_SEC_PKG_ERROR);
|
||
}
|
||
|
||
if ( (ImpersonationType == RPC_C_IMP_LEVEL_DELEGATE) &&
|
||
(!(ContextAttributes & ISC_RET_DELEGATE)) )
|
||
{
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
RPC_S_SEC_PKG_ERROR,
|
||
EEInfoDLInitializeThirdLeg40,
|
||
SEC_E_SECURITY_QOS_FAILED,
|
||
ImpersonationType,
|
||
ContextAttributes);
|
||
SetExtendedError(SEC_E_SECURITY_QOS_FAILED);
|
||
return (RPC_S_SEC_PKG_ERROR);
|
||
}
|
||
|
||
if ( (!(ContextAttributes & ISC_RET_MUTUAL_AUTH) )&&
|
||
(Capabilities == RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH) )
|
||
{
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
RPC_S_SEC_PKG_ERROR,
|
||
EEInfoDLInitializeThirdLeg50,
|
||
SEC_E_SECURITY_QOS_FAILED,
|
||
ImpersonationType,
|
||
ContextAttributes);
|
||
SetExtendedError(SEC_E_SECURITY_QOS_FAILED);
|
||
return (RPC_S_SEC_PKG_ERROR);
|
||
}
|
||
|
||
if ( SecurityStatus == SEC_I_COMPLETE_NEEDED )
|
||
{
|
||
fFullyConstructed = TRUE;
|
||
|
||
Status = SetMaximumLengths();
|
||
if (Status != RPC_S_OK)
|
||
return Status;
|
||
return(RPC_P_COMPLETE_NEEDED);
|
||
}
|
||
|
||
fFullyConstructed = TRUE;
|
||
|
||
Status = SetMaximumLengths();
|
||
if (Status != RPC_S_OK)
|
||
return Status;
|
||
|
||
if (AuthenticationService == RPC_C_AUTHN_GSS_SCHANNEL)
|
||
{
|
||
return VerifyCertificate();
|
||
}
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
RPC_STATUS
|
||
SECURITY_CONTEXT::GetWireIdForSnego(
|
||
OUT unsigned char *WireId
|
||
)
|
||
{
|
||
SecPkgContext_NegotiationInfo NegoInfo;
|
||
SECURITY_STATUS SecStatus;
|
||
RPC_STATUS RpcStatus = RPC_S_OK;
|
||
|
||
if (AuthenticationService != RPC_C_AUTHN_GSS_NEGOTIATE)
|
||
return RPC_S_INVALID_BINDING;
|
||
|
||
ASSERT(RpcSecurityInterface != NULL);
|
||
|
||
SecStatus = (*RpcSecurityInterface->QueryContextAttributes)(
|
||
&SecurityContext,
|
||
SECPKG_ATTR_NEGOTIATION_INFO,
|
||
&NegoInfo);
|
||
if (SecStatus == SEC_E_OK)
|
||
{
|
||
if (NegoInfo.NegotiationState == SECPKG_NEGOTIATION_COMPLETE)
|
||
{
|
||
*WireId = (unsigned char) NegoInfo.PackageInfo->wRPCID;
|
||
}
|
||
else
|
||
RpcStatus = RPC_S_SEC_PKG_ERROR;
|
||
|
||
(*RpcSecurityInterface->FreeContextBuffer)(NegoInfo.PackageInfo);
|
||
}
|
||
else
|
||
{
|
||
SetExtendedError(SecStatus);
|
||
RpcStatus = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
return RpcStatus;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
SECURITY_CONTEXT::AcceptFirstTime (
|
||
IN SECURITY_CREDENTIALS * NewCredentials,
|
||
IN SECURITY_BUFFER_DESCRIPTOR PAPI * InputBufferDescriptor,
|
||
IN OUT SECURITY_BUFFER_DESCRIPTOR PAPI * OutputBufferDescriptor,
|
||
IN unsigned long AuthenticationLevel,
|
||
IN unsigned long DataRepresentation,
|
||
IN unsigned long NewContextNeededFlag
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - Everything worked just fine.
|
||
|
||
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
|
||
operation.
|
||
|
||
RPC_P_CONTINUE_NEEDED - Indicates that everything is ok, but that we
|
||
need to send the output token back to the client, and then wait
|
||
for a token back from the client.
|
||
|
||
RPC_P_COMPLETE_NEEDED - Indicates that everyting is ok, but that we
|
||
need to call CompleteAuthToken before sending the message.
|
||
|
||
RPC_P_COMPLETE_AND_CONTINUE - Needs both a complete and a continue.
|
||
|
||
RPC_S_ACCESS_DENIED - Access is denied.
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
TimeStamp TimeStamp;
|
||
unsigned long ContextRequirements;
|
||
RPC_STATUS RpcStatus;
|
||
DWORD Status = 0;
|
||
|
||
ASSERT( (SecuritySupportLoaded != 0)
|
||
&& (FailedToLoad == 0) );
|
||
|
||
if (Credentials)
|
||
{
|
||
Credentials->DereferenceCredentials();
|
||
}
|
||
Credentials = NewCredentials;
|
||
Credentials->ReferenceCredentials();
|
||
|
||
RpcSecurityInterface = Credentials->InquireProviderFunctionTable();
|
||
|
||
if (NewContextNeededFlag == 1)
|
||
{
|
||
DeleteSecurityContext();
|
||
}
|
||
|
||
switch ( AuthenticationLevel )
|
||
{
|
||
case RPC_C_AUTHN_LEVEL_CONNECT :
|
||
ContextRequirements = ASC_REQ_MUTUAL_AUTH;
|
||
break;
|
||
|
||
case RPC_C_AUTHN_LEVEL_PKT :
|
||
ContextRequirements = ASC_REQ_MUTUAL_AUTH
|
||
| ASC_REQ_REPLAY_DETECT;
|
||
break;
|
||
|
||
case RPC_C_AUTHN_LEVEL_PKT_INTEGRITY :
|
||
ContextRequirements = ASC_REQ_MUTUAL_AUTH
|
||
| ASC_REQ_REPLAY_DETECT | ASC_REQ_SEQUENCE_DETECT;
|
||
break;
|
||
|
||
case RPC_C_AUTHN_LEVEL_PKT_PRIVACY :
|
||
ContextRequirements = ASC_REQ_MUTUAL_AUTH
|
||
| ASC_REQ_REPLAY_DETECT | ASC_REQ_SEQUENCE_DETECT
|
||
| ASC_REQ_CONFIDENTIALITY;
|
||
break;
|
||
|
||
default :
|
||
ASSERT(AuthenticationLevel == RPC_C_AUTHN_LEVEL_CONNECT ||
|
||
AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT ||
|
||
AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY ||
|
||
AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY );
|
||
return RPC_S_INTERNAL_ERROR;
|
||
}
|
||
|
||
if (fDatagram)
|
||
{
|
||
ContextRequirements |= ASC_REQ_DATAGRAM;
|
||
}
|
||
else
|
||
{
|
||
ContextRequirements |= ASC_REQ_CONNECTION;
|
||
}
|
||
|
||
if (Credentials->AuthenticationService == RPC_C_AUTHN_WINNT ||
|
||
Credentials->AuthenticationService == RPC_C_AUTHN_DCE_PRIVATE ||
|
||
Credentials->AuthenticationService == RPC_C_AUTHN_GSS_KERBEROS ||
|
||
Credentials->AuthenticationService == RPC_C_AUTHN_GSS_NEGOTIATE)
|
||
{
|
||
ContextRequirements |= ASC_REQ_USE_DCE_STYLE | ASC_REQ_DELEGATE;
|
||
}
|
||
|
||
if (AuthenticationService == RPC_C_AUTHN_WINNT
|
||
|| AuthenticationService == RPC_C_AUTHN_GSS_NEGOTIATE)
|
||
{
|
||
ContextRequirements |= ASC_REQ_ALLOW_NON_USER_LOGONS;
|
||
}
|
||
|
||
CallTestHook( TH_SECURITY_FN_ACCEPT1, this, &Status );
|
||
|
||
if (Status)
|
||
{
|
||
SetExtendedError(Status);
|
||
return Status;
|
||
}
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->AcceptSecurityContext)(
|
||
Credentials->InquireCredHandle(), 0, InputBufferDescriptor,
|
||
ContextRequirements, DataRepresentation, &SecurityContext,
|
||
OutputBufferDescriptor, &ContextAttributes, &TimeStamp);
|
||
|
||
if ( ( SecurityStatus != SEC_E_OK )
|
||
&& ( SecurityStatus != SEC_I_CONTINUE_NEEDED )
|
||
&& ( SecurityStatus != SEC_I_COMPLETE_NEEDED )
|
||
&& ( SecurityStatus != SEC_I_COMPLETE_AND_CONTINUE ) )
|
||
{
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
SecurityStatus,
|
||
EEInfoDLAcceptFirstTime10,
|
||
AuthenticationService,
|
||
AuthenticationLevel,
|
||
ContextRequirements);
|
||
|
||
SetExtendedError(SecurityStatus);
|
||
|
||
if ( (SecurityStatus == SEC_E_NO_CREDENTIALS)
|
||
|| (SecurityStatus == SEC_E_LOGON_DENIED)
|
||
|| (SecurityStatus == SEC_E_INVALID_TOKEN)
|
||
|| (SecurityStatus == SEC_E_NO_AUTHENTICATING_AUTHORITY)
|
||
|| (SecurityStatus == SEC_E_UNKNOWN_CREDENTIALS)
|
||
|| (SecurityStatus == SEC_E_CONTEXT_EXPIRED)
|
||
|| (SecurityStatus == SEC_E_TIME_SKEW))
|
||
{
|
||
RpcStatus = RPC_S_ACCESS_DENIED;
|
||
}
|
||
else if ( SecurityStatus == SEC_E_SHUTDOWN_IN_PROGRESS )
|
||
{
|
||
RpcStatus = ERROR_SHUTDOWN_IN_PROGRESS;
|
||
}
|
||
else if (SecurityStatus == SEC_E_SECPKG_NOT_FOUND)
|
||
{
|
||
RpcStatus = RPC_S_UNKNOWN_AUTHN_SERVICE;
|
||
}
|
||
else
|
||
RpcStatus = RPC_S_OUT_OF_MEMORY;
|
||
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
RpcStatus,
|
||
EEInfoDLAcceptFirstTime20,
|
||
SecurityStatus);
|
||
|
||
return RpcStatus;
|
||
}
|
||
|
||
DontForgetToDelete = 1;
|
||
|
||
Flags = ContextRequirements;
|
||
|
||
if ( SecurityStatus == SEC_I_CONTINUE_NEEDED )
|
||
{
|
||
return(RPC_P_CONTINUE_NEEDED);
|
||
}
|
||
if ( SecurityStatus == SEC_I_COMPLETE_AND_CONTINUE )
|
||
{
|
||
return(RPC_P_COMPLETE_AND_CONTINUE);
|
||
}
|
||
|
||
ASSERT((SecurityStatus == SEC_I_COMPLETE_NEEDED)
|
||
|| (SecurityStatus == SEC_E_OK));
|
||
|
||
|
||
fFullyConstructed = TRUE;
|
||
|
||
RpcStatus = SetMaximumLengths();
|
||
if (RpcStatus != RPC_S_OK)
|
||
return RpcStatus;
|
||
|
||
Credentials->DereferenceCredentials();
|
||
Credentials = 0;
|
||
if ( SecurityStatus == SEC_I_COMPLETE_NEEDED )
|
||
return(RPC_P_COMPLETE_NEEDED);
|
||
else
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
SECURITY_CONTEXT::AcceptThirdLeg (
|
||
IN unsigned long DataRepresentation,
|
||
IN SECURITY_BUFFER_DESCRIPTOR PAPI * BufferDescriptor,
|
||
OUT SECURITY_BUFFER_DESCRIPTOR PAPI * OutBufferDescriptor
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - Everything worked just fine.
|
||
|
||
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
|
||
operation.
|
||
|
||
RPC_S_ACCESS_DENIED - Access is denied.
|
||
|
||
RPC_P_COMPLETE_NEEDED - Indicates that everyting is ok, but that we
|
||
need to call CompleteAuthToken before sending the message.
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
TimeStamp TimeStamp;
|
||
RPC_STATUS RpcStatus;
|
||
|
||
ASSERT( (SecuritySupportLoaded != 0)
|
||
&& (FailedToLoad == 0) );
|
||
|
||
SetLastError(0);
|
||
|
||
|
||
{
|
||
DWORD Status = 0;
|
||
|
||
CallTestHook( TH_SECURITY_FN_ACCEPT3, this, &Status );
|
||
|
||
if (Status)
|
||
{
|
||
FailedContext = Status;
|
||
|
||
SetExtendedError(Status);
|
||
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->AcceptSecurityContext)(
|
||
Credentials->InquireCredHandle(),
|
||
&SecurityContext,
|
||
BufferDescriptor,
|
||
Flags,
|
||
DataRepresentation,
|
||
&SecurityContext,
|
||
OutBufferDescriptor,
|
||
&ContextAttributes,
|
||
&TimeStamp
|
||
);
|
||
|
||
//
|
||
// If 3rd Leg Failed Bit is set, map all errors other than out of memory
|
||
// to SUCCESS
|
||
//
|
||
if (
|
||
(
|
||
( SecurityStatus != SEC_E_OK )
|
||
&& ( SecurityStatus != SEC_I_COMPLETE_NEEDED)
|
||
&& ( SecurityStatus != SEC_I_CONTINUE_NEEDED)
|
||
&& ( SecurityStatus != SEC_I_COMPLETE_AND_CONTINUE)
|
||
&& ( SecurityStatus != SEC_E_INSUFFICIENT_MEMORY )
|
||
&& ( ContextAttributes & ASC_RET_THIRD_LEG_FAILED )
|
||
)
|
||
||
|
||
(
|
||
( SecurityStatus == SEC_E_LOGON_DENIED )
|
||
|| ( SecurityStatus == SEC_E_NO_CREDENTIALS )
|
||
|| ( SecurityStatus == SEC_E_INVALID_TOKEN )
|
||
|| ( SecurityStatus == SEC_E_UNKNOWN_CREDENTIALS )
|
||
|| ( SecurityStatus == SEC_E_NO_AUTHENTICATING_AUTHORITY )
|
||
|| ( SecurityStatus == SEC_E_TIME_SKEW )
|
||
)
|
||
)
|
||
{
|
||
FailedContext = GetLastError();
|
||
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
SecurityStatus,
|
||
EEInfoDLAcceptThirdLeg10,
|
||
AuthenticationService,
|
||
AuthenticationLevel,
|
||
FailedContext);
|
||
|
||
if (!fDatagram)
|
||
{
|
||
SecurityStatus = SEC_E_OK;
|
||
}
|
||
|
||
SetExtendedError(SecurityStatus);
|
||
|
||
if ( (FailedContext != ERROR_PASSWORD_MUST_CHANGE)
|
||
&& (FailedContext != ERROR_PASSWORD_EXPIRED)
|
||
&& (FailedContext != ERROR_ACCOUNT_DISABLED)
|
||
&& (FailedContext != ERROR_INVALID_LOGON_HOURS) )
|
||
{
|
||
FailedContext = RPC_S_ACCESS_DENIED;
|
||
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
FailedContext,
|
||
EEInfoDLAcceptThirdLeg30);
|
||
}
|
||
|
||
ASSERT(FailedContextEEInfo == NULL);
|
||
FailedContextEEInfo = RpcpGetEEInfo();
|
||
RpcpClearEEInfo();
|
||
}
|
||
|
||
if ( ( SecurityStatus != SEC_E_OK )
|
||
&& ( SecurityStatus != SEC_I_COMPLETE_NEEDED )
|
||
&& ( SecurityStatus != SEC_I_CONTINUE_NEEDED )
|
||
&& ( SecurityStatus != SEC_I_COMPLETE_AND_CONTINUE ) )
|
||
{
|
||
SetExtendedError(SecurityStatus);
|
||
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
SecurityStatus,
|
||
EEInfoDLAcceptThirdLeg20,
|
||
AuthenticationService,
|
||
AuthenticationLevel);
|
||
|
||
DontForgetToDelete = 0;
|
||
|
||
if ( SecurityStatus == SEC_E_SHUTDOWN_IN_PROGRESS )
|
||
{
|
||
RpcStatus = ERROR_SHUTDOWN_IN_PROGRESS;
|
||
}
|
||
else if ( (SecurityStatus == SEC_E_SECPKG_NOT_FOUND)
|
||
|| (SecurityStatus == SEC_E_NO_CREDENTIALS)
|
||
|| (SecurityStatus == SEC_E_LOGON_DENIED)
|
||
|| (SecurityStatus == SEC_E_INVALID_TOKEN)
|
||
|| (SecurityStatus == SEC_E_UNKNOWN_CREDENTIALS)
|
||
|| (SecurityStatus == SEC_E_NO_AUTHENTICATING_AUTHORITY)
|
||
|| (SecurityStatus == SEC_E_CONTEXT_EXPIRED)
|
||
|| (SecurityStatus == SEC_E_TIME_SKEW))
|
||
{
|
||
RpcStatus = RPC_S_ACCESS_DENIED;
|
||
}
|
||
else
|
||
{
|
||
ASSERT( SecurityStatus == SEC_E_INSUFFICIENT_MEMORY );
|
||
RpcStatus = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
RpcpErrorAddRecord (EEInfoGCRuntime,
|
||
RpcStatus,
|
||
EEInfoDLAcceptThirdLeg40,
|
||
SecurityStatus);
|
||
|
||
return RpcStatus;
|
||
}
|
||
|
||
if ( SecurityStatus == SEC_I_CONTINUE_NEEDED )
|
||
{
|
||
return(RPC_P_CONTINUE_NEEDED);
|
||
}
|
||
if ( SecurityStatus == SEC_I_COMPLETE_AND_CONTINUE )
|
||
{
|
||
return(RPC_P_COMPLETE_AND_CONTINUE);
|
||
}
|
||
|
||
|
||
ASSERT ( (SecurityStatus == SEC_I_COMPLETE_NEEDED)
|
||
|| (SecurityStatus == SEC_E_OK));
|
||
|
||
fFullyConstructed = TRUE;
|
||
|
||
RpcStatus = SetMaximumLengths();
|
||
if (RpcStatus)
|
||
{
|
||
FailedContext = RpcStatus;
|
||
|
||
ASSERT(FailedContextEEInfo == NULL);
|
||
FailedContextEEInfo = RpcpGetEEInfo();
|
||
RpcpClearEEInfo();
|
||
|
||
//
|
||
// We don't want to block third leg - mimic success
|
||
// Failed context has already been set
|
||
//
|
||
MaxSignatureLength = 256;
|
||
MaxHeaderLength = 256;
|
||
cbBlockSize = 64;
|
||
}
|
||
|
||
if (SecurityStatus == SEC_I_COMPLETE_NEEDED)
|
||
return(RPC_P_COMPLETE_NEEDED);
|
||
else
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
|
||
unsigned long
|
||
SECURITY_CONTEXT::InquireAuthorizationService (
|
||
)
|
||
/*++
|
||
|
||
Return Value:
|
||
|
||
The authorization service for this security context will be returned.
|
||
|
||
--*/
|
||
{
|
||
SecPkgContext_DceInfo DceInfo;
|
||
SECURITY_STATUS SecurityStatus;
|
||
SecurityStatus = (*RpcSecurityInterface->QueryContextAttributes)(
|
||
&SecurityContext, SECPKG_ATTR_DCE_INFO, &DceInfo);
|
||
ASSERT( SecurityStatus == SEC_E_OK );
|
||
return(DceInfo.AuthzSvc);
|
||
}
|
||
|
||
|
||
RPC_AUTHZ_HANDLE
|
||
SECURITY_CONTEXT::InquirePrivileges (
|
||
)
|
||
/*++
|
||
|
||
Return Value:
|
||
|
||
The privileges of the client at the other end of this security context
|
||
will be returned.
|
||
|
||
--*/
|
||
{
|
||
SecPkgContext_DceInfo DceInfo;
|
||
SECURITY_STATUS SecurityStatus;
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->QueryContextAttributes)(
|
||
&SecurityContext, SECPKG_ATTR_DCE_INFO, &DceInfo);
|
||
ASSERT( SecurityStatus == SEC_E_OK );
|
||
return(DceInfo.pPac);
|
||
}
|
||
|
||
|
||
DWORD
|
||
SECURITY_CONTEXT::GetDceInfo (
|
||
RPC_AUTHZ_HANDLE __RPC_FAR * PacHandle,
|
||
unsigned long __RPC_FAR * AuthzSvc
|
||
)
|
||
|
||
/*++
|
||
|
||
Return Value:
|
||
|
||
The privileges of the client at the other end of this security context
|
||
will be returned.
|
||
|
||
--*/
|
||
{
|
||
SecPkgContext_DceInfo DceInfo;
|
||
SECURITY_STATUS SecurityStatus;
|
||
|
||
*PacHandle = 0;
|
||
*AuthzSvc = 0;
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->QueryContextAttributes)(
|
||
&SecurityContext, SECPKG_ATTR_DCE_INFO, &DceInfo);
|
||
|
||
ASSERT( (SecurityStatus == SEC_E_OK)
|
||
|| (SecurityStatus == SEC_E_UNSUPPORTED_FUNCTION)
|
||
|| (SecurityStatus == SEC_E_INVALID_HANDLE));
|
||
|
||
if (SecurityStatus == SEC_E_OK)
|
||
{
|
||
*PacHandle = DceInfo.pPac;
|
||
*AuthzSvc = DceInfo.AuthzSvc;
|
||
return 0;
|
||
}
|
||
|
||
if (AuthenticationService == RPC_C_AUTHN_GSS_SCHANNEL)
|
||
{
|
||
SecurityStatus = (*RpcSecurityInterface->QueryContextAttributes)(
|
||
&SecurityContext, SECPKG_ATTR_REMOTE_CERT_CONTEXT, PacHandle);
|
||
|
||
if (SecurityStatus != SEC_E_OK)
|
||
{
|
||
*PacHandle = 0;
|
||
}
|
||
}
|
||
|
||
return SecurityStatus;
|
||
}
|
||
|
||
|
||
void
|
||
SECURITY_CONTEXT::DeleteSecurityContext (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
If there is a valid security context, we need to delete it.
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
unsigned int nRetries = 0;
|
||
|
||
if ( DontForgetToDelete != 0 )
|
||
{
|
||
if (AuthzClientContext)
|
||
{
|
||
AuthzFreeContextFn(AuthzClientContext);
|
||
AuthzClientContext = NULL;
|
||
}
|
||
|
||
// SEC_E_INSUFFICIENT_MEMORY may be returned under extremely low
|
||
// memory conditions. We will do the following:
|
||
// - Retry 10 times to delete the security context.
|
||
// - Raise a flag in the process that we have leaked one or more security contexts.
|
||
do
|
||
{
|
||
SecurityStatus = (*RpcSecurityInterface->DeleteSecurityContext)(
|
||
&SecurityContext );
|
||
nRetries++;
|
||
}
|
||
while (SecurityStatus == SEC_E_INSUFFICIENT_MEMORY && nRetries < 10);
|
||
|
||
if (SecurityStatus == SEC_E_INSUFFICIENT_MEMORY)
|
||
{
|
||
nSecurityContextsLeaked++;
|
||
}
|
||
|
||
// when the process shutdowns, the security system may return SEC_E_SECPKG_NOT_FOUND
|
||
// since it is uninitialized. This is the only time when this error will be
|
||
// returned, so it is safe to ignore.
|
||
if (SecurityStatus == SEC_E_SECPKG_NOT_FOUND)
|
||
SecurityStatus = SEC_E_OK;
|
||
|
||
#if DBG
|
||
if ((SecurityStatus != SEC_E_OK) && (SecurityStatus != SEC_E_SHUTDOWN_IN_PROGRESS))
|
||
{
|
||
PrintToDebugger("DeleteSecurityContext(0x%x) Returned [%lx]\n",
|
||
&SecurityContext,
|
||
SecurityStatus);
|
||
}
|
||
if (SecurityStatus == SEC_E_INSUFFICIENT_MEMORY)
|
||
{
|
||
PrintToDebugger("SecurityContext(0x%x) leaked\n",
|
||
&SecurityContext);
|
||
}
|
||
#endif
|
||
|
||
ASSERT( SecurityStatus == SEC_E_OK ||
|
||
SecurityStatus == SEC_E_SHUTDOWN_IN_PROGRESS ||
|
||
SecurityStatus == SEC_E_INSUFFICIENT_MEMORY);
|
||
|
||
DontForgetToDelete = 0;
|
||
}
|
||
|
||
if (FailedContextEEInfo)
|
||
{
|
||
FreeEEInfoChain(FailedContextEEInfo);
|
||
FailedContextEEInfo = NULL;
|
||
}
|
||
}
|
||
|
||
RPC_STATUS
|
||
SECURITY_CONTEXT::CheckForFailedThirdLeg (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
If the third leg has failed, we will return the error code
|
||
and restore the eeinfo.
|
||
|
||
--*/
|
||
{
|
||
ASSERT( ( SecuritySupportLoaded != 0 )
|
||
&& ( FailedToLoad == 0 ) );
|
||
|
||
if (FailedContext != 0)
|
||
{
|
||
if (FailedContextEEInfo)
|
||
{
|
||
RpcpSetEEInfo(FailedContextEEInfo);
|
||
FailedContextEEInfo = NULL;
|
||
}
|
||
return (RPC_S_ACCESS_DENIED);
|
||
}
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
void
|
||
SECURITY_CONTEXT::DeletePac(
|
||
void __RPC_FAR * PacHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
if (AuthenticationService == RPC_C_AUTHN_GSS_SCHANNEL)
|
||
{
|
||
if (!LoadCrypt32Imports())
|
||
{
|
||
return;
|
||
}
|
||
|
||
CertFreeCertificateContext( (PCERT_CONTEXT) PacHandle );
|
||
}
|
||
else
|
||
{
|
||
(*RpcSecurityInterface->FreeContextBuffer)( PacHandle );
|
||
}
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
SECURITY_CONTEXT::ImpersonateClient (
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The server thread calling this routine will impersonate the client at the
|
||
other end of this security context.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - The impersonation successfully occured.
|
||
|
||
RPC_S_NO_CONTEXT_AVAILABLE - There is no security context available to
|
||
be impersonated.
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
|
||
ASSERT( ( SecuritySupportLoaded != 0 )
|
||
&& ( FailedToLoad == 0 ) );
|
||
|
||
if (FailedContext != 0)
|
||
{
|
||
if (FailedContextEEInfo)
|
||
{
|
||
RpcpSetEEInfo(FailedContextEEInfo);
|
||
FailedContextEEInfo = NULL;
|
||
}
|
||
return (RPC_S_ACCESS_DENIED);
|
||
}
|
||
|
||
ASSERT( FullyConstructed() );
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->ImpersonateSecurityContext)(
|
||
&SecurityContext);
|
||
|
||
if ( SecurityStatus != SEC_E_OK )
|
||
{
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
RPC_S_NO_CONTEXT_AVAILABLE,
|
||
EEInfoDLImpersonateClient10,
|
||
SecurityStatus,
|
||
AuthenticationService,
|
||
AuthenticationLevel);
|
||
|
||
ASSERT( SecurityStatus == SEC_E_NO_IMPERSONATION );
|
||
return(RPC_S_NO_CONTEXT_AVAILABLE);
|
||
}
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
void
|
||
SECURITY_CONTEXT::RevertToSelf (
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The server thread calling this routine will stop impersonating. If the
|
||
thread is not impersonating, then this is a noop.
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
|
||
ASSERT( ( SecuritySupportLoaded != 0 )
|
||
&& ( FailedToLoad == 0 ) );
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->RevertSecurityContext)(
|
||
&SecurityContext);
|
||
|
||
ASSERT( SecurityStatus == SEC_E_OK );
|
||
}
|
||
|
||
RPC_STATUS
|
||
SECURITY_CONTEXT::GetAccessToken (
|
||
OUT HANDLE *ImpersonationToken,
|
||
OUT BOOL *fNeedToCloseToken
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the access token maintained by the security provider.
|
||
|
||
Arguments:
|
||
|
||
ImpersonationToken - contains the impersonation token on success
|
||
fNeedToCloseToken - true if the resulting token needs closing.
|
||
False otherwise. Some security providers support handing off
|
||
of the token itself (faster). Some don't. All support handing
|
||
off a copy of the token. Depending on what security provider
|
||
we have, we'll get the token, and set this variable. This
|
||
parameter is undefined in case of failure.
|
||
|
||
Return Value:
|
||
RPC_S_OK on success, or RPC_S_* on failure. Supports EEInfo.
|
||
|
||
--*/
|
||
{
|
||
SECURITY_STATUS SecurityStatus;
|
||
HANDLE Token;
|
||
|
||
ASSERT( ( SecuritySupportLoaded != 0 )
|
||
&& ( FailedToLoad == 0 ) );
|
||
|
||
ASSERT( FullyConstructed() );
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->QueryContextAttributes)(
|
||
&SecurityContext,
|
||
SECPKG_ATTR_ACCESS_TOKEN,
|
||
&Token);
|
||
|
||
if ( (SecurityStatus != SEC_E_OK)
|
||
&& (SecurityStatus != SEC_E_UNSUPPORTED_FUNCTION) )
|
||
{
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
RPC_S_NO_CONTEXT_AVAILABLE,
|
||
EEInfoDLSECURITY_CONTEXT__GetAccessToken10,
|
||
SecurityStatus,
|
||
AuthenticationService,
|
||
AuthenticationLevel);
|
||
|
||
ASSERT( 0 );
|
||
return(RPC_S_NO_CONTEXT_AVAILABLE);
|
||
}
|
||
|
||
if (SecurityStatus != SEC_E_OK)
|
||
{
|
||
ASSERT(SecurityStatus == SEC_E_UNSUPPORTED_FUNCTION);
|
||
|
||
// the security provider does not provide quick retrieval
|
||
// of token - go the long way
|
||
SecurityStatus = (*RpcSecurityInterface->QuerySecurityContextToken)(
|
||
&SecurityContext, &Token);
|
||
|
||
if (SecurityStatus != SEC_E_OK)
|
||
{
|
||
RpcpErrorAddRecord (EEInfoGCSecurityProvider,
|
||
RPC_S_NO_CONTEXT_AVAILABLE,
|
||
EEInfoDLSECURITY_CONTEXT__GetAccessToken20,
|
||
SecurityStatus,
|
||
AuthenticationService,
|
||
AuthenticationLevel);
|
||
|
||
ASSERT( SecurityStatus == SEC_E_NO_IMPERSONATION );
|
||
return(RPC_S_NO_CONTEXT_AVAILABLE);
|
||
}
|
||
|
||
*fNeedToCloseToken = TRUE;
|
||
}
|
||
else
|
||
{
|
||
*fNeedToCloseToken = FALSE;
|
||
}
|
||
|
||
*ImpersonationToken = Token;
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
PACKAGE_LEG_COUNT
|
||
GetPackageLegCount(
|
||
DWORD id
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This fn determines whether the given security package is a 3- or 4-leg
|
||
protocol. The relevance of this information is described in
|
||
ReadPackageLegInfo(). This fn. first searches the hardcoded entries in
|
||
PredefinedPackageLegInfo[], and if the package is not found it turns to the
|
||
registry information stored in FourLeggedPackages[].
|
||
|
||
Return Values:
|
||
|
||
LegsUnknown = the fn cannot give a reliable answer
|
||
|
||
ThreeLegs = this is a 3-leg protocol
|
||
|
||
EvenNumberOfLegs = this is not a 3-leg protocol
|
||
|
||
--*/
|
||
{
|
||
int i;
|
||
|
||
if ( InsureSecuritySupportLoaded() != RPC_S_OK )
|
||
{
|
||
return LegsUnknown;
|
||
}
|
||
|
||
for (i=0; PredefinedPackageLegInfo[i].Package != 0; ++i)
|
||
{
|
||
if (PredefinedPackageLegInfo[i].Package == id)
|
||
{
|
||
return PredefinedPackageLegInfo[i].Legs;
|
||
}
|
||
}
|
||
|
||
CLAIM_MUTEX Lock( *SecurityCritSect );
|
||
|
||
if (!FourLeggedPackages)
|
||
{
|
||
if (!ReadPackageLegInfo())
|
||
{
|
||
return LegsUnknown;
|
||
}
|
||
}
|
||
|
||
ASSERT(FourLeggedPackages);
|
||
|
||
for (i=0; FourLeggedPackages[i] != 0; ++i)
|
||
{
|
||
if (FourLeggedPackages[i] == id)
|
||
{
|
||
return EvenNumberOfLegs;
|
||
}
|
||
}
|
||
|
||
return ThreeLegs;
|
||
}
|
||
|
||
DWORD
|
||
SECURITY_CONTEXT::VerifyCertificate()
|
||
{
|
||
DWORD SecurityStatus = 0;
|
||
|
||
//
|
||
// Compare the name on the certificate against the expected principal name.
|
||
//
|
||
if (ServerPrincipalName)
|
||
{
|
||
//
|
||
// Get a copy of the raw certificate.
|
||
//
|
||
if (!LoadCrypt32Imports())
|
||
{
|
||
return GetLastError();
|
||
}
|
||
|
||
PCERT_CONTEXT ClientContext;
|
||
|
||
SecurityStatus = (*RpcSecurityInterface->QueryContextAttributes)(
|
||
&SecurityContext,
|
||
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
|
||
&ClientContext
|
||
);
|
||
if (SecurityStatus)
|
||
{
|
||
RpcpErrorAddRecord ( EEInfoGCSecurityProvider,
|
||
RPC_S_OUT_OF_MEMORY,
|
||
EEInfoDLInitializeThirdLeg60,
|
||
SecurityStatus );
|
||
|
||
ASSERT( SecurityStatus == SEC_E_INSUFFICIENT_MEMORY );
|
||
return SecurityStatus;
|
||
}
|
||
|
||
SecurityStatus = RpcCertMatchPrincipalName( ClientContext, ServerPrincipalName );
|
||
switch (SecurityStatus)
|
||
{
|
||
case 0:
|
||
case ERROR_NOT_ENOUGH_MEMORY:
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// we are supposed to have verified the princ name earlier.
|
||
//
|
||
ASSERT( SecurityStatus != ERROR_INVALID_PARAMETER );
|
||
|
||
SetExtendedError(SecurityStatus);
|
||
|
||
SecurityStatus = RPC_S_ACCESS_DENIED;
|
||
break;
|
||
}
|
||
|
||
CertFreeCertificateContext( ClientContext );
|
||
}
|
||
|
||
return SecurityStatus;
|
||
}
|