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.
2817 lines
80 KiB
2817 lines
80 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
aufilter.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the famous LSA logon Filter/Augmentor logic.
|
|
|
|
Author:
|
|
|
|
Jim Kelly (JimK) 11-Mar-1992
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <lsapch2.h>
|
|
#include <adtp.h>
|
|
//#define LSAP_DONT_ASSIGN_DEFAULT_DACL
|
|
|
|
#define LSAP_CONTEXT_SID_USER_INDEX 0
|
|
#define LSAP_CONTEXT_SID_PRIMARY_GROUP_INDEX 1
|
|
#define LSAP_FIXED_POSITION_SID_COUNT 2
|
|
#define LSAP_MAX_STANDARD_IDS 7 // user, group, world, logontype, terminal server, authuser, organization
|
|
|
|
#define ALIGN_SIZEOF(_u,_v) FIELD_OFFSET( struct { _u _test1; _v _test2; }, _test2 )
|
|
#define OFFSET_ALIGN(_p,_t) (_t *)(((INT_PTR)(((PBYTE)(_p))+TYPE_ALIGNMENT(_t) - 1)) & ~(TYPE_ALIGNMENT(_t)-1))
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Module local macros //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define LsapFreeSampUlongArray( A ) \
|
|
{ \
|
|
if ((A)->Element != NULL) { \
|
|
MIDL_user_free((A)->Element); \
|
|
} \
|
|
}
|
|
|
|
#define IsTerminalServer() (BOOLEAN)(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer))
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Module-wide global variables //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Indicates whether we have already opened SAM handles and initialized
|
|
// corresponding variables.
|
|
//
|
|
|
|
ULONG LsapAuSamOpened = FALSE;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Module local routine definitions //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
LsapAuSetLogonPrivilegeStates(
|
|
IN SECURITY_LOGON_TYPE LogonType,
|
|
IN ULONG PrivilegeCount,
|
|
IN PLUID_AND_ATTRIBUTES Privileges
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapAuSetPassedIds(
|
|
IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType,
|
|
IN PVOID TokenInformation,
|
|
IN PTOKEN_GROUPS LocalGroups,
|
|
IN ULONG FinalIdLimit,
|
|
OUT PULONG FinalIdCount,
|
|
OUT PSID_AND_ATTRIBUTES FinalIds
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapSetDefaultDacl(
|
|
IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType,
|
|
IN PVOID TokenInformation,
|
|
OUT PLSA_TOKEN_INFORMATION_V2 TokenInfo
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapAuAddStandardIds(
|
|
IN SECURITY_LOGON_TYPE LogonType,
|
|
IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType,
|
|
IN BOOLEAN fNullSessionRestricted,
|
|
IN OPTIONAL PSID UserSid,
|
|
IN ULONG FinalIdLimit,
|
|
IN OUT PULONG FinalIdCount,
|
|
IN OUT PSID_AND_ATTRIBUTES FinalIds
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapAuBuildTokenInfoAndAddLocalAliases(
|
|
IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType,
|
|
IN PVOID OldTokenInformation,
|
|
IN ULONG HighRateIdCount,
|
|
IN ULONG FinalIdCount,
|
|
IN PSID_AND_ATTRIBUTES FinalIds,
|
|
OUT PLSA_TOKEN_INFORMATION_V2 *TokenInfo,
|
|
OUT PULONG TokenSize,
|
|
IN BOOL RecoveryMode
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapGetAccountDomainInfo(
|
|
PPOLICY_ACCOUNT_DOMAIN_INFO *PolicyAccountDomainInfo
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapAuVerifyLogonType(
|
|
IN SECURITY_LOGON_TYPE LogonType,
|
|
IN ULONG SystemAccess
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapAuSetTokenInformation(
|
|
IN OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
|
|
IN OUT PVOID *TokenInformation,
|
|
IN ULONG FinalIdCount,
|
|
IN PSID_AND_ATTRIBUTES FinalIds,
|
|
IN ULONG PrivilegeCount,
|
|
IN PLUID_AND_ATTRIBUTES Privileges,
|
|
IN ULONG NewTokenInfoSize,
|
|
IN OUT PLSA_TOKEN_INFORMATION_V2 *NewTokenInfo
|
|
|
|
);
|
|
|
|
NTSTATUS
|
|
LsapAuDuplicateSid(
|
|
PSID *Target,
|
|
PSID Source
|
|
);
|
|
|
|
BOOLEAN
|
|
LsapIsSidLogonSid(
|
|
PSID Sid
|
|
);
|
|
|
|
BOOL
|
|
LsapIsAdministratorRecoveryMode(
|
|
IN PSID UserSid
|
|
);
|
|
|
|
BOOLEAN
|
|
CheckNullSessionAccess(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
IsTerminalServerRA(
|
|
VOID
|
|
);
|
|
|
|
BOOLEAN
|
|
IsTSUSerSidEnabled(
|
|
VOID
|
|
);
|
|
|
|
BOOLEAN
|
|
CheckAdminOwnerSetting(
|
|
VOID
|
|
);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Routines //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
NTSTATUS
|
|
LsapAuUserLogonPolicyFilter(
|
|
IN SECURITY_LOGON_TYPE LogonType,
|
|
IN PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
|
|
IN PVOID *TokenInformation,
|
|
IN PTOKEN_GROUPS LocalGroups,
|
|
OUT PQUOTA_LIMITS QuotaLimits,
|
|
OUT PPRIVILEGE_SET *PrivilegesAssigned,
|
|
IN BOOL RecoveryMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs per-logon filtering and augmentation to
|
|
implement local system security policies. These policies include
|
|
assignment of local aliases, privileges, and quotas.
|
|
|
|
The basic logic flow of the filter augmentor is:
|
|
|
|
1) Receive a set of user and group IDs that have already
|
|
been assigned as a result of authentication. Presumably
|
|
these IDs have been provided by the authenticating
|
|
security authority.
|
|
|
|
|
|
2) Based upon the LogonType, add a set of standard IDs to the
|
|
list. This will include WORLD and an ID representing the
|
|
logon type (e.g., INTERACTIVE, NETWORK, SERVICE).
|
|
|
|
|
|
3) Call SAM to retrieve additional ALIAS IDs assigned by the
|
|
local ACCOUNTS domain.
|
|
|
|
|
|
4) Call SAM to retrieve additional ALIAS IDs assigned by the
|
|
local BUILTIN domain.
|
|
|
|
|
|
5) Retrieve any privileges and or quotas assigned to the resultant
|
|
set of IDs. This also informs us whether or not the specific
|
|
type of logon is to be allowed. Enable privs for network logons.
|
|
|
|
|
|
6) If a default DACL has not already been established, assign
|
|
one.
|
|
|
|
|
|
7) Shuffle all high-use-rate IDs to preceed those that aren't
|
|
high-use-rate to obtain maximum performance.
|
|
|
|
Arguments:
|
|
|
|
LogonType - Specifies the type of logon being requested (e.g.,
|
|
Interactive, network, et cetera).
|
|
|
|
TokenInformationType - Indicates what format the provided set of
|
|
token information is in.
|
|
|
|
TokenInformation - Provides the set of user and group IDs. This
|
|
structure will be modified as necessary to incorporate local
|
|
security policy (e.g., SIDs added or removed, privileges added
|
|
or removed).
|
|
|
|
QuotaLimits - Quotas assigned to the user logging on.
|
|
|
|
RecoveryMode - if TRUE, this is an admin logon in recovery mode
|
|
and we already established that the administrator is a member
|
|
of way too many groups, so only minimal membership info
|
|
is returned.
|
|
|
|
Outside callers must ALWAYS set this parameter to FALSE
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The service has completed successfully.
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES - heap could not be allocated to house
|
|
the combination of the existing and new groups.
|
|
|
|
STATUS_INVALID_LOGON_TYPE - The value specified for LogonType is not
|
|
a valid value.
|
|
|
|
STATUS_LOGON_TYPE_NOT_GRANTED - Indicates the user has not been granted
|
|
the requested type of logon by local security policy. Logon should
|
|
be rejected.
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
BOOLEAN fNullSessionRestricted = FALSE;
|
|
ULONG i;
|
|
ULONG FinalIdCount = 0, FinalPrivilegeCount = 0;
|
|
ULONG FinalIdLimit;
|
|
PRIVILEGE_SET *FinalPrivileges = NULL;
|
|
PTOKEN_PRIVILEGES pPrivs = NULL;
|
|
LSAP_DB_ACCOUNT_TYPE_SPECIFIC_INFO AccountInfo;
|
|
PSID UserSid = NULL;
|
|
|
|
SID_AND_ATTRIBUTES *FinalIds = NULL;
|
|
PLSA_TOKEN_INFORMATION_V2 TokenInfo = NULL;
|
|
ULONG TokenInfoSize = 0;
|
|
|
|
//
|
|
// Validate the Logon Type.
|
|
//
|
|
|
|
if ( (LogonType != Interactive) &&
|
|
(LogonType != Network) &&
|
|
(LogonType != Service) &&
|
|
(LogonType != Batch) &&
|
|
(LogonType != NetworkCleartext) &&
|
|
(LogonType != NewCredentials ) &&
|
|
(LogonType != CachedInteractive) &&
|
|
(LogonType != RemoteInteractive ) ) {
|
|
|
|
Status = STATUS_INVALID_LOGON_TYPE;
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
//
|
|
// Estimate the number of Final IDs
|
|
//
|
|
|
|
FinalIdLimit = LSAP_MAX_STANDARD_IDS;
|
|
|
|
if ( *TokenInformationType == LsaTokenInformationNull ) {
|
|
|
|
fNullSessionRestricted = CheckNullSessionAccess();
|
|
|
|
if ( !fNullSessionRestricted ) {
|
|
|
|
FinalIdLimit += 1;
|
|
}
|
|
|
|
if ((( PLSA_TOKEN_INFORMATION_NULL )( *TokenInformation ))->Groups ) {
|
|
|
|
FinalIdLimit += (( PLSA_TOKEN_INFORMATION_NULL )( *TokenInformation ))->Groups->GroupCount;
|
|
}
|
|
|
|
} else if ( *TokenInformationType == LsaTokenInformationV1 ||
|
|
*TokenInformationType == LsaTokenInformationV2 ) {
|
|
|
|
//
|
|
// Figure out the user's SID
|
|
//
|
|
|
|
UserSid = ((PLSA_TOKEN_INFORMATION_V2)( *TokenInformation ))->User.User.Sid;
|
|
|
|
if ((( PLSA_TOKEN_INFORMATION_V2 )( *TokenInformation ))->Groups ) {
|
|
|
|
FinalIdLimit += (( PLSA_TOKEN_INFORMATION_V2 )( *TokenInformation ))->Groups->GroupCount;
|
|
}
|
|
|
|
//
|
|
// Get a local pointer to the privileges -- it'll be used below
|
|
//
|
|
|
|
pPrivs = ((PLSA_TOKEN_INFORMATION_V2) (*TokenInformation))->Privileges;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Unknown token information type
|
|
//
|
|
|
|
ASSERT( FALSE );
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
if ( LocalGroups ) {
|
|
|
|
FinalIdLimit += LocalGroups->GroupCount;
|
|
|
|
if ( RecoveryMode &&
|
|
FinalIdLimit > LSAI_CONTEXT_SID_LIMIT )
|
|
{
|
|
//
|
|
// If in recovery mode, trim the local group list as necessary
|
|
//
|
|
|
|
LocalGroups->GroupCount -= ( FinalIdLimit - LSAI_CONTEXT_SID_LIMIT );
|
|
FinalIdLimit = LSAI_CONTEXT_SID_LIMIT;
|
|
}
|
|
}
|
|
|
|
SafeAllocaAllocate(
|
|
FinalIds,
|
|
FinalIdLimit * sizeof( SID_AND_ATTRIBUTES )
|
|
);
|
|
|
|
if ( FinalIds == NULL ) {
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Build up a list of IDs and privileges to return //
|
|
// This list is initialized to contain the set of IDs //
|
|
// passed in. //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Leave room for SIDs that have a fixed position in the array.
|
|
FinalIdCount = LSAP_FIXED_POSITION_SID_COUNT;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Build a list of low rate ID's from standard list //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
Status = LsapAuAddStandardIds(
|
|
LogonType,
|
|
(*TokenInformationType),
|
|
fNullSessionRestricted,
|
|
UserSid,
|
|
FinalIdLimit,
|
|
&FinalIdCount,
|
|
FinalIds
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
Status = LsapAuSetPassedIds(
|
|
(*TokenInformationType),
|
|
(*TokenInformation),
|
|
LocalGroups,
|
|
FinalIdLimit,
|
|
&FinalIdCount,
|
|
FinalIds
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
if ( FinalIdCount > LSAI_CONTEXT_SID_LIMIT ) {
|
|
|
|
goto TooManyContextIds;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Copy in aliases from the local domains (BUILT-IN and ACCOUNT) //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
Status = LsapAuBuildTokenInfoAndAddLocalAliases(
|
|
(*TokenInformationType),
|
|
(*TokenInformation),
|
|
LSAP_FIXED_POSITION_SID_COUNT + (fNullSessionRestricted?0:1),
|
|
FinalIdCount,
|
|
FinalIds,
|
|
&TokenInfo,
|
|
&TokenInfoSize,
|
|
RecoveryMode
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Retrieve Privileges And Quotas //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Get the union of all Privileges, Quotas and System Accesses assigned
|
|
// to the user's list of ids from the LSA Policy Database.
|
|
//
|
|
|
|
if ( TokenInfo->Groups->GroupCount + 1 > LSAI_CONTEXT_SID_LIMIT ) {
|
|
|
|
goto TooManyContextIds;
|
|
|
|
} else if ( TokenInfo->Groups->GroupCount + 1 > FinalIdLimit ) {
|
|
|
|
SafeAllocaFree( FinalIds );
|
|
FinalIdLimit = TokenInfo->Groups->GroupCount + 1;
|
|
SafeAllocaAllocate( FinalIds, sizeof( SID_AND_ATTRIBUTES ) * FinalIdLimit );
|
|
|
|
if ( FinalIds == NULL ) {
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
}
|
|
|
|
FinalIds[0] = TokenInfo->User.User;
|
|
FinalIdCount = 1;
|
|
|
|
for(i=0; i < TokenInfo->Groups->GroupCount; i++)
|
|
{
|
|
FinalIds[FinalIdCount] = TokenInfo->Groups->Groups[i];
|
|
FinalIdCount++;
|
|
}
|
|
|
|
FinalPrivilegeCount = 0;
|
|
|
|
Status = LsapDbQueryAllInformationAccounts(
|
|
(LSAPR_HANDLE) LsapPolicyHandle,
|
|
FinalIdCount,
|
|
FinalIds,
|
|
&AccountInfo
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
//
|
|
// Verify that we have the necessary System Access for our logon type.
|
|
// We omit this check if we are using the NULL session. Override the
|
|
// privileges supplied by policy if they're explicitly set in the
|
|
// token info (i.e., in the case where we've cloned an existing logon
|
|
// session for a LOGON32_LOGON_NEW_CREDENTIALS logon).
|
|
//
|
|
|
|
if (pPrivs != NULL)
|
|
{
|
|
FinalPrivileges = (PPRIVILEGE_SET) MIDL_user_allocate(sizeof(PRIVILEGE_SET)
|
|
+ (pPrivs->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES));
|
|
|
|
if (FinalPrivileges == NULL)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
FinalPrivileges->PrivilegeCount = FinalPrivilegeCount = pPrivs->PrivilegeCount;
|
|
FinalPrivileges->Control = 0;
|
|
|
|
RtlCopyMemory(FinalPrivileges->Privilege,
|
|
pPrivs->Privileges,
|
|
pPrivs->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
|
|
|
|
MIDL_user_free( AccountInfo.PrivilegeSet );
|
|
}
|
|
else if (AccountInfo.PrivilegeSet != NULL)
|
|
{
|
|
FinalPrivileges = AccountInfo.PrivilegeSet;
|
|
FinalPrivilegeCount = AccountInfo.PrivilegeSet->PrivilegeCount;
|
|
}
|
|
|
|
AccountInfo.PrivilegeSet = NULL;
|
|
|
|
if (UserSid != NULL)
|
|
{
|
|
if (RtlEqualSid(UserSid, LsapLocalSystemSid))
|
|
{
|
|
AccountInfo.SystemAccess = SECURITY_ACCESS_INTERACTIVE_LOGON |
|
|
SECURITY_ACCESS_NETWORK_LOGON |
|
|
SECURITY_ACCESS_BATCH_LOGON |
|
|
SECURITY_ACCESS_SERVICE_LOGON |
|
|
SECURITY_ACCESS_PROXY_LOGON |
|
|
SECURITY_ACCESS_REMOTE_INTERACTIVE_LOGON ;
|
|
}
|
|
else if (RtlEqualSid(UserSid, LsapLocalServiceSid))
|
|
{
|
|
AccountInfo.SystemAccess = SECURITY_ACCESS_SERVICE_LOGON;
|
|
}
|
|
else if (RtlEqualSid(UserSid, LsapNetworkServiceSid))
|
|
{
|
|
AccountInfo.SystemAccess = SECURITY_ACCESS_SERVICE_LOGON;
|
|
}
|
|
}
|
|
|
|
if (*TokenInformationType != LsaTokenInformationNull) {
|
|
|
|
Status = LsapAuVerifyLogonType( LogonType, AccountInfo.SystemAccess );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
}
|
|
|
|
if (FinalPrivilegeCount > SEP_MAX_PRIVILEGE_COUNT)
|
|
{
|
|
ASSERT( FALSE ); // can't have more than the maximum defined number of privileges!
|
|
Status = STATUS_INTERNAL_ERROR;
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
#ifndef LSAP_DONT_ASSIGN_DEFAULT_DACL
|
|
|
|
Status = LsapSetDefaultDacl( (*TokenInformationType),
|
|
(*TokenInformation),
|
|
TokenInfo
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
#endif //LSAP_DONT_ASSIGN_DEFAULT_DACL
|
|
|
|
//
|
|
// Now update the TokenInformation structure.
|
|
// This causes all allocated IDs and privileges to be
|
|
// freed (even if unsuccessful).
|
|
//
|
|
|
|
Status = LsapAuSetTokenInformation(
|
|
TokenInformationType,
|
|
TokenInformation,
|
|
FinalIdCount,
|
|
FinalIds,
|
|
FinalPrivilegeCount,
|
|
FinalPrivileges->Privilege,
|
|
TokenInfoSize,
|
|
&TokenInfo
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
//
|
|
// Enable or Disable privileges according to our logon type
|
|
// This is necessary until we get dynamic security tracking.
|
|
//
|
|
// ISSUE: Skip this for NULL tokens?
|
|
//
|
|
|
|
if (pPrivs == NULL)
|
|
{
|
|
LsapAuSetLogonPrivilegeStates(
|
|
LogonType,
|
|
((PLSA_TOKEN_INFORMATION_V2)(*TokenInformation))->Privileges->PrivilegeCount,
|
|
((PLSA_TOKEN_INFORMATION_V2)(*TokenInformation))->Privileges->Privileges
|
|
);
|
|
}
|
|
|
|
//
|
|
// Return these so they can be audited. Data
|
|
// will be freed in the caller.
|
|
//
|
|
|
|
*QuotaLimits = AccountInfo.QuotaLimits;
|
|
*PrivilegesAssigned = FinalPrivileges;
|
|
|
|
UserLogonPolicyFilterFinish:
|
|
|
|
if ( FinalIds )
|
|
{
|
|
SafeAllocaFree(FinalIds);
|
|
}
|
|
|
|
if(TokenInfo)
|
|
{
|
|
LsapFreeTokenInformationV2(TokenInfo);
|
|
}
|
|
|
|
return(Status);
|
|
|
|
UserLogonPolicyFilterError:
|
|
|
|
//
|
|
// If necessary, clean up Privileges buffer
|
|
//
|
|
|
|
if (FinalPrivileges != NULL) {
|
|
|
|
MIDL_user_free( FinalPrivileges );
|
|
FinalPrivileges = NULL;
|
|
}
|
|
|
|
goto UserLogonPolicyFilterFinish;
|
|
|
|
TooManyContextIds:
|
|
|
|
if (( *TokenInformationType != LsaTokenInformationV1 &&
|
|
*TokenInformationType != LsaTokenInformationV2 ) ||
|
|
!LsapIsAdministratorRecoveryMode( UserSid )) {
|
|
|
|
CHAR * UserSidText = NULL;
|
|
|
|
Status = STATUS_TOO_MANY_CONTEXT_IDS;
|
|
|
|
if ( UserSid ) {
|
|
|
|
SafeAllocaAllocate( UserSidText, LsapDbGetSizeTextSid( UserSid ));
|
|
}
|
|
|
|
if ( UserSidText == NULL ||
|
|
!NT_SUCCESS( LsapDbSidToTextSid( UserSid, UserSidText ))) {
|
|
|
|
UserSidText = "<NULL>";
|
|
}
|
|
|
|
//
|
|
// Log an event describing the problem and possible solutions
|
|
//
|
|
|
|
SpmpReportEvent(
|
|
FALSE, // not UNICODE
|
|
EVENTLOG_WARNING_TYPE,
|
|
LSA_TOO_MANY_CONTEXT_IDS,
|
|
0,
|
|
0,
|
|
NULL,
|
|
1,
|
|
UserSidText
|
|
);
|
|
|
|
if ( UserSid ) {
|
|
|
|
SafeAllocaFree( UserSidText );
|
|
}
|
|
|
|
goto UserLogonPolicyFilterError;
|
|
|
|
} else if ( RecoveryMode ) {
|
|
|
|
//
|
|
// Must never get to this point in recovery mode, or infinite recursion will result
|
|
//
|
|
|
|
ASSERT( FALSE );
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto UserLogonPolicyFilterError;
|
|
|
|
} else {
|
|
|
|
LSA_TOKEN_INFORMATION_TYPE TokenInformationTypeMin;
|
|
PLSA_TOKEN_INFORMATION_V2 TokenInformationMin;
|
|
QUOTA_LIMITS QuotaLimitsMin = {0};
|
|
PPRIVILEGE_SET PrivilegesAssignedMin = NULL;
|
|
|
|
PLSA_TOKEN_INFORMATION_V2 TI = ( PLSA_TOKEN_INFORMATION_V2 )( *TokenInformation );
|
|
|
|
ULONG MinimalGroupRidsDs[] = {
|
|
DOMAIN_GROUP_RID_ADMINS, // Domain admins
|
|
};
|
|
ULONG MinimalGroupCountDs = sizeof( MinimalGroupRidsDs ) / sizeof( MinimalGroupRidsDs[0] );
|
|
|
|
ULONG MinimalGroupRidsNoDs[] = {
|
|
DOMAIN_GROUP_RID_USERS, // Domain users
|
|
};
|
|
ULONG MinimalGroupCountNoDs = sizeof( MinimalGroupRidsNoDs ) / sizeof( MinimalGroupRidsNoDs[0] );
|
|
|
|
ULONG * MinimalGroupRids;
|
|
ULONG MinimalGroupCount;
|
|
ULONG MinimalLocalGroupCount;
|
|
|
|
ULONG UserSidLen = RtlLengthSid( UserSid );
|
|
|
|
PTOKEN_GROUPS NewLocalGroups = NULL;
|
|
ULONG SwapLoc = 0;
|
|
|
|
TokenInformationTypeMin = *TokenInformationType;
|
|
|
|
TokenInformationMin = ( PLSA_TOKEN_INFORMATION_V2 )LsapAllocateLsaHeap( sizeof( LSA_TOKEN_INFORMATION_V2));
|
|
|
|
if ( TokenInformationMin == NULL ) {
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
//
|
|
// ExpirationTime
|
|
//
|
|
|
|
TokenInformationMin->ExpirationTime = TI->ExpirationTime;
|
|
|
|
//
|
|
// User
|
|
//
|
|
|
|
TokenInformationMin->User.User.Attributes = TI->User.User.Attributes;
|
|
|
|
if ( TI->User.User.Sid ) {
|
|
|
|
Status = LsapAuDuplicateSid(
|
|
&TokenInformationMin->User.User.Sid,
|
|
TI->User.User.Sid
|
|
);
|
|
|
|
if ( !NT_SUCCESS( Status )) {
|
|
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
} else {
|
|
|
|
ASSERT( FALSE ); // don't believe this is possible
|
|
TokenInformationMin->User.User.Sid = NULL;
|
|
}
|
|
|
|
//
|
|
// Groups
|
|
//
|
|
// If DS is not running, add DOMAIN_GROUP_RID_USERS only
|
|
// If DS is running, add DOMAIN_GROUP_RID_ADMINS
|
|
//
|
|
|
|
if ( LsapDsIsRunning ) {
|
|
|
|
MinimalGroupRids = MinimalGroupRidsDs;
|
|
MinimalGroupCount = MinimalGroupCountDs;
|
|
|
|
} else {
|
|
|
|
MinimalGroupRids = MinimalGroupRidsNoDs;
|
|
MinimalGroupCount = MinimalGroupCountNoDs;
|
|
}
|
|
|
|
TokenInformationMin->Groups = ( PTOKEN_GROUPS )LsapAllocateLsaHeap( sizeof( TOKEN_GROUPS ) + ( MinimalGroupCount - 1 ) * sizeof( SID_AND_ATTRIBUTES ));
|
|
|
|
if ( TokenInformationMin->Groups == NULL ) {
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
TokenInformationMin->Groups->GroupCount = 0;
|
|
|
|
for ( i = 0 ; i < MinimalGroupCount ; i++ ) {
|
|
|
|
SID * Sid;
|
|
|
|
Sid = ( SID * )LsapAllocateLsaHeap( UserSidLen );
|
|
|
|
if ( Sid == NULL ) {
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
RtlCopySid( UserSidLen, Sid, UserSid );
|
|
|
|
Sid->SubAuthority[Sid->SubAuthorityCount-1] = MinimalGroupRids[i];
|
|
|
|
TokenInformationMin->Groups->Groups[i].Attributes = SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED;
|
|
TokenInformationMin->Groups->Groups[i].Sid = ( PSID )Sid;
|
|
TokenInformationMin->Groups->GroupCount++;
|
|
}
|
|
|
|
//
|
|
// PrimaryGroup
|
|
//
|
|
|
|
if ( TI->PrimaryGroup.PrimaryGroup ) {
|
|
|
|
Status = LsapAuDuplicateSid(
|
|
&TokenInformationMin->PrimaryGroup.PrimaryGroup,
|
|
TI->PrimaryGroup.PrimaryGroup
|
|
);
|
|
|
|
if ( !NT_SUCCESS( Status )) {
|
|
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
} else {
|
|
|
|
TokenInformationMin->PrimaryGroup.PrimaryGroup = NULL;
|
|
}
|
|
|
|
//
|
|
// Privileges
|
|
//
|
|
|
|
TokenInformationMin->Privileges = NULL;
|
|
|
|
//
|
|
// Owner
|
|
//
|
|
|
|
if ( TI->Owner.Owner ) {
|
|
|
|
Status = LsapAuDuplicateSid(
|
|
&TokenInformationMin->Owner.Owner,
|
|
TI->Owner.Owner
|
|
);
|
|
|
|
if ( !NT_SUCCESS( Status )) {
|
|
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
} else {
|
|
|
|
TokenInformationMin->Owner.Owner = NULL;
|
|
}
|
|
|
|
//
|
|
// DefaultDacl
|
|
//
|
|
|
|
TokenInformationMin->DefaultDacl.DefaultDacl = NULL;
|
|
|
|
if ( LocalGroups ) {
|
|
|
|
//
|
|
// Rearrange the local groups to put the logon groups first -
|
|
// in case the list might have to be trimmed during the recursion pass
|
|
//
|
|
|
|
NewLocalGroups = (PTOKEN_GROUPS)LsapAllocateLsaHeap( sizeof( TOKEN_GROUPS ) + ( LocalGroups->GroupCount - ANYSIZE_ARRAY ) * sizeof( SID_AND_ATTRIBUTES ));
|
|
|
|
if ( NewLocalGroups == NULL )
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto UserLogonPolicyFilterError;
|
|
}
|
|
|
|
NewLocalGroups->GroupCount = LocalGroups->GroupCount;
|
|
|
|
RtlCopyMemory(
|
|
NewLocalGroups->Groups,
|
|
LocalGroups->Groups,
|
|
LocalGroups->GroupCount * sizeof( SID_AND_ATTRIBUTES ));
|
|
|
|
for ( i = 1; i < NewLocalGroups->GroupCount; i++ )
|
|
{
|
|
SID_AND_ATTRIBUTES Temp;
|
|
|
|
if ( NewLocalGroups->Groups[i].Attributes & SE_GROUP_LOGON_ID )
|
|
{
|
|
Temp = NewLocalGroups->Groups[SwapLoc];
|
|
NewLocalGroups->Groups[SwapLoc] = NewLocalGroups->Groups[i];
|
|
NewLocalGroups->Groups[i] = Temp;
|
|
SwapLoc += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ok, the minimal information has been built, we're off to the races
|
|
// Call ourselves recursively and steal the results
|
|
//
|
|
|
|
Status = LsapAuUserLogonPolicyFilter(
|
|
LogonType,
|
|
&TokenInformationTypeMin,
|
|
&TokenInformationMin,
|
|
NewLocalGroups,
|
|
&QuotaLimitsMin,
|
|
&PrivilegesAssignedMin,
|
|
TRUE
|
|
);
|
|
|
|
*TokenInformationType = TokenInformationTypeMin;
|
|
*TokenInformation = TokenInformationMin;
|
|
*QuotaLimits = QuotaLimitsMin;
|
|
*PrivilegesAssigned = PrivilegesAssignedMin;
|
|
|
|
LsapFreeLsaHeap( NewLocalGroups );
|
|
|
|
//
|
|
// We're prepared for anything but this, as it would
|
|
// put us into a recursive loop without end!
|
|
//
|
|
|
|
if ( Status == STATUS_TOO_MANY_CONTEXT_IDS ) {
|
|
|
|
//
|
|
// This must NEVER happen, as this is a sure recipe for
|
|
// infinite recursion. Assert in CHK, clear the error
|
|
// code and replace with something else in FRE
|
|
//
|
|
|
|
ASSERT( FALSE ); // we'll never get here, right?
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if ( !NT_SUCCESS( Status )) {
|
|
|
|
goto UserLogonPolicyFilterError;
|
|
|
|
} else {
|
|
|
|
goto UserLogonPolicyFilterFinish;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAuVerifyLogonType(
|
|
IN SECURITY_LOGON_TYPE LogonType,
|
|
IN ULONG SystemAccess
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function verifies that a User has the system access granted necessary
|
|
for the speicifed logon type.
|
|
|
|
Arguments
|
|
|
|
LogonType - Specifies the type of logon being requested (e.g.,
|
|
Interactive, network, et cetera).
|
|
|
|
SystemAccess - Specifies the System Access granted to the User.
|
|
|
|
Return Values:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
STATUS_SUCCESS - The user has the necessary system access.
|
|
|
|
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;
|
|
|
|
//
|
|
// Determine if the specified Logon Type is granted by any of the
|
|
// groups or aliases specified.
|
|
//
|
|
|
|
switch (LogonType) {
|
|
|
|
case Interactive:
|
|
case CachedInteractive:
|
|
|
|
if (!(SystemAccess & SECURITY_ACCESS_INTERACTIVE_LOGON) ||
|
|
(SystemAccess & SECURITY_ACCESS_DENY_INTERACTIVE_LOGON)) {
|
|
|
|
Status = STATUS_LOGON_TYPE_NOT_GRANTED;
|
|
}
|
|
|
|
break;
|
|
|
|
case NewCredentials:
|
|
|
|
//
|
|
// NewCredentials does not require a logon type, since this is a dup
|
|
// of someone who has logged on already somewhere else.
|
|
//
|
|
|
|
NOTHING;
|
|
|
|
break;
|
|
|
|
case Network:
|
|
case NetworkCleartext:
|
|
|
|
if (!(SystemAccess & SECURITY_ACCESS_NETWORK_LOGON)||
|
|
(SystemAccess & SECURITY_ACCESS_DENY_NETWORK_LOGON)) {
|
|
|
|
Status = STATUS_LOGON_TYPE_NOT_GRANTED;
|
|
}
|
|
|
|
break;
|
|
|
|
case Batch:
|
|
|
|
if ((SystemAccess & SECURITY_ACCESS_DENY_BATCH_LOGON) ||
|
|
!(SystemAccess & SECURITY_ACCESS_BATCH_LOGON)) {
|
|
|
|
Status = STATUS_LOGON_TYPE_NOT_GRANTED;
|
|
}
|
|
|
|
break;
|
|
|
|
case Service:
|
|
|
|
if ((SystemAccess & SECURITY_ACCESS_DENY_SERVICE_LOGON) ||
|
|
!(SystemAccess & SECURITY_ACCESS_SERVICE_LOGON)) {
|
|
|
|
Status = STATUS_LOGON_TYPE_NOT_GRANTED;
|
|
}
|
|
|
|
break;
|
|
|
|
case RemoteInteractive:
|
|
if ( ( SystemAccess & SECURITY_ACCESS_DENY_REMOTE_INTERACTIVE_LOGON ) ||
|
|
! ( SystemAccess & SECURITY_ACCESS_REMOTE_INTERACTIVE_LOGON ) ) {
|
|
|
|
Status = STATUS_LOGON_TYPE_NOT_GRANTED ;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAuSetPassedIds(
|
|
IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType,
|
|
IN PVOID TokenInformation,
|
|
IN PTOKEN_GROUPS LocalGroups,
|
|
IN ULONG FinalIdLimit,
|
|
OUT PULONG FinalIdCount,
|
|
OUT PSID_AND_ATTRIBUTES FinalIds
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the FinalIds array.
|
|
|
|
Arguments:
|
|
|
|
TokenInformationType - Indicates what format the provided set of
|
|
token information is in.
|
|
|
|
TokenInformation - Provides the initial set of user and group IDs.
|
|
|
|
FinalIdCount - Will be set to contain the number of IDs passed.
|
|
|
|
FinalIds - will contain the set of IDs passed in.
|
|
|
|
IdProperties - Will be set to indicate none of the initial
|
|
IDs were locally allocated. It will also identify the
|
|
first two ids (if there are two ids) to be HIGH_RATE.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Succeeded.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i, j;
|
|
PTOKEN_USER User;
|
|
PTOKEN_GROUPS Groups;
|
|
PTOKEN_PRIMARY_GROUP PrimaryGroup;
|
|
PSID PrimaryGroupSid = NULL;
|
|
PULONG PrimaryGroupAttributes = NULL;
|
|
ULONG CurrentId = 0;
|
|
ULONG ThisOrgIndex;
|
|
PTOKEN_GROUPS GroupsArray[2];
|
|
ULONG GroupsArraySize = 0;
|
|
|
|
//
|
|
// Get the passed ids
|
|
//
|
|
|
|
ASSERT( (TokenInformationType == LsaTokenInformationNull ) ||
|
|
(TokenInformationType == LsaTokenInformationV1) ||
|
|
(TokenInformationType == LsaTokenInformationV2));
|
|
|
|
if (TokenInformationType == LsaTokenInformationNull) {
|
|
User = NULL;
|
|
Groups = ((PLSA_TOKEN_INFORMATION_NULL)(TokenInformation))->Groups;
|
|
PrimaryGroup = NULL;
|
|
} else {
|
|
User = &((PLSA_TOKEN_INFORMATION_V2)TokenInformation)->User;
|
|
Groups = ((PLSA_TOKEN_INFORMATION_V2)TokenInformation)->Groups;
|
|
PrimaryGroup = &((PLSA_TOKEN_INFORMATION_V2)TokenInformation)->PrimaryGroup;
|
|
}
|
|
|
|
if (User != NULL) {
|
|
|
|
//
|
|
// TokenInformation included a user ID.
|
|
//
|
|
|
|
FinalIds[LSAP_CONTEXT_SID_USER_INDEX] = User->User;
|
|
|
|
}
|
|
else
|
|
{
|
|
// Set the user as anonymous
|
|
|
|
FinalIds[LSAP_CONTEXT_SID_USER_INDEX].Sid = LsapAnonymousSid;
|
|
FinalIds[LSAP_CONTEXT_SID_USER_INDEX].Attributes = (SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED
|
|
);
|
|
}
|
|
|
|
if ( PrimaryGroup != NULL )
|
|
{
|
|
//
|
|
// TokenInformation included a primary group ID.
|
|
//
|
|
|
|
FinalIds[LSAP_CONTEXT_SID_PRIMARY_GROUP_INDEX].Sid = PrimaryGroup->PrimaryGroup;
|
|
FinalIds[LSAP_CONTEXT_SID_PRIMARY_GROUP_INDEX].Attributes = (SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED
|
|
);
|
|
|
|
//
|
|
// Store a pointer to the attributes and the sid so we can later
|
|
// fill in the attributes from the rest of the group memebership.
|
|
//
|
|
|
|
PrimaryGroupAttributes = &FinalIds[LSAP_CONTEXT_SID_PRIMARY_GROUP_INDEX].Attributes;
|
|
PrimaryGroupSid = PrimaryGroup->PrimaryGroup;
|
|
}
|
|
else
|
|
{
|
|
FinalIds[LSAP_CONTEXT_SID_PRIMARY_GROUP_INDEX].Sid = LsapNullSid;
|
|
FinalIds[LSAP_CONTEXT_SID_PRIMARY_GROUP_INDEX].Attributes = 0;
|
|
}
|
|
|
|
if ( LocalGroups ) {
|
|
|
|
GroupsArray[GroupsArraySize++] = LocalGroups;
|
|
}
|
|
|
|
if ( Groups ) {
|
|
|
|
GroupsArray[GroupsArraySize++] = Groups;
|
|
}
|
|
|
|
CurrentId = (*FinalIdCount);
|
|
|
|
//
|
|
// Assume "this organization". If this assumption proves incorrect,
|
|
// the SID will be overwritten later.
|
|
//
|
|
|
|
ASSERT( CurrentId < FinalIdLimit );
|
|
FinalIds[CurrentId].Sid = LsapThisOrganizationSid;
|
|
FinalIds[CurrentId].Attributes = SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED;
|
|
ThisOrgIndex = CurrentId;
|
|
CurrentId++;
|
|
|
|
for ( j = 0; j < GroupsArraySize; j++ ) {
|
|
|
|
PTOKEN_GROUPS CurrentGroups = GroupsArray[j];
|
|
|
|
for ( i = 0; i < CurrentGroups->GroupCount; i++ ) {
|
|
|
|
//
|
|
// If the "other org" sid was passed,
|
|
// replace the "this org" sid and attributes with the one passed.
|
|
//
|
|
|
|
if ( RtlEqualSid(
|
|
LsapOtherOrganizationSid,
|
|
CurrentGroups->Groups[i].Sid )) {
|
|
|
|
FinalIds[ThisOrgIndex] = CurrentGroups->Groups[i];
|
|
|
|
|
|
} else if ( PrimaryGroupSid != NULL &&
|
|
RtlEqualSid(
|
|
PrimaryGroupSid,
|
|
CurrentGroups->Groups[i].Sid )) {
|
|
|
|
//
|
|
// If this sid is the primary group, it is already in the list
|
|
// of final IDs but we need to add the attribute
|
|
//
|
|
|
|
*PrimaryGroupAttributes = CurrentGroups->Groups[i].Attributes;
|
|
|
|
} else {
|
|
|
|
ASSERT( CurrentId < FinalIdLimit );
|
|
|
|
//
|
|
// Ownership of the SID remains with the LocalGroups structure, which
|
|
// will be freed by the caller
|
|
//
|
|
|
|
FinalIds[CurrentId] = CurrentGroups->Groups[i];
|
|
|
|
//
|
|
// if this SID is a logon SID, then set the SE_GROUP_LOGON_ID
|
|
// attribute
|
|
//
|
|
|
|
if (LsapIsSidLogonSid(FinalIds[CurrentId].Sid) == TRUE) {
|
|
|
|
FinalIds[CurrentId].Attributes |= SE_GROUP_LOGON_ID;
|
|
}
|
|
|
|
CurrentId++;
|
|
}
|
|
}
|
|
}
|
|
|
|
(*FinalIdCount) = CurrentId;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapSetDefaultDacl(
|
|
IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType,
|
|
IN PVOID TokenInformation,
|
|
IN OUT PLSA_TOKEN_INFORMATION_V2 TokenInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine produces a default DACL if the existing TokenInformation
|
|
does not already have one. NULL logon types don't have default DACLs
|
|
and so this routine simply returns success for those logon types.
|
|
|
|
|
|
The default DACL will be:
|
|
|
|
SYSTEM: ALL Access
|
|
Owner: ALL Access
|
|
|
|
!! IMPORTANT !! IMPORTANT !! IMPORTANT !! IMPORTANT !!
|
|
|
|
NOTE: The FinalOwnerIndex should not be changed after
|
|
calling this routine.
|
|
|
|
!! IMPORTANT !! IMPORTANT !! IMPORTANT !! IMPORTANT !!
|
|
|
|
Arguments:
|
|
|
|
TokenInformationType - Indicates what format the provided set of
|
|
token information is in.
|
|
|
|
TokenInformation - Points to token information which has the current
|
|
default DACL.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Succeeded.
|
|
|
|
STATUS_NO_MEMORY - Indicates there was not enough heap memory available
|
|
to allocate the default DACL.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PACL Acl;
|
|
ULONG Length;
|
|
PLSA_TOKEN_INFORMATION_V2 CastTokenInformation;
|
|
PSID OwnerSid = NULL;
|
|
|
|
//
|
|
// NULL token information?? (has no default dacl)
|
|
//
|
|
|
|
if (TokenInformationType == LsaTokenInformationNull) {
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
ASSERT((TokenInformationType == LsaTokenInformationV1) ||
|
|
(TokenInformationType == LsaTokenInformationV2));
|
|
|
|
CastTokenInformation = (PLSA_TOKEN_INFORMATION_V2)TokenInformation;
|
|
|
|
//
|
|
// Already have a default DACL?
|
|
//
|
|
|
|
Acl = CastTokenInformation->DefaultDacl.DefaultDacl;
|
|
|
|
if (Acl != NULL) {
|
|
|
|
ACL_SIZE_INFORMATION AclSize;
|
|
|
|
Status = RtlQueryInformationAcl(Acl,
|
|
&AclSize,
|
|
sizeof(AclSize),
|
|
AclSizeInformation);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
return Status;
|
|
}
|
|
|
|
RtlCopyMemory(TokenInfo->DefaultDacl.DefaultDacl, Acl,AclSize.AclBytesFree + AclSize.AclBytesInUse);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
Acl = TokenInfo->DefaultDacl.DefaultDacl;
|
|
|
|
OwnerSid = TokenInfo->Owner.Owner?TokenInfo->Owner.Owner:TokenInfo->User.User.Sid;
|
|
|
|
Length = sizeof(ACL) +
|
|
(2*((ULONG)sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) +
|
|
RtlLengthSid(OwnerSid) +
|
|
RtlLengthSid( LsapLocalSystemSid );
|
|
|
|
Status = RtlCreateAcl( Acl, Length, ACL_REVISION2);
|
|
|
|
if(!NT_SUCCESS(Status) )
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
//
|
|
// OWNER access - put this one first for performance sake
|
|
//
|
|
|
|
Status = RtlAddAccessAllowedAce (
|
|
Acl,
|
|
ACL_REVISION2,
|
|
GENERIC_ALL,
|
|
OwnerSid
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status) )
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
//
|
|
// SYSTEM access
|
|
//
|
|
|
|
Status = RtlAddAccessAllowedAce (
|
|
Acl,
|
|
ACL_REVISION2,
|
|
GENERIC_ALL,
|
|
LsapLocalSystemSid
|
|
);
|
|
error:
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAuAddStandardIds(
|
|
IN SECURITY_LOGON_TYPE LogonType,
|
|
IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType,
|
|
IN BOOLEAN fNullSessionRestricted,
|
|
IN OPTIONAL PSID UserSid,
|
|
IN ULONG FinalIdLimit,
|
|
IN OUT PULONG FinalIdCount,
|
|
IN OUT PSID_AND_ATTRIBUTES FinalIds
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds standard IDs to the FinalIds array.
|
|
|
|
This causes the WORLD id to be added and an ID representing
|
|
logon type to be added.
|
|
|
|
For anonymous logons, it will also add the ANONYMOUS id.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
LogonType - Specifies the type of logon being requested (e.g.,
|
|
Interactive, network, et cetera).
|
|
|
|
TokenInformationType - The token information type returned by
|
|
the authentication package. The set of IDs added is dependent
|
|
upon the type of logon.
|
|
|
|
FinalIdCount - Will be incremented to reflect newly added IDs.
|
|
|
|
FinalIds - will have new IDs added to it.
|
|
|
|
IdProperties - Will be set to indicate that these IDs must be
|
|
copied and that WORLD is a high-hit-rate id.
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Succeeded.
|
|
|
|
STATUS_TOO_MANY_CONTEXT_IDS - There are too many IDs in the context.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
ASSERT( LSAP_MAX_STANDARD_IDS <= FinalIdLimit );
|
|
ASSERT( *FinalIdCount < FinalIdLimit );
|
|
|
|
i = (*FinalIdCount);
|
|
|
|
if( !fNullSessionRestricted ) {
|
|
|
|
// This is a high rate id, so add it to the front of the array
|
|
FinalIds[i].Sid = LsapWorldSid;
|
|
FinalIds[i].Attributes = (SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED
|
|
);
|
|
i++;
|
|
}
|
|
|
|
//
|
|
// Add Logon type SID
|
|
//
|
|
|
|
switch ( LogonType ) {
|
|
case Interactive:
|
|
case NewCredentials:
|
|
case CachedInteractive:
|
|
|
|
FinalIds[i].Sid = LsapInteractiveSid;
|
|
break;
|
|
|
|
case RemoteInteractive:
|
|
FinalIds[i].Sid = LsapRemoteInteractiveSid;
|
|
break;
|
|
|
|
case Network:
|
|
case NetworkCleartext:
|
|
FinalIds[i].Sid = LsapNetworkSid;
|
|
break;
|
|
|
|
case Batch:
|
|
FinalIds[i].Sid = LsapBatchSid;
|
|
break;
|
|
|
|
case Service:
|
|
FinalIds[i].Sid = LsapServiceSid;
|
|
break;
|
|
|
|
default:
|
|
ASSERT("Unknown new logon type in LsapAuAddStandardIds" && FALSE);
|
|
}
|
|
|
|
|
|
if ( FinalIds[ i ].Sid )
|
|
{
|
|
FinalIds[i].Attributes = (SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED
|
|
);
|
|
i++;
|
|
}
|
|
|
|
//
|
|
// Add SIDs that are required when TS is running.
|
|
//
|
|
if ( IsTerminalServer() )
|
|
{
|
|
switch ( LogonType )
|
|
{
|
|
case RemoteInteractive:
|
|
|
|
//
|
|
// check to see if we are suppose to add the INTERACTIVE SID to the remote session
|
|
// for console level app compatability.
|
|
//
|
|
|
|
FinalIds[i].Sid = LsapInteractiveSid;
|
|
FinalIds[i].Attributes = (SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED
|
|
);
|
|
i++;
|
|
|
|
//
|
|
// fall thru
|
|
//
|
|
|
|
case Interactive :
|
|
case NewCredentials:
|
|
case CachedInteractive:
|
|
|
|
// check to see if we are suppose to add the TSUSER SID to the session. This
|
|
// is for TS4-app-compatability security mode.
|
|
|
|
if ( IsTSUSerSidEnabled() )
|
|
{
|
|
//
|
|
// Don't add TSUSER sid for GUEST logon
|
|
//
|
|
if ( ( TokenInformationType != LsaTokenInformationNull ) &&
|
|
( UserSid ) &&
|
|
( *RtlSubAuthorityCountSid( UserSid ) > 0 ) &&
|
|
( *RtlSubAuthoritySid( UserSid,
|
|
(ULONG) (*RtlSubAuthorityCountSid( UserSid ) ) - 1) != DOMAIN_USER_RID_GUEST ) )
|
|
{
|
|
FinalIds[i].Sid = LsapTerminalServerSid;
|
|
FinalIds[i].Attributes = (SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED
|
|
);
|
|
i++;
|
|
}
|
|
}
|
|
} // logon type switch for TS SIDs
|
|
} // if TS test
|
|
|
|
//
|
|
// If this is a not a null logon, and not a GUEST logon,
|
|
// then add in the AUTHENTICATED USER SID.
|
|
//
|
|
|
|
if ( ( TokenInformationType != LsaTokenInformationNull ) &&
|
|
( UserSid ) &&
|
|
( *RtlSubAuthorityCountSid( UserSid ) > 0 ) &&
|
|
( *RtlSubAuthoritySid( UserSid,
|
|
(ULONG) (*RtlSubAuthorityCountSid( UserSid ) ) - 1) != DOMAIN_USER_RID_GUEST ) )
|
|
{
|
|
FinalIds[i].Sid = LsapAuthenticatedUserSid; //Use the global SID
|
|
FinalIds[i].Attributes = (SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED
|
|
);
|
|
i++;
|
|
}
|
|
|
|
(*FinalIdCount) = i;
|
|
|
|
ASSERT( *FinalIdCount <= FinalIdLimit );
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAuBuildTokenInfoAndAddLocalAliases(
|
|
IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType,
|
|
IN PVOID OldTokenInformation,
|
|
IN ULONG HighRateIdCount,
|
|
IN ULONG FinalIdCount,
|
|
IN PSID_AND_ATTRIBUTES FinalIds,
|
|
OUT PLSA_TOKEN_INFORMATION_V2 *TokenInfo,
|
|
OUT PULONG TokenInfoSize,
|
|
IN BOOL RecoveryMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds aliases assigned to the IDs in FinalIds.
|
|
|
|
This will look in both the BUILT-IN and ACCOUNT domains locally.
|
|
|
|
|
|
1) Adds aliases assigned to the user via the local ACCOUNTS
|
|
domain.
|
|
|
|
2) Adds aliases assigned to the user via the local BUILT-IN
|
|
domain.
|
|
|
|
3) If the ADMINISTRATORS alias is assigned to the user, then it
|
|
is made the user's default owner.
|
|
|
|
|
|
NOTE: Aliases, by their nature, are expected to be high-use-rate
|
|
IDs.
|
|
|
|
Arguments:
|
|
|
|
|
|
FinalIdCount - Will be incremented to reflect any newly added IDs.
|
|
|
|
FinalIds - will have any assigned alias IDs added to it.
|
|
|
|
IdProperties - Will be set to indicate that any aliases added were
|
|
allocated by this routine.
|
|
|
|
RecoveryMode - if TRUE, this is an admin logon in recovery mode
|
|
and we already established that the administrator is a member
|
|
of way too many groups, so only minimal membership info
|
|
is returned.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Succeeded.
|
|
|
|
STATUS_TOO_MANY_CONTEXT_IDS - There are too many IDs in the context.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS, SuccessExpected;
|
|
ULONG i;
|
|
SAMPR_SID_INFORMATION *SidArray = NULL;
|
|
SAMPR_ULONG_ARRAY AccountMembership, BuiltinMembership;
|
|
SAMPR_PSID_ARRAY SamprSidArray;
|
|
|
|
ULONG TokenSize = 0;
|
|
PLSA_TOKEN_INFORMATION_V2 NewTokenInfo = NULL;
|
|
PSID_AND_ATTRIBUTES GroupArray = NULL;
|
|
|
|
PBYTE CurrentSid = NULL;
|
|
ULONG CurrentSidLength = 0;
|
|
ULONG CurrentGroup = 0;
|
|
|
|
PLSA_TOKEN_INFORMATION_V2 OldTokenInfo = NULL;
|
|
ULONG DefaultDaclSize = 0;
|
|
|
|
PSID SidPackage[1] = { NULL }; // room for only one
|
|
BYTE SidPackageBuffer[ SECURITY_MAX_SID_SIZE ];
|
|
ULONG SidPackageCount = 0;
|
|
|
|
if((TokenInformationType == LsaTokenInformationV1) ||
|
|
(TokenInformationType == LsaTokenInformationV2))
|
|
{
|
|
OldTokenInfo = (PLSA_TOKEN_INFORMATION_V2)OldTokenInformation;
|
|
}
|
|
|
|
//
|
|
// Make sure SAM has been opened. We'll get hadnles to both of the
|
|
// SAM Local Domains.
|
|
//
|
|
|
|
Status = LsapAuOpenSam( FALSE );
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(Status);
|
|
}
|
|
|
|
SafeAllocaAllocate( SidArray, (FinalIdCount * sizeof(SAMPR_SID_INFORMATION)) );
|
|
if( SidArray == NULL )
|
|
{
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
for ( i=0; i<FinalIdCount; i++) {
|
|
|
|
SidArray[i].SidPointer = (PRPC_SID)FinalIds[i].Sid;
|
|
}
|
|
|
|
SamprSidArray.Count = FinalIdCount;
|
|
SamprSidArray.Sids = &SidArray[0];
|
|
|
|
//
|
|
// For the given set of Sids, obtain their collective membership of
|
|
// Aliases in the Accounts domain
|
|
//
|
|
|
|
AccountMembership.Count = 0;
|
|
AccountMembership.Element = NULL;
|
|
|
|
Status = SamIGetAliasMembership( LsapAccountDomainHandle,
|
|
&SamprSidArray,
|
|
&AccountMembership
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
SafeAllocaFree( SidArray );
|
|
SidArray = NULL;
|
|
return(Status);
|
|
|
|
} else if ( RecoveryMode ) {
|
|
|
|
//
|
|
// Only leave built-in RIDs in the array
|
|
//
|
|
|
|
for ( i = AccountMembership.Count; i > 0; i-- ) {
|
|
|
|
if ( AccountMembership.Element[i-1] > SAMI_RESTRICTED_ACCOUNT_COUNT ) {
|
|
|
|
AccountMembership.Element[i-1] = AccountMembership.Element[AccountMembership.Count-1];
|
|
AccountMembership.Count -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// For the given set of Sids, obtain their collective membership of
|
|
// Aliases in the Built-In domain
|
|
//
|
|
|
|
BuiltinMembership.Count = 0;
|
|
BuiltinMembership.Element = NULL;
|
|
Status = SamIGetAliasMembership( LsapBuiltinDomainHandle,
|
|
&SamprSidArray,
|
|
&BuiltinMembership
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
LsapFreeSampUlongArray( &AccountMembership );
|
|
SafeAllocaFree( SidArray );
|
|
SidArray = NULL;
|
|
|
|
return(Status);
|
|
|
|
} else if ( RecoveryMode ) {
|
|
|
|
//
|
|
// Only leave built-in RIDs in the array
|
|
//
|
|
|
|
for ( i = BuiltinMembership.Count; i > 0; i-- ) {
|
|
|
|
if ( BuiltinMembership.Element[i-1] > SAMI_RESTRICTED_ACCOUNT_COUNT ) {
|
|
|
|
BuiltinMembership.Element[i-1] = BuiltinMembership.Element[BuiltinMembership.Count-1];
|
|
BuiltinMembership.Count -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// check for a package sid.
|
|
//
|
|
|
|
{
|
|
ULONG_PTR PackageId = GetCurrentPackageId();
|
|
DWORD dwRPCID;
|
|
|
|
if( PackageId )
|
|
{
|
|
dwRPCID = SpmpGetRpcPackageId( PackageId );
|
|
|
|
//
|
|
// if there was a valid package, craft a sid for it.
|
|
// don't do so for Kerberos at this time, as, cross-protocol
|
|
// delegation needs to be addressed.
|
|
//
|
|
|
|
if( (dwRPCID != 0) &&
|
|
(dwRPCID != SECPKG_ID_NONE) &&
|
|
(dwRPCID != RPC_C_AUTHN_GSS_KERBEROS)
|
|
)
|
|
{
|
|
SID_IDENTIFIER_AUTHORITY PackageSidAuthority = SECURITY_NT_AUTHORITY;
|
|
|
|
SidPackage[0] = (PSID)SidPackageBuffer;
|
|
|
|
RtlInitializeSid(SidPackage[0], &PackageSidAuthority, 2);
|
|
*(RtlSubAuthoritySid(SidPackage[0], 0)) = SECURITY_PACKAGE_BASE_RID;
|
|
*(RtlSubAuthoritySid(SidPackage[0], 1)) = dwRPCID;
|
|
|
|
SidPackageCount = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate memory to build the tokeninfo
|
|
//
|
|
|
|
// Calculate size of resulting tokeninfo
|
|
|
|
CurrentSidLength = RtlLengthSid( FinalIds[0].Sid);
|
|
|
|
// Size the base structure and group array
|
|
TokenSize = ALIGN_SIZEOF(LSA_TOKEN_INFORMATION_V2, TOKEN_GROUPS) +
|
|
sizeof(TOKEN_GROUPS) +
|
|
(AccountMembership.Count +
|
|
BuiltinMembership.Count +
|
|
SidPackageCount +
|
|
FinalIdCount - 1 - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES); // Do not include the User SID in this array
|
|
|
|
|
|
// Sids are ULONG aligned, whereas the SID_AND_ATTRIBUTES should be ULONG or greater aligned
|
|
TokenSize += CurrentSidLength +
|
|
LsapAccountDomainMemberSidLength*AccountMembership.Count +
|
|
LsapBuiltinDomainMemberSidLength*BuiltinMembership.Count;
|
|
|
|
// Add in size of all passed in/standard sids
|
|
for(i=1; i < FinalIdCount; i++)
|
|
{
|
|
TokenSize += RtlLengthSid( FinalIds[i].Sid);
|
|
}
|
|
|
|
for(i=0; i < SidPackageCount ;i++)
|
|
{
|
|
TokenSize += RtlLengthSid( SidPackage[i] );
|
|
}
|
|
|
|
// Add the size for the DACL
|
|
if(OldTokenInfo)
|
|
{
|
|
if(OldTokenInfo->DefaultDacl.DefaultDacl)
|
|
{
|
|
ACL_SIZE_INFORMATION AclSize;
|
|
|
|
Status = RtlQueryInformationAcl(OldTokenInfo->DefaultDacl.DefaultDacl,
|
|
&AclSize,
|
|
sizeof(AclSize),
|
|
AclSizeInformation);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
DefaultDaclSize = AclSize.AclBytesFree + AclSize.AclBytesInUse;
|
|
}
|
|
else
|
|
{
|
|
|
|
DefaultDaclSize = sizeof(ACL) + // Default ACL
|
|
(2*((ULONG)sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) +
|
|
max(CurrentSidLength, LsapBuiltinDomainMemberSidLength) +
|
|
RtlLengthSid( LsapLocalSystemSid );
|
|
}
|
|
TokenSize = PtrToUlong(OFFSET_ALIGN((ULONG_PTR)TokenSize, ACL)) + DefaultDaclSize;
|
|
}
|
|
|
|
// Add the privilege estimate
|
|
TokenSize = PtrToUlong(
|
|
(PVOID) ((INT_PTR) OFFSET_ALIGN((ULONG_PTR)TokenSize, TOKEN_PRIVILEGES) +
|
|
sizeof(TOKEN_PRIVILEGES) + // Prealloc some room for privileges
|
|
(sizeof(LUID_AND_ATTRIBUTES) * (SEP_MAX_PRIVILEGE_COUNT - ANYSIZE_ARRAY))));
|
|
|
|
|
|
|
|
NewTokenInfo = (PLSA_TOKEN_INFORMATION_V2)LsapAllocateLsaHeap(TokenSize);
|
|
if(NULL == NewTokenInfo)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
RtlZeroMemory(NewTokenInfo, TokenSize);
|
|
|
|
// Fixup pointers
|
|
NewTokenInfo->Groups = (PTOKEN_GROUPS)OFFSET_ALIGN((NewTokenInfo + 1), TOKEN_GROUPS);
|
|
NewTokenInfo->Groups->GroupCount = AccountMembership.Count +
|
|
BuiltinMembership.Count +
|
|
SidPackageCount +
|
|
FinalIdCount - 1;
|
|
|
|
CurrentSid = (PBYTE)(&NewTokenInfo->Groups->Groups[NewTokenInfo->Groups->GroupCount]);
|
|
|
|
// Copy user sid
|
|
SuccessExpected = RtlCopySid(CurrentSidLength, CurrentSid, FinalIds[0].Sid);
|
|
ASSERT( NT_SUCCESS( SuccessExpected ));
|
|
NewTokenInfo->User.User.Sid = (PSID)CurrentSid;
|
|
NewTokenInfo->User.User.Attributes = FinalIds[0].Attributes;
|
|
CurrentSid += CurrentSidLength;
|
|
|
|
GroupArray = NewTokenInfo->Groups->Groups;
|
|
|
|
// Copy high rate sids to array (they are static globals, so they don't need to be copied into buffer)
|
|
for(i=1; i < HighRateIdCount; i++)
|
|
{
|
|
CurrentSidLength = RtlLengthSid( FinalIds[i].Sid);
|
|
SuccessExpected = RtlCopySid(CurrentSidLength, CurrentSid, FinalIds[i].Sid);
|
|
ASSERT( NT_SUCCESS( SuccessExpected ));
|
|
GroupArray[CurrentGroup].Sid = CurrentSid;
|
|
GroupArray[CurrentGroup].Attributes = FinalIds[i].Attributes;
|
|
CurrentGroup++;
|
|
CurrentSid += CurrentSidLength;
|
|
}
|
|
|
|
NewTokenInfo->PrimaryGroup.PrimaryGroup = GroupArray[LSAP_CONTEXT_SID_PRIMARY_GROUP_INDEX-1].Sid;
|
|
|
|
//
|
|
// Copy Account Aliases
|
|
//
|
|
|
|
for ( i=0; i<AccountMembership.Count; i++) {
|
|
|
|
SuccessExpected = RtlCopySid( LsapAccountDomainMemberSidLength,
|
|
CurrentSid,
|
|
LsapAccountDomainMemberSid
|
|
);
|
|
|
|
ASSERT(NT_SUCCESS(SuccessExpected));
|
|
|
|
(*RtlSubAuthoritySid( CurrentSid, LsapAccountDomainSubCount-1)) =
|
|
AccountMembership.Element[i];
|
|
GroupArray[CurrentGroup].Sid = (PSID)CurrentSid;
|
|
|
|
GroupArray[CurrentGroup].Attributes = (SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED);
|
|
|
|
CurrentSid += LsapAccountDomainMemberSidLength;
|
|
CurrentGroup++;
|
|
|
|
}
|
|
|
|
// Copy Builtin Aliases
|
|
|
|
for ( i=0; i<BuiltinMembership.Count; i++) {
|
|
SuccessExpected = RtlCopySid( LsapBuiltinDomainMemberSidLength,
|
|
CurrentSid,
|
|
LsapBuiltinDomainMemberSid
|
|
);
|
|
ASSERT(NT_SUCCESS(SuccessExpected));
|
|
|
|
(*RtlSubAuthoritySid( CurrentSid, LsapBuiltinDomainSubCount-1)) =
|
|
BuiltinMembership.Element[i];
|
|
|
|
GroupArray[CurrentGroup].Sid = (PSID)CurrentSid;
|
|
GroupArray[CurrentGroup].Attributes = (SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED);
|
|
|
|
if (BuiltinMembership.Element[i] == DOMAIN_ALIAS_RID_ADMINS) {
|
|
|
|
//
|
|
// ADMINISTRATORS alias member - set it up as the default owner
|
|
//
|
|
GroupArray[CurrentGroup].Attributes |= (SE_GROUP_OWNER);
|
|
|
|
if ( CheckAdminOwnerSetting() )
|
|
{
|
|
NewTokenInfo->Owner.Owner = (PSID)CurrentSid;
|
|
}
|
|
}
|
|
CurrentSid += LsapBuiltinDomainMemberSidLength;
|
|
CurrentGroup++;
|
|
}
|
|
|
|
// Finish up with the low rate
|
|
// Copy high rate sids to array (they are static globals, so they don't need to be copied into buffer)
|
|
for(i=HighRateIdCount; i < FinalIdCount; i++)
|
|
{
|
|
CurrentSidLength = RtlLengthSid( FinalIds[i].Sid);
|
|
SuccessExpected = RtlCopySid(CurrentSidLength, CurrentSid, FinalIds[i].Sid);
|
|
ASSERT( NT_SUCCESS( SuccessExpected ));
|
|
GroupArray[CurrentGroup].Sid = CurrentSid;
|
|
GroupArray[CurrentGroup].Attributes = FinalIds[i].Attributes;
|
|
CurrentGroup++;
|
|
CurrentSid += CurrentSidLength;
|
|
}
|
|
|
|
for(i=0; i < SidPackageCount ;i++)
|
|
{
|
|
CurrentSidLength = RtlLengthSid( SidPackage[i] );
|
|
SuccessExpected = RtlCopySid(CurrentSidLength, CurrentSid, SidPackage[i]);
|
|
ASSERT( NT_SUCCESS( SuccessExpected ));
|
|
GroupArray[CurrentGroup].Sid = CurrentSid;
|
|
GroupArray[CurrentGroup].Attributes = (SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED);
|
|
CurrentGroup++;
|
|
CurrentSid += CurrentSidLength;
|
|
}
|
|
|
|
|
|
if(OldTokenInfo)
|
|
{
|
|
CurrentSid = (PSID)OFFSET_ALIGN(CurrentSid, ACL);
|
|
NewTokenInfo->DefaultDacl.DefaultDacl = (PACL)CurrentSid;
|
|
CurrentSid += DefaultDaclSize;
|
|
}
|
|
|
|
CurrentSid = (PSID) OFFSET_ALIGN(CurrentSid, TOKEN_PRIVILEGES);
|
|
NewTokenInfo->Privileges = (PTOKEN_PRIVILEGES)CurrentSid;
|
|
NewTokenInfo->Privileges->PrivilegeCount = 0;
|
|
|
|
LsapDsDebugOut((DEB_TRACE, "NewTokenInfo : %lx\n", NewTokenInfo));
|
|
LsapDsDebugOut((DEB_TRACE, "TokenSize : %lx\n", TokenSize));
|
|
LsapDsDebugOut((DEB_TRACE, "CurrentSid : %lx\n", CurrentSid));
|
|
|
|
ASSERT((PBYTE)NewTokenInfo + TokenSize == CurrentSid + sizeof(TOKEN_PRIVILEGES) +
|
|
sizeof(LUID_AND_ATTRIBUTES) * (SEP_MAX_PRIVILEGE_COUNT -
|
|
ANYSIZE_ARRAY));
|
|
|
|
|
|
(*TokenInfo) = NewTokenInfo;
|
|
NewTokenInfo = NULL;
|
|
(*TokenInfoSize) = TokenSize;
|
|
|
|
Cleanup:
|
|
|
|
if( SidArray != NULL )
|
|
{
|
|
SafeAllocaFree( SidArray );
|
|
}
|
|
|
|
if(NewTokenInfo)
|
|
{
|
|
LsapFreeLsaHeap(NewTokenInfo);
|
|
}
|
|
|
|
LsapFreeSampUlongArray( &AccountMembership );
|
|
LsapFreeSampUlongArray( &BuiltinMembership );
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapAuSetTokenInformation(
|
|
IN OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
|
|
IN PVOID *TokenInformation,
|
|
IN ULONG FinalIdCount,
|
|
IN PSID_AND_ATTRIBUTES FinalIds,
|
|
IN ULONG PrivilegeCount,
|
|
IN PLUID_AND_ATTRIBUTES Privileges,
|
|
IN ULONG NewTokenInfoSize,
|
|
IN OUT PLSA_TOKEN_INFORMATION_V2 *NewTokenInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes the information from the current TokenInformation,
|
|
the FinalIds array, and the Privileges and incorporates them into a
|
|
single TokenInformation structure. It may be necessary to free some
|
|
or all of the original TokenInformation. It may even be necessary to
|
|
produce a different TokenInformationType to accomplish this task.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
TokenInformationType - Indicates what format the provided set of
|
|
token information is in.
|
|
|
|
TokenInformation - The information in this structure will be superceded
|
|
by the information in the FinalIDs parameter and the Privileges
|
|
parameter.
|
|
|
|
FinalIdCount - Indicates the number of IDs (user, group, and alias)
|
|
to be incorporated in the final TokenInformation.
|
|
|
|
FinalIds - Points to an array of SIDs and their corresponding
|
|
attributes to be incorporated into the final TokenInformation.
|
|
|
|
IdProperties - Points to an array of properties relating to the FinalIds.
|
|
|
|
|
|
PrivilegeCount - Indicates the number of privileges to be incorporated
|
|
into the final TokenInformation.
|
|
|
|
Privileges - Points to an array of privileges that are to be
|
|
incorporated into the TokenInformation. This array will be
|
|
used directly in the resultant TokenInformation.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Succeeded.
|
|
|
|
STATUS_NO_MEMORY - Indicates there was not enough heap memory available
|
|
to produce the final TokenInformation structure.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ULONG i;
|
|
|
|
PLSA_TOKEN_INFORMATION_V2 OldV2;
|
|
PLSA_TOKEN_INFORMATION_NULL OldNull;
|
|
|
|
ASSERT(( *TokenInformationType == LsaTokenInformationV1) ||
|
|
(*TokenInformationType == LsaTokenInformationNull) ||
|
|
( *TokenInformationType == LsaTokenInformationV2));
|
|
|
|
if(*TokenInformationType == LsaTokenInformationNull)
|
|
{
|
|
OldNull = (PLSA_TOKEN_INFORMATION_NULL)(*TokenInformation);
|
|
(*NewTokenInfo)->ExpirationTime = OldNull->ExpirationTime;
|
|
}
|
|
else
|
|
{
|
|
OldV2 = (PLSA_TOKEN_INFORMATION_V2)(*TokenInformation);
|
|
(*NewTokenInfo)->ExpirationTime = OldV2->ExpirationTime;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Set the Privileges, if any //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
(*NewTokenInfo)->Privileges->PrivilegeCount = PrivilegeCount;
|
|
|
|
ASSERT((PBYTE)&(*NewTokenInfo)->Privileges->Privileges[PrivilegeCount] <=
|
|
((PBYTE)(*NewTokenInfo)) + NewTokenInfoSize);
|
|
|
|
for ( i=0; i<PrivilegeCount; i++) {
|
|
(*NewTokenInfo)->Privileges->Privileges[i] = Privileges[i];
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Free the old TokenInformation and set the new //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
switch ( (*TokenInformationType) ) {
|
|
case LsaTokenInformationNull:
|
|
LsapFreeTokenInformationNull(
|
|
(PLSA_TOKEN_INFORMATION_NULL)(*TokenInformation));
|
|
break;
|
|
|
|
case LsaTokenInformationV1:
|
|
LsapFreeTokenInformationV1(
|
|
(PLSA_TOKEN_INFORMATION_V1)(*TokenInformation));
|
|
break;
|
|
|
|
case LsaTokenInformationV2:
|
|
LsapFreeTokenInformationV2(
|
|
(PLSA_TOKEN_INFORMATION_V2)(*TokenInformation));
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Set the new TokenInformation
|
|
//
|
|
|
|
(*TokenInformationType) = LsaTokenInformationV2;
|
|
(*TokenInformation) = (*NewTokenInfo);
|
|
(*NewTokenInfo) = NULL;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAuDuplicateSid(
|
|
PSID *Target,
|
|
PSID Source
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Duplicate a SID.
|
|
|
|
|
|
Arguments:
|
|
|
|
Target - Recieves a pointer to the SID copy.
|
|
|
|
Source - points to the SID to be copied.
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The copy was successful.
|
|
|
|
STATUS_NO_MEMORY - memory could not be allocated to perform the copy.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Length;
|
|
|
|
//
|
|
// The SID needs to be copied ...
|
|
//
|
|
|
|
Length = RtlLengthSid( Source );
|
|
(*Target) = LsapAllocateLsaHeap( Length );
|
|
if ((*Target == NULL)) {
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
RtlMoveMemory( (*Target), Source, Length );
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapAuOpenSam(
|
|
BOOLEAN DuringStartup
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens SAM for use during authentication. It
|
|
opens a handle to both the BUILTIN domain and the ACCOUNT domain.
|
|
|
|
Arguments:
|
|
|
|
DuringStartup - TRUE if this is the call made during startup. In that case,
|
|
there is no need to wait on the SAM_STARTED_EVENT since the caller ensures
|
|
that SAM is started before the call is made.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Succeeded.
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status, IgnoreStatus;
|
|
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo;
|
|
|
|
|
|
if (LsapAuSamOpened == TRUE) {
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
Status = LsapOpenSamEx( DuringStartup );
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(Status);
|
|
}
|
|
|
|
|
|
//
|
|
// Set up the Built-In Domain Member Sid Information.
|
|
//
|
|
|
|
LsapBuiltinDomainSubCount = (*RtlSubAuthorityCountSid(LsapBuiltInDomainSid) + 1);
|
|
LsapBuiltinDomainMemberSidLength = RtlLengthRequiredSid( LsapBuiltinDomainSubCount );
|
|
|
|
//
|
|
// Get the member Sid information for the account domain
|
|
// and set the global variables related to this information.
|
|
//
|
|
|
|
Status = LsapGetAccountDomainInfo( &PolicyAccountDomainInfo );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(Status);
|
|
}
|
|
|
|
LsapAccountDomainSubCount =
|
|
(*(RtlSubAuthorityCountSid( PolicyAccountDomainInfo->DomainSid ))) +
|
|
(UCHAR)(1);
|
|
LsapAccountDomainMemberSidLength =
|
|
RtlLengthRequiredSid( (ULONG)LsapAccountDomainSubCount );
|
|
|
|
//
|
|
// Build typical SIDs for members of the BUILTIN and ACCOUNT domains.
|
|
// These are used to build SIDs when API return only RIDs.
|
|
// Don't bother setting the last RID to any particular value.
|
|
// It is always changed before use.
|
|
//
|
|
|
|
LsapAccountDomainMemberSid = LsapAllocateLsaHeap( LsapAccountDomainMemberSidLength );
|
|
if (LsapAccountDomainMemberSid != NULL) {
|
|
LsapBuiltinDomainMemberSid = LsapAllocateLsaHeap( LsapBuiltinDomainMemberSidLength );
|
|
if (LsapBuiltinDomainMemberSid == NULL) {
|
|
|
|
LsapFreeLsaHeap( LsapAccountDomainMemberSid );
|
|
|
|
LsaIFree_LSAPR_POLICY_INFORMATION(
|
|
PolicyAccountDomainInformation,
|
|
(PLSAPR_POLICY_INFORMATION) PolicyAccountDomainInfo );
|
|
|
|
return STATUS_NO_MEMORY ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LsaIFree_LSAPR_POLICY_INFORMATION(
|
|
PolicyAccountDomainInformation,
|
|
(PLSAPR_POLICY_INFORMATION) PolicyAccountDomainInfo );
|
|
|
|
return STATUS_NO_MEMORY ;
|
|
}
|
|
|
|
IgnoreStatus = RtlCopySid( LsapAccountDomainMemberSidLength,
|
|
LsapAccountDomainMemberSid,
|
|
PolicyAccountDomainInfo->DomainSid);
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
(*RtlSubAuthorityCountSid(LsapAccountDomainMemberSid))++;
|
|
|
|
IgnoreStatus = RtlCopySid( LsapBuiltinDomainMemberSidLength,
|
|
LsapBuiltinDomainMemberSid,
|
|
LsapBuiltInDomainSid);
|
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|
(*RtlSubAuthorityCountSid(LsapBuiltinDomainMemberSid))++;
|
|
|
|
|
|
//
|
|
// Free the ACCOUNT domain information
|
|
//
|
|
|
|
LsaIFree_LSAPR_POLICY_INFORMATION(
|
|
PolicyAccountDomainInformation,
|
|
(PLSAPR_POLICY_INFORMATION) PolicyAccountDomainInfo );
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
LsapAuSamOpened = TRUE;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
LsapIsSidLogonSid(
|
|
PSID Sid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Test to see if the provided sid is a LOGON_ID.
|
|
Such sids start with S-1-5-5 (see ntseapi.h for more on logon sids).
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
Sid - Pointer to SID to test. The SID is assumed to be a valid SID.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - Sid is a logon sid.
|
|
|
|
FALSE - Sid is not a logon sid.
|
|
|
|
--*/
|
|
{
|
|
SID *ISid;
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
|
|
|
ISid = Sid;
|
|
|
|
|
|
//
|
|
// if the identifier authority is SECURITY_NT_AUTHORITY and
|
|
// there are SECURITY_LOGON_IDS_RID_COUNT sub-authorities
|
|
// and the first sub-authority is SECURITY_LOGON_IDS_RID
|
|
// then this is a logon id.
|
|
//
|
|
|
|
|
|
if (ISid->SubAuthorityCount == SECURITY_LOGON_IDS_RID_COUNT) {
|
|
if (ISid->SubAuthority[0] == SECURITY_LOGON_IDS_RID) {
|
|
if (
|
|
(ISid->IdentifierAuthority.Value[0] == NtAuthority.Value[0]) &&
|
|
(ISid->IdentifierAuthority.Value[1] == NtAuthority.Value[1]) &&
|
|
(ISid->IdentifierAuthority.Value[2] == NtAuthority.Value[2]) &&
|
|
(ISid->IdentifierAuthority.Value[3] == NtAuthority.Value[3]) &&
|
|
(ISid->IdentifierAuthority.Value[4] == NtAuthority.Value[4]) &&
|
|
(ISid->IdentifierAuthority.Value[5] == NtAuthority.Value[5])
|
|
) {
|
|
|
|
return(TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
LsapAuSetLogonPrivilegeStates(
|
|
IN SECURITY_LOGON_TYPE LogonType,
|
|
IN ULONG PrivilegeCount,
|
|
IN PLUID_AND_ATTRIBUTES Privileges
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is an interesting routine. Its purpose is to establish the
|
|
intial state (enabled/disabled) of privileges. This information
|
|
comes from LSA, but we need to over-ride that information for the
|
|
time being based upon logon type.
|
|
|
|
Basically, without dynamic context tracking supported across the
|
|
network, network logons have no way to enable privileges. Therefore,
|
|
we will enable all privileges for network logons.
|
|
|
|
For interactive, service, and batch logons, the programs or utilities
|
|
used are able to enable privileges when needed. Therefore, privileges
|
|
for these logon types will be disabled.
|
|
|
|
Despite the rules above, the SeChangeNotifyPrivilege will ALWAYS
|
|
be enabled if granted to a user (even for interactive, service, and
|
|
batch logons).
|
|
|
|
|
|
Arguments:
|
|
|
|
PrivilegeCount - The number of privileges being assigned for this
|
|
logon.
|
|
|
|
Privileges - The privileges, and their attributes, being assigned
|
|
for this logon.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
ULONG
|
|
i,
|
|
NewAttributes;
|
|
|
|
LUID ChangeNotify;
|
|
LUID Impersonate;
|
|
LUID CreateXSession ;
|
|
|
|
//
|
|
// Enable or disable all privileges according to logon type
|
|
//
|
|
|
|
if ((LogonType == Network) ||
|
|
(LogonType == NetworkCleartext)) {
|
|
NewAttributes = (SE_PRIVILEGE_ENABLED_BY_DEFAULT |
|
|
SE_PRIVILEGE_ENABLED);
|
|
} else {
|
|
NewAttributes = 0;
|
|
}
|
|
|
|
|
|
for (i=0; i<PrivilegeCount; i++) {
|
|
Privileges[i].Attributes = NewAttributes;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Interactive, Service, and Batch need to have the
|
|
// SeChangeNotifyPrivilege enabled. Network already
|
|
// has it enabled.
|
|
//
|
|
|
|
if ((LogonType == Network) ||
|
|
(LogonType == NetworkCleartext)) {
|
|
return;
|
|
}
|
|
|
|
|
|
ChangeNotify = RtlConvertLongToLuid(SE_CHANGE_NOTIFY_PRIVILEGE);
|
|
Impersonate = RtlConvertLongToLuid(SE_IMPERSONATE_PRIVILEGE);
|
|
CreateXSession = RtlConvertLongToLuid(SE_CREATE_GLOBAL_PRIVILEGE);
|
|
|
|
for ( i=0; i<PrivilegeCount; i++) {
|
|
if (RtlEqualLuid(&Privileges[i].Luid, &ChangeNotify) == TRUE) {
|
|
Privileges[i].Attributes = (SE_PRIVILEGE_ENABLED_BY_DEFAULT |
|
|
SE_PRIVILEGE_ENABLED);
|
|
} else if ( RtlEqualLuid( &Privileges[i].Luid, &Impersonate) == TRUE ) {
|
|
Privileges[i].Attributes = (SE_PRIVILEGE_ENABLED_BY_DEFAULT |
|
|
SE_PRIVILEGE_ENABLED );
|
|
|
|
} else if ( RtlEqualLuid( &Privileges[i].Luid, &CreateXSession) == TRUE ) {
|
|
Privileges[i].Attributes = (SE_PRIVILEGE_ENABLED_BY_DEFAULT |
|
|
SE_PRIVILEGE_ENABLED );
|
|
|
|
}
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
CheckNullSessionAccess(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks to see if we should restict null session access.
|
|
in the registry under system\currentcontrolset\Control\Lsa\
|
|
AnonymousIncludesEveryone indicating whether or not to restrict access.
|
|
If the value is zero (or doesn't exist), we restrict anonymous by
|
|
preventing Everyone and Network from entering the groups.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
TRUE - NullSession access is restricted.
|
|
FALSE - NullSession access is not restricted.
|
|
|
|
--*/
|
|
{
|
|
return LsapGlobalRestrictNullSessions ? TRUE : FALSE;
|
|
}
|
|
|
|
BOOL
|
|
IsTerminalServerRA(
|
|
VOID
|
|
)
|
|
{
|
|
OSVERSIONINFOEX osVersionInfo;
|
|
ULONGLONG ConditionMask = 0;
|
|
|
|
ZeroMemory(&osVersionInfo, sizeof(osVersionInfo));
|
|
|
|
ConditionMask = VerSetConditionMask(ConditionMask, VER_SUITENAME, VER_AND);
|
|
|
|
osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
|
|
osVersionInfo.wSuiteMask = VER_SUITE_SINGLEUSERTS;
|
|
|
|
return VerifyVersionInfo(
|
|
&osVersionInfo,
|
|
VER_SUITENAME,
|
|
ConditionMask);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
IsTSUSerSidEnabled(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
UNICODE_STRING KeyName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE KeyHandle;
|
|
UCHAR Buffer[100];
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
|
|
ULONG KeyValueLength = 100;
|
|
ULONG ResultLength;
|
|
PULONG Flag;
|
|
|
|
|
|
BOOLEAN fIsTSUSerSidEnabled = FALSE;
|
|
|
|
|
|
//
|
|
// We don't add TSUserSid for Remote Admin mode of TS
|
|
//
|
|
if (IsTerminalServerRA() == TRUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Check in the registry if TSUserSid should be added to
|
|
// to the token
|
|
//
|
|
|
|
//
|
|
// Open the Terminal Server key in the registry
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&KeyName,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Terminal Server"
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
NtStatus = NtOpenKey(
|
|
&KeyHandle,
|
|
KEY_READ,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
RtlInitUnicodeString(
|
|
&KeyName,
|
|
L"TSUserEnabled"
|
|
);
|
|
|
|
NtStatus = NtQueryValueKey(
|
|
KeyHandle,
|
|
&KeyName,
|
|
KeyValuePartialInformation,
|
|
KeyValueInformation,
|
|
KeyValueLength,
|
|
&ResultLength
|
|
);
|
|
|
|
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
|
|
//
|
|
// Check that the data is the correct size and type - a ULONG.
|
|
//
|
|
|
|
if ((KeyValueInformation->DataLength >= sizeof(ULONG)) &&
|
|
(KeyValueInformation->Type == REG_DWORD)) {
|
|
|
|
|
|
Flag = (PULONG) KeyValueInformation->Data;
|
|
|
|
if (*Flag == 1) {
|
|
fIsTSUSerSidEnabled = TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
NtClose(KeyHandle);
|
|
|
|
Cleanup:
|
|
|
|
return fIsTSUSerSidEnabled;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
CheckAdminOwnerSetting(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks to see if we should set the default owner to the
|
|
ADMINISTRATORS alias. If the value is zero (or doesn't exist), then
|
|
the ADMINISTRATORS alias will be set as the default owner (if present).
|
|
Otherwise, no default owner is set.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
TRUE - If the ADMINISTRATORS alias is present, make it the default owner.
|
|
FALSE - Do not set a default owner.
|
|
|
|
--*/
|
|
{
|
|
return LsapGlobalSetAdminOwner ? TRUE : FALSE;
|
|
}
|
|
|
|
BOOL
|
|
LsapIsAdministratorRecoveryMode(
|
|
IN PSID UserSid
|
|
)
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
This routine will return true if UserSid is the administrator's SID
|
|
and the machine is currently in safe mode.
|
|
|
|
Once the fact is established, the value is assigned to a static variable.
|
|
|
|
Parameters:
|
|
|
|
UserSid - SID of the user logging on
|
|
|
|
Returns:
|
|
|
|
TRUE or FALSE
|
|
|
|
--*/
|
|
{
|
|
static LONG AdministratorRecoveryMode = -1L;
|
|
HKEY hKey;
|
|
DWORD dwType, dwSize;
|
|
DWORD SafeBootMode = 0;
|
|
|
|
if ( UserSid == NULL ||
|
|
!IsWellKnownSid( UserSid, WinAccountAdministratorSid )) {
|
|
|
|
return FALSE;
|
|
|
|
} else if ( AdministratorRecoveryMode != -1L ) {
|
|
|
|
return AdministratorRecoveryMode ? TRUE : FALSE;
|
|
}
|
|
|
|
//
|
|
// get the safeboot mode
|
|
//
|
|
|
|
if (RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
TEXT("system\\currentcontrolset\\control\\safeboot\\option"),
|
|
0,
|
|
KEY_READ,
|
|
& hKey
|
|
) == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof(DWORD);
|
|
|
|
RegQueryValueEx (
|
|
hKey,
|
|
TEXT("OptionValue"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &SafeBootMode,
|
|
&dwSize
|
|
);
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if ( SafeBootMode ) {
|
|
|
|
AdministratorRecoveryMode = TRUE;
|
|
|
|
} else {
|
|
|
|
AdministratorRecoveryMode = FALSE;
|
|
}
|
|
|
|
return AdministratorRecoveryMode ? TRUE : FALSE;
|
|
}
|