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.
 
 
 
 
 
 

1311 lines
33 KiB

//+-----------------------------------------------------------------------
//
// File: secdata.cxx
//
// Contents: Global data and methods on it.
//
//
// History:
//
//------------------------------------------------------------------------
#include "kdcsvr.hxx"
#include <kpasswd.h>
///////////////////////////////////////////////////////////////
//
//
// Global data
//
// This is all the security information that gets cached.
CSecurityData SecData;
CAuthenticatorList * Authenticators;
CAuthenticatorList * ReplayDetect;
///////////////////////////////////////////////////////////////
//
//
// Prototypes
//
fLsaPolicyChangeNotificationCallback KdcPolicyChangeCallback;
//+-------------------------------------------------------------------------
//
// Function: KdcPolicyChangeCallBack
//
// Synopsis: Function that gets called when policy changes
//
// Effects: Changes policy variables
//
// Arguments: MonitorInfoClass - class of data that changed
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
VOID
KdcPolicyChangeCallBack(
IN POLICY_NOTIFICATION_INFORMATION_CLASS MonitorInfoClass
)
{
NTSTATUS Status;
WCHAR Class[10];
TRACE(KDC, KdcPolicyChangeCallBack, DEB_FUNCTION);
Status = SecData.ReloadPolicy(MonitorInfoClass);
if (!NT_SUCCESS(Status))
{
_itow(MonitorInfoClass, Class, 10 );
ReportServiceEvent(
EVENTLOG_ERROR_TYPE,
KDCEVENT_POLICY_UPDATE_FAILED,
sizeof(NTSTATUS),
&Status,
1, // number of strings
Class
);
}
}
//+-------------------------------------------------------------------------
//
// Function: CSecurityData::ReloadPolicy
//
// Synopsis: Reloads a particular piece of policy
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
CSecurityData::ReloadPolicy(
IN POLICY_NOTIFICATION_INFORMATION_CLASS MonitorInfoClass
)
{
NTSTATUS Status = STATUS_SUCCESS;
PLSAPR_POLICY_DOMAIN_INFORMATION DomainPolicy = NULL;
PLSAPR_POLICY_INFORMATION LocalPolicy = NULL;
WCHAR Class[10];
TRACE(KDC, CSecurityData::ReloadPolicy, DEB_FUNCTION);
//
// Ignore changes to non-kerberos ticket information
//
switch(MonitorInfoClass) {
case PolicyNotifyDomainKerberosTicketInformation:
Status = LsarQueryDomainInformationPolicy(
GlobalPolicyHandle,
PolicyDomainKerberosTicketInformation,
&DomainPolicy
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
break;
case PolicyNotifyAuditEventsInformation:
Status = LsarQueryInformationPolicy(
GlobalPolicyHandle,
PolicyAuditEventsInformation,
&LocalPolicy
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
break;
default:
return(STATUS_SUCCESS);
}
//
// Update the changed information in the KDCs global data structures.
//
//
// Current policy defaults, see KirkSol/JBrezak
// [Kerberos Policy]
// MaxTicketAge=10 ;Maximum User Ticket Lifetime (hours)
// MaxRenewAge=7 ;Maximum lifetime that a user tickeet can be renewed (days)
// MaxServiceAge=60 ;Maximum Service Ticket Lifetime (minutes)
// MaxClockSkew=5 ;Maximum tolerance for synchronization of computer clocks (minutes)
// TicketValidateClient=1 ;Enforce user logon restrictions
WriteLock();
switch(MonitorInfoClass) {
case PolicyNotifyDomainKerberosTicketInformation:
DebugLog((DEB_TRACE, "MaxServiceTicketAge : %x\n", DomainPolicy->PolicyDomainKerbTicketInfo.MaxServiceTicketAge.QuadPart));
DebugLog((DEB_TRACE, "MaxTicketAge : %x\n", DomainPolicy->PolicyDomainKerbTicketInfo.MaxTicketAge.QuadPart));
DebugLog((DEB_TRACE, "MaxRenewAge : %x\n", DomainPolicy->PolicyDomainKerbTicketInfo.MaxRenewAge.QuadPart));
DebugLog((DEB_TRACE, "MaxClockSkew : %x\n", DomainPolicy->PolicyDomainKerbTicketInfo.MaxClockSkew.QuadPart));
// Validate parameters
if ((DomainPolicy->PolicyDomainKerbTicketInfo.MaxServiceTicketAge.QuadPart <= (LONGLONG) -1) ||
(DomainPolicy->PolicyDomainKerbTicketInfo.MaxTicketAge.QuadPart <= (LONGLONG) -1) ||
(DomainPolicy->PolicyDomainKerbTicketInfo.MaxRenewAge.QuadPart <= (LONGLONG) -1) ||
(DomainPolicy->PolicyDomainKerbTicketInfo.MaxClockSkew.QuadPart <= (LONGLONG) -1) ||
(DomainPolicy->PolicyDomainKerbTicketInfo.MaxServiceTicketAge.QuadPart == (LONGLONG) 0) ||
(DomainPolicy->PolicyDomainKerbTicketInfo.MaxTicketAge.QuadPart == (LONGLONG) 0) )
{
_itow(MonitorInfoClass, Class, 10 );
DebugLog((DEB_ERROR, "Policy update failed!\n"));
ReportServiceEvent(
EVENTLOG_ERROR_TYPE,
KDCEVENT_POLICY_UPDATE_FAILED,
sizeof(NTSTATUS),
&Status,
1, // number of strings
Class
);
}
else
{
_KDC_TgsTicketLifespan = DomainPolicy->PolicyDomainKerbTicketInfo.MaxServiceTicketAge;
_KDC_TgtTicketLifespan = DomainPolicy->PolicyDomainKerbTicketInfo.MaxTicketAge;
_KDC_TicketRenewSpan = DomainPolicy->PolicyDomainKerbTicketInfo.MaxRenewAge;
//
// never allow the skew window to drop down to zero, which prevents
// logon locally to the DC. The allowed skew window is at least
// 10 seconds for now
//
SkewTime.QuadPart = max(DomainPolicy->PolicyDomainKerbTicketInfo.MaxClockSkew.QuadPart, 10 * 10000000);
}
// Update domain policy flags. Don't depend on the flags keeping in sync
// with the kerberos internal flags
if ( DomainPolicy->PolicyDomainKerbTicketInfo.AuthenticationOptions &
POLICY_KERBEROS_VALIDATE_CLIENT)
{
_KDC_Flags |= AUTH_REQ_VALIDATE_CLIENT;
}
else
{
_KDC_Flags &= ~AUTH_REQ_VALIDATE_CLIENT;
}
break;
case PolicyNotifyAuditEventsInformation:
if ((LocalPolicy->PolicyAuditEventsInfo.AuditingMode) &&
(LocalPolicy->PolicyAuditEventsInfo.MaximumAuditEventCount > AuditCategoryAccountLogon))
{
if (LocalPolicy->PolicyAuditEventsInfo.EventAuditingOptions[AuditCategoryAccountLogon] & POLICY_AUDIT_EVENT_SUCCESS )
{
_KDC_AuditEvents |= KDC_AUDIT_AS_SUCCESS | KDC_AUDIT_TGS_SUCCESS | KDC_AUDIT_MAP_SUCCESS;
}
else
{
_KDC_AuditEvents &= ~(KDC_AUDIT_AS_SUCCESS | KDC_AUDIT_TGS_SUCCESS | KDC_AUDIT_MAP_SUCCESS);
}
if (LocalPolicy->PolicyAuditEventsInfo.EventAuditingOptions[AuditCategoryAccountLogon] & POLICY_AUDIT_EVENT_FAILURE )
{
_KDC_AuditEvents |= KDC_AUDIT_AS_FAILURE | KDC_AUDIT_TGS_FAILURE | KDC_AUDIT_MAP_FAILURE;
}
else
{
_KDC_AuditEvents &= ~(KDC_AUDIT_AS_FAILURE | KDC_AUDIT_TGS_FAILURE | KDC_AUDIT_MAP_FAILURE);
}
}
break;
}
Unlock();
Cleanup:
if (DomainPolicy != NULL)
{
LsaIFree_LSAPR_POLICY_DOMAIN_INFORMATION (
PolicyDomainKerberosTicketInformation,
DomainPolicy);
}
if (LocalPolicy != NULL)
{
LsaIFree_LSAPR_POLICY_INFORMATION(
PolicyAuditEventsInformation,
LocalPolicy);
}
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: CSecurityData::SetForestRoot
//
// Synopsis: Sets the forest root
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
CSecurityData::SetForestRoot(
IN PUNICODE_STRING NewForestRoot
)
{
NTSTATUS Status;
UNICODE_STRING Temp;
WriteLock();
RtlCopyMemory(
&Temp,
&_ForestRoot,
sizeof(UNICODE_STRING)
);
Status = KerbDuplicateString(
&_ForestRoot,
NewForestRoot
);
// on alloc failure, just keep old version as it will never change
if (!NT_SUCCESS(Status))
{
RtlCopyMemory(
&_ForestRoot,
&Temp,
sizeof(UNICODE_STRING)
);
}
else
{
KerbFreeString(&Temp);
}
_KDC_IsForestRoot = IsOurRealm(&_ForestRoot);
Unlock();
return Status;
}
////////////////////////////////////////////////////////////////////
//
// Name: CSecurityData::CSecurityData
//
// Synopsis: Constructor.
//
// Arguments: <none>
//
// Notes: .
//
CSecurityData::CSecurityData()
{
TRACE(KDC, CSecurityData::CSecurityData, DEB_FUNCTION);
RtlInitUnicodeString(
&_MachineName,
NULL
);
RtlInitUnicodeString(
&_SamMachineName,
NULL
);
RtlInitUnicodeString(
&_MachineUpn,
NULL
);
RtlInitUnicodeString(
&_RealmName,
NULL
);
RtlInitUnicodeString(
&_KDC_Name,
NULL
);
RtlInitUnicodeString(
&_KDC_FullName,
NULL
);
RtlInitUnicodeString(
&_KDC_FullDnsName,
NULL
);
RtlInitUnicodeString(
&_KDC_FullKdcName,
NULL
);
RtlInitUnicodeString(
&_ForestRoot,
NULL
);
_KerbRealmName = NULL;
_KerbDnsRealmName = NULL;
_KrbtgtServiceName = NULL;
_KpasswdServiceName = NULL;
RtlZeroMemory(
&_KrbtgtTicketInfo,
sizeof(KDC_TICKET_INFO)
);
_KrbtgtTicketInfoValid = FALSE;
_KDC_CrossForestEnabled = FALSE;
_KDC_IsForestRoot = FALSE;
_fMonitorInitialized = FALSE;
}
//+---------------------------------------------------------------------------
//
// Member: CSecurityData::InitLock
//
// Synopsis: Initializes the lock in the CSecurityData class.
//
// Effects:
//
// Arguments: (none)
//
// Returns: STATUS_SUCCESS or error code
//
// History: 2001-07-02 JSchwart created
//
// Notes: This must be called before any other method of CSecurityData.
// It needs to be separate from Init since SAM can call KDC routines
// that use the global SecData before Init has been called in the
// KDC ServiceMain.
//
//----------------------------------------------------------------------------
NTSTATUS
CSecurityData::InitLock(
VOID
)
{
NTSTATUS Status = STATUS_SUCCESS;
ASSERT(!_fMonitorInitialized);
__try {
RtlInitializeResource(&_Monitor);
} __except ( EXCEPTION_EXECUTE_HANDLER ) {
Status = GetExceptionCode();
}
if (NT_SUCCESS(Status))
{
_fMonitorInitialized = TRUE;
}
return Status;
}
//+---------------------------------------------------------------------------
//
// Member: CSecurityData::Init
//
// Synopsis: Initializes the global data.
//
// Effects: Allocates memory
//
// Arguments: (none)
//
// Returns: STATUS_SUCCESS or error code
//
// Signals: May raise exception on out of memory.
//
// History: 4-02-93 WadeR Created
//
// Notes: This must be called after InitLock and before any other
// method of CSecurityData. It gets data from the registry, the
// domain object, and the kdc.ini file.
//
//----------------------------------------------------------------------------
NTSTATUS
CSecurityData::Init()
{
TRACE(KDC, CSecurityData::Init, DEB_FUNCTION);
NTSTATUS Status;
UNICODE_STRING TempString;
WCHAR TempMachineName[CNLEN+1];
ULONG MachineNameLength = CNLEN+1;
LARGE_INTEGER MaxAuthenticatorAge;
PLSAPR_POLICY_INFORMATION PolicyInfo = NULL;
UNICODE_STRING KadminName;
UNICODE_STRING ChangePwName;
D_DebugLog(( DEB_TRACE, "Entered CSecurityData::Init()\n" ));
DsysAssert(_fMonitorInitialized);
//
// Get the domain name and ID from the registry
//
Status = KerbDuplicateString(
&_RealmName,
&GlobalDomainName
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
if (!KERB_SUCCESS(KerbConvertUnicodeStringToRealm(
&_KerbRealmName,
&GlobalDomainName)))
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Construct the KDC Name from the realm and the suffix.
//
RtlInitUnicodeString(
&TempString,
KDC_PRINCIPAL_NAME
);
Status = KerbDuplicateString(
&_KDC_Name,
&TempString
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
if (!GetComputerName(
TempMachineName,
&MachineNameLength
))
{
Status = STATUS_BUFFER_TOO_SMALL;
goto Cleanup;
}
RtlInitUnicodeString(
&TempString,
TempMachineName
);
Status = KerbDuplicateString(
&_MachineName,
&TempString
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = LsaIQueryInformationPolicyTrusted(
PolicyDnsDomainInformation,
&PolicyInfo
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
//
// WAS BUG: this DNS name may have a trailing '.' - if so, strip it off
//
if (PolicyInfo->PolicyDnsDomainInfo.DnsDomainName.Length >= sizeof(WCHAR))
{
if (PolicyInfo->PolicyDnsDomainInfo.DnsDomainName.Buffer[ -1 + PolicyInfo->PolicyDnsDomainInfo.DnsDomainName.Length / sizeof(WCHAR) ] == L'.')
{
PolicyInfo->PolicyDnsDomainInfo.DnsDomainName.Length -= sizeof(WCHAR);
}
}
Status = KerbDuplicateString(
&_DnsRealmName,
(PUNICODE_STRING) &PolicyInfo->PolicyDnsDomainInfo.DnsDomainName
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Status = RtlUpcaseUnicodeString(
&_DnsRealmName,
&_DnsRealmName,
FALSE
);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
if (!KERB_SUCCESS(KerbConvertUnicodeStringToRealm(
&_KerbDnsRealmName,
&_DnsRealmName)))
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Build a sam style machine name
//
_SamMachineName.Length = _MachineName.Length + sizeof(WCHAR);
_SamMachineName.MaximumLength = _SamMachineName.Length + sizeof(WCHAR);
_SamMachineName.Buffer = (LPWSTR) MIDL_user_allocate(_SamMachineName.MaximumLength);
if (_SamMachineName.Buffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(
_SamMachineName.Buffer,
_MachineName.Buffer,
_MachineName.Length
);
_SamMachineName.Buffer[_MachineName.Length / sizeof(WCHAR)] = L'$';
_SamMachineName.Buffer[_SamMachineName.Length / sizeof(WCHAR)] = L'\0';
//
// Build the machine UPN: [email protected]
//
_MachineUpn.Length = _MachineName.Length + 2 * sizeof(WCHAR) + _DnsRealmName.Length;
_MachineUpn.MaximumLength = _MachineUpn.Length + sizeof(WCHAR);
_MachineUpn.Buffer = (LPWSTR) MIDL_user_allocate(_MachineUpn.MaximumLength);
if (_MachineUpn.Buffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(
_MachineUpn.Buffer,
_MachineName.Buffer,
_MachineName.Length
);
_MachineUpn.Buffer[_MachineName.Length / sizeof(WCHAR)] = L'$';
_MachineUpn.Buffer[1+_MachineName.Length / sizeof(WCHAR)] = L'@';
RtlCopyMemory(
_MachineUpn.Buffer + _MachineName.Length / sizeof(WCHAR) + 2 ,
_DnsRealmName.Buffer,
_DnsRealmName.Length
);
_MachineUpn.Buffer[_MachineUpn.Length / sizeof(WCHAR)] = L'\0';
if (!KERB_SUCCESS(KerbBuildFullServiceName(
&_RealmName,
&_KDC_Name,
&_KDC_FullName
)))
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
if (!KERB_SUCCESS(KerbBuildFullServiceName(
&_DnsRealmName,
&_KDC_Name,
&_KDC_FullDnsName
)))
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Build the full kdc name - a kerberos style name
//
_KDC_FullKdcName.Length = _KDC_Name.Length + _DnsRealmName.Length + sizeof(WCHAR);
_KDC_FullKdcName.MaximumLength = _KDC_FullKdcName.Length + sizeof(WCHAR);
_KDC_FullKdcName.Buffer = (LPWSTR) MIDL_user_allocate(_KDC_FullDnsName.MaximumLength);
if (_KDC_FullKdcName.Buffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(
_KDC_FullKdcName.Buffer,
_KDC_Name.Buffer,
_KDC_Name.Length
);
_KDC_FullKdcName.Buffer[_KDC_Name.Length / sizeof(WCHAR)] = L'/';
RtlCopyMemory(
_KDC_FullKdcName.Buffer + 1 + _KDC_Name.Length / sizeof(WCHAR),
_DnsRealmName.Buffer,
_DnsRealmName.Length
);
_KDC_FullKdcName.Buffer[_KDC_FullKdcName.Length / sizeof(WCHAR)] = L'\0';
D_DebugLog((DEB_TRACE, "_KDC_Name='%wZ', MachineName='%wZ'\n",
&_KDC_Name,
&_MachineName ));
if (!KERB_SUCCESS(KerbBuildFullServiceKdcName(
&_DnsRealmName,
&_KDC_Name,
KRB_NT_SRV_INST,
&_KrbtgtServiceName
)))
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Build the kdc name for kadmin/changepw.
//
RtlInitUnicodeString(
&KadminName,
KERB_KPASSWD_NAME
);
RtlInitUnicodeString(
&ChangePwName,
L"changepw"
);
if (!KERB_SUCCESS(KerbBuildFullServiceKdcName(
&ChangePwName,
&KadminName,
KRB_NT_SRV_INST,
&_KpasswdServiceName
)))
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Status = LoadParameters(GlobalAccountDomainHandle);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"Failed to load parameters: 0x%x\n",Status));
goto Cleanup;
}
//
// Create the authenticators.
//
//
// In reality, set skew time to 5 minutes and same for authenticators.
//
SkewTime.QuadPart = (LONGLONG) 10000000 * 60 * 5;
MaxAuthenticatorAge = SkewTime;
//
// Create the authenticator list
//
Authenticators = new CAuthenticatorList( MaxAuthenticatorAge, 1 );
if (Authenticators == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Status = Authenticators->Init();
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
//
// Setup a list to track failed requests - we don't fail the
// same request twice for the timeout time
//
ReplayDetect = new CAuthenticatorList( MaxAuthenticatorAge, 1 );
if (ReplayDetect == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Status = ReplayDetect->Init();
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
//
// Setup a list to track potential canidates for fwd'ing to PDC
//
Status = AsNegCacheInit();
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
//
// Register for policy callbacks
//
Status = LsaIRegisterPolicyChangeNotificationCallback(
KdcPolicyChangeCallBack,
PolicyNotifyDomainKerberosTicketInformation
);
if (NT_SUCCESS(Status))
{
Status = LsaIRegisterPolicyChangeNotificationCallback(
KdcPolicyChangeCallBack,
PolicyNotifyAuditEventsInformation
);
}
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"Failed to register for policy changes: 0x%x\n",Status));
goto Cleanup;
}
Status = UpdateKrbtgtTicketInfo();
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
Cleanup:
if (PolicyInfo != NULL)
{
LsaIFree_LSAPR_POLICY_INFORMATION(
PolicyDnsDomainInformation,
PolicyInfo
);
}
return(Status);
}
//+---------------------------------------------------------------------------
//
// Member: CSecurityData::Cleanup
//
// Synopsis: Cleans up the object
//
// Effects: Frees memory
//
// Arguments: (none)
//
// History: 4-02-93 WadeR Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID
CSecurityData::Cleanup()
{
TRACE(KDC, CSecurityData::Cleanup, DEB_FUNCTION);
_KrbtgtTicketInfoValid = FALSE;
KerbFreeString(&_RealmName);
KerbFreeString(&_KDC_Name);
KerbFreeString(&_KDC_FullName);
KerbFreeString(&_KDC_FullDnsName);
KerbFreeString(&_KDC_FullKdcName);
KerbFreeString(&_MachineName);
KerbFreeString(&_SamMachineName);
KerbFreeString(&_MachineUpn);
KerbFreeString(&_DnsRealmName);
KerbFreeRealm(&_KerbRealmName);
KerbFreeRealm(&_KerbDnsRealmName);
KerbFreeKdcName(&_KrbtgtServiceName);
KerbFreeKdcName(&_KpasswdServiceName);
if (Authenticators != NULL)
{
delete Authenticators;
Authenticators = NULL;
}
if (ReplayDetect != NULL)
{
delete ReplayDetect;
ReplayDetect = NULL;
}
LsaIUnregisterAllPolicyChangeNotificationCallback(
KdcPolicyChangeCallBack
);
}
//+---------------------------------------------------------------------------
//
// Member: CSecurityData::~CSecurityData
//
// Synopsis: Destructor
//
// Effects: Frees memory
//
// Arguments: (none)
//
// History: 4-02-93 WadeR Created
//
// Notes:
//
//----------------------------------------------------------------------------
CSecurityData::~CSecurityData()
{
TRACE(KDC, CSecurityData::~CSecurityData, DEB_FUNCTION);
Cleanup();
//
// This doesn't happen during Cleanup() because we want to
// make sure it only happens once.
//
if (_fMonitorInitialized)
{
RtlDeleteResource(&_Monitor);
}
}
NTSTATUS
CSecurityData::LoadParameters(SAMPR_HANDLE DomainHandle)
{
NTSTATUS Status = STATUS_SUCCESS;
LARGE_INTEGER OneHour, EightHours, TenHours;
TRACE(KDC, CSecurityData::LoadParameters, DEB_FUNCTION);
OneHour.QuadPart = (LONGLONG) 10000000 * 60 * 60 * 1;
EightHours.QuadPart = (LONGLONG) 10000000 * 60 * 60 * 8;
TenHours.QuadPart = (LONGLONG) 10000000 * 60 * 60 * 10;
// New internal defaults according to JBrezak. 7/28/99
//
// Initialize Tgt lifetime to 10 hours.
//
_KDC_TgtTicketLifespan = TenHours;
//
// Initialize ticket max renew time to one hour.
//
_KDC_TicketRenewSpan = OneHour;
//
// Initialize Tgs lifetime to one hour.
//
_KDC_TgsTicketLifespan = OneHour;
//
// Initialize domain password replication skew tolerance to 60 minutes.
//
_KDC_DomainPasswordReplSkew.QuadPart = (LONGLONG) 60*60*10000000;
//
// Initialize restriciton lifetime to 20 minutes
//
_KDC_RestrictionLifetime.QuadPart = (LONGLONG) 20*60*10000000;
//
// Default authentication flags
//
_KDC_Flags = AUTH_REQ_ALLOW_FORWARDABLE |
AUTH_REQ_ALLOW_PROXIABLE |
AUTH_REQ_ALLOW_RENEWABLE |
AUTH_REQ_ALLOW_NOADDRESS |
AUTH_REQ_ALLOW_ENC_TKT_IN_SKEY |
AUTH_REQ_ALLOW_VALIDATE |
AUTH_REQ_VALIDATE_CLIENT |
AUTH_REQ_OK_AS_DELEGATE |
AUTH_REQ_ALLOW_S4U_DELEGATE;
_KDC_AuditEvents = 0;
//
// Get kerberos policy information
//
Status = ReloadPolicy(
PolicyNotifyDomainKerberosTicketInformation
);
if (!NT_SUCCESS(Status))
{
if ((Status != STATUS_NOT_FOUND) && (Status != STATUS_OBJECT_NAME_NOT_FOUND))
{
DebugLog((DEB_ERROR,"Failed to reload kerberos ticket policy: 0x%x\n",Status));
goto Cleanup;
}
Status = STATUS_SUCCESS;
}
//
// Get audit information
//
Status = ReloadPolicy(
PolicyNotifyAuditEventsInformation
);
if (!NT_SUCCESS(Status))
{
if (Status != STATUS_NOT_FOUND)
{
DebugLog((DEB_ERROR,"Failed to query audit event info: 0x%x\n",Status));
goto Cleanup;
}
Status = STATUS_SUCCESS;
}
Cleanup:
#if DBG
DebugShowState();
#endif
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: CSecurityData::GetKrbtgtTicketInfo
//
// Synopsis: Duplicates ticket info for krbtgt account
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
KERBERR
CSecurityData::GetKrbtgtTicketInfo(
OUT PKDC_TICKET_INFO TicketInfo
)
{
KERBERR KerbErr = KDC_ERR_NONE;
ULONG CredentialSize;
RtlZeroMemory(
TicketInfo,
sizeof(KDC_TICKET_INFO)
);
ReadLock();
if (!_KrbtgtTicketInfoValid)
{
KerbErr = KDC_ERR_S_PRINCIPAL_UNKNOWN;
goto Cleanup;
}
//
// Duplicate the cached copy of the KRBTGT information
//
*TicketInfo = _KrbtgtTicketInfo;
TicketInfo->Passwords = NULL;
TicketInfo->OldPasswords = NULL;
TicketInfo->TrustSid = NULL;
TicketInfo->AccountName.Buffer = NULL;
if (!NT_SUCCESS(KerbDuplicateString(
&TicketInfo->AccountName,
&_KrbtgtTicketInfo.AccountName
)))
{
KerbErr = KRB_ERR_GENERIC;
goto Cleanup;
}
KerbErr = KdcDuplicateCredentials(
&TicketInfo->Passwords,
&CredentialSize,
_KrbtgtTicketInfo.Passwords,
FALSE // don't marshall
);
if (!KERB_SUCCESS(KerbErr))
{
goto Cleanup;
}
KerbErr = KdcDuplicateCredentials(
&TicketInfo->OldPasswords,
&CredentialSize,
_KrbtgtTicketInfo.OldPasswords,
FALSE // don't marshall
);
Cleanup:
Unlock();
if (!KERB_SUCCESS(KerbErr))
{
FreeTicketInfo(TicketInfo);
}
return(KerbErr);
}
//+-------------------------------------------------------------------------
//
// Function: CSecurityData::UpdateKrbtgtTicketInfo
//
// Synopsis: Triggers an update of the krbtgt ticket info
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
CSecurityData::UpdateKrbtgtTicketInfo(
VOID
)
{
NTSTATUS Status = STATUS_SUCCESS;
KERBERR KerbErr;
KDC_TICKET_INFO NewTicketInfo = {0};
PUSER_INTERNAL6_INFORMATION UserInfo = NULL;
KERB_EXT_ERROR ExtendedError; // dummy var
WriteLock();
_KrbtgtTicketInfoValid = FALSE;
KerbErr = KdcGetTicketInfo(
SecData.KdcServiceName(),
0, // no lookup flags
FALSE, // do not restrict user accounts (user2user)
NULL, // no principal name
NULL, // no realm
&NewTicketInfo,
&ExtendedError, // dummy
NULL, // no user handle
USER_ALL_PASSWORDLASTSET,
0L, // no extended fields
&UserInfo,
NULL // no group membership
);
if (KERB_SUCCESS(KerbErr))
{
FreeTicketInfo(
&_KrbtgtTicketInfo
);
_KrbtgtTicketInfo = NewTicketInfo;
_KrbtgtTicketInfoValid = TRUE;
_KrbtgtPasswordLastSet = UserInfo->I1.PasswordLastSet;
SamIFree_UserInternal6Information( UserInfo );
}
else
{
Status = KerbMapKerbError(KerbErr);
}
Unlock();
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: KdcAccountChangeNotificationRoutine
//
// Synopsis: Receives notification of changes to interesting accounts
//
// Effects: updatees cached krbtgt information
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
KdcAccountChangeNotification (
IN PSID DomainSid,
IN SECURITY_DB_DELTA_TYPE DeltaType,
IN SECURITY_DB_OBJECT_TYPE ObjectType,
IN ULONG ObjectRid,
IN OPTIONAL PUNICODE_STRING ObjectName,
IN PLARGE_INTEGER ModifiedCount,
IN PSAM_DELTA_DATA DeltaData OPTIONAL
)
{
NTSTATUS Status;
//
// We are only interested in the krbtgt account
//
if (ObjectRid != DOMAIN_USER_RID_KRBTGT)
{
return(STATUS_SUCCESS);
}
Status = SecData.UpdateKrbtgtTicketInfo();
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"Failed to update krbtgt ticket info: 0x%x\n",Status));
}
return(Status);
}
#if DBG
////////////////////////////////////////////////////////////////////////////
//
// Some debugging functions.
//
void
CSecurityData::DebugShowState(void)
{
TRACE(KDC, CSecurityData::DebugShowState, DEB_FUNCTION);
PrintTime(DEB_TRACE, " TGT Ticket lifespan\t", &_KDC_TgtTicketLifespan );
PrintTime(DEB_TRACE, " Ticket Renew Span\t",&_KDC_TicketRenewSpan );
D_DebugLog((DEB_TRACE, " Blank Addresses?\t%s\n",(_KDC_Flags & AUTH_REQ_ALLOW_NOADDRESS ? "Yes" : "No")));
D_DebugLog((DEB_TRACE, " Proxies? \t%s\n", (_KDC_Flags & AUTH_REQ_ALLOW_PROXIABLE ? "Yes" : "No")));
D_DebugLog((DEB_TRACE, " Renewable? \t%s\n", (_KDC_Flags & AUTH_REQ_ALLOW_RENEWABLE ? "Yes" : "No")));
D_DebugLog((DEB_TRACE, " Postdated? \t%s\n", (_KDC_Flags & AUTH_REQ_ALLOW_POSTDATE ? "Yes" : "No")));
D_DebugLog((DEB_TRACE, " Forwardable? \t%s\n", (_KDC_Flags & AUTH_REQ_ALLOW_FORWARDABLE ? "Yes" : "No")));
}
NTSTATUS
CSecurityData::DebugGetState( DWORD * KDCFlags,
TimeStamp * MaxLifespan,
TimeStamp * MaxRenewSpan)
{
TRACE(KDC, CSecurityData::DebugGetState, DEB_FUNCTION);
*KDCFlags = _KDC_Flags;
*MaxLifespan = _KDC_TgtTicketLifespan;
*MaxRenewSpan = _KDC_TicketRenewSpan;
return(STATUS_SUCCESS);
}
NTSTATUS
CSecurityData::DebugSetState( DWORD KDCFlags,
TimeStamp MaxLifespan,
TimeStamp MaxRenewSpan)
{
TRACE(KDC, CSecurityData::DebugSetState, DEB_FUNCTION);
_KDC_Flags = KDC_AUTH_STATE(KDCFlags);
_KDC_AuditEvents = KDC_AUDIT_STATE(KDCFlags);
_KDC_TgtTicketLifespan = MaxLifespan;
_KDC_TicketRenewSpan = MaxRenewSpan;
return(STATUS_SUCCESS);
}
#endif // DBG