2020-09-30 17:12:29 +02:00

1611 lines
37 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
tconnect.c
Abstract:
This is the file for a simple connection test to SAM.
Author:
Jim Kelly (JimK) 4-July-1991
Environment:
User Mode - Win32
Revision History:
--*/
///////////////////////////////////////////////////////////////////////////////
// //
// Includes //
// //
///////////////////////////////////////////////////////////////////////////////
#include <samsrvp.h>
#include <msaudite.h>
///////////////////////////////////////////////////////////////////////////////
// //
// Global data structures //
// //
///////////////////////////////////////////////////////////////////////////////
ULONG AdministrativeRids[] = {
DOMAIN_ALIAS_RID_ADMINS,
DOMAIN_ALIAS_RID_SYSTEM_OPS,
DOMAIN_ALIAS_RID_PRINT_OPS,
DOMAIN_ALIAS_RID_BACKUP_OPS,
DOMAIN_ALIAS_RID_ACCOUNT_OPS
};
#define ADMINISTRATIVE_ALIAS_COUNT (sizeof(AdministrativeRids)/sizeof(ULONG))
#define RTLP_RXACT_KEY_NAME L"RXACT"
#define RTLP_RXACT_KEY_NAME_SIZE (sizeof(RTLP_RXACT_KEY_NAME) - sizeof(WCHAR))
#define SAMP_FIX_18471_KEY_NAME L"\\Registry\\Machine\\Security\\SAM\\Fix18471"
#define SAMP_FIX_18471_SHORT_KEY_NAME L"Fix18471"
#define SAMP_LSA_KEY_NAME L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa"
///////////////////////////////////////////////////////////////////////////////
// //
// Routines //
// //
///////////////////////////////////////////////////////////////////////////////
BOOLEAN
SampMatchDomainPrefix(
IN PSID AccountSid,
IN PSID DomainSid
)
/*++
Routine Description:
This function compares the domain sid to the domain prefix of an
account sid.
Arguments:
AccountSid - Specifies the account Sid to be compared. The Sid is assumed to be
syntactically valid.
DomainSid - Specifies the domain Sid to compare against.
Return Value:
TRUE - The account Sid is from the Domain specified by the domain Sid
FALSE - The domain prefix of the account Sid did not match the domain.
--*/
{
//
// Check if the account Sid has one more subauthority than the
// domain Sid.
//
if (*RtlSubAuthorityCountSid(DomainSid) + 1 !=
*RtlSubAuthorityCountSid(AccountSid)) {
return(FALSE);
}
if (memcmp(
RtlIdentifierAuthoritySid(DomainSid),
RtlIdentifierAuthoritySid(AccountSid),
sizeof(SID_IDENTIFIER_AUTHORITY) ) ) {
return(FALSE);
}
//
// Compare the sub authorities
//
if (memcmp(
RtlSubAuthoritySid(DomainSid, 0) ,
RtlSubAuthoritySid(AccountSid, 0) ,
*RtlSubAuthorityCountSid(DomainSid)
))
{
return(FALSE);
}
return(TRUE);
}
NTSTATUS
SampCreate18471Key(
)
/*++
Routine Description:
This routine creates the 18471 key used to transaction this fix.
Arguments:
Return Value:
Codes from the NT registry APIs
--*/
{
NTSTATUS Status;
UNICODE_STRING KeyName;
//
// Open the 18471 key in the registry to see if an upgrade is in
// progress
//
//
// Start a transaction with to create this key.
//
Status = SampAcquireWriteLock();
if (!NT_SUCCESS(Status)) {
return(Status);
}
SampSetTransactionDomain(0);
SampTransactionWithinDomain = FALSE;
//
// Create the fix18471 key in the registry
//
RtlInitUnicodeString(
&KeyName,
SAMP_FIX_18471_SHORT_KEY_NAME
);
Status = RtlAddActionToRXact(
SampRXactContext,
RtlRXactOperationSetValue,
&KeyName,
0, // no value type
NULL, // no value
0 // no value length
);
//
// Commit this change
//
if (NT_SUCCESS(Status)) {
Status = SampReleaseWriteLock( TRUE );
} else {
(void) SampReleaseWriteLock( FALSE );
}
return(Status);
}
NTSTATUS
SampAddAliasTo18471Key(
IN ULONG AliasRid
)
/*++
Routine Description:
This routine creates the 18471 key used to transaction this fix.
Arguments:
Return Value:
Codes from the NT registry APIs
--*/
{
NTSTATUS Status;
WCHAR KeyName[100];
WCHAR AliasName[15]; // big enough for 4 billion
UNICODE_STRING KeyNameString;
UNICODE_STRING AliasString;
//
// Build the key name. It will be "fix18471\rid_in_hex"
//
wcscpy(
KeyName,
SAMP_FIX_18471_SHORT_KEY_NAME L"\\"
);
AliasString.Buffer = AliasName;
AliasString.MaximumLength = sizeof(AliasName);
Status = RtlIntegerToUnicodeString(
AliasRid,
16,
&AliasString
);
ASSERT(NT_SUCCESS(Status));
wcscat(
KeyName,
AliasString.Buffer
);
RtlInitUnicodeString(
&KeyNameString,
KeyName
);
Status = SampAcquireWriteLock();
if (!NT_SUCCESS(Status)) {
return(Status);
}
SampSetTransactionDomain(0);
SampTransactionWithinDomain = FALSE;
//
// Open the Lsa key in the registry
//
Status = RtlAddActionToRXact(
SampRXactContext,
RtlRXactOperationSetValue,
&KeyNameString,
0, // no value type
NULL, // no value
0 // no value length
);
//
// Commit this change
//
if (NT_SUCCESS(Status)) {
Status = SampReleaseWriteLock( TRUE );
} else {
(void) SampReleaseWriteLock( FALSE );
}
return(Status);
}
NTSTATUS
SampAddMemberRidTo18471Key(
IN ULONG AliasRid,
IN ULONG MemberRid
)
/*++
Routine Description:
This routine adds a key for this member under the key for this alias
to the current registry transaction.
Arguments:
AliasRid - the rid of the alias
MemberRid - The rid of the member of the alias
Returns:
Errors from the RtlRXact APIs
--*/
{
NTSTATUS Status;
WCHAR KeyName[100];
WCHAR AliasName[15]; // big enough for 4 billion
UNICODE_STRING KeyNameString;
UNICODE_STRING AliasString;
//
// Build the full key name. It is of the form:
// "fix18471\alias_rid\member_rid"
//
wcscpy(
KeyName,
SAMP_FIX_18471_SHORT_KEY_NAME L"\\"
);
AliasString.Buffer = AliasName;
AliasString.MaximumLength = sizeof(AliasName);
Status = RtlIntegerToUnicodeString(
AliasRid,
16,
&AliasString
);
ASSERT(NT_SUCCESS(Status));
wcscat(
KeyName,
AliasString.Buffer
);
wcscat(
KeyName,
L"\\"
);
AliasString.MaximumLength = sizeof(AliasName);
Status = RtlIntegerToUnicodeString(
MemberRid,
16,
&AliasString
);
ASSERT(NT_SUCCESS(Status));
wcscat(
KeyName,
AliasString.Buffer
);
RtlInitUnicodeString(
&KeyNameString,
KeyName
);
//
// Add this action to the RXact
//
Status = RtlAddActionToRXact(
SampRXactContext,
RtlRXactOperationSetValue,
&KeyNameString,
0, // no value type
NULL, // no value
0 // no value length
);
return(Status);
}
NTSTATUS
SampCheckMemberUpgradedFor18471(
IN ULONG AliasRid,
IN ULONG MemberRid
)
/*++
Routine Description:
This routine checks if the SAM upgrade flag is set. The upgrade
flag is:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\control\lsa
UpgradeSam = REG_DWORD 1
Arguments:
Return Value:
TRUE - The flag was set
FALSE - The flag was not set or the value was not present
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE KeyHandle;
NTSTATUS Status;
WCHAR KeyName[100];
WCHAR AliasName[15]; // big enough for 4 billion
UNICODE_STRING KeyNameString;
UNICODE_STRING AliasString;
//
// Build the full key name. It is of the form:
// "fix18471\alias_rid\member_rid"
//
wcscpy(
KeyName,
SAMP_FIX_18471_KEY_NAME L"\\"
);
AliasString.Buffer = AliasName;
AliasString.MaximumLength = sizeof(AliasName);
Status = RtlIntegerToUnicodeString(
AliasRid,
16,
&AliasString
);
ASSERT(NT_SUCCESS(Status));
wcscat(
KeyName,
AliasString.Buffer
);
wcscat(
KeyName,
L"\\"
);
AliasString.MaximumLength = sizeof(AliasName);
Status = RtlIntegerToUnicodeString(
MemberRid,
16,
&AliasString
);
ASSERT(NT_SUCCESS(Status));
wcscat(
KeyName,
AliasString.Buffer
);
RtlInitUnicodeString(
&KeyNameString,
KeyName
);
//
// Open the member key in the registry
//
InitializeObjectAttributes(
&ObjectAttributes,
&KeyNameString,
OBJ_CASE_INSENSITIVE,
0,
NULL
);
SampDumpNtOpenKey((KEY_READ), &ObjectAttributes, 0);
Status = NtOpenKey(
&KeyHandle,
KEY_READ,
&ObjectAttributes
);
NtClose(KeyHandle);
return(Status);
}
VOID
SampBuild18471CleanupKey(
OUT PUNICODE_STRING KeyName,
IN PWCHAR AliasName,
IN ULONG AliasNameLength,
IN PWCHAR MemberName,
IN ULONG MemberNameLength
)
/*++
Routine Description:
Builds the key "Fix18471\alias_rid\member_rid"
Arguments:
Return Value:
None
--*/
{
PUCHAR Where = (PUCHAR) KeyName->Buffer;
RtlCopyMemory(
Where,
SAMP_FIX_18471_SHORT_KEY_NAME L"\\",
sizeof(SAMP_FIX_18471_SHORT_KEY_NAME) // terminating NULL used for '\'
);
Where += sizeof(SAMP_FIX_18471_SHORT_KEY_NAME);
RtlCopyMemory(
Where,
AliasName,
AliasNameLength
);
Where += AliasNameLength;
//
// If there is a member name to this alias, add it now.
//
if (MemberName != NULL) {
RtlCopyMemory(
Where,
L"\\",
sizeof(WCHAR)
);
Where += sizeof(WCHAR);
RtlCopyMemory(
Where,
MemberName,
MemberNameLength
);
Where += MemberNameLength;
}
KeyName->Length = (USHORT) (Where - (PUCHAR) KeyName->Buffer);
ASSERT(KeyName->Length <= KeyName->MaximumLength);
}
NTSTATUS
SampCleanup18471(
)
/*++
Routine Description:
Cleans up the transaction log left by fixing bug 18471. This routine
builds a transaction with all the keys in the log and then commits
the transaction
Arguments:
None.
Return Value:
Status codes from the NT registry APIs and NT RXact APIs
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
HANDLE RootKey = NULL;
HANDLE AliasKey = NULL;
UCHAR Buffer[sizeof(KEY_BASIC_INFORMATION) + 15 * sizeof(WCHAR)];
UCHAR Buffer2[sizeof(KEY_BASIC_INFORMATION) + 15 * sizeof(WCHAR)];
UNICODE_STRING KeyName;
WCHAR KeyBuffer[100];
PKEY_BASIC_INFORMATION BasicInfo = (PKEY_BASIC_INFORMATION) Buffer;
PKEY_BASIC_INFORMATION BasicInfo2 = (PKEY_BASIC_INFORMATION) Buffer2;
ULONG BasicInfoLength;
ULONG Index, Index2;
//
// Open the 18471 key in the registry
//
RtlInitUnicodeString(
&KeyName,
SAMP_FIX_18471_KEY_NAME
);
InitializeObjectAttributes(
&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
0,
NULL
);
SampDumpNtOpenKey((KEY_READ | DELETE), &ObjectAttributes, 0);
Status = NtOpenKey(
&RootKey,
KEY_READ | DELETE,
&ObjectAttributes
);
if (!NT_SUCCESS(Status)) {
//
// If the error was that the key did not exist, then there
// is nothing to cleanup, so return success.
//
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
return(STATUS_SUCCESS);
}
return(Status);
}
//
// Create a transaction to add all the keys to delete to
//
Status = SampAcquireWriteLock();
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
SampSetTransactionDomain(0);
SampTransactionWithinDomain = FALSE;
//
// Now enumerate all the subkeys of the root 18471 key
//
Index = 0;
do
{
Status = NtEnumerateKey(
RootKey,
Index,
KeyBasicInformation,
BasicInfo,
sizeof(Buffer),
&BasicInfoLength
);
SampDumpNtEnumerateKey(Index,
KeyBasicInformation,
BasicInfo,
sizeof(Buffer),
&BasicInfoLength);
//
//
// Check if this is the RXACT key. If it is, we don't want
// to add it to the delete log.
//
// Otherwise open this key and enumerate all the subkeys of it.
//
if (NT_SUCCESS(Status) &&
((BasicInfo->NameLength != RTLP_RXACT_KEY_NAME_SIZE) ||
memcmp(
BasicInfo->Name,
RTLP_RXACT_KEY_NAME,
RTLP_RXACT_KEY_NAME_SIZE
) ) ) {
KeyName.Buffer = BasicInfo->Name;
KeyName.Length = (USHORT) BasicInfo->NameLength;
KeyName.MaximumLength = KeyName.Length;
InitializeObjectAttributes(
&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
RootKey,
NULL
);
//
// Open the key for the alias rid. This really should
// succeed
//
SampDumpNtOpenKey((KEY_READ), &ObjectAttributes, 0);
Status = NtOpenKey(
&AliasKey,
KEY_READ,
&ObjectAttributes
);
if (!NT_SUCCESS(Status)) {
break;
}
//
// Enumerate all the subkeys (the alias members) and add them
// to the transaction
//
Index2 = 0;
do
{
Status = NtEnumerateKey(
AliasKey,
Index2,
KeyBasicInformation,
BasicInfo2,
sizeof(Buffer2),
&BasicInfoLength
);
SampDumpNtEnumerateKey(Index2,
KeyBasicInformation,
BasicInfo2,
sizeof(Buffer2),
&BasicInfoLength);
if (NT_SUCCESS(Status)) {
//
// Build the name of this key from the alias rid and the
// member rid
//
KeyName.Buffer = KeyBuffer;
KeyName.MaximumLength = sizeof(KeyBuffer);
SampBuild18471CleanupKey(
&KeyName,
BasicInfo->Name,
BasicInfo->NameLength,
BasicInfo2->Name,
BasicInfo2->NameLength
);
Status = RtlAddActionToRXact(
SampRXactContext,
RtlRXactOperationDelete,
&KeyName,
0,
NULL,
0
);
}
Index2++;
} while (NT_SUCCESS(Status));
NtClose(AliasKey);
AliasKey = NULL;
//
// If we suffered a serious error, get out of here now
//
if (!NT_SUCCESS(Status)) {
if (Status != STATUS_NO_MORE_ENTRIES) {
break;
} else {
Status = STATUS_SUCCESS;
}
}
//
// Add the alias RID key to the RXact now - we need to add it
// after deleting all the children
//
KeyName.Buffer = KeyBuffer;
KeyName.MaximumLength = sizeof(KeyBuffer);
SampBuild18471CleanupKey(
&KeyName,
BasicInfo->Name,
BasicInfo->NameLength,
NULL,
0
);
Status = RtlAddActionToRXact(
SampRXactContext,
RtlRXactOperationDelete,
&KeyName,
0,
NULL,
0
);
}
Index++;
} while (NT_SUCCESS(Status));
if (Status == STATUS_NO_MORE_ENTRIES) {
Status = STATUS_SUCCESS;
}
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
RtlInitUnicodeString(
&KeyName,
SAMP_FIX_18471_SHORT_KEY_NAME
);
Status = RtlAddActionToRXact(
SampRXactContext,
RtlRXactOperationDelete,
&KeyName,
0,
NULL,
0
);
if (NT_SUCCESS(Status)) {
//
// Write the new server revision to indicate that this
// upgrade has been performed
//
ULONG Revision = SAMP_SERVER_REVISION;
PSAMP_OBJECT ServerContext;
//
// We need to read the fixed attributes of the server objects.
// Create a context to do that.
//
ServerContext = SampCreateContext( SampServerObjectType, TRUE );
if ( ServerContext != NULL ) {
ServerContext->RootKey = SampKey;
Status = SampSetFixedAttributes(
ServerContext,
&Revision
);
if (NT_SUCCESS(Status)) {
Status = SampStoreObjectAttributes(
ServerContext,
TRUE
);
}
SampDeleteContext( ServerContext );
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
//
// Apply the RXACT and delete the remaining keys.
//
Cleanup:
//
// Cleanup any floating bits from above.
//
if (NT_SUCCESS(Status)) {
Status = SampReleaseWriteLock( TRUE );
} else {
(VOID) SampReleaseWriteLock( FALSE );
}
if (RootKey != NULL) {
NtClose(RootKey);
}
ASSERT(AliasKey == NULL);
return(Status);
}
NTSTATUS
SampFixBug18471 (
IN ULONG Revision
)
/*++
Routine Description:
This routine fixes bug 18471, that SAM does not adjust the protection
on groups that are members of administrative aliases in the builtin
domain. It fixes this by opening a fixed set of known aliases
(Administrators, Account Operators, Backup Operators, Print Operators,
and Server Operators), and enumerating their members. To fix this,
we will remove all the members of these aliases (except the
Administrator user account) and re-add them.
Arguments:
Revision - Revision of the Sam server.
Return Value:
Note:
--*/
{
NTSTATUS Status;
ULONG Index, Index2;
PSID BuiltinDomainSid = NULL;
SID_IDENTIFIER_AUTHORITY BuiltinAuthority = SECURITY_NT_AUTHORITY;
PSID AccountDomainSid;
ULONG AccountDomainIndex = 0xffffffff;
ULONG BuiltinDomainIndex = 0xffffffff;
SAMPR_PSID_ARRAY AliasMembership;
ULONG MemberRid;
ULONG SdRevision;
PSECURITY_DESCRIPTOR OldDescriptor;
PSECURITY_DESCRIPTOR SecurityDescriptor;
ULONG SecurityDescriptorLength;
SAMP_OBJECT_TYPE MemberType;
PSAMP_OBJECT MemberContext;
PSAMP_OBJECT AliasContext;
SAMP_V1_0A_FIXED_LENGTH_GROUP GroupV1Fixed;
SAMP_V1_0A_FIXED_LENGTH_USER UserV1Fixed;
//
// Check the revision on the server to see if this upgrade has
// already been performed.
//
if (Revision >= SAMP_SERVER_REVISION) {
//
// This upgrade has already been performed.
//
goto Cleanup;
}
//
// Build a the BuiltIn domain SID.
//
BuiltinDomainSid = RtlAllocateHeap(RtlProcessHeap(), 0,RtlLengthRequiredSid( 1 ));
if ( BuiltinDomainSid == NULL ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlInitializeSid( BuiltinDomainSid, &BuiltinAuthority, 1 );
*(RtlSubAuthoritySid( BuiltinDomainSid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID;
//
// Lookup the index of the account domain
//
for (Index = 0;
Index < SampDefinedDomainsCount ;
Index++ ) {
if (RtlEqualSid( BuiltinDomainSid, SampDefinedDomains[Index].Sid)) {
BuiltinDomainIndex = Index;
} else {
AccountDomainIndex = Index;
}
}
ASSERT(AccountDomainIndex < SampDefinedDomainsCount);
ASSERT(BuiltinDomainIndex < SampDefinedDomainsCount);
AccountDomainSid = SampDefinedDomains[AccountDomainIndex].Sid;
//
// Create out transaction log
//
Status = SampCreate18471Key();
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Now loop through and open the aliases we are intersted in
//
for (Index = 0;
Index < ADMINISTRATIVE_ALIAS_COUNT ;
Index++ )
{
SampSetTransactionDomain( BuiltinDomainIndex );
SampAcquireReadLock();
Status = SampCreateAccountContext(
SampAliasObjectType,
AdministrativeRids[Index],
TRUE, // Trusted client
TRUE, // Account exists
&AliasContext
);
if ( !NT_SUCCESS(Status) ) {
SampReleaseReadLock();
if (Status == STATUS_NO_SUCH_ALIAS) {
Status = STATUS_SUCCESS;
continue;
} else {
goto Cleanup;
}
}
//
// Get the members in the alias so we can remove and re-add them
//
Status = SampRetrieveAliasMembers(
AliasContext,
&(AliasMembership.Count),
(PSID **)&(AliasMembership.Sids)
);
SampDeleteContext(AliasContext);
SampReleaseReadLock();
if (!NT_SUCCESS(Status)) {
break;
}
//
// Write that we are opening this alias to the log. We don't need
// to do this for administrators, since for them we the update is
// idempotent.
//
if (AdministrativeRids[Index] != DOMAIN_ALIAS_RID_ADMINS) {
Status = SampAddAliasTo18471Key(
AdministrativeRids[Index]
);
if (!NT_SUCCESS(Status)) {
break;
}
}
//
// Loop through the members and split each sid. For every
// member in the account domain , remove it and re-add it from
// this alias.
//
for (Index2 = 0; Index2 < AliasMembership.Count ; Index2++ )
{
//
// Check to see if this account is in the account domain
//
if ( SampMatchDomainPrefix(
(PSID) AliasMembership.Sids[Index2].SidPointer,
AccountDomainSid
) )
{
//
// Get the RID for this member
//
MemberRid = *RtlSubAuthoritySid(
AliasMembership.Sids[Index2].SidPointer,
*RtlSubAuthorityCountSid(
AliasMembership.Sids[Index2].SidPointer
) - 1
);
//
// Now remove and re-add the administratie nature of this
// membership
//
if (AdministrativeRids[Index] == DOMAIN_ALIAS_RID_ADMINS) {
Status = SampAcquireWriteLock();
if (!NT_SUCCESS(Status)) {
break;
}
SampSetTransactionDomain( AccountDomainIndex );
//
// Try to create a context for the account as a group.
//
Status = SampCreateAccountContext(
SampGroupObjectType,
MemberRid,
TRUE, // Trusted client
TRUE, // Account exists
&MemberContext
);
if (!NT_SUCCESS( Status ) ) {
//
// If this ID does not exist as a group, that's fine -
// it might be a user or might have been deleted.
//
SampReleaseWriteLock( FALSE );
if (Status == STATUS_NO_SUCH_GROUP) {
Status = STATUS_SUCCESS;
continue;
}
break;
}
//
// Now set a flag in the group itself,
// so that when users are added and removed
// in the future it is known whether this
// group is in an ADMIN alias or not.
//
Status = SampRetrieveGroupV1Fixed(
MemberContext,
&GroupV1Fixed
);
if ( NT_SUCCESS(Status)) {
GroupV1Fixed.AdminCount = 1;
Status = SampReplaceGroupV1Fixed(
MemberContext,
&GroupV1Fixed
);
//
// Modify the security descriptor to
// prevent account operators from adding
// anybody to this group
//
if ( NT_SUCCESS( Status ) ) {
Status = SampGetAccessAttribute(
MemberContext,
SAMP_GROUP_SECURITY_DESCRIPTOR,
FALSE, // don't make copy
&SdRevision,
&OldDescriptor
);
if (NT_SUCCESS(Status)) {
Status = SampModifyAccountSecurity(
SampGroupObjectType,
TRUE, // this is an admin
OldDescriptor,
&SecurityDescriptor,
&SecurityDescriptorLength
);
}
if ( NT_SUCCESS( Status ) ) {
//
// Write the new security descriptor into the object
//
Status = SampSetAccessAttribute(
MemberContext,
SAMP_USER_SECURITY_DESCRIPTOR,
SecurityDescriptor,
SecurityDescriptorLength
);
MIDL_user_free( SecurityDescriptor );
}
}
if (NT_SUCCESS(Status)) {
//
// Add the modified group to the current transaction
// Don't use the open key handle since we'll be deleting the context.
//
Status = SampStoreObjectAttributes(MemberContext, FALSE);
}
}
//
// Clean up the group context
//
SampDeleteContext(MemberContext);
//
// we don't want the modified count to change
//
SampTransactionWithinDomain = FALSE;
if (NT_SUCCESS(Status)) {
Status = SampReleaseWriteLock( TRUE );
} else {
(VOID) SampReleaseWriteLock( FALSE );
}
}
else
{
//
// Check to see if we've already upgraded this member
//
Status = SampCheckMemberUpgradedFor18471(
AdministrativeRids[Index],
MemberRid);
if (NT_SUCCESS(Status)) {
//
// This member already was upgraded.
//
continue;
} else {
//
// We continue on with the upgrade
//
Status = STATUS_SUCCESS;
}
//
// Change the operator account for the other
// aliases.
//
if (NT_SUCCESS(Status)) {
Status = SampAcquireWriteLock();
if (!NT_SUCCESS(Status)) {
break;
}
SampSetTransactionDomain( AccountDomainIndex );
Status = SampChangeAccountOperatorAccessToMember(
AliasMembership.Sids[Index2].SidPointer,
NoChange,
AddToAdmin
);
//
// If that succeeded, add this member to the log
// as one that was upgraded.
//
if (NT_SUCCESS(Status)) {
Status = SampAddMemberRidTo18471Key(
AdministrativeRids[Index],
MemberRid
);
}
//
// We don't want the modified count to be updated so
// make this not a domain transaction
//
SampTransactionWithinDomain = FALSE;
if (NT_SUCCESS(Status)) {
Status = SampReleaseWriteLock( TRUE );
} else {
(VOID) SampReleaseWriteLock( FALSE );
}
}
if (!NT_SUCCESS(Status)) {
break;
}
}
}
}
SamIFree_SAMPR_PSID_ARRAY(
&AliasMembership
);
AliasMembership.Sids = NULL;
//
// If something up above failed or the upgrade was already done,
// exit now.
//
if (!NT_SUCCESS(Status)) {
break;
}
}
Cleanup:
if (BuiltinDomainSid != NULL) {
RtlFreeHeap(
RtlProcessHeap(),
0,
BuiltinDomainSid
);
}
if (NT_SUCCESS(Status)) {
Status = SampCleanup18471();
}
return(Status);
}
#if 0
BOOLEAN
SampUpgradeFlagSet(
)
/*++
Routine Description:
This routine checks if the SAM upgrade flag is set. The upgrade
flag is:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\control\lsa
UpgradeSam = REG_DWORD 1
Arguments:
Return Value:
TRUE - The flag was set
FALSE - The flag was not set or the value was not present
--*/
{
NTSTATUS NtStatus;
UNICODE_STRING KeyName;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE KeyHandle;
UCHAR Buffer[100];
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
ULONG KeyValueLength = 100;
ULONG ResultLength;
PULONG UpgradeFlag;
//
// Open the Lsa key in the registry
//
RtlInitUnicodeString(
&KeyName,
SAMP_LSA_KEY_NAME
);
InitializeObjectAttributes(
&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
0,
NULL
);
SampDumpNtOpenKey((KEY_READ), &ObjectAttributes, 0);
NtStatus = NtOpenKey(
&KeyHandle,
KEY_READ,
&ObjectAttributes
);
if (!NT_SUCCESS(NtStatus)) {
return(FALSE);
}
//
// Query the Notification Packages value
//
RtlInitUnicodeString(
&KeyName,
L"UpgradeSam"
);
NtStatus = NtQueryValueKey(
KeyHandle,
&KeyName,
KeyValuePartialInformation,
KeyValueInformation,
KeyValueLength,
&ResultLength
);
SampDumpNtQueryValueKey(&KeyName,
KeyValuePartialInformation,
KeyValueInformation,
KeyValueLength,
&ResultLength);
NtClose(KeyHandle);
if (!NT_SUCCESS(NtStatus)) {
return(FALSE);
}
//
// Check that the data is the correct size and type - a ULONG.
//
if ((KeyValueInformation->DataLength < sizeof(ULONG)) ||
(KeyValueInformation->Type != REG_DWORD)) {
return(FALSE);
}
//
// Check the flag.
//
UpgradeFlag = (PULONG) KeyValueInformation->Data;
if (*UpgradeFlag == 1) {
return(TRUE);
}
return(FALSE);
}
BOOLEAN
SampSetUpgradeFlag(
)
/*++
Routine Description:
This routine sets SAM upgrade flag is set. The upgrade
flag is:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\control\lsa
UpgradeSam = REG_DWORD 1
and the value will be deleted.
Arguments:
Return Value:
TRUE - The flag was set
FALSE - The flag was not set or the value was not present
--*/
{
NTSTATUS NtStatus;
UNICODE_STRING KeyName;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE KeyHandle;
UCHAR Buffer[100];
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
ULONG KeyValueLength = 100;
ULONG ResultLength;
PULONG UpgradeFlag;
//
// Open the Lsa key in the registry
//
RtlInitUnicodeString(
&KeyName,
SAMP_LSA_KEY_NAME
);
InitializeObjectAttributes(
&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
0,
NULL
);
SampDumpNtOpenKey((KEY_SET_VALUE), &ObjectAttributes, 0);
NtStatus = NtOpenKey(
&KeyHandle,
KEY_SET_VALUE,
&ObjectAttributes
);
if (!NT_SUCCESS(NtStatus)) {
return(FALSE);
}
//
// Query the Notification Packages value
//
RtlInitUnicodeString(
&KeyName,
L"UpgradeSam"
);
NtStatus = NtDeleteValueKey(
KeyHandle,
&KeyName
);
NtClose(KeyHandle);
}
#endif
NTSTATUS
SampUpgradeSamDatabase(
IN ULONG Revision
)
/*++
Routine Description:
Upgrades the SAM database.
Arguments:
Revision - The revision stored in the Server fixed length attributes
Return Value:
Note:
--*/
{
NTSTATUS Status;
Status = SampFixBug18471(Revision);
return(Status);
}