mirror of https://github.com/lianthony/NT4.0
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.
445 lines
13 KiB
445 lines
13 KiB
|
|
/****************************************************************************
|
|
|
|
PROGRAM: LSA.C
|
|
|
|
PURPOSE: Utility routines that access the LSA.
|
|
|
|
****************************************************************************/
|
|
|
|
#include "msgina.h"
|
|
|
|
|
|
|
|
// #define DEBUG_LSA
|
|
|
|
#ifdef DEBUG_LSA
|
|
#define VerbosePrint(s) WLPrint(s)
|
|
#else
|
|
#define VerbosePrint(s)
|
|
#endif
|
|
|
|
|
|
/***************************************************************************\
|
|
* OpenLsaOnController
|
|
*
|
|
* Purpose : Attempts to open the Lsa on the specified domain controller.
|
|
* If the open is successful, this routine checks that the
|
|
* controller is still a controller for the specified domain
|
|
*
|
|
* Notes: If the controller name is NULL, the local Lsa is opened.
|
|
*
|
|
* Returns : TRUE on success, FALSE on failure.
|
|
*
|
|
* Notes: Desired access must include POLICY_VIEW_LOCAL_INFO
|
|
*
|
|
* History:
|
|
* 11-03-92 Davidc Created.
|
|
\***************************************************************************/
|
|
BOOL
|
|
OpenLsaOnController(
|
|
PUNICODE_STRING ControllerName OPTIONAL,
|
|
ACCESS_MASK DesiredAccess,
|
|
PUNICODE_STRING PrimaryDomainName,
|
|
PLSA_HANDLE LsaHandle
|
|
)
|
|
{
|
|
NTSTATUS Status, IgnoreStatus;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
|
|
PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo;
|
|
PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo;
|
|
BOOL Success = FALSE;
|
|
|
|
//
|
|
// Attempt to open the Lsa on the controller
|
|
//
|
|
|
|
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
|
SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
|
|
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|
SecurityQualityOfService.EffectiveOnly = FALSE;
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes, NULL, 0L, NULL, NULL);
|
|
ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
|
|
|
|
Status = LsaOpenPolicy(
|
|
ControllerName,
|
|
&ObjectAttributes,
|
|
DesiredAccess,
|
|
LsaHandle
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DebugLog((DEB_TRACE, "Failed to open lsa on <%wZ>, status = 0x%lx\n", ControllerName, Status));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Check the controller is actually in this domain
|
|
//
|
|
|
|
ASSERT(DesiredAccess & POLICY_VIEW_LOCAL_INFORMATION);
|
|
|
|
Status = LsaQueryInformationPolicy(*LsaHandle,
|
|
PolicyPrimaryDomainInformation,
|
|
(PVOID *)&PrimaryDomainInfo);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DebugLog((DEB_TRACE, "Failed to query primary domain from Lsa on <%wZ>, Status = 0x%lx\n", ControllerName, Status));
|
|
} else {
|
|
|
|
//
|
|
// Check the controller is in our domain
|
|
//
|
|
|
|
Success = RtlEqualUnicodeString(PrimaryDomainName,
|
|
&PrimaryDomainInfo->Name,
|
|
TRUE // Case insensitive
|
|
);
|
|
if (!Success) {
|
|
DebugLog((DEB_TRACE, "Controller <%wZ> is not in our domain <%wZ>, ignoring it\n", ControllerName, PrimaryDomainName));
|
|
}
|
|
|
|
if (Success) {
|
|
|
|
//
|
|
// Computer is in the domain, is it still a DC?
|
|
//
|
|
|
|
Status = LsaQueryInformationPolicy(*LsaHandle,
|
|
PolicyAccountDomainInformation,
|
|
(PVOID *)&AccountDomainInfo);
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
Success = RtlEqualUnicodeString(&AccountDomainInfo->DomainName,
|
|
&PrimaryDomainInfo->Name,
|
|
TRUE // Case insensitive
|
|
);
|
|
|
|
IgnoreStatus = LsaFreeMemory(AccountDomainInfo);
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
|
|
} else {
|
|
|
|
Success = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free up returned Lsa structure
|
|
//
|
|
|
|
IgnoreStatus = LsaFreeMemory(PrimaryDomainInfo);
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
|
|
}
|
|
|
|
//
|
|
// Clean up the Lsa handle on failure
|
|
//
|
|
|
|
if (!Success) {
|
|
|
|
//
|
|
// The following call may fail if RPC has invalidated the handle
|
|
//
|
|
|
|
IgnoreStatus = LsaClose(*LsaHandle);
|
|
}
|
|
|
|
return(Success);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* OpenLsaOnDomain
|
|
*
|
|
* Purpose : Opens the Lsa on a domain controller in the domain.
|
|
*
|
|
* Notes: On successful return, the caller should free the ControllerName
|
|
* using RtlFreeUnicodeString()
|
|
*
|
|
* Returns : ThreadExitCode
|
|
*
|
|
* History:
|
|
* 11-12-92 Davidc Created.
|
|
\***************************************************************************/
|
|
BOOL
|
|
OpenLsaOnDomain(
|
|
PUNICODE_STRING PrimaryDomainName IN,
|
|
ACCESS_MASK DesiredAccess IN,
|
|
PUNICODE_STRING SuggestedControllerName IN OPTIONAL,
|
|
PUNICODE_STRING ControllerName OUT,
|
|
PLSA_HANDLE ControllerHandle OUT
|
|
)
|
|
{
|
|
NT_PRODUCT_TYPE NtProductType;
|
|
|
|
//
|
|
// Find out what product we are installed as
|
|
// This always defaults to something useful even on failure
|
|
//
|
|
|
|
RtlGetNtProductType(&NtProductType);
|
|
|
|
|
|
//
|
|
// Prepare for failure
|
|
//
|
|
|
|
*ControllerHandle = NULL;
|
|
RtlInitUnicodeString(ControllerName, NULL);
|
|
|
|
if (!IsWorkstation(NtProductType)) {
|
|
|
|
//
|
|
// LanmanNT machine - controller is local machine
|
|
//
|
|
|
|
if (!OpenLsaOnController( NULL,
|
|
DesiredAccess,
|
|
PrimaryDomainName,
|
|
ControllerHandle)) {
|
|
|
|
DebugLog((DEB_TRACE, "Failed to open local lsa, desired access = 0x%lx\n", DesiredAccess));
|
|
*ControllerHandle = NULL;
|
|
return(FALSE);
|
|
|
|
}
|
|
return(TRUE);
|
|
|
|
} else {
|
|
|
|
//
|
|
// WinNT machine - try the suggested controller, if that fails
|
|
// use I_NetGetDCList to get controller list and try each one
|
|
// until we open the Lsa successfully.
|
|
//
|
|
|
|
DWORD Error;
|
|
LPBYTE DCNameBuffer;
|
|
BOOLEAN Result;
|
|
UNICODE_STRING DCName;
|
|
|
|
|
|
//
|
|
// Wait for the network to start
|
|
//
|
|
|
|
if (!WaitForNetworkToStart(SERVICE_NETLOGON)) {
|
|
DebugLog((DEB_ERROR, "Failed to wait for network to start\n"));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Try suggested controller
|
|
// Don't bother if it's the local LSA
|
|
//
|
|
|
|
if ( SuggestedControllerName &&
|
|
(SuggestedControllerName->Buffer != NULL) &&
|
|
(SuggestedControllerName->Length != 0) ) {
|
|
|
|
if (OpenLsaOnController( SuggestedControllerName,
|
|
DesiredAccess,
|
|
PrimaryDomainName,
|
|
ControllerHandle)) {
|
|
//
|
|
// Success - the suggested controller came up trumps
|
|
//
|
|
|
|
if (!DuplicateUnicodeString(ControllerName,
|
|
SuggestedControllerName)) {
|
|
RtlInitUnicodeString(ControllerName, NULL);
|
|
}
|
|
|
|
DebugLog((DEB_TRACE, "Successfully opened Lsa on suggested controller\n"));
|
|
|
|
return(TRUE);
|
|
|
|
} else {
|
|
|
|
DebugLog((DEB_TRACE, "Failed to open Lsa on suggested controller <%wZ>, trying other controllers\n", SuggestedControllerName));
|
|
*ControllerHandle = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Go get the list of domain controllers for the domain
|
|
//
|
|
|
|
ASSERT(PrimaryDomainName->Length < PrimaryDomainName->MaximumLength);
|
|
PrimaryDomainName->Buffer[ PrimaryDomainName->Length/
|
|
sizeof(*(PrimaryDomainName->Buffer)) ] = 0;
|
|
|
|
|
|
Error = NetGetAnyDCName (
|
|
NULL,
|
|
PrimaryDomainName->Buffer,
|
|
&DCNameBuffer
|
|
);
|
|
|
|
if (Error != ERROR_SUCCESS) {
|
|
DebugLog((DEB_ERROR, "NetGetAnyDCName failed, error = %d\n", Error));
|
|
return(FALSE);
|
|
}
|
|
|
|
RtlInitUnicodeString( &DCName, (PCWSTR)DCNameBuffer );
|
|
|
|
//
|
|
// Attempt to open the LSA for one of the controllers on the list.
|
|
// For now, just scan the list from the end backwards. Later,
|
|
// use a more random method. The active Domain Controller is
|
|
// at the beginning of the list.
|
|
//
|
|
|
|
DebugLog((DEB_TRACE, "Trying to open Lsa on controller <%wZ>\n", &DCName));
|
|
|
|
Result = OpenLsaOnController( &DCName,
|
|
DesiredAccess,
|
|
PrimaryDomainName,
|
|
ControllerHandle);
|
|
|
|
if ( Result ) {
|
|
if (!DuplicateUnicodeString(ControllerName,
|
|
&DCName)) {
|
|
RtlInitUnicodeString(ControllerName, NULL);
|
|
}
|
|
} else {
|
|
DebugLog((DEB_TRACE, "Unable to open Lsa on controller <%s>\n", DCNameBuffer));
|
|
}
|
|
|
|
Error = NetApiBufferFree(DCNameBuffer);
|
|
ASSERT( Error == NO_ERROR );
|
|
|
|
return( Result );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* GetPrimaryDomain
|
|
*
|
|
* Purpose : Returns the primary domain name for authentication
|
|
*
|
|
* Returns : TRUE if primary domain exists and returned, otherwise FALSE
|
|
*
|
|
* The primary domain name should be freed using RtlFreeUnicodeString().
|
|
* The primary domain sid should be freed using Free()
|
|
*
|
|
* History:
|
|
* 02-13-92 Davidc Created.
|
|
\***************************************************************************/
|
|
BOOL
|
|
GetPrimaryDomain(
|
|
PUNICODE_STRING PrimaryDomainName,
|
|
PSID *PrimaryDomainSid OPTIONAL
|
|
)
|
|
{
|
|
NTSTATUS Status, IgnoreStatus;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
LSA_HANDLE LsaHandle;
|
|
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
|
|
PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo;
|
|
BOOL PrimaryDomainPresent = FALSE;
|
|
|
|
//
|
|
// Set up the Security Quality Of Service
|
|
//
|
|
|
|
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
|
SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
|
|
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|
SecurityQualityOfService.EffectiveOnly = FALSE;
|
|
|
|
//
|
|
// Set up the object attributes to open the Lsa policy object
|
|
//
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
NULL,
|
|
0L,
|
|
(HANDLE)NULL,
|
|
NULL);
|
|
ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
|
|
|
|
//
|
|
// Open the local LSA policy object
|
|
//
|
|
|
|
Status = LsaOpenPolicy( NULL,
|
|
&ObjectAttributes,
|
|
POLICY_VIEW_LOCAL_INFORMATION,
|
|
&LsaHandle
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DebugLog((DEB_ERROR, "Failed to open local LsaPolicyObject, Status = 0x%lx\n", Status));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Get the primary domain info
|
|
//
|
|
Status = LsaQueryInformationPolicy(LsaHandle,
|
|
PolicyPrimaryDomainInformation,
|
|
(PVOID *)&PrimaryDomainInfo);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DebugLog((DEB_ERROR, "Failed to query primary domain from Lsa, Status = 0x%lx\n", Status));
|
|
|
|
IgnoreStatus = LsaClose(LsaHandle);
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Copy the primary domain name into the return string
|
|
//
|
|
|
|
if (PrimaryDomainInfo->Sid != NULL) {
|
|
|
|
PrimaryDomainPresent = TRUE;
|
|
|
|
if (PrimaryDomainName)
|
|
{
|
|
|
|
if (DuplicateUnicodeString(PrimaryDomainName, &(PrimaryDomainInfo->Name))) {
|
|
|
|
if (PrimaryDomainSid != NULL) {
|
|
|
|
ULONG SidLength = RtlLengthSid(PrimaryDomainInfo->Sid);
|
|
|
|
*PrimaryDomainSid = Alloc(SidLength);
|
|
if (*PrimaryDomainSid != NULL) {
|
|
|
|
Status = RtlCopySid(SidLength, *PrimaryDomainSid, PrimaryDomainInfo->Sid);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
} else {
|
|
RtlFreeUnicodeString(PrimaryDomainName);
|
|
PrimaryDomainPresent = FALSE;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
PrimaryDomainPresent = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// We're finished with the Lsa
|
|
//
|
|
|
|
IgnoreStatus = LsaFreeMemory(PrimaryDomainInfo);
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
|
|
IgnoreStatus = LsaClose(LsaHandle);
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
|
|
|
|
return(PrimaryDomainPresent);
|
|
}
|