/*++ Copyright (c) 1997 Microsoft Corporation Module Name: setutl.c Abstract: Miscellaneous helper functions Author: Mac McLain (MacM) Feb 10, 1997 Environment: User Mode Revision History: --*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // For SetupPhase definition #include #include "secure.h" #include "lsa.h" DWORD DsRolepSetLsaInformationForReplica( IN HANDLE CallerToken, IN LPWSTR ReplicaPartner, IN LPWSTR Account, IN LPWSTR Password ) /*++ Routine Description: This function will set the local Lsa database information to that of the replica partner Arguments: ReplicaPartner -- Replica partner to get the information from Returns: ERROR_SUCCESS - Success --*/ { DWORD Win32Err = ERROR_SUCCESS; NTSTATUS Status; UNICODE_STRING PartnerServer; HANDLE LocalPolicy = NULL , PartnerPolicy = NULL; OBJECT_ATTRIBUTES ObjectAttributes; PBYTE Buffer; ULONG i; BOOLEAN UseAdded = FALSE; PWSTR FullServerPath = NULL; POLICY_INFORMATION_CLASS InfoClasses[ ] = { PolicyDnsDomainInformation }; if ( !ReplicaPartner ) { return( ERROR_INVALID_PARAMETER ); } DSROLEP_CURRENT_OP1( DSROLEEVT_SET_LSA_FROM, ReplicaPartner ); // // Open both lsas // RtlInitUnicodeString( &PartnerServer, ReplicaPartner ); RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) ); Status = ImpLsaOpenPolicy( CallerToken, &PartnerServer, &ObjectAttributes, MAXIMUM_ALLOWED, &PartnerPolicy ); if ( Status == STATUS_ACCESS_DENIED ) { WCHAR *BufPartnerServer = NULL; BufPartnerServer = (WCHAR*)malloc(PartnerServer.Length+sizeof(WCHAR)); if (BufPartnerServer) { CopyMemory(BufPartnerServer,PartnerServer.Buffer,PartnerServer.Length); BufPartnerServer[PartnerServer.Length/sizeof(WCHAR)] = L'\0'; DsRolepLogPrint(( DEB_TRACE, "LsaOpenPolicy on %ws failed with 0x%lx. Establishing use.\n", BufPartnerServer, Status )); free(BufPartnerServer); } // // Try establishing a session first... // if ( *ReplicaPartner != L'\\' ) { FullServerPath = RtlAllocateHeap( RtlProcessHeap(), 0, ( wcslen( ReplicaPartner ) + 3 ) * sizeof( WCHAR ) ); if ( FullServerPath == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { swprintf( FullServerPath, L"\\\\%ws", ReplicaPartner ); Status = STATUS_SUCCESS; } } else { FullServerPath = ReplicaPartner; Status = STATUS_SUCCESS; } if ( NT_SUCCESS( Status ) ) { Win32Err = ImpNetpManageIPCConnect( CallerToken, FullServerPath, Account, Password, NETSETUPP_CONNECT_IPC ); if ( Win32Err == ERROR_SUCCESS ) { UseAdded = TRUE; Status = ImpLsaOpenPolicy( CallerToken, &PartnerServer, &ObjectAttributes, MAXIMUM_ALLOWED, &PartnerPolicy ); } else { DsRolepLogPrint(( DEB_TRACE, "NetUseAdd to %ws failed with %lu\n", FullServerPath, Win32Err )); // // Temp status code so we know a failure occurred. // Status = STATUS_UNSUCCESSFUL; } } } else if ( !NT_SUCCESS( Status ) ) { WCHAR *BufPartnerServer = NULL; BufPartnerServer = (WCHAR*)malloc(PartnerServer.Length+sizeof(WCHAR)); if (BufPartnerServer) { CopyMemory(BufPartnerServer,PartnerServer.Buffer,PartnerServer.Length); BufPartnerServer[PartnerServer.Length/sizeof(WCHAR)] = L'\0'; DsRolepLogPrint(( DEB_TRACE, "LsaOpenPolicy on %ws failed with 0x%lx.\n", BufPartnerServer, Status )); free(BufPartnerServer); } } if ( NT_SUCCESS( Status ) ) { RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) ); Status = LsaOpenPolicy( NULL, &ObjectAttributes, MAXIMUM_ALLOWED, &LocalPolicy ); if ( !NT_SUCCESS( Status ) ) { DsRolepLogPrint(( DEB_TRACE, "Local LsaOpenPoolicy returned 0x%lx\n", Status )); } } for ( i = 0; i < sizeof( InfoClasses ) / sizeof( POLICY_INFORMATION_CLASS ) && NT_SUCCESS( Status ); i++ ) { Status = ImpLsaQueryInformationPolicy( CallerToken, PartnerPolicy, InfoClasses[ i ], &Buffer ); if ( NT_SUCCESS( Status ) ) { Status = LsaSetInformationPolicy( LocalPolicy, InfoClasses[ i ], Buffer ); LsaFreeMemory( Buffer ); } DsRolepLogPrint(( DEB_TRACE, "Setting Lsa policy %lu returned 0x%lx\n", InfoClasses[ i ], Status )); } // // Now, the same for the Efs policy // if ( NT_SUCCESS( Status ) ) { Status = ImpLsaQueryDomainInformationPolicy( CallerToken, PartnerPolicy, PolicyDomainEfsInformation, &Buffer ); if ( NT_SUCCESS( Status ) ) { Status = LsaSetDomainInformationPolicy( LocalPolicy, PolicyDomainEfsInformation, Buffer ); DsRolepLogPrint(( DEB_TRACE, "Setting Efs policy from %ws returned 0x%lx\n", ReplicaPartner, Status )); LsaFreeMemory( Buffer ); } else { DsRolepLogPrint(( DEB_TRACE, "Reading Efs policy from %ws returned 0x%lx\n", ReplicaPartner, Status )); if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) { Status = STATUS_SUCCESS; } } } if ( LocalPolicy ) { LsaClose( LocalPolicy ); } if ( PartnerPolicy ) { ImpLsaClose( CallerToken, PartnerPolicy ); } if ( UseAdded ) { Win32Err = ImpNetpManageIPCConnect( CallerToken, FullServerPath, Account, Password, (NETSETUPP_DISCONNECT_IPC|NETSETUPP_USE_LOTS_FORCE) ); } if ( FullServerPath && FullServerPath != ReplicaPartner ) { RtlFreeHeap( RtlProcessHeap(), 0, FullServerPath ); } // // We won't bother cleaning up any of the information we set on the local machine in // the failure case, since it won't hurt anything to have it here. // if ( Win32Err == ERROR_SUCCESS ) { Win32Err = RtlNtStatusToDosError( Status ); } DsRoleDebugOut(( DEB_TRACE_DS, "DsRolepSetLsaInformationForReplica %lu\n", Win32Err )); DsRolepLogOnFailure( Win32Err, DsRolepLogPrint(( DEB_TRACE, "DsRolepSetLsaInformationForReplica failed with %lu\n", Win32Err )) ); return( Win32Err ); } DWORD DsRolepSetLsaDomainPolicyInfo( IN LPWSTR DnsDomainName, IN LPWSTR FlatDomainName, IN LPWSTR EnterpriseDnsName, IN GUID *DomainGuid, IN PSID DomainSid, DWORD InstallOptions, OUT PDSROLEP_DOMAIN_POLICY_INFO BackupDomainInfo ) /*++ Routine Description: This routine sets the PolicyAccountDomainInformation and PolicyDnsDomainInformation in the lsa to reflect the recent role changes. Arguments: DnsDomainName - The Dns domain name of the newly installed Domain/Dc FlatDomainName - The NetBIOS domain name of the newly installed Domain/Dc EnterpriseDnsName - The Dns domain name of the root of the enterprise DomainGuid - The new domain guid DomainSid - The new domain sid InstallOptions : this describes the kind of install (new domain, enterprise, or replica) DomainGuid - The guid of the new domain is returned here Returns: ERROR_SUCCESS - Success; win error otherwise --*/ { NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; POLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo; POLICY_LSA_SERVER_ROLE_INFO ServerRoleInfo; POLICY_DNS_DOMAIN_INFO DnsDomainInfo; LSA_HANDLE PolicyHandle = NULL; // // If we are setting up the replica, we don't have things like the flat domain name and // the domain sid, so we'll use the information we have backed up. // if ( FlatDomainName == NULL || DomainSid == NULL ) { RtlCopyMemory( &AccountDomainInfo.DomainName, &BackupDomainInfo->DnsDomainInfo->Name, sizeof( UNICODE_STRING ) ); AccountDomainInfo.DomainSid = BackupDomainInfo->DnsDomainInfo->Sid ; } else { RtlInitUnicodeString( &AccountDomainInfo.DomainName, FlatDomainName); AccountDomainInfo.DomainSid = DomainSid; } // // Open the Lsa // RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) ); Status = LsaOpenPolicy( NULL, &ObjectAttributes, POLICY_WRITE, &PolicyHandle ); // // Set the AccountDomain information first // if ( NT_SUCCESS( Status ) ) { // // Set the values in the Account Domain Policy structure. // WCHAR *BufDomainName = NULL; DsRolepLogPrint(( DEB_TRACE, "Setting AccountDomainInfo to:\n" )); BufDomainName = (WCHAR*)malloc(AccountDomainInfo.DomainName.Length+sizeof(WCHAR)); if (BufDomainName) { CopyMemory(BufDomainName,AccountDomainInfo.DomainName.Buffer,AccountDomainInfo.DomainName.Length); BufDomainName[AccountDomainInfo.DomainName.Length/sizeof(WCHAR)] = L'\0'; DsRolepLogPrint(( DEB_TRACE, "\tDomain: %ws\n", BufDomainName, Status )); free(BufDomainName); } DsRolepLogSid( DEB_TRACE, "\tSid: ", AccountDomainInfo.DomainSid ); Status = LsaSetInformationPolicy( PolicyHandle, PolicyAccountDomainInformation, ( PVOID )&AccountDomainInfo ); DsRolepLogOnFailure( RtlNtStatusToDosError( Status ), DsRolepLogPrint(( DEB_TRACE, "Setting AccountDomainInformation failed with 0x%lx\n", RtlNtStatusToDosError( Status ) )) ); } // // Set the Dns domain information // if ( NT_SUCCESS( Status ) && !FLAG_ON( InstallOptions, NTDS_INSTALL_REPLICA ) ) { RtlInitUnicodeString( &DnsDomainInfo.Name, FlatDomainName ); RtlInitUnicodeString( &DnsDomainInfo.DnsDomainName, DnsDomainName ); RtlInitUnicodeString( &DnsDomainInfo.DnsForestName, EnterpriseDnsName ); RtlCopyMemory( &DnsDomainInfo.DomainGuid, DomainGuid, sizeof( GUID ) ); DnsDomainInfo.Sid = DomainSid; Status = LsaSetInformationPolicy( PolicyHandle, PolicyDnsDomainInformation, ( PVOID )&DnsDomainInfo ); DsRolepLogOnFailure( RtlNtStatusToDosError( Status ), DsRolepLogPrint(( DEB_TRACE, "Setting DnsDomainInformation failed with 0x%lx\n", RtlNtStatusToDosError( Status ) )) ); } // // If it isn't a replica, wipe the efs policy // if ( NT_SUCCESS( Status ) && !FLAG_ON( InstallOptions, NTDS_INSTALL_REPLICA ) ) { Status = LsaSetDomainInformationPolicy( PolicyHandle, PolicyDomainEfsInformation, NULL ); if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) { Status = STATUS_SUCCESS; } DsRolepLogOnFailure( RtlNtStatusToDosError( Status ), DsRolepLogPrint(( DEB_TRACE, "Erasing EfsPolicy failed with 0x%lx\n", Status )) ); } // // Now, cleanup and exit // if ( PolicyHandle ) { LsaClose( PolicyHandle ); } return( RtlNtStatusToDosError( Status ) ); } DWORD DsRolepBackupDomainPolicyInfo( IN PLSA_HANDLE LsaHandle, OPTIONAL OUT PDSROLEP_DOMAIN_POLICY_INFO DomainInfo ) /*++ Routine Description This routine reads and saves in a global the state of the account domain policy and primary domain policy so if an error occurs then the original state can be preserved. Parameters DomainInfo : pointer, to be filled in by this routine Return Values ERROR_SUCCESS if no errors; a winerror otherwise --*/ { NTSTATUS Status = STATUS_SUCCESS; LSA_HANDLE PolicyHandle = NULL; OBJECT_ATTRIBUTES ObjectAttributes; ASSERT(DomainInfo); if ( DomainInfo->PolicyBackedUp ) { return( STATUS_SUCCESS ); } if ( LsaHandle == NULL ) { RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) ); Status = LsaOpenPolicy( NULL, &ObjectAttributes, POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle ); } else { PolicyHandle = LsaHandle; } if ( NT_SUCCESS( Status ) ) { Status = LsaQueryInformationPolicy( PolicyHandle, PolicyDnsDomainInformation, ( PVOID * )&DomainInfo->DnsDomainInfo); } if ( NT_SUCCESS( Status ) ) { Status = LsaQueryInformationPolicy( PolicyHandle, PolicyAccountDomainInformation, ( PVOID * )&DomainInfo->AccountDomainInfo); } if ( NT_SUCCESS( Status ) ) { Status = LsaQueryInformationPolicy( PolicyHandle, PolicyLsaServerRoleInformation, ( PVOID * )&DomainInfo->ServerRoleInfo); } if ( NT_SUCCESS( Status ) ) { Status = LsaQueryDomainInformationPolicy( PolicyHandle, PolicyDomainEfsInformation, ( PVOID * )&DomainInfo->EfsPolicy ); if ( NT_SUCCESS( Status ) ) { DomainInfo->EfsPolicyPresent = TRUE; } else { // // It's ok for the Efs policy not to have existed // if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) { DomainInfo->EfsPolicyPresent = TRUE; Status = STATUS_SUCCESS; } else { DomainInfo->EfsPolicyPresent = FALSE; } } } if ( PolicyHandle && PolicyHandle != LsaHandle ) { LsaClose( PolicyHandle ); } if ( NT_SUCCESS( Status ) ) { DomainInfo->PolicyBackedUp = TRUE; } return( RtlNtStatusToDosError( Status ) ); } DWORD DsRolepRestoreDomainPolicyInfo( IN PDSROLEP_DOMAIN_POLICY_INFO DomainInfo ) /*++ Routine Description This routine sets the account and primary domain information to be the values that were stored of by DsRolepBackupDomainPolicyInformation. Parameters DomainInfo : pointer, expected to be filled Return Values ERROR_SUCCESS if no errors; a winerror otherwise ERROR_INVALID_DATA - The data was never successfully backed up --*/ { NTSTATUS Status, Status2; HANDLE PolicyHandle; OBJECT_ATTRIBUTES ObjectAttributes; ASSERT(DomainInfo); if ( !DomainInfo->PolicyBackedUp ) { return( ERROR_INVALID_DATA ); } RtlZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) ); Status = LsaOpenPolicy( NULL, &ObjectAttributes, POLICY_WRITE, &PolicyHandle ); if ( NT_SUCCESS( Status ) ) { Status = LsaSetInformationPolicy( PolicyHandle, PolicyDnsDomainInformation, ( PVOID )DomainInfo->DnsDomainInfo ); Status2 = LsaSetInformationPolicy( PolicyHandle, PolicyAccountDomainInformation, ( PVOID )DomainInfo->AccountDomainInfo ); if ( NT_SUCCESS( Status ) && !NT_SUCCESS( Status2 ) ) { Status = Status2; } // // Restore the Efs policy, if it exists // if ( NT_SUCCESS( Status ) && DomainInfo->EfsPolicyPresent ) { Status = LsaSetDomainInformationPolicy( PolicyHandle, PolicyDomainEfsInformation, ( PVOID )DomainInfo->EfsPolicy ); } Status2 = LsaClose( PolicyHandle ); if ( NT_SUCCESS( Status ) ) { Status = Status2; } } DsRolepLogOnFailure( Status, DsRolepLogPrint(( DEB_TRACE, "RestoreDomainPolicyInfo failed with 0x%lx\n", Status )) ); return( RtlNtStatusToDosError( Status ) ); } DWORD DsRolepFreeDomainPolicyInfo( IN PDSROLEP_DOMAIN_POLICY_INFO DomainInfo ) /*++ Routine Description This routine free the structures that were allocated during DsRolepBackupDomainPolicyInformation. Parameters DomainInfo : pointer, expected to be filled so the fields can be freed Return Values ERROR_SUCCESS if no errors; a winerror otherwise --*/ { if ( DomainInfo->AccountDomainInfo ) { LsaFreeMemory( DomainInfo->AccountDomainInfo ); } if ( DomainInfo->DnsDomainInfo ) { LsaFreeMemory( DomainInfo->DnsDomainInfo ); } if ( DomainInfo->ServerRoleInfo ) { LsaFreeMemory( DomainInfo->ServerRoleInfo ); } if ( DomainInfo->EfsPolicyPresent ) { LsaFreeMemory( DomainInfo->EfsPolicy ); } return ERROR_SUCCESS; } DWORD DsRolepUpgradeLsaToDs( BOOLEAN InitializeLsa ) /*++ Routine Description: Prompts Lsa to upgrade all the information it stores in the registry into the Ds Arguments: None Returns: ERROR_SUCCESS - Success ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed --*/ { NTSTATUS Status = STATUS_SUCCESS; DWORD WinError = ERROR_SUCCESS; if ( InitializeLsa ) { // // Make the Lsa think that we're initialized // DSROLEP_CURRENT_OP0( DSROLEEVT_SET_LSA ); // // Make the Lsa think that we're initialized // Status = LsapDsInitializeDsStateInfo( LsapDsDsSetup ); if ( !NT_SUCCESS( Status ) ) { DsRolepLogPrint(( DEB_TRACE, "Failed to convince Lsa to reinitialize: 0x%lx\n", Status )); } else { Status = LsaIUpgradeRegistryToDs( FALSE ); } } return( WinError == ERROR_SUCCESS ? RtlNtStatusToDosError( Status ) : WinError ); } VOID DsRolepFindSelfAndParentInForest( IN PLSAPR_FOREST_TRUST_INFO ForestTrustInfo, OUT PLSAPR_TREE_TRUST_INFO CurrentEntry, IN PUNICODE_STRING LocalDomain, OUT PLSAPR_TREE_TRUST_INFO *ParentEntry, OUT PLSAPR_TREE_TRUST_INFO *OwnEntry ) { DWORD WinError = ERROR_SUCCESS; ULONG i; BOOLEAN ParentKnown = FALSE; if ( *ParentEntry && *OwnEntry ) { return; } if ( ForestTrustInfo->ParentDomainReference ) { CurrentEntry = ForestTrustInfo->ParentDomainReference; ParentKnown = TRUE; } for ( i = 0; i < CurrentEntry->Children && *OwnEntry == NULL; i++ ) { if ( RtlCompareUnicodeString( ( PUNICODE_STRING )&CurrentEntry->ChildDomains[ i ].DnsDomainName, LocalDomain, TRUE ) == 0 ) { *OwnEntry = &CurrentEntry->ChildDomains[ i ]; *ParentEntry = CurrentEntry; break; } if ( !ParentKnown ) { DsRolepFindSelfAndParentInForest( ForestTrustInfo, &CurrentEntry->ChildDomains[ i ], LocalDomain, ParentEntry, OwnEntry ); } } return; }