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.
2006 lines
63 KiB
2006 lines
63 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
polsvr.cpp
|
|
|
|
Abstract:
|
|
|
|
Server routines to get policy notification
|
|
|
|
Author:
|
|
|
|
Jin Huang (jinhuang) 17-Jun-1998
|
|
|
|
Revision History:
|
|
|
|
-*/
|
|
|
|
#include "headers.h"
|
|
#include "serverp.h"
|
|
#include "pfp.h"
|
|
#include "scesetup.h"
|
|
#include "queue.h"
|
|
#include <sddl.h>
|
|
#include <ntldap.h>
|
|
|
|
//#include <gpedit.h>
|
|
//#include <initguid.h>
|
|
//#include <gpeditp.h>
|
|
#include <io.h>
|
|
|
|
#pragma hdrstop
|
|
|
|
DWORD
|
|
ScepNotifyGetAuditPolicies(
|
|
IN OUT PSCE_PROFILE_INFO pSmpInfo,
|
|
IN PSCE_PROFILE_INFO pScpInfo OPTIONAL,
|
|
IN BOOL bSaveToLocal,
|
|
OUT BOOL *pbChanged
|
|
);
|
|
|
|
DWORD
|
|
ScepNotifyPrivilegeChanges(
|
|
IN SECURITY_DB_DELTA_TYPE DeltaType,
|
|
IN PSID AccountSid,
|
|
IN BOOL bAccountDeleted,
|
|
IN OUT PSCE_PROFILE_INFO pSmpInfo,
|
|
IN OUT PSCE_PROFILE_INFO pScpInfo OPTIONAL,
|
|
IN BOOL bSaveToLocal,
|
|
IN DWORD ExplicitLowRight,
|
|
IN DWORD ExplicitHighRight,
|
|
OUT BOOL *pbChanged
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepNotifySaveFixValueSection(
|
|
IN PSCECONTEXT hProfile,
|
|
IN PSCE_PROFILE_INFO pInfo,
|
|
IN SCE_KEY_LOOKUP *Keys,
|
|
IN DWORD cKeys,
|
|
IN PCWSTR SectionName
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepNotifySavedAuditPolicy(
|
|
IN PSCECONTEXT hProfile,
|
|
IN PSCE_PROFILE_INFO pInfo
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepNotifySavedPrivileges(
|
|
IN PSCECONTEXT hProfile,
|
|
IN PSCE_PRIVILEGE_ASSIGNMENT pPrivList,
|
|
IN PSCE_PRIVILEGE_ASSIGNMENT pMergedList
|
|
);
|
|
|
|
SCESTATUS
|
|
ScepNotifySavedSystemAccess(
|
|
IN PSCECONTEXT hProfile,
|
|
IN PSCE_PROFILE_INFO pInfo
|
|
);
|
|
|
|
//*************************************************
|
|
DWORD
|
|
ScepNotifyGetChangedPolicies(
|
|
IN SECURITY_DB_TYPE DbType,
|
|
IN SECURITY_DB_DELTA_TYPE DeltaType,
|
|
IN SECURITY_DB_OBJECT_TYPE ObjectType,
|
|
IN PSID ObjectSid OPTIONAL,
|
|
IN OUT PSCE_PROFILE_INFO pSmpInfo,
|
|
IN PSCE_PROFILE_INFO pScpInfo OPTIONAL,
|
|
IN BOOL bSaveToLocal,
|
|
IN DWORD ExplicitLowRight,
|
|
IN DWORD ExplicitHighRight,
|
|
OUT BOOL *pbChanged
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Determine if policy has been changed in this notification (DbType and ObjectType).
|
|
|
|
If the effective policy buffer (pScpInfo) exists, should compare with
|
|
effective policy buffer because that's the last policy configured
|
|
on the system which may come from a domain GPO. If There is no effective
|
|
policy (such as in seutp clean install), the local policy should be
|
|
used to compare.
|
|
|
|
Arguments:
|
|
|
|
pSmpInfo - local policy
|
|
|
|
pScpInfo - effective policy
|
|
|
|
pbChanged - if the policy is changed, it's set to TRUE
|
|
|
|
*/
|
|
{
|
|
|
|
if ( pSmpInfo == NULL || pbChanged == NULL ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
*pbChanged = FALSE;
|
|
|
|
DWORD rc=ERROR_INVALID_PARAMETER;
|
|
|
|
switch ( DbType) {
|
|
case SecurityDbLsa:
|
|
|
|
//
|
|
// LSA policy changes
|
|
//
|
|
|
|
if ( ObjectType == SecurityDbObjectLsaPolicy ) {
|
|
//
|
|
// maybe audit policy is changed
|
|
//
|
|
|
|
rc = ScepNotifyGetAuditPolicies(pSmpInfo, pScpInfo, bSaveToLocal, pbChanged);
|
|
|
|
} else {
|
|
//
|
|
// account policy is changed (user rights)
|
|
//
|
|
rc = ScepNotifyPrivilegeChanges(DeltaType,
|
|
ObjectSid,
|
|
FALSE,
|
|
pSmpInfo,
|
|
pScpInfo,
|
|
bSaveToLocal,
|
|
ExplicitLowRight,
|
|
ExplicitHighRight,
|
|
pbChanged);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SecurityDbSam:
|
|
|
|
//
|
|
// SAM password and account policy changes
|
|
//
|
|
if ( ObjectType == SecurityDbObjectSamDomain ) {
|
|
|
|
rc = ScepAnalyzeSystemAccess(pSmpInfo,
|
|
pScpInfo,
|
|
SCEPOL_SAVE_BUFFER |
|
|
(bSaveToLocal ? SCEPOL_SAVE_DB : 0 ),
|
|
pbChanged,
|
|
NULL
|
|
);
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Query/compare system access", DbType, ObjectType, NULL);
|
|
|
|
} else {
|
|
|
|
//
|
|
// account is deleted. Should delete it from user rights
|
|
//
|
|
rc = ScepNotifyPrivilegeChanges(DeltaType,
|
|
ObjectSid,
|
|
TRUE,
|
|
pSmpInfo,
|
|
pScpInfo,
|
|
bSaveToLocal,
|
|
ExplicitLowRight,
|
|
ExplicitHighRight,
|
|
pbChanged);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepNotifyGetAuditPolicies(
|
|
IN OUT PSCE_PROFILE_INFO pSmpInfo,
|
|
IN PSCE_PROFILE_INFO pScpInfo OPTIONAL,
|
|
IN BOOL bSaveToLocal,
|
|
OUT BOOL *pbChanged
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Determine if audit policy has been changed in this notification.
|
|
|
|
If the effective policy buffer (pScpInfo) exists, should compare with
|
|
effective policy buffer because that's the last policy configured
|
|
on the system which may come from a domain GPO. If There is no effective
|
|
policy (such as in seutp clean install), the local policy should be
|
|
used to compare.
|
|
|
|
Arguments:
|
|
|
|
pSmpInfo - local policy
|
|
|
|
pScpInfo - effective policy
|
|
|
|
pbChanged - if the audit policy is changed, it's set to TRUE
|
|
|
|
*/
|
|
{
|
|
|
|
LSA_HANDLE lsaHandle=NULL;
|
|
NTSTATUS status;
|
|
DWORD rc;
|
|
|
|
//
|
|
// check if auditing policy is defined in the storage
|
|
//
|
|
|
|
PSCE_PROFILE_INFO pTmpInfo;
|
|
|
|
if ( pScpInfo ) {
|
|
pTmpInfo = pScpInfo;
|
|
} else {
|
|
pTmpInfo = pSmpInfo;
|
|
}
|
|
|
|
DWORD *pdwTemp = (DWORD *)&(pTmpInfo->AuditSystemEvents);
|
|
BOOL bDefined=FALSE;
|
|
|
|
for ( DWORD i=0; i<9; i++ ) {
|
|
if ( *pdwTemp != SCE_NO_VALUE ) {
|
|
bDefined = TRUE;
|
|
break;
|
|
}
|
|
pdwTemp++;
|
|
}
|
|
|
|
if ( !bDefined ) {
|
|
ScepNotifyLogPolicy(0, FALSE, L"No audit policy is defined", SecurityDbLsa, SecurityDbObjectLsaPolicy, NULL );
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// open Lsa policy for read/write
|
|
//
|
|
|
|
ScepNotifyLogPolicy(0, FALSE, L"Open LSA", SecurityDbLsa, SecurityDbObjectLsaPolicy, NULL );
|
|
|
|
status = ScepOpenLsaPolicy(
|
|
POLICY_VIEW_AUDIT_INFORMATION |
|
|
POLICY_AUDIT_LOG_ADMIN,
|
|
&lsaHandle,
|
|
TRUE
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
lsaHandle = NULL;
|
|
rc = RtlNtStatusToDosError( status );
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Open failed", SecurityDbLsa, SecurityDbObjectLsaPolicy, NULL );
|
|
|
|
return(rc);
|
|
}
|
|
|
|
PPOLICY_AUDIT_EVENTS_INFO pAuditEvent=NULL;
|
|
|
|
//
|
|
// Query audit event information
|
|
//
|
|
|
|
status = LsaQueryInformationPolicy( lsaHandle,
|
|
PolicyAuditEventsInformation,
|
|
(PVOID *)&pAuditEvent
|
|
);
|
|
rc = RtlNtStatusToDosError( status );
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Query Audit", SecurityDbLsa, SecurityDbObjectLsaPolicy, NULL );
|
|
|
|
if ( NT_SUCCESS( status ) ) {
|
|
|
|
//
|
|
// restore the auditing mode
|
|
//
|
|
DWORD *pdwAuditAddr=&(pTmpInfo->AuditSystemEvents);
|
|
DWORD *pdwLocalAudit=&(pSmpInfo->AuditSystemEvents);
|
|
|
|
DWORD dwVal;
|
|
|
|
for ( ULONG i=0; i<pAuditEvent->MaximumAuditEventCount && i<9; i++ ) {
|
|
//
|
|
// because secedit buffer is not defined in the exact same sequence as
|
|
// POLICY_AUDIT_EVENT_TYPE, have to case this
|
|
//
|
|
dwVal = pAuditEvent->AuditingMode ? pAuditEvent->EventAuditingOptions[i] : 0;
|
|
switch ( i ) {
|
|
case AuditCategoryDetailedTracking:
|
|
if ( pTmpInfo->AuditProcessTracking != SCE_NO_VALUE &&
|
|
pTmpInfo->AuditProcessTracking != dwVal ) {
|
|
// save the setting in local policy table
|
|
pSmpInfo->AuditProcessTracking = dwVal;
|
|
*pbChanged = TRUE;
|
|
} else if ( bSaveToLocal ) {
|
|
//
|
|
// turn this item off to indicate this one is not changed
|
|
//
|
|
pSmpInfo->AuditProcessTracking = SCE_NO_VALUE;
|
|
}
|
|
break;
|
|
case AuditCategoryPolicyChange:
|
|
if ( pTmpInfo->AuditPolicyChange != SCE_NO_VALUE &&
|
|
pTmpInfo->AuditPolicyChange != dwVal ) {
|
|
pSmpInfo->AuditPolicyChange = dwVal;
|
|
*pbChanged = TRUE;
|
|
} else if ( bSaveToLocal ) {
|
|
//
|
|
// turn this item off to indicate this one is not changed
|
|
//
|
|
pSmpInfo->AuditPolicyChange = SCE_NO_VALUE;
|
|
}
|
|
break;
|
|
case AuditCategoryAccountManagement:
|
|
if ( pTmpInfo->AuditAccountManage != SCE_NO_VALUE &&
|
|
pTmpInfo->AuditAccountManage != dwVal ) {
|
|
pSmpInfo->AuditAccountManage = dwVal;
|
|
*pbChanged = TRUE;
|
|
} else if ( bSaveToLocal ) {
|
|
//
|
|
// turn this item off to indicate this one is not changed
|
|
//
|
|
pSmpInfo->AuditAccountManage = SCE_NO_VALUE;
|
|
}
|
|
break;
|
|
default:
|
|
if ( pdwAuditAddr[i] != SCE_NO_VALUE &&
|
|
pdwAuditAddr[i] != dwVal ) {
|
|
pdwLocalAudit[i] = dwVal;
|
|
*pbChanged = TRUE;
|
|
} else if ( bSaveToLocal ) {
|
|
//
|
|
// turn this item off to indicate this one is not changed
|
|
//
|
|
pdwLocalAudit[i] = SCE_NO_VALUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
LsaFreeMemory((PVOID)pAuditEvent);
|
|
}
|
|
|
|
LsaClose( lsaHandle );
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepNotifyPrivilegeChanges(
|
|
IN SECURITY_DB_DELTA_TYPE DeltaType,
|
|
IN PSID AccountSid,
|
|
IN BOOL bAccountDeleted,
|
|
IN OUT PSCE_PROFILE_INFO pSmpInfo,
|
|
IN OUT PSCE_PROFILE_INFO pScpInfo OPTIONAL,
|
|
IN BOOL bSaveToLocal,
|
|
IN DWORD ExplicitLowRight,
|
|
IN DWORD ExplicitHighRight,
|
|
IN BOOL *pbChanged
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Determine if user rights has been changed in this notification.
|
|
|
|
If the effective policy buffer (pScpInfo) exists, should compare with
|
|
effective policy buffer because that's the last policy configured
|
|
on the system which may come from a domain GPO. If There is no effective
|
|
policy (such as in seutp clean install), the local policy should be
|
|
used to compare.
|
|
|
|
User rights should all come in the exact same format as defined in policy
|
|
storage (for example, SID string or free text names). There is no account
|
|
lookup in the query.
|
|
|
|
Arguments:
|
|
|
|
pSmpInfo - local policy
|
|
|
|
pScpInfo - effective policy
|
|
|
|
pbChanged - if the user rights is changed, it's set to TRUE
|
|
|
|
*/
|
|
{
|
|
if ( AccountSid == NULL || pSmpInfo == NULL ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// open Lsa policy
|
|
//
|
|
LSA_HANDLE lsaHandle=NULL;
|
|
NTSTATUS NtStatus;
|
|
DWORD rc=0;
|
|
|
|
//
|
|
// open Lsa policy for read/write
|
|
//
|
|
|
|
ScepNotifyLogPolicy(0, FALSE, L"Open LSA", SecurityDbLsa, SecurityDbObjectLsaAccount, NULL );
|
|
|
|
// GENERIC_READ | GENERIC_EXECUTE | bug in LsaOpenPolicy, can't pass in generic access
|
|
|
|
NtStatus = ScepOpenLsaPolicy(
|
|
POLICY_VIEW_LOCAL_INFORMATION |
|
|
POLICY_LOOKUP_NAMES,
|
|
&lsaHandle,
|
|
TRUE
|
|
);
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
|
|
lsaHandle = NULL;
|
|
ScepNotifyLogPolicy(RtlNtStatusToDosError(NtStatus),
|
|
FALSE,
|
|
L"Open Failed",
|
|
SecurityDbLsa,
|
|
SecurityDbObjectLsaAccount,
|
|
NULL );
|
|
return ( RtlNtStatusToDosError( NtStatus ) );
|
|
|
|
}
|
|
|
|
ScepNotifyLogPolicy(0,
|
|
FALSE,
|
|
L"Open completed",
|
|
SecurityDbLsa,
|
|
SecurityDbObjectLsaAccount,
|
|
NULL );
|
|
|
|
PWSTR StringSid=NULL;
|
|
DWORD StringLen=0;
|
|
|
|
//
|
|
// convert sid to sid string
|
|
//
|
|
ScepConvertSidToPrefixStringSid(AccountSid, &StringSid);
|
|
|
|
ScepNotifyLogPolicy(0, FALSE, L"Convert to string SID", SecurityDbLsa, SecurityDbObjectLsaAccount, StringSid );
|
|
|
|
LPTSTR AccountName = NULL;
|
|
DWORD Len=0;
|
|
|
|
if ( !bAccountDeleted ) {
|
|
|
|
//
|
|
// translate account sid to name
|
|
//
|
|
|
|
BOOL bFromAccountDomain = ScepIsSidFromAccountDomain( AccountSid );
|
|
|
|
NtStatus = ScepConvertSidToName(
|
|
lsaHandle,
|
|
AccountSid,
|
|
bFromAccountDomain,
|
|
&AccountName,
|
|
&Len
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
ScepNotifyLogPolicy(rc,
|
|
FALSE,
|
|
L"Get Account Name",
|
|
SecurityDbLsa,
|
|
SecurityDbObjectLsaAccount,
|
|
AccountName ? AccountName : StringSid);
|
|
|
|
}
|
|
|
|
DWORD dwPrivLowHeld, dwPrivHighHeld;
|
|
|
|
if ( AccountName || StringSid ) {
|
|
|
|
NtStatus = STATUS_SUCCESS;
|
|
//
|
|
// find out the account name pointer (without domain prefix)
|
|
//
|
|
PWSTR pNameStart = NULL;
|
|
|
|
if ( AccountName ) {
|
|
pNameStart = wcschr(AccountName, L'\\');
|
|
|
|
if ( pNameStart ) {
|
|
//
|
|
// domain relative account, check if this is from a foreign domain
|
|
//
|
|
UNICODE_STRING u;
|
|
u.Buffer = AccountName;
|
|
u.Length = ((USHORT)(pNameStart-AccountName))*sizeof(WCHAR);
|
|
|
|
if ( ScepIsDomainLocal(&u) ) {
|
|
//
|
|
// local domain (builtin, account, ...)
|
|
// this can be used to match free text accounts
|
|
//
|
|
pNameStart++;
|
|
} else {
|
|
//
|
|
// account from a foreign domain
|
|
// do not allow mapping of free text accounts
|
|
//
|
|
pNameStart = NULL;
|
|
}
|
|
} else pNameStart = AccountName;
|
|
}
|
|
|
|
if ( StringSid ) StringLen = wcslen(StringSid);
|
|
|
|
if ( DeltaType == SecurityDbDelete ) {
|
|
|
|
dwPrivLowHeld = 0;
|
|
dwPrivHighHeld = 0;
|
|
|
|
} else if ( ExplicitLowRight != 0 ||
|
|
ExplicitHighRight != 0 ) {
|
|
|
|
dwPrivLowHeld = ExplicitLowRight;
|
|
dwPrivHighHeld = ExplicitHighRight;
|
|
|
|
} else {
|
|
|
|
//
|
|
// get all privileges assigned to this account
|
|
//
|
|
|
|
NtStatus = ScepGetAccountExplicitRight(
|
|
lsaHandle,
|
|
AccountSid,
|
|
&dwPrivLowHeld,
|
|
&dwPrivHighHeld
|
|
);
|
|
}
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
WCHAR Msg[50];
|
|
swprintf(Msg, L"Get Priv/Right %8x %8x\0", dwPrivHighHeld, dwPrivLowHeld);
|
|
|
|
ScepNotifyLogPolicy(rc,
|
|
FALSE,
|
|
Msg,
|
|
SecurityDbLsa,
|
|
SecurityDbObjectLsaAccount,
|
|
AccountName ? AccountName : StringSid );
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
//
|
|
// loop through each privilege defined in SCE to add/remove the account
|
|
//
|
|
PSCE_PRIVILEGE_ASSIGNMENT pTemp, pTemp2;
|
|
PSCE_NAME_LIST pName, pParent, pName2, pParent2;
|
|
INT i;
|
|
|
|
for ( pTemp2=pSmpInfo->OtherInfo.smp.pPrivilegeAssignedTo;
|
|
pTemp2 != NULL; pTemp2=pTemp2->Next ) {
|
|
pTemp2->Status = SCE_STATUS_NOT_CONFIGURED;
|
|
}
|
|
|
|
if ( pScpInfo && bSaveToLocal ) {
|
|
//
|
|
// !!!do this only when save to database!!!
|
|
// if there is effective policy, compare with effective rights
|
|
// modify both effective policy list and local policy list
|
|
//
|
|
for ( pTemp=pScpInfo->OtherInfo.smp.pPrivilegeAssignedTo;
|
|
pTemp != NULL; pTemp=pTemp->Next ) {
|
|
|
|
pTemp->Status = 0;
|
|
|
|
i = ScepLookupPrivByName(pTemp->Name);
|
|
|
|
if ( i > -1 ) {
|
|
|
|
//
|
|
// find the local policy match
|
|
//
|
|
for ( pTemp2=pSmpInfo->OtherInfo.smp.pPrivilegeAssignedTo;
|
|
pTemp2 != NULL; pTemp2=pTemp2->Next ) {
|
|
if ( _wcsicmp(pTemp->Name, pTemp2->Name) == 0 ) {
|
|
// find it
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// compare with effective policy
|
|
// try to find in string sid first, then full account name,
|
|
// and last free text account
|
|
//
|
|
for ( pName=pTemp->AssignedTo, pParent=NULL;
|
|
pName != NULL; pParent=pName, pName = pName->Next ) {
|
|
if ( (StringSid && _wcsicmp(StringSid, pName->Name) == 0) ||
|
|
(AccountName && _wcsicmp(AccountName, pName->Name) == 0) ||
|
|
(pNameStart && _wcsicmp(pNameStart, pName->Name) == 0) ) {
|
|
// find it
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// also find the match in local policy (if there is any)
|
|
// try to find in string sid first, then full account name,
|
|
// and last free text account
|
|
//
|
|
if ( pTemp2 ) {
|
|
|
|
pTemp2->Status = 0;
|
|
|
|
for ( pName2=pTemp2->AssignedTo, pParent2=NULL;
|
|
pName2 != NULL; pParent2=pName2, pName2 = pName2->Next ) {
|
|
if ( (StringSid && _wcsicmp(StringSid, pName2->Name) == 0) ||
|
|
(AccountName && _wcsicmp(AccountName, pName2->Name) == 0) ||
|
|
(pNameStart && _wcsicmp(pNameStart, pName2->Name) == 0) ) {
|
|
// find it
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
pName2 = NULL;
|
|
pParent2 = NULL;
|
|
}
|
|
|
|
//
|
|
// now adjust the lists
|
|
//
|
|
if ( ( ( i < 32 ) && ( dwPrivLowHeld & (1 << i) ) ) ||
|
|
( ( i >= 32 ) && ( dwPrivHighHeld & (1 << (i-32) ) ) ) ) {
|
|
|
|
if ( pName == NULL ) {
|
|
//
|
|
// add this node to effective list
|
|
//
|
|
rc = ScepAddToNameList(&(pTemp->AssignedTo),
|
|
StringSid ? StringSid : AccountName,
|
|
StringSid ? StringLen : Len);
|
|
|
|
*pbChanged = TRUE;
|
|
pTemp->Status = SCE_STATUS_MISMATCH;
|
|
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
break;
|
|
}
|
|
}
|
|
if ( (pTemp2 != NULL) && (pName2 == NULL) ) {
|
|
//
|
|
// should add this node to local policy node
|
|
//
|
|
rc = ScepAddToNameList(&(pTemp2->AssignedTo),
|
|
StringSid ? StringSid : AccountName,
|
|
StringSid ? StringLen : Len);
|
|
|
|
*pbChanged = TRUE;
|
|
pTemp2->Status = SCE_STATUS_MISMATCH;
|
|
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( pName ) {
|
|
|
|
//
|
|
// should remove it from effective list
|
|
//
|
|
if ( pParent ) {
|
|
pParent->Next = pName->Next;
|
|
} else {
|
|
pTemp->AssignedTo = pName->Next;
|
|
}
|
|
|
|
pName->Next = NULL;
|
|
ScepFree(pName->Name);
|
|
ScepFree(pName);
|
|
pName = NULL;
|
|
|
|
*pbChanged = TRUE;
|
|
pTemp->Status = SCE_STATUS_MISMATCH;
|
|
}
|
|
|
|
if ( pTemp2 && pName2 ) {
|
|
//
|
|
// should remove it from local list
|
|
//
|
|
if ( pParent2 ) {
|
|
pParent2->Next = pName2->Next;
|
|
} else {
|
|
pTemp2->AssignedTo = pName2->Next;
|
|
}
|
|
|
|
pName2->Next = NULL;
|
|
ScepFree(pName2->Name);
|
|
ScepFree(pName2);
|
|
pName2 = NULL;
|
|
|
|
*pbChanged = TRUE;
|
|
pTemp2->Status = SCE_STATUS_MISMATCH;
|
|
}
|
|
}
|
|
|
|
if ( i < 32 ) {
|
|
|
|
dwPrivLowHeld &= ~(1 << i);
|
|
} else {
|
|
dwPrivHighHeld &= ~(1 << (i-32) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( pTemp=pSmpInfo->OtherInfo.smp.pPrivilegeAssignedTo;
|
|
pTemp != NULL; pTemp=pTemp->Next ) {
|
|
|
|
if ( pTemp->Status != SCE_STATUS_NOT_CONFIGURED ) {
|
|
//
|
|
// this one was already checked in previous loop
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// when get here, this privilege must not be found
|
|
// in the effective right list (or the effective
|
|
// right list is NULL)
|
|
//
|
|
pTemp->Status = 0;
|
|
|
|
i = ScepLookupPrivByName(pTemp->Name);
|
|
|
|
if ( i > -1 ) {
|
|
|
|
//
|
|
// detect if anything changed (with the local policy)
|
|
//
|
|
|
|
for ( pName=pTemp->AssignedTo, pParent=NULL;
|
|
pName != NULL; pParent=pName, pName = pName->Next ) {
|
|
if ( (StringSid && _wcsicmp(StringSid, pName->Name) == 0) ||
|
|
(AccountName && _wcsicmp(AccountName, pName->Name) == 0) ||
|
|
(pNameStart && _wcsicmp(pNameStart, pName->Name) == 0) ) {
|
|
// find it
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( ( ( i < 32 ) && ( dwPrivLowHeld & (1 << i) ) ) ||
|
|
( ( i >= 32 ) && ( dwPrivHighHeld & (1 << (i-32) ) ) ) ) {
|
|
|
|
if ( pName == NULL ) {
|
|
//
|
|
// should add this node
|
|
//
|
|
rc = ScepAddToNameList(&(pTemp->AssignedTo),
|
|
StringSid ? StringSid : AccountName,
|
|
StringSid ? StringLen : Len);
|
|
|
|
*pbChanged = TRUE;
|
|
pTemp->Status = SCE_STATUS_MISMATCH;
|
|
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( pName ) {
|
|
|
|
//
|
|
// should remove it
|
|
//
|
|
if ( pParent ) {
|
|
pParent->Next = pName->Next;
|
|
} else {
|
|
pTemp->AssignedTo = pName->Next;
|
|
}
|
|
|
|
pName->Next = NULL;
|
|
ScepFree(pName->Name);
|
|
ScepFree(pName);
|
|
pName = NULL;
|
|
|
|
*pbChanged = TRUE;
|
|
pTemp->Status = SCE_STATUS_MISMATCH;
|
|
}
|
|
}
|
|
|
|
if ( i < 32 ) {
|
|
|
|
dwPrivLowHeld &= ~(1 << i);
|
|
} else {
|
|
dwPrivHighHeld &= ~(1 << (i-32) );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// if the privilege is not covered by the template/db,
|
|
// do not trap it becuase user explicitly exclude this one.
|
|
//
|
|
if ( rc == ERROR_SUCCESS &&
|
|
( dwPrivLowHeld || dwPrivHighHeld ) ) {
|
|
|
|
//
|
|
// other new privileges added which are not in the template
|
|
//
|
|
|
|
for ( i=0; i<cPrivCnt; i++) {
|
|
|
|
if ( ( ( i < 32 ) && ( dwPrivLowHeld & (1 << i) ) ) ||
|
|
( ( i >= 32 ) && ( dwPrivHighHeld & (1 << (i-32) ) ) ) ) {
|
|
|
|
//
|
|
// add this account/right to the list
|
|
//
|
|
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
pTemp = (PSCE_PRIVILEGE_ASSIGNMENT)ScepAlloc( LMEM_ZEROINIT,
|
|
sizeof(SCE_PRIVILEGE_ASSIGNMENT) );
|
|
if ( pTemp ) {
|
|
pTemp->Name = (PWSTR)ScepAlloc( (UINT)0, (wcslen(SCE_Privileges[i].Name)+1)*sizeof(WCHAR));
|
|
|
|
if ( pTemp->Name != NULL ) {
|
|
|
|
wcscpy(pTemp->Name, SCE_Privileges[i].Name);
|
|
pTemp->Status = SCE_STATUS_GOOD;
|
|
pTemp->AssignedTo = NULL;
|
|
|
|
rc = ScepAddToNameList(&(pTemp->AssignedTo),
|
|
StringSid ? StringSid : AccountName,
|
|
StringSid ? StringLen : Len);
|
|
|
|
*pbChanged = TRUE;
|
|
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
|
|
ScepFree(pTemp->Name);
|
|
}
|
|
|
|
}
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
|
|
ScepFree(pTemp);
|
|
}
|
|
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
//
|
|
// add this node to the list
|
|
//
|
|
pTemp->Next = pSceInfo->OtherInfo.smp.pPrivilegeAssignedTo;
|
|
pSceInfo->OtherInfo.smp.pPrivilegeAssignedTo = pTemp;
|
|
pTemp = NULL;
|
|
|
|
} else {
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
} // loop to the next privilege
|
|
} // there are new privileges added to the template
|
|
#endif
|
|
|
|
ScepNotifyLogPolicy(rc,
|
|
FALSE,
|
|
L"Rights Modified",
|
|
SecurityDbLsa,
|
|
SecurityDbObjectLsaAccount,
|
|
AccountName ? AccountName : StringSid);
|
|
|
|
} // success getting current privileges assigned to the account
|
|
}
|
|
|
|
if ( AccountName ) {
|
|
LocalFree(AccountName);
|
|
}
|
|
|
|
if ( StringSid ) {
|
|
LocalFree(StringSid);
|
|
}
|
|
|
|
LsaClose( lsaHandle );
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepNotifySaveChangedPolicies(
|
|
IN PSCECONTEXT hProfile,
|
|
IN SECURITY_DB_TYPE DbType,
|
|
IN AREA_INFORMATION Area,
|
|
IN PSCE_PROFILE_INFO pInfo,
|
|
IN PSCE_PROFILE_INFO pMergedInfo OPTIONAL
|
|
)
|
|
{
|
|
|
|
if ( hProfile == NULL || pInfo == NULL ) {
|
|
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
SCESTATUS rc;
|
|
|
|
rc = SceJetStartTransaction( hProfile );
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
if ( Area & AREA_SECURITY_POLICY ) {
|
|
|
|
//
|
|
// handle auditing policy
|
|
//
|
|
|
|
if ( DbType == SecurityDbLsa ) {
|
|
rc = ScepNotifySavedAuditPolicy(hProfile,
|
|
pInfo
|
|
);
|
|
} else {
|
|
rc = ScepNotifySavedSystemAccess(hProfile,
|
|
pInfo
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( (SCESTATUS_SUCCESS == rc) &&
|
|
(Area & AREA_PRIVILEGES) ) {
|
|
|
|
//
|
|
// handle user rights.
|
|
//
|
|
|
|
rc = ScepNotifySavedPrivileges(hProfile,
|
|
pInfo->OtherInfo.smp.pPrivilegeAssignedTo,
|
|
pMergedInfo ? pMergedInfo->OtherInfo.smp.pPrivilegeAssignedTo : NULL
|
|
);
|
|
}
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
//
|
|
// needs return code for commiting the transaction
|
|
//
|
|
rc = SceJetCommitTransaction(hProfile, 0);
|
|
|
|
}
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
|
|
SceJetRollback(hProfile, 0);
|
|
}
|
|
}
|
|
|
|
|
|
return( ScepSceStatusToDosError(rc) );
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepNotifySavedAuditPolicy(
|
|
IN PSCECONTEXT hProfile,
|
|
IN PSCE_PROFILE_INFO pInfo
|
|
)
|
|
{
|
|
SCE_KEY_LOOKUP EventKeys[]={
|
|
{(PWSTR)TEXT("AuditSystemEvents"), offsetof(struct _SCE_PROFILE_INFO, AuditSystemEvents), 'D'},
|
|
{(PWSTR)TEXT("AuditLogonEvents"), offsetof(struct _SCE_PROFILE_INFO, AuditLogonEvents), 'D'},
|
|
{(PWSTR)TEXT("AuditObjectAccess"), offsetof(struct _SCE_PROFILE_INFO, AuditObjectAccess), 'D'},
|
|
{(PWSTR)TEXT("AuditPrivilegeUse"), offsetof(struct _SCE_PROFILE_INFO, AuditPrivilegeUse), 'D'},
|
|
{(PWSTR)TEXT("AuditPolicyChange"), offsetof(struct _SCE_PROFILE_INFO, AuditPolicyChange), 'D'},
|
|
{(PWSTR)TEXT("AuditAccountManage"), offsetof(struct _SCE_PROFILE_INFO, AuditAccountManage), 'D'},
|
|
{(PWSTR)TEXT("AuditProcessTracking"),offsetof(struct _SCE_PROFILE_INFO, AuditProcessTracking),'D'},
|
|
{(PWSTR)TEXT("AuditDSAccess"), offsetof(struct _SCE_PROFILE_INFO, AuditDSAccess), 'D'},
|
|
{(PWSTR)TEXT("AuditAccountLogon"), offsetof(struct _SCE_PROFILE_INFO, AuditAccountLogon), 'D'}};
|
|
|
|
DWORD cKeys = sizeof(EventKeys) / sizeof(SCE_KEY_LOOKUP);
|
|
|
|
|
|
if ( hProfile == NULL || pInfo == NULL ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
return( ScepNotifySaveFixValueSection(
|
|
hProfile,
|
|
pInfo,
|
|
EventKeys,
|
|
cKeys,
|
|
szAuditEvent
|
|
) );
|
|
}
|
|
|
|
SCESTATUS
|
|
ScepNotifySavedSystemAccess(
|
|
IN PSCECONTEXT hProfile,
|
|
IN PSCE_PROFILE_INFO pInfo
|
|
)
|
|
{
|
|
SCE_KEY_LOOKUP AccessKeys[] = {
|
|
{(PWSTR)TEXT("MinimumPasswordAge"), offsetof(struct _SCE_PROFILE_INFO, MinimumPasswordAge), 'D'},
|
|
{(PWSTR)TEXT("MaximumPasswordAge"), offsetof(struct _SCE_PROFILE_INFO, MaximumPasswordAge), 'D'},
|
|
{(PWSTR)TEXT("MinimumPasswordLength"), offsetof(struct _SCE_PROFILE_INFO, MinimumPasswordLength), 'D'},
|
|
{(PWSTR)TEXT("PasswordComplexity"), offsetof(struct _SCE_PROFILE_INFO, PasswordComplexity), 'D'},
|
|
{(PWSTR)TEXT("PasswordHistorySize"), offsetof(struct _SCE_PROFILE_INFO, PasswordHistorySize), 'D'},
|
|
{(PWSTR)TEXT("LockoutBadCount"), offsetof(struct _SCE_PROFILE_INFO, LockoutBadCount), 'D'},
|
|
{(PWSTR)TEXT("ResetLockoutCount"), offsetof(struct _SCE_PROFILE_INFO, ResetLockoutCount), 'D'},
|
|
{(PWSTR)TEXT("LockoutDuration"), offsetof(struct _SCE_PROFILE_INFO, LockoutDuration), 'D'},
|
|
{(PWSTR)TEXT("RequireLogonToChangePassword"),offsetof(struct _SCE_PROFILE_INFO, RequireLogonToChangePassword),'D'},
|
|
{(PWSTR)TEXT("ForceLogoffWhenHourExpire"),offsetof(struct _SCE_PROFILE_INFO, ForceLogoffWhenHourExpire),'D'},
|
|
{(PWSTR)TEXT("ClearTextPassword"), offsetof(struct _SCE_PROFILE_INFO, ClearTextPassword), 'D'}
|
|
};
|
|
DWORD cKeys = sizeof(AccessKeys) / sizeof(SCE_KEY_LOOKUP);
|
|
|
|
|
|
if ( hProfile == NULL || pInfo == NULL ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
return( ScepNotifySaveFixValueSection(
|
|
hProfile,
|
|
pInfo,
|
|
AccessKeys,
|
|
cKeys,
|
|
szSystemAccess
|
|
) );
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepNotifySaveFixValueSection(
|
|
IN PSCECONTEXT hProfile,
|
|
IN PSCE_PROFILE_INFO pInfo,
|
|
IN SCE_KEY_LOOKUP *Keys,
|
|
IN DWORD cKeys,
|
|
IN PCWSTR SectionName
|
|
)
|
|
{
|
|
|
|
SCESTATUS rc;
|
|
PSCESECTION hSectionSmp=NULL, hSectionScp=NULL;
|
|
|
|
DWORD i;
|
|
UINT Offset;
|
|
DWORD valNewScep;
|
|
|
|
//
|
|
// open smp section for system access
|
|
//
|
|
rc = ScepOpenSectionForName(
|
|
hProfile,
|
|
SCE_ENGINE_SMP,
|
|
SectionName,
|
|
&hSectionSmp
|
|
);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
DWORD dwThisTable = hProfile->Type & 0xF0L;
|
|
|
|
if ( SCEJET_MERGE_TABLE_1 == dwThisTable ||
|
|
SCEJET_MERGE_TABLE_2 == dwThisTable ) {
|
|
|
|
if ( SCESTATUS_SUCCESS != ScepOpenSectionForName(
|
|
hProfile,
|
|
SCE_ENGINE_SCP,
|
|
SectionName,
|
|
&hSectionScp
|
|
) ) {
|
|
hSectionScp = NULL;
|
|
}
|
|
}
|
|
|
|
for ( i=0; i<cKeys; i++) {
|
|
|
|
//
|
|
// get settings in AccessLookup table
|
|
//
|
|
|
|
Offset = Keys[i].Offset;
|
|
|
|
switch ( Keys[i].BufferType ) {
|
|
case 'B':
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
valNewScep = *((DWORD *)((CHAR *)pInfo+Offset));
|
|
|
|
//
|
|
// update the SMP entry
|
|
//
|
|
rc = ScepCompareAndSaveIntValue(
|
|
hSectionSmp,
|
|
Keys[i].KeyString,
|
|
FALSE,
|
|
SCE_NO_VALUE,
|
|
valNewScep
|
|
);
|
|
|
|
if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
|
|
//
|
|
// if not find for delete, ignore the error
|
|
//
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
} else if ( SCESTATUS_SUCCESS == rc &&
|
|
hSectionScp ) {
|
|
|
|
//
|
|
// update the SCP entry, ignore error
|
|
//
|
|
ScepCompareAndSaveIntValue(
|
|
hSectionScp,
|
|
Keys[i].KeyString,
|
|
FALSE,
|
|
SCE_NO_VALUE,
|
|
valNewScep
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( hSectionScp ) {
|
|
SceJetCloseSection(&hSectionScp, TRUE);
|
|
}
|
|
|
|
SceJetCloseSection(&hSectionSmp, TRUE);
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepNotifySavedPrivileges(
|
|
IN PSCECONTEXT hProfile,
|
|
IN PSCE_PRIVILEGE_ASSIGNMENT pPrivList,
|
|
IN PSCE_PRIVILEGE_ASSIGNMENT pMergedList OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Update privileges from
|
|
|
|
Arguements:
|
|
|
|
hProfile - the jet database handle
|
|
|
|
pPrivList - the changed privilege buffer
|
|
|
|
Return Value:
|
|
|
|
SCESTATUS
|
|
*/
|
|
{
|
|
SCESTATUS rc;
|
|
PSCESECTION hSectionSmp=NULL, hSectionScp=NULL;
|
|
PSCE_PRIVILEGE_ASSIGNMENT pPriv;
|
|
|
|
if ( hProfile == NULL ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( pPrivList == NULL ) {
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
LSA_HANDLE lsaHandle=NULL;
|
|
|
|
/* no need to lookup account in save
|
|
rc = RtlNtStatusToDosError(
|
|
ScepOpenLsaPolicy(
|
|
MAXIMUM_ALLOWED,
|
|
&lsaHandle,
|
|
TRUE
|
|
));
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
|
|
lsaHandle = NULL;
|
|
|
|
ScepNotifyLogPolicy(rc, FALSE, L"Open failed", SecurityDbLsa, SecurityDbObjectLsaPolicy, NULL );
|
|
|
|
return(ScepDosErrorToSceStatus(rc));
|
|
}
|
|
*/
|
|
//
|
|
// open smp section for privileges
|
|
//
|
|
rc = ScepOpenSectionForName(
|
|
hProfile,
|
|
SCE_ENGINE_SMP,
|
|
szPrivilegeRights,
|
|
&hSectionSmp
|
|
);
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
|
|
// if SCP is different then SMP, open it
|
|
|
|
DWORD dwThisTable = hProfile->Type & 0xF0L;
|
|
|
|
|
|
if ( SCEJET_MERGE_TABLE_1 == dwThisTable ||
|
|
SCEJET_MERGE_TABLE_2 == dwThisTable ) {
|
|
|
|
if ( SCESTATUS_SUCCESS != ScepOpenSectionForName(
|
|
hProfile,
|
|
SCE_ENGINE_SCP,
|
|
szPrivilegeRights,
|
|
&hSectionScp
|
|
) ) {
|
|
hSectionScp = NULL;
|
|
}
|
|
}
|
|
|
|
for ( pPriv=pPrivList; pPriv != NULL; pPriv = pPriv->Next ) {
|
|
//
|
|
// Process each privilege in the new list
|
|
// Update SMP with new value
|
|
//
|
|
if ( pPriv->Status == SCE_STATUS_MISMATCH ) {
|
|
|
|
//
|
|
// this is in name format, should convert it
|
|
//
|
|
rc = ScepWriteNameListValue(
|
|
lsaHandle,
|
|
hSectionSmp,
|
|
pPriv->Name,
|
|
pPriv->AssignedTo,
|
|
SCE_WRITE_EMPTY_LIST, // | SCE_WRITE_CONVERT, no need to lookup
|
|
0
|
|
);
|
|
|
|
if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
} else if ( rc != SCESTATUS_SUCCESS) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( hSectionScp && pMergedList ) {
|
|
|
|
for ( pPriv=pMergedList; pPriv != NULL; pPriv = pPriv->Next ) {
|
|
//
|
|
// Process each privilege in the new list
|
|
// Update SCP with new value, don't care error
|
|
//
|
|
if ( pPriv->Status == SCE_STATUS_MISMATCH ) {
|
|
|
|
//
|
|
// this is in name format, convert it
|
|
//
|
|
rc = ScepWriteNameListValue(
|
|
lsaHandle,
|
|
hSectionScp,
|
|
pPriv->Name,
|
|
pPriv->AssignedTo,
|
|
SCE_WRITE_EMPTY_LIST, // no need to lookup | SCE_WRITE_CONVERT,
|
|
0
|
|
);
|
|
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ( hSectionScp ) {
|
|
SceJetCloseSection(&hSectionScp, TRUE);
|
|
}
|
|
|
|
SceJetCloseSection(&hSectionSmp, TRUE);
|
|
}
|
|
|
|
if ( lsaHandle ) {
|
|
LsaClose(lsaHandle);
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
DWORD
|
|
ScepNotifyGetDefaultGPOTemplateName(
|
|
IN UNICODE_STRING DnsDomainName,
|
|
IN PWSTR ComputerName OPTIONAL,
|
|
IN BOOL bDomainPolicy,
|
|
IN DWORD dwInSetup,
|
|
OUT LPTSTR *pTemplateName
|
|
)
|
|
/*
|
|
Description:
|
|
|
|
This function builds and returns a full path Group Policy Template
|
|
name (gpttmpl.inf) in a specified GPO - default domain GPO or default
|
|
domain controller GPO.
|
|
|
|
|
|
In NT4 upgrade, because DS is not created yet, a temporary file is used in
|
|
%windir%\security\filtemp.inf
|
|
|
|
In NT5 upgrade, because network is not running in setup (sysvol share is not
|
|
accessible), the GPO template is referenced with absolute path, e.g.
|
|
%windir%\sysvol\sysvol\<dns name>\.... If sysvol path can't be queried,
|
|
the temporary file as in NT4 case is used.
|
|
|
|
Outside setup when DS/network is running, the GPO template is referenced
|
|
with the DNS UNC path, e.g, \\<computername>\sysvol\<dns name>\...
|
|
If ComputerName is passed in, the parameter will be used; otherwise, the
|
|
local computer name is queried and used.
|
|
|
|
Parameters:
|
|
|
|
DnsDomainName - Domain's DNS name used in the path
|
|
|
|
ComputerName - name for the computer to connect to
|
|
|
|
bDomainPolicy - TRUE = default domain GPO; FALSE = default domain controller GPO
|
|
|
|
dwInSetup - != 0 in setup (NT4 or NT5)
|
|
|
|
pTemplateName - the output template full path name
|
|
|
|
Return Value:
|
|
|
|
Win32 error
|
|
|
|
*/
|
|
{
|
|
|
|
if ( ( dwInSetup != SCEGPO_INSETUP_NT4 &&
|
|
( DnsDomainName.Buffer == NULL ||
|
|
DnsDomainName.Length == 0)) ||
|
|
pTemplateName == NULL ) {
|
|
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// we have to replace the first DNS name with computer name
|
|
// because it might point to a remote machine where
|
|
// we don't have write access.
|
|
//
|
|
|
|
|
|
TCHAR Buffer[MAX_PATH+1];
|
|
DWORD dSize=MAX_PATH;
|
|
PWSTR SysvolPath=NULL;
|
|
|
|
Buffer[0] = L'\0';
|
|
BOOL bDefaultToNT4 = FALSE;
|
|
|
|
if ( dwInSetup == SCEGPO_INSETUP_NT5 ) {
|
|
//
|
|
// query the sysvol path from netlogon\parameters\sysvol registry value
|
|
//
|
|
|
|
DWORD RegType;
|
|
DWORD rc = ScepRegQueryValue(HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Services\\Netlogon\\Parameters",
|
|
L"Sysvol",
|
|
(PVOID *)&SysvolPath,
|
|
&RegType,
|
|
NULL
|
|
);
|
|
|
|
if ( ERROR_SUCCESS != rc || SysvolPath == NULL || RegType != REG_SZ) {
|
|
|
|
//
|
|
// if fails to query the sysvol path, default to NT4 setup case
|
|
// where the changes are saved in the temp file
|
|
//
|
|
bDefaultToNT4 = TRUE;
|
|
if ( SysvolPath ) {
|
|
ScepFree(SysvolPath);
|
|
SysvolPath = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( dwInSetup == SCEGPO_INSETUP_NT5 ||
|
|
dwInSetup == SCEGPO_INSETUP_NT4 ) {
|
|
//
|
|
// temp file name is stored in %windir% directory
|
|
//
|
|
GetSystemWindowsDirectory(Buffer, MAX_PATH);
|
|
|
|
} else if ( ComputerName == NULL ) {
|
|
//
|
|
// get current computer name
|
|
//
|
|
GetComputerName(Buffer, &dSize);
|
|
|
|
} else {
|
|
|
|
//
|
|
// use the passed in computer name
|
|
//
|
|
wcscpy(Buffer, ComputerName);
|
|
}
|
|
|
|
Buffer[MAX_PATH] = L'\0';
|
|
|
|
dSize = wcslen(Buffer);
|
|
|
|
DWORD Len;
|
|
DWORD rc=ERROR_SUCCESS;
|
|
|
|
|
|
if ( dwInSetup == SCEGPO_INSETUP_NT4 ||
|
|
(dwInSetup == SCEGPO_INSETUP_NT5 && bDefaultToNT4) ) {
|
|
//
|
|
// in setup, use the temp GPO file name
|
|
//
|
|
|
|
Len = dSize + wcslen(TEXT("\\security\\filtemp.inf"));
|
|
|
|
*pTemplateName = (PWSTR)LocalAlloc(LPTR, (Len+2)*sizeof(TCHAR));
|
|
|
|
if ( *pTemplateName ) {
|
|
|
|
swprintf(*pTemplateName, L"%s\\security\\filtemp.inf\0", Buffer);
|
|
|
|
//
|
|
// create the registry value for post setup
|
|
//
|
|
|
|
ScepRegSetIntValue( HKEY_LOCAL_MACHINE,
|
|
SCE_ROOT_PATH,
|
|
TEXT("PolicyChangedInSetup"),
|
|
1
|
|
);
|
|
|
|
} else {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
if ( dwInSetup == SCEGPO_INSETUP_NT5 ||
|
|
dwInSetup == SCEGPO_INSETUP_NT4 ) {
|
|
|
|
//
|
|
// in NT5 setup upgrade, should use SysvolPath
|
|
// SysvolPath should not be NULL when get here
|
|
// but let's check it to avoid prefix errors
|
|
//
|
|
if ( SysvolPath == NULL ) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
dSize = wcslen(SysvolPath);
|
|
Len = dSize + 1;
|
|
|
|
} else {
|
|
|
|
Len = 2 + dSize + wcslen(TEXT("\\sysvol\\"));
|
|
}
|
|
|
|
Len += ( DnsDomainName.Length/sizeof(TCHAR) +
|
|
wcslen(TEXT("\\Policies\\{}\\Machine\\")) +
|
|
wcslen(GPTSCE_TEMPLATE) );
|
|
|
|
if ( bDomainPolicy ) {
|
|
|
|
Len += wcslen(STR_DEFAULT_DOMAIN_GPO_GUID);
|
|
|
|
} else {
|
|
|
|
Len += wcslen(STR_DEFAULT_DOMAIN_CONTROLLER_GPO_GUID);
|
|
}
|
|
|
|
//
|
|
// allocate buffer for the final GPO name
|
|
//
|
|
PWSTR GpoTemplateName = (PWSTR)LocalAlloc(LPTR, (Len+2)*sizeof(TCHAR));
|
|
|
|
if ( GpoTemplateName ) {
|
|
|
|
DWORD indx=0;
|
|
|
|
if ( dwInSetup == SCEGPO_INSETUP_NT5 ||
|
|
dwInSetup == SCEGPO_INSETUP_NT4 ) {
|
|
swprintf(GpoTemplateName, L"%s\\", SysvolPath);
|
|
indx = 1;
|
|
} else {
|
|
swprintf(GpoTemplateName, L"\\\\%s\\sysvol\\", Buffer);
|
|
indx = 10;
|
|
}
|
|
|
|
wcsncpy(GpoTemplateName+indx+dSize, DnsDomainName.Buffer, DnsDomainName.Length/2);
|
|
|
|
if ( bDomainPolicy ) {
|
|
swprintf(GpoTemplateName+indx+dSize+DnsDomainName.Length/2,
|
|
L"\\Policies\\{%s}\\Machine\\%s\0",
|
|
STR_DEFAULT_DOMAIN_GPO_GUID, GPTSCE_TEMPLATE );
|
|
|
|
} else {
|
|
swprintf(GpoTemplateName+indx+dSize+DnsDomainName.Length/2,
|
|
L"\\Policies\\{%s}\\Machine\\%s\0",
|
|
STR_DEFAULT_DOMAIN_CONTROLLER_GPO_GUID, GPTSCE_TEMPLATE );
|
|
|
|
}
|
|
|
|
//
|
|
// check to see if the template exists
|
|
//
|
|
if ( SCEGPO_NOCHECK_EXISTENCE != dwInSetup ) {
|
|
|
|
if ( 0xFFFFFFFF == GetFileAttributes(GpoTemplateName) ) {
|
|
|
|
rc = ERROR_OBJECT_NOT_FOUND;
|
|
|
|
LocalFree(GpoTemplateName);
|
|
GpoTemplateName = NULL;
|
|
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// free the buffers if it fails
|
|
//
|
|
if ( SysvolPath ) {
|
|
ScepFree(SysvolPath);
|
|
}
|
|
|
|
*pTemplateName = GpoTemplateName;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
DWORD
|
|
ScepNotifySaveNotifications(
|
|
IN PWSTR TemplateName,
|
|
IN SECURITY_DB_TYPE DbType,
|
|
IN SECURITY_DB_OBJECT_TYPE ObjectType,
|
|
IN SECURITY_DB_DELTA_TYPE DeltaType,
|
|
IN PSID ObjectSid OPTIONAL
|
|
)
|
|
{
|
|
if ( TemplateName == NULL ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
DWORD rc=ERROR_SUCCESS;
|
|
|
|
if ( SecurityDbLsa == DbType &&
|
|
SecurityDbObjectLsaPolicy == ObjectType ) {
|
|
//
|
|
// LSA policy changes
|
|
//
|
|
|
|
if ( !WritePrivateProfileString(L"Policies",
|
|
L"LsaPolicy",
|
|
L"1",
|
|
TemplateName
|
|
) ) {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
} else if ( SecurityDbSam == DbType &&
|
|
ObjectType != SecurityDbObjectSamUser &&
|
|
ObjectType != SecurityDbObjectSamGroup &&
|
|
ObjectType != SecurityDbObjectSamAlias ) {
|
|
|
|
//
|
|
// if it's not for deleted account, update the SAM policy section
|
|
//
|
|
|
|
if ( !WritePrivateProfileString(L"Policies",
|
|
L"SamPolicy",
|
|
L"1",
|
|
TemplateName
|
|
) ) {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
} else if ( ObjectSid &&
|
|
(SecurityDbLsa == DbType || SecurityDbSam == DbType ) ) {
|
|
|
|
//
|
|
// account policy is changed (user rights)
|
|
// get all privileges assigned to this account
|
|
//
|
|
|
|
DWORD dwPrivLowHeld=0, dwPrivHighHeld=0;
|
|
|
|
if ( DeltaType == SecurityDbDelete ) {
|
|
|
|
dwPrivLowHeld = 0;
|
|
dwPrivHighHeld = 0;
|
|
|
|
} else {
|
|
|
|
LSA_HANDLE lsaHandle=NULL;
|
|
|
|
NTSTATUS NtStatus = ScepOpenLsaPolicy(
|
|
POLICY_VIEW_LOCAL_INFORMATION |
|
|
POLICY_LOOKUP_NAMES,
|
|
&lsaHandle,
|
|
TRUE
|
|
);
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
NtStatus = ScepGetAccountExplicitRight(
|
|
lsaHandle,
|
|
ObjectSid,
|
|
&dwPrivLowHeld,
|
|
&dwPrivHighHeld
|
|
);
|
|
LsaClose( lsaHandle );
|
|
}
|
|
}
|
|
|
|
PWSTR SidString=NULL;
|
|
|
|
if ( ConvertSidToStringSid(ObjectSid,
|
|
&SidString
|
|
) &&
|
|
SidString ) {
|
|
|
|
TCHAR tmpBuf[40];
|
|
swprintf(tmpBuf, L"%d %d %d\0", (DWORD)DeltaType, dwPrivLowHeld, dwPrivHighHeld);
|
|
|
|
if ( !WritePrivateProfileString(L"Accounts",
|
|
SidString,
|
|
tmpBuf,
|
|
TemplateName
|
|
) ) {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
LocalFree(SidString);
|
|
|
|
} else {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepNotifyUpdateGPOVersion(
|
|
IN PWSTR GpoTemplateName,
|
|
IN BOOL bDomainPolicy
|
|
)
|
|
/*
|
|
Update the version # (in DS and gpt.ini) for machine policy change
|
|
property gPCMachineExtensionNames is not changed because security extension
|
|
guid should already be there (by default).
|
|
|
|
*/
|
|
{
|
|
if ( GpoTemplateName == NULL ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
DWORD rc=ERROR_SUCCESS;
|
|
DWORD dwVersion = 0;
|
|
|
|
//
|
|
// check gpt.ini existance
|
|
//
|
|
// build full path of gpt.ini first
|
|
//
|
|
PWSTR pTemp = wcsstr( GpoTemplateName, L"\\Machine\\");
|
|
|
|
if ( pTemp == NULL ) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
PWSTR pszVersionFile = (PWSTR)LocalAlloc(0, (pTemp-GpoTemplateName+wcslen(TEXT("\\gpt.ini"))+1)*sizeof(WCHAR));
|
|
|
|
if ( pszVersionFile == NULL ) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
wcsncpy(pszVersionFile, GpoTemplateName, (size_t)(pTemp-GpoTemplateName));
|
|
pszVersionFile[pTemp-GpoTemplateName] = L'\0';
|
|
|
|
wcscat(pszVersionFile, TEXT("\\gpt.ini"));
|
|
|
|
/*
|
|
DWORD dwVersion = GetPrivateProfileInt(TEXT("General"), TEXT("Version"), 0, pszVersionFile);
|
|
|
|
if ( dwVersion == 0 ) {
|
|
//
|
|
// couldn't find version #, this is bad
|
|
//
|
|
rc = ERROR_FILE_NOT_FOUND;
|
|
|
|
}
|
|
*/
|
|
|
|
|
|
DWORD dwFileAttributes = GetFileAttributes(pszVersionFile);
|
|
|
|
if(INVALID_FILE_ATTRIBUTES == dwFileAttributes){
|
|
|
|
rc = GetLastError();
|
|
|
|
} else {
|
|
|
|
//
|
|
// bind to DS, get DS root
|
|
//
|
|
|
|
PLDAP phLdap = ldap_open(NULL, LDAP_PORT);
|
|
|
|
if ( phLdap == NULL ) {
|
|
|
|
rc = ERROR_FILE_NOT_FOUND;
|
|
|
|
} else {
|
|
rc = ldap_bind_s(phLdap,
|
|
NULL,
|
|
NULL,
|
|
LDAP_AUTH_SSPI);
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
|
|
LDAPMessage *Message = NULL; // for LDAP calls.
|
|
PWSTR Attribs[3]; // for LDAP calls.
|
|
LDAPMessage *Entry = NULL;
|
|
PWSTR DsRootName=NULL;
|
|
|
|
Attribs[0] = LDAP_OPATT_DEFAULT_NAMING_CONTEXT_W; // ntldap.h
|
|
Attribs[1] = NULL;
|
|
Attribs[2] = NULL;
|
|
|
|
rc = ldap_search_s(phLdap,
|
|
L"",
|
|
LDAP_SCOPE_BASE,
|
|
L"(objectClass=*)",
|
|
Attribs,
|
|
0,
|
|
&Message);
|
|
|
|
if( rc == ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// read the first entry.
|
|
// we did base level search, we have only one entry.
|
|
// Entry does not need to be freed (it is freed with the message)
|
|
//
|
|
Entry = ldap_first_entry(phLdap, Message);
|
|
if(Entry != NULL) {
|
|
|
|
PWSTR *Values = ldap_get_values(phLdap, Entry, Attribs[0]);
|
|
|
|
if(Values != NULL) {
|
|
|
|
DsRootName = (PWSTR)LocalAlloc(0, (wcslen(Values[0])+1)*sizeof(WCHAR));
|
|
|
|
if ( DsRootName ) {
|
|
wcscpy(DsRootName, Values[0]);
|
|
} else {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
ldap_value_free(Values);
|
|
} else
|
|
rc = LdapMapErrorToWin32(phLdap->ld_errno);
|
|
|
|
} else
|
|
rc = LdapMapErrorToWin32(phLdap->ld_errno);
|
|
|
|
Entry = NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// ldap_search can return failure and still allocate the buffer
|
|
//
|
|
if ( Message ) {
|
|
ldap_msgfree(Message);
|
|
Message = NULL;
|
|
}
|
|
|
|
if ( DsRootName ) {
|
|
//
|
|
// query version from DS, if failed, query version from gpt.ini
|
|
//
|
|
Attribs[0] = L"distinguishedName";
|
|
Attribs[1] = L"versionNumber";
|
|
Attribs[2] = NULL;
|
|
|
|
|
|
WCHAR szFilter[128];
|
|
|
|
if ( bDomainPolicy ) {
|
|
swprintf(szFilter, L"( &(objectClass=groupPolicyContainer)(cn={%s}) )", STR_DEFAULT_DOMAIN_GPO_GUID);
|
|
} else {
|
|
swprintf(szFilter, L"( &(objectClass=groupPolicyContainer)(cn={%s}) )", STR_DEFAULT_DOMAIN_CONTROLLER_GPO_GUID);
|
|
}
|
|
|
|
phLdap->ld_options = 0; // no chased referrel
|
|
|
|
rc = ldap_search_s(
|
|
phLdap,
|
|
DsRootName,
|
|
LDAP_SCOPE_SUBTREE,
|
|
szFilter,
|
|
Attribs,
|
|
0,
|
|
&Message);
|
|
|
|
if( rc == ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// read the first entry.
|
|
// we did base level search, we have only one entry.
|
|
// Entry does not need to be freed (it is freed with the message)
|
|
//
|
|
Entry = ldap_first_entry(phLdap, Message);
|
|
if(Entry != NULL) {
|
|
|
|
PWSTR *Values = ldap_get_values(phLdap, Entry, Attribs[0]);
|
|
|
|
if(Values != NULL) {
|
|
if ( Values[0] == NULL ) {
|
|
//
|
|
// unknown error.
|
|
//
|
|
rc = ERROR_FILE_NOT_FOUND;
|
|
} else {
|
|
|
|
PWSTR *pszVersions = ldap_get_values(phLdap, Entry, Attribs[1]);
|
|
|
|
if ( pszVersions && pszVersions[0] ) {
|
|
//
|
|
// this is the version number
|
|
//
|
|
dwVersion = _wtol(pszVersions[0]);
|
|
}
|
|
|
|
if ( pszVersions ) {
|
|
ldap_value_free(pszVersions);
|
|
}
|
|
|
|
//
|
|
// Value[0] is the base GPO name,
|
|
// now modify the version #
|
|
//
|
|
|
|
PLDAPMod rgMods[2];
|
|
LDAPMod Mod;
|
|
PWSTR rgpszVals[2];
|
|
WCHAR szVal[32];
|
|
USHORT uMachine, uUser;
|
|
|
|
//
|
|
// split the version # for machine and user
|
|
//
|
|
uUser = (USHORT) HIWORD(dwVersion);
|
|
uMachine = (USHORT) LOWORD(dwVersion);
|
|
|
|
//
|
|
// increament version number and skip zero
|
|
// when it overflows and go to one.
|
|
// because zero is treated specially by
|
|
// the group policy engine and will lead
|
|
// to skip the GPO processing
|
|
//
|
|
|
|
uMachine++;
|
|
if(0 == uMachine)
|
|
uMachine++;
|
|
|
|
dwVersion = (ULONG) MAKELONG (uMachine, uUser);
|
|
|
|
rgMods[0] = &Mod;
|
|
rgMods[1] = NULL;
|
|
|
|
memset(szVal, '\0', 32*2);
|
|
swprintf(szVal, L"%d", dwVersion);
|
|
|
|
rgpszVals[0] = szVal;
|
|
rgpszVals[1] = NULL;
|
|
|
|
//
|
|
// lets set version number back
|
|
//
|
|
Mod.mod_op = LDAP_MOD_REPLACE;
|
|
Mod.mod_values = rgpszVals;
|
|
Mod.mod_type = L"versionNumber";
|
|
|
|
//
|
|
// Now, we'll do the write
|
|
//
|
|
rc = ldap_modify_s(phLdap,
|
|
Values[0],
|
|
rgMods
|
|
);
|
|
|
|
if ( rc == ERROR_ALREADY_EXISTS )
|
|
rc = ERROR_SUCCESS;
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
//
|
|
// update version in gpt.ini
|
|
//
|
|
WritePrivateProfileString (TEXT("General"), TEXT("Version"), szVal, pszVersionFile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ldap_value_free(Values);
|
|
|
|
} else
|
|
rc = LdapMapErrorToWin32(phLdap->ld_errno);
|
|
} else
|
|
rc = LdapMapErrorToWin32(phLdap->ld_errno);
|
|
|
|
}
|
|
|
|
LocalFree(DsRootName);
|
|
|
|
//
|
|
// ldap_search can return failure and still allocate the buffer
|
|
//
|
|
if ( Message ) {
|
|
ldap_msgfree(Message);
|
|
Message = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
ldap_unbind(phLdap);
|
|
}
|
|
}
|
|
|
|
LocalFree(pszVersionFile);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|