windows-nt/Source/XPSP1/NT/admin/snapin/wsecmgr/util.cpp

3431 lines
94 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1998.
//
// File: util.cpp
//
// Contents: Miscellaneous utility functions
//
// History:
//
//---------------------------------------------------------------------------
#include "stdafx.h"
#include "util.h"
#include "wrapper.h"
#include "defvals.h"
#include "resource.h"
#include <io.h>
#include "snapmgr.h"
extern "C" {
#include "getuser.h"
}
//////////////////////////////////////////////////////////////////////////////////////////
// CWriteHmtlFile body.
//
//+-------------------------------------------------------------------------------------------
// CWriteHtmlFile::CWriteHtmlFile
//
// Initialize the class.
//
//--------------------------------------------------------------------------------------------
CWriteHtmlFile::CWriteHtmlFile()
{
m_hFileHandle = INVALID_HANDLE_VALUE;
m_bErrored = FALSE;
}
//+-------------------------------------------------------------------------------------------
// CWriteHtmlFile::~CWriteHtmlFile
//
// Write the end of the html file and close the handle.
//
//--------------------------------------------------------------------------------------------
CWriteHtmlFile::~CWriteHtmlFile()
{
//
// Close the file handle, but don't delete the HTML file, unless there was an
// error during some write proccess.
//
Close(m_bErrored);
}
//+-------------------------------------------------------------------------------------------
// CWriteHtmlFile::Close
//
// Closes the HTML file handle, if [bDelete] is true then the file is deleted.
//
// Arguments: [bDelete] - Close and delete the file.
//
// Returns: ERROR_SUCCESS;
//--------------------------------------------------------------------------------------------
DWORD
CWriteHtmlFile::Close( BOOL bDelete )
{
if(m_hFileHandle == INVALID_HANDLE_VALUE){
return ERROR_SUCCESS;
}
if(bDelete){
CloseHandle(m_hFileHandle);
DeleteFile(m_strFileName );
} else {
Write( IDS_HTMLERR_END );
CloseHandle( m_hFileHandle );
}
m_hFileHandle = INVALID_HANDLE_VALUE;
return ERROR_SUCCESS;
}
//+-------------------------------------------------------------------------------------------
// CWriteHtmlFile::GetFileName
//
// Copies the file name associated with this class to [pstrFileName].
//
// Arguments: [pstrFileName] - A CString object which will contain the file name
// on return.
//
// Returns: 0 - If Create has not been called, or the HTML file is invalid for
// some reason. This could be caused by a bad write.
// The size in characters of the file name.
//
//--------------------------------------------------------------------------------------------
int CWriteHtmlFile::GetFileName( LPTSTR pszFileName, UINT nSize )
{
if(m_strFileName.IsEmpty() || m_hFileHandle == INVALID_HANDLE_VALUE || m_bErrored){
return 0;
}
if(pszFileName && (int)nSize > m_strFileName.GetLength()){
lstrcpy(pszFileName, m_strFileName);
}
return m_strFileName.GetLength();
}
//+-------------------------------------------------------------------------------------------
// CWriteHtmlFile::Write
//
// Writes a string resource to the html file at the current file position.
//
// Arguments: [uRes] - The String resource to load and write to the html.
//
// Returns: If the string can't be loaded then an error will be returned.
// See CWriteHtmlFile::Write( LPCTSTR ) for other errors.
//--------------------------------------------------------------------------------------------
DWORD
CWriteHtmlFile::Write( UINT uRes )
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CString str;
if( !str.LoadString(uRes) ){
return GetLastError();
}
#if defined(UNICODE) || defined(_UNICODE)
if ( uRes == IDS_HTMLERR_HEADER ){
WCHAR wszByteOrderMark[2] = {0xFEFF, 0x0000};
CString strByteOrderMark = wszByteOrderMark;
return Write( strByteOrderMark + str );
} else
#endif
return Write( str );
}
//+-------------------------------------------------------------------------------------------
// CWriteHtmlFile::Write
//
// Writes a string to an html file.
//
// Arguments: [pszString] - The string to write.
//
// Returns: ERROR_NOT_READ - if Create has not been called, or the file could not
// not be created.
// Other errors returned by WriteFile();
//--------------------------------------------------------------------------------------------
DWORD
CWriteHtmlFile::Write(LPCTSTR pszString, ... )
{
if(m_hFileHandle == INVALID_HANDLE_VALUE)
{
return ERROR_NOT_READY;
}
TCHAR szWrite[2048];
va_list marker;
va_start(marker, pszString);
#if defined(UNICODE) || defined(_UNICODE)
vswprintf( szWrite, pszString, marker );
#else
vsprintf( szWrite, pszString, marker );
#endif
va_end(marker);
DWORD dwRight;
if( !WriteFile( m_hFileHandle, szWrite, sizeof(TCHAR) * lstrlen(szWrite), &dwRight, NULL) )
{
//
// Check the error state of the right. Set m_bErrored if there was something wrong
// with the write.
//
dwRight = GetLastError();
if(dwRight != ERROR_SUCCESS)
{
m_bErrored = TRUE;
}
}
else
{
dwRight = ERROR_SUCCESS;
}
return dwRight;
}
DWORD
CWriteHtmlFile::CopyTextFile(
LPCTSTR pszFile,
DWORD dwPosLow,
BOOL bInterpret
)
{
HANDLE handle;
//
// Try to open the file for reading.
//
handle = ExpandAndCreateFile( pszFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
if(handle == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
LONG dwPosHigh = 0;
WCHAR szText[256];
char szRead[256];
BOOL IsMulti;
DWORD isUnicode;
//
// Determine if the file is a unicode text file.
//
ReadFile(handle, szText, 100 * sizeof(WCHAR), (DWORD *)&dwPosHigh, NULL );
if(dwPosHigh )
{
isUnicode = IsTextUnicode( szText, dwPosHigh, NULL );
}
//
// Set the pos we want to start from
//
dwPosHigh = 0;
SetFilePointer( handle, dwPosLow, &dwPosHigh, FILE_BEGIN );
if( GetLastError() != ERROR_SUCCESS )
{
return GetLastError();
}
DWORD dwErr = ERROR_SUCCESS;
do
{
start:
//
// Read 254 total bytes from the file. We don't care about the error returned
// by read, as long as read does not set dwPosHigh to something.
//
dwPosHigh = 0;
ReadFile( handle, szRead, 254, (DWORD *)&dwPosHigh, NULL );
//
// If the file is not considered unicode then convert it to a unicode file.
//
ZeroMemory(szText, sizeof(WCHAR) * 256);
if(!isUnicode)
{
dwPosHigh = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szRead, dwPosHigh, szText, 255 );
}
else
{
//
// Just copy the text to the szText buffer and get the number of UNICODE
// characters.
//
memcpy(szText, szRead, dwPosHigh);
dwPosHigh = wcslen(szText);
}
PWSTR pszWrite = szText;
LONG i = 0;
if( bInterpret )
{
//
// Write out line breaks.
//
for(;i < dwPosHigh; i++)
{
//Bug 141526, Yanggao, 3/20/2001
if( L'<' == szText[i] )
{
szText[i] = 0;
Write(pszWrite);
Write(L"&lt");
pszWrite = &(szText[i + 1]);
}
if( L'\r' == szText[i] || L'\n' == szText[i] )
{
if( i + 1 >= dwPosHigh )
{
szText[i] = 0;
Write(pszWrite);
SetFilePointer( handle, -(isUnicode ? 2:1), NULL, FILE_CURRENT);
//
// Read once again.
//
goto start;
}
//
// Check to see if this is a valid line break
//
i++;
if( L'\r' == szText[i] || L'\n' == szText[i] &&
szText[i] != szText[i - 1] )
{
szText[i - 1] = 0;
dwErr = Write( pszWrite );
if( dwErr != ERROR_SUCCESS)
{
break;
}
dwErr = Write( L"<BR>" );
if( dwErr != ERROR_SUCCESS)
{
break;
}
pszWrite = &(szText[i + 1]);
}
else
{
//
// This is not a valid line break, contintue with check with next character
//
i--;
}
}
}
}
//
// Write the rest of the text.
//
if(dwErr == ERROR_SUCCESS)
{
Write( pszWrite );
}
else
{
break;
}
} while( dwPosHigh );
CloseHandle(handle );
return ERROR_SUCCESS;
}
//+-------------------------------------------------------------------------------------------
// CWriteHtmlFile::Create
//
// Creates an html file, and starts the write proccess. If [pszFile] is null, then
// this function creates a temporary file in the GetTempPath() directory with a name
// like SCE###.HTM
//
// Arguments: [pszFile] - Optional parameter for file name
//
// returns: ERROR_SUCCESS - If creating the file was successful.
// If the file exists then ERROR_FILE_EXISTS is returned.
//
//--------------------------------------------------------------------------------------------
DWORD CWriteHtmlFile::Create(LPCTSTR pszFile )
{
if(!pszFile){
//
// Create a temporary file name.
//
DWORD dwSize = GetTempPath(0, NULL);
if(dwSize){
TCHAR szTempFile[512];
//
// Get the temp path.
//
LPTSTR pszPath = (LPTSTR)LocalAlloc( 0, (dwSize + 1) * sizeof(TCHAR));
if(!pszPath){
return ERROR_OUTOFMEMORY;
}
GetTempPath( dwSize + 1, pszPath );
pszPath[dwSize - 1] = 0;
if( GetTempFileName( pszPath, TEXT("SCE"), 0, szTempFile) ){
LocalFree(pszPath);
//
// Create the temporary file.
//
DeleteFile( szTempFile );
int i = lstrlen(szTempFile);
while(i--){
if( szTempFile[i] == L'.' ){
break;
}
}
if(i + 3 >= lstrlen(szTempFile)){
return ERROR_OUTOFMEMORY;
}
//
// We want to create an html file.
//
i++;
szTempFile[i] = L'h';
szTempFile[i + 1] = L't';
szTempFile[i + 2] = L'm';
m_strFileName = szTempFile;
} else {
LocalFree(pszPath);
}
}
} else {
m_strFileName = pszFile;
}
if(m_strFileName.IsEmpty()){
return ERROR_FILE_NOT_FOUND;
}
//
// Open the file for writing
//
m_hFileHandle = ExpandAndCreateFile( m_strFileName,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY,
NULL
);
if(m_hFileHandle == INVALID_HANDLE_VALUE){
return GetLastError();
}
//
// Write HTML header
//
return Write( IDS_HTMLERR_HEADER );
}
//+--------------------------------------------------------------------------
//
// Function: MyRegQueryValue
//
// Synopsis: Reads a registry value into [*Value]
//
//
// Arguments: [hKeyRoot] -
// [SubKey] -
// [ValueName] -
// [Value] -
// [pRegType] -
//
// Modifies: *[Value]
// *[pRegType]
//
// History:
//
//---------------------------------------------------------------------------
DWORD MyRegQueryValue( HKEY hKeyRoot,
LPCTSTR SubKey,
LPCTSTR ValueName,
PVOID *Value,
LPDWORD pRegType )
{
DWORD Rcode;
DWORD dSize=0;
HKEY hKey=NULL;
BOOL FreeMem=FALSE;
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)LocalAlloc( LPTR, (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 ) {
LocalFree(*Value);
*Value = NULL;
}
}
break;
default:
Rcode = ERROR_INVALID_DATATYPE;
break;
}
}
}
if ( hKey ) {
RegCloseKey( hKey );
}
return(Rcode);
}
//+--------------------------------------------------------------------------
//
// Function: MyRegSetValue
//
// Synopsis: Writes a registry value into [*Value]
//
//
// Arguments: [hKeyRoot] -
// [SubKey] -
// [ValueName] -
// [Value] -
// [cbValue] -
// [pRegType] -
//
//
// History:
//
//---------------------------------------------------------------------------
DWORD MyRegSetValue( HKEY hKeyRoot,
LPCTSTR SubKey,
LPCTSTR ValueName,
const BYTE *Value,
const DWORD cbValue,
const DWORD pRegType )
{
DWORD Rcode=0;
HKEY hKey=NULL;
BOOL FreeMem=FALSE;
if (( Rcode = RegCreateKeyEx(hKeyRoot,
SubKey,
0,
0,
0,
KEY_READ|KEY_SET_VALUE|KEY_CREATE_SUB_KEY,
NULL,
&hKey,
NULL)) == ERROR_SUCCESS ) {
Rcode = RegSetValueEx(hKey,
ValueName,
0,
pRegType,
Value,
cbValue );
}
if ( hKey ) {
RegCloseKey( hKey );
}
return(Rcode);
}
BOOL FilePathExist(LPCTSTR Name, BOOL IsPath, int Flag)
// Flag = 0 - check file, Flag = 1 - check path
{
// TODO:
struct _wfinddata_t FileInfo;
intptr_t hFile;
BOOL bExist = FALSE;
if ( (IsPath && Flag == 1) ||
(!IsPath && Flag == 0) ) {
// must be exact match
hFile = _wfindfirst((LPTSTR)Name, &FileInfo);
if ( hFile != -1 ) {// find it
if ( FileInfo.attrib & _A_SUBDIR ) {
if ( Flag == 1)
bExist = TRUE;
} else if ( Flag == 0 )
bExist = TRUE;
}
_findclose(hFile);
return bExist;
}
if ( IsPath && Flag == 0 ) {
// invalid parameter
return bExist;
}
// IsPath = FALSE and Flag == 1 (a file name is passed in and search for its path)
CString tmpstr = CString(Name);
int nPos = tmpstr.ReverseFind(L'\\');
if ( nPos > 2 ) {
hFile = _wfindfirst(tmpstr.GetBufferSetLength(nPos), &FileInfo);
if ( hFile != -1 && FileInfo.attrib & _A_SUBDIR )
bExist = TRUE;
_findclose(hFile);
} else if ( nPos == 2 && Name[1] == L':')
bExist = TRUE;
return bExist;
}
//+--------------------------------------------------------------------------
//
// Function: MyFormatResMessage
//
// Synopsis: Creates an error message combining a description of an error
// returned from an SCE function (in rc), the extended description
// of that error (in errBuf), and a custom error message
// (in residMessage)
//
// Arguments: [rc] - The return code of an SCE function
// [residMessage] - the resource id of the base error message
// [errBuf] - Extended error info returned from an SCE function
// [strOut] - A CString to hold the formatted message
//
// Modifies: [strOut]
//
// History:
//
//---------------------------------------------------------------------------
void
MyFormatResMessage(SCESTATUS rc, // in
UINT residMessage, // in
PSCE_ERROR_LOG_INFO errBuf,// in, optional
CString& strOut) // out
{
CString strMessage;
AFX_MANAGE_STATE(AfxGetStaticModuleState());
//
// If the LoadResource fails then strMessage will be empty
// It'll still be better to format the rest of the message than
// to return an empty strOut.
//
strMessage.LoadString(residMessage);
MyFormatMessage(rc,strMessage,errBuf,strOut);
}
//+--------------------------------------------------------------------------
//
// Function: MyFormatMessage
//
// Synopsis: Creates an error message combining a description of an error
// returned from an SCE function (in rc), the extended description
// of that error (in errBuf), and a custom error message (in mes)
//
// Arguments: [rc] - The return code of an SCE function
// [mes] - The base message
// [errBuf] - Extended error info returned from an SCE function
// [strOut] - A CString to hold the formatted message
//
// Modifies: [strOut]
//
// History:
//
//---------------------------------------------------------------------------
void
MyFormatMessage(SCESTATUS rc, // in
LPCTSTR mes, // in
PSCE_ERROR_LOG_INFO errBuf, // in, optional
CString& strOut) // out
{
LPVOID lpMsgBuf=NULL;
if ( rc != SCESTATUS_SUCCESS ) {
//
// translate SCESTATUS into DWORD
//
DWORD win32 = SceStatusToDosError(rc);
//
// get error description of rc
//
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
win32,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL
);
}
if ( lpMsgBuf != NULL ) {
strOut = (LPTSTR)lpMsgBuf;
LocalFree(lpMsgBuf);
lpMsgBuf = NULL;
} else {
strOut.Empty();
}
strOut += mes;
strOut += L"\n";
//
// Loop through the error buffers and append each of them to strOut
//
for (PSCE_ERROR_LOG_INFO pErr = errBuf;
pErr != NULL;
pErr = pErr->next) {
if (NULL == pErr) {
continue;
}
if ( pErr->rc != NO_ERROR) {
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
pErr->rc,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL
);
if ( lpMsgBuf ) {
strOut += (LPTSTR)lpMsgBuf;
LocalFree(lpMsgBuf);
lpMsgBuf = NULL;
}
}
if (pErr->buffer) {
strOut += pErr->buffer;
strOut += L"\n";
}
}
}
DWORD
FormatDBErrorMessage(
SCESTATUS sceStatus,
LPCTSTR pszDatabase,
CString &strOut
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
UINT uErr = 0;
switch (sceStatus) {
case SCESTATUS_SUCCESS:
return ERROR_INVALID_PARAMETER;
case SCESTATUS_INVALID_DATA:
uErr = IDS_DBERR_INVALID_DATA;
break;
case SCESTATUS_PROFILE_NOT_FOUND:
uErr = IDS_DBERR5_PROFILE_NOT_FOUND;
break;
case SCESTATUS_BAD_FORMAT:
uErr = IDS_DBERR_BAD_FORMAT;
break;
case SCESTATUS_BUFFER_TOO_SMALL:
case SCESTATUS_NOT_ENOUGH_RESOURCE:
uErr = IDS_DBERR_NOT_ENOUGH_RESOURCE;
break;
case SCESTATUS_ACCESS_DENIED:
uErr = IDS_DBERR5_ACCESS_DENIED;
break;
case SCESTATUS_NO_TEMPLATE_GIVEN:
uErr = IDS_DBERR_NO_TEMPLATE_GIVEN;
break;
case SCESTATUS_SPECIAL_ACCOUNT: //Raid #589139,XPSP1 DCR, yanggao, 4/12/2002.
uErr = IDS_DBERR5_ACCESS_DENIED;
break;
default:
uErr = IDS_DBERR_OTHER_ERROR;
}
if ( strOut.LoadString(uErr) ) {
return ERROR_SUCCESS;
}
return ERROR_INVALID_PARAMETER;
}
DWORD SceStatusToDosError(SCESTATUS SceStatus)
{
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_RESOURCE_DATA_NOT_FOUND);
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:
case SCESTATUS_SPECIAL_ACCOUNT: //Raid #589139,XPSP1 DCR, yanggao, 4/12/2002.
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);
default:
return(ERROR_EXTENDED_ERROR);
}
}
//+--------------------------------------------------------------------------
//
// Function: CreateNewProfile
//
// Synopsis: Create a new tempate with default values in the ProfileName location
//
// Returns: TRUE if a template ends up in the ProfileName file
// FALSE otherwise
//
// History:
//
//---------------------------------------------------------------------------
BOOL CreateNewProfile(CString ProfileName,PSCE_PROFILE_INFO *ppspi)
{
SCESTATUS status;
SCE_PROFILE_INFO *pTemplate;
//
// profile name must end with .inf
//
int nLen = ProfileName.GetLength ();
// start searching at the last 4 position
if ( ProfileName.Find (L".inf", nLen-4) != nLen-4 )
{
return FALSE;
}
//
// if the profile already exists then we don't need to do anything
//
if ( FilePathExist( (LPCTSTR)ProfileName, FALSE, 0) ) {
return TRUE;
}
//
// Make sure the directory for the profile exists
//
status = SceCreateDirectory(ProfileName,FALSE,NULL);
if (SCESTATUS_SUCCESS != status) {
return FALSE;
}
pTemplate = (SCE_PROFILE_INFO*)LocalAlloc(LPTR,sizeof(SCE_PROFILE_INFO));
if (!pTemplate) {
return FALSE;
}
#ifdef FILL_WITH_DEFAULT_VALUES
SCE_PROFILE_INFO *pDefault = GetDefaultTemplate();
//
// Fill with default values
//
pTemplate->Type = SCE_ENGINE_SCP;
#define CD(X) pTemplate->X = pDefault->X;
#else // !FILL_WITH_DEFAULT_VALUES
#define CD(X) pTemplate->X = SCE_NO_VALUE;
#endif // !FILL_WITH_DEFAULT_VALUES
CD(MinimumPasswordAge);
CD(MaximumPasswordAge);
CD(MinimumPasswordLength);
CD(PasswordComplexity);
CD(PasswordHistorySize);
CD(LockoutBadCount);
CD(ResetLockoutCount);
CD(LockoutDuration);
CD(RequireLogonToChangePassword);
CD(ForceLogoffWhenHourExpire);
CD(EnableAdminAccount);
CD(EnableGuestAccount);
// These members aren't declared in NT4
CD(ClearTextPassword);
CD(AuditDSAccess);
CD(AuditAccountLogon);
CD(LSAAnonymousNameLookup);
CD(MaximumLogSize[0]);
CD(MaximumLogSize[1]);
CD(MaximumLogSize[2]);
CD(AuditLogRetentionPeriod[0]);
CD(AuditLogRetentionPeriod[1]);
CD(AuditLogRetentionPeriod[2]);
CD(RetentionDays[0]);
CD(RetentionDays[1]);
CD(RetentionDays[2]);
CD(RestrictGuestAccess[0]);
CD(RestrictGuestAccess[1]);
CD(RestrictGuestAccess[2]);
CD(AuditSystemEvents);
CD(AuditLogonEvents);
CD(AuditObjectAccess);
CD(AuditPrivilegeUse);
CD(AuditPolicyChange);
CD(AuditAccountManage);
CD(AuditProcessTracking);
#ifdef FILL_WITH_DEFAULT_VALUES
//
// These two are strings rather than DWORDs
//
if (pDefault->NewAdministratorName) {
pTemplate->NewAdministratorName =
(LPTSTR) LocalAlloc(LPTR,(lstrlen(pDefault->NewAdministratorName)+1)*sizeof(TCHAR));
if (pTemplate->NewAdministratorName) {
lstrcpy(pTemplate->NewAdministratorName,
pDefault->NewAdministratorName);
}
}
if (pDefault->NewGuestName) {
pTemplate->NewGuestName =
(LPTSTR) LocalAlloc(LPTR,(lstrlen(pDefault->NewGuestName)+1)*sizeof(TCHAR));
if (pTemplate->NewGuestName) {
lstrcpy(pTemplate->NewGuestName,
pDefault->NewGuestName);
}
}
#endif // FILL_WITH_DEFAULT_VALUES
#undef CD
status = SceWriteSecurityProfileInfo(ProfileName,
AREA_ALL,
pTemplate,
NULL);
if (ppspi) {
*ppspi = pTemplate;
} else {
SceFreeProfileMemory(pTemplate);
}
return (SCESTATUS_SUCCESS == status);
}
BOOL
VerifyKerberosInfo(PSCE_PROFILE_INFO pspi) {
if (pspi->pKerberosInfo) {
return TRUE;
}
pspi->pKerberosInfo = (PSCE_KERBEROS_TICKET_INFO)
LocalAlloc(LPTR,sizeof(SCE_KERBEROS_TICKET_INFO));
if (pspi->pKerberosInfo) {
pspi->pKerberosInfo->MaxTicketAge = SCE_NO_VALUE;
pspi->pKerberosInfo->MaxRenewAge = SCE_NO_VALUE;
pspi->pKerberosInfo->MaxServiceAge = SCE_NO_VALUE;
pspi->pKerberosInfo->MaxClockSkew = SCE_NO_VALUE;
pspi->pKerberosInfo->TicketValidateClient = SCE_NO_VALUE;
return TRUE;
}
return FALSE;
}
BOOL
SetProfileInfo(LONG_PTR dwItem,LONG_PTR dwNew,PEDITTEMPLATE pEdit) {
if (!pEdit) {
return FALSE;
}
pEdit->SetDirty(AREA_SECURITY_POLICY);
switch (dwItem) {
case IDS_MAX_PAS_AGE:
pEdit->pTemplate->MaximumPasswordAge = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_MIN_PAS_AGE:
pEdit->pTemplate->MinimumPasswordAge = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_MIN_PAS_LEN:
pEdit->pTemplate->MinimumPasswordLength = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_PAS_UNIQUENESS:
pEdit->pTemplate->PasswordHistorySize = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_PAS_COMPLEX:
pEdit->pTemplate->PasswordComplexity = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_REQ_LOGON:
pEdit->pTemplate->RequireLogonToChangePassword = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_LOCK_COUNT:
pEdit->pTemplate->LockoutBadCount = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_LOCK_RESET_COUNT:
pEdit->pTemplate->ResetLockoutCount = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_LOCK_DURATION:
pEdit->pTemplate->LockoutDuration = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_FORCE_LOGOFF:
pEdit->pTemplate->ForceLogoffWhenHourExpire = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_ENABLE_ADMIN:
pEdit->pTemplate->EnableAdminAccount = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_ENABLE_GUEST:
pEdit->pTemplate->EnableGuestAccount = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_LSA_ANON_LOOKUP:
pEdit->pTemplate->LSAAnonymousNameLookup = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_NEW_ADMIN:
if (pEdit->pTemplate->NewAdministratorName) {
LocalFree(pEdit->pTemplate->NewAdministratorName);
}
if (dwNew && (dwNew != (LONG_PTR)ULongToPtr(SCE_NO_VALUE))) {
pEdit->pTemplate->NewAdministratorName = (PWSTR)LocalAlloc(LPTR,(lstrlen((PWSTR)dwNew)+1)*sizeof(WCHAR));
if (pEdit->pTemplate->NewAdministratorName) {
lstrcpy(pEdit->pTemplate->NewAdministratorName,(PWSTR)dwNew);
}
} else {
pEdit->pTemplate->NewAdministratorName = NULL;
}
break;
case IDS_NEW_GUEST:
if (pEdit->pTemplate->NewGuestName) {
LocalFree(pEdit->pTemplate->NewGuestName);
}
if (dwNew && (dwNew != (LONG_PTR)ULongToPtr(SCE_NO_VALUE))) {
pEdit->pTemplate->NewGuestName = (PWSTR)LocalAlloc(LPTR,(lstrlen((PWSTR)dwNew)+1)*sizeof(WCHAR));
if (pEdit->pTemplate->NewGuestName) {
lstrcpy(pEdit->pTemplate->NewGuestName,(PWSTR)dwNew);
}
} else {
pEdit->pTemplate->NewGuestName = NULL;
}
break;
case IDS_SYS_LOG_MAX:
pEdit->pTemplate->MaximumLogSize[EVENT_TYPE_SYSTEM] = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_SYS_LOG_RET:
pEdit->pTemplate->AuditLogRetentionPeriod[EVENT_TYPE_SYSTEM] = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_SYS_LOG_DAYS:
pEdit->pTemplate->RetentionDays[EVENT_TYPE_SYSTEM] = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_SEC_LOG_MAX:
pEdit->pTemplate->MaximumLogSize[EVENT_TYPE_SECURITY] = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_SEC_LOG_RET:
pEdit->pTemplate->AuditLogRetentionPeriod[EVENT_TYPE_SECURITY] = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_SEC_LOG_DAYS:
pEdit->pTemplate->RetentionDays[EVENT_TYPE_SECURITY] = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_APP_LOG_MAX:
pEdit->pTemplate->MaximumLogSize[EVENT_TYPE_APP] = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_APP_LOG_RET:
pEdit->pTemplate->AuditLogRetentionPeriod[EVENT_TYPE_APP] = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_APP_LOG_DAYS:
pEdit->pTemplate->RetentionDays[EVENT_TYPE_APP] = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_SYSTEM_EVENT:
pEdit->pTemplate->AuditSystemEvents = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_LOGON_EVENT:
pEdit->pTemplate->AuditLogonEvents = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_OBJECT_ACCESS:
pEdit->pTemplate->AuditObjectAccess = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_PRIVILEGE_USE:
pEdit->pTemplate->AuditPrivilegeUse = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_POLICY_CHANGE:
pEdit->pTemplate->AuditPolicyChange = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_ACCOUNT_MANAGE:
pEdit->pTemplate->AuditAccountManage = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_PROCESS_TRACK:
pEdit->pTemplate->AuditProcessTracking = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_DIRECTORY_ACCESS:
pEdit->pTemplate->AuditDSAccess = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_ACCOUNT_LOGON:
pEdit->pTemplate->AuditAccountLogon = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_SYS_LOG_GUEST:
pEdit->pTemplate->RestrictGuestAccess[EVENT_TYPE_SYSTEM] = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_SEC_LOG_GUEST:
pEdit->pTemplate->RestrictGuestAccess[EVENT_TYPE_SECURITY] = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_APP_LOG_GUEST:
pEdit->pTemplate->RestrictGuestAccess[EVENT_TYPE_APP] = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_CLEAR_PASSWORD:
pEdit->pTemplate->ClearTextPassword = (DWORD)PtrToUlong((PVOID)dwNew);
break;
case IDS_KERBEROS_MAX_SERVICE:
if (VerifyKerberosInfo(pEdit->pTemplate)) {
pEdit->pTemplate->pKerberosInfo->MaxServiceAge = (DWORD)PtrToUlong((PVOID)dwNew);
}
break;
case IDS_KERBEROS_MAX_CLOCK:
if (VerifyKerberosInfo( pEdit->pTemplate)) {
pEdit->pTemplate->pKerberosInfo->MaxClockSkew = (DWORD)PtrToUlong((PVOID)dwNew);
}
break;
case IDS_KERBEROS_VALIDATE_CLIENT:
if (VerifyKerberosInfo( pEdit->pTemplate)) {
pEdit->pTemplate->pKerberosInfo->TicketValidateClient = (DWORD)PtrToUlong((PVOID)dwNew);
}
break;
case IDS_KERBEROS_MAX_AGE:
if (VerifyKerberosInfo( pEdit->pTemplate)) {
pEdit->pTemplate->pKerberosInfo->MaxTicketAge = (DWORD)PtrToUlong((PVOID)dwNew);
}
break;
case IDS_KERBEROS_RENEWAL:
if (VerifyKerberosInfo( pEdit->pTemplate)) {
pEdit->pTemplate->pKerberosInfo->MaxRenewAge = (DWORD)PtrToUlong((PVOID)dwNew);
}
break;
default:
return FALSE;
}
return TRUE;
}
//
// FUNCTION: ErrorHandlerEx(WORD, LPSTR)
//
// PURPOSE: Calls GetLastError() and uses FormatMessage() to display the
// textual information of the error code along with the file
// and line number.
//
// PARAMETERS:
// wLine - line number where the error occured
// lpszFile - file where the error occured
//
// RETURN VALUE:
// none
//
// COMMENTS:
// This function has a macro ErrorHandler() which handles filling in
// the line number and file name where the error occured. ErrorHandler()
// is always used instead of calling this function directly.
//
void ErrorHandlerEx( WORD wLine, LPTSTR lpszFile )
{
LPVOID lpvMessage;
DWORD dwError;
TCHAR szBuffer[256];
// The the text of the error message
dwError = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
(LPTSTR)&lpvMessage,
0,
NULL);
// Check to see if an error occured calling FormatMessage()
if (0 == dwError) {
wsprintf(szBuffer, TEXT("An error occured calling FormatMessage().")
TEXT("Error Code %d"), GetLastError());
MessageBox(NULL, szBuffer, TEXT("Security Configuration Editor"), MB_ICONSTOP |
MB_ICONEXCLAMATION);
return;
}
// Display the error message
wsprintf(szBuffer, TEXT("Generic, Line=%d, File=%s"), wLine, lpszFile);
MessageBox(NULL, (LPTSTR)lpvMessage, szBuffer, MB_ICONEXCLAMATION | MB_OK);
return;
}
BOOL
GetSceStatusString(SCESTATUS status, CString *strStatus) {
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (!strStatus || (status > SCESTATUS_SERVICE_NOT_SUPPORT)) {
return false;
}
return strStatus->LoadString(status + IDS_SCESTATUS_SUCCESS);
}
//+---------------------------------------------------------------------------------------------
// EnumLangProc
//
// Creates the lanuage ID for the resource attached to the DLL. The function only enumerates
// on lanuage.
//
// Arguments: - See help on EnumResLangProc in the SDK Doc.
//
// Returns: - Returns FALSE because we only want the very first lanuage enumerated.
//
//+---------------------------------------------------------------------------------------------
BOOL CALLBACK EnumLangProc(
HMODULE hMod,
LPCTSTR pszType,
LPCTSTR pszName,
WORD wIDLanguage,
LONG_PTR lParam
)
{
//
// We only want the very first enumerated type, so create the language ID
// and exit this enumeration.
//
*((DWORD *)lParam) = wIDLanguage;
return FALSE;
}
bool
GetRightDisplayName(LPCTSTR szSystemName, LPCTSTR szName, LPTSTR szDisp, LPDWORD lpcbDisp) {
LPTSTR szLCName;
DWORD dwLang;
int i;
if (!szDisp || !szName) {
return false;
}
//
// Enumerate our resource to find out what language the resource is in.
//
DWORD dwDefaultLang;
if( !EnumResourceLanguages(
(HMODULE)AfxGetInstanceHandle(),
MAKEINTRESOURCE(RT_VERSION),
MAKEINTRESOURCE(VS_VERSION_INFO),
&EnumLangProc,
(LPARAM)&dwDefaultLang
) ){
if(GetLastError() != ERROR_SUCCESS){
//
// Default to system language if enumerating the version language
// was unsuccessful.
dwDefaultLang = MAKELANGID(LANG_NEUTRAL, 0);
}
}
dwDefaultLang = MAKELANGID( dwDefaultLang, SUBLANG_DEFAULT);
LCID langID = MAKELCID( dwDefaultLang, SORT_DEFAULT);
LCID langDefault = GetThreadLocale();
SetThreadLocale( langID );
*lpcbDisp = dwDefaultLang;
DWORD cBufSize=*lpcbDisp;
BOOL bFound;
bFound = LookupPrivilegeDisplayName(szSystemName,szName,szDisp,lpcbDisp,&dwLang);
if ( bFound && dwDefaultLang != dwLang && szSystemName ) {
// not the language I am looking for
// search on local system
*lpcbDisp = cBufSize;
bFound = LookupPrivilegeDisplayName(NULL,szName,szDisp,lpcbDisp,&dwLang);
}
SetThreadLocale(langDefault);
if (!bFound) {
if (0 == lstrcmpi(szName,L"senetworklogonright")) {
LoadString(AfxGetInstanceHandle(),IDS_SE_NETWORK_LOGON_RIGHT,szDisp,*lpcbDisp);
} else if (0 == lstrcmpi(szName,L"seinteractivelogonright")) {
LoadString(AfxGetInstanceHandle(),IDS_SE_INTERACTIVE_LOGON_RIGHT,szDisp,*lpcbDisp);
} else if (0 == lstrcmpi(szName,L"sebatchlogonright")) {
LoadString(AfxGetInstanceHandle(),IDS_SE_BATCH_LOGON_RIGHT,szDisp,*lpcbDisp);
} else if (0 == lstrcmpi(szName,L"seservicelogonright")) {
LoadString(AfxGetInstanceHandle(),IDS_SE_SERVICE_LOGON_RIGHT,szDisp,*lpcbDisp);
} else if (0 == lstrcmpi(szName,L"sedenyinteractivelogonright")) {
LoadString(AfxGetInstanceHandle(),IDS_DENY_LOGON_LOCALLY,szDisp,*lpcbDisp);
} else if (0 == lstrcmpi(szName,L"sedenynetworklogonright")) {
LoadString(AfxGetInstanceHandle(),IDS_DENY_LOGON_NETWORK,szDisp,*lpcbDisp);
} else if (0 == lstrcmpi(szName,L"sedenyservicelogonright")) {
LoadString(AfxGetInstanceHandle(),IDS_DENY_LOGON_SERVICE,szDisp,*lpcbDisp);
} else if (0 == lstrcmpi(szName,L"sedenybatchlogonright")) {
LoadString(AfxGetInstanceHandle(),IDS_DENY_LOGON_BATCH,szDisp,*lpcbDisp);
} else if (0 == lstrcmpi(szName,L"sedenyremoteinteractivelogonright")) {
LoadString(AfxGetInstanceHandle(),IDS_DENY_REMOTE_INTERACTIVE_LOGON,szDisp,*lpcbDisp);
} else if (0 == lstrcmpi(szName,L"seremoteinteractivelogonright")) {
LoadString(AfxGetInstanceHandle(),IDS_REMOTE_INTERACTIVE_LOGON,szDisp,*lpcbDisp);
} else {
lstrcpyn(szDisp,szName,*lpcbDisp);
}
}
return true;
}
#define DPI(X) {str.Format(L"%S: %d\n",#X,pInfo->X);OutputDebugString(str);}
void DumpProfileInfo(PSCE_PROFILE_INFO pInfo) {
CString str;
PSCE_PRIVILEGE_ASSIGNMENT ppa;
PSCE_NAME_LIST pName;
PSCE_GROUP_MEMBERSHIP pgm;
if (!pInfo) {
return;
}
DPI(MinimumPasswordAge);
DPI(MaximumPasswordAge);
DPI(MinimumPasswordLength);
DPI(PasswordComplexity);
DPI(PasswordHistorySize);
DPI(LockoutBadCount);
DPI(ResetLockoutCount);
DPI(LockoutDuration);
DPI(RequireLogonToChangePassword);
DPI(ForceLogoffWhenHourExpire);
DPI(EnableAdminAccount);
DPI(EnableGuestAccount);
DPI(ClearTextPassword);
DPI(AuditDSAccess);
DPI(AuditAccountLogon);
DPI(LSAAnonymousNameLookup);
// DPI(EventAuditingOnOff);
DPI(AuditSystemEvents);
DPI(AuditLogonEvents);
DPI(AuditObjectAccess);
DPI(AuditPrivilegeUse);
DPI(AuditPolicyChange);
DPI(AuditAccountManage);
DPI(AuditProcessTracking);
if (pInfo->NewGuestName) {
OutputDebugString(L"NewGuestName: ");
if ((DWORD_PTR)ULongToPtr(SCE_NO_VALUE) == (DWORD_PTR)pInfo->NewGuestName) {
OutputDebugString(L"[[undefined]]");
} else {
OutputDebugString(pInfo->NewGuestName);
}
OutputDebugString(L"\n");
} else {
OutputDebugString(L"NewGuestName: [[absent]]\n");
}
if (pInfo->NewAdministratorName) {
OutputDebugString(L"NewAdministratorName: ");
if ((DWORD_PTR)ULongToPtr(SCE_NO_VALUE) == (DWORD_PTR)pInfo->NewAdministratorName) {
OutputDebugString(L"[[undefined]]");
} else {
OutputDebugString(pInfo->NewAdministratorName);
}
OutputDebugString(L"\n");
} else {
OutputDebugString(L"NewGuestName: [[absent]]\n");
}
OutputDebugString(L"\n");
switch(pInfo->Type) {
case SCE_ENGINE_SCP:
ppa = pInfo->OtherInfo.scp.u.pInfPrivilegeAssignedTo;
break;
case SCE_ENGINE_SAP:
ppa = pInfo->OtherInfo.sap.pPrivilegeAssignedTo;
break;
case SCE_ENGINE_SMP:
ppa = pInfo->OtherInfo.smp.pPrivilegeAssignedTo;
break;
case SCE_ENGINE_SYSTEM:
ppa = NULL;
break;
default:
OutputDebugString(L"!!!Unknown Template Type!!!\n");
ppa = NULL;
break;
}
while(ppa) {
OutputDebugString(ppa->Name);
OutputDebugString(L":");
pName = ppa->AssignedTo;
while(pName) {
OutputDebugString(pName->Name);
OutputDebugString(L",");
pName = pName->Next;
}
ppa = ppa->Next;
OutputDebugString(L"\n");
}
OutputDebugString(L"\n");
PSCE_REGISTRY_VALUE_INFO aRegValues;
for(DWORD i = 0; i< pInfo->RegValueCount;i++) {
OutputDebugString(pInfo->aRegValues[i].FullValueName);
OutputDebugString(L":");
switch(pInfo->aRegValues[i].ValueType) {
case SCE_REG_DISPLAY_STRING:
OutputDebugString(pInfo->aRegValues[i].Value);
break;
default:
str.Format(L"%d",(ULONG_PTR)pInfo->aRegValues[i].Value);
OutputDebugString(str);
}
OutputDebugString(L"\n");
}
OutputDebugString(L"\n");
pgm = pInfo->pGroupMembership;
while(pgm) {
OutputDebugString(L"\nGROUP: ");
OutputDebugString(pgm->GroupName);
OutputDebugString(L"\nMembers: ");
pName = pgm->pMembers;
while(pName) {
OutputDebugString(pName->Name);
OutputDebugString(L",");
pName = pName->Next;
}
OutputDebugString(L"\nMember Of: ");
pName = pgm->pMemberOf;
while(pName) {
OutputDebugString(pName->Name);
OutputDebugString(L",");
pName = pName->Next;
}
OutputDebugString(L"\n");
pgm = pgm->Next;
}
OutputDebugString(L"\nGROUP: ");
}
HRESULT MyMakeSelfRelativeSD(
PSECURITY_DESCRIPTOR psdOriginal,
PSECURITY_DESCRIPTOR* ppsdNew )
{
ASSERT( NULL != psdOriginal );
if ( NULL == psdOriginal || NULL == ppsdNew ) {
return E_INVALIDARG;
}
// we have to find out whether the original is already self-relative
SECURITY_DESCRIPTOR_CONTROL sdc = 0;
DWORD dwRevision = 0;
if ( !GetSecurityDescriptorControl( psdOriginal, &sdc, &dwRevision ) ) {
ASSERT( FALSE );
DWORD err = GetLastError();
return HRESULT_FROM_WIN32( err );
}
DWORD cb = GetSecurityDescriptorLength( psdOriginal ) + 20;
PSECURITY_DESCRIPTOR psdSelfRelativeCopy = (PSECURITY_DESCRIPTOR)LocalAlloc( LMEM_ZEROINIT, cb );
if (NULL == psdSelfRelativeCopy) {
return E_UNEXPECTED; // just in case the exception is ignored
}
if ( sdc & SE_SELF_RELATIVE )
// the original is in self-relative format, just byte-copy it
{
memcpy( psdSelfRelativeCopy, psdOriginal, cb - 20 );
} else if ( !MakeSelfRelativeSD( psdOriginal, psdSelfRelativeCopy, &cb ) )
// the original is in absolute format, convert-copy it
{
ASSERT( FALSE );
VERIFY( NULL == LocalFree( psdSelfRelativeCopy ) );
DWORD err = GetLastError();
return HRESULT_FROM_WIN32( err );
}
*ppsdNew = psdSelfRelativeCopy;
return S_OK;
}
PSCE_NAME_STATUS_LIST
MergeNameStatusList(PSCE_NAME_LIST pTemplate, PSCE_NAME_LIST pInspect)
{
PSCE_NAME_LIST pTemp1;
PSCE_NAME_STATUS_LIST plMerge=NULL, pTemp2;
SCESTATUS rc=SCESTATUS_SUCCESS;
for ( pTemp1=pTemplate; pTemp1; pTemp1=pTemp1->Next ) {
rc = SceAddToNameStatusList(&plMerge, pTemp1->Name, 0, MERGED_TEMPLATE );
if ( SCESTATUS_SUCCESS != rc )
break;
}
if ( SCESTATUS_SUCCESS == rc ) {
for ( pTemp1=pInspect; pTemp1; pTemp1=pTemp1->Next ) {
for ( pTemp2=plMerge; pTemp2 != NULL ; pTemp2=pTemp2->Next ) {
if ( pTemp2->Status & MERGED_INSPECT ) {
// this one is processed
continue;
} else if ( _wcsicmp(pTemp1->Name, pTemp2->Name) == 0 ) {
// find a match
pTemp2->Status = MERGED_TEMPLATE | MERGED_INSPECT;
break;
}
}
if ( !pTemp2 ) {
// did not find the match, add this one in
rc = SceAddToNameStatusList(&plMerge, pTemp1->Name, 0, MERGED_INSPECT );
if ( SCESTATUS_SUCCESS != rc )
break;
}
}
}
if ( SCESTATUS_SUCCESS == rc ) {
return plMerge;
} else {
SceFreeMemory(plMerge, SCE_STRUCT_NAME_STATUS_LIST);
return NULL;
}
}
SCESTATUS
ConvertMultiSzToDelim(
IN PWSTR pValue,
IN DWORD Len,
IN WCHAR DelimFrom,
IN WCHAR Delim
)
/*
Convert the multi-sz delimiter \0 to space
*/
{
DWORD i;
for ( i=0; i<Len && pValue; i++) {
// if ( *(pValue+i) == L'\0' && *(pValue+i+1) != L'\0') {
if ( *(pValue+i) == DelimFrom && i+1 < Len &&
*(pValue+i+1) != L'\0' ) {
//
// a NULL delimiter is encounted and it's not the end (double NULL)
//
*(pValue+i) = Delim;
}
}
return(SCESTATUS_SUCCESS);
}
DWORD
SceRegEnumAllValues(
IN OUT PDWORD pCount,
IN OUT PSCE_REGISTRY_VALUE_INFO *paRegValues
)
/*
*/
{
DWORD Win32Rc;
HKEY hKey=NULL;
PSCE_NAME_STATUS_LIST pnsList=NULL;
DWORD nAdded=0;
Win32Rc = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
SCE_ROOT_REGVALUE_PATH,
0,
KEY_READ,
&hKey
);
DWORD cSubKeys = 0;
DWORD nMaxLen;
if ( Win32Rc == ERROR_SUCCESS ) {
//
// enumerate all subkeys of the key
//
Win32Rc = RegQueryInfoKey (
hKey,
NULL,
NULL,
NULL,
&cSubKeys,
&nMaxLen,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
}
if ( Win32Rc == ERROR_SUCCESS && cSubKeys > 0 ) {
PWSTR szName = (PWSTR)LocalAlloc(0, (nMaxLen+2)*sizeof(WCHAR));
if ( !szName ) {
Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
} else {
DWORD BufSize;
DWORD index = 0;
DWORD RegType;
do {
BufSize = nMaxLen+1;
Win32Rc = RegEnumKeyEx(
hKey,
index,
szName,
&BufSize,
NULL,
NULL,
NULL,
NULL);
if ( ERROR_SUCCESS == Win32Rc ) {
index++;
//
// get the full registry key name and Valuetype
//
cSubKeys = REG_SZ;
PDWORD pType = &cSubKeys;
//
// query ValueType, if error, default REG_SZ
//
MyRegQueryValue( hKey,
szName,
SCE_REG_VALUE_TYPE,
(PVOID *)&pType,
&RegType );
if ( cSubKeys < REG_SZ || cSubKeys > REG_MULTI_SZ ) {
cSubKeys = REG_SZ;
}
//
// convert the path name
//
ConvertMultiSzToDelim(szName, BufSize, L'/', L'\\');
//
// compare with the input array, if not exist,
// add it
//
for ( DWORD i=0; i<*pCount; i++ ) {
if ( (*paRegValues)[i].FullValueName &&
_wcsicmp(szName, (*paRegValues)[i].FullValueName) == 0 ) {
break;
}
}
if ( i >= *pCount ) {
//
// did not find a match, add it
//
if ( SCESTATUS_SUCCESS != SceAddToNameStatusList(&pnsList,
szName,
BufSize,
cSubKeys) ) {
Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
break;
}
nAdded++;
}
} else if ( ERROR_NO_MORE_ITEMS != Win32Rc ) {
break;
}
} while ( Win32Rc != ERROR_NO_MORE_ITEMS );
if ( Win32Rc == ERROR_NO_MORE_ITEMS ) {
Win32Rc = ERROR_SUCCESS;
}
//
// free the enumeration buffer
//
LocalFree(szName);
}
}
if ( hKey ) {
RegCloseKey(hKey);
}
if ( ERROR_SUCCESS == Win32Rc ) {
//
// add the name list to the output arrays
//
DWORD nNewCount = *pCount + nAdded;
PSCE_REGISTRY_VALUE_INFO aNewArray;
if ( nNewCount ) {
aNewArray = (PSCE_REGISTRY_VALUE_INFO)LocalAlloc(0, nNewCount*sizeof(SCE_REGISTRY_VALUE_INFO));
if ( aNewArray ) {
ZeroMemory(aNewArray, nNewCount * sizeof(SCE_REGISTRY_VALUE_INFO));
memcpy( aNewArray, *paRegValues, *pCount * sizeof( SCE_REGISTRY_VALUE_INFO ) );
DWORD i;
i=0;
for ( PSCE_NAME_STATUS_LIST pns=pnsList;
pns; pns=pns->Next ) {
if ( pns->Name && i < nAdded ) {
aNewArray[*pCount+i].FullValueName = pns->Name;
pns->Name = NULL;
aNewArray[*pCount+i].Value = NULL;
aNewArray[*pCount+i].ValueType = pns->Status;
aNewArray[*pCount+i].Status = SCE_STATUS_NOT_CONFIGURED;
i++;
}
}
//
// free the original array
// all components in the array are already transferred to the new array
//
LocalFree(*paRegValues);
*pCount = nNewCount;
*paRegValues = aNewArray;
} else {
Win32Rc = ERROR_NOT_ENOUGH_MEMORY;
}
}
}
//
// free the name status list
//
SceFreeMemory(pnsList, SCE_STRUCT_NAME_STATUS_LIST);
return( Win32Rc );
}
DWORD
GetGroupStatus(
DWORD status,
int flag
)
{
DWORD NewStatus;
switch ( flag ) {
case STATUS_GROUP_RECORD:
if (status & SCE_GROUP_STATUS_NC_MEMBERS) {
NewStatus = SCE_STATUS_NOT_CONFIGURED;
} else if ( (status & SCE_GROUP_STATUS_MEMBERS_MISMATCH) ||
(status & SCE_GROUP_STATUS_MEMBEROF_MISMATCH)) {
NewStatus = SCE_STATUS_MISMATCH;
} else if (status & SCE_GROUP_STATUS_NOT_ANALYZED) {
NewStatus = SCE_STATUS_NOT_ANALYZED;
} else if (status & SCE_GROUP_STATUS_ERROR_ANALYZED) {
NewStatus = SCE_STATUS_ERROR_NOT_AVAILABLE;
} else {
NewStatus = SCE_STATUS_GOOD;
}
break;
case STATUS_GROUP_MEMBERS:
if ( status & SCE_GROUP_STATUS_NOT_ANALYZED ) {
NewStatus = SCE_STATUS_NOT_ANALYZED; //do not display any status;
} else {
if ( status & SCE_GROUP_STATUS_NC_MEMBERS ) {
NewStatus = SCE_STATUS_NOT_CONFIGURED;
} else if ( status & SCE_GROUP_STATUS_MEMBERS_MISMATCH ) {
NewStatus = SCE_STATUS_MISMATCH;
} else if (status & SCE_GROUP_STATUS_ERROR_ANALYZED) {
NewStatus = SCE_STATUS_ERROR_NOT_AVAILABLE;
} else {
NewStatus = SCE_STATUS_GOOD;
}
}
break;
case STATUS_GROUP_MEMBEROF:
if ( status & SCE_GROUP_STATUS_NOT_ANALYZED ) {
NewStatus = SCE_STATUS_NOT_ANALYZED; // do not display any status;
} else {
if ( status & SCE_GROUP_STATUS_NC_MEMBEROF ) {
NewStatus = SCE_STATUS_NOT_CONFIGURED;
} else if ( status & SCE_GROUP_STATUS_MEMBEROF_MISMATCH ) {
NewStatus = SCE_STATUS_MISMATCH;
} else if (status & SCE_GROUP_STATUS_ERROR_ANALYZED) {
NewStatus = SCE_STATUS_ERROR_NOT_AVAILABLE;
} else {
NewStatus = SCE_STATUS_GOOD;
}
}
break;
default:
NewStatus = 0;
break;
}
return NewStatus;
}
//+--------------------------------------------------------------------------
//
// Function: AllocGetTempFileName
//
// Synopsis: Allocate and return a string with a temporary file name.
//
// Returns: The temporary file name, or 0 if a temp file can't be found
//
// History:
//
//---------------------------------------------------------------------------
LPTSTR
AllocGetTempFileName() {
DWORD dw;
CString strPath;
CString strFile;
LPTSTR szPath;
LPTSTR szFile;
//
// Get a temporary directory path in strPath
// If our buffer isn't large enough then keep reallocating until it is
//
dw = MAX_PATH;
do {
szPath = strPath.GetBuffer(dw);
dw = GetTempPath(MAX_PATH,szPath);
strPath.ReleaseBuffer();
} while (dw > (DWORD)strPath.GetLength() );
//
// Can't get a path to the temporary directory
//
if (!dw) {
return 0;
}
//
// Get a temporary file in that directory
//
szFile = strFile.GetBuffer(dw+MAX_PATH);
if (!GetTempFileName(szPath,L"SCE",0,szFile)) {
return 0;
}
strFile.ReleaseBuffer();
szFile = (LPTSTR)LocalAlloc(LPTR,(strFile.GetLength()+1)*sizeof(TCHAR));
if (!szFile) {
return 0;
}
lstrcpy(szFile,(LPCTSTR)strFile);
return szFile;
}
// If the given environment variable exists as the first part of the path,
// then the environment variable is inserted into the output buffer.
//
// Returns TRUE if pszResult is filled in.
//
// Example: Input -- C:\WINNT\SYSTEM32\FOO.TXT -and- lpEnvVar = %SYSTEMROOT%
// Output -- %SYSTEMROOT%\SYSTEM32\FOO.TXT
BOOL UnExpandEnvironmentString(LPCTSTR pszPath, LPCTSTR pszEnvVar, LPTSTR pszResult, UINT cbResult)
{
TCHAR szEnvVar[MAX_PATH];
DWORD dwEnvVar = ExpandEnvironmentStrings(pszEnvVar, szEnvVar, ARRAYSIZE(szEnvVar)) - 1; // don't count the NULL
if (CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
szEnvVar, dwEnvVar, pszPath, dwEnvVar) == 2) {
if (lstrlen(pszPath) + dwEnvVar < cbResult) {
lstrcpy(pszResult, pszEnvVar);
lstrcat(pszResult, pszPath + dwEnvVar);
return TRUE;
}
}
return FALSE;
}
//+--------------------------------------------------------------------------
//
// Function: UnexpandEnvironmentVariables
//
// Synopsis: Given a path, contract any leading members to use matching
// environment variables, if any
//
// Arguments:
// [szPath] - The path to expand
//
// Returns: The newly allocated path (NULL if no changes are made)
//
// History:
//
//---------------------------------------------------------------------------
LPTSTR
UnexpandEnvironmentVariables(LPCTSTR szPath) {
UINT cbNew;
LPTSTR szNew;
LPTSTR mszEnvVars;
LPTSTR szEnvVar;
DWORD dwEnvType;
BOOL bExpanded;
CString strKey;
CString strValueName;
CString str;
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (!strKey.LoadString(IDS_SECEDIT_KEY) ||
!strValueName.LoadString(IDS_ENV_VARS_REG_VALUE)) {
return NULL;
}
//
// Allocate memory for the new path
//
cbNew = lstrlen(szPath)+MAX_PATH+1;
szNew = (LPTSTR) LocalAlloc(LPTR,cbNew * sizeof(TCHAR));
if (!szNew) {
return NULL;
}
//
// Get Vars to expand from the registry
//
mszEnvVars = NULL;
if (ERROR_SUCCESS != MyRegQueryValue(HKEY_LOCAL_MACHINE, // hKeyRoot
strKey, // SubKey
strValueName, // ValueName
(LPVOID *)&mszEnvVars, // Value
&dwEnvType)) { // Reg Type
//
// Can't get any variables to expand
//
LocalFree(szNew);
return NULL;
}
//
// We need a multi-sz with the variables to replace in it
//
if (REG_MULTI_SZ != dwEnvType || mszEnvVars == NULL) //Bug350194, Yang Gao, 3/23/2001
{
LocalFree(szNew);
return NULL;
}
bExpanded = FALSE;
//
// Start at the beginning of the multi-sz block
//
szEnvVar = mszEnvVars;
while (*szEnvVar) {
if (UnExpandEnvironmentString(szPath,szEnvVar,szNew,cbNew)) {
//
// We can only unexpand (successfully) once
//
bExpanded = TRUE;
break;
}
//
// Advance szEnvVar to the end of this string
//
while (*szEnvVar) {
szEnvVar++;
}
//
// And the beginning of the next
//
szEnvVar++;
}
if (mszEnvVars) {
LocalFree(mszEnvVars);
}
if (!bExpanded) {
LocalFree(szNew);
szNew = NULL;
}
return szNew;
}
//+--------------------------------------------------------------------------
//
// Function: IsSystemDatabase
//
// Synopsis: Determine if a specific databse is the system database or a private one
//
// Arguments:
// [szDBPath] - The database path to check
//
// Returns: True if szDBPath is the system database, false otherwise
//
// History:
//
//---------------------------------------------------------------------------
BOOL
IsSystemDatabase(LPCTSTR szDBPath) {
CString szSysDB;
BOOL bIsSysDB;
DWORD rc;
DWORD RegType;
if (!szDBPath) {
return FALSE;
}
//Raid bug 261450, Yang Gao, 3/30/2001
if (FAILED(GetSystemDatabase(&szSysDB))) {
return FALSE;
}
//
// We found an appropriate szSysDB, so compare it with szDBPath
//
if (lstrcmp(szDBPath,szSysDB) == 0) {
bIsSysDB = TRUE;
} else {
bIsSysDB = FALSE;
}
return bIsSysDB;
}
//+--------------------------------------------------------------------------
//
// Function: GetSystemDatabase
//
// Synopsis: Get the name of the current system database
//
// Arguments:
// [szDBPath] - [in/out] a pointer for the name of the system database
// The caller is responsible for freeing it.
//
//
// Returns: S_OK if the system database is found, otherwise an error
//
// History:
//
//---------------------------------------------------------------------------
HRESULT
GetSystemDatabase(CString *szDBPath)
{
if (!szDBPath)
{
return E_INVALIDARG;
}
//Raid bug 261450, Yang Gao, 3/30/2001
CString sAppend;
sAppend.LoadString( IDS_DB_DEFAULT );
PWSTR pszPath = (LPTSTR)LocalAlloc( 0, (MAX_PATH + sAppend.GetLength() + 1) * sizeof(WCHAR));
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_WINDOWS, NULL, 0, pszPath)))
{
wcscpy( &(pszPath[lstrlen(pszPath)]), sAppend );
*szDBPath = pszPath;
if (pszPath)
{
LocalFree(pszPath);
pszPath = NULL;
}
return S_OK;
}
if (pszPath)
{
LocalFree(pszPath);
pszPath = NULL;
}
return E_FAIL;
}
//+--------------------------------------------------------------------------
//
// Function: ObjectStatusToString
//
// Synopsis: Convert an object status value to a printable string
//
// Arguments:
// [status] - [in] The status value to convert
// [str] - [out] The string to store the value in
//
//
//---------------------------------------------------------------------------
UINT
ObjectStatusToString(DWORD status, CString *strStatus) {
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if ( status & SCE_STATUS_PERMISSION_MISMATCH ) {
status = IDS_MISMATCH;
} else if (status & SCE_STATUS_AUDIT_MISMATCH) {
status = IDS_MISMATCH;
} else {
status &= 0x0F;
switch(status){
case SCE_STATUS_NOT_ANALYZED:
status = IDS_NOT_ANALYZED;
break;
case SCE_STATUS_GOOD:
status = IDS_OK ;
break;
case SCE_STATUS_MISMATCH:
status = IDS_MISMATCH;
break;
case SCE_STATUS_NOT_CONFIGURED:
//
// BUG 119215: The Analysis UI should never show "Not Defined"
// for the security of existing system objects
//
status = IDS_NOT_ANALYZED;
break;
case SCE_STATUS_CHILDREN_CONFIGURED:
status = IDS_CHILDREN_CONFIGURED;
break;
case SCE_STATUS_ERROR_NOT_AVAILABLE:
status = IDS_NOT_AVAILABLE;
break;
case SCE_STATUS_NEW_SERVICE:
status = IDS_NEW_SERVICE;
break;
default:
//
// We shouldn't get here, but for some reason we keep doing so
//
status = IDS_MISMATCH;
break;
}
}
if(strStatus){
strStatus->LoadString(status);
}
return status;
}
//+--------------------------------------------------------------------------
//
// Function: IsSecurityTemplate
//
// Synopsis: Validates a file to see if the file is a security template.
//
// Arguments: [pszFileName] - The full path to the file to check.
//
// Returns: FALSE if the file does not exist or is not a valid
// security template.
//
// TRUE if successful.
// History:
//
//---------------------------------------------------------------------------
BOOL
IsSecurityTemplate(
LPCTSTR pszFileName
)
{
if(!pszFileName){
return FALSE;
}
HANDLE hProfile;
SCESTATUS rc;
//
// Open the profile.
//
rc = SceOpenProfile(
pszFileName,
SCE_INF_FORMAT,
&hProfile
);
if(rc == SCESTATUS_SUCCESS && hProfile){
PSCE_PROFILE_INFO ProfileInfo = NULL;
PSCE_ERROR_LOG_INFO ErrBuf = NULL;
//
// The profile will be validated by trying to load all the security areas.
//
rc = SceGetSecurityProfileInfo(hProfile,
SCE_ENGINE_SCP,
AREA_ALL,
&ProfileInfo,
&ErrBuf);
if(ErrBuf){
rc = SCESTATUS_INVALID_DATA;
}
//
// Free up the memory.
//
SceFreeMemory((PVOID)ErrBuf, SCE_STRUCT_ERROR_LOG_INFO);
ErrBuf = NULL;
if ( ProfileInfo != NULL ) {
SceFreeMemory((PVOID)ProfileInfo, AREA_ALL);
LocalFree(ProfileInfo);
}
SceCloseProfile(&hProfile);
//
// return TRUE if everything is successful.
//
if(rc != SCESTATUS_INVALID_DATA){
return TRUE;
}
}
return FALSE;
}
//+--------------------------------------------------------------------------
//
// Function: WriteSprintf
//
// Synopsis: Writes formated [pszStr] to [pStm].
//
// Arguments: [pStm] - Stream to write to.
// [pszStr] - Format string to write.
// [...] - printf formating
//
// Returns: The total number of bytes written.
//
// History:
//
//---------------------------------------------------------------------------
int WriteSprintf( IStream *pStm, LPCTSTR pszStr, ...)
{
TCHAR szWrite[512];
va_list marker;
va_start(marker, pszStr);
vswprintf(szWrite, pszStr, marker);
va_end(marker);
ULONG nBytesWritten;
int iLen = lstrlen(szWrite);
if(pStm){
pStm->Write( szWrite, iLen * sizeof(TCHAR), &nBytesWritten );
return nBytesWritten;
}
return iLen;
}
//+--------------------------------------------------------------------------
//
// Function: ReadSprintf
//
// Synopsis: Reads formated [pszStr] from [pStm].
// supported character switches are
// 'd' - integer pointer.
//
// Arguments: [pStm] - Stream to read from.
// [pszStr] - Format string to test.
// [...] - pointer to the types defined by format
// specification types.
//
// Returns: Total number of bytes read from the stream
//
// History:
//
//---------------------------------------------------------------------------
int
ReadSprintf( IStream *pStm, LPCTSTR pszStr, ...)
{
if(!pStm || !pszStr){
return -1;
}
va_list marker;
va_start(marker, pszStr);
TCHAR szRead[256];
TCHAR szConv[512];
ULONG uRead = 0;
int i = 0;
LPCTSTR pszNext = szRead;
int iTotalRead = 0;
// Get the current seek position.
ULARGE_INTEGER liBack = { 0 };
LARGE_INTEGER liCur = { 0 };
pStm->Seek( liCur, STREAM_SEEK_CUR, &liBack);
#define INCBUFFER(sz)\
if(uRead){\
(sz)++;\
uRead--;\
} else {\
pStm->Read(szRead, 256 * sizeof(TCHAR), &uRead);\
uRead = uRead/sizeof(TCHAR);\
(sz) = szRead;\
}\
iTotalRead++;
while(*pszStr){
if(!uRead){
// Read information into buffer.
pStm->Read( szRead, 256 * sizeof(TCHAR), &uRead);
pszNext = szRead;
uRead = uRead/sizeof(TCHAR);
if(!uRead){
iTotalRead = -1;
break;
}
}
if(*pszStr == '%'){
pszStr++;
switch( *pszStr ){
case 'd':
// read integer.
pszStr++;
i = 0;
// copy number to our own buffer.
while( (*pszNext >= L'0' && *pszNext <= L'9') ){
szConv[i++] = *pszNext;
INCBUFFER( pszNext );
}
szConv[i] = 0;
// convert string to integer.
*(va_arg(marker, int *)) = _wtol(szConv);
continue;
case 's':
pszStr++;
i = 0;
// we have to have some kind of terminating character se we will use the
// next value in pszStr.
while( *pszNext && (*pszNext != *pszStr) ){
szConv[i++] = *pszNext;
INCBUFFER( pszNext );
}
if(*pszNext == *pszStr){
INCBUFFER( pszNext );
}
// copy the string value.
szConv[i] = 0;
if( i ){
LPTSTR pNew = (LPTSTR)LocalAlloc(0, sizeof(TCHAR) * (i + 1));
if(NULL != pNew){
lstrcpy(pNew, szConv);
}
LPTSTR *pArg;
pArg = (va_arg(marker, LPTSTR *));
if (pArg) {
*pArg = pNew;
}
} else {
va_arg(marker, LPTSTR *);
}
pszStr++;
continue;
}
}
// check to make sure we are at the correct position in the file.
if(*pszStr != *pszNext){
iTotalRead = -1;
break;
}
pszStr++;
// increment buffer pointer.
INCBUFFER( pszNext );
}
va_end(marker);
// Reset streem seek pointer.
liCur.LowPart = liBack.LowPart;
if(iTotalRead >= 0){
liCur.LowPart += iTotalRead * sizeof(TCHAR);
}
liCur.HighPart = liBack.HighPart;
pStm->Seek(liCur, STREAM_SEEK_SET, NULL);
return iTotalRead;
#undef INCBUFFER
}
//+--------------------------------------------------------------------------------
// FileCreateError
//
// This function tries to create a new file use [pszFile]. It will display a
// message to the user if the file cannot be created.
//
// Arguments: [pszFile] - Full path of file to create.
// [dwFlags] - Flags
// FCE_IGNORE_FILEEXISTS - Ignore File exists error, and
// delete the file.
//
// Returns: IDYES the file can be created
// IDNo The file cannot be created
DWORD
FileCreateError(
LPCTSTR pszFile,
DWORD dwFlags
)
{
if(!pszFile){
return ERROR_INVALID_PARAMETER;
}
HANDLE hFile;
DWORD dwErr = IDNO;
//
// Try to create the file.
//
hFile = ExpandAndCreateFile(
pszFile,
GENERIC_WRITE,
0,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_ARCHIVE,
NULL
);
if(hFile == INVALID_HANDLE_VALUE){
//
// Post error message to user.
//
dwErr = GetLastError();
LPTSTR pszErr;
CString strErr;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwErr,
0,
(LPTSTR)&pszErr,
0,
NULL
);
strErr = pszErr;
strErr += pszFile;
if(pszErr){
LocalFree(pszErr);
}
switch(dwErr){
case ERROR_ALREADY_EXISTS:
case ERROR_FILE_EXISTS:
if( dwFlags & FCE_IGNORE_FILEEXISTS ){
dwErr = IDYES;
break;
}
//
// Confirm overwrite.
//
strErr.Format(IDS_FILE_EXISTS_FMT, pszFile);
dwErr = AfxMessageBox(
strErr,
MB_YESNO
);
break;
default:
//
// The file cannot be created.
//
AfxMessageBox(
strErr,
MB_OK
);
dwErr = IDNO;
break;
}
} else {
//
// It's OK to create the file.
//
::CloseHandle( hFile );
DeleteFile(pszFile);
dwErr = IDYES;
}
return dwErr;
}
//+--------------------------------------------------------------------------
//
// Function: IsDBCSPath
//
// Synopsis: Check if a path contains DBCS characters
//
// Arguments: [pszFile] - [in] The path to check
//
// Returns: TRUE if pszFile contains characters that can't be
// represented by a LPSTR
//
// FALSE if pszFile only contains characters that can
// be represented by a LPSTR
//
//
//+--------------------------------------------------------------------------
BOOL
IsDBCSPath(LPCTSTR szWideFile) {
while(*szWideFile) {
if (*szWideFile >= 256) {
return TRUE;
}
szWideFile++;
}
return FALSE;
/*
LPSTR szMBFile;
int nMBFile;
BOOL bUsedDefaultChar = FALSE;
nMBFile = sizeof(LPSTR)*(lstrlen(szWideFile));
szMBFile = (LPSTR)LocalAlloc(LPTR,nMBFile+1);
if (szMBFile) {
WideCharToMultiByte( CP_ACP,
0,
szWideFile,
-1,
szMBFile,
nMBFile,
NULL,
&bUsedDefaultChar);
LocalFree(szMBFile);
}
return bUsedDefaultChar;
*/
}
//+--------------------------------------------------------------------------
//
// Function: GetSeceditHelpFilename
//
// Synopsis: Return the fully qualified path the help file for Secedit
//
// Arguments: None
//
// Returns: a CString containing the fully qualified help file name.
//
//
//+--------------------------------------------------------------------------
CString GetSeceditHelpFilename()
{
static CString helpFileName;
if ( helpFileName.IsEmpty () )
{
UINT result = ::GetSystemWindowsDirectory (
helpFileName.GetBufferSetLength (MAX_PATH+1), MAX_PATH);
ASSERT(result != 0 && result <= MAX_PATH);
helpFileName.ReleaseBuffer ();
helpFileName += L"\\help\\wsecedit.hlp";
}
return helpFileName;
}
//+--------------------------------------------------------------------------
//
// Function: GetGpeditHelpFilename
//
// Synopsis: Return the fully qualified path the help file for Secedit
//
// Arguments: None
//
// Returns: a CString containing the fully qualified help file name.
//
//
//+--------------------------------------------------------------------------
CString GetGpeditHelpFilename()
{
static CString helpFileName;
if ( helpFileName.IsEmpty () )
{
UINT result = ::GetSystemWindowsDirectory (
helpFileName.GetBufferSetLength (MAX_PATH+1), MAX_PATH);
ASSERT(result != 0 && result <= MAX_PATH);
helpFileName.ReleaseBuffer ();
helpFileName += L"\\help\\gpedit.hlp";
}
return helpFileName;
}
//+--------------------------------------------------------------------------
//
// Function: ExpandEnvironmentStringWrapper
//
// Synopsis: Takes an LPTSTR and expands the enviroment variables in it
//
// Arguments: Pointer to the string to expand.
//
// Returns: a CString containing the fully expanded string.
//
//+--------------------------------------------------------------------------
CString ExpandEnvironmentStringWrapper(LPCTSTR psz)
{
LPTSTR pszBuffer = NULL;
DWORD dwExpanded = 0;
CString sz;
dwExpanded = ExpandEnvironmentStrings(psz, NULL, 0);
pszBuffer = sz.GetBuffer(dwExpanded);
ExpandEnvironmentStrings(psz, pszBuffer, dwExpanded);
sz.ReleaseBuffer(dwExpanded);
return (sz);
}
//+--------------------------------------------------------------------------
//
// Function: ExpandAndCreateFile
//
// Synopsis: Just does a normal CreateFile(), but expands the filename before
// creating the file.
//
// Arguments: Same as CreateFile().
//
// Returns: HANDLE to the created file.
//
//+--------------------------------------------------------------------------
HANDLE WINAPI ExpandAndCreateFile (
LPCTSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
)
{
HANDLE hRet = INVALID_HANDLE_VALUE;
CString sz;
sz = ExpandEnvironmentStringWrapper(lpFileName);
return (CreateFile(
sz,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile));
}
//**********************************************************************
//
// FUNCTION: IsAdmin - This function checks the token of the
// calling thread to see if the caller belongs to
// the Administrators group.
//
// PARAMETERS: none
//
// RETURN VALUE: TRUE if the caller is an administrator on the local
// machine. Otherwise, FALSE.
//
//**********************************************************************
BOOL IsAdmin(void) {
HANDLE hAccessToken = NULL;
PTOKEN_GROUPS ptgGroups = NULL;
DWORD cbGroups = 0;
PSID psidAdmin = NULL;
UINT i;
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
// assume the caller is not an administrator
BOOL bIsAdmin = FALSE;
__try {
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,
&hAccessToken)) {
if (GetLastError() != ERROR_NO_TOKEN)
__leave;
// retry against process token if no thread token exists
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY,
&hAccessToken))
__leave;
}
// determine required size of buffer for token information
if (GetTokenInformation(hAccessToken, TokenGroups, NULL, 0,
&cbGroups)) {
// call should have failed due to zero-length buffer
__leave;
} else {
// call should have failed due to zero-length buffer
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
__leave;
}
// allocate a buffer to hold the token groups
ptgGroups = (PTOKEN_GROUPS) HeapAlloc(GetProcessHeap(), 0,
cbGroups);
if (!ptgGroups)
__leave;
// call GetTokenInformation() again to actually retrieve the groups
if (!GetTokenInformation(hAccessToken, TokenGroups, ptgGroups,
cbGroups, &cbGroups))
__leave;
// create a SID for the local administrators group
if (!AllocateAndInitializeSid(&siaNtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &psidAdmin))
__leave;
// scan the token's groups and compare the SIDs to the admin SID
for (i = 0; i < ptgGroups->GroupCount; i++) {
if (EqualSid(psidAdmin, ptgGroups->Groups[i].Sid)) {
bIsAdmin = TRUE;
break;
}
}
} __finally {
// free resources
if (hAccessToken)
CloseHandle(hAccessToken);
if (ptgGroups)
HeapFree(GetProcessHeap(), 0, ptgGroups);
if (psidAdmin)
FreeSid(psidAdmin);
}
return bIsAdmin;
}
//+--------------------------------------------------------------------------
//
// Function: MultiSZToSZ
//
// Synopsis: Converts a multiline string to a comma delimited normal string
//
// Returns: The converted string
//
//+--------------------------------------------------------------------------
PWSTR MultiSZToSZ(PCWSTR sz)
{
PWSTR szOut = NULL;
ASSERT(sz);
if (!sz)
{
return NULL;
}
//Bug 349000, Yang Gao, 3/23/2001
long i = 0;
long j = 0;
while( L'\0' != sz[i] )
{
if( L',' == sz[i] )
j++;
i++;
}
szOut = (PWSTR) LocalAlloc(LPTR,(lstrlen(sz)+j*2+1)*sizeof(wchar_t)); //Raid #376228, 4/25/2001
if (!szOut)
{
return NULL;
}
for(i=0,j=0; sz[i] != L'\0'; i++)
{
if( L'\n' == sz[i] )
{
szOut[j++] = MULTISZ_DELIMITER;
continue;
}
if( L'\r' == sz[i] )
{
continue; // ignore it
}
if( L',' == sz[i] )
{
szOut[j++] = MULTISZ_QUOTE;
szOut[j++] = sz[i];
szOut[j++] = MULTISZ_QUOTE;
continue;
}
szOut[j++] = sz[i];
}
return szOut;
}
//+--------------------------------------------------------------------------
//
// Function: SZToMultiSZ
//
// Synopsis: Converts a comma delimited string to a multiline string
//
// Returns: The converted string
//
//+--------------------------------------------------------------------------
PWSTR SZToMultiSZ(PCWSTR sz)
{
PWSTR szOut = NULL;
ASSERT(sz);
if (!sz)
{
return NULL;
}
//
// Calculate the length of the expanded string
//
int cSZ = 0;
for (int i = 0;sz[i] != L'\0'; i++)
{
if (MULTISZ_DELIMITER == sz[i])
{
//
// Delimiter expands into an extra character so count it twice
//
cSZ++;
}
cSZ++;
}
szOut = (PWSTR) LocalAlloc(LPTR,(cSZ+1)*sizeof(wchar_t));
if (!szOut)
{
return NULL;
}
BOOL qflag = FALSE;
for(int i=0, c=0; sz[i] != L'\0'; i++)
{
//Bug 349000, Yang Gao, 3/23/2001
if( MULTISZ_QUOTE == sz[i] && MULTISZ_DELIMITER == sz[i+1] )
{
qflag = TRUE;
continue;
}
if( MULTISZ_DELIMITER == sz[i] && MULTISZ_QUOTE == sz[i+1] && qflag )
{
szOut[c++] = sz[i];
i++;
qflag = FALSE;
continue;
}
qflag = FALSE;
if (MULTISZ_DELIMITER == sz[i])
{
szOut[c++] = L'\r';
szOut[c++] = L'\n';
}
else
{
szOut[c++] = sz[i];
}
}
return szOut;
}
//+--------------------------------------------------------------------------
//
// Function: MultiSZToDisp
//
// Synopsis: Converts a comma delimited multiline string to a display string
//
// Returns: The converted string
// Bug 349000, Yang Gao, 3/23/2001
//+--------------------------------------------------------------------------
void MultiSZToDisp(PCWSTR sz, CString &pszOut)
{
ASSERT(sz);
if (!sz)
{
return;
}
//
// Calculate the length of the expanded string
//
int cSZ = 0;
for (int i = 0;sz[i] != L'\0'; i++)
{
if (MULTISZ_DELIMITER == sz[i])
{
//
// Delimiter expands into an extra character so count it twice
//
cSZ++;
}
cSZ++;
}
PWSTR szOut;
szOut = (PWSTR) LocalAlloc(LPTR,(cSZ+1)*sizeof(wchar_t));
if (!szOut)
{
return;
}
BOOL qflag = FALSE;
for(int i=0, c=0; sz[i] != L'\0'; i++)
{
if( MULTISZ_QUOTE == sz[i] && MULTISZ_DELIMITER == sz[i+1] )
{
qflag = TRUE;
continue;
}
if( MULTISZ_DELIMITER == sz[i] && MULTISZ_QUOTE == sz[i+1] && qflag )
{
szOut[c++] = sz[i];
i++;
qflag = FALSE;
continue;
}
qflag = FALSE;
szOut[c++] = sz[i];
}
pszOut = szOut;
LocalFree(szOut);
return;
}
SCE_PROFILE_INFO *g_pDefaultTemplate = NULL;
SCE_PROFILE_INFO *
GetDefaultTemplate() {
SCE_PROFILE_INFO *pspi = NULL;
DWORD RegType = 0;
SCESTATUS rc = 0;
LPTSTR szInfFile = NULL;
PVOID pHandle = NULL;
if (g_pDefaultTemplate) {
return g_pDefaultTemplate;
}
rc = MyRegQueryValue(HKEY_LOCAL_MACHINE,
SCE_REGISTRY_KEY,
SCE_REGISTRY_DEFAULT_TEMPLATE,
(PVOID *)&szInfFile,
&RegType );
if (ERROR_SUCCESS != rc) {
if (szInfFile) {
LocalFree(szInfFile);
szInfFile = NULL;
}
return NULL;
}
if (EngineOpenProfile(szInfFile,OPEN_PROFILE_CONFIGURE,&pHandle) != SCESTATUS_SUCCESS) {
LocalFree(szInfFile);
szInfFile = NULL;
return NULL;
}
LocalFree(szInfFile);
szInfFile = NULL;
rc = SceGetSecurityProfileInfo(pHandle,
SCE_ENGINE_SCP,
AREA_ALL,
&pspi,
NULL
);
SceCloseProfile(&pHandle);
if (SCESTATUS_SUCCESS != rc) {
//
// expand registry value section based on registry values list on local machine
//
SceRegEnumAllValues(
&(pspi->RegValueCount),
&(pspi->aRegValues)
);
#define PD(X,Y) if (pspi->X == SCE_NO_VALUE) { pspi->X = Y; }
PD(MaximumPasswordAge,MAX_PASS_AGE_DEFAULT)
PD(MinimumPasswordAge,MIN_PASS_AGE_DEFAULT)
PD(MinimumPasswordLength,MIN_PASS_LENGTH_DEFAULT)
PD(PasswordHistorySize,PASS_HISTORY_SIZE_DEFAULT)
PD(PasswordComplexity,PASS_COMPLEXITY_DEFAULT)
PD(RequireLogonToChangePassword,REQUIRE_LOGIN_DEFAULT)
PD(LockoutBadCount,LOCKOUT_BAD_COUNT_DEFAULT)
PD(ResetLockoutCount,RESET_LOCKOUT_COUNT_DEFAULT)
PD(LockoutDuration,LOCKOUT_DURATION_DEFAULT)
PD(AuditSystemEvents,AUDIT_SYSTEM_EVENTS_DEFAULT)
PD(AuditLogonEvents,AUDIT_LOGON_EVENTS_DEFAULT)
PD(AuditObjectAccess,AUDIT_OBJECT_ACCESS_DEFAULT)
PD(AuditPrivilegeUse,AUDIT_PRIVILEGE_USE_DEFAULT)
PD(AuditPolicyChange,AUDIT_POLICY_CHANGE_DEFAULT)
PD(AuditAccountManage,AUDIT_ACCOUNT_MANAGE_DEFAULT)
PD(AuditProcessTracking,AUDIT_PROCESS_TRACKING_DEFAULT)
PD(AuditDSAccess,AUDIT_DS_ACCESS_DEFAULT)
PD(AuditAccountLogon,AUDIT_ACCOUNT_LOGON_DEFAULT)
PD(ForceLogoffWhenHourExpire,FORCE_LOGOFF_DEFAULT)
PD(EnableAdminAccount,ENABLE_ADMIN_DEFAULT)
PD(EnableGuestAccount,ENABLE_GUEST_DEFAULT)
PD(LSAAnonymousNameLookup,LSA_ANON_LOOKUP_DEFAULT)
PD(MaximumLogSize[EVENT_TYPE_SYSTEM],SYS_MAX_LOG_SIZE_DEFAULT)
PD(MaximumLogSize[EVENT_TYPE_APP],APP_MAX_LOG_SIZE_DEFAULT)
PD(MaximumLogSize[EVENT_TYPE_SECURITY],SEC_MAX_LOG_SIZE_DEFAULT)
PD(AuditLogRetentionPeriod[EVENT_TYPE_SYSTEM],SYS_LOG_RETENTION_PERIOD_DEFAULT)
PD(AuditLogRetentionPeriod[EVENT_TYPE_APP],APP_LOG_RETENTION_PERIOD_DEFAULT)
PD(AuditLogRetentionPeriod[EVENT_TYPE_SECURITY],SEC_LOG_RETENTION_PERIOD_DEFAULT)
PD(RetentionDays[EVENT_TYPE_APP],APP_LOG_RETENTION_DAYS_DEFAULT)
PD(RetentionDays[EVENT_TYPE_SYSTEM],SYS_LOG_RETENTION_DAYS_DEFAULT)
PD(RetentionDays[EVENT_TYPE_SECURITY],SEC_LOG_RETENTION_DAYS_DEFAULT)
PD(RestrictGuestAccess[EVENT_TYPE_APP],APP_RESTRICT_GUEST_ACCESS_DEFAULT)
PD(RestrictGuestAccess[EVENT_TYPE_SYSTEM],SYS_RESTRICT_GUEST_ACCESS_DEFAULT)
PD(RestrictGuestAccess[EVENT_TYPE_SECURITY],SEC_RESTRICT_GUEST_ACCESS_DEFAULT)
if (pspi->pFiles.pAllNodes->Count == 0) {
DWORD SDSize = 0;
pspi->pFiles.pAllNodes->Count = 1;
pspi->pFiles.pAllNodes->pObjectArray[0] =
(PSCE_OBJECT_SECURITY) LocalAlloc(LPTR,sizeof(SCE_OBJECT_SECURITY));
if (pspi->pFiles.pAllNodes->pObjectArray[0]) {
SceSvcConvertTextToSD (
FILE_SYSTEM_SECURITY_DEFAULT,
&(pspi->pFiles.pAllNodes->pObjectArray[0]->pSecurityDescriptor),
&SDSize,
&(pspi->pFiles.pAllNodes->pObjectArray[0]->SeInfo)
);
}
}
if (pspi->pRegistryKeys.pAllNodes->Count == 0) {
DWORD SDSize = 0;
pspi->pRegistryKeys.pAllNodes->Count = 1;
pspi->pRegistryKeys.pAllNodes->pObjectArray[0] =
(PSCE_OBJECT_SECURITY) LocalAlloc(LPTR,sizeof(SCE_OBJECT_SECURITY));
if (pspi->pRegistryKeys.pAllNodes->pObjectArray[0]) {
SceSvcConvertTextToSD (
REGISTRY_SECURITY_DEFAULT,
&(pspi->pRegistryKeys.pAllNodes->pObjectArray[0]->pSecurityDescriptor),
&SDSize,
&(pspi->pRegistryKeys.pAllNodes->pObjectArray[0]->SeInfo)
);
}
}
if (pspi->pServices->General.pSecurityDescriptor == NULL) {
DWORD SDSize = 0;
SceSvcConvertTextToSD (
SERVICE_SECURITY_DEFAULT,
&(pspi->pServices->General.pSecurityDescriptor),
&SDSize,
&(pspi->pServices->SeInfo)
);
}
}
g_pDefaultTemplate = pspi;
return pspi;
}
HRESULT
GetDefaultFileSecurity(PSECURITY_DESCRIPTOR *ppSD,
SECURITY_INFORMATION *pSeInfo) {
SCE_PROFILE_INFO *pspi = NULL;
ASSERT(ppSD);
ASSERT(pSeInfo);
if (!ppSD || !pSeInfo) {
return E_INVALIDARG;
}
pspi = GetDefaultTemplate();
*ppSD = NULL;
*pSeInfo = 0;
if (!pspi) {
return E_FAIL;
}
if (!pspi->pFiles.pAllNodes) {
return E_FAIL;
}
if (pspi->pFiles.pAllNodes->Count == 0) {
return E_FAIL;
}
*pSeInfo = pspi->pFiles.pAllNodes->pObjectArray[0]->SeInfo;
return MyMakeSelfRelativeSD(pspi->pFiles.pAllNodes->pObjectArray[0]->pSecurityDescriptor,
ppSD);
}
HRESULT
GetDefaultRegKeySecurity(PSECURITY_DESCRIPTOR *ppSD,
SECURITY_INFORMATION *pSeInfo) {
SCE_PROFILE_INFO *pspi = NULL;
ASSERT(ppSD);
ASSERT(pSeInfo);
if (!ppSD || !pSeInfo) {
return E_INVALIDARG;
}
pspi = GetDefaultTemplate();
*ppSD = NULL;
*pSeInfo = 0;
if (!pspi) {
return E_FAIL;
}
if (!pspi->pRegistryKeys.pAllNodes) {
return E_FAIL;
}
if (pspi->pRegistryKeys.pAllNodes->Count == 0) {
return E_FAIL;
}
*pSeInfo = pspi->pRegistryKeys.pAllNodes->pObjectArray[0]->SeInfo;
return MyMakeSelfRelativeSD(pspi->pRegistryKeys.pAllNodes->pObjectArray[0]->pSecurityDescriptor,
ppSD);
}
HRESULT
GetDefaultServiceSecurity(PSECURITY_DESCRIPTOR *ppSD,
SECURITY_INFORMATION *pSeInfo) {
SCE_PROFILE_INFO *pspi = NULL;
ASSERT(ppSD);
ASSERT(pSeInfo);
if (!ppSD || !pSeInfo) {
return E_INVALIDARG;
}
pspi = GetDefaultTemplate();
*ppSD = NULL;
*pSeInfo = 0;
if (!pspi) {
return E_FAIL;
}
if (!pspi->pServices) {
return E_FAIL;
}
*pSeInfo = pspi->pServices->SeInfo;
return MyMakeSelfRelativeSD(pspi->pServices->General.pSecurityDescriptor,
ppSD);
}
BOOL
GetSecureWizardName(
OUT LPTSTR *ppstrPathName OPTIONAL,
OUT LPTSTR *ppstrDisplayName OPTIONAL
)
{
BOOL b=FALSE;
if ( ppstrPathName == NULL && ppstrDisplayName == NULL) return FALSE;
if ( ppstrPathName )
*ppstrPathName = NULL;
if ( ppstrDisplayName )
*ppstrDisplayName = NULL;
#define SCE_WIZARD_PATH SCE_ROOT_PATH TEXT("\\Wizard")
DWORD rc;
DWORD RegType;
LPVOID pValue=NULL;
PWSTR pPathName = NULL;
rc = MyRegQueryValue(HKEY_LOCAL_MACHINE,
SCE_WIZARD_PATH,
TEXT("Path"),
&pValue,
&RegType
);
if ( ERROR_SUCCESS == rc && pValue &&
(RegType == REG_SZ ||
RegType == REG_EXPAND_SZ) ) {
if ( RegType == REG_EXPAND_SZ ) {
//
// Expand the environment variable
//
DWORD dSize = ExpandEnvironmentStrings((LPTSTR)pValue, NULL, 0);
if ( dSize > 0 ) {
pPathName = (PWSTR)LocalAlloc(LPTR, (dSize+1)*sizeof(WCHAR));
if ( pPathName ) {
ExpandEnvironmentStrings((LPTSTR)pValue, pPathName, dSize);
} else {
LocalFree(pValue);
return FALSE;
}
} else {
LocalFree(pValue);
return FALSE;
}
} else {
//
// just simply take the string
//
pPathName = (LPTSTR)pValue;
pValue = NULL;
}
if ( ppstrDisplayName ) {
//
// now query the display name (menu name) from the binary
// binary name is stored in pPathName (can't be NULL)
//
DWORD dwHandle=0;
DWORD dwSize = GetFileVersionInfoSize(pPathName, &dwHandle);
if ( dwSize > 0 ) {
LPVOID pBuffer = (LPVOID)LocalAlloc(LPTR, dwSize+1);
if ( pBuffer ) {
if ( GetFileVersionInfo(pPathName, 0, dwSize, pBuffer) ) {
PVOID lpInfo = 0;
UINT cch = 0;
CString key;
WCHAR szBuffer[10];
CString keyBase;
wsprintf (szBuffer, L"%04X", GetUserDefaultLangID ());
wcscat (szBuffer, L"04B0");
keyBase = L"\\StringFileInfo\\";
keyBase += szBuffer;
keyBase += L"\\";
key = keyBase + L"FileDescription";
if ( VerQueryValue (pBuffer, const_cast <PWSTR>((PCWSTR) key), &lpInfo, &cch) ) {
*ppstrDisplayName = (PWSTR)LocalAlloc(LPTR,(cch+1)*sizeof(WCHAR));
if ( *ppstrDisplayName ) {
wcscpy(*ppstrDisplayName, (PWSTR)lpInfo);
b=TRUE;
}
}
}
LocalFree(pBuffer);
}
}
}
//
// get the binary name
//
if ( ppstrPathName ) {
*ppstrPathName = pPathName;
pPathName = NULL;
b=TRUE;
}
}
if ( pPathName && (pPathName != pValue ) ) {
LocalFree(pPathName);
}
if ( pValue ) {
LocalFree(pValue);
}
return b;
}