diff options
Diffstat (limited to 'private/lsa/server/aufilter.c')
-rw-r--r-- | private/lsa/server/aufilter.c | 2009 |
1 files changed, 2009 insertions, 0 deletions
diff --git a/private/lsa/server/aufilter.c b/private/lsa/server/aufilter.c new file mode 100644 index 000000000..8d349a540 --- /dev/null +++ b/private/lsa/server/aufilter.c @@ -0,0 +1,2009 @@ + +/*++ + +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 <rpc.h> +#include "lsasrvp.h" +#include "ausrvp.h" + +//#define LSAP_DONT_ASSIGN_DEFAULT_DACL + + +////////////////////////////////////////////////////////////////////////////// +// // +// Module local macros // +// // +////////////////////////////////////////////////////////////////////////////// + + +#define LsapFreeSampUlongArray( A ) \ +{ \ + if ((A)->Element != NULL) { \ + MIDL_user_free((A)->Element); \ + } \ +} + + +////////////////////////////////////////////////////////////////////////////// +// // +// 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, + OUT PULONG FinalIdCount, + OUT PSID_AND_ATTRIBUTES FinalIds, + OUT PULONG IdProperties + ); + + +NTSTATUS +LsapSetDefaultDacl( + IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType, + IN PVOID TokenInformation, + IN PULONG FinalIdCount, + IN PSID_AND_ATTRIBUTES FinalIds, + IN ULONG FinalOwnerIndex + ); + + +NTSTATUS +LsapAuAddStandardIds( + IN SECURITY_LOGON_TYPE LogonType, + IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType, + IN OUT PULONG FinalIdCount, + IN OUT PSID_AND_ATTRIBUTES FinalIds, + IN OUT PULONG IdProperties + ); + +NTSTATUS +LsapAuAddLocalAliases( + IN OUT PULONG FinalIdCount, + IN OUT PSID_AND_ATTRIBUTES FinalIds, + IN OUT PULONG IdProperties, + IN OUT PULONG FinalOwnerIndex + ); + +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 PULONG IdProperties, + IN ULONG FinalOwnerIndex, + IN ULONG PrivilegeCount, + IN PLUID_AND_ATTRIBUTES Privileges + ); + +NTSTATUS +LsapAuCopySidAndAttributes( + PSID_AND_ATTRIBUTES Target, + PSID_AND_ATTRIBUTES Source, + PULONG SourceProperties + ); + +NTSTATUS +LsapAuCopySid( + PSID *Target, + PSID_AND_ATTRIBUTES Source, + PULONG SourceProperties + ); + +BOOLEAN +LsapIsSidLogonSid( + PSID Sid + ); + + + +////////////////////////////////////////////////////////////////////////////// +// // +// Routines // +// // +////////////////////////////////////////////////////////////////////////////// + + +NTSTATUS +LsapAuUserLogonPolicyFilter( + IN SECURITY_LOGON_TYPE LogonType, + IN PLSA_TOKEN_INFORMATION_TYPE TokenInformationType, + IN PVOID *TokenInformation, + OUT PQUOTA_LIMITS QuotaLimits, + OUT PPRIVILEGE_SET *PrivilegesAssigned + ) + +/*++ + +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. + +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; + ULONG i; + ULONG FinalIdCount, FinalPrivilegeCount, FinalOwnerIndex; + SID_AND_ATTRIBUTES FinalIds[LSAP_CONTEXT_SID_LIMIT]; + ULONG IdProperties[LSAP_CONTEXT_SID_LIMIT]; + PLUID_AND_ATTRIBUTES FinalPrivileges = NULL; + LSAP_DB_ACCOUNT_TYPE_SPECIFIC_INFO AccountInfo; + + // + // Validate the Logon Type. + // + + if ( LogonType != Interactive && + LogonType != Network && + LogonType != Service && + LogonType != Batch ) { + + Status = STATUS_INVALID_LOGON_TYPE; + goto UserLogonPolicyFilterError; + } + + ////////////////////////////////////////////////////////////////////////// + // // + // Build up a list of IDs and privileges to return // + // This list is initialized to contain the set of IDs // + // passed in. // + // // + ////////////////////////////////////////////////////////////////////////// + + // + // Start out with the IDs passed in and no privileges + // + + FinalIdCount = 0; + + Status = LsapAuSetPassedIds( + (*TokenInformationType), + TokenInformation, + &FinalIdCount, + FinalIds, + IdProperties + ); + + if (!NT_SUCCESS(Status)) { + + goto UserLogonPolicyFilterError; + } + + FinalOwnerIndex = 0; + + ////////////////////////////////////////////////////////////////////////// + // // + // Copy in standard IDs (world and logon type) // + // // + ////////////////////////////////////////////////////////////////////////// + + Status = LsapAuAddStandardIds( + LogonType, + (*TokenInformationType), + &FinalIdCount, + FinalIds, + IdProperties + ); + + if (!NT_SUCCESS(Status)) { + + goto UserLogonPolicyFilterError; + } + + ////////////////////////////////////////////////////////////////////////// + // // + // Copy in aliases from the local domains (BUILT-IN and ACCOUNT) // + // // + ////////////////////////////////////////////////////////////////////////// + + Status = LsapAuAddLocalAliases( + &FinalIdCount, + FinalIds, + IdProperties, + &FinalOwnerIndex + ); + + 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. + // + + 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. + // + + + if (*TokenInformationType != LsaTokenInformationNull) { + + Status = LsapAuVerifyLogonType( LogonType, AccountInfo.SystemAccess ); + + if (!NT_SUCCESS(Status)) { + + goto UserLogonPolicyFilterError; + } + } + + // + // Convert the Privilege Set returned by the Query routine to a Luid + // and ATTRIBUTES array. Free the Privilege Set. + // + + Status = LsapRtlPrivilegeSetToLuidAndAttributes( + AccountInfo.PrivilegeSet, + &FinalPrivilegeCount, + &FinalPrivileges + ); + + if (!NT_SUCCESS(Status)) { + + goto UserLogonPolicyFilterError; + } + + // + // Return these so they can be audited. Data + // will be freed in the caller. + // + + *PrivilegesAssigned = AccountInfo.PrivilegeSet; + AccountInfo.PrivilegeSet = NULL; + + // + // Enable or Disable privileges according to our logon type + // This is necessary until we get dynamic security tracking. + // + + LsapAuSetLogonPrivilegeStates( + LogonType, + FinalPrivilegeCount, + FinalPrivileges + ); + + *QuotaLimits = AccountInfo.QuotaLimits; + +#ifndef LSAP_DONT_ASSIGN_DEFAULT_DACL + + Status = LsapSetDefaultDacl( (*TokenInformationType), + (*TokenInformation), + &FinalIdCount, + &FinalIds[0], + FinalOwnerIndex + ); + 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, + IdProperties, + FinalOwnerIndex, + FinalPrivilegeCount, + FinalPrivileges + ); + + +UserLogonPolicyFilterFinish: + + return(Status); + +UserLogonPolicyFilterError: + + // + // Clean up any memory allocated for Sid properties. + // + + for ( i=0; i<FinalIdCount; i++) { + + if ((IdProperties[i] & LSAP_AU_SID_PROP_ALLOCATED) != 0) { + + LsapFreeLsaHeap( FinalIds[i].Sid ); + } + } + + // + // If necessary, clean up Privileges buffer + // + + if (FinalPrivileges != NULL) { + + MIDL_user_free( FinalPrivileges ); + FinalPrivileges = NULL; + } + + 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: + + if (!(SystemAccess & SECURITY_ACCESS_INTERACTIVE_LOGON)) { + + Status = STATUS_LOGON_TYPE_NOT_GRANTED; + } + + break; + + case Network: + + if (!(SystemAccess & SECURITY_ACCESS_NETWORK_LOGON)) { + + Status = STATUS_LOGON_TYPE_NOT_GRANTED; + } + + break; + + case Batch: + + if (!(SystemAccess & SECURITY_ACCESS_BATCH_LOGON)) { + + Status = STATUS_LOGON_TYPE_NOT_GRANTED; + } + + break; + + case Service: + + if (!(SystemAccess & SECURITY_ACCESS_SERVICE_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, + OUT PULONG FinalIdCount, + OUT PSID_AND_ATTRIBUTES FinalIds, + OUT PULONG IdProperties + ) + +/*++ + +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. + + STATUS_TOO_MANY_CONTEXT_IDS - There are too many IDs in the context. + + +--*/ + +{ + + ULONG i, j, InitialIdCount; + PTOKEN_USER User; + PTOKEN_GROUPS Groups; + PTOKEN_PRIMARY_GROUP PrimaryGroup; + PSID PrimaryGroupSid; + PULONG PrimaryGroupAttributes; + + + + + + + // + // Get the passed ids + // + + ASSERT( (TokenInformationType == LsaTokenInformationNull ) || + (TokenInformationType == LsaTokenInformationV1) ); + + if (TokenInformationType == LsaTokenInformationNull) { + User = NULL; + Groups = ((PLSA_TOKEN_INFORMATION_NULL)(*TokenInformation))->Groups; + PrimaryGroup = NULL; + } else { + User = &((PLSA_TOKEN_INFORMATION_V1)(*TokenInformation))->User; + Groups = ((PLSA_TOKEN_INFORMATION_V1)(*TokenInformation))->Groups; + PrimaryGroup = &((PLSA_TOKEN_INFORMATION_V1)(*TokenInformation))->PrimaryGroup; + } + + + if (Groups != NULL) { + InitialIdCount = Groups->GroupCount; + } else { + InitialIdCount = 0; + } + if (User != NULL) { + InitialIdCount ++; + } + if (InitialIdCount > LSAP_CONTEXT_SID_LIMIT) { + return(STATUS_TOO_MANY_CONTEXT_IDS); + } + + + j = 0; + if (User != NULL) { + + // + // TokenInformation included a user ID. + // + + FinalIds[j] = User->User; + IdProperties[j] = LSAP_AU_SID_PROP_COPY; + j++; + + } + + if (PrimaryGroup != NULL) { + // + // TokenInformation included a primary group ID. + // + + FinalIds[j].Sid = PrimaryGroup->PrimaryGroup; + FinalIds[j].Attributes = 0; + + // + // 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[j].Attributes; + PrimaryGroupSid = PrimaryGroup->PrimaryGroup; + IdProperties[j] = LSAP_AU_SID_PROP_COPY; + j++; + } + + if (Groups != NULL) { + for (i=0; i < Groups->GroupCount; i++) { + + // + // If this sid is the primary group, it is already in the list + // of final IDs but we need to add the attribute + // + + if (RtlEqualSid( + PrimaryGroupSid, + Groups->Groups[i].Sid + )) { + *PrimaryGroupAttributes = Groups->Groups[i].Attributes; + } else { + + FinalIds[j] = Groups->Groups[i]; + IdProperties[j] = LSAP_AU_SID_PROP_COPY; + + // + // if this SID is a logon SID, then set the SE_GROUP_LOGON_ID + // attribute + // + + if (LsapIsSidLogonSid(FinalIds[j].Sid) == TRUE) { + FinalIds[j].Attributes |= SE_GROUP_LOGON_ID; + } + j++; + + } + + + } + } + + + (*FinalIdCount) = InitialIdCount; + + + // + // We expect the user and primary group to be high hit rate IDs + // + + if (InitialIdCount >= 2) { + IdProperties[0] |= (LSAP_AU_SID_PROP_HIGH_RATE); + IdProperties[1] |= (LSAP_AU_SID_PROP_HIGH_RATE); + } + + return(STATUS_SUCCESS); + +} + + + +NTSTATUS +LsapSetDefaultDacl( + IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType, + IN PVOID TokenInformation, + IN PULONG FinalIdCount, + IN PSID_AND_ATTRIBUTES FinalIds, + IN ULONG FinalOwnerIndex + ) + +/*++ + +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. + + FinalIdCount - contains the number of IDs passed. + + FinalIds - contains the set of user and group SIDs. + + FinalOwnerIndex - Indicates which of the SIDs is the owner SID. + + + +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; + + SID_IDENTIFIER_AUTHORITY + NtAuthority = SECURITY_NT_AUTHORITY; + + PLSA_TOKEN_INFORMATION_V1 + CastTokenInformation; + + + // + // NULL token information?? (has no default dacl) + // + + if (TokenInformationType == LsaTokenInformationNull) { + return(STATUS_SUCCESS); + } + ASSERT(TokenInformationType == LsaTokenInformationV1); + + + CastTokenInformation = (PLSA_TOKEN_INFORMATION_V1)TokenInformation; + + + // + // Already have a default DACL? + // + + Acl = CastTokenInformation->DefaultDacl.DefaultDacl; + if (Acl != NULL) { + return(STATUS_SUCCESS); + } + + + // + // allocate and build default DACL... + // + + + Length = (ULONG)sizeof(ACL) + + (3*((ULONG)sizeof(ACCESS_ALLOWED_ACE))) + + RtlLengthSid( FinalIds[FinalOwnerIndex].Sid ) + + RtlLengthSid( LsapLocalSystemSid ); + + Acl = (PACL)RtlAllocateHeap( RtlProcessHeap(), 0, Length); + + if (Acl == NULL) { + return(STATUS_NO_MEMORY); + } + + + Status = RtlCreateAcl( Acl, Length, ACL_REVISION2); + ASSERT( NT_SUCCESS(Status) ); + + + // + // OWNER access - put this one first for performance sake + // + + Status = RtlAddAccessAllowedAce ( + Acl, + ACL_REVISION2, + GENERIC_ALL, + FinalIds[FinalOwnerIndex].Sid + ); + ASSERT( NT_SUCCESS(Status) ); + + + // + // SYSTEM access + // + + Status = RtlAddAccessAllowedAce ( + Acl, + ACL_REVISION2, + GENERIC_ALL, + LsapLocalSystemSid + ); + ASSERT( NT_SUCCESS(Status) ); + + + + CastTokenInformation->DefaultDacl.DefaultDacl = Acl; + + return(STATUS_SUCCESS); +} + + + +NTSTATUS +LsapAuAddStandardIds( + IN SECURITY_LOGON_TYPE LogonType, + IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType, + IN OUT PULONG FinalIdCount, + IN OUT PSID_AND_ATTRIBUTES FinalIds, + IN OUT PULONG IdProperties + ) + +/*++ + +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; + + i = (*FinalIdCount); + + + + // + // If this is a null logon, then add in the ANONYMOUS SID. + // (and make it the owner). We want this to be the first + // SID so that it is the default owner. + // + + if (TokenInformationType == LsaTokenInformationNull) { + if ( i + 1 > LSAP_CONTEXT_SID_LIMIT) { + return(STATUS_TOO_MANY_CONTEXT_IDS); + } + + FinalIds[i].Sid = LsapAnonymousSid; //Use the global SID + FinalIds[i].Attributes = (SE_GROUP_MANDATORY | + SE_GROUP_ENABLED_BY_DEFAULT | + SE_GROUP_ENABLED + ); + IdProperties[i] = (LSAP_AU_SID_PROP_COPY); + i++; + } + + // + // Add WORLD and something for logon type + // + + if ( i + 2 > LSAP_CONTEXT_SID_LIMIT) { + return(STATUS_TOO_MANY_CONTEXT_IDS); + } + + // + // WORLD + // + + FinalIds[i].Sid = LsapWorldSid; //Use the global SID + FinalIds[i].Attributes = (SE_GROUP_MANDATORY | + SE_GROUP_ENABLED_BY_DEFAULT | + SE_GROUP_ENABLED + ); + IdProperties[i] = (LSAP_AU_SID_PROP_COPY | LSAP_AU_SID_PROP_HIGH_RATE); + i++; + + + + + // + // Logon type SID + // + + switch ( LogonType ) { + case Interactive: + FinalIds[i].Sid = LsapInteractiveSid; + break; + case Network: + FinalIds[i].Sid = LsapNetworkSid; + break; + case Batch: + FinalIds[i].Sid = LsapBatchSid; + break; + case Service: + FinalIds[i].Sid = LsapServiceSid; + break; + } + + FinalIds[i].Attributes = (SE_GROUP_MANDATORY | + SE_GROUP_ENABLED_BY_DEFAULT | + SE_GROUP_ENABLED + ); + IdProperties[i] = LSAP_AU_SID_PROP_COPY; + i++; + + + (*FinalIdCount) = i; + return(STATUS_SUCCESS); + +} + + + +NTSTATUS +LsapAuAddLocalAliases( + IN OUT PULONG FinalIdCount, + IN OUT PSID_AND_ATTRIBUTES FinalIds, + IN OUT PULONG IdProperties, + IN OUT PULONG FinalOwnerIndex + ) + +/*++ + +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. + + FinalOwnerIndex - Will be adjusted to assign ADMINISTRATORS as the + default owner, if the user is a member of that alias. + + + +Return Value: + + STATUS_SUCCESS - Succeeded. + + STATUS_TOO_MANY_CONTEXT_IDS - There are too many IDs in the context. + + +--*/ + +{ + NTSTATUS Status, SuccessExpected; + ULONG i,j; + BOOLEAN SetNewOwner = FALSE; + ULONG InitialIdCount, NewIdCount, NewOwner; + SAMPR_SID_INFORMATION SidArray[LSAP_CONTEXT_SID_LIMIT]; + SAMPR_ULONG_ARRAY AccountMembership, BuiltinMembership; + ULONG MembershipCount; + PSID *MembershipSid; + SAMPR_PSID_ARRAY SamprSidArray; + + // + // Make sure SAM has been opened. We'll get hadnles to both of the + // SAM Local Domains. + // + + Status = LsapAuOpenSam(); + if (!NT_SUCCESS(Status)) { + return(Status); + } + + InitialIdCount = (*FinalIdCount); + + for ( i=0; i<InitialIdCount; i++) { + + SidArray[i].SidPointer = (PRPC_SID)FinalIds[i].Sid; + } + + SamprSidArray.Count = InitialIdCount; + 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 = SamrGetAliasMembership( LsapAccountDomainHandle, + &SamprSidArray, + &AccountMembership + ); + if (!NT_SUCCESS(Status)) { + + return(Status); + } + + // + // For the given set of Sids, obtain their collective membership of + // Aliases in the Built-In domain + // + + BuiltinMembership.Count = 0; + BuiltinMembership.Element = NULL; + Status = SamrGetAliasMembership( LsapBuiltinDomainHandle, + &SamprSidArray, + &BuiltinMembership + ); + if (!NT_SUCCESS(Status)) { + + LsapFreeSampUlongArray( &AccountMembership ); + return(Status); + } + + // + // Allocate memory to build the SIDs in. + // + + MembershipCount = AccountMembership.Count; + MembershipCount += BuiltinMembership.Count; + + if (MembershipCount != 0) { + MembershipSid = (PSID *)(LsapAllocateLsaHeap( MembershipCount * sizeof(PSID))); + Status = STATUS_INSUFFICIENT_RESOURCES; // Default status + } else { + MembershipSid = NULL; + Status = STATUS_SUCCESS; + } + + if (MembershipSid == NULL) { + LsapFreeSampUlongArray( &AccountMembership ); + LsapFreeSampUlongArray( &BuiltinMembership ); + return(Status); + } + + + for ( i=0; i<MembershipCount; i++) { + MembershipSid[i] = NULL; + } + + // + // Construct full Sids for all of the Account Domain Aliases returned. + // + + for ( i=0; i<AccountMembership.Count; i++) { + MembershipSid[i] = LsapAllocateLsaHeap( LsapAccountDomainMemberSidLength ); + if (MembershipSid[i] == NULL) { + goto au_local_alias_error; + } + SuccessExpected = RtlCopySid( LsapAccountDomainMemberSidLength, + MembershipSid[i], + LsapAccountDomainMemberSid + ); + ASSERT(NT_SUCCESS(SuccessExpected)); + + (*RtlSubAuthoritySid( MembershipSid[i], LsapAccountDomainSubCount-1)) = + AccountMembership.Element[i]; + } + + // + // Construct full Sids for all of the Built-in Domain Aliases returned. + // + + for ( j=0, i=AccountMembership.Count; i<MembershipCount; j++, i++) { + + MembershipSid[i] = LsapAllocateLsaHeap( LsapBuiltinDomainMemberSidLength ); + if (MembershipSid[i] == NULL) { + goto au_local_alias_error; + } + SuccessExpected = RtlCopySid( LsapBuiltinDomainMemberSidLength, + MembershipSid[i], + LsapBuiltinDomainMemberSid + ); + ASSERT(NT_SUCCESS(SuccessExpected)); + + (*RtlSubAuthoritySid( MembershipSid[i], LsapBuiltinDomainSubCount-1)) = + BuiltinMembership.Element[j]; + + if (BuiltinMembership.Element[j] == DOMAIN_ALIAS_RID_ADMINS) { + + // + // ADMINISTRATORS alias member - set it up as the default owner + // + + SetNewOwner = TRUE; + NewOwner = i; + } + } + + // + // Add the ids to the FinalIds array. + // + + NewIdCount = InitialIdCount + MembershipCount; + if ( NewIdCount > LSAP_CONTEXT_SID_LIMIT) { + Status = STATUS_TOO_MANY_CONTEXT_IDS; + goto au_local_alias_error; + } + + + for ( j=0, i=InitialIdCount; i<NewIdCount; j++, i++) { + + FinalIds[i].Sid = MembershipSid[j]; + FinalIds[i].Attributes = (SE_GROUP_MANDATORY | + SE_GROUP_ENABLED_BY_DEFAULT | + SE_GROUP_ENABLED + ); + IdProperties[i] = LSAP_AU_SID_PROP_ALLOCATED | + LSAP_AU_SID_PROP_HIGH_RATE; + + } + + + + (*FinalIdCount) = NewIdCount; + + + // + // If we need to, adjust the FinalOwnerIndex. + // + + if ( SetNewOwner == TRUE) { + (*FinalOwnerIndex) = InitialIdCount + NewOwner; + FinalIds[(*FinalOwnerIndex)].Attributes |= (SE_GROUP_OWNER); + } + + + LsapFreeLsaHeap( MembershipSid ); + LsapFreeSampUlongArray( &AccountMembership ); + LsapFreeSampUlongArray( &BuiltinMembership ); + + return(STATUS_SUCCESS); + + +au_local_alias_error: + + // + // Appropriate return status must be set before coming here. + // Don't use this until the MembershipSid array is initialized. + // + + LsapFreeSampUlongArray( &AccountMembership ); + LsapFreeSampUlongArray( &BuiltinMembership ); + + for ( i=0; i<MembershipCount; i++) { + LsapFreeLsaHeap( MembershipSid[i] ); + } + LsapFreeLsaHeap(MembershipSid); + + return(Status); + +} + + + +NTSTATUS +LsapAuSetTokenInformation( + IN OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType, + IN OUT PVOID *TokenInformation, + IN ULONG FinalIdCount, + IN PSID_AND_ATTRIBUTES FinalIds, + IN PULONG IdProperties, + IN ULONG FinalOwnerIndex, + IN ULONG PrivilegeCount, + IN PLUID_AND_ATTRIBUTES Privileges + ) + +/*++ + +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 superseeded + 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. + + + FinalOwnerIndex - If zero, indicates that there is no explicit default + owner value. Otherwise, is the index of the default owner ID in + the FinalIds array. + + 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; + ULONG Length, i; + + PLSA_TOKEN_INFORMATION_V1 New, OldV1; + PLSA_TOKEN_INFORMATION_NULL OldNull; + + ASSERT( FinalIdCount >= 2 ); + + ASSERT( *TokenInformationType == LsaTokenInformationV1 || + *TokenInformationType == LsaTokenInformationNull); + + + + + // + // It is not worth trying to see if the original + // TokenInformation has everything that the final one should. + // Just go about building a new TokenInformation structure. + // + + New = LsapAllocateLsaHeap( sizeof(LSA_TOKEN_INFORMATION_V1) ); + if (New == NULL) { + return(STATUS_NO_MEMORY); + } + RtlZeroMemory( New, sizeof(LSA_TOKEN_INFORMATION_V1) ); + + + + + + + //////////////////////////////////////////////////////////////////////// + // // + // Set the ExpirationTime and DefaultAcl from the original // + // TokenInformation. // + // // + //////////////////////////////////////////////////////////////////////// + + if ((*TokenInformationType) == LsaTokenInformationNull) { + + OldNull = (PLSA_TOKEN_INFORMATION_NULL)(*TokenInformation); + New->ExpirationTime = OldNull->ExpirationTime; + + } else { + + OldV1 = (PLSA_TOKEN_INFORMATION_V1)(*TokenInformation); + New->ExpirationTime = OldV1->ExpirationTime; + + // + // Move the DefaultDacl from the passed TokenInformation to the + // new TokenInformation. This is necessary to prevent the Dacl + // memory from being deallocate when the old TokenInformation is + // freed. + // + + New->DefaultDacl = OldV1->DefaultDacl; + OldV1->DefaultDacl.DefaultDacl = NULL; + } + + + + //////////////////////////////////////////////////////////////////////// + // // + // User is the first ID in the list. // + // // + //////////////////////////////////////////////////////////////////////// + + Status = LsapAuCopySidAndAttributes( + &New->User.User, + &FinalIds[0], + &IdProperties[0] ); + + + + + + //////////////////////////////////////////////////////////////////////// + // // + // Set the groups. // + // // + //////////////////////////////////////////////////////////////////////// + + if (NT_SUCCESS(Status)) { + + // + // Don't count the UserID when building the TOKEN_GROUPS + // + + Length = sizeof(TOKEN_GROUPS) + + (FinalIdCount-1-ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES); + New->Groups = LsapAllocateLsaHeap( Length ); + if (New->Groups == NULL) { + Status = STATUS_NO_MEMORY; + } + } + + if (NT_SUCCESS(Status)) { + + // Take 2 passes through the groups. First copy + // the high-hit-rate IDs, then copy the rest of them. + // + + + ULONG i,k; + + k=0; //Index into token groups structure; + + + New->Groups->GroupCount = 0; + + // + // Start with the second entry - first is USER + // + + for (i=1; (i<FinalIdCount && NT_SUCCESS(Status)); i++) { + + if ((IdProperties[i] & LSAP_AU_SID_PROP_HIGH_RATE) != 0) { + Status = LsapAuCopySidAndAttributes( + &New->Groups->Groups[k], + &FinalIds[i], + &IdProperties[i] + ); + New->Groups->GroupCount++; + k++; + } + } + for (i=1; (i<FinalIdCount && NT_SUCCESS(Status)); i++) { + + if ((IdProperties[i] & LSAP_AU_SID_PROP_HIGH_RATE) == 0) { + Status = LsapAuCopySidAndAttributes( + &New->Groups->Groups[k], + &FinalIds[i], + &IdProperties[i] + ); + New->Groups->GroupCount++; + k++; + } + } +#ifdef DBG + if (NT_SUCCESS(Status)) { + ASSERT(k == New->Groups->GroupCount); + } +#endif //DBG + + } + + + + + //////////////////////////////////////////////////////////////////////// + // // + // Primary group is the second ID in the list // + // // + //////////////////////////////////////////////////////////////////////// + + if (NT_SUCCESS(Status)) { + + Status = LsapAuCopySid( + &New->PrimaryGroup.PrimaryGroup, + &FinalIds[1], + &IdProperties[1] ); + } + + + + + + + //////////////////////////////////////////////////////////////////////// + // // + // Set the Privileges, if any // + // // + //////////////////////////////////////////////////////////////////////// + + if (NT_SUCCESS(Status) && (PrivilegeCount != 0)) { + + Length = sizeof(TOKEN_PRIVILEGES) + + (PrivilegeCount-ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES); + + New->Privileges = LsapAllocateLsaHeap( Length ); + if (New->Privileges == NULL) { + Status = STATUS_NO_MEMORY; + } else { + New->Privileges->PrivilegeCount = PrivilegeCount; + for ( i=0; i<PrivilegeCount; i++) { + New->Privileges->Privileges[i] = Privileges[i]; + } + } + + MIDL_user_free( Privileges ); + } + + + + + //////////////////////////////////////////////////////////////////////// + // // + // Default owner, if explicit // + // // + //////////////////////////////////////////////////////////////////////// + + if (NT_SUCCESS(Status) && FinalOwnerIndex != 0) { + + Status = LsapAuCopySid( + &New->Owner.Owner, + &FinalIds[FinalOwnerIndex], + &IdProperties[FinalOwnerIndex] ); + } + + + + + + + + //////////////////////////////////////////////////////////////////////// + // // + // 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; + } + + + // + // Set the new TokenInformation + // + + (*TokenInformationType) = LsaTokenInformationV1; + (*TokenInformation) = New; + + } else { + + // + // Something went wrong - free the new TokenInformationV1 structure + // + + LsapFreeTokenInformationV1( New ); + } + + return(Status); + +} + + +NTSTATUS +LsapAuCopySidAndAttributes( + PSID_AND_ATTRIBUTES Target, + PSID_AND_ATTRIBUTES Source, + PULONG SourceProperties + ) + +/*++ + +Routine Description: + + Copy or reference a SID and its corresonding attributes. + + The SID may be referenced if the SourceProperties indicate it + has been allocated. In this case, the SourceProperties must be + changed to indicate the SID is now a copy. + + +Arguments: + + Target - points to the SID_AND_ATTRIBUTES structure to receive + the copy of Source. + + Source - points to the SID_AND_ATTRIBUTES structure to be copied. + + SourceProperties - Contains LSAP_AU_SID_PROP_Xxx flags providing + information about the source. In some cases, the source may + be referenced instead of copied. + +Return Value: + + STATUS_SUCCESS - The copy was successful. + + STATUS_NO_MEMORY - memory could not be allocated to perform the copy. + +--*/ + +{ + ULONG Length; + + + if ((*SourceProperties) & LSAP_AU_SID_PROP_ALLOCATED) { + + (*Target) = (*Source); + (*SourceProperties) &= ~LSAP_AU_SID_PROP_ALLOCATED; + (*SourceProperties) |= LSAP_AU_SID_PROP_COPY; + + return(STATUS_SUCCESS); + } + + // + // The SID needs to be copied ... + // + + Length = RtlLengthSid( Source->Sid ); + Target->Sid = LsapAllocateLsaHeap( Length ); + if (Target->Sid == NULL) { + return(STATUS_NO_MEMORY); + } + + RtlMoveMemory( Target->Sid, Source->Sid, Length ); + Target->Attributes = Source->Attributes; + + return(STATUS_SUCCESS); + +} + + +NTSTATUS +LsapAuCopySid( + PSID *Target, + PSID_AND_ATTRIBUTES Source, + PULONG SourceProperties + ) + +/*++ + +Routine Description: + + Copy or reference a SID. + + The SID may be referenced if the SourceProperties indicate it + has been allocated. In this case, the SourceProperties must be + changed to indicate the SID is now a copy. + + +Arguments: + + Target - Recieves a pointer to the SID copy. + + Source - points to a SID_AND_ATTRIBUTES structure containing the SID + to be copied. + + SourceProperties - Contains LSAP_AU_SID_PROP_Xxx flags providing + information about the source. In some cases, the source may + be referenced instead of copied. + +Return Value: + + STATUS_SUCCESS - The copy was successful. + + STATUS_NO_MEMORY - memory could not be allocated to perform the copy. + +--*/ + +{ + ULONG Length; + + + if ((*SourceProperties) & LSAP_AU_SID_PROP_ALLOCATED) { + + (*Target) = Source->Sid; + (*SourceProperties) &= ~LSAP_AU_SID_PROP_ALLOCATED; + (*SourceProperties) |= LSAP_AU_SID_PROP_COPY; + + return(STATUS_SUCCESS); + } + + // + // The SID needs to be copied ... + // + + Length = RtlLengthSid( Source->Sid ); + (*Target) = LsapAllocateLsaHeap( Length ); + if ((*Target == NULL)) { + return(STATUS_NO_MEMORY); + } + + RtlMoveMemory( (*Target), Source->Sid, Length ); + + return(STATUS_SUCCESS); + +} + + + +NTSTATUS +LsapAuOpenSam( VOID ) + +/*++ + +Routine Description: + + This routine opens SAM for use during authentication. It + opens a handle to both the BUILTIN domain and the ACCOUNT domain. + +Arguments: + + None. + +Return Value: + + STATUS_SUCCESS - Succeeded. +--*/ + +{ + NTSTATUS Status, IgnoreStatus; + PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo; + + + if (LsapAuSamOpened == TRUE) { + return(STATUS_SUCCESS); + } + + Status = LsapOpenSam(); + 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 ); + LsaFreeMemory( PolicyAccountDomainInfo ); + } + } + + 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 + // + + LsaFreeMemory( 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; + + + // + // Enable or disable all privileges according to logon type + // + + if (LogonType == Network) { + 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) { + return; + } + + + ChangeNotify = RtlConvertLongToLuid(SE_CHANGE_NOTIFY_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); + } + } + + return; + +} |