Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5498 lines
132 KiB

/*++
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;
}