1269 lines
32 KiB
C++
1269 lines
32 KiB
C++
//+-----------------------------------------------------------------------
|
|
//
|
|
// 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)
|
|
{
|
|
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__ ));
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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)
|
|
{
|
|
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__ ));
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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)
|
|
{
|
|
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__ ));
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// 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 = 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)*(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)*(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;
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
KerbLockList(&KerbMitRealmList);
|
|
|
|
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);
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
KerbUnlockList(&KerbMitRealmList);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: KerbLookupMitRealm
|
|
//
|
|
// Synopsis: Looks up an MIT realm name
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOLEAN
|
|
KerbLookupMitRealm(
|
|
IN PUNICODE_STRING RealmName,
|
|
OUT PKERB_MIT_REALM * MitRealm,
|
|
OUT PBOOLEAN UsedAlternateName
|
|
)
|
|
{
|
|
ULONG Index;
|
|
PLIST_ENTRY ListEntry;
|
|
PKERB_MIT_REALM CurrentRealm;
|
|
BOOLEAN fReturn = FALSE;
|
|
BOOLEAN fListLocked = FALSE;
|
|
|
|
*UsedAlternateName = FALSE;
|
|
*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))
|
|
{
|
|
*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))
|
|
{
|
|
*UsedAlternateName = TRUE;
|
|
*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 );
|
|
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 UsedAlternateName, 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, ptr = 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;
|
|
DnsRecordName.Buffer = (PCHAR) KerbAllocate(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);
|
|
}
|
|
|
|
if (DnsRecordName.Buffer != NULL)
|
|
{
|
|
KerbFree(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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|