Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1552 lines
40 KiB

//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 1992 - 1996
//
// File: kerberos.cxx
//
// Contents: main entrypoints for the Kerberos security package
//
//
// History: 16-April-1996 Created MikeSw
// 26-Sep-1998 ChandanS
// Added more debugging support etc.
//
//------------------------------------------------------------------------
#include <kerb.hxx>
#define KERBP_ALLOCATE
#include <kerbp.h>
#include <userapi.h>
#include <safeboot.h>
#include <wow64t.h>
#ifdef RETAIL_LOG_SUPPORT
static TCHAR THIS_FILE[]=TEXT(__FILE__);
HANDLE g_hParamEvent = NULL;
HKEY g_hKeyParams = NULL;
#endif
#if DBG
extern LIST_ENTRY GlobalTicketList;
#endif
//
// Flags for initialization progress in SpInitialize
//
#define KERB_INIT_EVENTS 0x00000001
#define KERB_INIT_KDC_DATA 0x00000002
#define KERB_INIT_OPEN_POLICY 0x00000004
#define KERB_INIT_COMPUTER_NAME 0x00000008
#define KERB_INIT_SCAVENGER 0x00000010
#define KERB_INIT_LOGON_SESSION 0x00000020
#define KERB_INIT_TICKET 0x00000040
#define KERB_INIT_DOMAIN_NAME 0x00000100
#define KERB_INIT_CRED_LIST 0x00000200
#define KERB_INIT_CONTEXT_LIST 0x00000400
#define KERB_INIT_TICKET_CACHE 0x00000800
#define KERB_INIT_BINDING_CACHE 0x00001000
#define KERB_INIT_SPN_CACHE 0x00002000
#define KERB_INIT_S4U_CACHE 0x00004000
#define KERB_INIT_MIT 0x00008000
#define KERB_INIT_PKINIT 0x00010000
#define KERB_INIT_SOCKETS 0x00020000
#define KERB_INIT_DOMAIN_CHANGE 0x00040000
#define KERB_INIT_NS_LOOKBACK_DETECTION 0x00080000
#define KERB_INIT_NS_TIMER 0x00100000
#ifndef WIN32_CHICAGO
#ifdef RETAIL_LOG_SUPPORT
DEFINE_DEBUG2(Kerb);
extern DWORD KSuppInfoLevel; // needed to adjust values for common2 dir
HANDLE g_hWait = NULL;
DEBUG_KEY KerbDebugKeys[] = { {DEB_ERROR, "Error"},
{DEB_WARN, "Warn"},
{DEB_TRACE, "Trace"},
{DEB_TRACE_API, "API"},
{DEB_TRACE_CRED, "Cred"},
{DEB_TRACE_CTXT, "Ctxt"},
{DEB_TRACE_LSESS, "LSess"},
{DEB_TRACE_LOGON, "Logon"},
{DEB_TRACE_KDC, "KDC"},
{DEB_TRACE_CTXT2, "Ctxt2"},
{DEB_TRACE_TIME, "Time"},
{DEB_TRACE_LOCKS, "Locks"},
{DEB_TRACE_LEAKS, "Leaks"},
{DEB_TRACE_SPN_CACHE, "SPN"},
{DEB_S4U_ERROR, "S4uErr"},
{DEB_TRACE_S4U, "S4u"},
{DEB_TRACE_BND_CACHE, "Bnd"},
{DEB_TRACE_LOOPBACK, "LoopBack"},
{DEB_TRACE_TKT_RENEWAL, "Renew"},
{DEB_TRACE_U2U, "U2U"},
{DEB_TRACE_REFERRAL, "Refer"},
{0, NULL},
};
VOID
KerbInitializeDebugging(
VOID
)
{
KerbInitDebug(KerbDebugKeys);
}
#endif // RETAIL_LOG_SUPPORT
////////////////////////////////////////////////////////////////////
//
// Name: KerbGetKerbRegParams
//
// Synopsis: Gets the debug paramaters from the registry
//
// Arguments: HKEY to HKLM/System/CCS/LSA/Kerberos/Parameters
//
// Notes: Sets KerbInfolevel for debug spew
//
//
void
KerbGetKerbRegParams(HKEY ParamKey)
{
DWORD cbType, Value, cbSize;
DWORD dwErr;
#ifdef RETAIL_LOG_SUPPORT
cbSize = sizeof(Value);
Value = KerbInfoLevel;
dwErr = RegQueryValueExW(
ParamKey,
WSZ_KERBDEBUGLEVEL,
NULL,
&cbType,
(LPBYTE)&Value,
&cbSize
);
if (dwErr != ERROR_SUCCESS || cbType != REG_DWORD)
{
if (dwErr == ERROR_FILE_NOT_FOUND)
{
// no registry value is present, don't want info
// so reset to defaults
#if DBG
KSuppInfoLevel = KerbInfoLevel = DEB_ERROR;
#else // fre
KSuppInfoLevel = KerbInfoLevel = 0;
#endif
}else{
D_DebugLog((DEB_WARN, "Failed to query DebugLevel: 0x%x\n", dwErr));
}
}
KSuppInfoLevel = KerbInfoLevel = Value;
cbSize = sizeof(Value);
dwErr = RegQueryValueExW(
ParamKey,
WSZ_FILELOG,
NULL,
&cbType,
(LPBYTE)&Value,
&cbSize
);
if (dwErr == ERROR_SUCCESS)
{
KerbSetLoggingOption((BOOL) Value);
}
else if (dwErr == ERROR_FILE_NOT_FOUND)
{
KerbSetLoggingOption(FALSE);
}
#endif // RETAIL_LOG_SUPPORT
cbSize = sizeof(Value);
dwErr = RegQueryValueExW(
ParamKey,
KERB_PARAMETER_RETRY_PDC,
NULL,
&cbType,
(LPBYTE)&Value,
&cbSize
);
if (dwErr == ERROR_SUCCESS)
{
if ( Value != 0 )
{
KerbGlobalRetryPdc = TRUE;
}
else
{
KerbGlobalRetryPdc = FALSE;
}
}
else if (dwErr == ERROR_FILE_NOT_FOUND)
{
KerbGlobalRetryPdc = FALSE;
}
//
// Bug 356539: configuration key to regulate whether clients request
// addresses in tickets
//
cbSize = sizeof(Value);
dwErr = RegQueryValueExW(
ParamKey,
KERB_PARAMETER_CLIENT_IP_ADDRESSES,
NULL,
&cbType,
(LPBYTE)&Value,
&cbSize
);
if (dwErr == ERROR_SUCCESS)
{
if ( Value != 0 )
{
KerbGlobalUseClientIpAddresses = TRUE;
}
else
{
KerbGlobalUseClientIpAddresses = FALSE;
}
}
else if (dwErr == ERROR_FILE_NOT_FOUND)
{
KerbGlobalUseClientIpAddresses = KERB_DEFAULT_CLIENT_IP_ADDRESSES;
}
//
// Bug 353767: configuration key to regulate the TGT renewal interval
//
cbSize = sizeof(Value);
dwErr = RegQueryValueExW(
ParamKey,
KERB_PARAMETER_TGT_RENEWAL_TIME,
NULL,
&cbType,
(LPBYTE)&Value,
&cbSize
);
if (dwErr == ERROR_SUCCESS)
{
KerbGlobalTgtRenewalTime = Value;
}
else if (dwErr == ERROR_FILE_NOT_FOUND)
{
KerbGlobalTgtRenewalTime = KERB_DEFAULT_TGT_RENEWAL_TIME;
}
cbSize = sizeof(Value);
dwErr = RegQueryValueExW(
ParamKey,
KERB_PARAMETER_LOG_LEVEL,
NULL,
&cbType,
(LPBYTE)&Value,
&cbSize
);
if (dwErr == ERROR_SUCCESS)
{
KerbGlobalLoggingLevel = Value;
}
else if (dwErr == ERROR_FILE_NOT_FOUND)
{
KerbGlobalLoggingLevel = KERB_DEFAULT_LOGLEVEL;
}
cbSize = sizeof(Value);
dwErr = RegQueryValueExW(
ParamKey,
KERB_PARAMETER_ALLOW_TGT_SESSION_KEY,
NULL,
&cbType,
(LPBYTE)&Value,
&cbSize
);
if (dwErr == ERROR_SUCCESS)
{
KerbGlobalAllowTgtSessionKey = ( Value != 0 );
}
else if (dwErr == ERROR_FILE_NOT_FOUND)
{
KerbGlobalAllowTgtSessionKey = KERB_DEFAULT_ALLOW_TGT_SESSION_KEY;
}
dwErr = RegQueryValueExW(
ParamKey,
KERB_PARAMETER_MAX_TICKETS,
NULL,
&cbType,
(LPBYTE)&Value,
&cbSize
);
if ( dwErr == ERROR_SUCCESS && cbType == REG_DWORD )
{
KerbGlobalMaxTickets = Value;
}
else if (dwErr == ERROR_FILE_NOT_FOUND)
{
KerbGlobalMaxTickets = KERB_TICKET_COLLECTOR_THRESHHOLD;
}
return;
}
////////////////////////////////////////////////////////////////////
//
// Name: KerbWaitCleanup
//
// Synopsis: Cleans up wait from KerbWatchParamKey()
//
// Arguments: <none>
//
// Notes: .
//
void
KerbWaitCleanup()
{
NTSTATUS Status = STATUS_SUCCESS;
if (NULL != g_hWait) {
Status = RtlDeregisterWait(g_hWait);
if (NT_SUCCESS(Status) && NULL != g_hParamEvent ) {
CloseHandle(g_hParamEvent);
}
}
}
////////////////////////////////////////////////////////////////////
//
// Name: KerbWatchParamKey
//
// Synopsis: Sets RegNotifyChangeKeyValue() on param key, initializes
// debug level, then utilizes thread pool to wait on
// changes to this registry key. Enables dynamic debug
// level changes, as this function will also be callback
// if registry key modified.
//
// Arguments: pCtxt is actually a HANDLE to an event. This event
// will be triggered when key is modified.
//
// Notes: .
//
VOID
KerbWatchKerbParamKey(PVOID pCtxt,
BOOLEAN fWaitStatus)
{
NTSTATUS Status;
LONG lRes = ERROR_SUCCESS;
if (NULL == g_hKeyParams) // first time we've been called.
{
lRes = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
KERB_PARAMETER_PATH,
0,
KEY_READ,
&g_hKeyParams);
if ( lRes == ERROR_FILE_NOT_FOUND )
{
HKEY KerbKey;
lRes = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
KERB_PATH,
0,
KEY_CREATE_SUB_KEY,
&KerbKey
);
if ( lRes == ERROR_SUCCESS )
{
lRes = RegCreateKeyExW(
KerbKey,
L"Parameters",
0,
NULL,
0,
KEY_READ,
NULL,
&g_hKeyParams,
NULL
);
RegCloseKey( KerbKey );
}
}
if (ERROR_SUCCESS != lRes)
{
D_DebugLog((DEB_WARN,"Failed to open kerberos key: 0x%x\n", lRes));
goto Reregister;
}
}
if (NULL != g_hWait)
{
Status = RtlDeregisterWait(g_hWait);
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_WARN, "Failed to Deregister wait on registry key: 0x%x\n", Status));
goto Reregister;
}
}
lRes = RegNotifyChangeKeyValue(
g_hKeyParams,
FALSE,
REG_NOTIFY_CHANGE_LAST_SET,
(HANDLE) pCtxt,
TRUE);
if (ERROR_SUCCESS != lRes)
{
D_DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", lRes));
// we're tanked now. No further notifications, so get this one
}
KerbGetKerbRegParams(g_hKeyParams);
Reregister:
Status = RtlRegisterWait(&g_hWait,
(HANDLE) pCtxt,
KerbWatchKerbParamKey,
(HANDLE) pCtxt,
INFINITE,
WT_EXECUTEINPERSISTENTIOTHREAD|
WT_EXECUTEONLYONCE);
}
NTSTATUS NTAPI
SpCleanup(
DWORD dwProgress
);
BOOL
DllMain(
HINSTANCE Module,
ULONG Reason,
PVOID Context
)
{
if ( Reason == DLL_PROCESS_ATTACH )
{
DisableThreadLibraryCalls( Module );
#ifdef RETAIL_LOG_SUPPORT
KerbInitializeDebugging();
#endif
#if DBG
if ( !NT_SUCCESS( SafeLockInit( KERB_MAX_LOCK_ENUM, TRUE ))) {
return FALSE;
}
#endif
}
else if ( Reason == DLL_PROCESS_DETACH )
{
#if RETAIL_LOG_SUPPORT
KerbUnloadDebug();
#endif
KerbWaitCleanup();
#if DBG
SafeLockCleanup();
#endif
}
return TRUE ;
}
//+-------------------------------------------------------------------------
//
// Function: SpLsaModeInitialize
//
// Synopsis: This function is called by the LSA when this DLL is loaded.
// It returns security package function tables for all
// security packages in the DLL.
//
// Effects:
//
// Arguments: LsaVersion - Version number of the LSA
// PackageVersion - Returns version number of the package
// Tables - Returns array of function tables for the package
// TableCount - Returns number of entries in array of
// function tables.
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
SpLsaModeInitialize(
IN ULONG LsaVersion,
OUT PULONG PackageVersion,
OUT PSECPKG_FUNCTION_TABLE * Tables,
OUT PULONG TableCount
)
{
g_hParamEvent = CreateEvent(NULL,
FALSE,
FALSE,
NULL);
if (NULL == g_hParamEvent)
{
D_DebugLog((DEB_WARN, "CreateEvent for ParamEvent failed - 0x%x\n", GetLastError()));
} else {
KerbWatchKerbParamKey(g_hParamEvent, FALSE);
}
if (LsaVersion != SECPKG_INTERFACE_VERSION)
{
D_DebugLog((DEB_ERROR,"Invalid LSA version: %d. %ws, line %d\n",LsaVersion, THIS_FILE, __LINE__));
return(STATUS_INVALID_PARAMETER);
}
KerberosFunctionTable.InitializePackage = NULL;;
KerberosFunctionTable.LogonUser = NULL;
KerberosFunctionTable.CallPackage = LsaApCallPackage;
KerberosFunctionTable.LogonTerminated = LsaApLogonTerminated;
KerberosFunctionTable.CallPackageUntrusted = LsaApCallPackageUntrusted;
KerberosFunctionTable.LogonUserEx2 = LsaApLogonUserEx2;
KerberosFunctionTable.Initialize = SpInitialize;
KerberosFunctionTable.Shutdown = SpShutdown;
KerberosFunctionTable.GetInfo = SpGetInfo;
KerberosFunctionTable.AcceptCredentials = SpAcceptCredentials;
KerberosFunctionTable.AcquireCredentialsHandle = SpAcquireCredentialsHandle;
KerberosFunctionTable.FreeCredentialsHandle = SpFreeCredentialsHandle;
KerberosFunctionTable.QueryCredentialsAttributes = SpQueryCredentialsAttributes;
KerberosFunctionTable.SaveCredentials = SpSaveCredentials;
KerberosFunctionTable.GetCredentials = SpGetCredentials;
KerberosFunctionTable.DeleteCredentials = SpDeleteCredentials;
KerberosFunctionTable.InitLsaModeContext = SpInitLsaModeContext;
KerberosFunctionTable.AcceptLsaModeContext = SpAcceptLsaModeContext;
KerberosFunctionTable.DeleteContext = SpDeleteContext;
KerberosFunctionTable.ApplyControlToken = SpApplyControlToken;
KerberosFunctionTable.GetUserInfo = SpGetUserInfo;
KerberosFunctionTable.GetExtendedInformation = SpGetExtendedInformation;
KerberosFunctionTable.QueryContextAttributes = SpQueryLsaModeContextAttributes;
KerberosFunctionTable.CallPackagePassthrough = LsaApCallPackagePassthrough;
*PackageVersion = SECPKG_INTERFACE_VERSION;
*TableCount = 1;
*Tables = &KerberosFunctionTable;
// initialize event tracing (a/k/a WMI tracing, software tracing)
KerbInitializeTrace();
SafeAllocaInitialize(SAFEALLOCA_USE_DEFAULT,
SAFEALLOCA_USE_DEFAULT,
KerbAllocate,
KerbFree);
return(STATUS_SUCCESS);
}
#endif // WIN32_CHICAGO
//+-------------------------------------------------------------------------
//
// Function: SpInitialize
//
// Synopsis: Initializes the Kerberos package
//
// Effects:
//
// Arguments: PackageId - Contains ID for this package assigned by LSA
// Parameters - Contains machine-specific information
// FunctionTable - Contains table of LSA helper routines
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
SpInitialize(
IN ULONG_PTR PackageId,
IN PSECPKG_PARAMETERS Parameters,
IN PLSA_SECPKG_FUNCTION_TABLE FunctionTable
)
{
NTSTATUS Status;
UNICODE_STRING TempUnicodeString;
DWORD dwProgress = 0;
#if DBG
Status = SafeLockInit( KERB_MAX_LOCK_ENUM, TRUE );
if ( !NT_SUCCESS( Status )) {
return Status;
}
#endif
#if DBG
InitializeListHead( &GlobalTicketList );
#endif
#ifndef WIN32_CHICAGO
WCHAR SafeBootEnvVar[sizeof(SAFEBOOT_MINIMAL_STR_W) + sizeof(WCHAR)];
__try
{
SafeInitializeResource(&KerberosGlobalResource, GLOBAL_RESOURCE_LOCK_ENUM);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
#endif // WIN32_CHICAGO
KerberosPackageId = PackageId;
LsaFunctions = FunctionTable;
#ifndef WIN32_CHICAGO
KerberosState = KerberosLsaMode;
#else // WIN32_CHICAGO
KerberosState = KerberosUserMode;
#endif // WIN32_CHICAGO
RtlInitUnicodeString(
&KerbPackageName,
MICROSOFT_KERBEROS_NAME_W
);
#ifndef WIN32_CHICAGO
// Check if we are in safe boot.
//
// Does environment variable exist
//
RtlZeroMemory( SafeBootEnvVar, sizeof( SafeBootEnvVar ) );
KerbGlobalSafeModeBootOptionPresent = FALSE;
if ( GetEnvironmentVariable(L"SAFEBOOT_OPTION", SafeBootEnvVar, sizeof(SafeBootEnvVar)/sizeof(SafeBootEnvVar[0]) ) )
{
if ( !wcscmp( SafeBootEnvVar, SAFEBOOT_MINIMAL_STR_W ) )
{
KerbGlobalSafeModeBootOptionPresent = TRUE;
}
}
#endif // WIN32_CHICAGO
Status = KerbInitializeEvents();
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
dwProgress |= KERB_INIT_EVENTS;
//
// Init data for the kdc calling routine
//
#ifndef WIN32_CHICAGO
Status = KerbInitKdcData();
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
dwProgress |= KERB_INIT_KDC_DATA;
//
// init global LSA policy handle.
//
Status = LsaIOpenPolicyTrusted(
&KerbGlobalPolicyHandle
);
if(!NT_SUCCESS(Status))
{
goto Cleanup;
}
dwProgress |= KERB_INIT_OPEN_POLICY;
#endif // WIN32_CHICAGO
//
// Get our global role
//
if ((Parameters->MachineState & SECPKG_STATE_DOMAIN_CONTROLLER) != 0)
{
//
// We will behave like a member workstation/server until the DS
// says we are ready to act as a DC
//
KerbGlobalRole = KerbRoleWorkstation;
}
else if ((Parameters->MachineState & SECPKG_STATE_WORKSTATION) != 0)
{
KerbGlobalRole = KerbRoleWorkstation;
}
else
{
KerbGlobalRole = KerbRoleStandalone;
}
//
// Fill in various useful constants
//
KerbSetTime(&KerbGlobalWillNeverTime, MAXTIMEQUADPART);
KerbSetTime(&KerbGlobalHasNeverTime, 0);
//
// compute blank password hashes.
//
Status = RtlCalculateLmOwfPassword( "", &KerbGlobalNullLmOwfPassword );
ASSERT( NT_SUCCESS(Status) );
RtlInitUnicodeString(&TempUnicodeString, NULL);
Status = RtlCalculateNtOwfPassword(&TempUnicodeString,
&KerbGlobalNullNtOwfPassword);
ASSERT( NT_SUCCESS(Status) );
RtlInitUnicodeString(
&KerbGlobalKdcServiceName,
KDC_PRINCIPAL_NAME
);
//
// At some point we may want to read the registry here to
// find out whether we need to enforce times, currently times
// are always enforced.
//
KerbGlobalEnforceTime = FALSE;
KerbGlobalMachineNameChanged = FALSE;
//
// Get the machine Name
//
Status = KerbSetComputerName();
if( !NT_SUCCESS(Status) )
{
D_DebugLog((DEB_ERROR,"KerbSetComputerName failed\n"));
goto Cleanup;
}
dwProgress |= KERB_INIT_COMPUTER_NAME;
//
// Initialize the scavenger
//
Status = KerbInitializeScavenger();
if ( !NT_SUCCESS( Status )) {
D_DebugLog((DEB_ERROR,"KerbInitializeScavengerFailed\n"));
goto Cleanup;
}
dwProgress |= KERB_INIT_SCAVENGER;
//
// Initialize the logon session list. This has to be done because
// KerbSetDomainName will try to acess the logon session list
//
Status = KerbInitLogonSessionList();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize logon session list: 0x%x. %ws, line %d\n",
Status, THIS_FILE, __LINE__ ));
goto Cleanup;
}
dwProgress |= KERB_INIT_LOGON_SESSION;
Status = KerbInitLoopbackDetection();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize network service loopback detection: 0x%x. %ws, line %d\n",
Status, THIS_FILE, __LINE__ ));
goto Cleanup;
}
dwProgress |= KERB_INIT_NS_LOOKBACK_DETECTION;
Status = KerbCreateSKeyTimer();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize network service session key list timer: 0x%x. %ws, line %d\n",
Status, THIS_FILE, __LINE__ ));
goto Cleanup;
}
dwProgress |= KERB_INIT_NS_TIMER;
Status = KerbInitTicketHandling();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize ticket handling: 0x%x. %ws, line %d\n",
Status, THIS_FILE, __LINE__));
goto Cleanup;
}
dwProgress |= KERB_INIT_TICKET;
//
// Update all global structures referencing the domain name
//
Status = KerbSetDomainName(
&Parameters->DomainName,
&Parameters->DnsDomainName,
Parameters->DomainSid,
Parameters->DomainGuid
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
dwProgress |= KERB_INIT_DOMAIN_NAME;
//
// Initialize the internal Kerberos lists
//
Status = KerbInitCredentialList();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize credential list: 0x%x. %ws, line %d\n",
Status, THIS_FILE, __LINE__ ));
goto Cleanup;
}
dwProgress |= KERB_INIT_CRED_LIST;
Status = KerbInitContextList();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize context list: 0x%x. %ws, line %d\n",
Status, THIS_FILE, __LINE__ ));
goto Cleanup;
}
dwProgress |= KERB_INIT_CONTEXT_LIST;
Status = KerbInitTicketCaching();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize ticket cache: 0x%x. %ws, line %d\n",
Status, THIS_FILE, __LINE__));
goto Cleanup;
}
dwProgress |= KERB_INIT_TICKET_CACHE;
Status = KerbInitBindingCache();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize binding cache: 0x%x. %ws, line %d\n",
Status, THIS_FILE, __LINE__));
goto Cleanup;
}
dwProgress |= KERB_INIT_BINDING_CACHE;
Status = KerbInitSpnCache();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize SPN cache: 0x%x. %ws, line %d\n",
Status, THIS_FILE, __LINE__));
goto Cleanup;
}
dwProgress |= KERB_INIT_SPN_CACHE;
Status = KerbInitS4UCache();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize SPN cache: 0x%x. %ws, line %d\n",
Status, THIS_FILE, __LINE__));
goto Cleanup;
}
dwProgress |= KERB_INIT_S4U_CACHE;
Status = KerbInitializeMitRealmList();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize MIT realm list: 0x%x. %ws, line %d\n",
Status, THIS_FILE, __LINE__ ));
goto Cleanup;
}
dwProgress |= KERB_INIT_MIT;
Status = KerbInitUdpStatistics();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize UdpStats: 0x%x. %ws, line %d\n",
Status, THIS_FILE, __LINE__ ));
goto Cleanup;
}
#ifndef WIN32_CHICAGO
Status = KerbInitializePkinit();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize PKINT: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
goto Cleanup;
}
dwProgress |= KERB_INIT_PKINIT;
#endif // WIN32_CHICAGO
Status = KerbInitializeSockets(
MAKEWORD(1,1), // we want version 1.1
1, // we need at least 1 socket
&KerbGlobalNoTcpUdp
);
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR,"Failed to initialize sockets: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
goto Cleanup;
}
dwProgress |= KERB_INIT_SOCKETS;
#ifndef WIN32_CHICAGO
Status = KerbRegisterForDomainChange();
if (!NT_SUCCESS(Status))
{
D_DebugLog((DEB_ERROR, "Failed to register for domain change notification: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
goto Cleanup;
}
dwProgress |= KERB_INIT_DOMAIN_CHANGE;
//
// Check to see if there is a CSP registered for replacing the StringToKey calculation
//
CheckForOutsideStringToKey();
//
// See if there are any "join hints" to process
//
ReadInitialDcRecord(
&KerbGlobalInitialDcRecord,
&KerbGlobalInitialDcAddressType,
&KerbGlobalInitialDcFlags
);
KerbGlobalRunningServer = KerbRunningServer();
#endif // WIN32_CHICAGO
KerbGlobalInitialized = TRUE;
Cleanup:
//
// If we failed to initialize, shutdown
//
if (!NT_SUCCESS(Status))
{
SpCleanup(dwProgress);
}
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: SpCleanup
//
// Synopsis: Function to shutdown the Kerberos package.
//
// Effects: Forces the freeing of all credentials, contexts and
// logon sessions and frees all global data
//
// Arguments: none
//
// Requires:
//
// Returns:
//
// Notes: STATUS_SUCCESS in all cases
//
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
SpCleanup(
DWORD dwProgress
)
{
KerbGlobalInitialized = FALSE;
if (dwProgress & KERB_INIT_SCAVENGER)
{
KerbShutdownScavenger();
}
#ifndef WIN32_CHICAGO
if (dwProgress & KERB_INIT_DOMAIN_CHANGE)
{
KerbUnregisterForDomainChange();
}
#endif // WIN32_CHICAGO
if (dwProgress & KERB_INIT_LOGON_SESSION)
{
KerbFreeLogonSessionList();
}
if (dwProgress & KERB_INIT_NS_LOOKBACK_DETECTION)
{
KerbFreeSKeyListAndLock();
}
if (dwProgress & KERB_INIT_NS_TIMER)
{
KerbFreeSKeyTimer();
}
if (dwProgress & KERB_INIT_CONTEXT_LIST)
{
KerbFreeContextList();
}
if (dwProgress & KERB_INIT_TICKET_CACHE)
{
KerbFreeTicketCache();
}
// if (dwProgress & KERB_INIT_CRED_LIST)
// {
// KerbFreeCredentialList();
// }
KerbFreeString(&KerbGlobalDomainName);
KerbFreeString(&KerbGlobalDnsDomainName);
KerbFreeString(&KerbGlobalMachineName);
KerbFreeString((PUNICODE_STRING) &KerbGlobalKerbMachineName);
KerbFreeString(&KerbGlobalMachineServiceName);
KerbFreeKdcName(&KerbGlobalMitMachineServiceName);
if (dwProgress & KERB_INIT_TICKET)
{
KerbCleanupTicketHandling();
}
#ifndef WIN32_CHICAGO
if (KerbGlobalPolicyHandle != NULL)
{
ASSERT(dwProgress & KERB_INIT_OPEN_POLICY);
LsarClose( &KerbGlobalPolicyHandle );
KerbGlobalPolicyHandle = NULL;
}
if (KerbGlobalDomainSid != NULL)
{
KerbFree(KerbGlobalDomainSid);
}
#endif // WIN32_CHICAGO
if (dwProgress & KERB_INIT_SOCKETS)
{
KerbCleanupSockets();
}
if (dwProgress & KERB_INIT_BINDING_CACHE)
{
KerbCleanupBindingCache(TRUE);
}
if (dwProgress & KERB_INIT_MIT)
{
KerbUninitializeMitRealmList();
}
#ifndef WIN32_CHICAGO
if (dwProgress & KERB_INIT_KDC_DATA)
{
KerbFreeKdcData();
}
// RtlDeleteResource(&KerberosGlobalResource);
#endif // WIN32_CHICGAO
if (dwProgress & KERB_INIT_EVENTS)
{
KerbShutdownEvents();
}
return(STATUS_SUCCESS);
}
//+-------------------------------------------------------------------------
//
// Function: SpShutdown
//
// Synopsis: Exported function to shutdown the Kerberos package.
//
// Effects: Forces the freeing of all credentials, contexts and
// logon sessions and frees all global data
//
// Arguments: none
//
// Requires:
//
// Returns:
//
// Notes: STATUS_SUCCESS in all cases
//
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
SpShutdown(
VOID
)
{
#if 0
SpCleanup(0);
#endif
return(STATUS_SUCCESS);
}
#ifndef WIN32_CHICAGO
//+-------------------------------------------------------------------------
//
// Function: SpGetInfo
//
// Synopsis: Returns information about the package
//
// Effects: returns pointers to global data
//
// Arguments: PackageInfo - Receives kerberos package information
//
// Requires:
//
// Returns: STATUS_SUCCESS in all cases
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
SpGetInfo(
OUT PSecPkgInfo PackageInfo
)
{
PackageInfo->wVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
PackageInfo->wRPCID = RPC_C_AUTHN_GSS_KERBEROS;
PackageInfo->fCapabilities = KERBEROS_CAPABILITIES;
PackageInfo->cbMaxToken = KerbGlobalMaxTokenSize;
PackageInfo->Name = KERBEROS_PACKAGE_NAME;
PackageInfo->Comment = KERBEROS_PACKAGE_COMMENT;
return(STATUS_SUCCESS);
}
//+-------------------------------------------------------------------------
//
// Function: SpGetExtendedInformation
//
// Synopsis: returns additional information about the package
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
SpGetExtendedInformation(
IN SECPKG_EXTENDED_INFORMATION_CLASS Class,
OUT PSECPKG_EXTENDED_INFORMATION * ppInformation
)
{
NTSTATUS Status = STATUS_SUCCESS;
PSECPKG_EXTENDED_INFORMATION Information = NULL ;
PSECPKG_SERIALIZED_OID SerializedOid;
ULONG Size ;
switch(Class) {
case SecpkgGssInfo:
DsysAssert(gss_mech_krb5_new->length >= 2);
DsysAssert(gss_mech_krb5_new->length < 127);
//
// We need to leave space for the oid and the BER header, which is
// 0x6 and then the length of the oid.
//
Information = (PSECPKG_EXTENDED_INFORMATION)
KerbAllocate(sizeof(SECPKG_EXTENDED_INFORMATION) +
gss_mech_krb5_new->length - 2);
if (Information == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Information->Class = SecpkgGssInfo;
Information->Info.GssInfo.EncodedIdLength = gss_mech_krb5_new->length + 2;
Information->Info.GssInfo.EncodedId[0] = 0x6; // BER OID type
Information->Info.GssInfo.EncodedId[1] = (UCHAR) gss_mech_krb5_new->length;
RtlCopyMemory(
&Information->Info.GssInfo.EncodedId[2],
gss_mech_krb5_new->elements,
gss_mech_krb5_new->length
);
*ppInformation = Information;
Information = NULL;
break;
case SecpkgContextThunks:
//
// Note - we don't need to add any space for the thunks as there
// is only one, and the structure has space for one. If any more
// thunks are added, we will need to add space for those.
//
Information = (PSECPKG_EXTENDED_INFORMATION)
KerbAllocate(sizeof(SECPKG_EXTENDED_INFORMATION));
if (Information == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Information->Class = SecpkgContextThunks;
Information->Info.ContextThunks.InfoLevelCount = 1;
Information->Info.ContextThunks.Levels[0] = SECPKG_ATTR_NATIVE_NAMES;
*ppInformation = Information;
Information = NULL;
break;
case SecpkgWowClientDll:
//
// This indicates that we're smart enough to handle wow client processes
//
Information = (PSECPKG_EXTENDED_INFORMATION)
KerbAllocate( sizeof( SECPKG_EXTENDED_INFORMATION ) +
(MAX_PATH * sizeof(WCHAR) ) );
if ( Information == NULL )
{
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto Cleanup ;
}
Information->Class = SecpkgWowClientDll ;
Information->Info.WowClientDll.WowClientDllPath.Buffer = (PWSTR) (Information + 1);
Size = ExpandEnvironmentStrings(
L"%SystemRoot%\\" WOW64_SYSTEM_DIRECTORY_U L"\\Kerberos.DLL",
Information->Info.WowClientDll.WowClientDllPath.Buffer,
MAX_PATH );
Information->Info.WowClientDll.WowClientDllPath.Length = (USHORT) (Size * sizeof(WCHAR));
Information->Info.WowClientDll.WowClientDllPath.MaximumLength = (USHORT) ((Size + 1) * sizeof(WCHAR) );
*ppInformation = Information ;
Information = NULL ;
break;
case SecpkgExtraOids:
Size = sizeof( SECPKG_EXTENDED_INFORMATION ) +
2 * sizeof( SECPKG_SERIALIZED_OID ) ;
Information = (PSECPKG_EXTENDED_INFORMATION)
KerbAllocate( Size );
if ( Information == NULL )
{
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto Cleanup ;
}
Information->Class = SecpkgExtraOids ;
Information->Info.ExtraOids.OidCount = 2 ;
SerializedOid = Information->Info.ExtraOids.Oids;
SerializedOid->OidLength = gss_mech_krb5_spnego->length + 2;
SerializedOid->OidAttributes = SECPKG_CRED_BOTH ;
SerializedOid->OidValue[ 0 ] = 0x06 ; // BER OID type
SerializedOid->OidValue[ 1 ] = (UCHAR) gss_mech_krb5_spnego->length;
RtlCopyMemory(
&SerializedOid->OidValue[2],
gss_mech_krb5_spnego->elements,
gss_mech_krb5_spnego->length
);
SerializedOid++ ;
SerializedOid->OidLength = gss_mech_krb5_u2u->length + 2;
SerializedOid->OidAttributes = SECPKG_CRED_INBOUND ;
SerializedOid->OidValue[ 0 ] = 0x06 ; // BER OID type
SerializedOid->OidValue[ 1 ] = (UCHAR) gss_mech_krb5_u2u->length;
RtlCopyMemory(
&SerializedOid->OidValue[2],
gss_mech_krb5_u2u->elements,
gss_mech_krb5_u2u->length
);
*ppInformation = Information ;
Information = NULL ;
break;
default:
return(STATUS_INVALID_INFO_CLASS);
}
Cleanup:
if (Information != NULL)
{
KerbFree(Information);
}
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: LsaApInitializePackage
//
// Synopsis: Obsolete pacakge initialize function, supported for
// compatibility only. This function has no effect.
//
// Effects: none
//
// Arguments:
//
// Requires:
//
// Returns: STATUS_SUCCESS always
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
LsaApInitializePackage(
IN ULONG AuthenticationPackageId,
IN PLSA_DISPATCH_TABLE LsaDispatchTable,
IN PLSA_STRING Database OPTIONAL,
IN PLSA_STRING Confidentiality OPTIONAL,
OUT PLSA_STRING *AuthenticationPackageName
)
{
return(STATUS_SUCCESS);
}
BOOLEAN
KerbIsInitialized(
VOID
)
{
return KerbGlobalInitialized;
}
NTSTATUS
KerbKdcCallBack(
VOID
)
{
PKERB_BINDING_CACHE_ENTRY CacheEntry = NULL;
NTSTATUS Status = STATUS_SUCCESS;
KerbGlobalWriteLock();
KerbGlobalRole = KerbRoleDomainController;
Status = KerbLoadKdc();
//
// Purge the binding cache of entries for this domain
//
CacheEntry = KerbLocateBindingCacheEntry(
&KerbGlobalDnsDomainName,
0,
TRUE
);
if (CacheEntry != NULL)
{
KerbDereferenceBindingCacheEntry(CacheEntry);
}
CacheEntry = KerbLocateBindingCacheEntry(
&KerbGlobalDomainName,
0,
TRUE
);
if (CacheEntry != NULL)
{
KerbDereferenceBindingCacheEntry(CacheEntry);
}
//
// PurgeSpnCache, because we may now have "better" state,
// e.g. right after DCPromo our SPNs may not have replicated.
// For DCs, we can not even care about the spncache.
//
KerbCleanupSpnCache();
KerbSetTimeInMinutes(&KerbGlobalSpnCacheTimeout, 0);
KerbGlobalReleaseLock();
return Status;
}
VOID
FreAssert(
IN BOOL Expression,
IN CHAR * String
)
{
static BOOL KdPresenceChecked = FALSE;
static BOOL KdPresent = FALSE;
if ( !Expression )
{
//
// Kernel debugger is either present or not,
// this can not change without a reboot
//
if ( !KdPresenceChecked )
{
SYSTEM_KERNEL_DEBUGGER_INFORMATION KdInfo ;
NTSTATUS Status ;
Status = NtQuerySystemInformation(
SystemKernelDebuggerInformation,
&KdInfo,
sizeof( KdInfo ),
NULL );
if ( NT_SUCCESS( Status ) &&
KdInfo.KernelDebuggerEnabled )
{
KdPresent = TRUE;
}
//
// Set this variable to TRUE last in order to make this routine threadsafe
//
KdPresenceChecked = TRUE;
}
if ( KdPresent || IsDebuggerPresent())
{
OutputDebugStringA( String );
OutputDebugStringA( "\n" );
DebugBreak();
}
}
}
#endif // WIN32_CHICAGO