|
|
//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 1992 - 1997
//
// File: mitutil.cxx
//
// Contents: Routines for talking to MIT KDCs
//
//
// History: 4-March-1997 Created MikeSw
// 26-Sep-1998 ChandanS
// Added more debugging support etc.
//
//------------------------------------------------------------------------
#include <kerb.hxx>
#include <kerbp.h>
#ifdef RETAIL_LOG_SUPPORT
static TCHAR THIS_FILE[]=TEXT(__FILE__); #endif
static HKEY KerbMITRealmRootKey = NULL; static HANDLE hKerbMITRealmWaitEvent = NULL; static HANDLE hKerbMITRealmWaitObject = NULL;
KERBEROS_LIST KerbMitRealmList;
#define MAX_DOMAIN_NAME_LEN 128 // number of characters
//+-------------------------------------------------------------------------
//
// Function: KerbReadMitRealmList
//
// Synopsis: Loads the list of MIT realms from the registry
//
// Effects: Initialize and links domains to KerbMitRealmList
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS KerbReadMitRealmList( ) { NTSTATUS Status = STATUS_SUCCESS; ULONG WinError; HKEY DomainKey = NULL; LPWSTR KdcNames = NULL; LPWSTR KpasswdNames = NULL; LPWSTR AlternateRealmNames = NULL; TCHAR DomainName[MAX_DOMAIN_NAME_LEN]; // max domain name length
PKERB_MIT_REALM MitRealm = NULL; ULONG Index,Index2; ULONG Type; ULONG NameSize; ULONG KdcNameSize = 0; ULONG AltRealmSize = 0; ULONG KpasswdNameSize = 0; LPWSTR Where; ULONG NameCount, tmp; UNICODE_STRING TempString; ULONG Flags = 0; ULONG FlagSize = sizeof(ULONG); ULONG ApReqChecksumType = 0; ULONG PreAuthType = 0; BOOLEAN fListLocked = FALSE;
//
// If it is there, we now want to enumerate all the child keys.
//
KerbLockList(&KerbMitRealmList); fListLocked = TRUE;
for (Index = 0; TRUE ; Index++ ) { //
// Enumerate through all the keys
//
NameSize = MAX_DOMAIN_NAME_LEN; WinError = RegEnumKeyEx( KerbMITRealmRootKey, Index, DomainName, &NameSize, NULL, NULL, NULL, NULL );
if (WinError != ERROR_SUCCESS) { //
// nothing more to do.
//
Status = STATUS_SUCCESS; goto Cleanup; }
//
// Open the domain key to read the values under it
//
if( DomainKey != NULL ) { RegCloseKey( DomainKey ); DomainKey = NULL; }
WinError = RegOpenKey( KerbMITRealmRootKey, DomainName, &DomainKey ); if (WinError != ERROR_SUCCESS) { D_DebugLog((DEB_ERROR,"Failed to open key %ws \\ %ws: %d. %ws, line %d\n", KERB_DOMAINS_KEY, DomainName, WinError, THIS_FILE, __LINE__ ));
//
// keep going.
//
continue; }
//
// Now read the values from the domain
//
KdcNameSize = 0; WinError = RegQueryValueEx( DomainKey, KERB_DOMAIN_KDC_NAMES_VALUE, NULL, &Type, NULL, &KdcNameSize ); if (WinError == ERROR_SUCCESS) { KdcNames = (LPWSTR) KerbAllocate(KdcNameSize); if (KdcNames == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } WinError = RegQueryValueEx( DomainKey, KERB_DOMAIN_KDC_NAMES_VALUE, NULL, &Type, (PUCHAR) KdcNames, &KdcNameSize ); if (WinError != ERROR_SUCCESS || Type != REG_MULTI_SZ ) { D_DebugLog((DEB_ERROR,"Failed to query value %ws\\%ws: %d. %ws, line %d\n", DomainName, KERB_DOMAIN_KDC_NAMES_VALUE, WinError, THIS_FILE, __LINE__ )); continue; // keep reading...
} }
//
// Now read the Kpasswd values from the domain
//
KpasswdNameSize = 0; WinError = RegQueryValueEx( DomainKey, KERB_DOMAIN_KPASSWD_NAMES_VALUE, NULL, &Type, NULL, &KpasswdNameSize ); if (WinError == ERROR_SUCCESS) { KpasswdNames = (LPWSTR) KerbAllocate(KpasswdNameSize); if (KpasswdNames == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } WinError = RegQueryValueEx( DomainKey, KERB_DOMAIN_KPASSWD_NAMES_VALUE, NULL, &Type, (PUCHAR) KpasswdNames, &KpasswdNameSize ); if (WinError != ERROR_SUCCESS || Type != REG_MULTI_SZ ) { D_DebugLog((DEB_ERROR,"Failed to query value %ws\\%ws: %d. %ws, line %d\n", DomainName, KERB_DOMAIN_KPASSWD_NAMES_VALUE, WinError, THIS_FILE, __LINE__ )); continue; // keep reading
} }
//
// Get any alternate domain names
//
AltRealmSize = 0; WinError = RegQueryValueEx( DomainKey, KERB_DOMAIN_ALT_NAMES_VALUE, NULL, &Type, NULL, &AltRealmSize ); if (WinError == ERROR_SUCCESS) { AlternateRealmNames = (LPWSTR) KerbAllocate(AltRealmSize); if (AlternateRealmNames == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } WinError = RegQueryValueEx( DomainKey, KERB_DOMAIN_ALT_NAMES_VALUE, NULL, &Type, (PUCHAR) AlternateRealmNames, &AltRealmSize );
if (WinError != ERROR_SUCCESS || Type != REG_MULTI_SZ) { D_DebugLog((DEB_ERROR,"Failed to query value %ws\\%ws: %d. %ws, line %d\n", DomainName, KERB_DOMAIN_KDC_NAMES_VALUE, WinError, THIS_FILE, __LINE__ )); continue; }
}
//
// Read the flags
//
FlagSize = sizeof(ULONG); Flags = 0;
WinError = RegQueryValueEx( DomainKey, KERB_DOMAIN_FLAGS_VALUE, NULL, &Type, (PUCHAR) &Flags, &FlagSize ); if (WinError == ERROR_SUCCESS) { if (Type != REG_DWORD) { Flags = 0; } }
//
// Read the ApReq checksum type
//
FlagSize = sizeof(ULONG); ApReqChecksumType = KERB_DEFAULT_AP_REQ_CSUM;
WinError = RegQueryValueEx( DomainKey, KERB_DOMAIN_AP_REQ_CSUM_VALUE, NULL, &Type, (PUCHAR) &ApReqChecksumType, &FlagSize ); if (WinError == ERROR_SUCCESS) { if (Type != REG_DWORD) { ApReqChecksumType = KERB_DEFAULT_AP_REQ_CSUM; } }
//
// Read the ApReq checksum type
//
FlagSize = sizeof(ULONG); PreAuthType = KERB_DEFAULT_PREAUTH_TYPE;;
WinError = RegQueryValueEx( DomainKey, KERB_DOMAIN_PREAUTH_VALUE, NULL, &Type, (PUCHAR) &PreAuthType, &FlagSize ); if (WinError == ERROR_SUCCESS) { if (Type != REG_DWORD) { PreAuthType = KERB_DEFAULT_PREAUTH_TYPE; } }
//
// Now build the domain structure
//
MitRealm = (PKERB_MIT_REALM) KerbAllocate(sizeof(KERB_MIT_REALM)); if (MitRealm == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; }
MitRealm->Flags = Flags; MitRealm->ApReqChecksumType = ApReqChecksumType; MitRealm->PreAuthType = PreAuthType; #ifdef WIN32_CHICAGO
RtlCreateUnicodeStringFromAsciiz( &TempString, DomainName ); #else // WIN32_CHICAGO
RtlInitUnicodeString( &TempString, DomainName ); #endif // WIN32_CHICAGO
Status = KerbDuplicateString( &MitRealm->RealmName, &TempString );
if (!NT_SUCCESS(Status)) { goto Cleanup; }
//
// Fill in the KDC names etc.
//
NameCount = 0; if ((AlternateRealmNames != NULL ) && (AltRealmSize != 0)) { Where = AlternateRealmNames; NameCount ++; while (Where + wcslen(Where) + 1 < (AlternateRealmNames + AltRealmSize /sizeof(WCHAR))) { NameCount++; Where += wcslen(Where)+1; } MitRealm->AlternateRealmNames = (PUNICODE_STRING) KerbAllocate(NameCount * sizeof(UNICODE_STRING)); if (MitRealm->AlternateRealmNames == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; }
MitRealm->RealmNameCount = NameCount; Where = AlternateRealmNames; for (Index2 = 0;Index2 < NameCount; Index2++) { RtlInitUnicodeString( &MitRealm->AlternateRealmNames[Index2], Where ); Where += MitRealm->AlternateRealmNames[Index2].Length / sizeof(WCHAR) + 1; }
AlternateRealmNames = NULL; }
NameCount = 0; if ((KdcNames != NULL ) && (KdcNameSize != 0)) { Where = KdcNames; while (Where + wcslen(Where) + 1 < (KdcNames + KdcNameSize /sizeof(WCHAR))) { // There's a bug in ksetup which adds a couple of "" strings to this, so...
tmp = (ULONG) wcslen(Where) + 1; if (tmp > 1) { NameCount++; } Where += tmp; } MitRealm->KdcNames.ServerNames = (PUNICODE_STRING) KerbAllocate(NameCount * sizeof(UNICODE_STRING)); if (MitRealm->KdcNames.ServerNames == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } MitRealm->KdcNames.ServerCount = NameCount; Where = KdcNames; for (Index2 = 0;Index2 < NameCount; Index2++) { RtlInitUnicodeString( &MitRealm->KdcNames.ServerNames[Index2], Where );
// ugh. Didn't want to have to allocate, but keep it simple.
MitRealm->KdcNames.ServerNames[Index2].Buffer = (LPWSTR) KerbAllocate(sizeof(WCHAR) * ((ULONG) wcslen(Where) + 2));
if (NULL == MitRealm->KdcNames.ServerNames[Index2].Buffer) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; }
wcscpy(MitRealm->KdcNames.ServerNames[Index2].Buffer, Where); Where += MitRealm->KdcNames.ServerNames[Index2].Length / sizeof(WCHAR) + 1; } KerbFree(KdcNames); KdcNames = NULL; }
if (NameCount == 0) { MitRealm->Flags |= KERB_MIT_REALM_KDC_LOOKUP; }
NameCount = 0; if ((KpasswdNames != NULL ) && (KpasswdNameSize != 0)) { Where = KpasswdNames; NameCount ++; while (Where + wcslen(Where) + 1 - (KpasswdNames + KpasswdNameSize /sizeof(WCHAR)) > 0) { NameCount++; Where += wcslen(Where)+1; } MitRealm->KpasswdNames.ServerNames = (PUNICODE_STRING) KerbAllocate(NameCount * sizeof(UNICODE_STRING)); if (MitRealm->KpasswdNames.ServerNames == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } MitRealm->KpasswdNames.ServerCount = NameCount; Where = KpasswdNames; for (Index2 = 0;Index2 < NameCount; Index2++) { RtlInitUnicodeString( &MitRealm->KpasswdNames.ServerNames[Index2], Where );
// ugh. Didn't want to have to allocate, but keep it simple.
MitRealm->KpasswdNames.ServerNames[Index2].Buffer = (LPWSTR) KerbAllocate(sizeof(WCHAR) * ((ULONG) wcslen(Where) + 2));
if (NULL == MitRealm->KpasswdNames.ServerNames[Index2].Buffer) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; }
wcscpy(MitRealm->KpasswdNames.ServerNames[Index2].Buffer, Where); Where += MitRealm->KpasswdNames.ServerNames[Index2].Length / sizeof(WCHAR) + 1; }
KerbFree(KpasswdNames); KpasswdNames = NULL; }
if (NameCount == 0) { MitRealm->Flags |= KERB_MIT_REALM_KPWD_LOOKUP; }
KerbInsertListEntry( &MitRealm->Next, &KerbMitRealmList ); MitRealm = NULL;
} // ** FOR **
Cleanup:
if (fListLocked) { KerbUnlockList(&KerbMitRealmList); }
if( DomainKey != NULL ) { RegCloseKey( DomainKey ); }
if (KdcNames != NULL) { KerbFree(KdcNames); } if (KpasswdNames != NULL) { KerbFree(KpasswdNames); } if (AlternateRealmNames != NULL) { KerbFree(AlternateRealmNames); } if (MitRealm != NULL) { if (MitRealm->AlternateRealmNames != NULL) { #if 0 // note: embededded buffers are all enclosed within AlternateRealmNames[0]
for(Index = 0 ; Index < MitRealm->RealmNameCount ; Index++) { if (MitRealm->AlternateRealmNames[Index].Buffer != NULL) { KerbFree(MitRealm->AlternateRealmNames[Index].Buffer); } } #else
if (MitRealm->AlternateRealmNames[0].Buffer != NULL) { KerbFree(MitRealm->AlternateRealmNames[0].Buffer); } #endif
KerbFree(MitRealm->AlternateRealmNames); } if (MitRealm->KdcNames.ServerNames != NULL) { LONG lIndex;
for(lIndex = 0 ; lIndex < MitRealm->KdcNames.ServerCount ; lIndex++) { if (MitRealm->KdcNames.ServerNames[lIndex].Buffer != NULL) { KerbFree(MitRealm->KdcNames.ServerNames[lIndex].Buffer); } }
KerbFree(MitRealm->KdcNames.ServerNames); } if (MitRealm->KpasswdNames.ServerNames != NULL) { LONG lIndex;
for(lIndex = 0 ; lIndex < MitRealm->KpasswdNames.ServerCount ; lIndex++) { if (MitRealm->KpasswdNames.ServerNames[lIndex].Buffer != NULL) { KerbFree(MitRealm->KpasswdNames.ServerNames[lIndex].Buffer); } }
KerbFree(MitRealm->KpasswdNames.ServerNames); } KerbFree(MitRealm); } return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: KerbCleanupMitRealmList
//
// Synopsis: Frees the list of MIT realms
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
VOID KerbCleanupMitRealmList( ) { PKERB_MIT_REALM MitRealm; BOOLEAN ListLocked = FALSE;
KerbLockList(&KerbMitRealmList); ListLocked = TRUE;
if (KerbMitRealmList.List.Flink == NULL) { goto Cleanup; }
while (!IsListEmpty(&KerbMitRealmList.List)) { MitRealm = CONTAINING_RECORD( KerbMitRealmList.List.Flink, KERB_MIT_REALM, Next );
KerbReferenceListEntry( &KerbMitRealmList, &MitRealm->Next, TRUE );
if (MitRealm->AlternateRealmNames != NULL) { if (MitRealm->AlternateRealmNames[0].Buffer != NULL) { KerbFree(MitRealm->AlternateRealmNames[0].Buffer); } KerbFree(MitRealm->AlternateRealmNames); }
if (MitRealm->KdcNames.ServerNames != NULL) { LONG lIndex;
for(lIndex = 0 ; lIndex < MitRealm->KdcNames.ServerCount ; lIndex++) { if (MitRealm->KdcNames.ServerNames[lIndex].Buffer != NULL) { KerbFree(MitRealm->KdcNames.ServerNames[lIndex].Buffer); } }
KerbFree(MitRealm->KdcNames.ServerNames); } if (MitRealm->KpasswdNames.ServerNames != NULL) { LONG lIndex;
for(lIndex = 0 ; lIndex < MitRealm->KpasswdNames.ServerCount ; lIndex++) { if (MitRealm->KpasswdNames.ServerNames[lIndex].Buffer != NULL) { KerbFree(MitRealm->KpasswdNames.ServerNames[lIndex].Buffer); } }
KerbFree(MitRealm->KpasswdNames.ServerNames); }
if (MitRealm->RealmName.Buffer != NULL) { MIDL_user_free(MitRealm->RealmName.Buffer);
} KerbFree(MitRealm); }
KerbUnlockList(&KerbMitRealmList); ListLocked = FALSE;
//
// Purge our old entries.
//
KerbCleanupBindingCache(FALSE);
Cleanup: if ( ListLocked ) { KerbUnlockList(&KerbMitRealmList); } }
//+-------------------------------------------------------------------------
//
// Function: KerbLookupMitRealm
//
// Synopsis: Looks up an MIT realm name
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
BOOLEAN KerbLookupMitRealm( IN PUNICODE_STRING RealmName, OUT OPTIONAL PKERB_MIT_REALM* MitRealm, OUT OPTIONAL PBOOLEAN UsedAlternateName ) { ULONG Index; PLIST_ENTRY ListEntry; PKERB_MIT_REALM CurrentRealm; BOOLEAN fReturn = FALSE; BOOLEAN fListLocked = FALSE;
if (UsedAlternateName) { *UsedAlternateName = FALSE; }
if (MitRealm) { *MitRealm = NULL; }
if (RealmName->Length == 0) { goto Cleanup; }
KerbLockList(&KerbMitRealmList); fListLocked = TRUE;
for (ListEntry = KerbMitRealmList.List.Flink ; ListEntry != &KerbMitRealmList.List ; ListEntry = ListEntry->Flink ) { CurrentRealm = CONTAINING_RECORD(ListEntry, KERB_MIT_REALM, Next);
if (RtlEqualUnicodeString( RealmName, &CurrentRealm->RealmName, TRUE)) { if (MitRealm) { *MitRealm = CurrentRealm; }
fReturn = TRUE; goto Cleanup; }
//
// Check for an alternate name for the realm
//
for (Index = 0; Index < CurrentRealm->RealmNameCount ; Index++ ) { if (RtlEqualUnicodeString( RealmName, &CurrentRealm->AlternateRealmNames[Index], TRUE)) { if (UsedAlternateName) { *UsedAlternateName = TRUE; }
if (MitRealm) { *MitRealm = CurrentRealm; }
fReturn = TRUE; goto Cleanup; } } } Cleanup: if (fListLocked) { KerbUnlockList(&KerbMitRealmList); } return(fReturn);
}
////////////////////////////////////////////////////////////////////
//
// Name: KerbWatchMITKey
//
// Synopsis: Sets RegNotifyChangeKeyValue() on MIT key and
// utilizes thread pool to wait on changes to this
// registry key. Enables dynamic changing of MIT
// realms as this function will also be callback
// if the registry key is modified.
//
// Arguments: pCtxt is actually a HANDLE to an event. This event
// will be triggered when key is modified.
//
// Notes:
//
void KerbWatchMITKey(PVOID pCtxt, BOOLEAN fWaitStatus) { NTSTATUS Status = STATUS_SUCCESS; ULONG Error;
KerbCleanupMitRealmList(); Status = KerbReadMitRealmList(); if (!NT_SUCCESS(Status)) { D_DebugLog((DEB_ERROR,"Debug reading MIT realm list failed: 0x%x\n", Status)); }
if (NULL != hKerbMITRealmWaitEvent) { Error = RegNotifyChangeKeyValue( KerbMITRealmRootKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME, hKerbMITRealmWaitEvent, TRUE);
if (ERROR_SUCCESS != Error) { D_DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", Status)); // we're tanked now. No further notifications, so get this one
} }
return; }
//+-------------------------------------------------------------------------
//
// Function: KerbInitializeMitRealmList
//
// Synopsis: Loads the list of MIT realms from the registry
//
// Effects: Initialize and links domains to KerbMitRealmList
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS KerbInitializeMitRealmList( ) { ULONG Disposition; ULONG Error; HKEY RootKey = NULL; NTSTATUS Status = STATUS_SUCCESS;
//
// Open the domains root key - if it is not there, so be it.
//
Error = RegCreateKeyEx( HKEY_LOCAL_MACHINE, KERB_DOMAINS_KEY, 0, NULL, 0, KEY_READ, NULL, &RootKey, &Disposition);
if (ERROR_SUCCESS != Error) { D_DebugLog((DEB_WARN,"Failed to open MIT realm key: 0x%x\n", Status)); Status = STATUS_UNSUCCESSFUL; goto Cleanup; }
//
// Initialize the list
//
Status = KerbInitializeList( &KerbMitRealmList, MIT_REALM_LIST_LOCK_ENUM ); if (!NT_SUCCESS(Status)) { D_DebugLog((DEB_ERROR, "Intialization of MIT realm list failed - 0x%x\n", Status)); goto Cleanup; }
hKerbMITRealmWaitEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
if (NULL == hKerbMITRealmWaitEvent) { D_DebugLog((DEB_ERROR, "CreateEvent for MIT realm list wait failed - 0x%x\n", GetLastError())); Status = STATUS_NO_MEMORY; goto Cleanup; }
KerbMITRealmRootKey = RootKey; RootKey = NULL;
//
// read in the list and setup the RegNotify
//
KerbWatchMITKey(NULL, FALSE);
hKerbMITRealmWaitObject = RegisterWaitForSingleObjectEx( hKerbMITRealmWaitEvent, KerbWatchMITKey, NULL, INFINITE, 0 // dwFlags
);
Cleanup:
if( RootKey != NULL ) { RegCloseKey( RootKey ); }
return Status; }
//+-------------------------------------------------------------------------
//
// Function: KerbUninitializeMitRealmList
//
// Synopsis: Loads the list of MIT realms from the registry
//
// Effects: Initialize and links domains to KerbMitRealmList
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
VOID KerbUninitializeMitRealmList( ) { if( hKerbMITRealmWaitObject ) UnregisterWait( hKerbMITRealmWaitObject );
if( hKerbMITRealmWaitEvent ) CloseHandle( hKerbMITRealmWaitEvent );
KerbCleanupMitRealmList();
return; }
//+-------------------------------------------------------------------------
//
// Function: KerbLookupMitSrvRecords
//
// Synopsis: Looks up MIT KDCs / Kpassword in DNS
//
// Effects: Builds MIT_SERVER_LIST for specified realm, and adds it to
// MIT REALM LIST
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS KerbLookupMitSrvRecords(IN PKERB_MIT_REALM RealmEntry, IN BOOLEAN Kpasswd, IN BOOLEAN UseTcp ) { ANSI_STRING DnsRecordName; ANSI_STRING AnsiRealmName; HANDLE SrvContext = NULL; BOOLEAN ListLocked = FALSE; NTSTATUS Status = STATUS_SUCCESS; ULONG AddressCount = 0, SrvCount = 0; ULONG Index = 0, uBuff = 0; LPSOCKET_ADDRESS Addresses = NULL; NET_API_STATUS NetApiStatus = NERR_Success; LPSTR pDnsName[MAX_SRV_RECORDS]; PKERB_MIT_SERVER_LIST ServerList = NULL; PUNICODE_STRING ServerNames = NULL;
TimeStamp CurrentTime, Timeout; //
// Test to see if we need to do a lookup, or if its time to try again
//
if (RealmEntry->LastLookup.QuadPart != 0 ) { GetSystemTimeAsFileTime((PFILETIME) &CurrentTime ); KerbSetTimeInMinutes(&Timeout, DNS_LOOKUP_TIMEOUT); if (KerbGetTime(RealmEntry->LastLookup) + KerbGetTime(Timeout) < KerbGetTime(CurrentTime)) { return STATUS_SUCCESS; } } // Kpasswd only uses UDP
if (Kpasswd) { UseTcp = FALSE; } RtlInitAnsiString(&DnsRecordName,NULL); RtlInitAnsiString(&AnsiRealmName,NULL); DnsRecordName.Length = (RealmEntry->RealmName.Length / sizeof(WCHAR)) + DNS_MAX_PREFIX + 1; DnsRecordName.MaximumLength = DnsRecordName.Length; SafeAllocaAllocate(DnsRecordName.Buffer, DnsRecordName.Length);
if (NULL == DnsRecordName.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; }
RtlUnicodeStringToAnsiString( &AnsiRealmName, &RealmEntry->RealmName, TRUE );
sprintf(DnsRecordName.Buffer, "%s%s%s", (Kpasswd ? DNS_KPASSWD : DNS_KERBEROS), (UseTcp ? DNS_TCP : DNS_UDP), AnsiRealmName.Buffer );
NetApiStatus = NetpSrvOpen( DnsRecordName.Buffer, 0, &SrvContext );
if (NERR_Success != NetApiStatus) { D_DebugLog((DEB_WARN, "No SRV records for MIT Realm %wZ - %x\n", RealmEntry->RealmName, NetApiStatus )); Status = STATUS_SUCCESS; goto Cleanup; }
// Loop and update server list for realm
for (SrvCount = 0; SrvCount < MAX_SRV_RECORDS; SrvCount++) {
NetApiStatus = NetpSrvNext( SrvContext, &AddressCount, &Addresses, &pDnsName[SrvCount] );
if (NERR_Success != NetApiStatus) { if( ERROR_NO_MORE_ITEMS == NetApiStatus) // we're through
{ NetApiStatus = NERR_Success; break; }
D_DebugLog((DEB_ERROR, "NetpSrvNext failed: %s - %x\n",DnsRecordName.Buffer, NetApiStatus)); Status = NetApiStatus; goto Cleanup; } }
KerbLockList(&KerbMitRealmList); ListLocked = TRUE; // Loop through available server names, and copy
if (Kpasswd) { ServerList = &RealmEntry->KpasswdNames; } else { ServerList = &RealmEntry->KdcNames; } // reg entries are always at beginning of server list.
uBuff = ( SrvCount * sizeof(UNICODE_STRING));
ServerNames = (PUNICODE_STRING) KerbAllocate(uBuff);
if (NULL == ServerNames) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } for (Index = 0; Index < SrvCount;Index++) { if (!KerbMbStringToUnicodeString( &ServerNames[Index ], pDnsName[Index] )) { D_DebugLog((DEB_ERROR,"KerbConvertMbStringToUnicodeString failed!\n")); continue; // let's keep going. Maybe we're not hosed.
} } KerbFreeServerNames(ServerList); ServerList->ServerCount = SrvCount; ServerList->ServerNames = ServerNames;
RealmEntry->Flags &= ~( Kpasswd ? KERB_MIT_REALM_KPWD_LOOKUP : KERB_MIT_REALM_KDC_LOOKUP );
Cleanup: // always update realm entry, even on failure
if (!ListLocked) { KerbLockList(&KerbMitRealmList); ListLocked = TRUE; } GetSystemTimeAsFileTime((PFILETIME) &RealmEntry->LastLookup); if (ListLocked) { KerbUnlockList(&KerbMitRealmList); } if (AnsiRealmName.Buffer != NULL) { RtlFreeAnsiString(&AnsiRealmName); }
SafeAllocaFree(DnsRecordName.Buffer);
if (SrvContext != NULL) { NetpSrvClose(SrvContext); }
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: KerbFreeServerNames
//
// Synopsis: Frees server names PUNICODE_STRING array
//
// Effects:
//
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
void KerbFreeServerNames(PKERB_MIT_SERVER_LIST ServerList) { LONG Index = 0;
for (Index = 0; Index < ServerList->ServerCount; Index++) { if (ServerList->ServerNames[Index].Buffer != NULL) { KerbFree(ServerList->ServerNames[Index].Buffer); } }
KerbFree(ServerList->ServerNames); // free UNICODE_STRING array
}
//+-------------------------------------------------------------------------
//
// Function: KerbLookupMitRealmWithSrvLookup
//
// Synopsis: Frees server names PUNICODE_STRING array
//
// Effects:
//
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
BOOLEAN KerbLookupMitRealmWithSrvLookup(PUNICODE_STRING RealmName, PKERB_MIT_REALM* MitRealm, BOOLEAN Kpasswd, BOOLEAN UseTcp) { BOOLEAN UsedAlternateName, fRet = FALSE; NTSTATUS Status;
fRet = KerbLookupMitRealm( RealmName, MitRealm, &UsedAlternateName ); //
// Found an MIT realm. See if its time to check on SRV records
//
if ( fRet ) {
if ((((*MitRealm)->Flags & KERB_MIT_REALM_KDC_LOOKUP) && !Kpasswd ) || (((*MitRealm)->Flags & KERB_MIT_REALM_KPWD_LOOKUP) && Kpasswd )) { Status = KerbLookupMitSrvRecords( (*MitRealm), Kpasswd, UseTcp ); if (Status != STATUS_SUCCESS) { D_DebugLog((DEB_TRACE, "KerbLookupMitRealmWIthSrvLookup failed - %x\n", Status)); } } } return fRet; }
|