Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4232 lines
114 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
dbaccnt.c
Abstract:
LSA - Database - Account Object Private API Workers
NOTE: This module should remain as portable code that is independent
of the implementation of the LSA Database. As such, it is
permitted to use only the exported LSA Database interfaces
contained in db.h and NOT the private implementation
dependent functions in dbp.h.
Author:
Scott Birrell (ScottBi) April 29, 1991
Environment:
Revision History:
--*/
#include <lsapch2.h>
#include "dbp.h"
/////////////////////////////////////////////////////////////////////////////
// //
// Private Datatypes //
// //
/////////////////////////////////////////////////////////////////////////////
//
// The following structures define output for the LsarQueryInformationAccount()
// API. Curerently, this API is internal. If made external, these structures
// should be moved to lsarpc.idl and annotated with MIDL qualifiers [..].
//
//
// This data type defines the following information classes that may be
// queried or set.
//
typedef enum _ACCOUNT_INFORMATION_CLASS {
AccountSystemAccessInformation = 1,
AccountPrivilegeInformation,
AccountQuotaInformation
} ACCOUNT_INFORMATION_CLASS, *PACCOUNT_INFORMATION_CLASS;
typedef PRIVILEGE_SET LSAPR_ACCOUNT_PRIVILEGE_INFO;
typedef QUOTA_LIMITS LSAPR_ACCOUNT_QUOTA_INFO;
typedef ULONG LSAPR_ACCOUNT_SYSTEM_ACCESS_INFO;
typedef union _LSAPR_ACCOUNT_INFO {
LSAPR_ACCOUNT_PRIVILEGE_INFO AccountPrivilegeInfo;
LSAPR_ACCOUNT_QUOTA_INFO AccountQuotaInfo;
LSAPR_ACCOUNT_SYSTEM_ACCESS_INFO AccountSystemAccessInfo;
} LSAPR_ACCOUNT_INFO, *PLSAPR_ACCOUNT_INFO;
#define LsapDbFirstAccount() \
((PLSAP_DB_ACCOUNT) LsapDbAccountList.Links.Flink)
#define LsapDbNextAccount( Account ) \
((PLSAP_DB_ACCOUNT) Account->Links.Flink)
#define LSAP_DB_BUILD_ACCOUNT_LIST_LENGTH ((ULONG) 0x00001000L)
/////////////////////////////////////////////////////////////////////////////
// //
// Private Function Prototypes //
// //
/////////////////////////////////////////////////////////////////////////////
NTSTATUS
LsarQueryInformationAccount(
IN LSAPR_HANDLE AccountHandle,
IN ACCOUNT_INFORMATION_CLASS InformationClass,
OUT PLSAPR_ACCOUNT_INFO *AccountInformation
);
NTSTATUS
LsapDbQueryInformationAccount(
IN LSAPR_HANDLE AccountHandle,
IN ACCOUNT_INFORMATION_CLASS InformationClass,
OUT PLSAPR_ACCOUNT_INFO *AccountInformation
);
NTSTATUS
LsapDbQueryAllInformationAccounts(
IN LSAPR_HANDLE PolicyHandle,
IN ULONG IdCount,
IN PSID_AND_ATTRIBUTES Ids,
OUT PLSAP_DB_ACCOUNT_TYPE_SPECIFIC_INFO AccountInfo
);
NTSTATUS
LsapDbSlowQueryAllInformationAccounts(
IN LSAPR_HANDLE PolicyHandle,
IN ULONG IdCount,
IN PSID_AND_ATTRIBUTES Ids,
OUT PLSAP_DB_ACCOUNT_TYPE_SPECIFIC_INFO AccountInfo
);
NTSTATUS
LsapDbSlowQueryInformationAccount(
IN LSAPR_HANDLE AccountHandle,
IN ACCOUNT_INFORMATION_CLASS InformationClass,
OUT PLSAPR_ACCOUNT_INFO *AccountInformation
);
NTSTATUS
LsapDbSlowQueryPrivilegesAccount(
IN LSAPR_HANDLE AccountHandle,
OUT PLSAPR_PRIVILEGE_SET *Privileges
);
NTSTATUS
LsapDbSlowQueryQuotasAccount(
IN LSAPR_HANDLE AccountHandle,
OUT PQUOTA_LIMITS QuotaLimits
);
NTSTATUS
LsapDbSlowQuerySystemAccessAccount(
IN LSAPR_HANDLE AccountHandle,
OUT PULONG SystemAccess
);
NTSTATUS
LsapDbLookupAccount(
IN PSID AccountSid,
OUT PLSAP_DB_ACCOUNT *Account
);
NTSTATUS
LsapDbUpdateSystemAccessAccount(
IN PLSAPR_SID AccountSid,
IN PULONG SystemAccess
);
NTSTATUS
LsapDbUpdatePrivilegesAccount(
IN PLSAPR_SID AccountSid,
IN OPTIONAL PPRIVILEGE_SET Privileges
);
NTSTATUS
LsapDbUpdateQuotasAccount(
IN PLSAPR_SID AccountSid,
IN PQUOTA_LIMITS QuotaLimits
);
NTSTATUS
LsapDbCreateAccountList(
OUT PLSAP_DB_ACCOUNT_LIST AccountList
);
/////////////////////////////////////////////////////////////////////////////
// //
// Private Global Data //
// //
/////////////////////////////////////////////////////////////////////////////
LSAP_DB_ACCOUNT_LIST LsapDbAccountList;
/////////////////////////////////////////////////////////////////////////////
// //
// Code //
// //
/////////////////////////////////////////////////////////////////////////////
NTSTATUS
LsarCreateAccount(
IN LSAPR_HANDLE PolicyHandle,
IN PLSAPR_SID AccountSid,
IN ACCESS_MASK DesiredAccess,
OUT PLSAPR_HANDLE AccountHandle
)
/*++
Routine Description:
This function is the LSA server RPC worker routine for the
LsaCreateAccount API.
The LsaCreateAccount API creates a new Account Object. The account will
be opened with the specified accesses granted. The caller must
have POLICY_CREATE_ACCOUNT access to the Policy Object.
Note that no verification is done to ensure the SID actually represents
a valid user, group or alias in any trusted domain.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call.
AccountSid - Points to the SID of the account.
DesiredAccess - Specifies the accesses to be granted to the newly
created and opened account at this time.
AccountHandle - Receives a handle referencing the newly created
account. This handle is used on subsequent accesses to the
account object.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
to complete the operation.
STATUS_OBJECT_NAME_EXISTS - An account object having the given Sid
already exists and has been opened because LSA_OBJECT_OPEN_IF
disposition has been specified. This is a warning only.
STATUS_OBJECT_NAME_COLLISION - An account object having the given Sid
already exists but has not been opened because LSA_OBJECT_CREATE
disposition has been specified. This is an error.
STATUS_INVALID_PARAMETER - An invalid parameter has been specified.
--*/
{
NTSTATUS Status;
LSAP_DB_OBJECT_INFORMATION ObjectInformation;
LSAP_DB_ATTRIBUTE Attributes[LSAP_DB_ATTRS_ACCOUNT];
PLSAP_DB_ATTRIBUTE NextAttribute;
UNICODE_STRING LogicalNameU;
ULONG AttributeCount;
BOOLEAN ContainerReferenced = FALSE;
LsarpReturnCheckSetup();
LsapDsDebugOut(( DEB_FTRACE, "LsarCreateAccount\n" ));
LogicalNameU.Length = 0;
//
// Set up the object's attributes specific to the Account object type.
// These are the Account Type and the Sid.
//
AttributeCount = 0;
NextAttribute = Attributes;
//
// Validate the Account Sid.
//
if (!RtlValidSid( (PSID) AccountSid )) {
Status = STATUS_INVALID_PARAMETER;
goto CreateAccountError;
}
Status = LsapDbMakeSidAttributeDs(
AccountSid,
Sid,
NextAttribute
);
if (!NT_SUCCESS(Status)) {
goto CreateAccountError;
}
AttributeCount++;
NextAttribute++;
//
// Acquire the Lsa Database lock. Verify that the PolicyHandle
// is valid and has the necessary access granted. Reference the Policy
// Object handle (as container object).
//
Status = LsapDbReferenceObject(
PolicyHandle,
POLICY_CREATE_ACCOUNT,
PolicyObject,
AccountObject,
LSAP_DB_LOCK | LSAP_DB_NO_DS_OP_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION
);
if (!NT_SUCCESS(Status)) {
goto CreateAccountError;
}
ContainerReferenced = TRUE;
//
// Construct the Logical Name (Internal LSA Database Name) of the
// account object. The Logical Name is constructed from the account
// Sid by extracting the Relative Id (lowest subauthority) and converting
// it to an 8-digit numeric Unicode String in which leading zeros are
// added if needed.
//
Status = LsapDbSidToLogicalNameObject(AccountSid, &LogicalNameU);
if (!NT_SUCCESS(Status)) {
goto CreateAccountError;
}
//
// Fill in the ObjectInformation structure. Initialize the
// embedded Object Attributes with the PolicyHandle as the
// Root Directory (Container Object) handle and the Logical Name
// of the account. Store the types of the object and its container.
//
InitializeObjectAttributes(
&ObjectInformation.ObjectAttributes,
&LogicalNameU,
OBJ_CASE_INSENSITIVE,
PolicyHandle,
NULL
);
ObjectInformation.ObjectTypeId = AccountObject;
ObjectInformation.ContainerTypeId = PolicyObject;
ObjectInformation.Sid = AccountSid;
ObjectInformation.ObjectAttributeNameOnly = FALSE;
ObjectInformation.DesiredObjectAccess = DesiredAccess;
//
// Create the Account Object. We fail if the object already exists.
// Note that the object create routine performs a Database transaction.
// If caching is supported, the object will also be added to the cache.
//
Status = LsapDbCreateObject(
&ObjectInformation,
DesiredAccess,
LSAP_DB_OBJECT_CREATE,
0,
Attributes,
&AttributeCount,
RTL_NUMBER_OF(Attributes),
AccountHandle
);
if (!NT_SUCCESS(Status)) {
goto CreateAccountError;
}
CreateAccountFinish:
//
// If necessary, release the LSA Database lock.
//
if (ContainerReferenced) {
LsapDbApplyTransaction( PolicyHandle,
LSAP_DB_NO_DS_OP_TRANSACTION |
LSAP_DB_READ_ONLY_TRANSACTION,
(SECURITY_DB_DELTA_TYPE) 0 );
LsapDbReleaseLockEx( AccountObject,
LSAP_DB_READ_ONLY_TRANSACTION );
}
//
// If necessary, free the Unicode String buffer allocated for the Logical Name
//
if (LogicalNameU.Length > 0) {
RtlFreeUnicodeString(&LogicalNameU);
}
LsarpReturnPrologue();
LsapDsDebugOut(( DEB_FTRACE, "LsarCreateAccount: 0x%lx\n", Status ));
return( Status );
CreateAccountError:
//
// If necessary, dereference the Container Object, release the LSA
// Database Lock and return.
//
if (ContainerReferenced) {
Status = LsapDbDereferenceObject(
&PolicyHandle,
PolicyObject,
AccountObject,
LSAP_DB_LOCK | LSAP_DB_NO_DS_OP_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION,
(SECURITY_DB_DELTA_TYPE) 0,
Status
);
ContainerReferenced = FALSE;
}
goto CreateAccountFinish;
}
NTSTATUS
LsarOpenAccount(
IN LSAPR_HANDLE PolicyHandle,
IN PLSAPR_SID AccountSid,
IN ACCESS_MASK DesiredAccess,
OUT PLSAPR_HANDLE AccountHandle
)
/*++
Routine Description:
This function is the LSA server RPC worker routine for the LsaOpenAccount
API.
The LsaOpenAccount API opens an account object in the Lsa Database of the
target system. An account must be opened before any operation can be
performed, including deletion of the account. A handle to the account
object is returned for use on subsequent API calls that access the
account. Before calling this API, the caller must have connected to
the target system's LSA and opened the LsaDatabase object by means
of a preceding call to LsaOpenPolicy.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call.
AccountSid - Pointer to the account's Sid.
DesiredAccess - This is an access mask indicating accesses being
requested for the Account object. These access types
are reconciled with the Discretionary Access Control List of the
object to determine whether the accesses will be granted or denied.
AccountHandle - Pointer to location in which a handle to the opened
account object will be returned if the call succeeds.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
to complete the operation.
STATUS_OBJECT_NAME_NOT_FOUND - There is no account object in the
target system's LSA Database having the specified AccountSid.
--*/
{
NTSTATUS Status;
LSAP_DB_OBJECT_INFORMATION ObjectInformation;
UNICODE_STRING LogicalNameU;
BOOLEAN ContainerReferenced = FALSE;
BOOLEAN AcquiredLock = FALSE;
LsarpReturnCheckSetup();
LsapDsDebugOut(( DEB_FTRACE, "LsarOpenAccount\n" ));
//
// Validate the Account Sid.
//
if (!RtlValidSid( AccountSid )) {
Status = STATUS_INVALID_PARAMETER;
goto OpenAccountError;
}
//
// Acquire the Lsa Database lock. Verify that the connection handle
// (container object handle) is valid, and is of the expected type.
// Reference the container object handle. This reference remains in
// effect until the child object handle is closed.
//
// We can't check access on the policy handle. Too many applications
// rely on no access being acquired.
//
Status = LsapDbReferenceObject(
PolicyHandle,
0,
PolicyObject,
AccountObject,
LSAP_DB_LOCK |
LSAP_DB_NO_DS_OP_TRANSACTION |
LSAP_DB_READ_ONLY_TRANSACTION
);
if (!NT_SUCCESS(Status)) {
goto OpenAccountError;
}
AcquiredLock = TRUE;
ContainerReferenced =TRUE;
//
// Setup Object Information prior to calling the Object
// Open routine. The Object Type, Container Object Type and
// Logical Name (derived from the Sid) need to be filled in.
//
ObjectInformation.ObjectTypeId = AccountObject;
ObjectInformation.ContainerTypeId = PolicyObject;
ObjectInformation.Sid = AccountSid;
ObjectInformation.ObjectAttributeNameOnly = FALSE;
ObjectInformation.DesiredObjectAccess = DesiredAccess;
//
// Construct the Logical Name (Internal LSA Database Name) of the
// account object. The Logical Name is constructed from the account
// Sid by extracting the Relative Id (lowest subauthority) and converting
// it to an 8-digit numeric Unicode String in which leading zeros are
// added if needed.
//
Status = LsapDbSidToLogicalNameObject(AccountSid,&LogicalNameU);
if (!NT_SUCCESS(Status)) {
goto OpenAccountError;
}
//
// Initialize the Object Attributes. The Container Object Handle and
// Logical Name (Internal Name) of the object must be set up.
//
InitializeObjectAttributes(
&ObjectInformation.ObjectAttributes,
&LogicalNameU,
0,
PolicyHandle,
NULL
);
//
// Open the specific account object. Note that the account object
// handle returned is an RPC Context Handle.
//
Status = LsapDbOpenObject(
&ObjectInformation,
DesiredAccess,
0,
AccountHandle
);
RtlFreeUnicodeString( &LogicalNameU );
if (!NT_SUCCESS(Status)) {
goto OpenAccountError;
}
OpenAccountFinish:
//
// If necessary, release the LSA Database lock.
//
if (AcquiredLock) {
LsapDbApplyTransaction( PolicyHandle,
LSAP_DB_NO_DS_OP_TRANSACTION |
LSAP_DB_READ_ONLY_TRANSACTION,
(SECURITY_DB_DELTA_TYPE) 0 );
LsapDbReleaseLockEx( AccountObject,
LSAP_DB_READ_ONLY_TRANSACTION );
AcquiredLock = FALSE;
}
LsarpReturnPrologue();
LsapDsDebugOut(( DEB_FTRACE, "LsarOpenAccount: 0x%lx\n", Status ));
return( Status );
OpenAccountError:
//
// If necessary, dereference the Container Object handle. Note that
// this is only done in the error case. In the non-error case, the
// Container handle stays referenced until the Account object is
// closed.
//
if (ContainerReferenced) {
*AccountHandle = NULL;
Status = LsapDbDereferenceObject(
&PolicyHandle,
PolicyObject,
AccountObject,
LSAP_DB_LOCK | LSAP_DB_NO_DS_OP_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION,
(SECURITY_DB_DELTA_TYPE) 0,
Status
);
ContainerReferenced = FALSE;
AcquiredLock = FALSE;
}
goto OpenAccountFinish;
}
NTSTATUS
LsarEnumerateAccounts(
IN LSAPR_HANDLE PolicyHandle,
IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext,
OUT PLSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer,
IN ULONG PreferedMaximumLength
)
/*++
Routine Description:
This function is the LSA server RPC worker routine for the
LsaEnumerateAccounts API.
The LsaEnumerateAccounts API returns information about the accounts
in the target system's Lsa Database. This call requires
POLICY_VIEW_LOCAL_INFORMATION access to the Policy object. Since there
may be more information than can be returned in a single call of the
routine, multiple calls can be made to get all of the information. To
support this feature, the caller is provided with a handle that can be
used across calls to the API. On the initial call, EnumerationContext
should point to a variable that has been initialized to 0. On each
subsequent call, the value returned by the preceding call should be passed
in unchanged. The enumeration is complete when the warning
STATUS_NO_MORE_ENTRIES is returned.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call.
EnumerationContext - API-specific handle to allow multiple calls
(see Routine Description above).
EnumerationBuffer - Pointer to an enumeration structure that will receive
a count of the accounts enumerated on this call and a pointer to
an array of entries containing information for each enumerated
account.
PreferedMaximumLength - Prefered maximum length of returned data (in 8-bit
bytes). This is not a hard upper limit, but serves as a guide. Due to
data conversion between systems with different natural data sizes, the
actual amount of data returned may be greater than this value.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
to complete the operation.
STATUS_NO_MORE_ENTRIES - There are no more entries. This warning
is returned if no objects are enumerated because the
EnumerationContext value passed in is too high.
--*/
{
NTSTATUS Status;
LSAP_DB_SID_ENUMERATION_BUFFER DbEnumerationBuffer;
ULONG MaxLength;
LsarpReturnCheckSetup();
LsapDsDebugOut(( DEB_FTRACE, "LsarEnumerateAccounts\n" ));
//
// If no Enumeration Structure or index is provided, return an error.
//
if ( !ARGUMENT_PRESENT(EnumerationBuffer) ||
!ARGUMENT_PRESENT(EnumerationContext) ) {
return(STATUS_INVALID_PARAMETER);
}
//
// Initialize the internal Lsa Database Enumeration Buffer, and
// the provided Enumeration Buffer to NULL.
//
DbEnumerationBuffer.EntriesRead = 0;
DbEnumerationBuffer.Sids = NULL;
EnumerationBuffer->EntriesRead = 0;
EnumerationBuffer->Information = NULL;
//
// Bug #340164: anonymous users are not allowed to look at accounts
//
if ( LsapGlobalRestrictAnonymous &&
PolicyHandle != NULL &&
((LSAP_DB_HANDLE)PolicyHandle)->Options & LSAP_DB_OPENED_BY_ANONYMOUS ) {
return STATUS_ACCESS_DENIED;
}
//
// Acquire the Lsa Database lock. Verify that the connection handle is
// valid, is of the expected type and has all of the desired accesses
// granted. Reference the handle.
//
Status = LsapDbReferenceObject(
PolicyHandle,
POLICY_VIEW_LOCAL_INFORMATION,
PolicyObject,
AccountObject,
LSAP_DB_LOCK |
LSAP_DB_NO_DS_OP_TRANSACTION |
LSAP_DB_READ_ONLY_TRANSACTION
);
if ( NT_SUCCESS( Status )) {
//
// Limit the enumeration length except for trusted callers
//
if ( !((LSAP_DB_HANDLE)PolicyHandle)->Trusted &&
(PreferedMaximumLength > LSA_MAXIMUM_ENUMERATION_LENGTH)
) {
MaxLength = LSA_MAXIMUM_ENUMERATION_LENGTH;
} else {
MaxLength = PreferedMaximumLength;
}
//
// Call general Sid enumeration routine.
//
Status = LsapDbEnumerateSids(
PolicyHandle,
AccountObject,
EnumerationContext,
&DbEnumerationBuffer,
MaxLength
);
LsapDbDereferenceObject(
&PolicyHandle,
PolicyObject,
AccountObject,
LSAP_DB_LOCK |
LSAP_DB_NO_DS_OP_TRANSACTION |
LSAP_DB_READ_ONLY_TRANSACTION,
(SECURITY_DB_DELTA_TYPE) 0,
Status
);
}
//
// Copy the enumerated information to the output. We can use the
// information actually returned by LsapDbEnumerateSids because it
// happens to be in exactly the correct form.
//
EnumerationBuffer->EntriesRead = DbEnumerationBuffer.EntriesRead;
EnumerationBuffer->Information = (PLSAPR_ACCOUNT_INFORMATION) DbEnumerationBuffer.Sids;
LsarpReturnPrologue();
LsapDsDebugOut(( DEB_FTRACE, "LsarEnumerateAccounts:0x%lx\n", Status ));
return(Status);
}
NTSTATUS
LsarEnumeratePrivilegesAccount(
IN LSAPR_HANDLE AccountHandle,
OUT PLSAPR_PRIVILEGE_SET *Privileges
)
/*++
Routine Description:
This function is the LSA server RPC worker routine for the
LsaEnumeratePrivilegesOfAccount API.
The LsaEnumeratePrivilegesOfAccount API obtains information which
describes the privileges assigned to an account. This call requires
ACCOUNT_VIEW access to the account object.
Arguments:
AccountHandle - The handle to the open account object whose privilege
information is to be obtained. This handle will have been returned
from a prior LsaOpenAccount or LsaCreateAccountInLsa API call.
Privileges - Receives a pointer to a buffer containing the Privilege
Set. The Privilege Set is an array of structures, one for each
privilege. Each structure contains the LUID of the privilege and
a mask of the privilege's attributes.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_SUCCESS - The call completed successfully.
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
to complete the operation.
STATUS_INVALID_HANDLE - The specified AccountHandle is not valid.
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
such as memory, to complete the call.
--*/
{
return(LsarQueryInformationAccount(
AccountHandle,
AccountPrivilegeInformation,
(PLSAPR_ACCOUNT_INFO *) Privileges
));
}
NTSTATUS
LsarAddPrivilegesToAccount(
IN LSAPR_HANDLE AccountHandle,
IN PLSAPR_PRIVILEGE_SET Privileges
)
/*++
Routine Description:
This function is the LSA server RPC worker routine for the
LsaAddPrivilegesToAccount API.
The LsaAddPrivilegesToAccount API adds privileges and their attributes
to an account object. If any provided privilege is already assigned
to the account object, the attributes of that privilege are replaced
by the newly rpovided values. This API call requires
ACCOUNT_ADJUST_PRIVILEGES access to the account object.
Arguments:
AccountHandle - The handle to the open account object to which
privileges are to be added. This handle will have been returned
from a prior LsaOpenAccount or LsaCreateAccountInLsa API call.
Privileges - Points to a set of privileges (and their attributes) to
be assigned to the account.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
to complete the operation.
STATUS_INVALID_HANDLE - The specified AccountHandle is not valid.
--*/
{
return LsapAddPrivilegesToAccount( AccountHandle, Privileges, TRUE );
}
NTSTATUS
LsapAddPrivilegesToAccount(
IN LSAPR_HANDLE AccountHandle,
IN PLSAPR_PRIVILEGE_SET Privileges,
IN BOOL LockSce
)
/*++
Routine Description:
This is the worker routine for LsarAddPrivilegesToAccount, with an added
semantics of not locking the SCE policy.
--*/
{
NTSTATUS Status;
LsarpReturnCheckSetup();
LsapDsDebugOut(( DEB_FTRACE, "LsapAddPrivilegesToAccount\n" ));
Status = LsapDbChangePrivilegesAccount( AccountHandle,
AddPrivileges,
FALSE,
(PPRIVILEGE_SET) Privileges,
LockSce );
LsarpReturnPrologue();
LsapDsDebugOut(( DEB_FTRACE, "LsapAddPrivilegesToAccount: 0x%lx\n", Status ));
return( Status );
}
NTSTATUS
LsarRemovePrivilegesFromAccount(
IN LSAPR_HANDLE AccountHandle,
IN BOOLEAN AllPrivileges,
IN OPTIONAL PLSAPR_PRIVILEGE_SET Privileges
)
/*++
Routine Description:
This function is the RPC server worker routine for the
LsaRemovePrivilegesFromAccount API.
The LsaRemovePrivilegesFromAccount API removes privileges from an
account object. This API call requires ACCOUNT_ADJUST_PRIVILEGES
access to the account object. Note that if all privileges are removed
from the account object, the account object remains in existence until
deleted explicitly via a call to the LsaDeleteAccount API.
Arguments:
AccountHandle - The handle to the open account object to which
privileges are to be removed. This handle will have been returned
from a prior LsaOpenAccount or LsaCreateAccountInLsa API call.
AllPrivileges - If TRUE, then all privileges are to be removed from
the account. In this case, the Privileges parameter must be
specified as NULL. If FALSE, the Privileges parameter specifies
the privileges to be removed, and must be non NULL.
Privileges - Optionally points to a set of privileges (and their
attributes) to be removed from the account object. The attributes
fields of this structure are ignored. This parameter must
be specified as non-NULL if and only if AllPrivileges is set to
FALSE.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
to complete the operation.
STATUS_INVALID_HANDLE - The specified AccountHandle is not valid.
STATUS_INVALID_PARAMETER - The optional Privileges paraemter was
specified as NULL and AllPrivileges was set to FALSE.
--*/
{
return LsapRemovePrivilegesFromAccount( AccountHandle, AllPrivileges, Privileges, TRUE );
}
NTSTATUS
LsapRemovePrivilegesFromAccount(
IN LSAPR_HANDLE AccountHandle,
IN BOOLEAN AllPrivileges,
IN OPTIONAL PLSAPR_PRIVILEGE_SET Privileges,
IN BOOL LockSce
)
/*++
Routine Description:
This is the worker routine for LsarRemovePrivilegesFromAccount, with an added
semantics of not locking the SCE policy.
--*/
{
NTSTATUS Status;
LsarpReturnCheckSetup();
LsapDsDebugOut(( DEB_FTRACE, "LsapRemovePrivilegesFromAccount\n" ));
//
// Verify that a meaningful combination of AllPrivileges and Privileges
// has been specified.
//
if (AllPrivileges) {
if (Privileges != NULL) {
return STATUS_INVALID_PARAMETER;
}
} else {
if (Privileges == NULL) {
return STATUS_INVALID_PARAMETER;
}
}
//
// Remove the privileges requested.
//
Status = LsapDbChangePrivilegesAccount(
AccountHandle,
RemovePrivileges,
AllPrivileges,
(PPRIVILEGE_SET) Privileges,
LockSce
);
LsarpReturnPrologue();
LsapDsDebugOut(( DEB_FTRACE, "LsapRemovePrivilegesFromAccount: 0x%lx\n", Status ));
return(Status);
}
NTSTATUS
LsapDbChangePrivilegesAccount(
IN LSAPR_HANDLE AccountHandle,
IN LSAP_DB_CHANGE_PRIVILEGE_MODE ChangeMode,
IN BOOLEAN AllPrivileges,
IN OPTIONAL PPRIVILEGE_SET Privileges,
IN BOOL LockSce
)
/*++
Routine Description:
This function changes the privileges assigned to an account. It is
called only by LsarAddPrivilegesToAccount and LsarRemovePrivilegesFrom-
Account.
WARNING: The Lsa Database must be in the locked state when this function
is called.
Arguments:
AccountHandle - Handle to open Account object obtained from LsaOpenAccount.
ChangeMode - Specifies the change mode
AddPrivileges - Add the privileges
RemovePrivileges - Delete the privileges
AllPrivileges - If removing privileges from an account and this boolean
is set to TRUE, all privileges are to be removed. In this case,
the Privileges parameter must be set to NULL. In all other cases,
AllPrivileges must be set to FALSE and Privileges must be non-NULL.
Privileges - Specifies set of privileges to be changed. This parameter
must be set to NULL if and only if removing all privileges.
LockSce - Specifies whether SCE policy should be locked or not (should be FALSE
for situations where the caller already has it locked)
Return Value:
NTSTATUS - Standard Nt Result Code
--*/
{
NTSTATUS Status = STATUS_SUCCESS, IgnoreStatus;
ULONG ExistingPrivilegesSize;
LSAPR_HANDLE SubKeyHandle = NULL;
PPRIVILEGE_SET ExistingPrivileges = NULL;
PPRIVILEGE_SET PrivilegesToAudit = NULL;
BOOLEAN TransactionAbort = FALSE;
ULONG AuditEventId;
PLUID_AND_ATTRIBUTES Luids = NULL;
BOOLEAN ObjectReferenced = FALSE;
PLSAPR_SID AccountSid = NULL;
BOOLEAN bAudit = FALSE;
LSAP_DB_HANDLE InternalHandle = AccountHandle;
BOOLEAN ScePolicyLocked = FALSE;
BOOLEAN NotifySce = FALSE;
ULONG MaxPrivileges = 0;
#if DBG
if( AllPrivileges ) {
//
// If AllPrivileges is TRUE then we must be removing privileges
// and Privileges must be NULL
//
ASSERT( ChangeMode == RemovePrivileges );
ASSERT( Privileges == NULL );
} else {
//
// If AllPrivileges is FALSE then
// Privileges must be non-NULL
//
ASSERT( Privileges != NULL );
}
//
// Does ChangeMode has a valid value?
//
switch( ChangeMode ) {
case AddPrivileges:
case RemovePrivileges:
case SetPrivileges:
break;
default:
ASSERT( !"Change mode doesn't have a valid value" );
break;
}
#endif
//
// Do not grab the SCE policy lock for handles opened as SCE policy handles
//
if ( !InternalHandle->SceHandleChild ) {
if ( LockSce ) {
RtlEnterCriticalSection( &LsapDbState.ScePolicyLock.CriticalSection );
if ( LsapDbState.ScePolicyLock.NumberOfWaitingShared > MAX_SCE_WAITING_SHARED ) {
Status = STATUS_TOO_MANY_THREADS;
}
RtlLeaveCriticalSection( &LsapDbState.ScePolicyLock.CriticalSection );
if ( !NT_SUCCESS( Status )) {
goto ChangePrivilegesError;
}
WaitForSingleObject( LsapDbState.SceSyncEvent, INFINITE );
RtlAcquireResourceShared( &LsapDbState.ScePolicyLock, TRUE );
ASSERT( !g_ScePolicyLocked );
ScePolicyLocked = TRUE;
}
NotifySce = TRUE;
}
//
// Acquire the Lsa Database lock. Verify that the Account Object handle is
// valid, is of the expected type and has all of the desired accesses
// granted. Reference the handle and open a database transaction.
//
Status = LsapDbReferenceObject(
AccountHandle,
ACCOUNT_ADJUST_PRIVILEGES,
AccountObject,
AccountObject,
LSAP_DB_LOCK |
LSAP_DB_START_TRANSACTION |
LSAP_DB_NO_DS_OP_TRANSACTION
);
if (!NT_SUCCESS(Status)) {
goto ChangePrivilegesError;
}
ObjectReferenced = TRUE;
//
// Query size of buffer needed for the existing Privileges.
// Read the Account Object's Privileges data from the LSA Database
//
ExistingPrivilegesSize = 0;
//
// If we're doing a SetPrivileges and we're in registry mode, we'll just pretend we
// have no existing privs and do an add
//
if ( ChangeMode == SetPrivileges ) {
ExistingPrivileges = NULL;
ChangeMode = AddPrivileges;
} else {
Status = LsapDbReadAttributeObject(
AccountHandle,
&LsapDbNames[Privilgs],
NULL,
&ExistingPrivilegesSize
);
if (!NT_SUCCESS(Status)) {
//
// The only error permitted is STATUS_OBJECT_NAME_NOT_FOUND
// because the account object does not have any privileges
// assigned and has no Privilgs attribute.
//
if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
goto ChangePrivilegesError;
}
//
// Account has no existing privileges.
//
ExistingPrivileges = NULL;
} else {
//
// Account already has privileges. Allocate buffer for reading
// the existing privilege set and read them in.
//
ExistingPrivileges = LsapAllocateLsaHeap( ExistingPrivilegesSize );
if (ExistingPrivileges == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto ChangePrivilegesError;
}
Status = LsapDbReadAttributeObject(
AccountHandle,
&LsapDbNames[Privilgs],
ExistingPrivileges,
&ExistingPrivilegesSize
);
if (!NT_SUCCESS(Status)) {
goto ChangePrivilegesError;
}
}
}
//
// when caller wants to remove privileges and AllPrivileges == TRUE,
// the passed value of Privileges is NULL. This poses a problem for
// the auditing code as we wnat to see what privileges got removed
// in the audit event. Therefore, in this case, make a copy of the
// existing privileges so that we can use it later in auditing.
//
if (AllPrivileges && (ChangeMode == RemovePrivileges)) {
PrivilegesToAudit = ExistingPrivileges;
ExistingPrivileges = NULL;
} else {
PrivilegesToAudit = Privileges;
//
// Now query the size of buffer required for the updated privilege
// set
//
if ( ExistingPrivileges ) {
MaxPrivileges = ExistingPrivileges->PrivilegeCount;
}
if (ChangeMode == AddPrivileges) {
BOOLEAN Changed = FALSE;
Status = LsapRtlAddPrivileges(
&ExistingPrivileges,
&MaxPrivileges,
Privileges,
RTL_SUPERSEDE_PRIVILEGE_ATTRIBUTES,
&Changed
);
if ( NT_SUCCESS( Status ) && !Changed ) {
//
// Nothing has changed, so bail
//
goto ChangePrivilegesFinish;
}
} else {
Status = LsapRtlRemovePrivileges(
ExistingPrivileges,
Privileges
);
}
}
//
// If privileges remain, write the updated privilege set back to
// the LSA Database as the value of the Privilgs attribute of the
// account object. If no privileges remain, delete the Privilgs
// attribute.
//
if (ExistingPrivileges && (ExistingPrivileges->PrivilegeCount > 0)) {
Status = LsapDbWriteAttributeObject(
AccountHandle,
&LsapDbNames[Privilgs],
ExistingPrivileges,
sizeof (PRIVILEGE_SET) + (ExistingPrivileges->PrivilegeCount - 1)*sizeof(LUID_AND_ATTRIBUTES)
);
} else {
Status = LsapDbDeleteAttributeObject(
AccountHandle,
&LsapDbNames[Privilgs],
FALSE
);
//
// The only error permitted is STATUS_OBJECT_NAME_NOT_FOUND
// because the account object does not have any privileges
// assigned and so has no Privilgs attribute.
//
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
Status = STATUS_SUCCESS;
}
}
//
// If auditing of policy changes is enabled, generate an audit.
//
AccountSid = LsapDbSidFromHandle( AccountHandle );
IgnoreStatus = LsapAdtAuditingEnabledBySid(
AuditCategoryPolicyChange,
AccountSid,
EVENTLOG_AUDIT_SUCCESS,
&bAudit
);
if (NT_SUCCESS(IgnoreStatus) && bAudit &&
PrivilegesToAudit && PrivilegesToAudit->PrivilegeCount) {
AuditEventId = ((ChangeMode == AddPrivileges) ?
SE_AUDITID_USER_RIGHT_ASSIGNED :
SE_AUDITID_USER_RIGHT_REMOVED);
//
// Audit the privilege set change. Ignore failures from Auditing.
//
IgnoreStatus = LsapAdtGenerateLsaAuditEvent(
AccountHandle,
SE_CATEGID_POLICY_CHANGE,
AuditEventId,
PrivilegesToAudit,
1,
(PSID *) &AccountSid,
0,
NULL,
NULL
);
}
//
// Update the Account Object Cache while holding the Lsa Database Lock.
// If the commit to backing storage below fails, caching will automatically
// be turned off.
//
// NOTE: A pointer to the UpdatedPrivileges buffer will be placed directly
// in the cached Account Object, so it should not be freed by this routine.
//
if (ExistingPrivileges && (ExistingPrivileges->PrivilegeCount > 0)) {
IgnoreStatus = LsapDbUpdatePrivilegesAccount(
AccountSid,
ExistingPrivileges
);
//
// The cache takes ownership of the privileges structure, so we don't
// want to free it.
//
if( NT_SUCCESS( IgnoreStatus ) ) {
ExistingPrivileges = NULL;
}
} else {
IgnoreStatus = LsapDbUpdatePrivilegesAccount(
AccountSid,
NULL
);
}
ChangePrivilegesFinish:
//
// free the allocated privileges
//
if ( AllPrivileges && (ChangeMode == RemovePrivileges) && PrivilegesToAudit )
{
LsapFreeLsaHeap( PrivilegesToAudit );
}
//
// If necessary, free the ExistingPrivileges buffer.
//
if (ExistingPrivileges != NULL) {
LsapFreeLsaHeap(ExistingPrivileges);
ExistingPrivileges = NULL;
}
//
// If necessary, dereference the Account object, close the database
// transaction, release the LSA Database lock and return.
//
if (ObjectReferenced) {
IgnoreStatus = LsapDbDereferenceObject(
&AccountHandle,
AccountObject,
AccountObject,
LSAP_DB_LOCK |
LSAP_DB_FINISH_TRANSACTION |
LSAP_DB_NO_DS_OP_TRANSACTION,
SecurityDbChange,
Status
);
}
//
// Notify SCE of the change. Only notify for callers
// that did not open their policy handles with LsaOpenPolicySce.
//
if ( NotifySce && NT_SUCCESS( Status )) {
LsapSceNotify(
SecurityDbChange,
SecurityDbObjectLsaAccount,
InternalHandle->Sid
);
}
if ( ScePolicyLocked ) {
RtlReleaseResource( &LsapDbState.ScePolicyLock );
}
return Status;
ChangePrivilegesError:
goto ChangePrivilegesFinish;
}
NTSTATUS
LsarGetQuotasForAccount(
IN LSAPR_HANDLE AccountHandle,
OUT PQUOTA_LIMITS QuotaLimits
)
/*++
Routine Description:
This function is the LSA server RPC worker routine for the
LsarGetQuotasForAccount API.
The LsaGetQuotasForAccount API obtains the quota limits for pageable and
non-pageable memory (in Kilobytes) and the maximum execution time (in
seconds) for any session logged on to the account specified by
AccountHandle.
Quotas is not supported any more. In the past, we need LSA_ACCOUNT_VIEW
access to the object, but currently, there is no such access right &
you don't need any right to call this function. We will return QuotaLimits
as 0 and return SUCCESS.
Arguments:
AccountHandle - The handle to the open account object whose quotas
are to be obtained. This handle will have been returned
from a prior LsaOpenAccount or LsaCreateAccountInLsa API call.
QuotaLimits - Pointer to structure in which the system resource
quota limits applicable to each session logged on to this account
will be returned. Note that all quotas, including those specified
as being the system default values, are returned as actual values.
Return Values:
NTSTATUS - Standard Nt Result Code
--*/
{
NTSTATUS Status;
PLSAPR_ACCOUNT_INFO AccountInformation = NULL;
LsarpReturnCheckSetup();
//
// Stub it out
//
LsapDsDebugOut(( DEB_TRACE,
"LsarGetQuotasForAccount has been removed. Returning STATUS_SUCCESS anyway\n" ));
RtlZeroMemory( QuotaLimits, sizeof( QUOTA_LIMITS ) );
LsarpReturnPrologue();
return( STATUS_SUCCESS );
}
NTSTATUS
LsarSetQuotasForAccount(
IN LSAPR_HANDLE AccountHandle,
IN PQUOTA_LIMITS QuotaLimits
)
/*++
Routine Description:
This function is the LSA server RPC worker routine for the
LsaSetQuotasForAccount API.
The LsaSetQuotasForAccount API sets the quota limits for pageable and
non-pageable memory (in Kilobytes) and the maximum execution time (in
seconds) for any session logged on to the account specified by
AccountHandle. For each quota an explicit value or the system default
may be specified.
Quotas is not supported any more. In the past, we need LSA_ACCOUNT_ADJUST_QUOTAS
access to the account, but currently, there is no such access right &
you don't need any right to call this function. We will return SUCCESS.
Arguments:
AccountHandle - The handle to the open account object whose quotas
are to be set. This handle will have been returned from a prior
LsaOpenAccount or LsaCreateAccountInLsa API call.
QuotaLimits - Pointer to structure containing the system resource
quota limits applicable to each session logged on to this account.
A zero value specified in any field indicates that the current
System Default Quota Limit is to be applied.
Return Values:
NTSTATUS - Standard Nt Result Code
--*/
{
LsarpReturnCheckSetup();
//
// Quotas have been disabled.
//
LsapDsDebugOut(( DEB_TRACE,
"LsarSetQuotasForAccount has been removed: Returning STATUS_SUCCESS anyway\n" ));
return( STATUS_SUCCESS );
}
NTSTATUS
LsarGetSystemAccessAccount(
IN LSAPR_HANDLE AccountHandle,
OUT PULONG SystemAccess
)
/*++
Routine Description:
The LsaGetSystemAccessAccount() service returns the System Access
account flags for an Account object.
Arguments:
AccountHandle - The handle to the Account object whose system access
flags are to be read. This handle will have been returned
from a preceding LsaOpenAccount() or LsaCreateAccount() call
an must be open for ACCOUNT_VIEW access.
SystemAccess - Points to location that will receive the system access
flags for the account.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_SUCCESS - The call was successful.
STATUS_ACCESS_DENIED - The AccountHandle does not specify
ACCOUNT_VIEW access.
STATUS_INVALID_HANDLE - The specified AccountHandle is invalid.
--*/
{
NTSTATUS Status;
PLSAPR_ACCOUNT_INFO AccountInformation = NULL;
LsarpReturnCheckSetup();
LsapDsDebugOut(( DEB_FTRACE, "LsarGetSystemAccessAccount\n" ));
Status = LsarQueryInformationAccount(
AccountHandle,
AccountSystemAccessInformation,
&AccountInformation
);
if (!NT_SUCCESS(Status)) {
goto GetSystemAccessAccountError;
}
*SystemAccess = *((PULONG) AccountInformation);
GetSystemAccessAccountFinish:
//
// If necessary, free the buffer in which the Account Information was
// returned.
//
if (AccountInformation != NULL) {
MIDL_user_free( AccountInformation );
AccountInformation = NULL;
}
LsarpReturnPrologue();
LsapDsDebugOut(( DEB_FTRACE, "LsarGetSystemAccessAccount: 0x%lx\n", Status ));
return(Status);
GetSystemAccessAccountError:
*SystemAccess = 0;
goto GetSystemAccessAccountFinish;
}
NTSTATUS
LsarSetSystemAccessAccount(
IN LSAPR_HANDLE AccountHandle,
IN ULONG SystemAccess
)
/*++
Routine Description:
The LsaSetSystemAccessAccount() service sets the System Access
account flags for an Account object.
Arguments:
AccountHandle - The handle to the Account object whose system access
flags are to be read. This handle will have been returned
from a preceding LsaOpenAccount() or LsaCreateAccount() call
an must be open for ACCOUNT_ADJUST_SYSTEM_ACCESS access.
SystemAccess - A mask of the system access flags to assign to the
Account object. The valid access flags include:
POLICY_MODE_INTERACTIVE - Account can be accessed interactively
POLICY_MODE_NETWORK - Account can be accessed remotely
POLICY_MODE_SERVICE - TBS
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_SUCCESS - The call was successful.
STATUS_ACCESS_DENIED - The AccountHandle does not specify
ACCOUNT_VIEW access.
STATUS_INVALID_HANDLE - The specified AccountHandle is invalid.
STATUS_INVALID_PARAMETER - The specified Access Flags are invalid.
--*/
{
return LsapSetSystemAccessAccount( AccountHandle, SystemAccess, TRUE );
}
NTSTATUS
LsapSetSystemAccessAccount(
IN LSAPR_HANDLE AccountHandle,
IN ULONG SystemAccess,
IN BOOL LockSce
)
/*++
Routine Description:
This is the worker routine for LsarSetSystemAccessAccount, with an added
semantics of not locking the SCE policy.
--*/
{
NTSTATUS Status = STATUS_SUCCESS, IgnoreStatus;
BOOLEAN ObjectReferenced = FALSE;
PLSAPR_SID AccountSid = NULL;
LSAP_DB_HANDLE InternalHandle = ( LSAP_DB_HANDLE )AccountHandle;
BOOLEAN ScePolicyLocked = FALSE;
BOOLEAN NotifySce = FALSE;
PLSAPR_ACCOUNT_INFO pAccountInfo = NULL;
LONG i;
BOOLEAN bObtainedPreviousAccountInfo = TRUE;
BOOLEAN bAudit = FALSE;
LsarpReturnCheckSetup();
LsapDsDebugOut(( DEB_FTRACE, "LsarSetSystemAccessAccount\n" ));
//
// Verify that the specified flags are valid
//
if (SystemAccess != (SystemAccess & (POLICY_MODE_ALL))) {
Status = STATUS_INVALID_PARAMETER;
goto SetSystemAccessAccountError;
}
//
// Do not grab the SCE policy lock for handles opened as SCE policy handles
//
if ( !InternalHandle->SceHandleChild ) {
if ( LockSce ) {
RtlEnterCriticalSection( &LsapDbState.ScePolicyLock.CriticalSection );
if ( LsapDbState.ScePolicyLock.NumberOfWaitingShared > MAX_SCE_WAITING_SHARED ) {
Status = STATUS_TOO_MANY_THREADS;
}
RtlLeaveCriticalSection( &LsapDbState.ScePolicyLock.CriticalSection );
if ( !NT_SUCCESS( Status )) {
goto SetSystemAccessAccountError;
}
WaitForSingleObject( LsapDbState.SceSyncEvent, INFINITE );
RtlAcquireResourceShared( &LsapDbState.ScePolicyLock, TRUE );
ASSERT( !g_ScePolicyLocked );
ScePolicyLocked = TRUE;
}
NotifySce = TRUE;
}
//
// Acquire the Lsa Database lock. Verify that the Account Object handle is
// valid, is of the expected type and has all of the desired accesses
// granted. Reference the handle and open a database transaction.
//
Status = LsapDbReferenceObject(
AccountHandle,
ACCOUNT_ADJUST_SYSTEM_ACCESS,
AccountObject,
AccountObject,
LSAP_DB_LOCK | LSAP_DB_START_TRANSACTION | LSAP_DB_NO_DS_OP_TRANSACTION
);
if (!NT_SUCCESS(Status)) {
goto SetSystemAccessAccountError;
}
ObjectReferenced = TRUE;
//
// Record the previous access flags for auditing.
//
bObtainedPreviousAccountInfo = FALSE;
if( LsapDbIsCacheValid( AccountObject ) ) {
Status = LsapDbQueryInformationAccount(
AccountHandle,
AccountSystemAccessInformation,
&pAccountInfo
);
if( NT_SUCCESS( Status ) ) {
bObtainedPreviousAccountInfo = TRUE;
}
}
//
// Write the System Access flags
//
Status = LsapDbWriteAttributeObject(
AccountHandle,
&LsapDbNames[ActSysAc],
&SystemAccess,
sizeof (ULONG)
);
if (!NT_SUCCESS(Status)) {
goto SetSystemAccessAccountError;
}
AccountSid = LsapDbSidFromHandle( AccountHandle );
//
// Update the Account Object Cache while holding the Lsa Database Lock.
// If the commit to backing storage below fails, caching will automatically
// be turned off.
//
IgnoreStatus = LsapDbUpdateSystemAccessAccount(
AccountSid,
&SystemAccess
);
//
// If auditing of policy changes is enabled, generate an audit.
//
IgnoreStatus = LsapAdtAuditingEnabledBySid(
AuditCategoryPolicyChange,
AccountSid,
EVENTLOG_AUDIT_SUCCESS,
&bAudit
);
if (bObtainedPreviousAccountInfo && NT_SUCCESS(IgnoreStatus) && bAudit) {
//
// Audit the system access change. Ignore failures from Auditing.
//
NTSTATUS Status2 = STATUS_SUCCESS;
LUID ClientAuthenticationId;
PTOKEN_USER TokenUserInformation;
PSID ClientSid;
PWCHAR GrantedAccess[11];
LONG GrantedAccessCount = 0;
ULONG GrantedAccessMask = 0;
PWCHAR RemovedAccess[11];
LONG RemovedAccessCount = 0;
ULONG RemovedAccessMask = 0;
USHORT EventType = EVENTLOG_AUDIT_SUCCESS;
//
// Determine the rights that were enabled.
//
GrantedAccessMask = (pAccountInfo != NULL ) ? SystemAccess & (~pAccountInfo->AccountSystemAccessInfo) : SystemAccess;
if (FLAG_ON(GrantedAccessMask, POLICY_MODE_INTERACTIVE)) {
GrantedAccess[GrantedAccessCount++] = SE_INTERACTIVE_LOGON_NAME;
}
if (FLAG_ON(GrantedAccessMask, POLICY_MODE_NETWORK)) {
GrantedAccess[GrantedAccessCount++] = SE_NETWORK_LOGON_NAME;
}
if (FLAG_ON(GrantedAccessMask, POLICY_MODE_BATCH)) {
GrantedAccess[GrantedAccessCount++] = SE_BATCH_LOGON_NAME;
}
if (FLAG_ON(GrantedAccessMask, POLICY_MODE_SERVICE)) {
GrantedAccess[GrantedAccessCount++] = SE_SERVICE_LOGON_NAME;
}
if (FLAG_ON(GrantedAccessMask, POLICY_MODE_REMOTE_INTERACTIVE)) {
GrantedAccess[GrantedAccessCount++] = SE_REMOTE_INTERACTIVE_LOGON_NAME;
}
if (FLAG_ON(GrantedAccessMask, POLICY_MODE_DENY_INTERACTIVE)) {
GrantedAccess[GrantedAccessCount++] = SE_DENY_INTERACTIVE_LOGON_NAME;
}
if (FLAG_ON(GrantedAccessMask, POLICY_MODE_DENY_NETWORK)) {
GrantedAccess[GrantedAccessCount++] = SE_DENY_NETWORK_LOGON_NAME;
}
if (FLAG_ON(GrantedAccessMask, POLICY_MODE_DENY_BATCH)) {
GrantedAccess[GrantedAccessCount++] = SE_DENY_BATCH_LOGON_NAME;
}
if (FLAG_ON(GrantedAccessMask, POLICY_MODE_DENY_SERVICE)) {
GrantedAccess[GrantedAccessCount++] = SE_DENY_SERVICE_LOGON_NAME;
}
if (FLAG_ON(GrantedAccessMask, POLICY_MODE_DENY_REMOTE_INTERACTIVE)) {
GrantedAccess[GrantedAccessCount++] = SE_DENY_REMOTE_INTERACTIVE_LOGON_NAME;
}
//
// Determine the rights which were turned off.
//
RemovedAccessMask = (pAccountInfo != NULL) ? pAccountInfo->AccountSystemAccessInfo & (~SystemAccess) : SystemAccess;
if (FLAG_ON(RemovedAccessMask, POLICY_MODE_INTERACTIVE)) {
RemovedAccess[RemovedAccessCount++] = SE_INTERACTIVE_LOGON_NAME;
}
if (FLAG_ON(RemovedAccessMask, POLICY_MODE_NETWORK)) {
RemovedAccess[RemovedAccessCount++] = SE_NETWORK_LOGON_NAME;
}
if (FLAG_ON(RemovedAccessMask, POLICY_MODE_BATCH)) {
RemovedAccess[RemovedAccessCount++] = SE_BATCH_LOGON_NAME;
}
if (FLAG_ON(RemovedAccessMask, POLICY_MODE_SERVICE)) {
RemovedAccess[RemovedAccessCount++] = SE_SERVICE_LOGON_NAME;
}
if (FLAG_ON(RemovedAccessMask, POLICY_MODE_REMOTE_INTERACTIVE)) {
RemovedAccess[RemovedAccessCount++] = SE_REMOTE_INTERACTIVE_LOGON_NAME;
}
if (FLAG_ON(RemovedAccessMask, POLICY_MODE_DENY_INTERACTIVE)) {
RemovedAccess[RemovedAccessCount++] = SE_DENY_INTERACTIVE_LOGON_NAME;
}
if (FLAG_ON(RemovedAccessMask, POLICY_MODE_DENY_NETWORK)) {
RemovedAccess[RemovedAccessCount++] = SE_DENY_NETWORK_LOGON_NAME;
}
if (FLAG_ON(RemovedAccessMask, POLICY_MODE_DENY_BATCH)) {
RemovedAccess[RemovedAccessCount++] = SE_DENY_BATCH_LOGON_NAME;
}
if (FLAG_ON(RemovedAccessMask, POLICY_MODE_DENY_SERVICE)) {
RemovedAccess[RemovedAccessCount++] = SE_DENY_SERVICE_LOGON_NAME;
}
if (FLAG_ON(RemovedAccessMask, POLICY_MODE_DENY_REMOTE_INTERACTIVE)) {
RemovedAccess[RemovedAccessCount++] = SE_DENY_REMOTE_INTERACTIVE_LOGON_NAME;
}
Status2 = LsapQueryClientInfo(
&TokenUserInformation,
&ClientAuthenticationId
);
if ( NT_SUCCESS( Status2 )) {
//
// We can't generate an audit without a
// user Sid.
//
ClientSid = TokenUserInformation->User.Sid;
//
// Audit any granted system access rights
//
for (i = 0; i < GrantedAccessCount; i++) {
LsapAdtGenerateLsaAuditSystemAccessChange(
SE_CATEGID_POLICY_CHANGE,
SE_AUDITID_SYSTEM_ACCESS_GRANTED,
EventType,
ClientSid,
ClientAuthenticationId,
AccountSid,
GrantedAccess[i]
);
}
//
// Audit any removed system access rights
//
for (i = 0; i < RemovedAccessCount; i++) {
LsapAdtGenerateLsaAuditSystemAccessChange(
SE_CATEGID_POLICY_CHANGE,
SE_AUDITID_SYSTEM_ACCESS_REMOVED,
EventType,
ClientSid,
ClientAuthenticationId,
AccountSid,
RemovedAccess[i]
);
}
LsapFreeLsaHeap( TokenUserInformation );
}
}
SetSystemAccessAccountFinish:
if (NULL != pAccountInfo) {
LsaFreeMemory(pAccountInfo);
}
//
// If necessary, dereference the Account object, close the database
// transaction, notify the LSA Database Replicator of the change,
// release the LSA Database lock and return.
//
if (ObjectReferenced) {
LsapDbDereferenceObject(
&AccountHandle,
AccountObject,
AccountObject,
LSAP_DB_LOCK | LSAP_DB_FINISH_TRANSACTION | LSAP_DB_NO_DS_OP_TRANSACTION,
SecurityDbChange,
Status
);
}
//
// Notify SCE of the change. Only notify for callers
// that did not open their policy handles with LsaOpenPolicySce.
//
if ( NotifySce && NT_SUCCESS( Status )) {
LsapSceNotify(
SecurityDbChange,
SecurityDbObjectLsaAccount,
AccountSid
);
}
if ( ScePolicyLocked ) {
RtlReleaseResource( &LsapDbState.ScePolicyLock );
}
LsarpReturnPrologue();
LsapDsDebugOut(( DEB_FTRACE, "LsarSetSystemAccessAccount: 0x%lx\n", Status ));
return(Status);
SetSystemAccessAccountError:
goto SetSystemAccessAccountFinish;
}
NTSTATUS
LsarQueryInformationAccount(
IN LSAPR_HANDLE AccountHandle,
IN ACCOUNT_INFORMATION_CLASS InformationClass,
OUT PLSAPR_ACCOUNT_INFO *AccountInformation
)
/*++
Routine Description:
This function is the LSA server RPC worker routine for the
(as yet non-existent) LsarQueryInformationAccount API. Currently,
LsarGet...Account() API call this routine. In the future, this
routine may be added as an API.
The LsaQueryInformationAccount API obtains information from the Policy
object. The caller must have access appropriate to the information
being requested (see InformationClass parameter).
Arguments:
AccountHandle - Handle from an LsaOpenAccount call.
InformationClass - Specifies the information to be returned. The
Information Classes and accesses required are as follows:
Information Class Required Access Type
AccountPrivilegeInformation ACCOUNT_VIEW
AccountQuotaInformation ACCOUNT_VIEW
AccountSystemAccessInformation ACCOUNT_VIEW
AccountInformation - Receives a pointer to the buffer returned comtaining the
requested information. This buffer is allocated by this service
and must be freed when no longer needed by passing the returned
value to LsaFreeMemory().
Return Value:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate
access to complete the operation.
STATUS_INTERNAL_DB_CORRUPTION - The Policy Database is possibly
corrupt. The returned Policy Information is invalid for
the given class.
--*/
{
NTSTATUS Status;
PLSAP_DB_ACCOUNT Account = NULL;
PLSAPR_ACCOUNT_INFO CachedAccountInformation = NULL;
LsarpReturnCheckSetup();
LsapDsDebugOut(( DEB_FTRACE, "LsarQueryInformationAccount\n" ));
//
// Acquire the Lsa Database lock. Verify that the Account Object handle is
// valid, is of the expected type and has all of the desired accesses
// granted. Reference the handle.
//
Status = LsapDbReferenceObject(
AccountHandle,
ACCOUNT_VIEW,
AccountObject,
AccountObject,
LSAP_DB_LOCK |
LSAP_DB_NO_DS_OP_TRANSACTION |
LSAP_DB_READ_ONLY_TRANSACTION
);
if (NT_SUCCESS(Status)) {
if (LsapDbIsCacheValid(AccountObject)) {
Status = LsapDbQueryInformationAccount(
AccountHandle,
InformationClass,
AccountInformation
);
} else {
Status = LsapDbSlowQueryInformationAccount(
AccountHandle,
InformationClass,
AccountInformation
);
}
Status = LsapDbDereferenceObject(
&AccountHandle,
AccountObject,
AccountObject,
LSAP_DB_LOCK |
LSAP_DB_NO_DS_OP_TRANSACTION |
LSAP_DB_READ_ONLY_TRANSACTION,
(SECURITY_DB_DELTA_TYPE) 0,
Status
);
}
LsarpReturnPrologue();
LsapDsDebugOut(( DEB_FTRACE, "LsarQueryInformationAccount: 0x%lx\n", Status ));
return(Status);
}
NTSTATUS
LsapDbQueryInformationAccount(
IN LSAPR_HANDLE AccountHandle,
IN ACCOUNT_INFORMATION_CLASS InformationClass,
OUT PLSAPR_ACCOUNT_INFO *AccountInformation
)
/*++
Routine Description:
This function is the fast LSA server RPC worker routine for the
(as yet non-existent) LsarQueryInformationAccount API. It is called
when the in-memory Account List is valid.
Arguments:
AccountHandle - Handle from an LsaOpenAccount call.
InformationClass - Specifies the information to be returned. The
Information Classes and accesses required are as follows:
Information Class Required Access Type
AccountPrivilegeInformation ACCOUNT_VIEW
AccountQuotaInformation ACCOUNT_VIEW
AccountSystemAccessInformation ACCOUNT_VIEW
AccountInformation - Receives a pointer to the buffer returned containing
the requested information. This buffer is allocated by this service
and must be freed when no longer needed by passing the returned
value to LsaFreeMemory().
Return Value:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate
access to complete the operation.
STATUS_INTERNAL_DB_CORRUPTION - The Policy Database is possibly
corrupt. The returned Policy Information is invalid for
the given class.
--*/
{
NTSTATUS Status;
PLSAP_DB_ACCOUNT Account = NULL;
ULONG AccountInformationLength = 0;
PLSAPR_ACCOUNT_INFO CachedAccountInformation = NULL;
ULONG PrivilegesCount;
PLSAPR_PRIVILEGE_SET OutputPrivilegeSet = NULL;
ASSERTMSG( "Account Cache is not valid!", LsapDbIsCacheValid( AccountObject ) );
(*AccountInformation) = NULL;
//
// Lookup the Account.
//
Status = LsapDbLookupAccount(
LsapDbSidFromHandle( AccountHandle ),
&Account
);
if (!NT_SUCCESS(Status)) {
goto QueryInformationAccountError;
}
//
// Branch on Information Class.
//
switch (InformationClass) {
case AccountPrivilegeInformation:
//
// Calculate size of buffer needed for the output privilege set.
//
PrivilegesCount = 0;
if (Account->Info.PrivilegeSet != NULL) {
PrivilegesCount = Account->Info.PrivilegeSet->PrivilegeCount;
}
AccountInformationLength = sizeof(PRIVILEGE_SET) +
(PrivilegesCount * sizeof(LUID_AND_ATTRIBUTES)) -
(sizeof(LUID_AND_ATTRIBUTES));
CachedAccountInformation = (PLSAPR_ACCOUNT_INFO) Account->Info.PrivilegeSet;
break;
case AccountQuotaInformation:
//
// Calculate size of buffer needed for the output privilege set.
//
AccountInformationLength = sizeof(QUOTA_LIMITS);
CachedAccountInformation = (PLSAPR_ACCOUNT_INFO) &Account->Info.QuotaLimits;
break;
case AccountSystemAccessInformation:
//
// Calculate size of buffer needed for the output privilege set.
//
AccountInformationLength = sizeof(ULONG);
CachedAccountInformation = (PLSAPR_ACCOUNT_INFO) &Account->Info.SystemAccess;
break;
default:
Status = STATUS_INVALID_PARAMETER;
break;
}
if (!NT_SUCCESS(Status)) {
goto QueryInformationAccountError;
}
//
// Allocate output buffer.
//
*AccountInformation = MIDL_user_allocate( AccountInformationLength );
if (*AccountInformation == NULL) {
Status = STATUS_NO_MEMORY;
goto QueryInformationAccountError;
}
//
// Copy the data requested if the cached information is non-NULL.
//
if (CachedAccountInformation != NULL) {
RtlCopyMemory(
*AccountInformation,
CachedAccountInformation,
AccountInformationLength
);
goto QueryInformationAccountFinish;
}
//
// The cached information is NULL. The only information class for which
// this can happen is AccountPrivilegeInformation, since this is the
// only class for which a pointer is kept rather than in-structure data.
//
if (InformationClass == AccountPrivilegeInformation) {
OutputPrivilegeSet = (PLSAPR_PRIVILEGE_SET) *AccountInformation;
OutputPrivilegeSet->PrivilegeCount = 0;
OutputPrivilegeSet->Control = 0;
} else {
Status = STATUS_INTERNAL_DB_CORRUPTION;
}
if (!NT_SUCCESS(Status)) {
goto QueryInformationAccountError;
}
QueryInformationAccountFinish:
return(Status);
QueryInformationAccountError:
if (*AccountInformation) {
MIDL_user_free(*AccountInformation);
}
(*AccountInformation) = NULL;
goto QueryInformationAccountFinish;
}
NTSTATUS
LsapDbSlowQueryInformationAccount(
IN LSAPR_HANDLE AccountHandle,
IN ACCOUNT_INFORMATION_CLASS InformationClass,
OUT PLSAPR_ACCOUNT_INFO *Buffer
)
/*++
Routine Description:
This function is the slow LSA server RPC worker routine for the
(as yet non-existent) LsarQueryInformationAccount API. It is called
when the in-memory Account List is valid.
Arguments:
AccountHandle - Handle from an LsaOpenAccount call.
InformationClass - Specifies the information to be returned. The
Information Classes and accesses required are as follows:
Information Class Required Access Type
AccountPrivilegeInformation ACCOUNT_VIEW
AccountQuotaInformation ACCOUNT_VIEW
AccountSystemAccessInformation ACCOUNT_VIEW
Buffer - Receives a pointer to the buffer returned comtaining the
requested information. This buffer is allocated by this service
and must be freed when no longer needed by passing the returned
value to LsaFreeMemory().
Return Value:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate
access to complete the operation.
STATUS_INTERNAL_DB_CORRUPTION - The Policy Database is possibly
corrupt. The returned Policy Information is invalid for
the given class.
--*/
{
NTSTATUS Status;
QUOTA_LIMITS QuotaLimits;
ULONG SystemAccess;
PLSAPR_ACCOUNT_INFO OutputBuffer = NULL;
//
// Branch on Information Class.
//
switch (InformationClass) {
case AccountPrivilegeInformation:
Status = LsapDbSlowQueryPrivilegesAccount(
AccountHandle,
(PLSAPR_PRIVILEGE_SET *) &OutputBuffer
);
break;
case AccountQuotaInformation:
Status = LsapDbSlowQueryQuotasAccount(
AccountHandle,
&QuotaLimits
);
if (!NT_SUCCESS(Status)) {
break;
}
OutputBuffer = MIDL_user_allocate( sizeof(QUOTA_LIMITS));
if (OutputBuffer == NULL) {
Status = STATUS_NO_MEMORY;
break;
}
*((PQUOTA_LIMITS) OutputBuffer) = QuotaLimits;
break;
case AccountSystemAccessInformation:
Status = LsapDbSlowQuerySystemAccessAccount(
AccountHandle,
&SystemAccess
);
if (!NT_SUCCESS(Status)) {
break;
}
OutputBuffer = MIDL_user_allocate( sizeof(ULONG));
if (OutputBuffer == NULL) {
Status = STATUS_NO_MEMORY;
break;
}
*((PULONG) OutputBuffer) = SystemAccess;
break;
default:
Status = STATUS_INVALID_PARAMETER;
break;
}
if (!NT_SUCCESS(Status)) {
goto SlowQueryInformationAccountError;
}
*Buffer = OutputBuffer;
SlowQueryInformationAccountFinish:
return(Status);
SlowQueryInformationAccountError:
*Buffer = NULL;
goto SlowQueryInformationAccountFinish;
}
NTSTATUS
LsapDbQueryAllInformationAccounts(
IN LSAPR_HANDLE PolicyHandle,
IN ULONG IdCount,
IN PSID_AND_ATTRIBUTES Ids,
OUT PLSAP_DB_ACCOUNT_TYPE_SPECIFIC_INFO AccountInfo
)
/*++
Routine Description:
This routine:
1) Gets all privileges assigned to the user (or any group/alias
the user is a member of).
2) Establishes the quotas assigned to the user. This is the
maximum of the system default quotas or any quotas assigned
to the user (or any group/alias the user is a member of).
3) Gets all the System Accesses assigned to the user.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call. The handle must
have POLICY_VIEW_LOCAL_INFORMATION access granted.
IdCount - Indicates the number of IDs being provided in the Ids array.
Ids - Points to an array of SIDs.
AccountInfo - Pointer to buffer that will receive the Account information
comprising its Privilege Set, System Access Flags and Quotas.
Return Value:
STATUS_SUCCESS - Succeeded.
STATUS_LOGON_TYPE_NOT_GRANTED - Indicates the specified type of logon
has not been granted to any of the IDs in the passed set.
--*/
{
NTSTATUS Status;
BOOLEAN ObjectReferenced = FALSE;
PPRIVILEGE_SET RunningPrivileges = NULL;
ULONG MaxRunningPrivileges = 0;
PPRIVILEGE_SET NextPrivileges = NULL;
ULONG RunningSystemAccess;
QUOTA_LIMITS NextQuotaLimits;
QUOTA_LIMITS RunningQuotaLimits;
PQUOTA_LIMITS PolicyDefaultQuotaLimits = NULL;
PPOLICY_DEFAULT_QUOTA_INFO PolicyDefaultQuotaInfo = NULL;
ULONG SidIndex;
PLSAP_DB_ACCOUNT Account = NULL;
//
// If we are unable to use the Account List, use the slow method
// for querying Privileges and Quotas
//
if (!LsapDbIsCacheValid(AccountObject)) {
return(LsapDbSlowQueryAllInformationAccounts(
PolicyHandle,
IdCount,
Ids,
AccountInfo
));
}
//
// The Account List is valid. We'll use it instead of opening individual
// Account objects. Verify that the Policy Handle is valid, is the handle
// object and has the necessary access granted. Reference the handle.
//
Status = LsapDbReferenceObject(
PolicyHandle,
POLICY_VIEW_LOCAL_INFORMATION,
PolicyObject,
AccountObject,
LSAP_DB_LOCK | LSAP_DB_NO_DS_OP_TRANSACTION
);
if (!NT_SUCCESS(Status)) {
goto QueryAllInformationAccountsError;
}
ObjectReferenced = TRUE;
//
// Obtain the Master Default Quota Limits from the Policy Object. If
// the Policy Object is cached (partially for now) instruct the query
// routine to just copy the data.
PolicyDefaultQuotaLimits = &RunningQuotaLimits;
Status = LsapDbQueryInformationPolicy(
PolicyHandle,
PolicyDefaultQuotaInformation,
(PLSAPR_POLICY_INFORMATION *) &PolicyDefaultQuotaLimits
);
if (!NT_SUCCESS(Status)) {
goto QueryAllInformationAccountsError;
}
//
// Iterate through all of the Sids provided. For each one, check if the
// Sid is that of an Account object in the local LSA. If it is,
//
// (1) Obtain the System Accesses and add those found so far.
// (2) Obtain the Account Privileges and add to those found so far.
// (3) Obtain the Quota Limits (if any) assigned to the account.
// Compare these with the quota limits obtained so far. If any
// limits are more generous than the running values, update
// the running values.
//
RunningSystemAccess = 0;
for( SidIndex = 0; SidIndex < IdCount; SidIndex++) {
//
// Locate the Account information block for this Sid.
//
Status = LsapDbLookupAccount( Ids[SidIndex].Sid, &Account );
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_NO_SUCH_USER) {
Status = STATUS_SUCCESS;
continue;
}
break;
}
//
// We have found the Account information. Add in the System Accesses
// for this account.
//
RunningSystemAccess |= Account->Info.SystemAccess;
//
// Obtain the account's Special privileges.
//
NextPrivileges = Account->Info.PrivilegeSet;
//
// Add the Privileges of this account (if any) to the running set.
//
if (NextPrivileges != NULL) {
Status = LsapRtlAddPrivileges(
&RunningPrivileges,
&MaxRunningPrivileges,
NextPrivileges,
RTL_COMBINE_PRIVILEGE_ATTRIBUTES,
NULL // don't care if the set has changed or not
);
if (!NT_SUCCESS(Status)) {
goto QueryAllInformationAccountsError;
}
}
//
// Obtain the special Quota Limits for this account (if any).
//
RtlMoveMemory(&NextQuotaLimits, &Account->Info.QuotaLimits, sizeof(QUOTA_LIMITS));
//
// Special Quota Limits are assigned. Compare each of the quota
// limits obtained with the running values. If a quota limit just
// obtained is less restrictive than the running value, supersede the
// running value.
//
if (RunningQuotaLimits.PagedPoolLimit < NextQuotaLimits.PagedPoolLimit) {
RunningQuotaLimits.PagedPoolLimit = NextQuotaLimits.PagedPoolLimit;
}
if (RunningQuotaLimits.NonPagedPoolLimit < NextQuotaLimits.NonPagedPoolLimit) {
RunningQuotaLimits.NonPagedPoolLimit = NextQuotaLimits.NonPagedPoolLimit;
}
if (RunningQuotaLimits.MinimumWorkingSetSize > NextQuotaLimits.MinimumWorkingSetSize) {
RunningQuotaLimits.MinimumWorkingSetSize = NextQuotaLimits.MinimumWorkingSetSize;
}
if (RunningQuotaLimits.MaximumWorkingSetSize < NextQuotaLimits.MaximumWorkingSetSize) {
RunningQuotaLimits.MaximumWorkingSetSize = NextQuotaLimits.MaximumWorkingSetSize;
}
if (RunningQuotaLimits.PagefileLimit < NextQuotaLimits.PagefileLimit) {
RunningQuotaLimits.PagefileLimit = NextQuotaLimits.PagefileLimit;
}
if (RunningQuotaLimits.TimeLimit.QuadPart < NextQuotaLimits.TimeLimit.QuadPart) {
RunningQuotaLimits.TimeLimit = NextQuotaLimits.TimeLimit;
}
}
if (!NT_SUCCESS(Status)) {
goto QueryAllInformationAccountsError;
}
//
// Return the collective Privilege Set
//
AccountInfo->PrivilegeSet = RunningPrivileges;
//
// Return the collective System Accesses
AccountInfo->SystemAccess = RunningSystemAccess;
//
// Return the collective Quota Limits
//
AccountInfo->QuotaLimits = RunningQuotaLimits;
QueryAllInformationAccountsFinish:
//
// If necessary, dereference the Policy Object.
//
if (ObjectReferenced) {
LsapDbDereferenceObject(
&PolicyHandle,
PolicyObject,
AccountObject,
LSAP_DB_LOCK | LSAP_DB_NO_DS_OP_TRANSACTION,
(SECURITY_DB_DELTA_TYPE) 0,
Status
);
}
return(Status);
QueryAllInformationAccountsError:
//
// If necessary, free the memory allocated for the Privilege Set.
//
if (RunningPrivileges != NULL) {
MIDL_user_free( RunningPrivileges );
RunningPrivileges = NULL;
}
//
// Return null values
//
RtlZeroMemory( &AccountInfo->QuotaLimits, sizeof(QUOTA_LIMITS) );
AccountInfo->SystemAccess = 0;
AccountInfo->PrivilegeSet = NULL;
goto QueryAllInformationAccountsFinish;
}
NTSTATUS
LsapDbSlowQueryAllInformationAccounts(
IN LSAPR_HANDLE PolicyHandle,
IN ULONG IdCount,
IN PSID_AND_ATTRIBUTES Ids,
OUT PLSAP_DB_ACCOUNT_TYPE_SPECIFIC_INFO AccountInfo
)
/*++
Routine Description:
This routine is the slow version of LsapDbQueryInformation().
It is called when the Account List is not available, and assembles the
necessary information from the Policy Database.
This routine:
1) Gets all privileges assigned to the user (or any group/alias
the user is a member of).
2) Establishes the quotas assigned to the user. This is the
maximum of the system default quotas or any quotas assigned
to the user (or any group/alias the user is a member of).
3) Gets all the System Accesses assigned to the user.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call. The handle must
have POLICY_VIEW_LOCAL_INFORMATION access granted.
IdCount - Indicates the number of IDs being provided in the Ids array.
Ids - Points to an array of SIDs.
AccountInfo - Pointer to buffer that will receive the Account information
comprising its Privilege Set, System Access Flags and Quotas.
Return Value:
STATUS_SUCCESS - Succeeded.
STATUS_LOGON_TYPE_NOT_GRANTED - Indicates the specified type of logon
has not been granted to any of the IDs in the passed set.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
NTSTATUS LocalStatus;
BOOLEAN ObjectReferenced = FALSE;
PPRIVILEGE_SET RunningPrivileges = NULL;
ULONG MaxRunningPrivileges = 0;
PPRIVILEGE_SET NextPrivileges = NULL;
ULONG RunningSystemAccess;
QUOTA_LIMITS NextQuotaLimits;
QUOTA_LIMITS RunningQuotaLimits;
PQUOTA_LIMITS PointerToNextQuotaLimits = NULL;
PQUOTA_LIMITS PolicyDefaultQuotaLimits = NULL;
ULONG SidIndex;
LSAPR_HANDLE AccountHandle = NULL;
PULONG SystemAccessThisId = NULL;
//
// Verify that the Policy Handle is valid, is the handle to the Policy
// object and has the necessary access granted. Reference the handle.
// Note that the Lsa Database lock is NOT held at this point. Instead,
// the lock is taken and released by called routines where required.
//
Status = LsapDbReferenceObject(
PolicyHandle,
POLICY_VIEW_LOCAL_INFORMATION,
PolicyObject,
AccountObject,
LSAP_DB_LOCK | LSAP_DB_START_TRANSACTION |
LSAP_DB_NO_DS_OP_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION
);
if (!NT_SUCCESS(Status)) {
goto SlowQueryAllInformationAccountsError;
}
ObjectReferenced = TRUE;
PolicyDefaultQuotaLimits = &RunningQuotaLimits;
//
// Obtain the Master Default Quota Limits from the Policy Object.
//
Status = LsapDbQueryInformationPolicy(
LsapPolicyHandle,
PolicyDefaultQuotaInformation,
(PLSAPR_POLICY_INFORMATION *) &PolicyDefaultQuotaLimits
);
if (!NT_SUCCESS(Status)) {
goto SlowQueryAllInformationAccountsError;
}
//
// Iterate through all of the Sids provided. For each one, check if the
// Sid is that of an Account object in the local LSA. If it is,
//
// (1) Obtain the System Accesses and add those found so far.
// (2) Obtain the Account Privileges and add to thosde found so far.
// (3) Obtain the Quota Limits (if any) assigned to the account.
// Compare these with the quota limits obtained so far. If any
// limits are more generous than the running values, update
// the running values.
//
RunningSystemAccess = 0;
for( SidIndex = 0; SidIndex < IdCount; SidIndex++) {
//
// Attempt to open an Lsa Account object specifying the next Sid.
// If successful, the open returns a Trusted handle to the account.
//
Status = LsarOpenAccount(
PolicyHandle,
Ids[SidIndex].Sid,
ACCOUNT_VIEW,
(LSAPR_HANDLE *) &AccountHandle
);
if (!NT_SUCCESS(Status)) {
if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
break;
}
Status = STATUS_SUCCESS;
continue;
}
//
// An account object has been successfully opened. Obtain
// its system accesses.
//
Status = LsapDbSlowQueryInformationAccount(
AccountHandle,
AccountSystemAccessInformation,
(PLSAPR_ACCOUNT_INFO *) &SystemAccessThisId
);
if (!NT_SUCCESS(Status)) {
goto SlowQueryAllInformationAccountsError;
}
RunningSystemAccess |= *SystemAccessThisId;
MIDL_user_free(SystemAccessThisId);
SystemAccessThisId = NULL;
//
// Obtain the account's Special privileges.
//
ASSERT( NextPrivileges == NULL );
Status = LsapDbSlowQueryInformationAccount(
AccountHandle,
AccountPrivilegeInformation,
(PLSAPR_ACCOUNT_INFO *) &NextPrivileges
);
if (!NT_SUCCESS(Status)) {
goto SlowQueryAllInformationAccountsError;
}
//
// Add the Privileges of this account (if any) to the running set.
//
if (NextPrivileges != NULL) {
Status = LsapRtlAddPrivileges(
&RunningPrivileges,
&MaxRunningPrivileges,
NextPrivileges,
RTL_COMBINE_PRIVILEGE_ATTRIBUTES,
NULL // don't care if the set has changed or not
);
MIDL_user_free(NextPrivileges);
NextPrivileges = NULL;
if (!NT_SUCCESS(Status)) {
goto SlowQueryAllInformationAccountsError;
}
}
//
// Obtain the special Quota Limits for this account (if any).
//
Status = LsapDbSlowQueryInformationAccount(
AccountHandle,
AccountQuotaInformation,
(PLSAPR_ACCOUNT_INFO *) &PointerToNextQuotaLimits
);
if (Status == STATUS_NO_QUOTAS_FOR_ACCOUNT) {
LocalStatus = LsapCloseHandle( &AccountHandle, STATUS_SUCCESS );
continue;
}
if (!NT_SUCCESS(Status)) {
goto SlowQueryAllInformationAccountsError;
}
NextQuotaLimits = *PointerToNextQuotaLimits;
MIDL_user_free(PointerToNextQuotaLimits);
PointerToNextQuotaLimits = NULL;
//
// Special Quota Limits are assigned. Compare each of the quota
// limits obtained with the running values. If a quota limit just
// obtained is less restrictive than the running value, supersede the
// running value.
//
if (RunningQuotaLimits.PagedPoolLimit < NextQuotaLimits.PagedPoolLimit) {
RunningQuotaLimits.PagedPoolLimit = NextQuotaLimits.PagedPoolLimit;
}
if (RunningQuotaLimits.NonPagedPoolLimit < NextQuotaLimits.NonPagedPoolLimit) {
RunningQuotaLimits.NonPagedPoolLimit = NextQuotaLimits.NonPagedPoolLimit;
}
if (RunningQuotaLimits.MinimumWorkingSetSize > NextQuotaLimits.MinimumWorkingSetSize) {
RunningQuotaLimits.MinimumWorkingSetSize = NextQuotaLimits.MinimumWorkingSetSize;
}
if (RunningQuotaLimits.MaximumWorkingSetSize < NextQuotaLimits.MaximumWorkingSetSize) {
RunningQuotaLimits.MaximumWorkingSetSize = NextQuotaLimits.MaximumWorkingSetSize;
}
if (RunningQuotaLimits.PagefileLimit < NextQuotaLimits.PagefileLimit) {
RunningQuotaLimits.PagefileLimit = NextQuotaLimits.PagefileLimit;
}
if (RunningQuotaLimits.TimeLimit.QuadPart < NextQuotaLimits.TimeLimit.QuadPart) {
RunningQuotaLimits.TimeLimit = NextQuotaLimits.TimeLimit;
}
//
// Close the account handle
//
LocalStatus = LsapCloseHandle( &AccountHandle, STATUS_SUCCESS );
}
if (!NT_SUCCESS(Status)) {
goto SlowQueryAllInformationAccountsError;
}
//
// Return the collective Privilege Set
//
AccountInfo->PrivilegeSet = RunningPrivileges;
//
// Return the collective System Accesses
AccountInfo->SystemAccess = RunningSystemAccess;
//
// Return the collective Quota Limits
//
AccountInfo->QuotaLimits = RunningQuotaLimits;
SlowQueryAllInformationAccountsFinish:
if ( NextPrivileges != NULL ) {
MIDL_user_free( NextPrivileges );
}
//
// If necessary, dereference the Policy Object.
//
if (ObjectReferenced) {
LsapDbDereferenceObject(
&PolicyHandle,
PolicyObject,
AccountObject,
LSAP_DB_LOCK | LSAP_DB_FINISH_TRANSACTION |
LSAP_DB_NO_DS_OP_TRANSACTION | LSAP_DB_READ_ONLY_TRANSACTION,
(SECURITY_DB_DELTA_TYPE) 0,
Status
);
}
return(Status);
SlowQueryAllInformationAccountsError:
//
// If necessary, free the memory allocated for the Privilege Set.
//
if (RunningPrivileges != NULL) {
MIDL_user_free( RunningPrivileges );
RunningPrivileges = NULL;
}
//
// Close an account handle, if one is open
//
if (AccountHandle != NULL) {
LocalStatus = LsapCloseHandle( &AccountHandle, Status );
}
//
// Return null values
//
RtlZeroMemory( &AccountInfo->QuotaLimits, sizeof(QUOTA_LIMITS) );
AccountInfo->SystemAccess = 0;
AccountInfo->PrivilegeSet = NULL;
goto SlowQueryAllInformationAccountsFinish;
}
NTSTATUS
LsapDbSlowQueryPrivilegesAccount(
IN LSAPR_HANDLE AccountHandle,
OUT PLSAPR_PRIVILEGE_SET *Privileges
)
/*++
Routine Description:
This function is the slow LSA server RPC worker routine for the
LsaEnumeratePrivilegesOfAccount API.
The LsaEnumeratePrivilegesOfAccount API obtains information which
describes the privileges assigned to an account. This call requires
ACCOUNT_VIEW access to the account object.
Arguments:
AccountHandle - The handle to the open account object whose privilege
information is to be obtained. This handle will have been returned
from a prior LsaOpenAccount or LsaCreateAccountInLsa API call.
Privileges - Receives a pointer to a buffer containing the Privilege
Set. The Privilege Set is an array of structures, one for each
privilege. Each structure contains the LUID of the privilege and
a mask of the privilege's attributes.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_SUCCESS - The call completed successfully.
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
to complete the operation.
STATUS_INVALID_HANDLE - The specified AccountHandle is not valid.
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
such as memory, to complete the call.
--*/
{
NTSTATUS Status;
PPRIVILEGE_SET PrivilegeSet = NULL;
ULONG PrivilegeSetLength;
BOOLEAN ObjectReferenced = FALSE;
LSAP_DB_ATTRIBUTE Attribute;
PPRIVILEGE_SET DsPrivs;
UCHAR FastBuffer[ 256 ];
//
// Attempt query of attribute using fast stack buffer.
//
PrivilegeSetLength = sizeof(FastBuffer);
Status = LsapDbReadAttributeObject(
AccountHandle,
&LsapDbNames[Privilgs],
FastBuffer,
&PrivilegeSetLength
);
if(NT_SUCCESS(Status)) {
if( PrivilegeSetLength <= (sizeof(PRIVILEGE_SET) - sizeof (LUID_AND_ATTRIBUTES)) )
{
//
// The privilege set attribute exists but has zero entries.
// fall-through and handle it same way as non-existent entry.
//
Status = STATUS_OBJECT_NAME_NOT_FOUND;
} else {
//
// Success! copy the fast buffer for the caller.
//
PrivilegeSet = MIDL_user_allocate ( PrivilegeSetLength );
if (PrivilegeSet == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto SlowQueryPrivilegesError;
}
RtlCopyMemory( PrivilegeSet, FastBuffer, PrivilegeSetLength );
*Privileges = (PLSAPR_PRIVILEGE_SET) PrivilegeSet;
goto SlowQueryPrivilegesFinish;
}
}
if ((Status == STATUS_OBJECT_NAME_NOT_FOUND)) {
//
// If the Privileg attribute does not exist, convert the status
// back to STATUS_SUCCESS. Note that an account object need not
// have any privileges assigned so STATUS_OBJECT_NAME_NOT_FOUND is
// not an error in this case. Return a Privilege Set containing
// a zero Count.
//
PrivilegeSetLength = sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES);
PrivilegeSet = MIDL_user_allocate ( PrivilegeSetLength );
if (PrivilegeSet == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto SlowQueryPrivilegesError;
}
Status = STATUS_SUCCESS;
PrivilegeSet->Control = (ULONG) 0L;
PrivilegeSet->PrivilegeCount = (ULONG) 0L;
*Privileges = (PLSAPR_PRIVILEGE_SET) PrivilegeSet;
goto SlowQueryPrivilegesFinish;
}
//
// The Privileg attribute exists and has a value assigned. Allocate
// a buffer for its value.
//
PrivilegeSet = MIDL_user_allocate ( PrivilegeSetLength );
if (PrivilegeSet == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto SlowQueryPrivilegesError;
}
//
// Read the Privilgs attribute into the buffer. Note that although
// the value of this attribute has a variable length, it is bounded
// above.
//
Status = LsapDbReadAttributeObject(
AccountHandle,
&LsapDbNames[Privilgs],
PrivilegeSet,
&PrivilegeSetLength
);
if (!NT_SUCCESS(Status)) {
MIDL_user_free(PrivilegeSet);
goto SlowQueryPrivilegesError;
}
//
// Return the Privilege Set or NULL
//
*Privileges = (PLSAPR_PRIVILEGE_SET) PrivilegeSet;
SlowQueryPrivilegesFinish:
return( Status );
SlowQueryPrivilegesError:
*Privileges = NULL;
goto SlowQueryPrivilegesFinish;
}
NTSTATUS
LsapDbSlowQueryQuotasAccount(
IN LSAPR_HANDLE AccountHandle,
OUT PQUOTA_LIMITS QuotaLimits
)
/*++
Routine Description:
This function is the slow LSA server RPC worker routine for the
LsarGetQuotasForAccount API.
The LsaGetQuotasForAccount API obtains the quota limits for pageable and
non-pageable memory (in Kilobytes) and the maximum execution time (in
seconds) for any session logged on to the account specified by
AccountHandle. For each quota and explicit value is returned.
Quotas is not supported any more. In the past, we need LSA_ACCOUNT_VIEW
access to the object, but currently, there is no such access right &
you don't need any right to call this function. We will return QuotaLimits
as 0 and return STATUS_NO_QUOTAS_FOR_ACCOUNT.
Arguments:
AccountHandle - The handle to the open account object whose quotas
are to be obtained. This handle will have been returned
from a prior LsaOpenAccount or LsaCreateAccountInLsa API call.
QuotaLimits - Pointer to structure in which the system resource
quota limits applicable to each session logged on to this account
will be returned. Note that all quotas, including those specified
as being the system default values, are returned as actual values.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_INVALID_HANDLE - The specified AccountHandle is not valid.
--*/
{
//
// Quotas are defunct.
//
QuotaLimits->PagedPoolLimit = 0;
QuotaLimits->NonPagedPoolLimit = 0;
QuotaLimits->MinimumWorkingSetSize = 0;
QuotaLimits->MaximumWorkingSetSize = 0;
return( STATUS_NO_QUOTAS_FOR_ACCOUNT );
}
NTSTATUS
LsapDbSlowQuerySystemAccessAccount(
IN LSAPR_HANDLE AccountHandle,
OUT PULONG SystemAccess
)
/*++
Routine Description:
This function is the Slow worker for the LsaGetSystemAccessAccount()
API.
Arguments:
AccountHandle - The handle to the Account object whose system access
flags are to be read. This handle will have been returned
from a preceding LsaOpenAccount() or LsaCreateAccount() call
an must be open for ACCOUNT_VIEW access.
SystemAccess - Points to location that will receive the system access
flags for the account.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_SUCCESS - The call was successful.
STATUS_ACCESS_DENIED - The AccountHandle does not specify
ACCOUNT_VIEW access.
STATUS_INVALID_HANDLE - The specified AccountHandle is invalid.
--*/
{
NTSTATUS Status;
ULONG ReturnedSystemAccess;
ULONG ReturnedSystemAccessLength;
//
// Read the Account Object's System Access Flags
//
ReturnedSystemAccessLength = sizeof(ULONG);
Status = LsapDbReadAttributeObject(
AccountHandle,
&LsapDbNames[ActSysAc],
&ReturnedSystemAccess,
&ReturnedSystemAccessLength
);
if (!NT_SUCCESS(Status)) {
//
// If there is no System Access attribute, return the system default
// access.
//
// NOTE: The Master Default for the System Access attribute is
// currently hardwired.
//
if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
goto SlowQuerySystemAccessAccountError;
}
ReturnedSystemAccess = LSAP_DB_ACCOUNT_DEFAULT_SYS_ACCESS;
Status = STATUS_SUCCESS;
} else {
//
// Verify that the returned flags are valid
//
if (ReturnedSystemAccess != (ReturnedSystemAccess & POLICY_MODE_ALL)) {
if ( ReturnedSystemAccess == 0 && LsapDsWriteDs ) {
ReturnedSystemAccess = LSAP_DB_ACCOUNT_DEFAULT_SYS_ACCESS;
Status = STATUS_SUCCESS;
} else {
Status = STATUS_INTERNAL_DB_CORRUPTION;
goto SlowQuerySystemAccessAccountError;
}
}
}
*SystemAccess = ReturnedSystemAccess;
SlowQuerySystemAccessAccountFinish:
return(Status);
SlowQuerySystemAccessAccountError:
*SystemAccess = 0;
goto SlowQuerySystemAccessAccountFinish;
}
NTSTATUS
LsapDbLookupAccount(
IN PSID AccountSid,
OUT PLSAP_DB_ACCOUNT *Account
)
/*++
Routine Description:
This function looks up the Account information for a given Lsa Account.
Arguments:
AccountSid - Sid of the account
Account - Receives a pointer to the Account information.
--*/
{
PLSAP_DB_ACCOUNT NextAccount = NULL;
ULONG AccountIndex;
BOOLEAN AccountFound = FALSE;
ASSERTMSG( "Account Cache is not valid!", LsapDbIsCacheValid( AccountObject ) );
//
// Scan the list of Accounts.
//
for (AccountIndex = 0, NextAccount = LsapDbFirstAccount();
AccountIndex < LsapDbAccountList.AccountCount;
AccountIndex++, NextAccount = LsapDbNextAccount( NextAccount)
) {
//
// If the Sids match, we've found the account.
//
if (RtlEqualSid( AccountSid, NextAccount->Sid )) {
*Account = NextAccount;
AccountFound = TRUE;
break;
}
}
if (AccountFound) {
return(STATUS_SUCCESS);
}
return(STATUS_NO_SUCH_USER);
}
NTSTATUS
LsapDbCreateAccount(
IN PLSAPR_SID AccountSid,
OUT OPTIONAL PLSAP_DB_ACCOUNT *Account
)
/*++
Routine Description:
This function creates an Account's information block
Arguments:
AccountSid - Specifies the Sid of the Account
Account - Optionally receives a pointer to the newly created Account
information block.
--*/
{
NTSTATUS Status;
PLSAPR_SID CopiedSid = NULL;
PLSAP_DB_ACCOUNT OutputAccount = NULL;
//
// Verify that the Account List is valid.
//
if ((!LsapDbIsCacheValid(AccountObject)) && LsapInitialized ) {
Status = STATUS_INVALID_PARAMETER;
goto CreateAccountError;
}
//
// Make a copy of the Sid.
//
Status = LsapRpcCopySid(
NULL,
(PSID *) &CopiedSid,
(PSID) AccountSid
);
if (!NT_SUCCESS(Status)) {
goto CreateAccountError;
}
//
// Allocate memory for the Account information block.
//
OutputAccount = MIDL_user_allocate( sizeof(LSAP_DB_ACCOUNT) );
if (OutputAccount == NULL) {
Status = STATUS_NO_MEMORY;
goto CreateAccountError;
}
//
// Zeroise the new block.
//
RtlZeroMemory( OutputAccount, sizeof(LSAP_DB_ACCOUNT) );
//
// Copy in the Sid.
//
OutputAccount->Sid = CopiedSid;
//
// Link the Account to the head of the Account List.
//
InsertHeadList( &LsapDbAccountList.Links, &OutputAccount->Links );
//
// If requested, return a pointer to the Account.
//
if (Account != NULL) {
*Account = OutputAccount;
}
LsapDbAccountList.AccountCount++;
Status = STATUS_SUCCESS;
CreateAccountFinish:
return(Status);
CreateAccountError:
//
// If necessary, free the copied Sid.
//
if (CopiedSid != NULL) {
MIDL_user_free( CopiedSid );
CopiedSid = NULL;
}
//
// If necessary, free the memory allocated for the Account block.
//
if (OutputAccount != NULL) {
MIDL_user_free( OutputAccount);
OutputAccount = NULL;
}
//
// If a return pointer was specified, return NULL.
//
if (Account != NULL) {
*Account = NULL;
}
goto CreateAccountFinish;
}
NTSTATUS
LsapDbDeleteAccount(
IN PLSAPR_SID AccountSid
)
/*++
Routine Description:
This function deletes an Account's information block
Arguments:
AccountSid - Specifies the Sid of the Account
--*/
{
NTSTATUS Status;
PLSAP_DB_ACCOUNT Account = NULL;
//
// Verify that the Account List is valid.
//
if (!LsapDbIsCacheValid(AccountObject)) {
Status = STATUS_INVALID_PARAMETER;
goto DeleteAccountError;
}
//
// Lookup the Account Information Block to be deleted
//
Status = LsapDbLookupAccount( AccountSid, &Account);
if (!NT_SUCCESS(Status)) {
goto DeleteAccountError;
}
//
// We found the account. Unlink it from the Account List
//
RemoveEntryList( &Account->Links );
//
// Now free the Account Information
//
if (Account->Sid != NULL) {
MIDL_user_free( Account->Sid);
Account->Sid = NULL;
}
if (Account->Info.PrivilegeSet != NULL) {
MIDL_user_free( Account->Info.PrivilegeSet );
Account->Info.PrivilegeSet = NULL;
}
MIDL_user_free( Account );
LsapDbAccountList.AccountCount--;
DeleteAccountFinish:
return(Status);
DeleteAccountError:
goto DeleteAccountFinish;
}
NTSTATUS
LsapDbUpdateSystemAccessAccount(
IN PLSAPR_SID AccountSid,
IN PULONG SystemAccess
)
/*++
Routine Description:
This function updates the System Access flags in an Account's information
block.
Arguments:
AccountSid - Sid of account
SystemAccess - Pointer to new System Access flags. These flags
will overwrite the old value
Return Values:
NTSTATUS - Standard Nt Result Code
--*/
{
NTSTATUS Status;
PLSAP_DB_ACCOUNT Account = NULL;
//
// Verify that the Account List is valid.
//
if (!LsapDbIsCacheValid(AccountObject)) {
Status = STATUS_INVALID_PARAMETER;
goto UpdateSystemAccessAccountError;
}
//
// Lookup the Account
//
Status = LsapDbLookupAccount( AccountSid, &Account );
if (!NT_SUCCESS(Status)) {
goto UpdateSystemAccessAccountError;
}
//
// Update the System Access Flags
//
Account->Info.SystemAccess = *SystemAccess;
UpdateSystemAccessAccountFinish:
return(Status);
UpdateSystemAccessAccountError:
goto UpdateSystemAccessAccountFinish;
}
NTSTATUS
LsapDbUpdateQuotasAccount(
IN PLSAPR_SID AccountSid,
IN PQUOTA_LIMITS QuotaLimits
)
/*++
Routine Description:
This function updates the Quota Limits an Account's information
block.
Arguments:
AccountSid - Sid of Account
Quotas - Pointer to new Quota Limits flags. These flags
will overwrite the old value
Return Values:
NTSTATUS - Standard Nt Result Code
--*/
{
NTSTATUS Status;
PLSAP_DB_ACCOUNT Account = NULL;
//
// Verify that the Account List is valid.
//
if (!LsapDbIsCacheValid(AccountObject)) {
Status = STATUS_INVALID_PARAMETER;
goto UpdateQuotasAccountError;
}
//
// Lookup the Account
//
Status = LsapDbLookupAccount( AccountSid, &Account );
if (!NT_SUCCESS(Status)) {
goto UpdateQuotasAccountError;
}
//
// Update the System Access Flags
//
Account->Info.QuotaLimits = *QuotaLimits;
UpdateQuotasAccountFinish:
return(Status);
UpdateQuotasAccountError:
goto UpdateQuotasAccountFinish;
}
NTSTATUS
LsapDbUpdatePrivilegesAccount(
IN PLSAPR_SID AccountSid,
IN OPTIONAL PPRIVILEGE_SET Privileges
)
/*++
Routine Description:
This function replates the Privilege Set in an Account's information
block with the one given. The existing Privilege Set (if any) in the
block will be freed.
Arguments:
AccountSid - Sid of account
Privileges - Optional pointer to new Privilege Set. These flags
will overwrite the old value. if NULL is specified, a Privilege
Set containing 0 entries will be written.
Return Values:
NTSTATUS - Standard Nt Result Code
--*/
{
NTSTATUS Status;
PLSAP_DB_ACCOUNT Account = NULL;
PPRIVILEGE_SET OutputPrivileges = Privileges;
//
// Verify that the Account List is valid.
//
if (!LsapDbIsCacheValid( AccountObject)) {
Status = STATUS_INVALID_PARAMETER;
goto UpdatePrivilegesAccountError;
}
//
// Lookup the Account
//
Status = LsapDbLookupAccount( AccountSid, &Account );
if (!NT_SUCCESS(Status)) {
goto UpdatePrivilegesAccountError;
}
//
// If NULL was specified for the Privileges, construct a Privilege Set
// having 0 entries.
//
if (OutputPrivileges == NULL) {
OutputPrivileges = MIDL_user_allocate( sizeof(PRIVILEGE_SET) );
if (OutputPrivileges == NULL) {
Status = STATUS_NO_MEMORY;
goto UpdatePrivilegesAccountError;
}
OutputPrivileges->PrivilegeCount = 0;
OutputPrivileges->Control = 0;
}
//
// If there is an existing Privilege Set in the cache, free it.
//
if (Account->Info.PrivilegeSet != NULL) {
MIDL_user_free( Account->Info.PrivilegeSet );
Account->Info.PrivilegeSet = NULL;
}
//
// Update the Privileges
//
Account->Info.PrivilegeSet = OutputPrivileges;
UpdatePrivilegesAccountFinish:
return(Status);
UpdatePrivilegesAccountError:
if (Account != NULL) {
if( Account->Info.PrivilegeSet ) {
MIDL_user_free( Account->Info.PrivilegeSet );
}
Account->Info.PrivilegeSet = NULL;
}
goto UpdatePrivilegesAccountFinish;
}
NTSTATUS
LsapDbCreateAccountList(
OUT PLSAP_DB_ACCOUNT_LIST AccountList
)
/*++
Routine Description:
This function creates an empty Account List
Arguments
AccountList - Pointer to Account List structure that will be initialized.
Return Values:
NTSTATUS - Standard Nt Result Code
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
AccountList->AccountCount = 0;
InitializeListHead( &AccountList->Links );
return(Status);
}
NTSTATUS
LsapDbBuildAccountCache(
)
/*++
Routine Description:
This function constructs a cache for the Account objects. The cache
is a counted doubly linked list of blocks, one for each Account Object
found in the LSA Policy Database.
Arguments:
None.
Return Values:
NTSTATUS - Standard Nt Result Code
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
SID_AND_ATTRIBUTES AccountSidAndAttributes;
ULONG EnumerationIndex, EnumerationContext;
LSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer;
PLSAPR_SID AccountSid = NULL;
PLSAP_DB_ACCOUNT Account = NULL;
//
// Ensure caching of Account objects is turned off.
//
LsapDbMakeCacheBuilding( AccountObject );
//
// Initialize the Account List header with a skeleton entry for the
// System Account.
//
Status = LsapDbCreateAccountList(&LsapDbAccountList);
if (!NT_SUCCESS(Status)) {
goto BuildAccountCacheError;
}
LsapDbMakeCacheInvalid( AccountObject );
//
// Enumerate each of the LSA Account objects
//
Status = STATUS_MORE_ENTRIES;
EnumerationContext = 0;
while (Status == STATUS_MORE_ENTRIES) {
//
// Enumerate the next bunch of accounts.
//
Status = LsarEnumerateAccounts(
LsapPolicyHandle,
&EnumerationContext,
&EnumerationBuffer,
LSAP_DB_BUILD_ACCOUNT_LIST_LENGTH
);
if (!NT_SUCCESS(Status)) {
//
// We might just have got the warning that there are no more
// accounts. Reset to STATUS_SUCCESS and break out.
//
if (Status == STATUS_NO_MORE_ENTRIES) {
Status = STATUS_SUCCESS;
}
break;
}
//
// We've got some more accounts. Add them to the Account List
//
for( EnumerationIndex = 0;
EnumerationIndex < EnumerationBuffer.EntriesRead;
EnumerationIndex++ ) {
AccountSid = EnumerationBuffer.Information[ EnumerationIndex ].Sid;
Status = LsapDbCreateAccount( AccountSid, &Account );
if (!NT_SUCCESS(Status)) {
break;
}
AccountSidAndAttributes.Sid = (PSID) AccountSid;
AccountSidAndAttributes.Attributes = 0;
Status = LsapDbSlowQueryAllInformationAccounts(
LsapPolicyHandle,
1,
&AccountSidAndAttributes,
&Account->Info
);
if (!NT_SUCCESS(Status)) {
if (Status != STATUS_NO_MORE_ENTRIES) {
break;
}
Status = STATUS_SUCCESS;
}
}
if (!NT_SUCCESS(Status)) {
break;
}
Status = STATUS_MORE_ENTRIES;
LsaIFree_LSAPR_ACCOUNT_ENUM_BUFFER( &EnumerationBuffer );
}
if (!NT_SUCCESS(Status)) {
goto BuildAccountCacheError;
}
//
// Turn on caching for Account objects.
//
LsapDbMakeCacheValid( AccountObject );
Status = STATUS_SUCCESS;
BuildAccountCacheFinish:
return(Status);
BuildAccountCacheError:
LsapDbMakeCacheInvalid(AccountObject);
LsapDbMakeCacheUnsupported(AccountObject); goto BuildAccountCacheFinish; }