diff options
Diffstat (limited to 'private/windows/gina/msgina/lsa.c')
-rw-r--r-- | private/windows/gina/msgina/lsa.c | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/private/windows/gina/msgina/lsa.c b/private/windows/gina/msgina/lsa.c new file mode 100644 index 000000000..4edbcd896 --- /dev/null +++ b/private/windows/gina/msgina/lsa.c @@ -0,0 +1,445 @@ + +/**************************************************************************** + + 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); +} |