5499 lines
132 KiB
C++
5499 lines
132 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
common.cpp
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Shared APIs
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jin Huang
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
jinhuang 23-Jan-1998 merged from multiple modules
|
|||
|
|
|||
|
--*/
|
|||
|
#include "headers.h"
|
|||
|
#include <alloca.h>
|
|||
|
|
|||
|
#if DBG
|
|||
|
|
|||
|
DEFINE_DEBUG2(Sce);
|
|||
|
|
|||
|
DEBUG_KEY SceDebugKeys[] = {{DEB_ERROR, "Error"},
|
|||
|
{DEB_WARN, "Warn"},
|
|||
|
{DEB_TRACE, "Trace"},
|
|||
|
{0, NULL}};
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DebugInitialize()
|
|||
|
{
|
|||
|
SceInitDebug(SceDebugKeys);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
DebugUninit()
|
|||
|
{
|
|||
|
SceUnloadDebug();
|
|||
|
}
|
|||
|
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
HINSTANCE MyModuleHandle=NULL;
|
|||
|
HANDLE hEventLog = NULL;
|
|||
|
TCHAR EventSource[64];
|
|||
|
const TCHAR c_szCRLF[] = TEXT("\r\n");
|
|||
|
|
|||
|
#define RIGHT_DS_CREATE_CHILD ACTRL_DS_CREATE_CHILD
|
|||
|
#define RIGHT_DS_DELETE_CHILD ACTRL_DS_DELETE_CHILD
|
|||
|
#define RIGHT_DS_DELETE_SELF DELETE
|
|||
|
#define RIGHT_DS_LIST_CONTENTS ACTRL_DS_LIST
|
|||
|
#define RIGHT_DS_SELF_WRITE ACTRL_DS_SELF
|
|||
|
#define RIGHT_DS_READ_PROPERTY ACTRL_DS_READ_PROP
|
|||
|
#define RIGHT_DS_WRITE_PROPERTY ACTRL_DS_WRITE_PROP
|
|||
|
|
|||
|
//
|
|||
|
// defines for DSDIT, DSLOG, SYSVOL registry path
|
|||
|
//
|
|||
|
#define szNetlogonKey TEXT("System\\CurrentControlSet\\Services\\Netlogon\\Parameters")
|
|||
|
#define szNTDSKey TEXT("System\\CurrentControlSet\\Services\\NTDS\\Parameters")
|
|||
|
#define szSetupKey TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Setup")
|
|||
|
#define szSysvolValue TEXT("SysVol")
|
|||
|
#define szDSDITValue TEXT("DSA Working Directory")
|
|||
|
#define szDSLOGValue TEXT("Database log files path")
|
|||
|
#define szBootDriveValue TEXT("BootDir")
|
|||
|
|
|||
|
//
|
|||
|
// Define the generic rights
|
|||
|
//
|
|||
|
|
|||
|
// generic read
|
|||
|
#define GENERIC_READ_MAPPING ((STANDARD_RIGHTS_READ) | \
|
|||
|
(ACTRL_DS_LIST) | \
|
|||
|
(ACTRL_DS_READ_PROP))
|
|||
|
|
|||
|
// generic execute
|
|||
|
#define GENERIC_EXECUTE_MAPPING ((STANDARD_RIGHTS_EXECUTE) | \
|
|||
|
(ACTRL_DS_LIST))
|
|||
|
// generic right
|
|||
|
#define GENERIC_WRITE_MAPPING ((STANDARD_RIGHTS_WRITE) | \
|
|||
|
(ACTRL_DS_SELF) | \
|
|||
|
(ACTRL_DS_WRITE_PROP))
|
|||
|
// generic all
|
|||
|
|
|||
|
#define GENERIC_ALL_MAPPING ((STANDARD_RIGHTS_REQUIRED) | \
|
|||
|
(ACTRL_DS_CREATE_CHILD) | \
|
|||
|
(ACTRL_DS_DELETE_CHILD) | \
|
|||
|
(ACTRL_DS_READ_PROP) | \
|
|||
|
(ACTRL_DS_WRITE_PROP) | \
|
|||
|
(ACTRL_DS_LIST) | \
|
|||
|
(ACTRL_DS_SELF))
|
|||
|
|
|||
|
GENERIC_MAPPING DsGenMap = {
|
|||
|
GENERIC_READ_MAPPING,
|
|||
|
GENERIC_WRITE_MAPPING,
|
|||
|
GENERIC_EXECUTE_MAPPING,
|
|||
|
GENERIC_ALL_MAPPING
|
|||
|
};
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepCompareExplicitAcl(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN PACL pAcl1,
|
|||
|
IN PACL pAcl2,
|
|||
|
OUT PBOOL pDifferent
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ScepAnyExplicitAcl(
|
|||
|
IN PACL Acl,
|
|||
|
IN DWORD Processed,
|
|||
|
OUT PBOOL pExist
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
ScepEqualAce(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN ACE_HEADER *pAce1,
|
|||
|
IN ACE_HEADER *pAce2
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepGetCurrentUserProfilePath(
|
|||
|
OUT PWSTR *ProfilePath
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepGetUsersProfileName(
|
|||
|
IN UNICODE_STRING AssignedProfile,
|
|||
|
IN PSID AccountSid,
|
|||
|
IN BOOL bDefault,
|
|||
|
OUT PWSTR *UserProfilePath
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
ScepConvertSDDLAceType(
|
|||
|
LPTSTR pszValue,
|
|||
|
PCWSTR szSearchFor, // only two letters are allowed
|
|||
|
PCWSTR szReplace
|
|||
|
);
|
|||
|
BOOL
|
|||
|
ScepConvertSDDLSid(
|
|||
|
LPTSTR pszValue,
|
|||
|
PCWSTR szSearchFor, // only two letters are allowed
|
|||
|
PCWSTR szReplace
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ScepConvertAclBlobToAdl(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN PACL pAcl,
|
|||
|
OUT DWORD *pdwAceNumber,
|
|||
|
OUT BOOL *pbAclNoExplicitAces,
|
|||
|
OUT PSCEP_ADL_NODE *hTable
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepAdlLookupAdd(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN ACE_HEADER *pAce,
|
|||
|
OUT PSCEP_ADL_NODE *hTable
|
|||
|
);
|
|||
|
|
|||
|
PSCEP_ADL_NODE
|
|||
|
ScepAdlLookup(
|
|||
|
IN ACE_HEADER *pAce,
|
|||
|
IN PSCEP_ADL_NODE *hTable
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepAddToAdlList(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN ACE_HEADER *pAce,
|
|||
|
OUT PSCEP_ADL_NODE *pAdlList
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
ScepAdlMergeMasks(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN ACE_HEADER *pAce,
|
|||
|
IN PSCEP_ADL_NODE pNode
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
ScepEqualAdls(
|
|||
|
IN PSCEP_ADL_NODE *hTable1,
|
|||
|
IN PSCEP_ADL_NODE *hTable2
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
ScepFreeAdl(
|
|||
|
IN PSCEP_ADL_NODE *hTable
|
|||
|
);
|
|||
|
|
|||
|
SCESTATUS
|
|||
|
ScepFreeAdlList(
|
|||
|
IN PSCEP_ADL_NODE pAdlList
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
ScepEqualSid(
|
|||
|
IN PISID pSid1,
|
|||
|
IN PISID pSid2
|
|||
|
);
|
|||
|
|
|||
|
PWSTR
|
|||
|
ScepMultiSzWcsstr(
|
|||
|
PWSTR pszStringToSearchIn,
|
|||
|
PWSTR pszStringToSearchFor
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// function definitions
|
|||
|
//
|
|||
|
|
|||
|
SCESTATUS
|
|||
|
WINAPI
|
|||
|
SceSvcpGetInformationTemplate(
|
|||
|
IN HINF hInf,
|
|||
|
IN PCWSTR ServiceName,
|
|||
|
IN PCWSTR Key OPTIONAL,
|
|||
|
OUT PSCESVC_CONFIGURATION_INFO *ServiceInfo
|
|||
|
)
|
|||
|
{
|
|||
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|||
|
|
|||
|
if ( hInf == NULL || hInf == INVALID_HANDLE_VALUE ||
|
|||
|
ServiceName == NULL || ServiceInfo == NULL ) {
|
|||
|
|
|||
|
return(SCESTATUS_INVALID_PARAMETER);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
LONG nCount=0;
|
|||
|
|
|||
|
if ( Key == NULL ) {
|
|||
|
//
|
|||
|
// get the entire section count
|
|||
|
//
|
|||
|
nCount = SetupGetLineCount(hInf, ServiceName);
|
|||
|
|
|||
|
if ( nCount <= 0 ) {
|
|||
|
//
|
|||
|
// the section is not there, or nothing in the section
|
|||
|
//
|
|||
|
rc =SCESTATUS_RECORD_NOT_FOUND;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
nCount = 1;
|
|||
|
}
|
|||
|
|
|||
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|||
|
|
|||
|
//
|
|||
|
// allocate buffer for the section
|
|||
|
//
|
|||
|
*ServiceInfo = (PSCESVC_CONFIGURATION_INFO)ScepAlloc(LMEM_FIXED,
|
|||
|
sizeof(SCESVC_CONFIGURATION_INFO));
|
|||
|
|
|||
|
if ( *ServiceInfo == NULL ) {
|
|||
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
(*ServiceInfo)->Lines =
|
|||
|
(PSCESVC_CONFIGURATION_LINE)ScepAlloc(LMEM_ZEROINIT,
|
|||
|
nCount*sizeof(SCESVC_CONFIGURATION_LINE));
|
|||
|
|
|||
|
if ( (*ServiceInfo)->Lines == NULL ) {
|
|||
|
|
|||
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|||
|
ScepFree(*ServiceInfo);
|
|||
|
*ServiceInfo = NULL;
|
|||
|
|
|||
|
} else {
|
|||
|
(*ServiceInfo)->Count = nCount;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|||
|
|
|||
|
//
|
|||
|
// get each line in the section, nor a single key now
|
|||
|
//
|
|||
|
INFCONTEXT InfLine;
|
|||
|
DWORD LineLen, Len, KeyLen, DataSize;
|
|||
|
DWORD i, cFields;
|
|||
|
DWORD LineCount=0;
|
|||
|
PWSTR Keyname=NULL, Strvalue=NULL;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// look for the first line in the Servi ceName section
|
|||
|
//
|
|||
|
if(SetupFindFirstLine(hInf,ServiceName,NULL,&InfLine)) {
|
|||
|
|
|||
|
do {
|
|||
|
//
|
|||
|
// read each line in the section and append to the end of the buffer
|
|||
|
// note: the required size returned from SetupGetStringField already
|
|||
|
// has one more character space.
|
|||
|
//
|
|||
|
rc = SCESTATUS_INVALID_DATA;
|
|||
|
|
|||
|
if ( SetupGetStringField(&InfLine, 0, NULL, 0, &KeyLen) ) {
|
|||
|
|
|||
|
Keyname = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (KeyLen+1)*sizeof(WCHAR));
|
|||
|
|
|||
|
if ( Keyname != NULL ) {
|
|||
|
|
|||
|
if ( SetupGetStringField(&InfLine, 0, Keyname, KeyLen, NULL) ) {
|
|||
|
|
|||
|
//
|
|||
|
// Got key name, compare with Key if specified.
|
|||
|
//
|
|||
|
if ( Key == NULL || _wcsicmp(Keyname, Key) == 0 ) {
|
|||
|
|
|||
|
cFields = SetupGetFieldCount( &InfLine );
|
|||
|
LineLen = 0;
|
|||
|
Len = 0;
|
|||
|
|
|||
|
rc = SCESTATUS_SUCCESS;
|
|||
|
//
|
|||
|
// count total number of characters for the value
|
|||
|
//
|
|||
|
for ( i=0; i<cFields; i++) {
|
|||
|
|
|||
|
if( SetupGetStringField(&InfLine,i+1,NULL,0,&DataSize) ) {
|
|||
|
|
|||
|
LineLen += (DataSize + 1);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
rc = SCESTATUS_INVALID_DATA;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|||
|
|
|||
|
Strvalue = (PWSTR)ScepAlloc( LMEM_ZEROINIT,
|
|||
|
(LineLen+1)*sizeof(WCHAR) );
|
|||
|
|
|||
|
if( Strvalue != NULL ) {
|
|||
|
|
|||
|
for ( i=0; i<cFields; i++) {
|
|||
|
|
|||
|
if ( !SetupGetStringField(&InfLine, i+1,
|
|||
|
Strvalue+Len, LineLen-Len, &DataSize) ) {
|
|||
|
|
|||
|
rc = SCESTATUS_INVALID_DATA;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if ( i == cFields-1)
|
|||
|
*(Strvalue+Len+DataSize-1) = L'\0';
|
|||
|
else
|
|||
|
*(Strvalue+Len+DataSize-1) = L',';
|
|||
|
Len += DataSize;
|
|||
|
}
|
|||
|
|
|||
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|||
|
//
|
|||
|
// everything is successful
|
|||
|
//
|
|||
|
(*ServiceInfo)->Lines[LineCount].Key = Keyname;
|
|||
|
(*ServiceInfo)->Lines[LineCount].Value = Strvalue;
|
|||
|
(*ServiceInfo)->Lines[LineCount].ValueLen = LineLen*sizeof(WCHAR);
|
|||
|
|
|||
|
Keyname = NULL;
|
|||
|
Strvalue = NULL;
|
|||
|
rc = SCESTATUS_SUCCESS;
|
|||
|
|
|||
|
LineCount++;
|
|||
|
|
|||
|
if ( Key != NULL ) {
|
|||
|
break; // break the do while loop because the exact match for the key is found
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
ScepFree( Strvalue );
|
|||
|
Strvalue = NULL;
|
|||
|
}
|
|||
|
|
|||
|
} else
|
|||
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// did not find the right key, go to next line
|
|||
|
//
|
|||
|
rc = SCESTATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( Keyname != NULL ) {
|
|||
|
ScepFree(Keyname);
|
|||
|
Keyname = NULL;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( rc != SCESTATUS_SUCCESS ) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
} while ( SetupFindNextLine(&InfLine,&InfLine) );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
rc = SCESTATUS_RECORD_NOT_FOUND;
|
|||
|
}
|
|||
|
//
|
|||
|
// if no exact match for the key is found, return the error code
|
|||
|
//
|
|||
|
if ( rc == SCESTATUS_SUCCESS && Key != NULL && LineCount == 0 ) {
|
|||
|
rc = SCESTATUS_RECORD_NOT_FOUND;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( rc != SCESTATUS_SUCCESS && *ServiceInfo != NULL ) {
|
|||
|
//
|
|||
|
// free ServiceInfo
|
|||
|
//
|
|||
|
PSCESVC_CONFIGURATION_LINE Lines;
|
|||
|
|
|||
|
Lines = ((PSCESVC_CONFIGURATION_INFO)(*ServiceInfo))->Lines;
|
|||
|
|
|||
|
for ( DWORD i=0; i<((PSCESVC_CONFIGURATION_INFO)(*ServiceInfo))->Count; i++) {
|
|||
|
|
|||
|
if ( Lines[i].Key != NULL ) {
|
|||
|
ScepFree(Lines[i].Key);
|
|||
|
}
|
|||
|
|
|||
|
if ( Lines[i].Value != NULL ) {
|
|||
|
ScepFree(Lines[i].Value);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ScepFree(Lines);
|
|||
|
ScepFree(*ServiceInfo);
|
|||
|
*ServiceInfo = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return(rc);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepAddToNameList(
|
|||
|
OUT PSCE_NAME_LIST *pNameList,
|
|||
|
IN PWSTR Name,
|
|||
|
IN ULONG Len
|
|||
|
)
|
|||
|
/* ++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine adds a name (wchar) to the name list. The new added
|
|||
|
node is always placed as the head of the list for performance reason.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pNameList - The address of the name list to add to.
|
|||
|
|
|||
|
Name - The name to add
|
|||
|
|
|||
|
Len - number of wchars in Name
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
Win32 error code
|
|||
|
-- */
|
|||
|
{
|
|||
|
|
|||
|
PSCE_NAME_LIST pList=NULL;
|
|||
|
ULONG Length=Len;
|
|||
|
|
|||
|
//
|
|||
|
// check arguments
|
|||
|
//
|
|||
|
if ( pNameList == NULL )
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
|
|||
|
if ( Name == NULL )
|
|||
|
return(NO_ERROR);
|
|||
|
|
|||
|
if ( Len == 0 )
|
|||
|
Length = wcslen(Name);
|
|||
|
|
|||
|
if ( Length == 0 )
|
|||
|
return(NO_ERROR);
|
|||
|
|
|||
|
//
|
|||
|
// allocate a new node
|
|||
|
//
|
|||
|
pList = (PSCE_NAME_LIST)ScepAlloc( (UINT)0, sizeof(SCE_NAME_LIST));
|
|||
|
|
|||
|
if ( pList == NULL )
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
|
|||
|
pList->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (Length+1)*sizeof(TCHAR));
|
|||
|
if ( pList->Name == NULL ) {
|
|||
|
ScepFree(pList);
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// add the node to the front of the list and link its next to the old list
|
|||
|
//
|
|||
|
wcsncpy(pList->Name, Name, Length);
|
|||
|
pList->Next = *pNameList;
|
|||
|
*pNameList = pList;
|
|||
|
|
|||
|
return(NO_ERROR);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
SCESTATUS
|
|||
|
ScepBuildErrorLogInfo(
|
|||
|
IN DWORD rc,
|
|||
|
OUT PSCE_ERROR_LOG_INFO *errlog,
|
|||
|
IN UINT nId,
|
|||
|
// IN PCWSTR fmt,
|
|||
|
...
|
|||
|
)
|
|||
|
/* ++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine add the error information to the end of error log info list
|
|||
|
(errlog). The error information is stored in SCE_ERROR_LOG_INFO structure.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
rc - Win32 error code
|
|||
|
|
|||
|
errlog - the error log info list head
|
|||
|
|
|||
|
fmt - a format string
|
|||
|
|
|||
|
... - variable arguments
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
SCESTATUS error code
|
|||
|
|
|||
|
-- */
|
|||
|
{
|
|||
|
PSCE_ERROR_LOG_INFO pNode;
|
|||
|
PSCE_ERROR_LOG_INFO pErr;
|
|||
|
DWORD bufferSize;
|
|||
|
PWSTR buf=NULL;
|
|||
|
va_list args;
|
|||
|
WCHAR szTempString[256];
|
|||
|
|
|||
|
//
|
|||
|
// check arguments
|
|||
|
//
|
|||
|
// if ( errlog == NULL || fmt == NULL )
|
|||
|
if ( errlog == NULL || nId == 0 )
|
|||
|
return(SCESTATUS_SUCCESS);
|
|||
|
|
|||
|
szTempString[0] = L'\0';
|
|||
|
|
|||
|
LoadString( MyModuleHandle,
|
|||
|
nId,
|
|||
|
szTempString,
|
|||
|
256
|
|||
|
);
|
|||
|
if ( szTempString[0] == L'\0' )
|
|||
|
return(SCESTATUS_SUCCESS);
|
|||
|
|
|||
|
SafeAllocaAllocate( buf, SCE_BUF_LEN*sizeof(WCHAR) );
|
|||
|
|
|||
|
if ( buf == NULL ) {
|
|||
|
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
|
|||
|
}
|
|||
|
|
|||
|
va_start( args, nId );
|
|||
|
vswprintf( buf, szTempString, args );
|
|||
|
va_end( args );
|
|||
|
|
|||
|
bufferSize = wcslen(buf);
|
|||
|
|
|||
|
//
|
|||
|
// no error information to be stored. return
|
|||
|
//
|
|||
|
|
|||
|
SCESTATUS rCode=SCESTATUS_SUCCESS;
|
|||
|
|
|||
|
if ( bufferSize != 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// allocate memory and store error information in pNode->buffer
|
|||
|
//
|
|||
|
|
|||
|
pNode = (PSCE_ERROR_LOG_INFO)ScepAlloc( 0, sizeof(SCE_ERROR_LOG_INFO) );
|
|||
|
|
|||
|
if ( pNode != NULL ) {
|
|||
|
|
|||
|
pNode->buffer = (LPTSTR)ScepAlloc( 0, (bufferSize+1)*sizeof(TCHAR) );
|
|||
|
if ( pNode->buffer != NULL ) {
|
|||
|
|
|||
|
//
|
|||
|
// Error information is in "SystemMessage : Caller'sMessage" format
|
|||
|
//
|
|||
|
pNode->buffer[0] = L'\0';
|
|||
|
|
|||
|
wcscpy(pNode->buffer, buf);
|
|||
|
|
|||
|
pNode->rc = rc;
|
|||
|
pNode->next = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// link it to the list
|
|||
|
//
|
|||
|
if ( *errlog == NULL )
|
|||
|
|
|||
|
//
|
|||
|
// This is the first node in the error log information list
|
|||
|
//
|
|||
|
|
|||
|
*errlog = pNode;
|
|||
|
|
|||
|
else {
|
|||
|
|
|||
|
//
|
|||
|
// find the last node in the list
|
|||
|
//
|
|||
|
|
|||
|
for ( pErr=*errlog; pErr->next; pErr = pErr->next );
|
|||
|
pErr->next = pNode;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
ScepFree(pNode);
|
|||
|
rCode = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
rCode = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
SafeAllocaFree( buf );
|
|||
|
|
|||
|
return(rc);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepRegQueryIntValue(
|
|||
|
IN HKEY hKeyRoot,
|
|||
|
IN PWSTR SubKey,
|
|||
|
IN PWSTR ValueName,
|
|||
|
OUT DWORD *Value
|
|||
|
)
|
|||
|
/* ++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine queries a REG_DWORD value from a value name/subkey.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKeyRoot - root
|
|||
|
|
|||
|
SubKey - key path
|
|||
|
|
|||
|
ValueName - name of the value
|
|||
|
|
|||
|
Value - the output value for the ValueName
|
|||
|
|
|||
|
Return values:
|
|||
|
|
|||
|
Win32 error code
|
|||
|
-- */
|
|||
|
{
|
|||
|
DWORD Rcode;
|
|||
|
DWORD RegType;
|
|||
|
DWORD dSize=0;
|
|||
|
HKEY hKey=NULL;
|
|||
|
|
|||
|
if(( Rcode = RegOpenKeyEx(hKeyRoot,
|
|||
|
SubKey,
|
|||
|
0,
|
|||
|
KEY_READ,
|
|||
|
&hKey
|
|||
|
)) == ERROR_SUCCESS ) {
|
|||
|
|
|||
|
if(( Rcode = RegQueryValueEx(hKey,
|
|||
|
ValueName,
|
|||
|
0,
|
|||
|
&RegType,
|
|||
|
NULL,
|
|||
|
&dSize
|
|||
|
)) == ERROR_SUCCESS ) {
|
|||
|
switch (RegType) {
|
|||
|
case REG_DWORD:
|
|||
|
case REG_DWORD_BIG_ENDIAN:
|
|||
|
|
|||
|
Rcode = RegQueryValueEx(hKey,
|
|||
|
ValueName,
|
|||
|
0,
|
|||
|
&RegType,
|
|||
|
(BYTE *)Value,
|
|||
|
&dSize
|
|||
|
);
|
|||
|
if ( Rcode != ERROR_SUCCESS ) {
|
|||
|
|
|||
|
if ( Value != NULL )
|
|||
|
*Value = 0;
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
Rcode = ERROR_INVALID_DATATYPE;
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if( hKey )
|
|||
|
RegCloseKey( hKey );
|
|||
|
|
|||
|
return(Rcode);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepRegSetIntValue(
|
|||
|
IN HKEY hKeyRoot,
|
|||
|
IN PWSTR SubKey,
|
|||
|
IN PWSTR ValueName,
|
|||
|
IN DWORD Value
|
|||
|
)
|
|||
|
/* ++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sets a REG_DWORD value to a value name/subkey.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKeyRoot - root
|
|||
|
|
|||
|
SubKey - key path
|
|||
|
|
|||
|
ValueName - name of the value
|
|||
|
|
|||
|
Value - the value to set
|
|||
|
|
|||
|
Return values:
|
|||
|
|
|||
|
Win32 error code
|
|||
|
-- */
|
|||
|
{
|
|||
|
DWORD Rcode;
|
|||
|
HKEY hKey=NULL;
|
|||
|
|
|||
|
if(( Rcode = RegOpenKeyEx(hKeyRoot,
|
|||
|
SubKey,
|
|||
|
0,
|
|||
|
KEY_SET_VALUE,
|
|||
|
&hKey
|
|||
|
)) == ERROR_SUCCESS ) {
|
|||
|
|
|||
|
Rcode = RegSetValueEx( hKey,
|
|||
|
ValueName,
|
|||
|
0,
|
|||
|
REG_DWORD,
|
|||
|
(BYTE *)&Value,
|
|||
|
4
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if( hKey )
|
|||
|
RegCloseKey( hKey );
|
|||
|
|
|||
|
return(Rcode);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepRegQueryBinaryValue(
|
|||
|
IN HKEY hKeyRoot,
|
|||
|
IN PWSTR SubKey,
|
|||
|
IN PWSTR ValueName,
|
|||
|
OUT PBYTE *ppValue
|
|||
|
)
|
|||
|
/* ++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine queries a REG_BINARY value from a value name/subkey.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKeyRoot - root
|
|||
|
|
|||
|
SubKey - key path
|
|||
|
|
|||
|
ValueName - name of the value
|
|||
|
|
|||
|
Value - the output value for the ValueName
|
|||
|
|
|||
|
Return values:
|
|||
|
|
|||
|
Win32 error code
|
|||
|
-- */
|
|||
|
{
|
|||
|
DWORD Rcode;
|
|||
|
DWORD RegType;
|
|||
|
DWORD dSize=0;
|
|||
|
HKEY hKey=NULL;
|
|||
|
|
|||
|
if(( Rcode = RegOpenKeyEx(hKeyRoot,
|
|||
|
SubKey,
|
|||
|
0,
|
|||
|
KEY_READ,
|
|||
|
&hKey
|
|||
|
)) == ERROR_SUCCESS ) {
|
|||
|
|
|||
|
// get the size since it is free form binary
|
|||
|
if(( Rcode = RegQueryValueEx(hKey,
|
|||
|
ValueName,
|
|||
|
0,
|
|||
|
&RegType,
|
|||
|
NULL,
|
|||
|
&dSize
|
|||
|
)) == ERROR_SUCCESS ) {
|
|||
|
switch (RegType) {
|
|||
|
case REG_BINARY:
|
|||
|
|
|||
|
//need to free this outside
|
|||
|
if (ppValue)
|
|||
|
*ppValue = ( PBYTE )ScepAlloc( 0, sizeof(BYTE) * dSize);
|
|||
|
|
|||
|
Rcode = RegQueryValueEx(hKey,
|
|||
|
ValueName,
|
|||
|
0,
|
|||
|
&RegType,
|
|||
|
( PBYTE ) *ppValue,
|
|||
|
&dSize
|
|||
|
);
|
|||
|
if ( Rcode != ERROR_SUCCESS ) {
|
|||
|
|
|||
|
if ( *ppValue != NULL )
|
|||
|
**ppValue = (BYTE)0;
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
Rcode = ERROR_INVALID_DATATYPE;
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if( hKey )
|
|||
|
RegCloseKey( hKey );
|
|||
|
|
|||
|
return(Rcode);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepRegSetValue(
|
|||
|
IN HKEY hKeyRoot,
|
|||
|
IN PWSTR SubKey,
|
|||
|
IN PWSTR ValueName,
|
|||
|
IN DWORD RegType,
|
|||
|
IN BYTE *Value,
|
|||
|
IN DWORD ValueLen
|
|||
|
)
|
|||
|
/* ++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sets a string value to a value name/subkey.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKeyRoot - root
|
|||
|
|
|||
|
SubKey - key path
|
|||
|
|
|||
|
ValueName - name of the value
|
|||
|
|
|||
|
Value - the value to set
|
|||
|
|
|||
|
ValueLen - The number of bytes in Value
|
|||
|
|
|||
|
Return values:
|
|||
|
|
|||
|
Win32 error code
|
|||
|
-- */
|
|||
|
{
|
|||
|
DWORD Rcode;
|
|||
|
DWORD NewKey;
|
|||
|
HKEY hKey=NULL;
|
|||
|
SECURITY_ATTRIBUTES SecurityAttributes;
|
|||
|
PSECURITY_DESCRIPTOR SecurityDescriptor=NULL;
|
|||
|
|
|||
|
|
|||
|
if(( Rcode = RegOpenKeyEx(hKeyRoot,
|
|||
|
SubKey,
|
|||
|
0,
|
|||
|
KEY_SET_VALUE,
|
|||
|
&hKey
|
|||
|
)) != ERROR_SUCCESS ) {
|
|||
|
|
|||
|
SecurityAttributes.nLength = sizeof( SECURITY_ATTRIBUTES );
|
|||
|
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
|
|||
|
SecurityAttributes.bInheritHandle = FALSE;
|
|||
|
|
|||
|
Rcode = RegCreateKeyEx(
|
|||
|
hKeyRoot,
|
|||
|
SubKey,
|
|||
|
0,
|
|||
|
NULL, // LPTSTR lpClass,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_WRITE, // KEY_SET_VALUE,
|
|||
|
NULL, // &SecurityAttributes,
|
|||
|
&hKey,
|
|||
|
&NewKey
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if ( Rcode == ERROR_SUCCESS ) {
|
|||
|
|
|||
|
Rcode = RegSetValueEx( hKey,
|
|||
|
ValueName,
|
|||
|
0,
|
|||
|
RegType,
|
|||
|
Value,
|
|||
|
ValueLen
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if( hKey )
|
|||
|
RegCloseKey( hKey );
|
|||
|
|
|||
|
return(Rcode);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepRegQueryValue(
|
|||
|
IN HKEY hKeyRoot,
|
|||
|
IN PWSTR SubKey,
|
|||
|
IN PCWSTR ValueName,
|
|||
|
OUT PVOID *Value,
|
|||
|
OUT LPDWORD pRegType
|
|||
|
)
|
|||
|
/* ++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine queries a REG_SZ value from a value name/subkey.
|
|||
|
The output buffer is allocated if it is NULL. It must be freed
|
|||
|
by LocalFree
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKeyRoot - root
|
|||
|
|
|||
|
SubKey - key path
|
|||
|
|
|||
|
ValueName - name of the value
|
|||
|
|
|||
|
Value - the output string for the ValueName
|
|||
|
|
|||
|
Return values:
|
|||
|
|
|||
|
Win32 error code
|
|||
|
-- */
|
|||
|
{
|
|||
|
DWORD Rcode;
|
|||
|
DWORD dSize=0;
|
|||
|
HKEY hKey=NULL;
|
|||
|
BOOL FreeMem=FALSE;
|
|||
|
|
|||
|
if ( SubKey == NULL || ValueName == NULL ||
|
|||
|
Value == NULL || pRegType == NULL ) {
|
|||
|
return(SCESTATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
if(( Rcode = RegOpenKeyEx(hKeyRoot,
|
|||
|
SubKey,
|
|||
|
0,
|
|||
|
KEY_READ,
|
|||
|
&hKey
|
|||
|
)) == ERROR_SUCCESS ) {
|
|||
|
|
|||
|
if(( Rcode = RegQueryValueEx(hKey,
|
|||
|
ValueName,
|
|||
|
0,
|
|||
|
pRegType,
|
|||
|
NULL,
|
|||
|
&dSize
|
|||
|
)) == ERROR_SUCCESS ) {
|
|||
|
switch (*pRegType) {
|
|||
|
/*
|
|||
|
case REG_DWORD:
|
|||
|
case REG_DWORD_BIG_ENDIAN:
|
|||
|
|
|||
|
Rcode = RegQueryValueEx(hKey,
|
|||
|
ValueName,
|
|||
|
0,
|
|||
|
pRegType,
|
|||
|
(BYTE *)(*Value),
|
|||
|
&dSize
|
|||
|
);
|
|||
|
if ( Rcode != ERROR_SUCCESS ) {
|
|||
|
|
|||
|
if ( *Value != NULL )
|
|||
|
*((BYTE *)(*Value)) = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
*/
|
|||
|
case REG_SZ:
|
|||
|
case REG_EXPAND_SZ:
|
|||
|
case REG_MULTI_SZ:
|
|||
|
if ( *Value == NULL ) {
|
|||
|
*Value = (PVOID)ScepAlloc( LMEM_ZEROINIT, (dSize+1)*sizeof(TCHAR));
|
|||
|
FreeMem = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if ( *Value == NULL ) {
|
|||
|
Rcode = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
Rcode = RegQueryValueEx(hKey,
|
|||
|
ValueName,
|
|||
|
0,
|
|||
|
pRegType,
|
|||
|
(BYTE *)(*Value),
|
|||
|
&dSize
|
|||
|
);
|
|||
|
if ( Rcode != ERROR_SUCCESS && FreeMem ) {
|
|||
|
ScepFree(*Value);
|
|||
|
*Value = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
default:
|
|||
|
|
|||
|
Rcode = ERROR_INVALID_DATATYPE;
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if( hKey )
|
|||
|
RegCloseKey( hKey );
|
|||
|
|
|||
|
return(Rcode);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepRegDeleteValue(
|
|||
|
IN HKEY hKeyRoot,
|
|||
|
IN PWSTR SubKey,
|
|||
|
IN PWSTR ValueName
|
|||
|
)
|
|||
|
/* ++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine delete the reg value
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKeyRoot - root
|
|||
|
|
|||
|
SubKey - key path
|
|||
|
|
|||
|
ValueName - name of the value
|
|||
|
|
|||
|
|
|||
|
Return values:
|
|||
|
|
|||
|
Win32 error code
|
|||
|
-- */
|
|||
|
{
|
|||
|
DWORD Rcode;
|
|||
|
HKEY hKey=NULL;
|
|||
|
|
|||
|
if(( Rcode = RegOpenKeyEx(hKeyRoot,
|
|||
|
SubKey,
|
|||
|
0,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&hKey
|
|||
|
)) == ERROR_SUCCESS ) {
|
|||
|
|
|||
|
Rcode = RegDeleteValue(hKey, ValueName);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if( hKey )
|
|||
|
RegCloseKey( hKey );
|
|||
|
|
|||
|
return(Rcode);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
SCESTATUS
|
|||
|
ScepCreateDirectory(
|
|||
|
IN PCWSTR ProfileLocation,
|
|||
|
IN BOOL FileOrDir,
|
|||
|
PSECURITY_DESCRIPTOR pSecurityDescriptor OPTIONAL
|
|||
|
)
|
|||
|
/* ++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine creates directory(ies) as specified in the ProfileLocation.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ProfileLocation - The directory (full path) to create
|
|||
|
|
|||
|
FileOrDir - TRUE = Dir name, FALSE = file name
|
|||
|
|
|||
|
pSecurityDescriptor - The secrity descriptor for the directories to create.
|
|||
|
If it is NULL, then the parent directory's inherit
|
|||
|
security descriptor is used.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
SCESTATUS_SUCCESS
|
|||
|
SCESTATUS_INVALID_PARAMETER
|
|||
|
SCESTATUS_NOT_ENOUGH_RESOURCE
|
|||
|
SCESTATUS_OTHER_ERROR
|
|||
|
|
|||
|
-- */
|
|||
|
{
|
|||
|
PWSTR Buffer=NULL;
|
|||
|
PWSTR pTemp=NULL;
|
|||
|
DWORD Len=0;
|
|||
|
SCESTATUS rc;
|
|||
|
SECURITY_ATTRIBUTES sa;
|
|||
|
|
|||
|
|
|||
|
if ( ProfileLocation == NULL ) {
|
|||
|
return(SCESTATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
if ( wcsncmp(ProfileLocation,L"\\\\?\\",4) == 0 ) {
|
|||
|
|
|||
|
pTemp = (PWSTR)ProfileLocation+4;
|
|||
|
} else {
|
|||
|
pTemp = (PWSTR)ProfileLocation;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// skip the first '\\' for example, c:\winnt
|
|||
|
//
|
|||
|
pTemp = wcschr(pTemp, L'\\');
|
|||
|
if ( pTemp == NULL ) {
|
|||
|
if ( ProfileLocation[1] == L':' ) {
|
|||
|
return(SCESTATUS_SUCCESS);
|
|||
|
} else {
|
|||
|
return(SCESTATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
} else if ( *(pTemp+1) == L'\\' ) {
|
|||
|
//
|
|||
|
// there is a machine name here
|
|||
|
//
|
|||
|
pTemp = wcschr(pTemp+2, L'\\');
|
|||
|
if ( pTemp == NULL ) {
|
|||
|
//
|
|||
|
// just a machine name, invalid
|
|||
|
//
|
|||
|
return(SCESTATUS_INVALID_PARAMETER);
|
|||
|
} else {
|
|||
|
//
|
|||
|
// look for the share name end
|
|||
|
//
|
|||
|
pTemp = wcschr(pTemp+1, L'\\');
|
|||
|
|
|||
|
if ( pTemp == NULL ) {
|
|||
|
//
|
|||
|
// no directory is specified
|
|||
|
//
|
|||
|
return(SCESTATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Make a copy of the profile location
|
|||
|
//
|
|||
|
Buffer = (PWSTR)ScepAlloc( 0, (wcslen(ProfileLocation)+1)*sizeof(WCHAR));
|
|||
|
if ( Buffer == NULL ) {
|
|||
|
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
|
|||
|
}
|
|||
|
|
|||
|
wcscpy( Buffer, ProfileLocation );
|
|||
|
|
|||
|
//
|
|||
|
// Looping to find the next '\\'
|
|||
|
//
|
|||
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|||
|
sa.lpSecurityDescriptor = (LPVOID)pSecurityDescriptor;
|
|||
|
sa.bInheritHandle = FALSE;
|
|||
|
|
|||
|
do {
|
|||
|
pTemp = wcschr( pTemp+1, L'\\');
|
|||
|
if ( pTemp != NULL ) {
|
|||
|
Len = (DWORD)(pTemp - ProfileLocation);
|
|||
|
Buffer[Len] = L'\0';
|
|||
|
} else if ( FileOrDir )
|
|||
|
Len = 0; // dir name
|
|||
|
else
|
|||
|
break; // file name. DO NOT create directory for the file name part
|
|||
|
|
|||
|
//
|
|||
|
// should make a security descriptor and set
|
|||
|
//
|
|||
|
if ( CreateDirectory(
|
|||
|
Buffer,
|
|||
|
&sa
|
|||
|
) == FALSE ) {
|
|||
|
if ( GetLastError() != ERROR_ALREADY_EXISTS ) {
|
|||
|
rc = ScepDosErrorToSceStatus(GetLastError());
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( Len != 0 )
|
|||
|
Buffer[Len] = L'\\';
|
|||
|
|
|||
|
|
|||
|
} while ( pTemp != NULL );
|
|||
|
|
|||
|
rc = SCESTATUS_SUCCESS;
|
|||
|
|
|||
|
Done:
|
|||
|
|
|||
|
ScepFree(Buffer);
|
|||
|
|
|||
|
return(rc);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepSceStatusToDosError(
|
|||
|
IN SCESTATUS SceStatus
|
|||
|
)
|
|||
|
// converts SCESTATUS error code to dos error defined in winerror.h
|
|||
|
{
|
|||
|
switch(SceStatus) {
|
|||
|
|
|||
|
case SCESTATUS_SUCCESS:
|
|||
|
return(NO_ERROR);
|
|||
|
|
|||
|
case SCESTATUS_OTHER_ERROR:
|
|||
|
return(ERROR_EXTENDED_ERROR);
|
|||
|
|
|||
|
case SCESTATUS_INVALID_PARAMETER:
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
|
|||
|
case SCESTATUS_RECORD_NOT_FOUND:
|
|||
|
return(ERROR_NO_MORE_ITEMS);
|
|||
|
|
|||
|
case SCESTATUS_NO_MAPPING:
|
|||
|
return(ERROR_NONE_MAPPED);
|
|||
|
|
|||
|
case SCESTATUS_TRUST_FAIL:
|
|||
|
return(ERROR_TRUSTED_DOMAIN_FAILURE);
|
|||
|
|
|||
|
case SCESTATUS_INVALID_DATA:
|
|||
|
return(ERROR_INVALID_DATA);
|
|||
|
|
|||
|
case SCESTATUS_OBJECT_EXIST:
|
|||
|
return(ERROR_FILE_EXISTS);
|
|||
|
|
|||
|
case SCESTATUS_BUFFER_TOO_SMALL:
|
|||
|
return(ERROR_INSUFFICIENT_BUFFER);
|
|||
|
|
|||
|
case SCESTATUS_PROFILE_NOT_FOUND:
|
|||
|
return(ERROR_FILE_NOT_FOUND);
|
|||
|
|
|||
|
case SCESTATUS_BAD_FORMAT:
|
|||
|
return(ERROR_BAD_FORMAT);
|
|||
|
|
|||
|
case SCESTATUS_NOT_ENOUGH_RESOURCE:
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
|
|||
|
case SCESTATUS_ACCESS_DENIED:
|
|||
|
return(ERROR_ACCESS_DENIED);
|
|||
|
|
|||
|
case SCESTATUS_CANT_DELETE:
|
|||
|
return(ERROR_CURRENT_DIRECTORY);
|
|||
|
|
|||
|
case SCESTATUS_PREFIX_OVERFLOW:
|
|||
|
return(ERROR_BUFFER_OVERFLOW);
|
|||
|
|
|||
|
case SCESTATUS_ALREADY_RUNNING:
|
|||
|
return(ERROR_SERVICE_ALREADY_RUNNING);
|
|||
|
|
|||
|
case SCESTATUS_SERVICE_NOT_SUPPORT:
|
|||
|
return(ERROR_NOT_SUPPORTED);
|
|||
|
|
|||
|
case SCESTATUS_MOD_NOT_FOUND:
|
|||
|
return(ERROR_MOD_NOT_FOUND);
|
|||
|
|
|||
|
case SCESTATUS_EXCEPTION_IN_SERVER:
|
|||
|
return(ERROR_EXCEPTION_IN_SERVICE);
|
|||
|
|
|||
|
case SCESTATUS_JET_DATABASE_ERROR:
|
|||
|
return(ERROR_DATABASE_FAILURE);
|
|||
|
|
|||
|
case SCESTATUS_TIMEOUT:
|
|||
|
return(ERROR_TIMEOUT);
|
|||
|
|
|||
|
case SCESTATUS_PENDING_IGNORE:
|
|||
|
return(ERROR_IO_PENDING);
|
|||
|
|
|||
|
case SCESTATUS_SPECIAL_ACCOUNT:
|
|||
|
return(ERROR_SPECIAL_ACCOUNT);
|
|||
|
|
|||
|
default:
|
|||
|
return(ERROR_EXTENDED_ERROR);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
SCESTATUS
|
|||
|
ScepDosErrorToSceStatus(
|
|||
|
DWORD rc
|
|||
|
)
|
|||
|
{
|
|||
|
switch(rc) {
|
|||
|
case NO_ERROR:
|
|||
|
return(SCESTATUS_SUCCESS);
|
|||
|
|
|||
|
case ERROR_INVALID_PARAMETER:
|
|||
|
case RPC_S_INVALID_STRING_BINDING:
|
|||
|
case RPC_S_INVALID_BINDING:
|
|||
|
case RPC_X_NULL_REF_POINTER:
|
|||
|
return(SCESTATUS_INVALID_PARAMETER);
|
|||
|
|
|||
|
case ERROR_INVALID_DATA:
|
|||
|
return(SCESTATUS_INVALID_DATA);
|
|||
|
|
|||
|
case ERROR_FILE_NOT_FOUND:
|
|||
|
case ERROR_PATH_NOT_FOUND:
|
|||
|
case ERROR_BAD_NETPATH:
|
|||
|
|
|||
|
return(SCESTATUS_PROFILE_NOT_FOUND);
|
|||
|
|
|||
|
case ERROR_ACCESS_DENIED:
|
|||
|
case ERROR_SHARING_VIOLATION:
|
|||
|
case ERROR_LOCK_VIOLATION:
|
|||
|
case ERROR_NETWORK_ACCESS_DENIED:
|
|||
|
case ERROR_CANT_ACCESS_FILE:
|
|||
|
case RPC_S_SERVER_TOO_BUSY:
|
|||
|
|
|||
|
return(SCESTATUS_ACCESS_DENIED);
|
|||
|
|
|||
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|||
|
case ERROR_OUTOFMEMORY:
|
|||
|
case RPC_S_OUT_OF_RESOURCES:
|
|||
|
return(SCESTATUS_NOT_ENOUGH_RESOURCE);
|
|||
|
|
|||
|
case ERROR_BAD_FORMAT:
|
|||
|
return(SCESTATUS_BAD_FORMAT);
|
|||
|
|
|||
|
case ERROR_CURRENT_DIRECTORY:
|
|||
|
return(SCESTATUS_CANT_DELETE);
|
|||
|
|
|||
|
case ERROR_SECTOR_NOT_FOUND:
|
|||
|
case ERROR_SERVICE_DOES_NOT_EXIST:
|
|||
|
case ERROR_RESOURCE_DATA_NOT_FOUND:
|
|||
|
case ERROR_NO_MORE_ITEMS:
|
|||
|
return(SCESTATUS_RECORD_NOT_FOUND);
|
|||
|
|
|||
|
case ERROR_NO_TRUST_LSA_SECRET:
|
|||
|
case ERROR_NO_TRUST_SAM_ACCOUNT:
|
|||
|
case ERROR_TRUSTED_DOMAIN_FAILURE:
|
|||
|
case ERROR_TRUSTED_RELATIONSHIP_FAILURE:
|
|||
|
case ERROR_TRUST_FAILURE:
|
|||
|
return(SCESTATUS_TRUST_FAIL);
|
|||
|
|
|||
|
case ERROR_NONE_MAPPED:
|
|||
|
return(SCESTATUS_NO_MAPPING);
|
|||
|
|
|||
|
case ERROR_DUP_NAME:
|
|||
|
case ERROR_FILE_EXISTS:
|
|||
|
|
|||
|
return(SCESTATUS_OBJECT_EXIST);
|
|||
|
|
|||
|
case ERROR_BUFFER_OVERFLOW:
|
|||
|
return(SCESTATUS_PREFIX_OVERFLOW);
|
|||
|
|
|||
|
case ERROR_INSUFFICIENT_BUFFER:
|
|||
|
case RPC_S_STRING_TOO_LONG:
|
|||
|
|
|||
|
return(SCESTATUS_BUFFER_TOO_SMALL);
|
|||
|
|
|||
|
case ERROR_SERVICE_ALREADY_RUNNING:
|
|||
|
return(SCESTATUS_ALREADY_RUNNING);
|
|||
|
|
|||
|
case ERROR_NOT_SUPPORTED:
|
|||
|
case RPC_S_INVALID_NET_ADDR:
|
|||
|
case RPC_S_NO_ENDPOINT_FOUND:
|
|||
|
case RPC_S_SERVER_UNAVAILABLE:
|
|||
|
case RPC_S_CANNOT_SUPPORT:
|
|||
|
return(SCESTATUS_SERVICE_NOT_SUPPORT);
|
|||
|
|
|||
|
case ERROR_MOD_NOT_FOUND:
|
|||
|
case ERROR_PROC_NOT_FOUND:
|
|||
|
return(SCESTATUS_MOD_NOT_FOUND);
|
|||
|
|
|||
|
case ERROR_EXCEPTION_IN_SERVICE:
|
|||
|
return(SCESTATUS_EXCEPTION_IN_SERVER);
|
|||
|
|
|||
|
case ERROR_DATABASE_FAILURE:
|
|||
|
return(SCESTATUS_JET_DATABASE_ERROR);
|
|||
|
|
|||
|
case ERROR_TIMEOUT:
|
|||
|
return(SCESTATUS_TIMEOUT);
|
|||
|
|
|||
|
case ERROR_IO_PENDING:
|
|||
|
return(SCESTATUS_PENDING_IGNORE);
|
|||
|
|
|||
|
case ERROR_SPECIAL_ACCOUNT:
|
|||
|
case ERROR_PASSWORD_RESTRICTION:
|
|||
|
return(SCESTATUS_SPECIAL_ACCOUNT);
|
|||
|
|
|||
|
default:
|
|||
|
return(SCESTATUS_OTHER_ERROR);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
SCESTATUS
|
|||
|
ScepChangeAclRevision(
|
|||
|
IN PSECURITY_DESCRIPTOR pSD,
|
|||
|
IN BYTE NewRevision
|
|||
|
)
|
|||
|
/*
|
|||
|
Change AclRevision to the NewRevision.
|
|||
|
|
|||
|
This routine is made for backward compatility because NT4 does not support
|
|||
|
the new ACL_REVISION_DS.
|
|||
|
|
|||
|
*/
|
|||
|
{
|
|||
|
BOOLEAN bPresent=FALSE;
|
|||
|
BOOLEAN bDefault=FALSE;
|
|||
|
PACL pAcl=NULL;
|
|||
|
NTSTATUS NtStatus;
|
|||
|
|
|||
|
|
|||
|
if ( pSD ) {
|
|||
|
//
|
|||
|
// change acl revision on DACL
|
|||
|
//
|
|||
|
NtStatus = RtlGetDaclSecurityDescriptor (
|
|||
|
pSD,
|
|||
|
&bPresent,
|
|||
|
&pAcl,
|
|||
|
&bDefault
|
|||
|
);
|
|||
|
if ( NT_SUCCESS(NtStatus) && bPresent && pAcl ) {
|
|||
|
pAcl->AclRevision = NewRevision;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// change acl revision on SACL
|
|||
|
//
|
|||
|
pAcl = NULL;
|
|||
|
bPresent = FALSE;
|
|||
|
|
|||
|
NtStatus = RtlGetSaclSecurityDescriptor (
|
|||
|
pSD,
|
|||
|
&bPresent,
|
|||
|
&pAcl,
|
|||
|
&bDefault
|
|||
|
);
|
|||
|
if ( NT_SUCCESS(NtStatus) && bPresent && pAcl ) {
|
|||
|
pAcl->AclRevision = NewRevision;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
return(SCESTATUS_SUCCESS);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
ScepEqualSid(
|
|||
|
IN PISID pSid1,
|
|||
|
IN PISID pSid2
|
|||
|
)
|
|||
|
{
|
|||
|
if ( pSid1 == NULL && pSid2 == NULL )
|
|||
|
return(TRUE);
|
|||
|
if ( pSid1 == NULL || pSid2 == NULL )
|
|||
|
return(FALSE);
|
|||
|
|
|||
|
return (EqualSid((PSID)pSid1, (PSID)pSid2) ? TRUE: FALSE);
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
ScepEqualGuid(
|
|||
|
IN GUID *Guid1,
|
|||
|
IN GUID *Guid2
|
|||
|
)
|
|||
|
{
|
|||
|
if ( Guid1 == NULL && Guid2 == NULL )
|
|||
|
return(TRUE);
|
|||
|
if ( Guid1 == NULL || Guid2 == NULL )
|
|||
|
return(FALSE);
|
|||
|
/*
|
|||
|
if ( Guid1->Data1 != Guid2->Data1 ||
|
|||
|
Guid1->Data2 != Guid2->Data2 ||
|
|||
|
Guid1->Data3 != Guid2->Data3 ||
|
|||
|
*((DWORD *)(Guid1->Data4)) != *((DWORD *)(Guid2->Data4)) ||
|
|||
|
*((DWORD *)(Guid1->Data4)+1) != *((DWORD *)(Guid2->Data4)+1) )
|
|||
|
return(FALSE);
|
|||
|
|
|||
|
return(TRUE);
|
|||
|
*/
|
|||
|
return (!memcmp(Guid1, Guid2, sizeof(GUID)));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
SCESTATUS
|
|||
|
ScepAddToGroupMembership(
|
|||
|
OUT PSCE_GROUP_MEMBERSHIP *pGroupMembership,
|
|||
|
IN PWSTR Keyname,
|
|||
|
IN DWORD KeyLen,
|
|||
|
IN PSCE_NAME_LIST pMembers,
|
|||
|
IN DWORD ValueType,
|
|||
|
IN BOOL bCheckDup,
|
|||
|
IN BOOL bReplaceList
|
|||
|
)
|
|||
|
{
|
|||
|
PSCE_GROUP_MEMBERSHIP pGroup=NULL;
|
|||
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|||
|
|
|||
|
if ( pGroupMembership == NULL || Keyname == NULL ||
|
|||
|
KeyLen <= 0 ) {
|
|||
|
return(SCESTATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// find if the group is already defined
|
|||
|
//
|
|||
|
if ( bCheckDup ) {
|
|||
|
|
|||
|
for ( pGroup=*pGroupMembership; pGroup != NULL; pGroup=pGroup->Next ) {
|
|||
|
if ( _wcsnicmp( pGroup->GroupName, Keyname, KeyLen) == 0 &&
|
|||
|
pGroup->GroupName[KeyLen] == L'\0' )
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( pGroup == NULL ) {
|
|||
|
// not found. create a new node
|
|||
|
|
|||
|
pGroup = (PSCE_GROUP_MEMBERSHIP)ScepAlloc( LMEM_ZEROINIT,
|
|||
|
sizeof(SCE_GROUP_MEMBERSHIP) );
|
|||
|
|
|||
|
if ( pGroup != NULL ) {
|
|||
|
|
|||
|
pGroup->GroupName = (PWSTR)ScepAlloc( LMEM_ZEROINIT,
|
|||
|
(KeyLen+1)*sizeof(WCHAR) );
|
|||
|
if (pGroup->GroupName != NULL) {
|
|||
|
|
|||
|
wcsncpy( pGroup->GroupName, Keyname, KeyLen );
|
|||
|
|
|||
|
pGroup->Next = *pGroupMembership;
|
|||
|
pGroup->Status = SCE_GROUP_STATUS_NC_MEMBERS | SCE_GROUP_STATUS_NC_MEMBEROF;
|
|||
|
*pGroupMembership = pGroup;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
ScepFree(pGroup);
|
|||
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|||
|
}
|
|||
|
|
|||
|
} else
|
|||
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|||
|
|
|||
|
if ( ValueType == 0 ) {
|
|||
|
|
|||
|
if ( bReplaceList ) {
|
|||
|
|
|||
|
ScepFreeNameList(pGroup->pMembers);
|
|||
|
pGroup->pMembers = pMembers;
|
|||
|
|
|||
|
} else if ( pGroup->pMembers == NULL )
|
|||
|
pGroup->pMembers = pMembers;
|
|||
|
|
|||
|
pGroup->Status &= ~SCE_GROUP_STATUS_NC_MEMBERS;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if ( bReplaceList ) {
|
|||
|
|
|||
|
ScepFreeNameList(pGroup->pMemberOf);
|
|||
|
pGroup->pMemberOf = pMembers;
|
|||
|
|
|||
|
} else if ( pGroup->pMemberOf == NULL )
|
|||
|
pGroup->pMemberOf = pMembers;
|
|||
|
|
|||
|
pGroup->Status &= ~SCE_GROUP_STATUS_NC_MEMBEROF;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(rc);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepAddOneServiceToList(
|
|||
|
IN LPWSTR lpServiceName,
|
|||
|
IN LPWSTR lpDisplayName,
|
|||
|
IN DWORD ServiceStatus,
|
|||
|
IN PVOID pGeneral OPTIONAL,
|
|||
|
IN SECURITY_INFORMATION SeInfo,
|
|||
|
IN BOOL bSecurity,
|
|||
|
OUT PSCE_SERVICES *pServiceList
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Add service name, startup status, security descriptor or a engine name
|
|||
|
to the service list. The service list must be freed using SceFreePSCE_SERVICES
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lpServiceName - The service name
|
|||
|
|
|||
|
ServiceStatus - The startup status of the service
|
|||
|
|
|||
|
pGeneral - The security descriptor or the engine dll name, decided by
|
|||
|
bSecurity
|
|||
|
|
|||
|
bSecurity - TRUE = a security descriptor is passed in pGeneral
|
|||
|
FALSE = a engine dll name is passed in pGeneral
|
|||
|
|
|||
|
pServiceList - The service list to output
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS
|
|||
|
Win32 errors
|
|||
|
*/
|
|||
|
{
|
|||
|
if ( NULL == lpServiceName || pServiceList == NULL ) {
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
PSCE_SERVICES pServiceNode;
|
|||
|
DWORD rc=ERROR_SUCCESS;
|
|||
|
|
|||
|
//
|
|||
|
// allocate a service node
|
|||
|
//
|
|||
|
pServiceNode = (PSCE_SERVICES)LocalAlloc(LMEM_ZEROINIT, sizeof(SCE_SERVICES));
|
|||
|
if ( pServiceNode != NULL ) {
|
|||
|
//
|
|||
|
// allocate buffer for ServiceName
|
|||
|
//
|
|||
|
pServiceNode->ServiceName = (PWSTR)LocalAlloc(LMEM_FIXED,
|
|||
|
(wcslen(lpServiceName) + 1)*sizeof(WCHAR));
|
|||
|
if ( NULL != pServiceNode->ServiceName ) {
|
|||
|
//
|
|||
|
// fill the service node
|
|||
|
//
|
|||
|
if ( lpDisplayName != NULL ) {
|
|||
|
|
|||
|
pServiceNode->DisplayName = (PWSTR)LocalAlloc(LMEM_FIXED,
|
|||
|
(wcslen(lpDisplayName) + 1)*sizeof(WCHAR));
|
|||
|
|
|||
|
if ( pServiceNode->DisplayName != NULL ) {
|
|||
|
wcscpy(pServiceNode->DisplayName, lpDisplayName);
|
|||
|
|
|||
|
} else {
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
} else
|
|||
|
pServiceNode->DisplayName = NULL;
|
|||
|
|
|||
|
if ( rc == NO_ERROR ) {
|
|||
|
|
|||
|
wcscpy(pServiceNode->ServiceName, lpServiceName);
|
|||
|
pServiceNode->Status = 0;
|
|||
|
pServiceNode->Startup = (BYTE)ServiceStatus;
|
|||
|
|
|||
|
if ( bSecurity ) {
|
|||
|
//
|
|||
|
// security descriptor
|
|||
|
//
|
|||
|
pServiceNode->General.pSecurityDescriptor = (PSECURITY_DESCRIPTOR)pGeneral;
|
|||
|
pServiceNode->SeInfo = SeInfo;
|
|||
|
} else {
|
|||
|
//
|
|||
|
// service engine name
|
|||
|
//
|
|||
|
pServiceNode->General.ServiceEngineName = (PWSTR)pGeneral;
|
|||
|
}
|
|||
|
//
|
|||
|
// link to the list
|
|||
|
//
|
|||
|
pServiceNode->Next = *pServiceList;
|
|||
|
*pServiceList = pServiceNode;
|
|||
|
|
|||
|
} else {
|
|||
|
LocalFree(pServiceNode->ServiceName);
|
|||
|
}
|
|||
|
|
|||
|
} else
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
|
|||
|
if ( rc != ERROR_SUCCESS ) {
|
|||
|
LocalFree(pServiceNode);
|
|||
|
}
|
|||
|
|
|||
|
} else
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
|
|||
|
return(rc);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepIsAdminLoggedOn(
|
|||
|
OUT PBOOL bpAdminLogon
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
HANDLE Token;
|
|||
|
NTSTATUS NtStatus;
|
|||
|
SID_IDENTIFIER_AUTHORITY IdAuth=SECURITY_NT_AUTHORITY;
|
|||
|
PSID AdminsSid=NULL;
|
|||
|
|
|||
|
|
|||
|
if ( bpAdminLogon == NULL ) {
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
*bpAdminLogon = FALSE;
|
|||
|
|
|||
|
if (!OpenThreadToken( GetCurrentThread(),
|
|||
|
TOKEN_QUERY | TOKEN_DUPLICATE,
|
|||
|
FALSE,
|
|||
|
&Token)) {
|
|||
|
|
|||
|
if (!OpenProcessToken( GetCurrentProcess(),
|
|||
|
TOKEN_QUERY | TOKEN_DUPLICATE,
|
|||
|
&Token))
|
|||
|
|
|||
|
return(GetLastError());
|
|||
|
|
|||
|
}
|
|||
|
//
|
|||
|
// Parepare AdminsSid
|
|||
|
//
|
|||
|
NtStatus = RtlAllocateAndInitializeSid(
|
|||
|
&IdAuth,
|
|||
|
2,
|
|||
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|||
|
DOMAIN_ALIAS_RID_ADMINS,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0,
|
|||
|
&AdminsSid );
|
|||
|
|
|||
|
DWORD rc32 = RtlNtStatusToDosError(NtStatus);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus) ) {
|
|||
|
|
|||
|
//
|
|||
|
// use the CheckTokenMembership API which handles the group attributes
|
|||
|
//
|
|||
|
|
|||
|
HANDLE NewToken;
|
|||
|
|
|||
|
if ( DuplicateToken( Token, SecurityImpersonation, &NewToken )) {
|
|||
|
|
|||
|
if ( FALSE == CheckTokenMembership(
|
|||
|
NewToken,
|
|||
|
AdminsSid,
|
|||
|
bpAdminLogon
|
|||
|
) ) {
|
|||
|
|
|||
|
//
|
|||
|
// error occured when checking membership, assume it is not a member
|
|||
|
//
|
|||
|
|
|||
|
*bpAdminLogon = FALSE;
|
|||
|
|
|||
|
rc32 = GetLastError();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
CloseHandle(NewToken);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
rc32 = GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
DWORD i;
|
|||
|
DWORD ReturnLen, NewLen;
|
|||
|
PVOID Info=NULL;
|
|||
|
|
|||
|
//
|
|||
|
// check groups
|
|||
|
//
|
|||
|
NtStatus = NtQueryInformationToken (
|
|||
|
Token,
|
|||
|
TokenGroups,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
&ReturnLen
|
|||
|
);
|
|||
|
if ( NtStatus == STATUS_BUFFER_TOO_SMALL ) {
|
|||
|
//
|
|||
|
// allocate buffer
|
|||
|
//
|
|||
|
Info = ScepAlloc(0, ReturnLen+1);
|
|||
|
|
|||
|
if ( Info != NULL ) {
|
|||
|
NtStatus = NtQueryInformationToken (
|
|||
|
Token,
|
|||
|
TokenGroups,
|
|||
|
Info,
|
|||
|
ReturnLen,
|
|||
|
&NewLen
|
|||
|
);
|
|||
|
if ( NT_SUCCESS(NtStatus) ) {
|
|||
|
|
|||
|
for ( i = 0; i<((PTOKEN_GROUPS)Info)->GroupCount; i++) {
|
|||
|
//
|
|||
|
// check each group sid
|
|||
|
//
|
|||
|
if ( ((PTOKEN_GROUPS)Info)->Groups[i].Sid != NULL &&
|
|||
|
RtlEqualSid(((PTOKEN_GROUPS)Info)->Groups[i].Sid, AdminsSid) ) {
|
|||
|
*bpAdminLogon = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ScepFree(Info);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
rc32 = RtlNtStatusToDosError(NtStatus);
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Free administrators Sid
|
|||
|
//
|
|||
|
RtlFreeSid(AdminsSid);
|
|||
|
}
|
|||
|
|
|||
|
CloseHandle(Token);
|
|||
|
|
|||
|
return(rc32);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepGetProfileSetting(
|
|||
|
IN PCWSTR ValueName,
|
|||
|
IN BOOL bAdminLogon,
|
|||
|
OUT PWSTR *Setting
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns JET profile setting for the ValueName from registry.
|
|||
|
If there is no setting in registry (e.g., first time), a default setting
|
|||
|
for the ValueName will be built. The output Setting string must be freed
|
|||
|
by LocalFree after its use.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ValueName - The registry value name to retrieve
|
|||
|
|
|||
|
bAdminLogon - The flag to indicate if logged on user is admin equivalent
|
|||
|
|
|||
|
Setting - the ouptut buffer
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Win32 error codes
|
|||
|
*/
|
|||
|
{
|
|||
|
DWORD RegType;
|
|||
|
DWORD rc;
|
|||
|
PWSTR SysRoot=NULL;
|
|||
|
PWSTR ProfilePath=NULL;
|
|||
|
TCHAR TempName[256];
|
|||
|
|
|||
|
|
|||
|
if ( ValueName == NULL || Setting == NULL ) {
|
|||
|
return( ERROR_INVALID_PARAMETER );
|
|||
|
}
|
|||
|
|
|||
|
*Setting = NULL;
|
|||
|
|
|||
|
if (bAdminLogon ) {
|
|||
|
if ( _wcsicmp(L"DefaultProfile", ValueName ) == 0 ) {
|
|||
|
//
|
|||
|
// do not query the system database name in registry
|
|||
|
//
|
|||
|
rc = ERROR_FILE_NOT_FOUND;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
rc = ScepRegQueryValue(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
SCE_ROOT_PATH,
|
|||
|
ValueName,
|
|||
|
(PVOID *)Setting,
|
|||
|
&RegType
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
HKEY hCurrentUser=NULL;
|
|||
|
//
|
|||
|
// the HKEY_CURRENT_USER may be linked to .default
|
|||
|
// depends on the current calling process
|
|||
|
//
|
|||
|
rc =RegOpenCurrentUser(
|
|||
|
KEY_READ,
|
|||
|
&hCurrentUser
|
|||
|
);
|
|||
|
|
|||
|
if ( rc != NO_ERROR ) {
|
|||
|
hCurrentUser = NULL;
|
|||
|
}
|
|||
|
|
|||
|
rc = ScepRegQueryValue(
|
|||
|
hCurrentUser ? hCurrentUser : HKEY_CURRENT_USER,
|
|||
|
SCE_ROOT_PATH,
|
|||
|
ValueName,
|
|||
|
(PVOID *)Setting,
|
|||
|
&RegType
|
|||
|
);
|
|||
|
|
|||
|
if ( hCurrentUser ) {
|
|||
|
// close it
|
|||
|
RegCloseKey(hCurrentUser);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// if registry type is not REG_SZ or REG_EXPAND_SZ,
|
|||
|
// return status won't be SUCCESS
|
|||
|
//
|
|||
|
|
|||
|
if ( rc != NO_ERROR ) {
|
|||
|
|
|||
|
//
|
|||
|
// use the default
|
|||
|
//
|
|||
|
RegType = 0;
|
|||
|
rc = ScepGetNTDirectory( &SysRoot, &RegType, SCE_FLAG_WINDOWS_DIR );
|
|||
|
|
|||
|
if ( rc == NO_ERROR ) {
|
|||
|
|
|||
|
if ( SysRoot != NULL ) {
|
|||
|
|
|||
|
if ( bAdminLogon ) {
|
|||
|
//
|
|||
|
// default location is %SystemRoot%\Security\Database\secedit.sdb
|
|||
|
//
|
|||
|
wcscpy(TempName, L"\\Security\\Database\\secedit.sdb");
|
|||
|
RegType += wcslen(TempName)+1;
|
|||
|
|
|||
|
*Setting = (PWSTR)ScepAlloc( 0, RegType*sizeof(WCHAR));
|
|||
|
if ( *Setting != NULL ) {
|
|||
|
swprintf(*Setting, L"%s%s", SysRoot, TempName );
|
|||
|
|
|||
|
*(*Setting+RegType-1) = L'\0';
|
|||
|
/*
|
|||
|
// do not save system database name
|
|||
|
// set this value as the default profile name for administrators
|
|||
|
//
|
|||
|
|
|||
|
ScepRegSetValue(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
SCE_ROOT_PATH,
|
|||
|
(PWSTR)ValueName,
|
|||
|
REG_SZ,
|
|||
|
(BYTE *)(*Setting),
|
|||
|
(RegType-1)*sizeof(WCHAR)
|
|||
|
);
|
|||
|
*/
|
|||
|
|
|||
|
} else
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// default location is <UserProfilesDirectory>\Profiles\<User>\secedit.sdb
|
|||
|
// on NT5, it will be %SystemDrive%\Users\Profiles...
|
|||
|
// on NT4, it is %SystemRoot%\Profiles...
|
|||
|
// GetCurrentUserProfilePath already handles NT4/NT5 difference
|
|||
|
//
|
|||
|
rc = ScepGetCurrentUserProfilePath(&ProfilePath);
|
|||
|
|
|||
|
if ( rc == NO_ERROR && ProfilePath != NULL ) {
|
|||
|
//
|
|||
|
// get the current user profile path
|
|||
|
//
|
|||
|
wcscpy(TempName, L"\\secedit.sdb");
|
|||
|
|
|||
|
*Setting = (PWSTR)ScepAlloc(0, (wcslen(ProfilePath)+wcslen(TempName)+1)*sizeof(WCHAR));
|
|||
|
|
|||
|
if ( *Setting != NULL ) {
|
|||
|
swprintf(*Setting, L"%s%s\0", ProfilePath,TempName );
|
|||
|
|
|||
|
} else
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
|
|||
|
ScepFree(ProfilePath);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
rc = NO_ERROR;
|
|||
|
wcscpy(TempName, L"\\Profiles\\secedit.sdb");
|
|||
|
#if _WINNT_WIN32>=0x0500
|
|||
|
//
|
|||
|
// default to <ProfilesDirectory>\Profiles
|
|||
|
// get the profiles directory first
|
|||
|
//
|
|||
|
RegType = 0;
|
|||
|
GetProfilesDirectory(NULL, &RegType);
|
|||
|
|
|||
|
if ( RegType ) {
|
|||
|
//
|
|||
|
// allocate the total buffer
|
|||
|
//
|
|||
|
RegType += wcslen(TempName);
|
|||
|
|
|||
|
*Setting = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (RegType+1)*sizeof(WCHAR));
|
|||
|
|
|||
|
if ( *Setting ) {
|
|||
|
//
|
|||
|
// call to get the profiles directory again
|
|||
|
//
|
|||
|
if ( GetProfilesDirectory(*Setting, &RegType) ) {
|
|||
|
|
|||
|
wcscat(*Setting, TempName );
|
|||
|
|
|||
|
} else {
|
|||
|
rc = GetLastError();
|
|||
|
|
|||
|
ScepFree(*Setting);
|
|||
|
*Setting = NULL;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
rc = GetLastError();
|
|||
|
}
|
|||
|
#else
|
|||
|
//
|
|||
|
// default to %SystemRoot%\Profiles
|
|||
|
//
|
|||
|
RegType += wcslen(TempName)+1;
|
|||
|
|
|||
|
*Setting = (PWSTR)ScepAlloc( 0, RegType*sizeof(WCHAR));
|
|||
|
|
|||
|
if ( *Setting != NULL ) {
|
|||
|
swprintf(*Setting, L"%s%s", SysRoot,TempName );
|
|||
|
|
|||
|
*(*Setting+RegType-1) = L'\0';
|
|||
|
|
|||
|
rc = ERROR_SUCCESS;
|
|||
|
|
|||
|
} else {
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ScepFree(SysRoot);
|
|||
|
|
|||
|
} else
|
|||
|
rc = ERROR_INVALID_DATA;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(rc);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepCompareObjectSecurity(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|||
|
IN PSECURITY_DESCRIPTOR ProfileSD,
|
|||
|
IN SECURITY_INFORMATION ProfileSeInfo,
|
|||
|
OUT PBYTE IsDifferent
|
|||
|
)
|
|||
|
/* ++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Compare two security descriptors
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ObjectType - the object type
|
|||
|
|
|||
|
pSecurityDescriptor - The security descriptor of current object's setting
|
|||
|
|
|||
|
ProfileSD - security descriptor specified in the template
|
|||
|
|
|||
|
ProfileSeInfo - security information specified in the template
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
SCESTATUS error codes
|
|||
|
|
|||
|
++ */
|
|||
|
{
|
|||
|
BOOL Different=FALSE;
|
|||
|
BOOL DifPermOrAudit;
|
|||
|
DWORD rc=ERROR_SUCCESS;
|
|||
|
PSID pSid1=NULL;
|
|||
|
PSID pSid2=NULL;
|
|||
|
BOOLEAN tFlag;
|
|||
|
BOOLEAN aclPresent;
|
|||
|
PACL pAcl1=NULL;
|
|||
|
PACL pAcl2=NULL;
|
|||
|
SECURITY_DESCRIPTOR_CONTROL Control1;
|
|||
|
SECURITY_DESCRIPTOR_CONTROL Control2;
|
|||
|
DWORD Win32rc;
|
|||
|
|
|||
|
|
|||
|
BYTE Status=0;
|
|||
|
|
|||
|
if ( IsDifferent == NULL ) {
|
|||
|
return(SCESTATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
if ( pSecurityDescriptor == NULL &&
|
|||
|
ProfileSD == NULL ) {
|
|||
|
|
|||
|
if ( IsDifferent ) {
|
|||
|
*IsDifferent = SCE_STATUS_MISMATCH;
|
|||
|
}
|
|||
|
return(rc);
|
|||
|
}
|
|||
|
|
|||
|
if ( IsDifferent ) {
|
|||
|
*IsDifferent = 0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// if ProfileSD is specified and protection does not match SystemSD, then mismatch
|
|||
|
// don't care if ProfileSD is not specified
|
|||
|
//
|
|||
|
|
|||
|
if ( pSecurityDescriptor == NULL || !NT_SUCCESS(RtlGetControlSecurityDescriptor (
|
|||
|
pSecurityDescriptor,
|
|||
|
&Control1,
|
|||
|
&Win32rc // temp use
|
|||
|
))) {
|
|||
|
|
|||
|
Control1 = 0;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( ProfileSD == NULL || !NT_SUCCESS(RtlGetControlSecurityDescriptor (
|
|||
|
ProfileSD,
|
|||
|
&Control2,
|
|||
|
&Win32rc // temp use
|
|||
|
))) {
|
|||
|
|
|||
|
Control2 = 0;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ((Control1 & SE_DACL_PROTECTED) != (Control2 & SE_DACL_PROTECTED)) {
|
|||
|
|
|||
|
Different = TRUE;
|
|||
|
Status |= SCE_STATUS_PERMISSION_MISMATCH;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ((Control1 & SE_SACL_PROTECTED) != (Control2 & SE_SACL_PROTECTED)) {
|
|||
|
|
|||
|
Different = TRUE;
|
|||
|
Status |= SCE_STATUS_AUDIT_MISMATCH;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Compare two security descriptors
|
|||
|
//
|
|||
|
if ( ProfileSeInfo & OWNER_SECURITY_INFORMATION ) {
|
|||
|
if ( pSecurityDescriptor == NULL ||
|
|||
|
!NT_SUCCESS( RtlGetOwnerSecurityDescriptor(
|
|||
|
pSecurityDescriptor,
|
|||
|
&pSid1,
|
|||
|
&tFlag)
|
|||
|
) ) {
|
|||
|
|
|||
|
pSid1 = NULL;
|
|||
|
}
|
|||
|
if ( ProfileSD == NULL ||
|
|||
|
!NT_SUCCESS( RtlGetOwnerSecurityDescriptor(
|
|||
|
ProfileSD,
|
|||
|
&pSid2,
|
|||
|
&tFlag)
|
|||
|
) ) {
|
|||
|
|
|||
|
pSid2 = NULL;
|
|||
|
}
|
|||
|
if ( (pSid1 == NULL && pSid2 != NULL) ||
|
|||
|
(pSid1 != NULL && pSid2 == NULL) ||
|
|||
|
(pSid1 != NULL && pSid2 != NULL && !EqualSid(pSid1, pSid2)) ) {
|
|||
|
|
|||
|
Different = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
//
|
|||
|
// Get Group address
|
|||
|
//
|
|||
|
|
|||
|
if ( ProfileSeInfo & GROUP_SECURITY_INFORMATION ) {
|
|||
|
pSid1 = NULL;
|
|||
|
pSid2 = NULL;
|
|||
|
if ( pSecurityDescriptor == NULL ||
|
|||
|
!NT_SUCCESS( RtlGetGroupSecurityDescriptor(
|
|||
|
pSecurityDescriptor,
|
|||
|
&pSid1,
|
|||
|
&tFlag)
|
|||
|
) ) {
|
|||
|
|
|||
|
pSid1 = NULL;
|
|||
|
}
|
|||
|
if ( ProfileSD == NULL ||
|
|||
|
!NT_SUCCESS( RtlGetGroupSecurityDescriptor(
|
|||
|
ProfileSD,
|
|||
|
&pSid2,
|
|||
|
&tFlag)
|
|||
|
) ) {
|
|||
|
|
|||
|
pSid2 = NULL;
|
|||
|
}
|
|||
|
if ( (pSid1 == NULL && pSid2 != NULL) ||
|
|||
|
(pSid1 != NULL && pSid2 == NULL) ||
|
|||
|
(pSid1 != NULL && pSid2 != NULL && !EqualSid(pSid1, pSid2)) ) {
|
|||
|
|
|||
|
Different = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Get DACL address
|
|||
|
//
|
|||
|
|
|||
|
if ( !(Status & SCE_STATUS_PERMISSION_MISMATCH) && (ProfileSeInfo & DACL_SECURITY_INFORMATION) ) {
|
|||
|
if ( pSecurityDescriptor == NULL ||
|
|||
|
!NT_SUCCESS( RtlGetDaclSecurityDescriptor(
|
|||
|
pSecurityDescriptor,
|
|||
|
&aclPresent,
|
|||
|
&pAcl1,
|
|||
|
&tFlag)
|
|||
|
) ) {
|
|||
|
|
|||
|
pAcl1 = NULL;
|
|||
|
} else if ( !aclPresent )
|
|||
|
pAcl1 = NULL;
|
|||
|
if ( ProfileSD == NULL ||
|
|||
|
!NT_SUCCESS( RtlGetDaclSecurityDescriptor(
|
|||
|
ProfileSD,
|
|||
|
&aclPresent,
|
|||
|
&pAcl2,
|
|||
|
&tFlag)
|
|||
|
) ) {
|
|||
|
|
|||
|
pAcl2 = NULL;
|
|||
|
} else if ( !aclPresent )
|
|||
|
pAcl2 = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// compare two ACLs
|
|||
|
//
|
|||
|
DifPermOrAudit = FALSE;
|
|||
|
rc = ScepCompareExplicitAcl( ObjectType, IsContainer, pAcl1, pAcl2, &DifPermOrAudit );
|
|||
|
|
|||
|
if ( rc != ERROR_SUCCESS ) {
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
|
|||
|
if ( DifPermOrAudit ) {
|
|||
|
Different = TRUE;
|
|||
|
Status |= SCE_STATUS_PERMISSION_MISMATCH;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get SACL address
|
|||
|
//
|
|||
|
|
|||
|
if ( !(Status & SCE_STATUS_AUDIT_MISMATCH) && (ProfileSeInfo & SACL_SECURITY_INFORMATION) ) {
|
|||
|
pAcl1 = NULL;
|
|||
|
pAcl2 = NULL;
|
|||
|
if ( pSecurityDescriptor == NULL ||
|
|||
|
!NT_SUCCESS( RtlGetSaclSecurityDescriptor(
|
|||
|
pSecurityDescriptor,
|
|||
|
&aclPresent,
|
|||
|
&pAcl1,
|
|||
|
&tFlag)
|
|||
|
) ) {
|
|||
|
|
|||
|
pAcl1 = NULL;
|
|||
|
|
|||
|
} else if ( !aclPresent )
|
|||
|
pAcl1 = NULL;
|
|||
|
|
|||
|
if ( ProfileSD == NULL ||
|
|||
|
!NT_SUCCESS( RtlGetSaclSecurityDescriptor(
|
|||
|
ProfileSD,
|
|||
|
&aclPresent,
|
|||
|
&pAcl2,
|
|||
|
&tFlag)
|
|||
|
) ) {
|
|||
|
|
|||
|
pAcl2 = NULL;
|
|||
|
|
|||
|
} else if ( !aclPresent )
|
|||
|
pAcl2 = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// compare two ACLs
|
|||
|
//
|
|||
|
DifPermOrAudit = FALSE;
|
|||
|
rc = ScepCompareExplicitAcl( ObjectType, IsContainer, pAcl1, pAcl2, &DifPermOrAudit );
|
|||
|
|
|||
|
if ( rc != ERROR_SUCCESS ) {
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
|
|||
|
if ( DifPermOrAudit ) {
|
|||
|
Different = TRUE;
|
|||
|
Status |= SCE_STATUS_AUDIT_MISMATCH;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( IsDifferent && Different ) {
|
|||
|
|
|||
|
*IsDifferent = SCE_STATUS_MISMATCH;
|
|||
|
|
|||
|
if ( Status ) {
|
|||
|
*IsDifferent |= Status;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Done:
|
|||
|
|
|||
|
return(rc);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepCompareExplicitAcl(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN PACL pAcl1,
|
|||
|
IN PACL pAcl2,
|
|||
|
OUT PBOOL pDifferent
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine compares explicit aces of two ACLs for exact match. Exact
|
|||
|
match means: same access type, same inheritance flag, same access mask,
|
|||
|
same GUID/Object GUID (if available), and same SID.
|
|||
|
|
|||
|
Inherited aces (INHERITED_ACE is set) are ignored.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pAcl1 - The first ACL
|
|||
|
|
|||
|
pAcl2 - The 2nd ACL
|
|||
|
|
|||
|
pDifferent - The output flag to indicate different
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Win32 error codes
|
|||
|
*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus=STATUS_SUCCESS;
|
|||
|
DWORD dwAcl1AceCount, dwAcl2AceCount;
|
|||
|
ACE_HEADER *pAce1=NULL;
|
|||
|
ACE_HEADER *pAce2=NULL;
|
|||
|
PSCEP_ADL_NODE hTable1 [SCEP_ADL_HTABLE_SIZE];
|
|||
|
PSCEP_ADL_NODE hTable2 [SCEP_ADL_HTABLE_SIZE];
|
|||
|
|
|||
|
memset(hTable1, NULL, SCEP_ADL_HTABLE_SIZE * sizeof(PSCEP_ADL_NODE) );
|
|||
|
memset(hTable2, NULL, SCEP_ADL_HTABLE_SIZE * sizeof(PSCEP_ADL_NODE) );
|
|||
|
|
|||
|
*pDifferent = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// if pAcl1 is NULL, pAcl2 should have 0 explicit Ace
|
|||
|
//
|
|||
|
if ( pAcl1 == NULL ) {
|
|||
|
NtStatus = ScepAnyExplicitAcl( pAcl2, 0, pDifferent );
|
|||
|
return(RtlNtStatusToDosError(NtStatus));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// if pAcl2 is NULL, pAcl1 should have 0 explicit Ace
|
|||
|
//
|
|||
|
if ( pAcl2 == NULL ) {
|
|||
|
NtStatus = ScepAnyExplicitAcl( pAcl1, 0, pDifferent );
|
|||
|
return(RtlNtStatusToDosError(NtStatus));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// both ACLs are not NULL
|
|||
|
//
|
|||
|
|
|||
|
BOOL bAcl1NoExplicitAces;
|
|||
|
BOOL bAcl2NoExplicitAces;
|
|||
|
|
|||
|
dwAcl1AceCount = 0;
|
|||
|
dwAcl2AceCount = 0;
|
|||
|
|
|||
|
while ( dwAcl1AceCount < pAcl1->AceCount || dwAcl2AceCount < pAcl2->AceCount) {
|
|||
|
//
|
|||
|
// convert Acl1 into Access Description Language and insert into htable for this blob
|
|||
|
// blob is defined as a contiguous AceList of same type
|
|||
|
//
|
|||
|
bAcl1NoExplicitAces = TRUE;
|
|||
|
if (dwAcl1AceCount < pAcl1->AceCount) {
|
|||
|
NtStatus = ScepConvertAclBlobToAdl(ObjectType,
|
|||
|
IsContainer,
|
|||
|
pAcl1,
|
|||
|
&dwAcl1AceCount,
|
|||
|
&bAcl1NoExplicitAces,
|
|||
|
hTable1);
|
|||
|
|
|||
|
if ( !NT_SUCCESS(NtStatus) )
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// convert Acl2 into Access Description Language and insert into htable for this blob
|
|||
|
//
|
|||
|
bAcl2NoExplicitAces = TRUE;
|
|||
|
if (dwAcl2AceCount < pAcl2->AceCount) {
|
|||
|
NtStatus = ScepConvertAclBlobToAdl(ObjectType,
|
|||
|
IsContainer,
|
|||
|
pAcl2,
|
|||
|
&dwAcl2AceCount,
|
|||
|
&bAcl2NoExplicitAces,
|
|||
|
hTable2);
|
|||
|
if ( !NT_SUCCESS(NtStatus) )
|
|||
|
goto Done;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// compare Adls for Acl1 and Acl2 blobs
|
|||
|
// if after ignoring INHERITED_ACES, one Acl has no aces and the other has, then bAcl1NoExplicitAces != bAcl2NoExplicitAces
|
|||
|
//
|
|||
|
|
|||
|
if (bAcl1NoExplicitAces != bAcl2NoExplicitAces || !ScepEqualAdls(hTable1, hTable2) ) {
|
|||
|
|
|||
|
*pDifferent = TRUE;
|
|||
|
ScepFreeAdl(hTable1);
|
|||
|
ScepFreeAdl(hTable2);
|
|||
|
return(ERROR_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// need to reuse hTables for next blobs
|
|||
|
//
|
|||
|
|
|||
|
ScepFreeAdl(hTable1);
|
|||
|
ScepFreeAdl(hTable2);
|
|||
|
|
|||
|
//
|
|||
|
// the Adls are equal - so continue with next blobs for Acl1 and Acl2
|
|||
|
//
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Done:
|
|||
|
|
|||
|
//
|
|||
|
// free in case goto was taken
|
|||
|
//
|
|||
|
|
|||
|
ScepFreeAdl(hTable1);
|
|||
|
ScepFreeAdl(hTable2);
|
|||
|
|
|||
|
return(RtlNtStatusToDosError(NtStatus));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ScepConvertAclBlobToAdl(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN PACL pAcl,
|
|||
|
OUT DWORD *pdwAceNumber,
|
|||
|
OUT BOOL *pbAclNoExplicitAces,
|
|||
|
OUT PSCEP_ADL_NODE *hTable
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine builds the Adl for a contiguous block of same type aces.
|
|||
|
Inherited aces (INHERITED_ACE is set) are ignored.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN ObjectType - the type of object, passed on to other functions
|
|||
|
IN IsContainer - whether container or not, passed on to other functions
|
|||
|
IN pAcl - the Acl to be converted to Adl
|
|||
|
OUT pdwAceNumber - running count of the aces considered
|
|||
|
OUT pbAclNoExplicitAces - whether there were explicit aces (if FALSE, there is at leat one explicit ace)
|
|||
|
OUT hTable - the Adl structure for this Acl
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Win32 error codes
|
|||
|
*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus=STATUS_SUCCESS;
|
|||
|
ACE_HEADER *pAce=NULL;
|
|||
|
|
|||
|
if (pAcl == NULL || pdwAceNumber == NULL ||
|
|||
|
hTable == NULL || pbAclNoExplicitAces == NULL) {
|
|||
|
|
|||
|
return (STATUS_INVALID_PARAMETER);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DWORD dwAceNumber = *pdwAceNumber;
|
|||
|
|
|||
|
NtStatus = RtlGetAce(pAcl, dwAceNumber, (PVOID *)&pAce);
|
|||
|
if ( !NT_SUCCESS(NtStatus) )
|
|||
|
goto Done;
|
|||
|
|
|||
|
//
|
|||
|
// get the first non INHERITED_ACE
|
|||
|
//
|
|||
|
|
|||
|
while ( (pAce->AceFlags & INHERITED_ACE) && (++dwAceNumber < pAcl->AceCount) ) {
|
|||
|
|
|||
|
NtStatus = RtlGetAce(pAcl, dwAceNumber, (PVOID *)&pAce);
|
|||
|
if ( !NT_SUCCESS(NtStatus) )
|
|||
|
goto Done;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( !(pAce->AceFlags & INHERITED_ACE) ) {
|
|||
|
|
|||
|
UCHAR AclAceType;
|
|||
|
|
|||
|
*pbAclNoExplicitAces = FALSE;
|
|||
|
|
|||
|
AclAceType = pAce->AceType;
|
|||
|
|
|||
|
//
|
|||
|
// in a blob of AclAceType
|
|||
|
//
|
|||
|
while ( (pAce->AceType == AclAceType) && (dwAceNumber < pAcl->AceCount) ) {
|
|||
|
|
|||
|
if (NO_ERROR != ScepAdlLookupAdd(ObjectType, IsContainer, pAce, hTable)){
|
|||
|
|
|||
|
NtStatus = STATUS_NO_MEMORY;
|
|||
|
goto Done;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// get the next ace in Acl
|
|||
|
//
|
|||
|
if (++dwAceNumber < pAcl->AceCount) {
|
|||
|
|
|||
|
//
|
|||
|
// skip INHERITED_ACEs if any except if AceType changes
|
|||
|
//
|
|||
|
do {
|
|||
|
|
|||
|
NtStatus = RtlGetAce(pAcl, dwAceNumber, (PVOID *)&pAce);
|
|||
|
if ( !NT_SUCCESS(NtStatus) )
|
|||
|
goto Done;
|
|||
|
|
|||
|
//
|
|||
|
// if AceType changes (e.g. from A to D) we quit building the Adl
|
|||
|
// irrespective of whether it is an INHERITED_ACE
|
|||
|
//
|
|||
|
|
|||
|
if (pAce->AceType != AclAceType)
|
|||
|
break;
|
|||
|
|
|||
|
} while ( (pAce->AceFlags & INHERITED_ACE) && (++dwAceNumber < pAcl->AceCount) );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Done:
|
|||
|
//
|
|||
|
// update the running count of aces for this Acl
|
|||
|
//
|
|||
|
|
|||
|
*pdwAceNumber = dwAceNumber;
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
ScepEqualAdls(
|
|||
|
IN PSCEP_ADL_NODE *hTable1,
|
|||
|
IN PSCEP_ADL_NODE *hTable2
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine compares rwo Adls - if the Adls are equal, the hTables will be laid out in the same
|
|||
|
fashion since hashing function is the same. Two Adls are equal iff they match all of the below
|
|||
|
|
|||
|
(a) SID, GIUD1, GIUD2
|
|||
|
(b) AceType
|
|||
|
(c) All the masks
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN hTable1 - the first Adl hash table
|
|||
|
IN hTable2 - the secomd Adl hash table
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
BOOL - true if equal
|
|||
|
*/
|
|||
|
{
|
|||
|
PSCEP_ADL_NODE pNode1 = NULL;
|
|||
|
PSCEP_ADL_NODE pNode2 = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// the Adls should be the same if superimposed over each other since they use the same hash etc.
|
|||
|
//
|
|||
|
|
|||
|
for (DWORD numBucket = 0; numBucket < SCEP_ADL_HTABLE_SIZE; numBucket++) {
|
|||
|
|
|||
|
//
|
|||
|
// walk each bucket, marching pointers in pairs
|
|||
|
//
|
|||
|
|
|||
|
pNode1 = hTable1[numBucket];
|
|||
|
pNode2 = hTable2[numBucket];
|
|||
|
|
|||
|
while (pNode1 && pNode2) {
|
|||
|
|
|||
|
if ( pNode1->AceType != pNode2->AceType ||
|
|||
|
pNode1->dwEffectiveMask != pNode2->dwEffectiveMask ||
|
|||
|
pNode1->dw_CI_IO_Mask != pNode2->dw_CI_IO_Mask ||
|
|||
|
pNode1->dw_OI_IO_Mask != pNode2->dw_OI_IO_Mask ||
|
|||
|
pNode1->dw_NP_CI_IO_Mask != pNode2->dw_NP_CI_IO_Mask ||
|
|||
|
!ScepEqualSid(pNode1->pSid, pNode2->pSid) ||
|
|||
|
!ScepEqualGuid(pNode1->pGuidObjectType, pNode2->pGuidObjectType) ||
|
|||
|
!ScepEqualGuid(pNode1->pGuidInheritedObjectType, pNode2->pGuidInheritedObjectType) ) {
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
pNode1 = pNode1->Next;
|
|||
|
pNode2 = pNode2->Next;
|
|||
|
}
|
|||
|
|
|||
|
if (pNode1 == NULL && pNode2 != NULL ||
|
|||
|
pNode1 != NULL && pNode2 == NULL) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return(TRUE);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepAdlLookupAdd(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN ACE_HEADER *pAce,
|
|||
|
OUT PSCEP_ADL_NODE *hTable
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine adds and initializes a new entry in the hTable for pAce->Sid or merges the
|
|||
|
existing access masks if pAce->Sid already exists
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN ObjectType - the type of object, passed on to other functions
|
|||
|
IN IsContainer - whether container or not, passed on to other functions
|
|||
|
IN pAce - the ace to be parsed into the Adl hTable
|
|||
|
OUT hTable - the hTable for this Adl
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Dos error codes
|
|||
|
*/
|
|||
|
{
|
|||
|
DWORD rc = NO_ERROR;
|
|||
|
PISID pSid = NULL;
|
|||
|
PSCEP_ADL_NODE pNode = NULL;
|
|||
|
|
|||
|
if (pAce == NULL || hTable == NULL)
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
|
|||
|
switch ( pAce->AceType ) {
|
|||
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|||
|
case ACCESS_DENIED_ACE_TYPE:
|
|||
|
case SYSTEM_AUDIT_ACE_TYPE:
|
|||
|
case SYSTEM_ALARM_ACE_TYPE:
|
|||
|
|
|||
|
pSid = (PISID)&((PACCESS_ALLOWED_ACE)pAce)->SidStart;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|||
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|||
|
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
|
|||
|
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
|
|||
|
|
|||
|
pSid = (PISID)ScepObjectAceObjectType(pAce);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
// should not get in here taken care of just after switch
|
|||
|
;
|
|||
|
}
|
|||
|
|
|||
|
if (pSid == NULL)
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
|
|||
|
pNode = ScepAdlLookup(pAce, hTable);
|
|||
|
|
|||
|
//
|
|||
|
// hashed by last subauthority of SID - will need to change this if too many collisions in hTable
|
|||
|
// once mapped to a bucket, for exact match, have to match the triple <SID,GUID1,GUID2>
|
|||
|
//
|
|||
|
|
|||
|
if (pNode == NULL)
|
|||
|
|
|||
|
//
|
|||
|
// seeing this triple <SID, GUID1, GUID2> for the first time
|
|||
|
//
|
|||
|
|
|||
|
rc = ScepAddToAdlList( ObjectType,
|
|||
|
IsContainer,
|
|||
|
pAce,
|
|||
|
&hTable[(pSid->SubAuthority[pSid->SubAuthorityCount - 1] % SCEP_ADL_HTABLE_SIZE)]
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
else
|
|||
|
|
|||
|
//
|
|||
|
// already exists so simply merge the masks
|
|||
|
//
|
|||
|
|
|||
|
ScepAdlMergeMasks(ObjectType,
|
|||
|
IsContainer,
|
|||
|
pAce,
|
|||
|
pNode
|
|||
|
);
|
|||
|
|
|||
|
return rc;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PSCEP_ADL_NODE
|
|||
|
ScepAdlLookup(
|
|||
|
IN ACE_HEADER *pAce,
|
|||
|
IN PSCEP_ADL_NODE *hTable
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine searches searches the Adl hTable for the converted pAce's entry and returns
|
|||
|
a pointer to it if present, else returns NULL
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN pAce - the Ace to convert to <SID,GUID1,GUID2> and search for
|
|||
|
IN hTable - the Adl in which pAce might exist
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The node corresponding to pAce if it found, else NULL
|
|||
|
*/
|
|||
|
{
|
|||
|
PSCEP_ADL_NODE pNode;
|
|||
|
PISID pSid = NULL;
|
|||
|
GUID *pGuidObjectType = NULL;
|
|||
|
GUID *pGuidInheritedObjectType = NULL;
|
|||
|
|
|||
|
switch ( pAce->AceType ) {
|
|||
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|||
|
case ACCESS_DENIED_ACE_TYPE:
|
|||
|
case SYSTEM_AUDIT_ACE_TYPE:
|
|||
|
case SYSTEM_ALARM_ACE_TYPE:
|
|||
|
|
|||
|
pSid = (PISID)&((PACCESS_ALLOWED_ACE)pAce)->SidStart;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|||
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|||
|
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
|
|||
|
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
|
|||
|
|
|||
|
pSid = (PISID)ScepObjectAceObjectType(pAce);
|
|||
|
pGuidObjectType = ScepObjectAceObjectType(pAce);
|
|||
|
pGuidInheritedObjectType = ScepObjectAceInheritedObjectType(pAce);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
// should not get in here since filtered out by caller ScepAdlLookupAdd()
|
|||
|
// in any case we do a check right after thsi switch
|
|||
|
;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// there might be something better we can do to handle this case
|
|||
|
//
|
|||
|
if (pSid == NULL)
|
|||
|
return NULL;
|
|||
|
|
|||
|
|
|||
|
for (pNode = hTable[(pSid->SubAuthority[pSid->SubAuthorityCount - 1] % SCEP_ADL_HTABLE_SIZE)];
|
|||
|
pNode != NULL; pNode = pNode->Next){
|
|||
|
|
|||
|
if ( ScepEqualSid(pNode->pSid, pSid) &&
|
|||
|
ScepEqualGuid(pNode->pGuidObjectType, pGuidObjectType) &&
|
|||
|
ScepEqualGuid(pNode->pGuidInheritedObjectType, pGuidInheritedObjectType) ) {
|
|||
|
|
|||
|
return pNode;
|
|||
|
}
|
|||
|
}
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepAddToAdlList(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN ACE_HEADER *pAce,
|
|||
|
OUT PSCEP_ADL_NODE *pAdlList
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine adds an ace to the head of the bucket into which pAce->Sid hashes (pAdlList)
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN ObjectType - the type of object, passed on to other functions
|
|||
|
IN IsContainer - whether container or not, passed on to other functions
|
|||
|
IN pAce - the Ace to convert and add
|
|||
|
OUT pAdlList - head of the bucket into which pAce->Sid hashes into
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Dos error code
|
|||
|
*/
|
|||
|
{
|
|||
|
|
|||
|
PSCEP_ADL_NODE pNode=NULL;
|
|||
|
|
|||
|
//
|
|||
|
// check arguments
|
|||
|
//
|
|||
|
if ( pAdlList == NULL || pAce == NULL )
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
|
|||
|
//
|
|||
|
// allocate a new node
|
|||
|
//
|
|||
|
pNode = (PSCEP_ADL_NODE)ScepAlloc( (UINT)0, sizeof(SCEP_ADL_NODE));
|
|||
|
|
|||
|
if ( pNode == NULL )
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
|
|||
|
pNode->pSid = NULL;
|
|||
|
pNode->pGuidObjectType = NULL;
|
|||
|
pNode->pGuidInheritedObjectType = NULL;
|
|||
|
pNode->AceType = pAce->AceType;
|
|||
|
pNode->Next = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// initialize the node with fields from pAce
|
|||
|
//
|
|||
|
|
|||
|
switch ( pAce->AceType ) {
|
|||
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|||
|
case ACCESS_DENIED_ACE_TYPE:
|
|||
|
case SYSTEM_AUDIT_ACE_TYPE:
|
|||
|
case SYSTEM_ALARM_ACE_TYPE:
|
|||
|
|
|||
|
pNode->pSid = (PISID)&((PACCESS_ALLOWED_ACE)pAce)->SidStart;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|||
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|||
|
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
|
|||
|
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
|
|||
|
|
|||
|
pNode->pSid = (PISID)ScepObjectAceObjectType(pAce);
|
|||
|
pNode->pGuidObjectType = ScepObjectAceObjectType(pAce);
|
|||
|
pNode->pGuidInheritedObjectType = ScepObjectAceInheritedObjectType(pAce);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
// should not get in here since filtered out by caller ScepAdlLookupAdd()
|
|||
|
ScepFree(pNode);
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// initialize all masks for this node
|
|||
|
//
|
|||
|
|
|||
|
pNode->dwEffectiveMask = 0;
|
|||
|
pNode->dw_CI_IO_Mask = 0;
|
|||
|
pNode->dw_OI_IO_Mask = 0;
|
|||
|
pNode->dw_NP_CI_IO_Mask = 0;
|
|||
|
|
|||
|
ScepAdlMergeMasks(ObjectType,
|
|||
|
IsContainer,
|
|||
|
pAce,
|
|||
|
pNode
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// add the node to the front of the list and link its next to the old list
|
|||
|
//
|
|||
|
|
|||
|
pNode->Next = *pAdlList;
|
|||
|
*pAdlList = pNode;
|
|||
|
|
|||
|
return(NO_ERROR);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ScepAdlMergeMasks(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN ACE_HEADER *pAce,
|
|||
|
IN PSCEP_ADL_NODE pNode
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The actual routine that merges the masks from pAce onto pNode
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN ObjectType - the type of object, passed on to other functions
|
|||
|
IN IsContainer - whether container or not, passed on to other functions
|
|||
|
IN pAce - the Ace to extract flags and OR with (source)
|
|||
|
IN pNode - the Adl node to update masks (target)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Nothing
|
|||
|
*/
|
|||
|
{
|
|||
|
DWORD dwMask = 0;
|
|||
|
|
|||
|
switch ( pAce->AceType ) {
|
|||
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|||
|
case ACCESS_DENIED_ACE_TYPE:
|
|||
|
case SYSTEM_AUDIT_ACE_TYPE:
|
|||
|
case SYSTEM_ALARM_ACE_TYPE:
|
|||
|
dwMask = ((PACCESS_ALLOWED_ACE)pAce)->Mask;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|||
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|||
|
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
|
|||
|
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
|
|||
|
|
|||
|
dwMask = ((PACCESS_ALLOWED_OBJECT_ACE)pAce)->Mask;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
// should not get in here since filtered out by all callers (3 deep)
|
|||
|
;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// if generic bits present, get the object specific masks
|
|||
|
//
|
|||
|
if ( dwMask & (GENERIC_READ |
|
|||
|
GENERIC_WRITE |
|
|||
|
GENERIC_EXECUTE |
|
|||
|
GENERIC_ALL)) {
|
|||
|
|
|||
|
switch ( ObjectType ) {
|
|||
|
case SE_DS_OBJECT:
|
|||
|
|
|||
|
RtlMapGenericMask (
|
|||
|
&dwMask,
|
|||
|
&DsGenMap
|
|||
|
);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case SE_SERVICE:
|
|||
|
|
|||
|
RtlMapGenericMask (
|
|||
|
&dwMask,
|
|||
|
&SvcGenMap
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case SE_REGISTRY_KEY:
|
|||
|
|
|||
|
RtlMapGenericMask (
|
|||
|
&dwMask,
|
|||
|
&KeyGenericMapping
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case SE_FILE_OBJECT:
|
|||
|
|
|||
|
RtlMapGenericMask (
|
|||
|
&dwMask,
|
|||
|
&FileGenericMapping
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
// if this happens, dwMask is not mapped to object specific bits
|
|||
|
;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// effective mask is updated for non-IO aces only
|
|||
|
//
|
|||
|
|
|||
|
if ( !(pAce->AceFlags & INHERIT_ONLY_ACE) ) {
|
|||
|
pNode->dwEffectiveMask |= dwMask;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// for non-containers, we don't care about the CI, OI masks (to simulate config)
|
|||
|
//
|
|||
|
|
|||
|
if (IsContainer) {
|
|||
|
|
|||
|
//
|
|||
|
// if NP, we only care about CI
|
|||
|
// else we care about CI, OI
|
|||
|
//
|
|||
|
|
|||
|
if (pAce->AceFlags & NO_PROPAGATE_INHERIT_ACE) {
|
|||
|
|
|||
|
if (pAce->AceFlags & CONTAINER_INHERIT_ACE) {
|
|||
|
pNode->dw_NP_CI_IO_Mask |= dwMask;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if ( (pAce->AceFlags & CONTAINER_INHERIT_ACE) )
|
|||
|
pNode->dw_CI_IO_Mask |= dwMask;
|
|||
|
if ( !(ObjectType & SE_REGISTRY_KEY) && (pAce->AceFlags & OBJECT_INHERIT_ACE) )
|
|||
|
pNode->dw_OI_IO_Mask |= dwMask;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ScepFreeAdl(
|
|||
|
IN PSCEP_ADL_NODE *hTable
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine frees the linked lists of nodes (buckets) and reset's them for further use
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN hTable - the hash-table to free
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Nothing
|
|||
|
*/
|
|||
|
{
|
|||
|
|
|||
|
if (hTable) {
|
|||
|
for (UINT bucketNum = 0; bucketNum < SCEP_ADL_HTABLE_SIZE; bucketNum++ ) {
|
|||
|
ScepFreeAdlList(hTable[bucketNum]);
|
|||
|
hTable[bucketNum] = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
SCESTATUS
|
|||
|
ScepFreeAdlList(
|
|||
|
IN PSCEP_ADL_NODE pAdlList
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the actual routine that frees the linked lists of nodes (buckets)
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN pAdlList - head of bucket to free
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Nothing
|
|||
|
*/
|
|||
|
{
|
|||
|
PSCEP_ADL_NODE pCurAdlNode;
|
|||
|
PSCEP_ADL_NODE pTempNode;
|
|||
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|||
|
|
|||
|
if ( pAdlList == NULL )
|
|||
|
return(rc);
|
|||
|
|
|||
|
pCurAdlNode = pAdlList;
|
|||
|
while ( pCurAdlNode != NULL ) {
|
|||
|
|
|||
|
pTempNode = pCurAdlNode;
|
|||
|
pCurAdlNode = pCurAdlNode->Next;
|
|||
|
|
|||
|
__try {
|
|||
|
ScepFree( pTempNode );
|
|||
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
rc = SCESTATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
return(rc);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ScepAnyExplicitAcl(
|
|||
|
IN PACL Acl,
|
|||
|
IN DWORD Processed,
|
|||
|
OUT PBOOL pExist
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine detects if there is any explicit ace in the Acl. The DWORD
|
|||
|
Processed is a bit mask of the aces already checked.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Acl - The Acl
|
|||
|
|
|||
|
Processed - The bit mask for the processed aces (so it won't be checked again)
|
|||
|
|
|||
|
pExist - The output flag to indicate if there is any explicit ace
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus=STATUS_SUCCESS;
|
|||
|
DWORD j;
|
|||
|
ACE_HEADER *pAce=NULL;
|
|||
|
|
|||
|
//
|
|||
|
// check output argument
|
|||
|
//
|
|||
|
if ( pExist == NULL )
|
|||
|
return(STATUS_INVALID_PARAMETER);
|
|||
|
|
|||
|
*pExist = FALSE;
|
|||
|
|
|||
|
if ( Acl == NULL )
|
|||
|
return(NtStatus);
|
|||
|
|
|||
|
for ( j=0; j<Acl->AceCount; j++ ) {
|
|||
|
if ( Processed & (1 << j) )
|
|||
|
continue;
|
|||
|
|
|||
|
NtStatus = RtlGetAce(Acl, j, (PVOID *)&pAce);
|
|||
|
if ( !NT_SUCCESS(NtStatus) )
|
|||
|
return(NtStatus);
|
|||
|
|
|||
|
if ( pAce == NULL )
|
|||
|
continue;
|
|||
|
|
|||
|
if ( !(pAce->AceFlags & INHERITED_ACE) ) {
|
|||
|
//
|
|||
|
// find a explicit Ace in Acl
|
|||
|
//
|
|||
|
*pExist = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
ScepEqualAce(
|
|||
|
IN SE_OBJECT_TYPE ObjectType,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN ACE_HEADER *pAce1,
|
|||
|
IN ACE_HEADER *pAce2
|
|||
|
)
|
|||
|
// compare two aces for exact match. The return BOOL value indicates the
|
|||
|
// match or not
|
|||
|
{
|
|||
|
PSID pSid1=NULL, pSid2=NULL;
|
|||
|
ACCESS_MASK Access1=0, Access2=0;
|
|||
|
|
|||
|
if ( pAce1 == NULL && pAce2 == NULL )
|
|||
|
return(TRUE);
|
|||
|
|
|||
|
if ( pAce1 == NULL || pAce2 == NULL )
|
|||
|
return(FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// compare ace access type
|
|||
|
//
|
|||
|
if ( pAce1->AceType != pAce2->AceType )
|
|||
|
return(FALSE);
|
|||
|
|
|||
|
|
|||
|
if ( IsContainer ) {
|
|||
|
//
|
|||
|
// compare ace inheritance flag
|
|||
|
//
|
|||
|
if ( pAce1->AceFlags != pAce2->AceFlags )
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
switch ( pAce1->AceType ) {
|
|||
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|||
|
case ACCESS_DENIED_ACE_TYPE:
|
|||
|
case SYSTEM_AUDIT_ACE_TYPE:
|
|||
|
case SYSTEM_ALARM_ACE_TYPE:
|
|||
|
pSid1 = (PSID)&((PACCESS_ALLOWED_ACE)pAce1)->SidStart;
|
|||
|
pSid2 = (PSID)&((PACCESS_ALLOWED_ACE)pAce2)->SidStart;
|
|||
|
Access1 = ((PACCESS_ALLOWED_ACE)pAce1)->Mask;
|
|||
|
Access2 = ((PACCESS_ALLOWED_ACE)pAce2)->Mask;
|
|||
|
break;
|
|||
|
|
|||
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|||
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|||
|
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
|
|||
|
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
|
|||
|
|
|||
|
if ( ((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->Flags !=
|
|||
|
((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->Flags ) {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
if ( ( ((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->Flags & ACE_OBJECT_TYPE_PRESENT ) ||
|
|||
|
( ((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT ) ) {
|
|||
|
//
|
|||
|
// at least one GUID exists
|
|||
|
//
|
|||
|
if ( !ScepEqualGuid( (GUID *)&((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->ObjectType,
|
|||
|
(GUID *)&((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->ObjectType ) ) {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
if ( ( ((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->Flags & ACE_OBJECT_TYPE_PRESENT ) &&
|
|||
|
( ((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT ) ) {
|
|||
|
//
|
|||
|
// the second GUID also exists
|
|||
|
//
|
|||
|
if ( !ScepEqualGuid( (GUID *)&((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->InheritedObjectType,
|
|||
|
(GUID *)&((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->InheritedObjectType) ) {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
pSid1 = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->SidStart;
|
|||
|
pSid2 = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->SidStart;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
pSid1 = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->InheritedObjectType;
|
|||
|
pSid2 = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->InheritedObjectType;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// none of the GUID exists
|
|||
|
//
|
|||
|
pSid1 = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->ObjectType;
|
|||
|
pSid2 = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->ObjectType;
|
|||
|
}
|
|||
|
|
|||
|
Access1 = ((PACCESS_ALLOWED_OBJECT_ACE)pAce1)->Mask;
|
|||
|
Access2 = ((PACCESS_ALLOWED_OBJECT_ACE)pAce2)->Mask;
|
|||
|
|
|||
|
|
|||
|
break;
|
|||
|
default:
|
|||
|
return(FALSE); // not recognized Ace type
|
|||
|
}
|
|||
|
|
|||
|
if ( pSid1 == NULL || pSid2 == NULL )
|
|||
|
//
|
|||
|
// no Sid, ignore the Ace
|
|||
|
//
|
|||
|
return(FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// compare the sids
|
|||
|
//
|
|||
|
if ( !EqualSid(pSid1, pSid2) )
|
|||
|
return(FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// access mask
|
|||
|
//
|
|||
|
// Translation is already done when calculating security descriptor
|
|||
|
// for file objects and registry objects
|
|||
|
//
|
|||
|
if ( Access1 != Access2 ) {
|
|||
|
switch ( ObjectType ) {
|
|||
|
case SE_DS_OBJECT:
|
|||
|
//
|
|||
|
// convert access mask of Access2 (from ProfileSD) for ds objects
|
|||
|
//
|
|||
|
|
|||
|
RtlMapGenericMask (
|
|||
|
&Access2,
|
|||
|
&DsGenMap
|
|||
|
);
|
|||
|
if ( Access1 != Access2)
|
|||
|
return(FALSE);
|
|||
|
break;
|
|||
|
|
|||
|
case SE_SERVICE:
|
|||
|
|
|||
|
RtlMapGenericMask (
|
|||
|
&Access2,
|
|||
|
&SvcGenMap
|
|||
|
);
|
|||
|
if ( Access1 != Access2)
|
|||
|
return(FALSE);
|
|||
|
break;
|
|||
|
|
|||
|
case SE_REGISTRY_KEY:
|
|||
|
|
|||
|
RtlMapGenericMask (
|
|||
|
&Access2,
|
|||
|
&KeyGenericMapping
|
|||
|
);
|
|||
|
if ( Access1 != Access2)
|
|||
|
return(FALSE);
|
|||
|
break;
|
|||
|
|
|||
|
case SE_FILE_OBJECT:
|
|||
|
|
|||
|
RtlMapGenericMask (
|
|||
|
&Access2,
|
|||
|
&FileGenericMapping
|
|||
|
);
|
|||
|
if ( Access1 != Access2)
|
|||
|
return(FALSE);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
SCESTATUS
|
|||
|
ScepAddToNameStatusList(
|
|||
|
OUT PSCE_NAME_STATUS_LIST *pNameList,
|
|||
|
IN PWSTR Name,
|
|||
|
IN ULONG Len,
|
|||
|
IN DWORD Status
|
|||
|
)
|
|||
|
/* ++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine adds a name (wchar) and a status to the name list.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pNameList - The name list to add to.
|
|||
|
|
|||
|
Name - The name to add
|
|||
|
|
|||
|
Len - number of wchars to add
|
|||
|
|
|||
|
Status - The value for the status field
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
Win32 error code
|
|||
|
-- */
|
|||
|
{
|
|||
|
|
|||
|
PSCE_NAME_STATUS_LIST pList=NULL;
|
|||
|
ULONG Length=Len;
|
|||
|
|
|||
|
if ( pNameList == NULL )
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
|
|||
|
if ( Name != NULL && Name[0] && Len == 0 )
|
|||
|
Length = wcslen(Name) + 1;
|
|||
|
|
|||
|
// if ( Length <= 1)
|
|||
|
// return(NO_ERROR);
|
|||
|
|
|||
|
pList = (PSCE_NAME_STATUS_LIST)ScepAlloc( (UINT)0, sizeof(SCE_NAME_STATUS_LIST));
|
|||
|
|
|||
|
if ( pList == NULL )
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
|
|||
|
if ( Name != NULL && Name[0] ) {
|
|||
|
pList->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (Length+1)*sizeof(TCHAR));
|
|||
|
if ( pList->Name == NULL ) {
|
|||
|
ScepFree(pList);
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
wcsncpy(pList->Name, Name, Length);
|
|||
|
} else
|
|||
|
pList->Name = NULL;
|
|||
|
|
|||
|
pList->Status = Status;
|
|||
|
pList->Next = *pNameList;
|
|||
|
*pNameList = pList;
|
|||
|
|
|||
|
return(NO_ERROR);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepAddToObjectList(
|
|||
|
OUT PSCE_OBJECT_LIST *pNameList,
|
|||
|
IN PWSTR Name,
|
|||
|
IN ULONG Len,
|
|||
|
IN BOOL IsContainer,
|
|||
|
IN BYTE Status,
|
|||
|
IN DWORD Count,
|
|||
|
IN BYTE byFlags
|
|||
|
)
|
|||
|
/* ++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine adds a name (wchar), a status, and a count to the name list.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pNameList - The name list to add to.
|
|||
|
|
|||
|
Name - The name to add
|
|||
|
|
|||
|
Len - number of wchars to add
|
|||
|
|
|||
|
Status - The value for the status field
|
|||
|
|
|||
|
Count - The value for the count field
|
|||
|
|
|||
|
byFlags - SCE_CHECK_DUP do not add for duplicates
|
|||
|
SCE_INCREASE_COUNT increase count by 1
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
Win32 error code
|
|||
|
-- */
|
|||
|
{
|
|||
|
|
|||
|
PSCE_OBJECT_LIST pList=NULL;
|
|||
|
ULONG Length=Len;
|
|||
|
|
|||
|
if ( pNameList == NULL )
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
|
|||
|
if ( Name == NULL )
|
|||
|
return(NO_ERROR);
|
|||
|
|
|||
|
if ( Len == 0 )
|
|||
|
Length = wcslen(Name);
|
|||
|
|
|||
|
if ( Length < 1)
|
|||
|
return(NO_ERROR);
|
|||
|
|
|||
|
if ( byFlags & SCE_CHECK_DUP ) {
|
|||
|
for ( pList = *pNameList; pList != NULL; pList = pList->Next ) {
|
|||
|
if ( _wcsnicmp( pList->Name, Name, Length) == 0 &&
|
|||
|
pList->Name[Length] == L'\0') {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if ( NULL != pList ) {
|
|||
|
//
|
|||
|
// already exist. return
|
|||
|
//
|
|||
|
if ( (byFlags & SCE_INCREASE_COUNT) && 0 == pList->Count ) {
|
|||
|
pList->Count++;
|
|||
|
}
|
|||
|
return(NO_ERROR);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
pList = (PSCE_OBJECT_LIST)ScepAlloc( (UINT)0, sizeof(SCE_OBJECT_LIST));
|
|||
|
|
|||
|
if ( pList == NULL )
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
|
|||
|
pList->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (Length+1)*sizeof(TCHAR));
|
|||
|
if ( pList->Name == NULL ) {
|
|||
|
ScepFree(pList);
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
wcsncpy(pList->Name, Name, Length);
|
|||
|
pList->Status = Status;
|
|||
|
pList->IsContainer = IsContainer;
|
|||
|
|
|||
|
if ( byFlags & SCE_INCREASE_COUNT && 0 == Count )
|
|||
|
pList->Count = 1;
|
|||
|
else
|
|||
|
pList->Count = Count;
|
|||
|
|
|||
|
pList->Next = *pNameList;
|
|||
|
*pNameList = pList;
|
|||
|
|
|||
|
return(NO_ERROR);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepGetNTDirectory(
|
|||
|
IN PWSTR *ppDirectory,
|
|||
|
IN PDWORD pDirSize,
|
|||
|
IN DWORD Flag
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine retrieves windows directory location or system directory
|
|||
|
location based on the input Flag. The output directory location must
|
|||
|
be freed by LocalFree after use.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ppDirectory - the output buffer holding the directory location.
|
|||
|
|
|||
|
pDirSize - The returned number of wchars of the output buffer
|
|||
|
|
|||
|
Flag - Flag to indicate directory
|
|||
|
1 = Windows directory
|
|||
|
2 = System directory
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Win32 error codes
|
|||
|
*/
|
|||
|
{
|
|||
|
DWORD dSize=0;
|
|||
|
DWORD rc=0;
|
|||
|
PWSTR pSubKey=NULL;
|
|||
|
PWSTR pValName=NULL;
|
|||
|
|
|||
|
if ( ppDirectory == NULL )
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
|
|||
|
switch ( Flag ) {
|
|||
|
case SCE_FLAG_WINDOWS_DIR: // windows directory
|
|||
|
dSize=GetSystemWindowsDirectory( *ppDirectory, 0 );
|
|||
|
break;
|
|||
|
case SCE_FLAG_SYSTEM_DIR: // system directory
|
|||
|
dSize=GetSystemDirectory( *ppDirectory, 0 );
|
|||
|
break;
|
|||
|
|
|||
|
case SCE_FLAG_DSDIT_DIR: // DS working directory
|
|||
|
case SCE_FLAG_DSLOG_DIR: // DS database log files directory
|
|||
|
case SCE_FLAG_SYSVOL_DIR: // Sysvol directory
|
|||
|
case SCE_FLAG_BOOT_DRIVE: // boot drive
|
|||
|
|
|||
|
// get the appropriate registry path and value name
|
|||
|
if ( SCE_FLAG_SYSVOL_DIR == Flag ) {
|
|||
|
pSubKey = szNetlogonKey;
|
|||
|
pValName = szSysvolValue;
|
|||
|
|
|||
|
} else if ( SCE_FLAG_BOOT_DRIVE == Flag ) {
|
|||
|
pSubKey = szSetupKey;
|
|||
|
pValName = szBootDriveValue;
|
|||
|
|
|||
|
} else {
|
|||
|
pSubKey = szNTDSKey;
|
|||
|
if ( SCE_FLAG_DSDIT_DIR == Flag ) {
|
|||
|
pValName = szDSDITValue;
|
|||
|
} else {
|
|||
|
pValName = szDSLOGValue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// query the value.
|
|||
|
// if this function is executed on a non DC, this function will fail
|
|||
|
// possibly with ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND
|
|||
|
// which in turn fails the translation.
|
|||
|
//
|
|||
|
DWORD RegType;
|
|||
|
rc = ScepRegQueryValue(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
pSubKey,
|
|||
|
pValName,
|
|||
|
(PVOID *)ppDirectory,
|
|||
|
&RegType
|
|||
|
);
|
|||
|
|
|||
|
if ( rc == ERROR_SUCCESS && RegType != REG_SZ ) {
|
|||
|
rc = ERROR_FILE_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
if ( rc == ERROR_SUCCESS && *ppDirectory ) {
|
|||
|
|
|||
|
if ( Flag == SCE_FLAG_SYSVOL_DIR ) {
|
|||
|
//
|
|||
|
// for sysvol path, it will look like d:\winnt\sysvol\sysvol.
|
|||
|
// we need to remove the last sysvol from this variable
|
|||
|
//
|
|||
|
PWSTR pTemp = ScepWcstrr(*ppDirectory, L"\\sysvol");
|
|||
|
if ( pTemp && (pTemp != *ppDirectory) &&
|
|||
|
_wcsnicmp(pTemp-7, L"\\sysvol",7 ) == 0 ) {
|
|||
|
|
|||
|
// terminate the string here
|
|||
|
*pTemp = L'\0';
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
dSize = wcslen(*ppDirectory);
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default: // invalid
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if ( dSize > 0 &&
|
|||
|
( SCE_FLAG_WINDOWS_DIR == Flag ||
|
|||
|
SCE_FLAG_SYSTEM_DIR == Flag ) ) {
|
|||
|
|
|||
|
*ppDirectory = (PWSTR)ScepAlloc(LMEM_ZEROINIT, (dSize+1)*sizeof(WCHAR));
|
|||
|
if ( *ppDirectory == NULL )
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
|
|||
|
switch ( Flag ) {
|
|||
|
case SCE_FLAG_WINDOWS_DIR: // windows directory
|
|||
|
dSize=GetSystemWindowsDirectory( *ppDirectory, dSize );
|
|||
|
break;
|
|||
|
case SCE_FLAG_SYSTEM_DIR: // system directory
|
|||
|
dSize=GetSystemDirectory( *ppDirectory, dSize );
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
*pDirSize = dSize;
|
|||
|
|
|||
|
if ( dSize == 0 ) {
|
|||
|
if ( *ppDirectory != NULL )
|
|||
|
ScepFree(*ppDirectory);
|
|||
|
*ppDirectory = NULL;
|
|||
|
|
|||
|
if ( rc ) {
|
|||
|
return(rc);
|
|||
|
} else if ( NO_ERROR == GetLastError() )
|
|||
|
return(ERROR_INVALID_DATA);
|
|||
|
else
|
|||
|
return(GetLastError());
|
|||
|
} else
|
|||
|
_wcsupr(*ppDirectory);
|
|||
|
|
|||
|
return(NO_ERROR);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepGetCurrentUserProfilePath(
|
|||
|
OUT PWSTR *ProfilePath
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
HANDLE Token;
|
|||
|
NTSTATUS NtStatus;
|
|||
|
DWORD rc;
|
|||
|
PVOID Info=NULL;
|
|||
|
DWORD ReturnLen, NewLen;
|
|||
|
UNICODE_STRING ProfileName;
|
|||
|
|
|||
|
|
|||
|
if (!OpenThreadToken( GetCurrentThread(),
|
|||
|
TOKEN_QUERY,
|
|||
|
FALSE,
|
|||
|
&Token)) {
|
|||
|
|
|||
|
if (!OpenProcessToken( GetCurrentProcess(),
|
|||
|
TOKEN_QUERY,
|
|||
|
&Token))
|
|||
|
|
|||
|
return(GetLastError());
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// get token user
|
|||
|
//
|
|||
|
NtStatus = NtQueryInformationToken (
|
|||
|
Token,
|
|||
|
TokenUser,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
&ReturnLen
|
|||
|
);
|
|||
|
if ( NtStatus == STATUS_BUFFER_TOO_SMALL ) {
|
|||
|
//
|
|||
|
// allocate buffer
|
|||
|
//
|
|||
|
Info = ScepAlloc(0, ReturnLen+1);
|
|||
|
|
|||
|
if ( Info != NULL ) {
|
|||
|
NtStatus = NtQueryInformationToken (
|
|||
|
Token,
|
|||
|
TokenUser,
|
|||
|
Info,
|
|||
|
ReturnLen,
|
|||
|
&NewLen
|
|||
|
);
|
|||
|
if ( NT_SUCCESS(NtStatus) ) {
|
|||
|
|
|||
|
ProfileName.Length = 0;
|
|||
|
|
|||
|
rc = ScepGetUsersProfileName(
|
|||
|
ProfileName,
|
|||
|
((PTOKEN_USER)Info)->User.Sid,
|
|||
|
FALSE,
|
|||
|
ProfilePath
|
|||
|
);
|
|||
|
} else
|
|||
|
rc = RtlNtStatusToDosError(NtStatus);
|
|||
|
|
|||
|
ScepFree(Info);
|
|||
|
|
|||
|
} else {
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
} else
|
|||
|
rc = RtlNtStatusToDosError(NtStatus);
|
|||
|
|
|||
|
CloseHandle(Token);
|
|||
|
|
|||
|
return(rc);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepGetUsersProfileName(
|
|||
|
IN UNICODE_STRING AssignedProfile,
|
|||
|
IN PSID AccountSid,
|
|||
|
IN BOOL bDefault,
|
|||
|
OUT PWSTR *UserProfilePath
|
|||
|
)
|
|||
|
{
|
|||
|
DWORD rc=ERROR_INVALID_PARAMETER;
|
|||
|
SID_IDENTIFIER_AUTHORITY *a;
|
|||
|
DWORD Len, i, j;
|
|||
|
WCHAR KeyName[356];
|
|||
|
PWSTR StrValue=NULL;
|
|||
|
PWSTR SystemRoot=NULL;
|
|||
|
DWORD DirSize=0;
|
|||
|
|
|||
|
|
|||
|
if ( AssignedProfile.Length > 0 && AssignedProfile.Buffer != NULL ) {
|
|||
|
//
|
|||
|
// use the assigned profile
|
|||
|
//
|
|||
|
*UserProfilePath = (PWSTR)ScepAlloc( LMEM_ZEROINIT, AssignedProfile.Length+2);
|
|||
|
if ( *UserProfilePath == NULL )
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
|
|||
|
wcsncpy(*UserProfilePath, AssignedProfile.Buffer, AssignedProfile.Length/2);
|
|||
|
return(NO_ERROR);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( AccountSid != NULL ) {
|
|||
|
//
|
|||
|
// look for this user's ProfileImageName in ProfileList in registry
|
|||
|
// if this user logged on the system once
|
|||
|
//
|
|||
|
|
|||
|
memset(KeyName, '\0', 356*sizeof(WCHAR));
|
|||
|
|
|||
|
swprintf(KeyName, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\");
|
|||
|
Len = wcslen(KeyName);
|
|||
|
|
|||
|
a = RtlIdentifierAuthoritySid(AccountSid);
|
|||
|
|
|||
|
swprintf(KeyName+Len, L"S-1-");
|
|||
|
for ( i=0; i<6; i++ ) {
|
|||
|
if ( a -> Value[i] > 0 )
|
|||
|
break;
|
|||
|
}
|
|||
|
for ( j=i; j<6; j++) {
|
|||
|
swprintf(KeyName+Len, L"%s%d", KeyName+Len, a -> Value[j]);
|
|||
|
}
|
|||
|
|
|||
|
for (i = 0; i < *RtlSubAuthorityCountSid(AccountSid); i++) {
|
|||
|
swprintf(KeyName+Len, L"%s-%d", KeyName+Len, *RtlSubAuthoritySid(AccountSid, i));
|
|||
|
}
|
|||
|
//
|
|||
|
// now the registry full path name for the user profile is built into KeyName
|
|||
|
//
|
|||
|
rc = ScepRegQueryValue(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
KeyName,
|
|||
|
L"ProfileImagePath",
|
|||
|
(PVOID *)&StrValue,
|
|||
|
&Len
|
|||
|
);
|
|||
|
|
|||
|
if ( rc == NO_ERROR && StrValue != NULL ) {
|
|||
|
//
|
|||
|
// translatethe name to expand environment variables
|
|||
|
//
|
|||
|
DirSize = ExpandEnvironmentStrings(StrValue, NULL, 0);
|
|||
|
if ( DirSize ) {
|
|||
|
|
|||
|
*UserProfilePath = (PWSTR)ScepAlloc(0, (DirSize+1)*sizeof(WCHAR));
|
|||
|
if ( *UserProfilePath ) {
|
|||
|
|
|||
|
if ( !ExpandEnvironmentStrings(StrValue, *UserProfilePath, DirSize) ) {
|
|||
|
// error occurs
|
|||
|
rc = GetLastError();
|
|||
|
|
|||
|
ScepFree(*UserProfilePath);
|
|||
|
*UserProfilePath = NULL;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
} else {
|
|||
|
rc = GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
ScepFree(StrValue);
|
|||
|
|
|||
|
return(rc);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
if ( StrValue ) {
|
|||
|
ScepFree(StrValue);
|
|||
|
StrValue = NULL;
|
|||
|
}
|
|||
|
//
|
|||
|
// if user is not assigned a profile explicitly, and there is no
|
|||
|
// profile created (under ProfileList), take the default profile
|
|||
|
//
|
|||
|
if ( bDefault ) {
|
|||
|
|
|||
|
rc = NO_ERROR;
|
|||
|
|
|||
|
#if _WINNT_WIN32>=0x0500
|
|||
|
//
|
|||
|
// Take the default user profile
|
|||
|
//
|
|||
|
DirSize = 355;
|
|||
|
GetDefaultUserProfileDirectory(KeyName, &DirSize);
|
|||
|
|
|||
|
if ( DirSize ) {
|
|||
|
//
|
|||
|
// length of "\\NTUSER.DAT" is 11
|
|||
|
//
|
|||
|
*UserProfilePath = (PWSTR)ScepAlloc( 0, (DirSize+12)*sizeof(WCHAR));
|
|||
|
|
|||
|
if ( *UserProfilePath ) {
|
|||
|
if ( DirSize > 355 ) {
|
|||
|
//
|
|||
|
// KeyName buffer is not enough, call again
|
|||
|
//
|
|||
|
Len = DirSize;
|
|||
|
if ( !GetDefaultUserProfileDirectory(*UserProfilePath, &Len) ) {
|
|||
|
//
|
|||
|
// error occurs, free the buffer
|
|||
|
//
|
|||
|
rc = GetLastError();
|
|||
|
|
|||
|
ScepFree(*UserProfilePath);
|
|||
|
*UserProfilePath = NULL;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// KeyName contains the directory
|
|||
|
//
|
|||
|
wcscpy(*UserProfilePath, KeyName);
|
|||
|
(*UserProfilePath)[DirSize] = L'\0';
|
|||
|
}
|
|||
|
//
|
|||
|
// append NTUSER.DAT to the end
|
|||
|
//
|
|||
|
if ( NO_ERROR == rc ) {
|
|||
|
wcscat(*UserProfilePath, L"\\NTUSER.DAT");
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
} else {
|
|||
|
rc = GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
#else
|
|||
|
//
|
|||
|
// for NT4: Take the default user profile
|
|||
|
//
|
|||
|
rc = ScepGetNTDirectory( &SystemRoot, &DirSize, SCE_FLAG_WINDOWS_DIR );
|
|||
|
|
|||
|
if ( NO_ERROR == rc ) {
|
|||
|
//
|
|||
|
// string to append to the %SystemRoot%
|
|||
|
//
|
|||
|
wcscpy(KeyName, L"\\Profiles\\Default User\\NTUSER.DAT");
|
|||
|
Len = wcslen(KeyName);
|
|||
|
|
|||
|
*UserProfilePath = (PWSTR)ScepAlloc( 0, (DirSize+Len+1)*sizeof(WCHAR));
|
|||
|
|
|||
|
if ( *UserProfilePath == NULL ) {
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
swprintf( *UserProfilePath, L"%s%s", SystemRoot, KeyName);
|
|||
|
}
|
|||
|
}
|
|||
|
if ( SystemRoot != NULL )
|
|||
|
ScepFree( SystemRoot);
|
|||
|
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
return(rc);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
SceAdjustPrivilege(
|
|||
|
IN ULONG Priv,
|
|||
|
IN BOOL Enable,
|
|||
|
IN HANDLE TokenToAdjust
|
|||
|
)
|
|||
|
/* ++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine enable/disable the specified privilege (Priv) to the current process.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Priv - The privilege to adjust
|
|||
|
|
|||
|
Enable - TRUE = enable, FALSE = disable
|
|||
|
|
|||
|
TokenToAdjust - The Token of current thread/process. It is optional
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
Win32 error code
|
|||
|
|
|||
|
-- */
|
|||
|
{
|
|||
|
HANDLE Token;
|
|||
|
NTSTATUS Status;
|
|||
|
TOKEN_PRIVILEGES Privs;
|
|||
|
|
|||
|
if ( TokenToAdjust == NULL ) {
|
|||
|
if (!OpenThreadToken( GetCurrentThread(),
|
|||
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|||
|
FALSE,
|
|||
|
&Token)) {
|
|||
|
|
|||
|
if (!OpenProcessToken( GetCurrentProcess(),
|
|||
|
TOKEN_ADJUST_PRIVILEGES,
|
|||
|
&Token))
|
|||
|
|
|||
|
return(GetLastError());
|
|||
|
|
|||
|
}
|
|||
|
} else
|
|||
|
Token = TokenToAdjust;
|
|||
|
|
|||
|
//
|
|||
|
// Token_privileges contains enough room for one privilege.
|
|||
|
//
|
|||
|
|
|||
|
Privs.PrivilegeCount = 1;
|
|||
|
Privs.Privileges[0].Luid = RtlConvertUlongToLuid(Priv); // RtlConvertLongToLuid(Priv);
|
|||
|
Privs.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
|
|||
|
|
|||
|
Status = NtAdjustPrivilegesToken(Token,
|
|||
|
FALSE,
|
|||
|
&Privs,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0);
|
|||
|
|
|||
|
if (TokenToAdjust == NULL )
|
|||
|
CloseHandle(Token);
|
|||
|
|
|||
|
return (RtlNtStatusToDosError( Status ) );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepGetEnvStringSize(
|
|||
|
IN LPVOID peb
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
if ( !peb ) {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
DWORD dwSize=0;
|
|||
|
|
|||
|
LPTSTR pTemp=(LPTSTR)peb;
|
|||
|
DWORD Len;
|
|||
|
|
|||
|
while ( *pTemp ) {
|
|||
|
Len = wcslen(pTemp);
|
|||
|
dwSize += Len+1;
|
|||
|
|
|||
|
pTemp += Len+1;
|
|||
|
|
|||
|
};
|
|||
|
|
|||
|
dwSize++;
|
|||
|
|
|||
|
return dwSize*sizeof(WCHAR);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//*************************************************************
|
|||
|
// Routines to handle events
|
|||
|
//*************************************************************
|
|||
|
|
|||
|
BOOL InitializeEvents (
|
|||
|
IN LPTSTR EventSourceName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Opens the event log
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
EventSourceName - the event's source name (usually dll or exe's name)
|
|||
|
|
|||
|
Return:
|
|||
|
|
|||
|
TRUE if successful
|
|||
|
FALSE if an error occurs
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
if ( hEventLog ) {
|
|||
|
//
|
|||
|
// already initialized
|
|||
|
//
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Open the event source
|
|||
|
//
|
|||
|
|
|||
|
if ( EventSourceName ) {
|
|||
|
|
|||
|
wcscpy(EventSource, EventSourceName);
|
|||
|
|
|||
|
hEventLog = RegisterEventSource(NULL, EventSource);
|
|||
|
|
|||
|
if (hEventLog) {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
EventSource[0] = L'\0';
|
|||
|
}
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
LogEvent(
|
|||
|
IN HINSTANCE hInstance,
|
|||
|
IN DWORD LogLevel,
|
|||
|
IN DWORD dwEventID,
|
|||
|
IN UINT idMsg,
|
|||
|
...)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Logs a verbose event to the event log
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hInstance - the resource dll instance
|
|||
|
|
|||
|
bLogLevel - the severity level of the log
|
|||
|
STATUS_SEVERITY_INFORMATIONAL
|
|||
|
STATUS_SEVERITY_WARNING
|
|||
|
STATUS_SEVERITY_ERROR
|
|||
|
|
|||
|
dwEventID - the event ID (defined in uevents.mc)
|
|||
|
|
|||
|
idMsg - Message id
|
|||
|
|
|||
|
Return:
|
|||
|
|
|||
|
TRUE if successful
|
|||
|
FALSE if an error occurs
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
TCHAR szMsg[MAX_PATH];
|
|||
|
TCHAR szErrorMsg[2*MAX_PATH+40];
|
|||
|
LPTSTR aStrings[2];
|
|||
|
WORD wType;
|
|||
|
va_list marker;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Check for the event log being open.
|
|||
|
//
|
|||
|
|
|||
|
if (!hEventLog ) {
|
|||
|
|
|||
|
if ( EventSource[0] == L'\0' ||
|
|||
|
!InitializeEvents(EventSource)) {
|
|||
|
return -1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Load the message
|
|||
|
//
|
|||
|
|
|||
|
if (idMsg != 0) {
|
|||
|
if (!LoadString (hInstance, idMsg, szMsg, MAX_PATH)) {
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
lstrcpy (szMsg, TEXT("%s"));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Plug in the arguments
|
|||
|
//
|
|||
|
szErrorMsg[0] = L'\0';
|
|||
|
va_start(marker, idMsg);
|
|||
|
|
|||
|
__try {
|
|||
|
wvsprintf(szErrorMsg, szMsg, marker);
|
|||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
|
|||
|
}
|
|||
|
va_end(marker);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Report the event to the eventlog
|
|||
|
//
|
|||
|
|
|||
|
aStrings[0] = szErrorMsg;
|
|||
|
|
|||
|
switch (LogLevel) {
|
|||
|
case STATUS_SEVERITY_WARNING:
|
|||
|
wType = EVENTLOG_WARNING_TYPE;
|
|||
|
break;
|
|||
|
case STATUS_SEVERITY_ERROR:
|
|||
|
wType = EVENTLOG_ERROR_TYPE;
|
|||
|
break;
|
|||
|
default:
|
|||
|
wType = EVENTLOG_INFORMATION_TYPE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (!ReportEvent(hEventLog,
|
|||
|
wType,
|
|||
|
0,
|
|||
|
dwEventID,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
0,
|
|||
|
(LPCTSTR *)aStrings,
|
|||
|
NULL) ) {
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int
|
|||
|
LogEventAndReport(
|
|||
|
IN HINSTANCE hInstance,
|
|||
|
IN LPTSTR LogFileName,
|
|||
|
IN DWORD LogLevel,
|
|||
|
IN DWORD dwEventID,
|
|||
|
IN UINT idMsg,
|
|||
|
...)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Logs a verbose event to the event log and logs
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hInstance - the resource dll handle
|
|||
|
|
|||
|
LofFileName - the log file also reported to
|
|||
|
|
|||
|
bLogLevel - the severity level of the log
|
|||
|
STATUS_SEVERITY_INFORMATIONAL
|
|||
|
STATUS_SEVERITY_WARNING
|
|||
|
STATUS_SEVERITY_ERROR
|
|||
|
|
|||
|
dwEventID - the event ID (defined in uevents.mc)
|
|||
|
|
|||
|
idMsg - Message id
|
|||
|
|
|||
|
Return:
|
|||
|
|
|||
|
TRUE if successful
|
|||
|
FALSE if an error occurs
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
TCHAR szMsg[MAX_PATH];
|
|||
|
TCHAR szErrorMsg[2*MAX_PATH+40];
|
|||
|
LPTSTR aStrings[2];
|
|||
|
WORD wType;
|
|||
|
va_list marker;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Load the message
|
|||
|
//
|
|||
|
|
|||
|
if (idMsg != 0) {
|
|||
|
if (!LoadString (hInstance, idMsg, szMsg, MAX_PATH)) {
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
lstrcpy (szMsg, TEXT("%s"));
|
|||
|
}
|
|||
|
|
|||
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|||
|
if ( LogFileName ) {
|
|||
|
hFile = CreateFile(LogFileName,
|
|||
|
GENERIC_WRITE,
|
|||
|
FILE_SHARE_READ,
|
|||
|
NULL,
|
|||
|
OPEN_ALWAYS,
|
|||
|
FILE_ATTRIBUTE_NORMAL,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|||
|
|
|||
|
DWORD dwBytesWritten;
|
|||
|
|
|||
|
SetFilePointer (hFile, 0, NULL, FILE_BEGIN);
|
|||
|
|
|||
|
BYTE TmpBuf[3];
|
|||
|
TmpBuf[0] = 0xFF;
|
|||
|
TmpBuf[1] = 0xFE;
|
|||
|
TmpBuf[2] = 0;
|
|||
|
|
|||
|
WriteFile (hFile, (LPCVOID)TmpBuf, 2,
|
|||
|
&dwBytesWritten,
|
|||
|
NULL);
|
|||
|
|
|||
|
SetFilePointer (hFile, 0, NULL, FILE_END);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check for the event log being open.
|
|||
|
//
|
|||
|
|
|||
|
if (!hEventLog && dwEventID > 0 ) {
|
|||
|
|
|||
|
if ( EventSource[0] == L'\0' ||
|
|||
|
!InitializeEvents(EventSource)) {
|
|||
|
|
|||
|
if ( INVALID_HANDLE_VALUE == hFile ) {
|
|||
|
return -1; // no event log and the log file can't be opened
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Plug in the arguments
|
|||
|
//
|
|||
|
szErrorMsg[0] = L'\0';
|
|||
|
va_start(marker, idMsg);
|
|||
|
|
|||
|
__try {
|
|||
|
wvsprintf(szErrorMsg, szMsg, marker);
|
|||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
|
|||
|
}
|
|||
|
va_end(marker);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Report the event to the eventlog
|
|||
|
//
|
|||
|
|
|||
|
int iRet = 0;
|
|||
|
|
|||
|
if ( hEventLog && dwEventID > 0 ) {
|
|||
|
|
|||
|
aStrings[0] = szErrorMsg;
|
|||
|
|
|||
|
switch (LogLevel) {
|
|||
|
case STATUS_SEVERITY_WARNING:
|
|||
|
wType = EVENTLOG_WARNING_TYPE;
|
|||
|
break;
|
|||
|
case STATUS_SEVERITY_ERROR:
|
|||
|
wType = EVENTLOG_ERROR_TYPE;
|
|||
|
break;
|
|||
|
default:
|
|||
|
wType = EVENTLOG_INFORMATION_TYPE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (!ReportEvent(hEventLog,
|
|||
|
wType,
|
|||
|
0,
|
|||
|
dwEventID,
|
|||
|
NULL,
|
|||
|
1,
|
|||
|
0,
|
|||
|
(LPCTSTR *)aStrings,
|
|||
|
NULL) ) {
|
|||
|
iRet = 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( INVALID_HANDLE_VALUE != hFile ) {
|
|||
|
//
|
|||
|
// Log to the log file
|
|||
|
//
|
|||
|
ScepWriteSingleUnicodeLog(hFile, FALSE, L"\r\n");
|
|||
|
ScepWriteSingleUnicodeLog(hFile, TRUE, szErrorMsg );
|
|||
|
|
|||
|
CloseHandle(hFile);
|
|||
|
}
|
|||
|
|
|||
|
return iRet;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
ShutdownEvents (void)
|
|||
|
/*++
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Stops the event log
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return:
|
|||
|
|
|||
|
TRUE if successful
|
|||
|
FALSE if an error occurs
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOL bRetVal = TRUE;
|
|||
|
HANDLE hTemp = hEventLog;
|
|||
|
|
|||
|
hEventLog = NULL;
|
|||
|
if (hTemp) {
|
|||
|
bRetVal = DeregisterEventSource(hTemp);
|
|||
|
}
|
|||
|
|
|||
|
EventSource[0] = L'\0';
|
|||
|
return bRetVal;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
SCESTATUS
|
|||
|
ScepConvertToSDDLFormat(
|
|||
|
IN LPTSTR pszValue,
|
|||
|
IN DWORD Len
|
|||
|
)
|
|||
|
{
|
|||
|
if ( pszValue == NULL || Len == 0 ) {
|
|||
|
return SCESTATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
ScepConvertSDDLSid(pszValue, L"DA", L"BA");
|
|||
|
|
|||
|
ScepConvertSDDLSid(pszValue, L"RP", L"RE");
|
|||
|
|
|||
|
ScepConvertSDDLAceType(pszValue, L"SA", L"AU");
|
|||
|
|
|||
|
ScepConvertSDDLAceType(pszValue, L"SM", L"AL");
|
|||
|
|
|||
|
ScepConvertSDDLAceType(pszValue, L"OM", L"OL");
|
|||
|
|
|||
|
return SCESTATUS_SUCCESS;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
ScepConvertSDDLSid(
|
|||
|
LPTSTR pszValue,
|
|||
|
PCWSTR szSearchFor, // only two letters are allowed
|
|||
|
PCWSTR szReplace
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
PWSTR pTemp = pszValue;
|
|||
|
DWORD i;
|
|||
|
|
|||
|
while ( pTemp && *pTemp != L'\0' ) {
|
|||
|
|
|||
|
pTemp = wcsstr(pTemp, szSearchFor);
|
|||
|
|
|||
|
if ( pTemp != NULL ) {
|
|||
|
|
|||
|
//
|
|||
|
// find the first non space char
|
|||
|
// must be : or ;
|
|||
|
//
|
|||
|
i=1;
|
|||
|
|
|||
|
while ( pTemp-i > pszValue && *(pTemp-i) == L' ' ) {
|
|||
|
i++;
|
|||
|
}
|
|||
|
|
|||
|
if ( pTemp-i > pszValue &&
|
|||
|
( *(pTemp-i) == L':' || *(pTemp-i) == L';') ) {
|
|||
|
|
|||
|
//
|
|||
|
// find the next non space char
|
|||
|
// must be ), O:, G:, D:, S:
|
|||
|
//
|
|||
|
|
|||
|
i=2;
|
|||
|
while ( *(pTemp+i) == L' ' ) {
|
|||
|
i++;
|
|||
|
}
|
|||
|
|
|||
|
if ( *(pTemp+i) == L')' ||
|
|||
|
( *(pTemp+i) != L'\0' && *(pTemp+i+1) == L':')) {
|
|||
|
//
|
|||
|
// find one, replace it
|
|||
|
//
|
|||
|
*pTemp = szReplace[0];
|
|||
|
*(pTemp+1) = szReplace[1];
|
|||
|
}
|
|||
|
|
|||
|
pTemp += 2;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// this is not a one to convert
|
|||
|
//
|
|||
|
pTemp += 2;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
ScepConvertSDDLAceType(
|
|||
|
LPTSTR pszValue,
|
|||
|
PCWSTR szSearchFor, // only two letters are allowed
|
|||
|
PCWSTR szReplace
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
PWSTR pTemp = pszValue;
|
|||
|
DWORD i;
|
|||
|
|
|||
|
while ( pTemp && *pTemp != L'\0' ) {
|
|||
|
|
|||
|
pTemp = wcsstr(pTemp, szSearchFor);
|
|||
|
|
|||
|
if ( pTemp != NULL ) {
|
|||
|
|
|||
|
//
|
|||
|
// find the first non space char
|
|||
|
// must be (
|
|||
|
//
|
|||
|
i=1;
|
|||
|
|
|||
|
while ( pTemp-i > pszValue && *(pTemp-i) == L' ' ) {
|
|||
|
i++;
|
|||
|
}
|
|||
|
|
|||
|
if ( pTemp-i > pszValue &&
|
|||
|
( *(pTemp-i) == L'(') ) {
|
|||
|
|
|||
|
//
|
|||
|
// find the next non space char
|
|||
|
// must be ;
|
|||
|
//
|
|||
|
|
|||
|
i=2;
|
|||
|
while ( *(pTemp+i) == L' ' ) {
|
|||
|
i++;
|
|||
|
}
|
|||
|
|
|||
|
if ( *(pTemp+i) == L';' ) {
|
|||
|
//
|
|||
|
// find one, replace it with AU
|
|||
|
//
|
|||
|
*pTemp = szReplace[0];
|
|||
|
*(pTemp+1) = szReplace[1];
|
|||
|
}
|
|||
|
|
|||
|
pTemp += 2;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// this is not a one to convert
|
|||
|
//
|
|||
|
pTemp += 2;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
SceIsSystemDatabase(
|
|||
|
IN LPCTSTR DatabaseName
|
|||
|
)
|
|||
|
/*
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Determine if the given database is the default system database
|
|||
|
|
|||
|
Argument:
|
|||
|
|
|||
|
DatabaseName - the database name (full path)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - the given database is the system database
|
|||
|
|
|||
|
FALSE - the database is not the system database or error occurred
|
|||
|
GetLastError() to get the error.
|
|||
|
*/
|
|||
|
{
|
|||
|
|
|||
|
if ( DatabaseName == NULL ) {
|
|||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
DWORD rc;
|
|||
|
PWSTR DefProfile=NULL;
|
|||
|
DWORD RegType;
|
|||
|
|
|||
|
/*
|
|||
|
// do not save system database in registry
|
|||
|
// always "hardcoded" to %windir%\security\database
|
|||
|
// query the system database name
|
|||
|
//
|
|||
|
rc = ScepRegQueryValue(
|
|||
|
HKEY_LOCAL_MACHINE,
|
|||
|
SCE_ROOT_PATH,
|
|||
|
L"DefaultProfile",
|
|||
|
(PVOID *)&DefProfile,
|
|||
|
&RegType
|
|||
|
);
|
|||
|
|
|||
|
if ( rc != NO_ERROR ) {
|
|||
|
*/
|
|||
|
//
|
|||
|
// use the default
|
|||
|
//
|
|||
|
PWSTR SysRoot=NULL;
|
|||
|
|
|||
|
RegType = 0;
|
|||
|
|
|||
|
rc = ScepGetNTDirectory( &SysRoot, &RegType, SCE_FLAG_WINDOWS_DIR );
|
|||
|
|
|||
|
if ( rc == NO_ERROR ) {
|
|||
|
|
|||
|
if ( SysRoot != NULL ) {
|
|||
|
|
|||
|
//
|
|||
|
// default location is %SystemRoot%\Security\Database\secedit.sdb
|
|||
|
//
|
|||
|
TCHAR TempName[256];
|
|||
|
|
|||
|
wcscpy(TempName, L"\\Security\\Database\\secedit.sdb");
|
|||
|
RegType += wcslen(TempName)+1;
|
|||
|
|
|||
|
DefProfile = (PWSTR)ScepAlloc( 0, RegType*sizeof(WCHAR));
|
|||
|
if ( DefProfile != NULL ) {
|
|||
|
swprintf(DefProfile, L"%s%s", SysRoot, TempName );
|
|||
|
|
|||
|
*(DefProfile+RegType-1) = L'\0';
|
|||
|
|
|||
|
} else
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
|
|||
|
|
|||
|
ScepFree(SysRoot);
|
|||
|
|
|||
|
} else
|
|||
|
rc = ERROR_INVALID_DATA;
|
|||
|
}
|
|||
|
// }
|
|||
|
|
|||
|
BOOL bRet=FALSE;
|
|||
|
|
|||
|
if ( (rc == NO_ERROR) && DefProfile ) {
|
|||
|
|
|||
|
if ( _wcsicmp(DefProfile, DatabaseName) == 0 ) {
|
|||
|
//
|
|||
|
// this is the system database
|
|||
|
//
|
|||
|
bRet = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ScepFree(DefProfile);
|
|||
|
|
|||
|
//
|
|||
|
// set last error and return
|
|||
|
//
|
|||
|
if ( bRet ) {
|
|||
|
SetLastError(ERROR_SUCCESS);
|
|||
|
} else {
|
|||
|
SetLastError(rc);
|
|||
|
}
|
|||
|
|
|||
|
return(bRet);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepWriteVariableUnicodeLog(
|
|||
|
IN HANDLE hFile,
|
|||
|
IN BOOL bAddCRLF,
|
|||
|
IN LPTSTR szFormat,
|
|||
|
...
|
|||
|
)
|
|||
|
{
|
|||
|
if ( INVALID_HANDLE_VALUE == hFile || NULL == hFile ||
|
|||
|
NULL == szFormat ) {
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
va_list args;
|
|||
|
LPTSTR lpDebugBuffer;
|
|||
|
DWORD rc=ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
|
|||
|
lpDebugBuffer = (LPTSTR) LocalAlloc (LPTR, 2048 * sizeof(TCHAR));
|
|||
|
|
|||
|
if (lpDebugBuffer) {
|
|||
|
|
|||
|
va_start( args, szFormat );
|
|||
|
|
|||
|
_vsnwprintf(lpDebugBuffer, 2048 - 1, szFormat, args);
|
|||
|
|
|||
|
va_end( args );
|
|||
|
|
|||
|
//
|
|||
|
// always put a CR/LF at the end
|
|||
|
//
|
|||
|
|
|||
|
DWORD dwBytesWritten;
|
|||
|
|
|||
|
if ( WriteFile (hFile, (LPCVOID) lpDebugBuffer,
|
|||
|
wcslen (lpDebugBuffer) * sizeof(WCHAR),
|
|||
|
&dwBytesWritten,
|
|||
|
NULL) ) {
|
|||
|
|
|||
|
if ( bAddCRLF ) {
|
|||
|
|
|||
|
WriteFile (hFile, (LPCVOID) c_szCRLF,
|
|||
|
2 * sizeof(WCHAR),
|
|||
|
&dwBytesWritten,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
rc = ERROR_SUCCESS;
|
|||
|
|
|||
|
} else {
|
|||
|
rc = GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
LocalFree(lpDebugBuffer);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return(rc);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepWriteSingleUnicodeLog(
|
|||
|
IN HANDLE hFile,
|
|||
|
IN BOOL bAddCRLF,
|
|||
|
IN LPWSTR szMsg
|
|||
|
)
|
|||
|
{
|
|||
|
if ( INVALID_HANDLE_VALUE == hFile ) {
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
DWORD dwBytesWritten;
|
|||
|
|
|||
|
if ( WriteFile (hFile, (LPCVOID) szMsg,
|
|||
|
wcslen (szMsg) * sizeof(WCHAR),
|
|||
|
&dwBytesWritten,
|
|||
|
NULL) ) {
|
|||
|
|
|||
|
if ( bAddCRLF) {
|
|||
|
// add \r\n to the end of the string
|
|||
|
WriteFile (hFile, (LPCVOID) c_szCRLF,
|
|||
|
2 * sizeof(WCHAR),
|
|||
|
&dwBytesWritten,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
return(ERROR_SUCCESS);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
return(GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+--------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: ScepWcstrr
|
|||
|
//
|
|||
|
// Synopsis: Returns ptr to rightmost occurence of pSubstring in pString, NULL if none
|
|||
|
//
|
|||
|
// Arguments: pString to look in, pSubstring to look for
|
|||
|
//
|
|||
|
// Returns: Returns ptr to rightmost occurence of pSubstring in pString, NULL if none
|
|||
|
//
|
|||
|
//+--------------------------------------------------------------------------
|
|||
|
WCHAR *
|
|||
|
ScepWcstrr(
|
|||
|
IN PWSTR pString,
|
|||
|
IN const WCHAR *pSubstring
|
|||
|
)
|
|||
|
{
|
|||
|
int i, j, k;
|
|||
|
|
|||
|
for (i = wcslen(pString) - wcslen(pSubstring) ; i >= 0; i-- ) {
|
|||
|
|
|||
|
for (j = i, k = 0; pSubstring[k] != L'\0' && towlower(pString[j]) == towlower(pSubstring[k]); j++, k++)
|
|||
|
;
|
|||
|
|
|||
|
if ( k > 0 && pSubstring[k] == L'\0')
|
|||
|
|
|||
|
return pString + i;
|
|||
|
}
|
|||
|
|
|||
|
return NULL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepExpandEnvironmentVariable(
|
|||
|
IN PWSTR oldFileName,
|
|||
|
IN PCWSTR szEnv,
|
|||
|
IN DWORD nFlag,
|
|||
|
OUT PWSTR *newFileName)
|
|||
|
/*
|
|||
|
Description:
|
|||
|
|
|||
|
Expand built-in environment variables known by SCE, including %SystemRoot%,
|
|||
|
%SystemDirectory%, %SystemDrive%, %DSDIT%, %DSLOG%, %SYSVOL%, %BOOTDRIVE%.
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
oldFileName - the file name to expand
|
|||
|
|
|||
|
szEnv - the environment variable to search for
|
|||
|
|
|||
|
nFlag - the corresponding system env variable flag
|
|||
|
SCE_FLAG_WINDOWS_DIR
|
|||
|
SCE_FLAG_SYSTEM_DIR
|
|||
|
SCE_FLAG_BOOT_DRIVE
|
|||
|
SCE_FLAG_DSDIT_DIR
|
|||
|
SCE_FLAG_DSLOG_DIR
|
|||
|
SCE_FLAG_SYSVOL_DIR
|
|||
|
|
|||
|
newFileName - the expanded file name if succeeded
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_FILE_NOT_FOUND if the environment varialbe is not found in the input file name
|
|||
|
|
|||
|
ERROR_SUCCESS if the env variable is successfully expanded
|
|||
|
|
|||
|
Otherwise, error code is returned.
|
|||
|
|
|||
|
*/
|
|||
|
{
|
|||
|
if ( oldFileName == NULL || szEnv == NULL || newFileName == NULL ) {
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
PWSTR pTemp = wcsstr( _wcsupr(oldFileName), szEnv);
|
|||
|
LPTSTR NtDir=NULL;
|
|||
|
DWORD newFileSize, dSize=0;
|
|||
|
DWORD rc = ERROR_FILE_NOT_FOUND;
|
|||
|
|
|||
|
if ( pTemp != NULL ) {
|
|||
|
//
|
|||
|
// found the environment variable
|
|||
|
//
|
|||
|
rc = ScepGetNTDirectory( &NtDir, &dSize, nFlag );
|
|||
|
|
|||
|
if ( NO_ERROR == rc && NtDir ) {
|
|||
|
|
|||
|
pTemp += wcslen(szEnv);
|
|||
|
BOOL bSysDrive=FALSE;
|
|||
|
|
|||
|
switch ( nFlag ) {
|
|||
|
case SCE_FLAG_WINDOWS_DIR:
|
|||
|
if ( _wcsicmp(szEnv, L"%SYSTEMDRIVE%") == 0 ) {
|
|||
|
dSize = 3;
|
|||
|
bSysDrive = TRUE;
|
|||
|
}
|
|||
|
break;
|
|||
|
case SCE_FLAG_BOOT_DRIVE:
|
|||
|
if ( *pTemp == L'\\' ) pTemp++; // NtDir contains the back slash already
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
newFileSize = dSize + wcslen(pTemp) + 1;
|
|||
|
*newFileName = (PWSTR)ScepAlloc( LMEM_ZEROINIT, newFileSize*sizeof(TCHAR));
|
|||
|
|
|||
|
if (*newFileName != NULL) {
|
|||
|
|
|||
|
if ( SCE_FLAG_WINDOWS_DIR == nFlag && bSysDrive ) {
|
|||
|
|
|||
|
// system drive letter
|
|||
|
**newFileName = NtDir[0];
|
|||
|
if ( pTemp[0] )
|
|||
|
swprintf(*newFileName+1, L":%s", _wcsupr(pTemp));
|
|||
|
else
|
|||
|
swprintf(*newFileName+1, L":\\");
|
|||
|
|
|||
|
} else {
|
|||
|
swprintf(*newFileName, L"%s%s", NtDir, _wcsupr(pTemp));
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
|
|||
|
} else if ( NO_ERROR == rc && !NtDir ) {
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
if ( NtDir ) {
|
|||
|
ScepFree(NtDir);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(rc);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepEnforcePolicyPropagation()
|
|||
|
{
|
|||
|
|
|||
|
DWORD rc;
|
|||
|
HKEY hKey1=NULL;
|
|||
|
HKEY hKey=NULL;
|
|||
|
DWORD RegType;
|
|||
|
DWORD dwInterval=0;
|
|||
|
DWORD DataSize=sizeof(DWORD);
|
|||
|
|
|||
|
if(( rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|||
|
GPT_SCEDLL_NEW_PATH,
|
|||
|
0,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&hKey
|
|||
|
)) == ERROR_SUCCESS ) {
|
|||
|
|
|||
|
rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|||
|
SCE_ROOT_PATH,
|
|||
|
0,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&hKey1
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == rc ) {
|
|||
|
|
|||
|
if ( ERROR_SUCCESS != RegQueryValueEx(hKey1,
|
|||
|
TEXT("GPOSavedInterval"),
|
|||
|
0,
|
|||
|
&RegType,
|
|||
|
(BYTE *)&dwInterval,
|
|||
|
&DataSize
|
|||
|
) ) {
|
|||
|
//
|
|||
|
// either the value doesn't exist or fail to read it.
|
|||
|
// In either case, it's considered as no backup value
|
|||
|
// Now query the current value and save it
|
|||
|
//
|
|||
|
DataSize = sizeof(DWORD);
|
|||
|
if ( ERROR_SUCCESS != RegQueryValueEx(hKey,
|
|||
|
TEXT("MaxNoGPOListChangesInterval"),
|
|||
|
0,
|
|||
|
&RegType,
|
|||
|
(BYTE *)&dwInterval,
|
|||
|
&DataSize
|
|||
|
) ) {
|
|||
|
dwInterval = 960;
|
|||
|
}
|
|||
|
|
|||
|
rc = RegSetValueEx( hKey1,
|
|||
|
TEXT("GPOSavedInterval"),
|
|||
|
0,
|
|||
|
REG_DWORD,
|
|||
|
(BYTE *)&dwInterval,
|
|||
|
sizeof(DWORD)
|
|||
|
);
|
|||
|
|
|||
|
} // else if the value already exists, don't need to save it again
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == rc ) {
|
|||
|
dwInterval = 1;
|
|||
|
rc = RegSetValueEx( hKey,
|
|||
|
TEXT("MaxNoGPOListChangesInterval"),
|
|||
|
0,
|
|||
|
REG_DWORD,
|
|||
|
(BYTE *)&dwInterval,
|
|||
|
sizeof(DWORD)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// close the keys
|
|||
|
//
|
|||
|
if ( hKey1 )
|
|||
|
RegCloseKey( hKey1 );
|
|||
|
|
|||
|
if ( hKey )
|
|||
|
RegCloseKey( hKey );
|
|||
|
|
|||
|
return(rc);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepGetTimeStampString(
|
|||
|
IN OUT PWSTR pvBuffer
|
|||
|
)
|
|||
|
/*
|
|||
|
Retrun long format of date/time string based on the locale.
|
|||
|
*/
|
|||
|
{
|
|||
|
if ( pvBuffer == NULL ) {
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
DWORD rc;
|
|||
|
LARGE_INTEGER CurrentTime;
|
|||
|
LARGE_INTEGER SysTime;
|
|||
|
TIME_FIELDS TimeFields;
|
|||
|
NTSTATUS NtStatus;
|
|||
|
|
|||
|
FILETIME ft;
|
|||
|
SYSTEMTIME st;
|
|||
|
|
|||
|
NtStatus = NtQuerySystemTime(&SysTime);
|
|||
|
rc = RtlNtStatusToDosError(NtStatus);
|
|||
|
|
|||
|
RtlSystemTimeToLocalTime (&SysTime,&CurrentTime);
|
|||
|
|
|||
|
if ( NT_SUCCESS(NtStatus) &&
|
|||
|
(CurrentTime.LowPart != 0 || CurrentTime.HighPart != 0) ) {
|
|||
|
|
|||
|
rc = ERROR_SUCCESS;
|
|||
|
|
|||
|
ft.dwLowDateTime = CurrentTime.LowPart;
|
|||
|
ft.dwHighDateTime = CurrentTime.HighPart;
|
|||
|
|
|||
|
if ( !FileTimeToSystemTime(&ft, &st) ) {
|
|||
|
|
|||
|
rc = GetLastError();
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// format date/time into the right locale format
|
|||
|
//
|
|||
|
|
|||
|
TCHAR szDate[32];
|
|||
|
TCHAR szTime[32];
|
|||
|
|
|||
|
//
|
|||
|
// GetDateFormat is the NLS routine that formats a time in a
|
|||
|
// locale-sensitive fashion.
|
|||
|
//
|
|||
|
if (0 == GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE,
|
|||
|
&st, NULL,szDate, 32)) {
|
|||
|
rc = GetLastError();
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// GetTimeFormat is the NLS routine that formats a time in a
|
|||
|
// locale-sensitive fashion.
|
|||
|
//
|
|||
|
if (0 == GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &st, NULL, szTime, 32)) {
|
|||
|
|
|||
|
rc = GetLastError();
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Concatenate date and time
|
|||
|
//
|
|||
|
wcscpy(pvBuffer, szDate);
|
|||
|
wcscat(pvBuffer, L" ");
|
|||
|
wcscat(pvBuffer, szTime);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// if can't get the system time in right locale,
|
|||
|
// print it in the current (default) format
|
|||
|
//
|
|||
|
if ( rc != NO_ERROR ) {
|
|||
|
|
|||
|
memset(&TimeFields, 0, sizeof(TIME_FIELDS));
|
|||
|
|
|||
|
RtlTimeToTimeFields (
|
|||
|
&CurrentTime,
|
|||
|
&TimeFields
|
|||
|
);
|
|||
|
if ( TimeFields.Month > 0 && TimeFields.Month <= 12 &&
|
|||
|
TimeFields.Day > 0 && TimeFields.Day <= 31 &&
|
|||
|
TimeFields.Year > 1600 ) {
|
|||
|
|
|||
|
swprintf(pvBuffer, L"%02d/%02d/%04d %02d:%02d:%02d\0",
|
|||
|
TimeFields.Month, TimeFields.Day, TimeFields.Year,
|
|||
|
TimeFields.Hour, TimeFields.Minute, TimeFields.Second);
|
|||
|
} else {
|
|||
|
swprintf(pvBuffer, L"%08x08x\0", CurrentTime.HighPart, CurrentTime.LowPart);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
rc = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
return(rc);
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepAppendCreateMultiSzRegValue(
|
|||
|
IN HKEY hKeyRoot,
|
|||
|
IN PWSTR pszSubKey,
|
|||
|
IN PWSTR pszValueName,
|
|||
|
IN PWSTR pszValueValue
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will append(if existing)/create(if not existing) w.r.t. MULTI_SZ values
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKeyRoot - root such as HKEY_LOCAL_MACHINE
|
|||
|
pszSubKey - subkey such as "Software\\Microsoft\\Windows NT\\CurrentVersion\\SeCEdit"
|
|||
|
pszValueName - value name of the key to be changed
|
|||
|
pszValueValue - value of the value name to be changed
|
|||
|
|
|||
|
|
|||
|
Return:
|
|||
|
|
|||
|
error code (DWORD)
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
DWORD rc = ERROR_SUCCESS;
|
|||
|
DWORD dwSize = 0;
|
|||
|
HKEY hKey = NULL;
|
|||
|
DWORD dwNewKey = NULL;
|
|||
|
DWORD dwRegType = 0;
|
|||
|
|
|||
|
if (hKeyRoot == NULL || pszSubKey == NULL || pszValueName == NULL || pszValueValue == NULL) {
|
|||
|
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if(( rc = RegOpenKeyEx(hKeyRoot,
|
|||
|
pszSubKey,
|
|||
|
0,
|
|||
|
KEY_SET_VALUE | KEY_QUERY_VALUE ,
|
|||
|
&hKey
|
|||
|
)) != ERROR_SUCCESS ) {
|
|||
|
|
|||
|
rc = RegCreateKeyEx(
|
|||
|
hKeyRoot,
|
|||
|
pszSubKey,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_WRITE,
|
|||
|
NULL,
|
|||
|
&hKey,
|
|||
|
&dwNewKey
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == rc ) {
|
|||
|
|
|||
|
//
|
|||
|
// need to read the MULTI_SZ, append to it and set then new MULTI_SZ value
|
|||
|
//
|
|||
|
|
|||
|
rc = RegQueryValueEx(hKey,
|
|||
|
pszValueName,
|
|||
|
0,
|
|||
|
&dwRegType,
|
|||
|
NULL,
|
|||
|
&dwSize
|
|||
|
);
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == rc || ERROR_FILE_NOT_FOUND == rc ) {
|
|||
|
|
|||
|
//
|
|||
|
// dwSize is always size in bytes
|
|||
|
//
|
|||
|
|
|||
|
DWORD dwBytesToAdd = 0;
|
|||
|
|
|||
|
//
|
|||
|
// if dwUnicodeSize == 0, then MULTI_SZ value was non-existent before
|
|||
|
//
|
|||
|
|
|||
|
DWORD dwUnicodeSize = (dwSize >= 2 ? dwSize/2 - 1 : 0);
|
|||
|
|
|||
|
dwBytesToAdd = 2 * (wcslen(pszValueValue) + 2);
|
|||
|
|
|||
|
PWSTR pszValue = (PWSTR)ScepAlloc( LMEM_ZEROINIT, dwSize + dwBytesToAdd) ;
|
|||
|
|
|||
|
if ( pszValue != NULL ) {
|
|||
|
|
|||
|
rc = RegQueryValueEx(hKey,
|
|||
|
pszValueName,
|
|||
|
0,
|
|||
|
&dwRegType,
|
|||
|
(BYTE *)pszValue,
|
|||
|
&dwSize
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// append pszValueValue to the end of the MULTI_SZ taking care of duplicates
|
|||
|
// i.e. abc\0def\0ghi\0\0 to something like
|
|||
|
// abc\0def\0ghi\0jkl\0\0
|
|||
|
//
|
|||
|
|
|||
|
if ( ScepMultiSzWcsstr(pszValue, pszValueValue) == NULL ) {
|
|||
|
|
|||
|
memcpy(pszValue + dwUnicodeSize, pszValueValue, dwBytesToAdd);
|
|||
|
memset(pszValue + dwUnicodeSize + (dwBytesToAdd/2 - 2), '\0', 4);
|
|||
|
|
|||
|
if ( ERROR_SUCCESS == rc || ERROR_FILE_NOT_FOUND == rc) {
|
|||
|
|
|||
|
rc = RegSetValueEx( hKey,
|
|||
|
pszValueName,
|
|||
|
0,
|
|||
|
REG_MULTI_SZ,
|
|||
|
(BYTE *)pszValue,
|
|||
|
(dwUnicodeSize == 0 ? dwSize + dwBytesToAdd : dwSize + dwBytesToAdd - 2)
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ScepFree(pszValue);
|
|||
|
}
|
|||
|
|
|||
|
else {
|
|||
|
|
|||
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if( hKey )
|
|||
|
RegCloseKey( hKey );
|
|||
|
|
|||
|
return rc;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
PWSTR
|
|||
|
ScepMultiSzWcsstr(
|
|||
|
PWSTR pszStringToSearchIn,
|
|||
|
PWSTR pszStringToSearchFor
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
MULTI_SZ version of wcsstr
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pszStringToSearchIn - \0\0 terminated string to search in (MULTI_SZ)
|
|||
|
pszStringToSearchFor - \0 terminated string to search for (regular unicode string)
|
|||
|
|
|||
|
Return:
|
|||
|
|
|||
|
pointer to first occurence of pszStringToSearchFor in pszStringToSearchIn
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PWSTR pszCurrString = NULL;
|
|||
|
|
|||
|
if (pszStringToSearchIn == NULL || pszStringToSearchFor == NULL) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (pszStringToSearchFor[0] == L'\0' ||
|
|||
|
(pszStringToSearchIn[0] == L'\0' && pszStringToSearchIn[1] == L'\0') ) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
pszCurrString = pszStringToSearchIn;
|
|||
|
|
|||
|
__try {
|
|||
|
|
|||
|
while ( !(pszCurrString[0] == L'\0' && pszCurrString[1] == L'\0') ) {
|
|||
|
|
|||
|
if ( NULL != wcsstr(pszCurrString, pszStringToSearchFor) ) {
|
|||
|
return pszCurrString;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// so, if C:\0E:\0\0, advance pszCurrString to the first \0 at the end ie. C:\0E:\0\0
|
|||
|
// ^ ^
|
|||
|
|
|||
|
pszCurrString += wcslen(pszCurrString) ;
|
|||
|
|
|||
|
if (pszCurrString[0] == L'\0' && pszCurrString[1] == L'\0') {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// if it stopped at C:\0E:\0\0, advance pszCurrString C:\0E:\0\0
|
|||
|
// ^ ^
|
|||
|
|
|||
|
pszCurrString += 1;
|
|||
|
}
|
|||
|
|
|||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ScepEscapeString(
|
|||
|
IN const PWSTR pszSource,
|
|||
|
IN const DWORD dwSourceChars,
|
|||
|
IN const WCHAR wcEscapee,
|
|||
|
IN const WCHAR wcEscaper,
|
|||
|
IN OUT PWSTR pszTarget
|
|||
|
)
|
|||
|
|
|||
|
/* ++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Escapes escapee with escaper i.e.
|
|||
|
|
|||
|
escapee -> escaper escapee escaper
|
|||
|
|
|||
|
e.g. a,\0b\0c\0\0 -> a","\0b\0c\0\0
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pszSource - The source string
|
|||
|
|
|||
|
dwSourceChars - The number of chars in pszSource
|
|||
|
|
|||
|
wcEscapee - The escapee
|
|||
|
|
|||
|
wcEscaper - The escaper
|
|||
|
|
|||
|
pszTarget - The destination string
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
Number of characters copied to the target
|
|||
|
|
|||
|
-- */
|
|||
|
{
|
|||
|
|
|||
|
DWORD dwTargetChars = 0;
|
|||
|
|
|||
|
for (DWORD dwIndex=0; dwIndex < dwSourceChars; dwIndex++) {
|
|||
|
|
|||
|
if ( pszSource[dwIndex] == wcEscapee ){
|
|||
|
pszTarget[0] = wcEscaper;
|
|||
|
pszTarget[1] = wcEscapee;
|
|||
|
pszTarget[2] = wcEscaper;
|
|||
|
pszTarget += 3;
|
|||
|
dwTargetChars +=3;
|
|||
|
}
|
|||
|
else {
|
|||
|
pszTarget[0] = pszSource[dwIndex];
|
|||
|
pszTarget++;
|
|||
|
++dwTargetChars ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return dwTargetChars;
|
|||
|
}
|
|||
|
|