3976 lines
104 KiB
C
3976 lines
104 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
alias.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This file contains services related to the SAM "alias" object.
|
|||
|
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Chad Schwitters (chads) 15-Jan-1992
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
User Mode - Win32
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Includes //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#include <samsrvp.h>
|
|||
|
#include <msaudite.h>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// private service prototypes //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampAddAccountToAlias(
|
|||
|
IN PSAMP_OBJECT AccountContext,
|
|||
|
IN PSID AccountSid
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampRemoveAccountFromAlias(
|
|||
|
IN PSAMP_OBJECT AccountContext,
|
|||
|
IN PSID AccountSid
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampAddAliasToAccountMembership(
|
|||
|
IN ULONG AliasRid,
|
|||
|
IN PSID AccountSid
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampRemoveAliasFromAccountMembership(
|
|||
|
IN ULONG AliasRid,
|
|||
|
IN PSID AccountSid
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampRemoveAliasFromAllAccounts(
|
|||
|
IN PSAMP_OBJECT AliasContext
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampDeleteAliasKeys(
|
|||
|
IN PSAMP_OBJECT Context
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampRetrieveAliasMembers(
|
|||
|
IN PSAMP_OBJECT AliasContext,
|
|||
|
IN PULONG MemberCount,
|
|||
|
IN PSID **Members OPTIONAL
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampDeleteAliasMembershipKeysForAccount(
|
|||
|
IN PSID AccountSid
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampAdjustAliasDomainsCount(
|
|||
|
IN BOOLEAN Increment
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampValidateNewAliasMember(
|
|||
|
IN PSID MemberId
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampChangeAliasAccountName(
|
|||
|
IN PSAMP_OBJECT Context,
|
|||
|
IN PUNICODE_STRING NewAccountName,
|
|||
|
OUT PUNICODE_STRING OldAccountName
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Exposed RPC'able Services //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrOpenAlias(
|
|||
|
IN SAM_HANDLE DomainHandle,
|
|||
|
IN ACCESS_MASK DesiredAccess,
|
|||
|
IN ULONG AliasId,
|
|||
|
OUT PSAM_HANDLE AliasHandle
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This API opens an existing Alias object. The Alias is specified by
|
|||
|
a ID value that is relative to the SID of the domain. The operations
|
|||
|
that will be performed on the Alias must be declared at this time.
|
|||
|
|
|||
|
This call returns a handle to the newly opened Alias that may be used
|
|||
|
for successive operations on the Alias. This handle may be closed
|
|||
|
with the SamCloseHandle API.
|
|||
|
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
DomainHandle - A domain handle returned from a previous call to
|
|||
|
SamOpenDomain.
|
|||
|
|
|||
|
DesiredAccess - Is an access mask indicating which access types are
|
|||
|
desired to the alias.
|
|||
|
|
|||
|
AliasId - Specifies the relative ID value of the Alias to be opened.
|
|||
|
|
|||
|
AliasHandle - Receives a handle referencing the newly opened Alias.
|
|||
|
This handle will be required in successive calls to operate on
|
|||
|
the Alias.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
STATUS_SUCCESS - The Alias was successfully opened.
|
|||
|
|
|||
|
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
|||
|
to complete the operation.
|
|||
|
|
|||
|
STATUS_NO_SUCH_ALIAS - The specified Alias does not exist.
|
|||
|
|
|||
|
STATUS_INVALID_HANDLE - The domain handle passed is invalid.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
|
|||
|
NtStatus = SampOpenAccount(
|
|||
|
SampAliasObjectType,
|
|||
|
DomainHandle,
|
|||
|
DesiredAccess,
|
|||
|
AliasId,
|
|||
|
FALSE,
|
|||
|
AliasHandle
|
|||
|
);
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrQueryInformationAlias(
|
|||
|
IN SAMPR_HANDLE AliasHandle,
|
|||
|
IN ALIAS_INFORMATION_CLASS AliasInformationClass,
|
|||
|
OUT PSAMPR_ALIAS_INFO_BUFFER *Buffer
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This API retrieves information on the alias specified.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
AliasHandle - The handle of an opened alias to operate on.
|
|||
|
|
|||
|
AliasInformationClass - Class of information to retrieve. The
|
|||
|
accesses required for each class is shown below:
|
|||
|
|
|||
|
Info Level Required Access Type
|
|||
|
----------------------- ----------------------
|
|||
|
|
|||
|
AliasGeneralInformation ALIAS_READ_INFORMATION
|
|||
|
AliasNameInformation ALIAS_READ_INFORMATION
|
|||
|
AliasAdminInformation ALIAS_READ_INFORMATION
|
|||
|
|
|||
|
Buffer - Receives a pointer to a buffer containing the requested
|
|||
|
information. When this information is no longer needed, this
|
|||
|
buffer and any memory pointed to through this buffer must be
|
|||
|
freed using SamFreeMemory().
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
STATUS_SUCCESS - The Service completed successfully.
|
|||
|
|
|||
|
STATUS_ACCESS_DENIED - Caller does not have the appropriate
|
|||
|
access to complete the operation.
|
|||
|
|
|||
|
STATUS_INVALID_HANDLE - The handle passed is invalid.
|
|||
|
|
|||
|
STATUS_INVALID_INFO_CLASS - The class provided was invalid.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus;
|
|||
|
NTSTATUS IgnoreStatus;
|
|||
|
PSAMP_OBJECT AccountContext;
|
|||
|
SAMP_OBJECT_TYPE FoundType;
|
|||
|
ACCESS_MASK DesiredAccess;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
//
|
|||
|
// Used for tracking allocated blocks of memory - so we can deallocate
|
|||
|
// them in case of error. Don't exceed this number of allocated buffers.
|
|||
|
// ||
|
|||
|
// vv
|
|||
|
PVOID AllocatedBuffer[10];
|
|||
|
ULONG AllocatedBufferCount = 0;
|
|||
|
|
|||
|
#define RegisterBuffer(Buffer) \
|
|||
|
{ \
|
|||
|
if ((Buffer) != NULL) { \
|
|||
|
\
|
|||
|
ASSERT(AllocatedBufferCount < \
|
|||
|
sizeof(AllocatedBuffer) / sizeof(*AllocatedBuffer)); \
|
|||
|
\
|
|||
|
AllocatedBuffer[AllocatedBufferCount++] = (Buffer); \
|
|||
|
} \
|
|||
|
}
|
|||
|
|
|||
|
#define AllocateBuffer(NewBuffer, Size) \
|
|||
|
{ \
|
|||
|
(NewBuffer) = MIDL_user_allocate(Size); \
|
|||
|
RegisterBuffer(NewBuffer); \
|
|||
|
} \
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Make sure we understand what RPC is doing for (to) us.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (Buffer != NULL);
|
|||
|
ASSERT ((*Buffer) == NULL);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set the desired access based upon the Info class
|
|||
|
//
|
|||
|
|
|||
|
switch (AliasInformationClass) {
|
|||
|
|
|||
|
case AliasGeneralInformation:
|
|||
|
case AliasNameInformation:
|
|||
|
case AliasAdminCommentInformation:
|
|||
|
|
|||
|
DesiredAccess = ALIAS_READ_INFORMATION;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
(*Buffer) = NULL;
|
|||
|
return(STATUS_INVALID_INFO_CLASS);
|
|||
|
} // end_switch
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Allocate the info structure
|
|||
|
//
|
|||
|
|
|||
|
AllocateBuffer( *Buffer, sizeof(SAMPR_ALIAS_INFO_BUFFER) );
|
|||
|
if ((*Buffer) == NULL) {
|
|||
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
SampAcquireReadLock();
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Validate type of, and access to object.
|
|||
|
//
|
|||
|
|
|||
|
AccountContext = (PSAMP_OBJECT)AliasHandle;
|
|||
|
NtStatus = SampLookupContext(
|
|||
|
AccountContext,
|
|||
|
DesiredAccess,
|
|||
|
SampAliasObjectType, // ExpectedType
|
|||
|
&FoundType
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// case on the type information requested
|
|||
|
//
|
|||
|
|
|||
|
switch (AliasInformationClass) {
|
|||
|
|
|||
|
case AliasGeneralInformation:
|
|||
|
|
|||
|
//
|
|||
|
// Get the member count
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampRetrieveAliasMembers(
|
|||
|
AccountContext,
|
|||
|
&(*Buffer)->General.MemberCount,
|
|||
|
NULL // Only need members
|
|||
|
);
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Get copies of the strings we must retrieve from
|
|||
|
// the registry.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampGetUnicodeStringAttribute(
|
|||
|
AccountContext,
|
|||
|
SAMP_ALIAS_NAME,
|
|||
|
TRUE, // Make copy
|
|||
|
(PUNICODE_STRING)&((*Buffer)->General.Name)
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
RegisterBuffer((*Buffer)->General.Name.Buffer);
|
|||
|
|
|||
|
NtStatus = SampGetUnicodeStringAttribute(
|
|||
|
AccountContext,
|
|||
|
SAMP_ALIAS_ADMIN_COMMENT,
|
|||
|
TRUE, // Make copy
|
|||
|
(PUNICODE_STRING)&((*Buffer)->General.AdminComment)
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
RegisterBuffer((*Buffer)->General.AdminComment.Buffer);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case AliasNameInformation:
|
|||
|
|
|||
|
//
|
|||
|
// Get copies of the strings we must retrieve from
|
|||
|
// the registry.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampGetUnicodeStringAttribute(
|
|||
|
AccountContext,
|
|||
|
SAMP_ALIAS_NAME,
|
|||
|
TRUE, // Make copy
|
|||
|
(PUNICODE_STRING)&((*Buffer)->Name.Name)
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
RegisterBuffer((*Buffer)->Name.Name.Buffer);
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case AliasAdminCommentInformation:
|
|||
|
|
|||
|
//
|
|||
|
// Get copies of the strings we must retrieve from
|
|||
|
// the registry.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampGetUnicodeStringAttribute(
|
|||
|
AccountContext,
|
|||
|
SAMP_ALIAS_ADMIN_COMMENT,
|
|||
|
TRUE, // Make copy
|
|||
|
(PUNICODE_STRING)&((*Buffer)->AdminComment.AdminComment)
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
RegisterBuffer((*Buffer)->AdminComment.AdminComment.Buffer);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
} // end_switch
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// De-reference the object, discard any changes
|
|||
|
//
|
|||
|
|
|||
|
IgnoreStatus = SampDeReferenceContext( AccountContext, FALSE );
|
|||
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the read lock
|
|||
|
//
|
|||
|
|
|||
|
SampReleaseReadLock();
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If we didn't succeed, free any allocated memory
|
|||
|
//
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
for ( i=0; i<AllocatedBufferCount ; i++ ) {
|
|||
|
MIDL_user_free( AllocatedBuffer[i] );
|
|||
|
}
|
|||
|
|
|||
|
(*Buffer) = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrSetInformationAlias(
|
|||
|
IN SAMPR_HANDLE AliasHandle,
|
|||
|
IN ALIAS_INFORMATION_CLASS AliasInformationClass,
|
|||
|
IN PSAMPR_ALIAS_INFO_BUFFER Buffer
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This API allows the caller to modify alias information.
|
|||
|
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
AliasHandle - The handle of an opened alias to operate on.
|
|||
|
|
|||
|
AliasInformationClass - Class of information to retrieve. The
|
|||
|
accesses required for each class is shown below:
|
|||
|
|
|||
|
Info Level Required Access Type
|
|||
|
------------------------ -------------------------
|
|||
|
|
|||
|
AliasGeneralInformation (can't write)
|
|||
|
|
|||
|
AliasNameInformation ALIAS_WRITE_ACCOUNT
|
|||
|
AliasAdminCommentInformation ALIAS_WRITE_ACCOUNT
|
|||
|
|
|||
|
Buffer - Buffer where information retrieved is placed.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
STATUS_SUCCESS - The Service completed successfully.
|
|||
|
|
|||
|
STATUS_ACCESS_DENIED - Caller does not have the appropriate
|
|||
|
access to complete the operation.
|
|||
|
|
|||
|
STATUS_INVALID_INFO_CLASS - The class provided was invalid.
|
|||
|
|
|||
|
STATUS_INVALID_HANDLE - The handle passed is invalid.
|
|||
|
|
|||
|
STATUS_NO_SUCH_ALIAS - The alias specified is unknown.
|
|||
|
|
|||
|
STATUS_SPECIAL_ALIAS - The alias specified is a special alias and
|
|||
|
cannot be operated on in the requested fashion.
|
|||
|
|
|||
|
STATUS_INVALID_DOMAIN_STATE - The domain server is not in the
|
|||
|
correct state (disabled or enabled) to perform the requested
|
|||
|
operation. The domain server must be enabled for this
|
|||
|
operation
|
|||
|
|
|||
|
STATUS_INVALID_DOMAIN_ROLE - The domain server is serving the
|
|||
|
incorrect role (primary or backup) to perform the requested
|
|||
|
operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus;
|
|||
|
NTSTATUS TmpStatus;
|
|||
|
NTSTATUS IgnoreStatus;
|
|||
|
|
|||
|
PSAMP_OBJECT AccountContext;
|
|||
|
|
|||
|
SAMP_OBJECT_TYPE FoundType;
|
|||
|
|
|||
|
PSAMP_DEFINED_DOMAINS Domain;
|
|||
|
|
|||
|
ACCESS_MASK DesiredAccess;
|
|||
|
|
|||
|
UNICODE_STRING OldAccountName;
|
|||
|
|
|||
|
ULONG AliasRid,
|
|||
|
DomainIndex;
|
|||
|
|
|||
|
BOOLEAN Modified = FALSE;
|
|||
|
|
|||
|
|
|||
|
OldAccountName.Buffer = NULL;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Make sure we understand what RPC is doing for (to) us.
|
|||
|
//
|
|||
|
|
|||
|
if (Buffer == NULL) {
|
|||
|
return(STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set the desired access based upon the Info class
|
|||
|
//
|
|||
|
|
|||
|
switch (AliasInformationClass) {
|
|||
|
|
|||
|
case AliasNameInformation:
|
|||
|
case AliasAdminCommentInformation:
|
|||
|
|
|||
|
DesiredAccess = ALIAS_WRITE_ACCOUNT;
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case AliasGeneralInformation:
|
|||
|
default:
|
|||
|
|
|||
|
return(STATUS_INVALID_INFO_CLASS);
|
|||
|
|
|||
|
} // end_switch
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Grab the lock
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampAcquireWriteLock();
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Validate type of, and access to object.
|
|||
|
//
|
|||
|
|
|||
|
AccountContext = (PSAMP_OBJECT)AliasHandle;
|
|||
|
NtStatus = SampLookupContext(
|
|||
|
AccountContext,
|
|||
|
DesiredAccess,
|
|||
|
SampAliasObjectType, // ExpectedType
|
|||
|
&FoundType
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Get a pointer to the domain this object is in.
|
|||
|
// This is used for auditing.
|
|||
|
//
|
|||
|
|
|||
|
DomainIndex = AccountContext->DomainIndex;
|
|||
|
Domain = &SampDefinedDomains[ DomainIndex ];
|
|||
|
|
|||
|
//
|
|||
|
// case on the type information requested
|
|||
|
//
|
|||
|
|
|||
|
switch (AliasInformationClass) {
|
|||
|
|
|||
|
case AliasNameInformation:
|
|||
|
|
|||
|
NtStatus = SampChangeAliasAccountName(
|
|||
|
AccountContext,
|
|||
|
(PUNICODE_STRING)&(Buffer->Name.Name),
|
|||
|
&OldAccountName
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
OldAccountName.Buffer = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Don't delete the old account name yet; we'll still need
|
|||
|
// to pass it to Netlogon below.
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case AliasAdminCommentInformation:
|
|||
|
|
|||
|
NtStatus = SampSetUnicodeStringAttribute(
|
|||
|
AccountContext,
|
|||
|
SAMP_ALIAS_ADMIN_COMMENT,
|
|||
|
(PUNICODE_STRING)&(Buffer->AdminComment.AdminComment)
|
|||
|
);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
} // end_switch
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Generate an audit if necessary
|
|||
|
//
|
|||
|
|
|||
|
if ((NT_SUCCESS(NtStatus) &&
|
|||
|
SampDoAccountAuditing(DomainIndex))) {
|
|||
|
|
|||
|
UNICODE_STRING
|
|||
|
AccountName;
|
|||
|
|
|||
|
IgnoreStatus = SampGetUnicodeStringAttribute(
|
|||
|
AccountContext, // Context
|
|||
|
SAMP_ALIAS_NAME, // AttributeIndex
|
|||
|
FALSE, // MakeCopy
|
|||
|
&AccountName // UnicodeAttribute
|
|||
|
);
|
|||
|
if (NT_SUCCESS(IgnoreStatus)) {
|
|||
|
LsaIAuditSamEvent(
|
|||
|
STATUS_SUCCESS,
|
|||
|
SE_AUDITID_LOCAL_GROUP_CHANGE, // AuditId
|
|||
|
Domain->Sid, // Domain SID
|
|||
|
NULL, // Member Rid (not used)
|
|||
|
NULL, // Member Sid (not used)
|
|||
|
&AccountName, // Account Name
|
|||
|
&Domain->ExternalName, // Domain
|
|||
|
&AccountContext->TypeBody.Alias.Rid, // Account Rid
|
|||
|
NULL // Privileges used
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Dereference the account context
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Save object RID before dereferencing context.
|
|||
|
// RID is used in SampNotifyNetlogonOfDelta() call.
|
|||
|
//
|
|||
|
|
|||
|
AliasRid = AccountContext->TypeBody.Alias.Rid;
|
|||
|
|
|||
|
//
|
|||
|
// De-reference the object, write out any change to current xaction.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampDeReferenceContext( AccountContext, TRUE );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// De-reference the object, ignore changes
|
|||
|
//
|
|||
|
|
|||
|
TmpStatus = SampDeReferenceContext( AccountContext, FALSE );
|
|||
|
ASSERT(NT_SUCCESS(TmpStatus));
|
|||
|
}
|
|||
|
|
|||
|
} //end_if
|
|||
|
|
|||
|
//
|
|||
|
// Commit the transaction and notify netlogon of any changes
|
|||
|
//
|
|||
|
|
|||
|
if ( NT_SUCCESS(NtStatus) ) {
|
|||
|
|
|||
|
NtStatus = SampCommitAndRetainWriteLock();
|
|||
|
|
|||
|
if ( NT_SUCCESS(NtStatus) ) {
|
|||
|
|
|||
|
if ( AliasInformationClass == AliasNameInformation ) {
|
|||
|
|
|||
|
SampNotifyNetlogonOfDelta(
|
|||
|
SecurityDbRename,
|
|||
|
SecurityDbObjectSamAlias,
|
|||
|
AliasRid,
|
|||
|
&OldAccountName,
|
|||
|
(DWORD) FALSE, // Replicate immediately
|
|||
|
NULL // Delta data
|
|||
|
);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
SampNotifyNetlogonOfDelta(
|
|||
|
SecurityDbChange,
|
|||
|
SecurityDbObjectSamAlias,
|
|||
|
AliasRid,
|
|||
|
NULL,
|
|||
|
(DWORD) FALSE, // Replicate immediately
|
|||
|
NULL // Delta data
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Free up our old account name if we have one
|
|||
|
//
|
|||
|
|
|||
|
SampFreeUnicodeString( &OldAccountName );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now release the write lock and return, propogating any errors.
|
|||
|
//
|
|||
|
|
|||
|
TmpStatus = SampReleaseWriteLock( FALSE );
|
|||
|
ASSERT(NT_SUCCESS(TmpStatus));
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
NtStatus = TmpStatus;
|
|||
|
}
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrDeleteAlias(
|
|||
|
IN SAM_HANDLE *AliasHandle
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This API deletes an Alias from the account database. The Alias does
|
|||
|
not have to be empty.
|
|||
|
|
|||
|
Note that following this call, the AliasHandle is no longer valid.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
AliasHandle - The handle of an opened Alias to operate on.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
STATUS_SUCCESS - The Service completed successfully.
|
|||
|
|
|||
|
STATUS_ACCESS_DENIED - Caller does not have the appropriate
|
|||
|
access to complete the operation.
|
|||
|
|
|||
|
STATUS_INVALID_HANDLE - The handle passed is invalid.
|
|||
|
|
|||
|
STATUS_INVALID_DOMAIN_STATE - The domain server is not in the
|
|||
|
correct state (disabled or enabled) to perform the requested
|
|||
|
operation. The domain server must be enabled for this
|
|||
|
operation
|
|||
|
|
|||
|
STATUS_INVALID_DOMAIN_ROLE - The domain server is serving the
|
|||
|
incorrect role (primary or backup) to perform the requested
|
|||
|
operation.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UNICODE_STRING AliasName;
|
|||
|
NTSTATUS NtStatus, TmpStatus, IgnoreStatus;
|
|||
|
PSAMP_OBJECT AccountContext;
|
|||
|
PSAMP_DEFINED_DOMAINS Domain;
|
|||
|
SAMP_OBJECT_TYPE FoundType;
|
|||
|
ULONG AliasRid,
|
|||
|
DomainIndex;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Grab the lock
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampAcquireWriteLock();
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Validate type of, and access to object.
|
|||
|
//
|
|||
|
|
|||
|
AccountContext = (PSAMP_OBJECT)(*AliasHandle);
|
|||
|
|
|||
|
NtStatus = SampLookupContext(
|
|||
|
AccountContext,
|
|||
|
DELETE,
|
|||
|
SampAliasObjectType, // ExpectedType
|
|||
|
&FoundType
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
AliasRid = AccountContext->TypeBody.Alias.Rid;
|
|||
|
|
|||
|
//
|
|||
|
// Get a pointer to the domain this object is in.
|
|||
|
// This is used for auditing.
|
|||
|
//
|
|||
|
|
|||
|
DomainIndex = AccountContext->DomainIndex;
|
|||
|
Domain = &SampDefinedDomains[ DomainIndex ];
|
|||
|
|
|||
|
//
|
|||
|
// Make sure the account is one that can be deleted.
|
|||
|
// Can't be a built-in account, unless caller is trusted.
|
|||
|
//
|
|||
|
|
|||
|
if ( !AccountContext->TrustedClient ) {
|
|||
|
|
|||
|
NtStatus = SampIsAccountBuiltIn( AliasRid );
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Remove this alias from every account's alias-membership list
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampRemoveAliasFromAllAccounts(AccountContext);
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// First get and save the account name for
|
|||
|
// I_NetNotifyLogonOfDelta.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampGetUnicodeStringAttribute(
|
|||
|
AccountContext,
|
|||
|
SAMP_ALIAS_NAME,
|
|||
|
TRUE, // Make copy
|
|||
|
&AliasName
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// This must be done before we invalidate contexts, because our
|
|||
|
// own handle to the alias gets closed as well.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampDeleteAliasKeys( AccountContext );
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// We must invalidate any open contexts to this alias
|
|||
|
// This will close all handles to the alias's keys.
|
|||
|
// THIS IS AN IRREVERSIBLE PROCESS.
|
|||
|
//
|
|||
|
|
|||
|
SampInvalidateAliasContexts( AliasRid );
|
|||
|
|
|||
|
//
|
|||
|
// Commit the whole mess
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampCommitAndRetainWriteLock();
|
|||
|
|
|||
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|||
|
|
|||
|
//
|
|||
|
// Update the Alias Information Cache
|
|||
|
//
|
|||
|
|
|||
|
IgnoreStatus = SampAlDeleteAlias( AliasHandle );
|
|||
|
|
|||
|
//
|
|||
|
// Audit the deletion before we free the write lock
|
|||
|
// so that we have access to the context block.
|
|||
|
//
|
|||
|
|
|||
|
if (SampDoAccountAuditing(DomainIndex) &&
|
|||
|
NT_SUCCESS(NtStatus) ) {
|
|||
|
|
|||
|
LsaIAuditSamEvent(
|
|||
|
STATUS_SUCCESS,
|
|||
|
SE_AUDITID_LOCAL_GROUP_DELETED, // AuditId
|
|||
|
Domain->Sid, // Domain SID
|
|||
|
NULL, // Member Rid (not used)
|
|||
|
NULL, // Member sid (not used)
|
|||
|
&AliasName, // Account Name
|
|||
|
&Domain->ExternalName, // Domain
|
|||
|
&AliasRid, // Account Rid
|
|||
|
NULL // Privileges used
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Notify netlogon of the change
|
|||
|
//
|
|||
|
|
|||
|
SampNotifyNetlogonOfDelta(
|
|||
|
SecurityDbDelete,
|
|||
|
SecurityDbObjectSamAlias,
|
|||
|
AliasRid,
|
|||
|
&AliasName,
|
|||
|
(DWORD) FALSE, // Replicate immediately
|
|||
|
NULL // Delta data
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Do delete auditing
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
(VOID) NtDeleteObjectAuditAlarm(
|
|||
|
&SampSamSubsystem,
|
|||
|
*AliasHandle,
|
|||
|
AccountContext->AuditOnClose
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SampFreeUnicodeString( &AliasName );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// De-reference the object, discard any changes
|
|||
|
//
|
|||
|
|
|||
|
TmpStatus = SampDeReferenceContext( AccountContext, FALSE );
|
|||
|
ASSERT(NT_SUCCESS(TmpStatus));
|
|||
|
|
|||
|
|
|||
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|||
|
|
|||
|
//
|
|||
|
// If we actually deleted the alias, then delete the context
|
|||
|
// and let RPC know that the handle is invalid.
|
|||
|
//
|
|||
|
|
|||
|
SampDeleteContext( AccountContext );
|
|||
|
|
|||
|
(*AliasHandle) = NULL;
|
|||
|
}
|
|||
|
|
|||
|
} //end_if
|
|||
|
|
|||
|
//
|
|||
|
// Free the lock -
|
|||
|
//
|
|||
|
// Everything has already been committed above, so we must indicate
|
|||
|
// no additional changes have taken place.
|
|||
|
//
|
|||
|
|
|||
|
TmpStatus = SampReleaseWriteLock( FALSE );
|
|||
|
|
|||
|
if (NtStatus == STATUS_SUCCESS) {
|
|||
|
NtStatus = TmpStatus;
|
|||
|
}
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrAddMemberToAlias(
|
|||
|
IN SAMPR_HANDLE AliasHandle,
|
|||
|
IN PRPC_SID MemberId
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This API adds a member to an alias. Note that this API requires the
|
|||
|
ALIAS_ADD_MEMBER access type for the alias.
|
|||
|
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
AliasHandle - The handle of an opened alias to operate on.
|
|||
|
|
|||
|
MemberId - SID of the member to add.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
STATUS_SUCCESS - The Service completed successfully.
|
|||
|
|
|||
|
|
|||
|
STATUS_ACCESS_DENIED - Caller does not have the appropriate
|
|||
|
access to complete the operation.
|
|||
|
|
|||
|
STATUS_INVALID_HANDLE - The handle passed is invalid.
|
|||
|
|
|||
|
STATUS_NO_SUCH_MEMBER - The member specified is unknown.
|
|||
|
|
|||
|
STATUS_MEMBER_IN_ALIAS - The member already belongs to the alias.
|
|||
|
|
|||
|
STATUS_INVALID_MEMBER - The member has the wrong account type.
|
|||
|
|
|||
|
STATUS_INVALID_SID - The member sid is corrupted.
|
|||
|
|
|||
|
STATUS_INVALID_DOMAIN_STATE - The domain server is not in the
|
|||
|
correct state (disabled or enabled) to perform the requested
|
|||
|
operation. The domain server must be enabled for this
|
|||
|
operation
|
|||
|
|
|||
|
STATUS_INVALID_DOMAIN_ROLE - The domain server is serving the
|
|||
|
incorrect role (primary or backup) to perform the requested
|
|||
|
operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus, TmpStatus, IgnoreStatus;
|
|||
|
PSAMP_OBJECT AccountContext;
|
|||
|
SAMP_OBJECT_TYPE FoundType;
|
|||
|
ULONG ObjectRid;
|
|||
|
SAMP_MEMBERSHIP_DELTA AdminChange = NoChange;
|
|||
|
SAMP_MEMBERSHIP_DELTA OperatorChange = NoChange;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Grab the lock
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampAcquireWriteLock();
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Validate type of, and access to object.
|
|||
|
//
|
|||
|
|
|||
|
AccountContext = (PSAMP_OBJECT)(AliasHandle);
|
|||
|
NtStatus = SampLookupContext(
|
|||
|
AccountContext,
|
|||
|
ALIAS_ADD_MEMBER,
|
|||
|
SampAliasObjectType, // ExpectedType
|
|||
|
&FoundType
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Check the potential new member is OK
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampValidateNewAliasMember(MemberId);
|
|||
|
|
|||
|
//
|
|||
|
// If the member is being added to an ADMIN alias, we must make
|
|||
|
// sure the member ACL(s) don't allow access by account operators.
|
|||
|
//
|
|||
|
|
|||
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|||
|
if ( AccountContext->TypeBody.Alias.Rid == DOMAIN_ALIAS_RID_ADMINS ) {
|
|||
|
|
|||
|
AdminChange = AddToAdmin;
|
|||
|
|
|||
|
} else if ( ( AccountContext->TypeBody.Alias.Rid == DOMAIN_ALIAS_RID_SYSTEM_OPS ) ||
|
|||
|
( AccountContext->TypeBody.Alias.Rid == DOMAIN_ALIAS_RID_PRINT_OPS ) ||
|
|||
|
( AccountContext->TypeBody.Alias.Rid == DOMAIN_ALIAS_RID_BACKUP_OPS ) ||
|
|||
|
( AccountContext->TypeBody.Alias.Rid == DOMAIN_ALIAS_RID_ACCOUNT_OPS ) ) {
|
|||
|
|
|||
|
OperatorChange = AddToAdmin;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If either of these are changing, change account operator
|
|||
|
// access to this member
|
|||
|
//
|
|||
|
|
|||
|
if ( ( OperatorChange != NoChange ) ||
|
|||
|
( AdminChange != NoChange ) ) {
|
|||
|
|
|||
|
NtStatus = SampChangeAccountOperatorAccessToMember(
|
|||
|
MemberId,
|
|||
|
AdminChange,
|
|||
|
OperatorChange
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Perform the user object side of things
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampAddAliasToAccountMembership(
|
|||
|
AccountContext->TypeBody.Alias.Rid,
|
|||
|
MemberId
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now perform the alias side of things
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Add the user to the alias (should not fail)
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampAddAccountToAlias(
|
|||
|
AccountContext,
|
|||
|
MemberId
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Dereference the account context
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Save object RID before dereferencing context.
|
|||
|
// RID is used in SampNotifyNetlogonOfDelta() call.
|
|||
|
//
|
|||
|
|
|||
|
ObjectRid = AccountContext->TypeBody.Alias.Rid;
|
|||
|
|
|||
|
//
|
|||
|
// De-reference the object, write out any change to current xaction.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampDeReferenceContext( AccountContext, TRUE );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// De-reference the object, ignore changes
|
|||
|
//
|
|||
|
|
|||
|
TmpStatus = SampDeReferenceContext( AccountContext, FALSE );
|
|||
|
ASSERT(NT_SUCCESS(TmpStatus));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Commit the whole mess
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampCommitAndRetainWriteLock();
|
|||
|
|
|||
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|||
|
|
|||
|
SAM_DELTA_DATA DeltaData;
|
|||
|
|
|||
|
//
|
|||
|
// Update the Alias Information Cache
|
|||
|
//
|
|||
|
|
|||
|
SAMPR_PSID_ARRAY MemberSids;
|
|||
|
MemberSids.Count = 1;
|
|||
|
MemberSids.Sids = (PSAMPR_SID_INFORMATION) &MemberId;
|
|||
|
|
|||
|
IgnoreStatus = SampAlAddMembersToAlias(
|
|||
|
AliasHandle,
|
|||
|
0,
|
|||
|
&MemberSids
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Fill in id of member being added
|
|||
|
//
|
|||
|
|
|||
|
DeltaData.AliasMemberId.MemberSid = MemberId;
|
|||
|
|
|||
|
SampNotifyNetlogonOfDelta(
|
|||
|
SecurityDbChangeMemberAdd,
|
|||
|
SecurityDbObjectSamAlias,
|
|||
|
ObjectRid,
|
|||
|
(PUNICODE_STRING) NULL,
|
|||
|
(DWORD) FALSE, // Replicate immediately
|
|||
|
&DeltaData
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
TmpStatus = SampReleaseWriteLock( FALSE );
|
|||
|
ASSERT(NT_SUCCESS(TmpStatus));
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrAddMultipleMembersToAlias(
|
|||
|
IN SAMPR_HANDLE AliasHandle,
|
|||
|
IN PSAMPR_PSID_ARRAY MembersBuffer
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This api adds multiple members to an alias.
|
|||
|
|
|||
|
NOTE: For now, this routine takes a brute force approach.
|
|||
|
I tried to do it in a better (more efficient) manner,
|
|||
|
but kept running into problems. Finally, when I ran
|
|||
|
into problems in the way SAM uses RXACT, I gave up
|
|||
|
and did this brute force approach.
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
AliasHandle - The handle of an opened Alias to operate on.
|
|||
|
|
|||
|
MembersBuffer - Contains a count of SIDs to be added to the
|
|||
|
alias and a pointer to a buffer containing an array of
|
|||
|
pointers to SIDs. These SIDs are the SIDs of the members to
|
|||
|
be added to the Alias.
|
|||
|
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
STATUS_SUCCESS - The Service completed successfully. All of the
|
|||
|
listed members are now members of the alias. However, some of
|
|||
|
the members may already have been members of the alias (this is
|
|||
|
NOT an error or warning condition).
|
|||
|
|
|||
|
STATUS_ACCESS_DENIED - Caller does not have the object open for
|
|||
|
the required access.
|
|||
|
|
|||
|
STATUS_INVALID_HANDLE - The handle passed is invalid.
|
|||
|
|
|||
|
STATUS_INVALID_MEMBER - The member has the wrong account type.
|
|||
|
|
|||
|
STATUS_INVALID_SID - The member sid is corrupted.
|
|||
|
|
|||
|
STATUS_INVALID_DOMAIN_STATE - The domain server is not in the
|
|||
|
correct state (disabled or enabled) to perform the requested
|
|||
|
operation. The domain server must be enabled for this
|
|||
|
operation
|
|||
|
|
|||
|
STATUS_INVALID_DOMAIN_ROLE - The domain server is serving the
|
|||
|
incorrect role (primary or backup) to perform the requested
|
|||
|
operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NtStatus;
|
|||
|
|
|||
|
LONG
|
|||
|
MemberCount,
|
|||
|
i;
|
|||
|
|
|||
|
PSID
|
|||
|
*MemberId;
|
|||
|
|
|||
|
MemberCount = (LONG)MembersBuffer->Count;
|
|||
|
MemberId = (PSID *)MembersBuffer->Sids;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set completion status in case there are no members
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = STATUS_SUCCESS;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the SIDs, adding them to the alias.
|
|||
|
// Ignore any status value indicating the member is already
|
|||
|
// a member. Other errors, however, will cause us to abort.
|
|||
|
//
|
|||
|
|
|||
|
for (i=0; i<MemberCount; i++) {
|
|||
|
|
|||
|
NtStatus = SamrAddMemberToAlias( AliasHandle, MemberId[i] );
|
|||
|
|
|||
|
if (NtStatus == STATUS_MEMBER_IN_ALIAS) {
|
|||
|
NtStatus = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
break; //for loop
|
|||
|
}
|
|||
|
|
|||
|
} //end_for
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrRemoveMemberFromAlias(
|
|||
|
IN SAMPR_HANDLE AliasHandle,
|
|||
|
IN PRPC_SID MemberId
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This API removes a member from an alias. Note that this API requires the
|
|||
|
ALIAS_REMOVE_MEMBER access type for the alias.
|
|||
|
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
AliasHandle - The handle of an opened alias to operate on.
|
|||
|
|
|||
|
MemberId - SID of the member to remove.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
????
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus, TmpStatus, IgnoreStatus;
|
|||
|
PSAMP_OBJECT AccountContext;
|
|||
|
SAMP_OBJECT_TYPE FoundType;
|
|||
|
ULONG ObjectRid;
|
|||
|
SAMP_MEMBERSHIP_DELTA AdminChange = NoChange;
|
|||
|
SAMP_MEMBERSHIP_DELTA OperatorChange = NoChange;
|
|||
|
|
|||
|
//
|
|||
|
// Grab the lock
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampAcquireWriteLock();
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Validate type of, and access to object.
|
|||
|
//
|
|||
|
|
|||
|
AccountContext = (PSAMP_OBJECT)(AliasHandle);
|
|||
|
NtStatus = SampLookupContext(
|
|||
|
AccountContext,
|
|||
|
ALIAS_REMOVE_MEMBER,
|
|||
|
SampAliasObjectType, // ExpectedType
|
|||
|
&FoundType
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Validate the sid of the member.
|
|||
|
//
|
|||
|
|
|||
|
if ((MemberId == NULL) || !RtlValidSid(MemberId)) {
|
|||
|
NtStatus = STATUS_INVALID_SID;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Perform the user object side of things
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampRemoveAliasFromAccountMembership(
|
|||
|
AccountContext->TypeBody.Alias.Rid,
|
|||
|
(PSID)MemberId
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now perform the alias side of things
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Remove the user from the alias (should not fail)
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampRemoveAccountFromAlias(
|
|||
|
AccountContext,
|
|||
|
(PSID)MemberId
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// If the member is being removed from an ADMIN alias, we must make
|
|||
|
// sure the member ACL(s) allow access by account operators.
|
|||
|
//
|
|||
|
|
|||
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|||
|
if ( AccountContext->TypeBody.Alias.Rid == DOMAIN_ALIAS_RID_ADMINS ) {
|
|||
|
|
|||
|
AdminChange = RemoveFromAdmin;
|
|||
|
|
|||
|
} else if ( ( AccountContext->TypeBody.Alias.Rid == DOMAIN_ALIAS_RID_SYSTEM_OPS ) ||
|
|||
|
( AccountContext->TypeBody.Alias.Rid == DOMAIN_ALIAS_RID_PRINT_OPS ) ||
|
|||
|
( AccountContext->TypeBody.Alias.Rid == DOMAIN_ALIAS_RID_BACKUP_OPS ) ||
|
|||
|
( AccountContext->TypeBody.Alias.Rid == DOMAIN_ALIAS_RID_ACCOUNT_OPS ) ) {
|
|||
|
|
|||
|
OperatorChange = RemoveFromAdmin;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If either of these are changing, change account operator
|
|||
|
// access to this member
|
|||
|
//
|
|||
|
|
|||
|
if ( ( OperatorChange != NoChange ) ||
|
|||
|
( AdminChange != NoChange ) ) {
|
|||
|
|
|||
|
NtStatus = SampChangeAccountOperatorAccessToMember(
|
|||
|
MemberId,
|
|||
|
AdminChange,
|
|||
|
OperatorChange
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Dereference the account context
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Save object RID before dereferencing context.
|
|||
|
// RID is used in SampNotifyNetlogonOfDelta() call.
|
|||
|
//
|
|||
|
|
|||
|
ObjectRid = AccountContext->TypeBody.Alias.Rid;
|
|||
|
|
|||
|
//
|
|||
|
// De-reference the object, write out any change to current xaction.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampDeReferenceContext( AccountContext, TRUE );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// De-reference the object, ignore changes
|
|||
|
//
|
|||
|
|
|||
|
TmpStatus = SampDeReferenceContext( AccountContext, FALSE );
|
|||
|
ASSERT(NT_SUCCESS(TmpStatus));
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = SampCommitAndRetainWriteLock();
|
|||
|
|
|||
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|||
|
|
|||
|
SAM_DELTA_DATA DeltaData;
|
|||
|
|
|||
|
//
|
|||
|
// Update the Alias Information Cache
|
|||
|
//
|
|||
|
|
|||
|
SAMPR_PSID_ARRAY MemberSids;
|
|||
|
MemberSids.Count = 1;
|
|||
|
MemberSids.Sids = (PSAMPR_SID_INFORMATION) &MemberId;
|
|||
|
|
|||
|
IgnoreStatus = SampAlRemoveMembersFromAlias(
|
|||
|
AliasHandle,
|
|||
|
0,
|
|||
|
&MemberSids
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Fill in id of member being deleted
|
|||
|
//
|
|||
|
|
|||
|
DeltaData.AliasMemberId.MemberSid = MemberId;
|
|||
|
|
|||
|
SampNotifyNetlogonOfDelta(
|
|||
|
SecurityDbChangeMemberDel,
|
|||
|
SecurityDbObjectSamAlias,
|
|||
|
ObjectRid,
|
|||
|
(PUNICODE_STRING) NULL,
|
|||
|
(DWORD) FALSE, // Replicate immediately
|
|||
|
&DeltaData
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
TmpStatus = SampReleaseWriteLock( FALSE );
|
|||
|
ASSERT(NT_SUCCESS(TmpStatus));
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrRemoveMultipleMembersFromAlias(
|
|||
|
IN SAMPR_HANDLE AliasHandle,
|
|||
|
IN PSAMPR_PSID_ARRAY MembersBuffer
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This API removes members from an alias. Note that this API requires
|
|||
|
the ALIAS_REMOVE_MEMBER access type for the alias.
|
|||
|
|
|||
|
NOTE: This api currently uses a brute-force approach to adding
|
|||
|
members to the alias. This is because of problems
|
|||
|
encountered when trying to do "the right thing".
|
|||
|
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
AliasHandle - The handle of an opened alias to operate on.
|
|||
|
|
|||
|
MembersBuffer - Contains a count of SIDs to be added to the
|
|||
|
alias and a pointer to a buffer containing an array of
|
|||
|
pointers to SIDs. These SIDs are the SIDs of the members to
|
|||
|
be added to the Alias.
|
|||
|
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
STATUS_SUCCESS - The Service completed successfully. All of the
|
|||
|
listed members are now members of the alias. However, some of
|
|||
|
the members may already have been members of the alias (this is
|
|||
|
NOT an error or warning condition).
|
|||
|
|
|||
|
STATUS_ACCESS_DENIED - Caller does not have the object open for
|
|||
|
the required access.
|
|||
|
|
|||
|
STATUS_INVALID_HANDLE - The handle passed is invalid.
|
|||
|
|
|||
|
STATUS_INVALID_SID - The member sid is corrupted.
|
|||
|
|
|||
|
STATUS_INVALID_DOMAIN_STATE - The domain server is not in the
|
|||
|
correct state (disabled or enabled) to perform the requested
|
|||
|
operation. The domain server must be enabled for this
|
|||
|
operation
|
|||
|
|
|||
|
STATUS_INVALID_DOMAIN_ROLE - The domain server is serving the
|
|||
|
incorrect role (primary or backup) to perform the requested
|
|||
|
operation.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NtStatus;
|
|||
|
|
|||
|
LONG
|
|||
|
MemberCount,
|
|||
|
i;
|
|||
|
|
|||
|
PSID
|
|||
|
*MemberId;
|
|||
|
|
|||
|
MemberCount = (LONG)MembersBuffer->Count;
|
|||
|
MemberId = (PSID *)MembersBuffer->Sids;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set completion status in case there are no members
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = STATUS_SUCCESS;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the SIDs, adding them to the alias.
|
|||
|
// Ignore any status value indicating the member is already
|
|||
|
// a member. Other errors, however, will cause us to abort.
|
|||
|
//
|
|||
|
|
|||
|
for (i=0; i<MemberCount; i++) {
|
|||
|
|
|||
|
NtStatus = SamrAddMemberToAlias( AliasHandle, MemberId[i] );
|
|||
|
|
|||
|
if (NtStatus == STATUS_MEMBER_NOT_IN_ALIAS) {
|
|||
|
NtStatus = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
break; //for loop
|
|||
|
}
|
|||
|
|
|||
|
} //end_for
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrGetMembersInAlias(
|
|||
|
IN SAM_HANDLE AliasHandle,
|
|||
|
OUT PSAMPR_PSID_ARRAY GetMembersBuffer
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This API lists all members in an Alias. This API requires
|
|||
|
ALIAS_LIST_MEMBERS access to the Alias.
|
|||
|
|
|||
|
NOTE: This function does not use the Alias cache.
|
|||
|
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
AliasHandle - The handle of an opened Alias to operate on.
|
|||
|
|
|||
|
MemberIds - Receives a pointer to a buffer containing an array of
|
|||
|
pointers to SIDs. These SIDs are the SIDs of the members of the
|
|||
|
Alias. When this information is no longer needed, this buffer
|
|||
|
must be freed using SamFreeMemory().
|
|||
|
|
|||
|
MemberCount - number of members in the Alias (and, thus, the number
|
|||
|
of relative IDs returned).
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
STATUS_SUCCESS - The Service completed successfully, and there are
|
|||
|
no additional entries.
|
|||
|
|
|||
|
STATUS_ACCESS_DENIED - Caller does not have privilege required to
|
|||
|
request that data.
|
|||
|
|
|||
|
STATUS_INVALID_HANDLE - The handle passed is invalid.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus, IgnoreStatus;
|
|||
|
PSAMP_OBJECT AccountContext;
|
|||
|
SAMP_OBJECT_TYPE FoundType;
|
|||
|
|
|||
|
//
|
|||
|
// Make sure we understand what RPC is doing for (to) us.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (GetMembersBuffer != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Grab the lock
|
|||
|
//
|
|||
|
|
|||
|
SampAcquireReadLock();
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Validate type of, and access to object.
|
|||
|
//
|
|||
|
|
|||
|
AccountContext = (PSAMP_OBJECT)AliasHandle;
|
|||
|
NtStatus = SampLookupContext(
|
|||
|
AccountContext,
|
|||
|
ALIAS_LIST_MEMBERS,
|
|||
|
SampAliasObjectType, // ExpectedType
|
|||
|
&FoundType
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = SampRetrieveAliasMembers(
|
|||
|
AccountContext,
|
|||
|
&(GetMembersBuffer->Count),
|
|||
|
(PSID **)&(GetMembersBuffer->Sids)
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// De-reference the object, discarding changes
|
|||
|
//
|
|||
|
|
|||
|
IgnoreStatus = SampDeReferenceContext( AccountContext, FALSE );
|
|||
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the read lock
|
|||
|
//
|
|||
|
|
|||
|
SampReleaseReadLock();
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Tidy up on failure
|
|||
|
//
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)){
|
|||
|
|
|||
|
GetMembersBuffer->Count = 0;
|
|||
|
GetMembersBuffer->Sids = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Internal Services Available For Use in Other SAM Modules //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampRemoveAccountFromAllAliases(
|
|||
|
IN PSID AccountSid,
|
|||
|
IN BOOLEAN CheckAccess,
|
|||
|
IN SAMPR_HANDLE DomainHandle OPTIONAL,
|
|||
|
IN PULONG MembershipCount OPTIONAL,
|
|||
|
IN PULONG *Membership OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine removes the specified account from the member list of all
|
|||
|
aliases in this domain.
|
|||
|
|
|||
|
|
|||
|
The caller of this service is expected to be in the middle of a
|
|||
|
RXACT transaction. This service simply adds some actions to that
|
|||
|
RXACT transaction.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AccountSid - The SID of the account being Removed.
|
|||
|
|
|||
|
CheckAccess - if TRUE, this routine will make sure that the caller
|
|||
|
is allowed REMOVE_ALIAS_MEMBER access to this alias. If FALSE,
|
|||
|
the caller is already known to have proper access.
|
|||
|
|
|||
|
DomainHandle - if CheckAccess is TRUE, this handle must be provided
|
|||
|
to allow access to be checked.
|
|||
|
|
|||
|
MembershipCount - if CheckAccess is TRUE, this pointer must be
|
|||
|
provided to receive the number of aliases the account was
|
|||
|
deleted from.
|
|||
|
|
|||
|
Membership - if CheckAccess is TRUE, this pointer must be provided
|
|||
|
to point to a list of aliases the account was removed from. The
|
|||
|
caller must free this list with MIDL_user_free().
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
STATUS_SUCCESS - The user has been Removed from all aliases.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus, IgnoreStatus;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
UNICODE_STRING DomainKeyName, AccountKeyName;
|
|||
|
HANDLE TempHandle, AliasHandle;
|
|||
|
ULONG LocalMembershipCount;
|
|||
|
PULONG LocalMembership;
|
|||
|
ULONG KeyValueLength;
|
|||
|
ULONG i;
|
|||
|
PSAMP_OBJECT AliasContext;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Get the alias membership for this account
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampBuildAliasMembersKeyName(
|
|||
|
AccountSid,
|
|||
|
&DomainKeyName,
|
|||
|
&AccountKeyName
|
|||
|
);
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjectAttributes,
|
|||
|
&AccountKeyName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
SampKey,
|
|||
|
NULL
|
|||
|
);
|
|||
|
NtStatus = RtlpNtOpenKey(
|
|||
|
&TempHandle,
|
|||
|
(KEY_READ),
|
|||
|
&ObjectAttributes,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
if ((NtStatus == STATUS_OBJECT_PATH_NOT_FOUND) ||
|
|||
|
(NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) ) {
|
|||
|
|
|||
|
//
|
|||
|
// This account is not a member of any of our aliases
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = STATUS_SUCCESS;
|
|||
|
|
|||
|
if ( CheckAccess ) {
|
|||
|
|
|||
|
//
|
|||
|
// Return the list of aliases the account was
|
|||
|
// removed from; in this case, none.
|
|||
|
//
|
|||
|
|
|||
|
( *MembershipCount ) = 0;
|
|||
|
( *Membership ) = NULL;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Load in the alias membership list
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
KeyValueLength = 0;
|
|||
|
|
|||
|
NtStatus = RtlpNtQueryValueKey( TempHandle,
|
|||
|
&LocalMembershipCount,
|
|||
|
NULL,
|
|||
|
&KeyValueLength,
|
|||
|
NULL);
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
ASSERT(LocalMembershipCount == 0);
|
|||
|
}
|
|||
|
|
|||
|
if (NtStatus == STATUS_BUFFER_OVERFLOW) {
|
|||
|
|
|||
|
LocalMembership = MIDL_user_allocate( KeyValueLength );
|
|||
|
|
|||
|
if (LocalMembership == NULL) {
|
|||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
} else {
|
|||
|
|
|||
|
NtStatus = RtlpNtQueryValueKey(
|
|||
|
TempHandle,
|
|||
|
NULL,
|
|||
|
LocalMembership,
|
|||
|
&KeyValueLength,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Remove the account from each alias
|
|||
|
//
|
|||
|
|
|||
|
for (i=0; i < LocalMembershipCount; i++) {
|
|||
|
|
|||
|
if ( CheckAccess ) {
|
|||
|
|
|||
|
//
|
|||
|
// If account is being removed from
|
|||
|
// the ADMIN alias, change ACL to
|
|||
|
// allow account operators to access
|
|||
|
// the account (unless account is an
|
|||
|
// admin some other way). Kind of
|
|||
|
// useless since the account is about
|
|||
|
// to be deleted, but do it anyway
|
|||
|
// in case something bad happens and
|
|||
|
// it doesn't get deleted.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// BUGBUG: this may not do it - we may
|
|||
|
// need to check the admin count on
|
|||
|
// the group. MMS 9/5/95
|
|||
|
//
|
|||
|
|
|||
|
if ( LocalMembership[i] ==
|
|||
|
DOMAIN_ALIAS_RID_ADMINS ) {
|
|||
|
|
|||
|
NtStatus = SampChangeAccountOperatorAccessToMember(
|
|||
|
AccountSid,
|
|||
|
RemoveFromAdmin,
|
|||
|
NoChange );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Just open and close the alias
|
|||
|
// to make sure we are allowed
|
|||
|
// the necessary access.
|
|||
|
//
|
|||
|
|
|||
|
SampTransactionWithinDomain = FALSE;
|
|||
|
|
|||
|
NtStatus = SampOpenAccount(
|
|||
|
SampAliasObjectType,
|
|||
|
DomainHandle,
|
|||
|
ALIAS_REMOVE_MEMBER,
|
|||
|
LocalMembership[i],
|
|||
|
TRUE,
|
|||
|
(SAMPR_HANDLE *)&AliasHandle
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
SampDeleteContext(
|
|||
|
(PSAMP_OBJECT)( AliasHandle ) );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
NtStatus = SampCreateAccountContext(
|
|||
|
SampAliasObjectType,
|
|||
|
LocalMembership[i],
|
|||
|
TRUE, // Trusted client
|
|||
|
TRUE, // Account exists
|
|||
|
&AliasContext
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = SampRemoveAccountFromAlias(
|
|||
|
AliasContext,
|
|||
|
AccountSid );
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Save the alias changes we just
|
|||
|
// made. We'll delete the context,
|
|||
|
// so don't let RXACT use the open
|
|||
|
// key handle in the context.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampStoreObjectAttributes(
|
|||
|
AliasContext,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
SampDeleteContext(AliasContext);
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Delete the account membership keys
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = SampDeleteAliasMembershipKeysForAccount(
|
|||
|
AccountSid);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( CheckAccess ) {
|
|||
|
|
|||
|
//
|
|||
|
// Return the list of aliases the account was
|
|||
|
// removed from.
|
|||
|
//
|
|||
|
|
|||
|
( *MembershipCount ) = LocalMembershipCount;
|
|||
|
( *Membership ) = LocalMembership;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
MIDL_user_free(LocalMembership);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IgnoreStatus = NtClose( TempHandle );
|
|||
|
ASSERT( NT_SUCCESS(IgnoreStatus) );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SampFreeUnicodeString( &DomainKeyName );
|
|||
|
SampFreeUnicodeString( &AccountKeyName );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return( NtStatus );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampRetrieveAliasMembership(
|
|||
|
IN PSID Account,
|
|||
|
OUT PULONG MemberCount OPTIONAL,
|
|||
|
IN OUT PULONG BufferSize OPTIONAL,
|
|||
|
OUT PULONG Buffer OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service retrieves the number of aliases in the current domain
|
|||
|
that the specified account is a member of. If desired it will also fill
|
|||
|
in a buffer with the alias rids.
|
|||
|
|
|||
|
|
|||
|
Note: THIS ROUTINE REFERENCES THE CURRENT TRANSACTION DOMAIN
|
|||
|
(ESTABLISHED USING SampSetTransactioDomain()). THIS
|
|||
|
SERVICE MAY ONLY BE CALLED AFTER SampSetTransactionDomain()
|
|||
|
AND BEFORE SampReleaseWriteLock().
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Account - the account whose membership we are interested in.
|
|||
|
|
|||
|
MemberCount - Receives the number of current-domain-aliases the
|
|||
|
account is a member of.
|
|||
|
|
|||
|
BufferSize - (Optional) Specified the size of memory pointer to by buffer.
|
|||
|
|
|||
|
Buffer - (Otional) Is filled in with the list of alias membership rids.
|
|||
|
If this value is NULL, then this information
|
|||
|
is not returned. The returned buffer is allocated using
|
|||
|
MIDL_user_allocate() and must be freed using MIDL_user_free() when
|
|||
|
no longer needed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
STATUS_SUCCESS - The information has been retrieved.
|
|||
|
|
|||
|
STATUS_INSUFFICIENT_RESOURCES - Memory could not be allocated for the
|
|||
|
string to be returned in.
|
|||
|
|
|||
|
Other status values that may be returned are those returned
|
|||
|
by:
|
|||
|
|
|||
|
NtOpenKey()
|
|||
|
NtQueryValueKey()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus, IgnoreStatus;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
UNICODE_STRING DomainKeyName, AccountKeyName;
|
|||
|
HANDLE TempHandle;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Get the membership count for this account
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampBuildAliasMembersKeyName(
|
|||
|
Account,
|
|||
|
&DomainKeyName,
|
|||
|
&AccountKeyName
|
|||
|
);
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjectAttributes,
|
|||
|
&AccountKeyName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
SampKey,
|
|||
|
NULL
|
|||
|
);
|
|||
|
NtStatus = RtlpNtOpenKey(
|
|||
|
&TempHandle,
|
|||
|
(KEY_READ),
|
|||
|
&ObjectAttributes,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
if ((NtStatus == STATUS_OBJECT_PATH_NOT_FOUND) ||
|
|||
|
(NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) ) {
|
|||
|
|
|||
|
//
|
|||
|
// This account is not a member of any of our aliases
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = STATUS_SUCCESS;
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(MemberCount)) {
|
|||
|
*MemberCount = 0;
|
|||
|
}
|
|||
|
if (ARGUMENT_PRESENT(BufferSize)) {
|
|||
|
*BufferSize = 0;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = RtlpNtQueryValueKey( TempHandle,
|
|||
|
MemberCount,
|
|||
|
Buffer,
|
|||
|
BufferSize,
|
|||
|
NULL);
|
|||
|
|
|||
|
IgnoreStatus = NtClose( TempHandle );
|
|||
|
ASSERT( NT_SUCCESS(IgnoreStatus) );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SampFreeUnicodeString( &DomainKeyName );
|
|||
|
SampFreeUnicodeString( &AccountKeyName );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return( NtStatus );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Services Private to this file //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampAddAccountToAlias(
|
|||
|
IN PSAMP_OBJECT AccountContext,
|
|||
|
IN PSID AccountSid
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service is used to add an account as a member of a specified alias
|
|||
|
This is done by simply adding the account SID to the list of SIDs
|
|||
|
in the MEMBERS attribute of the the specified alias
|
|||
|
|
|||
|
|
|||
|
The caller of this service is expected to be in the middle of a
|
|||
|
RXACT transaction. This service simply edits the in-memory copy of
|
|||
|
the alias information.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AliasRid - The RID of the alias the account is to be made a member of.
|
|||
|
|
|||
|
AccountSid - The Sid of the account being added as a new member.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - The account was added.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
ULONG MemberCount, i;
|
|||
|
ULONG MemberArraySize;
|
|||
|
PSID MemberArray;
|
|||
|
|
|||
|
|
|||
|
NtStatus = SampGetSidArrayAttribute(
|
|||
|
AccountContext,
|
|||
|
SAMP_ALIAS_MEMBERS,
|
|||
|
FALSE, // Reference directly
|
|||
|
&MemberArray,
|
|||
|
&MemberArraySize,
|
|||
|
&MemberCount
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
PSID MemberPointer = MemberArray;
|
|||
|
|
|||
|
//
|
|||
|
// Check the member is really new
|
|||
|
//
|
|||
|
|
|||
|
for (i = 0; i<MemberCount ; i++ ) {
|
|||
|
|
|||
|
if (RtlEqualSid(MemberPointer, AccountSid)) {
|
|||
|
|
|||
|
NtStatus = STATUS_MEMBER_IN_ALIAS;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
((PCHAR)MemberPointer) += RtlLengthSid(MemberPointer);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// MemberPointer now points at the byte beyond the end of the
|
|||
|
// old member array
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a new membership buffer large enough for the existing
|
|||
|
// member list and the new one.
|
|||
|
//
|
|||
|
|
|||
|
ULONG OldTotalSize = ((PCHAR)MemberPointer) - ((PCHAR)MemberArray);
|
|||
|
ULONG NewMemberSize = RtlLengthSid(AccountSid);
|
|||
|
ULONG NewTotalSize = OldTotalSize + NewMemberSize;
|
|||
|
PSID NewMemberArray;
|
|||
|
|
|||
|
|
|||
|
NewMemberArray = MIDL_user_allocate( NewTotalSize );
|
|||
|
|
|||
|
if (NewMemberArray == NULL) {
|
|||
|
|
|||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Copy the member list into the new array
|
|||
|
//
|
|||
|
|
|||
|
RtlCopyMemory(NewMemberArray, MemberArray, OldTotalSize);
|
|||
|
|
|||
|
//
|
|||
|
// Add the new member to the end
|
|||
|
//
|
|||
|
|
|||
|
MemberCount += 1;
|
|||
|
|
|||
|
NtStatus = RtlCopySid(
|
|||
|
NewMemberSize,
|
|||
|
((PCHAR)NewMemberArray) + OldTotalSize,
|
|||
|
AccountSid);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Update the alias with it's new member list
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampSetSidArrayAttribute(
|
|||
|
AccountContext,
|
|||
|
SAMP_ALIAS_MEMBERS,
|
|||
|
NewMemberArray,
|
|||
|
NewTotalSize,
|
|||
|
MemberCount
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// audit this, if necessary.
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus) &&
|
|||
|
SampDoAccountAuditing(AccountContext->DomainIndex)) {
|
|||
|
|
|||
|
UNICODE_STRING NameString;
|
|||
|
PSAMP_DEFINED_DOMAINS Domain;
|
|||
|
SAMP_OBJECT_TYPE ObjectType;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
Domain = &SampDefinedDomains[ AccountContext->DomainIndex ];
|
|||
|
|
|||
|
Status = SampLookupAccountName(
|
|||
|
AccountContext->TypeBody.Alias.Rid,
|
|||
|
&NameString,
|
|||
|
&ObjectType
|
|||
|
);
|
|||
|
|
|||
|
if ( !NT_SUCCESS( Status )) {
|
|||
|
RtlInitUnicodeString( &NameString, L"-" );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LsaIAuditSamEvent(
|
|||
|
STATUS_SUCCESS,
|
|||
|
SE_AUDITID_LOCAL_GROUP_ADD, // AuditId
|
|||
|
Domain->Sid, // Domain SID
|
|||
|
NULL, // Member Rid
|
|||
|
AccountSid, // Member sid
|
|||
|
&NameString, // Account Name
|
|||
|
&Domain->ExternalName, // Domain
|
|||
|
&AccountContext->TypeBody.Alias.Rid, // Account Rid
|
|||
|
NULL // Privileges used
|
|||
|
);
|
|||
|
|
|||
|
if ( NT_SUCCESS( Status )) {
|
|||
|
MIDL_user_free( NameString.Buffer );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free up the membership array we allocated
|
|||
|
//
|
|||
|
|
|||
|
MIDL_user_free( NewMemberArray );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampRemoveAccountFromAlias(
|
|||
|
IN PSAMP_OBJECT AccountContext,
|
|||
|
IN PSID AccountSid
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is used to Remove an account from a specified alias.
|
|||
|
This is done by simply Removing the user's Sid From the list of Sids
|
|||
|
in the MEMBERS sub-key of the the specified alias.
|
|||
|
|
|||
|
It is the caller's responsibility to know that the user is, in fact,
|
|||
|
currently a member of the alias.
|
|||
|
|
|||
|
|
|||
|
The caller of this service is expected to be in the middle of a
|
|||
|
RXACT transaction. This service simply adds some actions to that
|
|||
|
RXACT transaction.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AliasRid - The RID of the alias the account is to be removed from.
|
|||
|
|
|||
|
AccountSid - The SID of the account being Removed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
STATUS_SUCCESS - The user has been Removed.
|
|||
|
|
|||
|
STATUS_MEMBER_NOT_IN_ALIAS - The account was not a member of the alias.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
ULONG MemberCount, i;
|
|||
|
ULONG MemberArraySize;
|
|||
|
PSID MemberArray, Member, NextMember;
|
|||
|
|
|||
|
ULONG RemovedMemberSize = RtlLengthSid(AccountSid);
|
|||
|
|
|||
|
//
|
|||
|
// Get a copy of the current member array.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampGetSidArrayAttribute(
|
|||
|
AccountContext,
|
|||
|
SAMP_ALIAS_MEMBERS,
|
|||
|
TRUE, // Make copy
|
|||
|
&MemberArray,
|
|||
|
&MemberArraySize,
|
|||
|
&MemberCount
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// For each member sid, copy it from old to new member
|
|||
|
// arrays if it is not the sid we're trying to delete
|
|||
|
//
|
|||
|
|
|||
|
Member = MemberArray;
|
|||
|
|
|||
|
for (i = 0; i < MemberCount ; i++ ) {
|
|||
|
|
|||
|
NextMember = (PSID)(((PCHAR)Member) + RtlLengthSid(Member));
|
|||
|
|
|||
|
if (RtlEqualSid(Member, AccountSid)) {
|
|||
|
|
|||
|
//
|
|||
|
// Found the member to delete. Shift subsequent members
|
|||
|
//
|
|||
|
|
|||
|
while ((PCHAR)NextMember <
|
|||
|
(((PCHAR)MemberArray) + MemberArraySize)) {
|
|||
|
|
|||
|
*((PCHAR)Member)++ = *((PCHAR)NextMember)++;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Advance the old pointer
|
|||
|
//
|
|||
|
|
|||
|
Member = NextMember;
|
|||
|
|
|||
|
ASSERT((PCHAR)Member <= (((PCHAR)MemberArray) + MemberArraySize));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If nothing was removed, we didn't find the account
|
|||
|
//
|
|||
|
|
|||
|
if (i == MemberCount) {
|
|||
|
|
|||
|
NtStatus = STATUS_MEMBER_NOT_IN_ALIAS;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The member has been removed, write out the new member list
|
|||
|
//
|
|||
|
|
|||
|
ASSERT((PCHAR)Member ==
|
|||
|
(((PCHAR)MemberArray)) + MemberArraySize - RemovedMemberSize);
|
|||
|
|
|||
|
NtStatus = SampSetSidArrayAttribute(
|
|||
|
AccountContext,
|
|||
|
SAMP_ALIAS_MEMBERS,
|
|||
|
MemberArray,
|
|||
|
MemberArraySize - RemovedMemberSize,
|
|||
|
MemberCount - 1
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// audit this, if necessary.
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus) &&
|
|||
|
SampDoAccountAuditing(AccountContext->DomainIndex)) {
|
|||
|
|
|||
|
UNICODE_STRING NameString;
|
|||
|
SAMP_OBJECT_TYPE ObjectType;
|
|||
|
NTSTATUS Status;
|
|||
|
PSAMP_DEFINED_DOMAINS Domain;
|
|||
|
|
|||
|
Status = SampLookupAccountName(
|
|||
|
AccountContext->TypeBody.Alias.Rid,
|
|||
|
&NameString,
|
|||
|
&ObjectType
|
|||
|
);
|
|||
|
|
|||
|
if ( !NT_SUCCESS( Status )) {
|
|||
|
RtlInitUnicodeString( &NameString, L"-" );
|
|||
|
}
|
|||
|
|
|||
|
Domain = &SampDefinedDomains[ AccountContext->DomainIndex ];
|
|||
|
|
|||
|
LsaIAuditSamEvent(
|
|||
|
STATUS_SUCCESS,
|
|||
|
SE_AUDITID_LOCAL_GROUP_REM, // AuditId
|
|||
|
Domain->Sid, // Domain SID
|
|||
|
NULL, // Member Rid
|
|||
|
AccountSid, // Member sid
|
|||
|
&NameString, // Account Name
|
|||
|
&Domain->ExternalName, // Domain
|
|||
|
&AccountContext->TypeBody.Alias.Rid, // Account Rid
|
|||
|
NULL // Privileges used
|
|||
|
);
|
|||
|
|
|||
|
if ( NT_SUCCESS( Status )) {
|
|||
|
MIDL_user_free( NameString.Buffer );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free up the member array
|
|||
|
//
|
|||
|
|
|||
|
MIDL_user_free(MemberArray);
|
|||
|
}
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampAddAliasToAccountMembership(
|
|||
|
IN ULONG AliasRid,
|
|||
|
IN PSID AccountSid
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service adds the specified alias to the account's membership
|
|||
|
list. It is not assumed that the caller knows anything about
|
|||
|
the target account. In particular, the caller doesn't know whether
|
|||
|
the account exists or not, nor whether the account is already a member
|
|||
|
of the alias.
|
|||
|
|
|||
|
THIS SERVICE MUST BE CALLED WITH THE TRANSACTION DOMAIN SET.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AliasRid - The relative ID of the alias.
|
|||
|
|
|||
|
AccountSid - The SID of the account.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
STATUS_SUCCESS - The information has been updated and added to the
|
|||
|
RXACT.
|
|||
|
|
|||
|
STATUS_MEMBER_IN_ALIAS - The account is already a member of the
|
|||
|
specified alias.
|
|||
|
|
|||
|
Other status values that may be returned are those returned
|
|||
|
by:
|
|||
|
|
|||
|
NtOpenKey()
|
|||
|
NtQueryValueKey()
|
|||
|
RtlAddActionToRXact()
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus, IgnoreStatus;
|
|||
|
UNICODE_STRING DomainKeyName;
|
|||
|
UNICODE_STRING AccountKeyName;
|
|||
|
HANDLE TempHandle;
|
|||
|
ULONG MembershipCount, KeyValueLength;
|
|||
|
ULONG DomainRidCount;
|
|||
|
ULONG i;
|
|||
|
PULONG MembershipArray;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
BOOLEAN NewAccount;
|
|||
|
|
|||
|
//
|
|||
|
// Get the account membership
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Assume the account is a member of at least one of our aliases
|
|||
|
//
|
|||
|
|
|||
|
NewAccount = FALSE;
|
|||
|
|
|||
|
NtStatus = SampBuildAliasMembersKeyName(
|
|||
|
AccountSid,
|
|||
|
&DomainKeyName,
|
|||
|
&AccountKeyName
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Try to open the domain alias/members/(domain) key for this account
|
|||
|
//
|
|||
|
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjectAttributes,
|
|||
|
&DomainKeyName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
SampKey,
|
|||
|
NULL
|
|||
|
);
|
|||
|
NtStatus = RtlpNtOpenKey(
|
|||
|
&TempHandle,
|
|||
|
(KEY_READ),
|
|||
|
&ObjectAttributes,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the current domain rid count
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = RtlpNtQueryValueKey(
|
|||
|
TempHandle,
|
|||
|
&DomainRidCount,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
IgnoreStatus = NtClose(TempHandle);
|
|||
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|||
|
|
|||
|
//
|
|||
|
// No other accounts in this domain are members of any of our
|
|||
|
// aliases.
|
|||
|
//
|
|||
|
// Create a new key for this domain with no accounts (rids).
|
|||
|
//
|
|||
|
|
|||
|
NewAccount = TRUE;
|
|||
|
|
|||
|
DomainRidCount = 0; // No accounts yet
|
|||
|
|
|||
|
NtStatus = RtlAddActionToRXact(
|
|||
|
SampRXactContext,
|
|||
|
RtlRXactOperationSetValue,
|
|||
|
&DomainKeyName,
|
|||
|
DomainRidCount,
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Keep our domain count uptodate
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampAdjustAliasDomainsCount(TRUE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
if (!NewAccount) {
|
|||
|
|
|||
|
//
|
|||
|
// Try to open the domain alias/members/(domain)/(account) key
|
|||
|
//
|
|||
|
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjectAttributes,
|
|||
|
&AccountKeyName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
SampKey,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
NtStatus = RtlpNtOpenKey(
|
|||
|
&TempHandle,
|
|||
|
(KEY_READ),
|
|||
|
&ObjectAttributes,
|
|||
|
0
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (NewAccount || (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND)) {
|
|||
|
|
|||
|
//
|
|||
|
// This account is not a member of any of our aliases yet.
|
|||
|
//
|
|||
|
|
|||
|
NewAccount = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Set up it's initial membership
|
|||
|
//
|
|||
|
|
|||
|
MembershipCount = 1;
|
|||
|
MembershipArray = &AliasRid;
|
|||
|
|
|||
|
NtStatus = STATUS_SUCCESS; // We're doing fine
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus) && !NewAccount) {
|
|||
|
|
|||
|
//
|
|||
|
// This account already exists
|
|||
|
//
|
|||
|
// Get the current membership buffer and add the new alias
|
|||
|
//
|
|||
|
|
|||
|
KeyValueLength = 0;
|
|||
|
|
|||
|
NtStatus = RtlpNtQueryValueKey(
|
|||
|
TempHandle,
|
|||
|
&MembershipCount,
|
|||
|
NULL,
|
|||
|
&KeyValueLength,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus) || (NtStatus == STATUS_BUFFER_OVERFLOW)) {
|
|||
|
|
|||
|
ASSERT(KeyValueLength == (MembershipCount * sizeof(ULONG)));
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a membership buffer large enough for an
|
|||
|
// additional member.
|
|||
|
//
|
|||
|
|
|||
|
KeyValueLength += sizeof(ULONG);
|
|||
|
MembershipArray = MIDL_user_allocate( KeyValueLength );
|
|||
|
|
|||
|
if (MembershipArray == NULL) {
|
|||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
} else {
|
|||
|
|
|||
|
NtStatus = RtlpNtQueryValueKey(
|
|||
|
TempHandle,
|
|||
|
NULL,
|
|||
|
MembershipArray,
|
|||
|
&KeyValueLength,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// See if the account is already a member ...
|
|||
|
//
|
|||
|
|
|||
|
for (i = 0; i<MembershipCount ; i++ ) {
|
|||
|
if ( MembershipArray[i] == AliasRid ) {
|
|||
|
NtStatus = STATUS_MEMBER_IN_ALIAS;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Add the new alias's RID to the end
|
|||
|
//
|
|||
|
|
|||
|
MembershipCount += 1;
|
|||
|
MembershipArray[MembershipCount-1] = AliasRid;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Close the account key handle
|
|||
|
//
|
|||
|
|
|||
|
IgnoreStatus = NtClose( TempHandle );
|
|||
|
ASSERT( NT_SUCCESS(IgnoreStatus) );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We now have a new membership list desribed by :
|
|||
|
// MembershipArray, MembershipCount
|
|||
|
//
|
|||
|
// Write it out and free it up
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
KeyValueLength = MembershipCount * sizeof(ULONG);
|
|||
|
|
|||
|
NtStatus = RtlAddActionToRXact(
|
|||
|
SampRXactContext,
|
|||
|
RtlRXactOperationSetValue,
|
|||
|
&AccountKeyName,
|
|||
|
MembershipCount,
|
|||
|
MembershipArray,
|
|||
|
KeyValueLength
|
|||
|
);
|
|||
|
|
|||
|
if (MembershipArray != &AliasRid) {
|
|||
|
MIDL_user_free( MembershipArray );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this is a new account, we need to increment the rid count
|
|||
|
// in the account domain.
|
|||
|
//
|
|||
|
|
|||
|
if (NewAccount) {
|
|||
|
|
|||
|
//
|
|||
|
// Increment the domain rid count
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = RtlAddActionToRXact(
|
|||
|
SampRXactContext,
|
|||
|
RtlRXactOperationSetValue,
|
|||
|
&DomainKeyName,
|
|||
|
DomainRidCount + 1,
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
SampFreeUnicodeString( &DomainKeyName );
|
|||
|
SampFreeUnicodeString( &AccountKeyName );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return( NtStatus );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampRemoveAliasFromAccountMembership(
|
|||
|
IN ULONG AliasRid,
|
|||
|
IN PSID AccountSid
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service removes the specified alias from the account's membership
|
|||
|
list. It is not assumed that the caller knows anything about
|
|||
|
the target account. In particular, the caller doesn't know whether
|
|||
|
the account exists or not, nor whether the account is really a member
|
|||
|
of the alias.
|
|||
|
|
|||
|
This routine removes the reference to the alias from the account's
|
|||
|
membership list, removes the account key if there are no more aliases,
|
|||
|
and removes the domain-sid key if this is the last account in the
|
|||
|
domain.
|
|||
|
|
|||
|
THIS SERVICE MUST BE CALLED WITH THE TRANSACTION DOMAIN SET.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AliasRid - The relative ID of the alias.
|
|||
|
|
|||
|
AccountSid - The SID of the account.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
STATUS_SUCCESS - The information has been updated and added to the
|
|||
|
RXACT.
|
|||
|
|
|||
|
STATUS_NO_SUCH_USER - The account does not exist.
|
|||
|
|
|||
|
STATUS_MEMBER_NOT_IN_ALIAS - The account is not a member of the
|
|||
|
specified alias.
|
|||
|
|
|||
|
Other status values that may be returned are those returned
|
|||
|
by:
|
|||
|
|
|||
|
NtOpenKey()
|
|||
|
NtQueryValueKey()
|
|||
|
RtlAddActionToRXact()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus, IgnoreStatus;
|
|||
|
UNICODE_STRING DomainKeyName;
|
|||
|
UNICODE_STRING AccountKeyName;
|
|||
|
HANDLE TempHandle;
|
|||
|
ULONG MembershipCount, KeyValueLength, i;
|
|||
|
PULONG MembershipArray;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
|
|||
|
//
|
|||
|
// Get the account membership
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampBuildAliasMembersKeyName(
|
|||
|
AccountSid,
|
|||
|
&DomainKeyName,
|
|||
|
&AccountKeyName
|
|||
|
);
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjectAttributes,
|
|||
|
&AccountKeyName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
SampKey,
|
|||
|
NULL
|
|||
|
);
|
|||
|
NtStatus = RtlpNtOpenKey(
|
|||
|
&TempHandle,
|
|||
|
(KEY_READ),
|
|||
|
&ObjectAttributes,
|
|||
|
0
|
|||
|
);
|
|||
|
if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND ||
|
|||
|
NtStatus == STATUS_OBJECT_PATH_NOT_FOUND) {
|
|||
|
|
|||
|
NtStatus = STATUS_MEMBER_NOT_IN_ALIAS;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Retrieve the length of the membership buffer
|
|||
|
//
|
|||
|
|
|||
|
KeyValueLength = 0;
|
|||
|
|
|||
|
NtStatus = RtlpNtQueryValueKey(
|
|||
|
TempHandle,
|
|||
|
&MembershipCount,
|
|||
|
NULL,
|
|||
|
&KeyValueLength,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
ASSERT(MembershipCount == 0);
|
|||
|
|
|||
|
NtStatus = STATUS_MEMBER_NOT_IN_ALIAS;
|
|||
|
}
|
|||
|
|
|||
|
if (NtStatus == STATUS_BUFFER_OVERFLOW) {
|
|||
|
|
|||
|
ASSERT(MembershipCount != 0);
|
|||
|
ASSERT(KeyValueLength == (MembershipCount * sizeof(ULONG)));
|
|||
|
|
|||
|
MembershipArray = MIDL_user_allocate( KeyValueLength );
|
|||
|
|
|||
|
if (MembershipArray == NULL) {
|
|||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
} else {
|
|||
|
|
|||
|
NtStatus = RtlpNtQueryValueKey(
|
|||
|
TempHandle,
|
|||
|
NULL,
|
|||
|
MembershipArray,
|
|||
|
&KeyValueLength,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// See if the account is a member ...
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = STATUS_MEMBER_NOT_IN_ALIAS;
|
|||
|
|
|||
|
for (i = 0; i<MembershipCount ; i++ ) {
|
|||
|
if ( MembershipArray[i] == AliasRid ) {
|
|||
|
NtStatus = STATUS_SUCCESS;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Replace the removed alias information
|
|||
|
// with the last entry's information.
|
|||
|
// Then add it to the RXACT transaction
|
|||
|
// to be written out.
|
|||
|
//
|
|||
|
|
|||
|
MembershipCount -= 1;
|
|||
|
KeyValueLength -= sizeof(ULONG);
|
|||
|
|
|||
|
if (MembershipCount > 0) {
|
|||
|
|
|||
|
MembershipArray[i] = MembershipArray[MembershipCount];
|
|||
|
|
|||
|
ASSERT(KeyValueLength == (MembershipCount * sizeof(ULONG)));
|
|||
|
NtStatus = RtlAddActionToRXact(
|
|||
|
SampRXactContext,
|
|||
|
RtlRXactOperationSetValue,
|
|||
|
&AccountKeyName,
|
|||
|
MembershipCount,
|
|||
|
MembershipArray,
|
|||
|
KeyValueLength
|
|||
|
);
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// This is the last alias membership for
|
|||
|
// this account. Delete the keys.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampDeleteAliasMembershipKeysForAccount(
|
|||
|
AccountSid);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
MIDL_user_free( MembershipArray );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
IgnoreStatus = NtClose( TempHandle );
|
|||
|
ASSERT( NT_SUCCESS(IgnoreStatus) );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
SampFreeUnicodeString( &DomainKeyName );
|
|||
|
SampFreeUnicodeString( &AccountKeyName );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
return( NtStatus );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampRemoveAliasFromAllAccounts(
|
|||
|
IN PSAMP_OBJECT AliasContext
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service removes the specified alias from all account memberships
|
|||
|
|
|||
|
THIS SERVICE MUST BE CALLED WITH THE TRANSACTION DOMAIN SET.
|
|||
|
|
|||
|
This service leaves the alias membership list intact. It is assumed
|
|||
|
that the caller will delete the alias member list as part of the
|
|||
|
current transaction.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AliasRid - The relative ID of the alias.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
STATUS_SUCCESS - The information has been updated and added to the
|
|||
|
RXACT.
|
|||
|
|
|||
|
STATUS_NO_SUCH_ALIAS - The alias does not exist.
|
|||
|
|
|||
|
|
|||
|
Other status values that may be returned are those returned
|
|||
|
by:
|
|||
|
|
|||
|
NtOpenKey()
|
|||
|
NtQueryValueKey()
|
|||
|
RtlAddActionToRXact()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
ULONG MemberCount, i;
|
|||
|
PSID *MemberArray;
|
|||
|
|
|||
|
//
|
|||
|
// Get the list of members in this alias
|
|||
|
//
|
|||
|
|
|||
|
MemberArray = NULL;
|
|||
|
|
|||
|
NtStatus = SampRetrieveAliasMembers(
|
|||
|
AliasContext,
|
|||
|
&MemberCount,
|
|||
|
&MemberArray);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
ASSERT((MemberCount != 0) == (MemberArray != NULL));
|
|||
|
|
|||
|
//
|
|||
|
// Remove this alias from each of our members in turn
|
|||
|
//
|
|||
|
|
|||
|
for (i = 0; i < MemberCount ; i++ ) {
|
|||
|
|
|||
|
ULONG AliasRid = AliasContext->TypeBody.Alias.Rid;
|
|||
|
|
|||
|
NtStatus = SampRemoveAliasFromAccountMembership(AliasRid, MemberArray[i]);
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (MemberArray != NULL) {
|
|||
|
MIDL_user_free( MemberArray );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampRetrieveAliasMembers(
|
|||
|
IN PSAMP_OBJECT AliasContext,
|
|||
|
OUT PULONG MemberCount,
|
|||
|
OUT PSID **Members OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service retrieves the number of members in a alias. If desired,
|
|||
|
it will also retrieve an array of SIDs of the members of the alias.
|
|||
|
|
|||
|
THIS SERVICE MUST BE CALLED WITH THE TRANSACTION DOMAIN SET.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - Points to the account context whose alias members are to
|
|||
|
to be retrieved.
|
|||
|
|
|||
|
MemberCount - Receives the number of members currently in the alias.
|
|||
|
|
|||
|
Members - (Otional) Receives a pointer to a buffer containing an array
|
|||
|
of member PSIDs. If this value is NULL, then this information
|
|||
|
is not returned. The returned buffer is allocated using
|
|||
|
MIDL_user_allocate() and must be freed using MIDL_user_free() when
|
|||
|
no longer needed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
STATUS_SUCCESS - The information has been retrieved.
|
|||
|
|
|||
|
STATUS_INSUFFICIENT_RESOURCES - Memory could not be allocated for the
|
|||
|
string to be returned in.
|
|||
|
|
|||
|
Other status values that may be returned are those returned
|
|||
|
by:
|
|||
|
|
|||
|
NtOpenKey()
|
|||
|
NtQueryValueKey()
|
|||
|
|
|||
|
If this routine returns failure, *MemberCount will be zero and
|
|||
|
*Members will be NULL.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus;
|
|||
|
PSID MemberArray;
|
|||
|
ULONG MemberArraySize;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
|
|||
|
NtStatus = SampGetSidArrayAttribute(
|
|||
|
AliasContext,
|
|||
|
SAMP_ALIAS_MEMBERS,
|
|||
|
FALSE, // Reference directly
|
|||
|
&MemberArray,
|
|||
|
&MemberArraySize,
|
|||
|
MemberCount
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(Members)) {
|
|||
|
|
|||
|
//
|
|||
|
// Allocate memory for the sid array and sid data
|
|||
|
//
|
|||
|
|
|||
|
ULONG SidArraySize = *MemberCount * sizeof(PSID);
|
|||
|
ULONG SidDataSize = MemberArraySize;
|
|||
|
|
|||
|
if ( *MemberCount == 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// Nothing to copy, just return success.
|
|||
|
//
|
|||
|
|
|||
|
*Members = NULL;
|
|||
|
return( NtStatus );
|
|||
|
}
|
|||
|
|
|||
|
(*Members) = (PSID *)MIDL_user_allocate(SidArraySize + SidDataSize);
|
|||
|
|
|||
|
if ((*Members) == NULL) {
|
|||
|
|
|||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Copy the sid data into the last part of the block
|
|||
|
//
|
|||
|
|
|||
|
PSID SidData = (PSID)(&((*Members)[*MemberCount]));
|
|||
|
|
|||
|
RtlCopyMemory(SidData, MemberArray, MemberArraySize);
|
|||
|
|
|||
|
//
|
|||
|
// Fill in the sid pointer array
|
|||
|
//
|
|||
|
|
|||
|
for (i = 0; i < *MemberCount ; i++) {
|
|||
|
|
|||
|
(*Members)[i] = SidData;
|
|||
|
|
|||
|
((PCHAR)SidData) += RtlLengthSid(SidData);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(SidData == ((PCHAR)(*Members)) + SidArraySize + SidDataSize);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return( NtStatus );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampDeleteAliasKeys(
|
|||
|
IN PSAMP_OBJECT Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service deletes all registry keys related to a alias object.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - Points to the alias context whose registry keys are
|
|||
|
being deleted.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
STATUS_SUCCESS - The information has been retrieved.
|
|||
|
|
|||
|
|
|||
|
Other status values that may be returned by:
|
|||
|
|
|||
|
RtlAddActionToRXact()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus;
|
|||
|
ULONG Rid;
|
|||
|
UNICODE_STRING AccountName, KeyName;
|
|||
|
|
|||
|
|
|||
|
Rid = Context->TypeBody.Alias.Rid;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Aliases are arranged as follows:
|
|||
|
//
|
|||
|
// +-- Aliases [Count]
|
|||
|
// ---+--
|
|||
|
// +-- Names
|
|||
|
// | --+--
|
|||
|
// | +-- (AliasName) [AliasRid,]
|
|||
|
// |
|
|||
|
// +-- (AliasRid) [Revision,SecurityDescriptor]
|
|||
|
// ---+-----
|
|||
|
// +-- V1_Fixed [,SAM_V1_FIXED_LENGTH_ALIAS]
|
|||
|
// +-- Name [,Name]
|
|||
|
// +-- AdminComment [,unicode string]
|
|||
|
// +-- Members [Count,(Member0Sid, (...), MemberX-1Sid)]
|
|||
|
//
|
|||
|
// This all needs to be deleted from the bottom up.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Decrement the alias count
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampAdjustAccountCount(SampAliasObjectType, FALSE );
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Delete the registry key that has the alias's name to RID mapping.
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the name
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampGetUnicodeStringAttribute(
|
|||
|
Context,
|
|||
|
SAMP_ALIAS_NAME,
|
|||
|
TRUE, // Make copy
|
|||
|
&AccountName
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = SampBuildAccountKeyName(
|
|||
|
SampAliasObjectType,
|
|||
|
&KeyName,
|
|||
|
&AccountName
|
|||
|
);
|
|||
|
|
|||
|
SampFreeUnicodeString( &AccountName );
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = RtlAddActionToRXact(
|
|||
|
SampRXactContext,
|
|||
|
RtlRXactOperationDelete,
|
|||
|
&KeyName,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
SampFreeUnicodeString( &KeyName );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Delete the attribute keys
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = SampDeleteAttributeKeys(
|
|||
|
Context
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Delete the RID key
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = SampBuildAccountSubKeyName(
|
|||
|
SampAliasObjectType,
|
|||
|
&KeyName,
|
|||
|
Rid,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
|
|||
|
NtStatus = RtlAddActionToRXact(
|
|||
|
SampRXactContext,
|
|||
|
RtlRXactOperationDelete,
|
|||
|
&KeyName,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
SampFreeUnicodeString( &KeyName );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
return( NtStatus );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampDeleteAliasMembershipKeysForAccount(
|
|||
|
IN PSID AccountSid
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service deletes the alias membership keys for the specified account.
|
|||
|
|
|||
|
This account rid key is deleted. If this was the last account-rid for
|
|||
|
the domain then the domain keys is deleted also.
|
|||
|
|
|||
|
THIS SERVICE MUST BE CALLED WITH THE TRANSACTION DOMAIN SET.
|
|||
|
|
|||
|
It is assumed we are in the middle of a registry transaction.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AccountSid - The SID of the account.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
STATUS_SUCCESS - The transactions have been added.
|
|||
|
|
|||
|
Other status values that may be returned are those returned
|
|||
|
by:
|
|||
|
|
|||
|
NtOpenKey()
|
|||
|
NtQueryValueKey()
|
|||
|
RtlAddActionToRXact()
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus, IgnoreStatus;
|
|||
|
UNICODE_STRING DomainKeyName;
|
|||
|
UNICODE_STRING AccountKeyName;
|
|||
|
HANDLE TempHandle;
|
|||
|
ULONG MembershipCount;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
|
|||
|
//
|
|||
|
// Get the account membership key names
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampBuildAliasMembersKeyName(
|
|||
|
AccountSid,
|
|||
|
&DomainKeyName,
|
|||
|
&AccountKeyName
|
|||
|
);
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Delete the account rid key
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = RtlAddActionToRXact(
|
|||
|
SampRXactContext,
|
|||
|
RtlRXactOperationDelete,
|
|||
|
&AccountKeyName,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Adjust the rid count for the domain
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjectAttributes,
|
|||
|
&DomainKeyName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
SampKey,
|
|||
|
NULL
|
|||
|
);
|
|||
|
NtStatus = RtlpNtOpenKey(
|
|||
|
&TempHandle,
|
|||
|
(KEY_READ),
|
|||
|
&ObjectAttributes,
|
|||
|
0
|
|||
|
);
|
|||
|
ASSERT(NT_SUCCESS(NtStatus)); // We just opened a sub-key successfully !
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = RtlpNtQueryValueKey(
|
|||
|
TempHandle,
|
|||
|
&MembershipCount,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Decrement the rid count, write out or delete key if 0
|
|||
|
//
|
|||
|
|
|||
|
MembershipCount -= 1;
|
|||
|
if (MembershipCount > 0) {
|
|||
|
|
|||
|
//
|
|||
|
// Decrement the domain rid count
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = RtlAddActionToRXact(
|
|||
|
SampRXactContext,
|
|||
|
RtlRXactOperationSetValue,
|
|||
|
&DomainKeyName,
|
|||
|
MembershipCount,
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Delete the domain key
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = RtlAddActionToRXact(
|
|||
|
SampRXactContext,
|
|||
|
RtlRXactOperationDelete,
|
|||
|
&DomainKeyName,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Adjust the count of domain keys
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = SampAdjustAliasDomainsCount(FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Close the domain key handle
|
|||
|
//
|
|||
|
|
|||
|
IgnoreStatus = NtClose( TempHandle );
|
|||
|
ASSERT( NT_SUCCESS(IgnoreStatus) );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
SampFreeUnicodeString( &DomainKeyName );
|
|||
|
SampFreeUnicodeString( &AccountKeyName );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
return( NtStatus );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampAdjustAliasDomainsCount(
|
|||
|
IN BOOLEAN Increment
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service increments or decrements the number of domains that have
|
|||
|
at least one account that is a member of one of our aliases.
|
|||
|
|
|||
|
This value is contained in the type of \(domain)\ALIASES\MEMBERS
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Note: THIS ROUTINE REFERENCES THE CURRENT TRANSACTION DOMAIN
|
|||
|
(ESTABLISHED USING SampSetTransactioDomain()). THIS
|
|||
|
SERVICE MAY ONLY BE CALLED AFTER SampSetTransactionDomain()
|
|||
|
AND BEFORE SampReleaseWriteLock().
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Increment - TRUE to increment, FALSE to decrement
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - The value has been adjusted and the new value added
|
|||
|
to the current RXACT transaction.
|
|||
|
|
|||
|
STATUS_INSUFFICIENT_RESOURCES - Not enough memory could be allocated
|
|||
|
to perform the requested operation.
|
|||
|
|
|||
|
Other values are unexpected errors. These may originate from
|
|||
|
internal calls to:
|
|||
|
|
|||
|
NtOpenKey()
|
|||
|
NtQueryInformationKey()
|
|||
|
RtlAddActionToRXact()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Don't maintain a count of domains for now
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
|
|||
|
DBG_UNREFERENCED_PARAMETER(Increment);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampValidateNewAliasMember(
|
|||
|
IN PSID MemberId
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service checks the passed Sid is acceptable as a potential new
|
|||
|
member of one of the aliases in the current domain.
|
|||
|
|
|||
|
Note: THIS ROUTINE REFERENCES THE CURRENT TRANSACTION DOMAIN
|
|||
|
(ESTABLISHED USING SampSetTransactioDomain()). THIS
|
|||
|
SERVICE MAY ONLY BE CALLED AFTER SampSetTransactionDomain()
|
|||
|
AND BEFORE SampReleaseWriteLock().
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
MemberId - the full Sid of the member to validate
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - MemberId is a valid potential alias member
|
|||
|
|
|||
|
STATUS_INVALID_MEMBER - MemberId has the wrong account type.
|
|||
|
|
|||
|
STATUS_NO_SUCH_MEMBER - MemberId is not a valid account.
|
|||
|
|
|||
|
STATUS_INVALID_SID - MemberId is not a valid sid.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
PSID MemberDomainSid = NULL, CurrentDomainSid = NULL;
|
|||
|
ULONG MemberRid;
|
|||
|
SAMP_OBJECT_TYPE MemberType;
|
|||
|
|
|||
|
//
|
|||
|
// Check the new member sid for structural soundness
|
|||
|
//
|
|||
|
|
|||
|
if ((MemberId == NULL) || !RtlValidSid(MemberId)) {
|
|||
|
return(STATUS_INVALID_SID);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Get the current domain sid
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(SampTransactionWithinDomain);
|
|||
|
CurrentDomainSid = SampDefinedDomains[SampTransactionDomainIndex].Sid;
|
|||
|
|
|||
|
//
|
|||
|
// Break up the new member into domain and rid
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampSplitSid(MemberId, &MemberDomainSid, &MemberRid);
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the member isn't from this domain, then they're OK.
|
|||
|
//
|
|||
|
|
|||
|
if (!RtlEqualSid(CurrentDomainSid, MemberDomainSid)) {
|
|||
|
|
|||
|
NtStatus = STATUS_SUCCESS;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The member is in our domain - check that the type of
|
|||
|
// account is acceptable.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampLookupAccountName(
|
|||
|
MemberRid,
|
|||
|
NULL,
|
|||
|
&MemberType
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
switch (MemberType) {
|
|||
|
case SampUserObjectType:
|
|||
|
case SampGroupObjectType:
|
|||
|
NtStatus = STATUS_SUCCESS;
|
|||
|
break;
|
|||
|
|
|||
|
case SampUnknownObjectType:
|
|||
|
NtStatus = STATUS_NO_SUCH_MEMBER;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
NtStatus = STATUS_INVALID_MEMBER;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
MIDL_user_free(MemberDomainSid);
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampChangeAliasAccountName(
|
|||
|
IN PSAMP_OBJECT Context,
|
|||
|
IN PUNICODE_STRING NewAccountName,
|
|||
|
OUT PUNICODE_STRING OldAccountName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine changes the account name of an alias account.
|
|||
|
|
|||
|
THIS SERVICE MUST BE CALLED WITH THE TRANSACTION DOMAIN SET.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - Points to the account context whose name is to be changed.
|
|||
|
|
|||
|
NewAccountName - New name to give this account
|
|||
|
|
|||
|
OldAccountName - old name is returned here. The buffer should be freed
|
|||
|
by calling MIDL_user_free.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
STATUS_SUCCESS - The information has been retrieved.
|
|||
|
|
|||
|
|
|||
|
Other status values that may be returned by:
|
|||
|
|
|||
|
SampGetUnicodeStringAttribute()
|
|||
|
SampSetUnicodeStringAttribute()
|
|||
|
SampValidateAccountNameChange()
|
|||
|
RtlAddActionToRXact()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus;
|
|||
|
UNICODE_STRING KeyName;
|
|||
|
|
|||
|
|
|||
|
/////////////////////////////////////////////////////////////
|
|||
|
// There are two copies of the name of each account. //
|
|||
|
// one is under the DOMAIN\(domainName)\ALIAS\NAMES key, //
|
|||
|
// one is the value of the //
|
|||
|
// DOMAIN\(DomainName)\ALIAS\(rid)\NAME key //
|
|||
|
/////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Get the current name so we can delete the old Name->Rid
|
|||
|
// mapping key.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampGetUnicodeStringAttribute(
|
|||
|
Context,
|
|||
|
SAMP_ALIAS_NAME,
|
|||
|
TRUE, // Make copy
|
|||
|
OldAccountName
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Make sure the name is valid and not already in use
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = SampValidateAccountNameChange(
|
|||
|
NewAccountName,
|
|||
|
OldAccountName
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Delete the old name key
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = SampBuildAccountKeyName(
|
|||
|
SampAliasObjectType,
|
|||
|
&KeyName,
|
|||
|
OldAccountName
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = RtlAddActionToRXact(
|
|||
|
SampRXactContext,
|
|||
|
RtlRXactOperationDelete,
|
|||
|
&KeyName,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
SampFreeUnicodeString( &KeyName );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// Create the new Name->Rid mapping key
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = SampBuildAccountKeyName(
|
|||
|
SampAliasObjectType,
|
|||
|
&KeyName,
|
|||
|
NewAccountName
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
ULONG AliasRid = Context->TypeBody.Alias.Rid;
|
|||
|
|
|||
|
NtStatus = RtlAddActionToRXact(
|
|||
|
SampRXactContext,
|
|||
|
RtlRXactOperationSetValue,
|
|||
|
&KeyName,
|
|||
|
AliasRid,
|
|||
|
(PVOID)NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
SampFreeUnicodeString( &KeyName );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// replace the account's name
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
NtStatus = SampSetUnicodeStringAttribute(
|
|||
|
Context,
|
|||
|
SAMP_ALIAS_NAME,
|
|||
|
NewAccountName
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free up the old account name if we failed
|
|||
|
//
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
SampFreeUnicodeString(OldAccountName);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
}
|