windows-nt/Source/XPSP1/NT/inetsrv/iis/setup/osrc/setuputl.cpp
2020-09-26 16:20:57 +08:00

2981 lines
97 KiB
C++

#include "stdafx.h"
#include <setupapi.h>
#include <shlobj.h>
#include <ole2.h>
#include "lzexpand.h"
#include "log.h"
#include "dcomperm.h"
#include "strfn.h"
#include "other.h"
#include <direct.h>
#include <aclapi.h>
typedef struct _QUEUECONTEXT {
HWND OwnerWindow;
DWORD MainThreadId;
HWND ProgressDialog;
HWND ProgressBar;
BOOL Cancelled;
PTSTR CurrentSourceName;
BOOL ScreenReader;
BOOL MessageBoxUp;
WPARAM PendingUiType;
PVOID PendingUiParameters;
UINT CancelReturnCode;
BOOL DialogKilled;
//
// If the SetupInitDefaultQueueCallbackEx is used, the caller can
// specify an alternate handler for progress. This is useful to
// get the default behavior for disk prompting, error handling, etc,
// but to provide a gas gauge embedded, say, in a wizard page.
//
// The alternate window is sent ProgressMsg once when the copy queue
// is started (wParam = 0. lParam = number of files to copy).
// It is then also sent once per file copied (wParam = 1. lParam = 0).
//
// NOTE: a silent installation (i.e., no progress UI) can be accomplished
// by specifying an AlternateProgressWindow handle of INVALID_HANDLE_VALUE.
//
HWND AlternateProgressWindow;
UINT ProgressMsg;
UINT NoToAllMask;
HANDLE UiThreadHandle;
#ifdef NOCANCEL_SUPPORT
BOOL AllowCancel;
#endif
} QUEUECONTEXT, *PQUEUECONTEXT;
//-------------------------------------------------------------------
// purpose: install an section in an .inf file
//-------------------------------------------------------------------
int InstallInfSection_NoFiles(HINF InfHandle,TCHAR szINFFileName[],TCHAR szSectionName[])
{
HWND Window = NULL;
BOOL bReturn = FALSE;
BOOL bReturnTemp = FALSE; // assume failure.
TCHAR ActualSection[1000];
DWORD ActualSectionLength;
BOOL bPleaseCloseInfHandle = FALSE;
iisDebugOut_Start1(_T("InstallInfSection_NoFiles"),szSectionName,LOG_TYPE_PROGRAM_FLOW);
__try {
// Check if a valid infhandle as passed in....
// if so, use that, otherwise, use the passed in filename...
if(InfHandle == INVALID_HANDLE_VALUE)
{
// Try to use the filename.
if (_tcsicmp(szINFFileName, _T("")) == 0)
{
goto c1;
}
// we have a filename entry. let's try to use it.
// Check if the file exists
if (!IsFileExist(szINFFileName))
{
//MessageBox(NULL, "unable to find file", "cannot find file", MB_OK);
goto c1;
}
// Load the inf file and get the handle
InfHandle = SetupOpenInfFile(szINFFileName, NULL, INF_STYLE_WIN4, NULL);
bPleaseCloseInfHandle = TRUE;
}
if(InfHandle == INVALID_HANDLE_VALUE) {goto c1;}
//
// See if there is an nt-specific section
//
SetupDiGetActualSectionToInstall(InfHandle,szSectionName,ActualSection,sizeof(ActualSection),&ActualSectionLength,NULL);
//
// Perform non-file operations for the section passed on the cmd line.
//
bReturn = SetupInstallFromInfSection(Window,InfHandle,ActualSection,SPINST_ALL & ~SPINST_FILES,NULL,NULL,0,NULL,NULL,NULL,NULL);
if(!bReturn) {goto c1;}
//
// Install any services for the section
//
bReturn = SetupInstallServicesFromInfSection(InfHandle,ActualSection,0);
if(!bReturn)
{
iisDebugOut((LOG_TYPE_TRACE, _T("SetupInstallServicesFromInfSection failed.Ret=%d.\n"), GetLastError()));
}
//
// Refresh the desktop.
//
SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_FLUSHNOWAIT,0,0);
//
// If we get to here, then this routine has been successful.
//
bReturnTemp = TRUE;
c1:
//
// If the bReturnTemp failed and it was because the user cancelled, then we don't want to consider
// that as an bReturnTemp (i.e., we don't want to give an bReturnTemp popup later).
//
if((bReturnTemp != TRUE) && (GetLastError() == ERROR_CANCELLED)) {bReturnTemp = TRUE;}
if (bPleaseCloseInfHandle == TRUE)
{
if(InfHandle != INVALID_HANDLE_VALUE) {SetupCloseInfFile(InfHandle);InfHandle = INVALID_HANDLE_VALUE;}
}
;}
__except(EXCEPTION_EXECUTE_HANDLER)
{
if (bPleaseCloseInfHandle == TRUE)
{
if(InfHandle != INVALID_HANDLE_VALUE) {SetupCloseInfFile(InfHandle);InfHandle = INVALID_HANDLE_VALUE;}
}
}
//
// If the bReturnTemp failed because the user cancelled, then we don't want to consider
// that as an bReturnTemp (i.e., we don't want to give an bReturnTemp popup later).
//
if((bReturnTemp != TRUE) && (GetLastError() == ERROR_CANCELLED)) {bReturnTemp = TRUE;}
// Display installation failed message
//if(bReturnTemp) {MyMessageBox(NULL, _T("IDS_INF_FAILED"), MB_OK);}
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("InstallInfSection_NoFiles.[%s].End.Ret=%d.\n"), szSectionName, bReturnTemp));
return bReturnTemp;
}
//-------------------------------------------------------------------
// purpose: install an section in an .inf file
//-------------------------------------------------------------------
int InstallInfSection(HINF InfHandle,TCHAR szINFFileName[],TCHAR szSectionName[])
{
HWND Window = NULL;
PTSTR SourcePath = NULL;
//HINF InfHandle = INVALID_HANDLE_VALUE;
HSPFILEQ FileQueue = INVALID_HANDLE_VALUE;
PQUEUECONTEXT QueueContext = NULL;
BOOL bReturn = FALSE;
BOOL bReturnTemp = FALSE; // assume failure.
TCHAR ActualSection[1000];
DWORD ActualSectionLength;
BOOL bPleaseCloseInfHandle = FALSE;
iisDebugOut_Start1(_T("InstallInfSection"),szSectionName,LOG_TYPE_PROGRAM_FLOW);
__try {
// Check if a valid infhandle as passed in....
// if so, use that, otherwise, use the passed in filename...
if(InfHandle == INVALID_HANDLE_VALUE)
{
// Try to use the filename.
if (_tcsicmp(szINFFileName, _T("")) == 0)
{
goto c1;
}
// we have a filename entry. let's try to use it.
// Check if the file exists
if (!IsFileExist(szINFFileName))
{
//MessageBox(NULL, "unable to find file", "cannot find file", MB_OK);
goto c1;
}
// Load the inf file and get the handle
InfHandle = SetupOpenInfFile(szINFFileName, NULL, INF_STYLE_WIN4, NULL);
bPleaseCloseInfHandle = TRUE;
}
if(InfHandle == INVALID_HANDLE_VALUE) {goto c1;}
//
// See if there is an nt-specific section
//
SetupDiGetActualSectionToInstall(InfHandle,szSectionName,ActualSection,sizeof(ActualSection),&ActualSectionLength,NULL);
//
// Create a setup file queue and initialize the default queue callback.
//
FileQueue = SetupOpenFileQueue();
if(FileQueue == INVALID_HANDLE_VALUE) {goto c1;}
//QueueContext = SetupInitDefaultQueueCallback(Window);
//if(!QueueContext) {goto c1;}
QueueContext = (PQUEUECONTEXT) SetupInitDefaultQueueCallbackEx(Window,NULL,0,0,0);
if(!QueueContext) {goto c1;}
QueueContext->PendingUiType = IDF_CHECKFIRST;
//
// Enqueue file operations for the section passed on the cmd line.
//
//SourcePath = NULL;
// SP_COPY_NOPRUNE = setupapi has a new deal which will prune files from the copyqueue if they already exist on the system.
// however, the problem with the new deal is that the pruning code does not check if you have the same file
// queued in the delete or rename queue. specify SP_COPY_NOPRUNE to make sure that our file never gets
// pruned (removed) from the copy queue. aaronl 12/4/98
//bReturn = SetupInstallFilesFromInfSection(InfHandle,NULL,FileQueue,ActualSection,SourcePath,SP_COPY_NEWER | SP_COPY_NOPRUNE);
bReturn = SetupInstallFilesFromInfSection(InfHandle,NULL,FileQueue,ActualSection,SourcePath, SP_COPY_NOPRUNE);
if(!bReturn) {goto c1;}
//
// Commit file queue.
//
if(!SetupCommitFileQueue(Window, FileQueue, SetupDefaultQueueCallback, QueueContext)) {goto c1;}
//
// Perform non-file operations for the section passed on the cmd line.
//
bReturn = SetupInstallFromInfSection(Window,InfHandle,ActualSection,SPINST_ALL & ~SPINST_FILES,NULL,NULL,0,NULL,NULL,NULL,NULL);
if(!bReturn) {goto c1;}
//
// Refresh the desktop.
//
SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_FLUSHNOWAIT,0,0);
//
// If we get to here, then this routine has been successful.
//
bReturnTemp = TRUE;
c1:
//
// If the bReturnTemp failed and it was because the user cancelled, then we don't want to consider
// that as an bReturnTemp (i.e., we don't want to give an bReturnTemp popup later).
//
if((bReturnTemp != TRUE) && (GetLastError() == ERROR_CANCELLED)) {bReturnTemp = TRUE;}
if(QueueContext) {SetupTermDefaultQueueCallback(QueueContext);QueueContext = NULL;}
if(FileQueue != INVALID_HANDLE_VALUE) {SetupCloseFileQueue(FileQueue);FileQueue = INVALID_HANDLE_VALUE;}
if (bPleaseCloseInfHandle == TRUE)
{
if(InfHandle != INVALID_HANDLE_VALUE) {SetupCloseInfFile(InfHandle);InfHandle = INVALID_HANDLE_VALUE;}
}
;}
__except(EXCEPTION_EXECUTE_HANDLER)
{
if(QueueContext) {SetupTermDefaultQueueCallback(QueueContext);}
if(FileQueue != INVALID_HANDLE_VALUE) {SetupCloseFileQueue(FileQueue);}
if (bPleaseCloseInfHandle == TRUE)
{
if(InfHandle != INVALID_HANDLE_VALUE) {SetupCloseInfFile(InfHandle);InfHandle = INVALID_HANDLE_VALUE;}
}
}
//
// If the bReturnTemp failed because the user cancelled, then we don't want to consider
// that as an bReturnTemp (i.e., we don't want to give an bReturnTemp popup later).
//
if((bReturnTemp != TRUE) && (GetLastError() == ERROR_CANCELLED)) {bReturnTemp = TRUE;}
// Display installation failed message
//if(bReturnTemp) {MyMessageBox(NULL, _T("IDS_INF_FAILED"), MB_OK);}
iisDebugOut((LOG_TYPE_PROGRAM_FLOW, _T("InstallInfSection.[%s].End.Ret=%d.\n"), szSectionName, bReturnTemp));
return bReturnTemp;
}
BOOL IsValidDriveType(LPTSTR szRoot)
{
BOOL fReturn = FALSE;
int i;
i = GetDriveType(szRoot);
if (i == DRIVE_FIXED) {fReturn = TRUE;}
if (i == DRIVE_REMOVABLE)
{
BOOL b;
ULONGLONG TotalSpace;
DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters;
DWORD FloppySpace = 10 * 1024 * 1024;// use 10MB to distinguish a floppy from other drives, like JAZ drive 1GB
b = GetDiskFreeSpace(szRoot,&SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters);
if (b)
{
TotalSpace = (ULONGLONG) TotalNumberOfClusters * SectorsPerCluster * BytesPerSector;
if (TotalSpace > (ULONGLONG) FloppySpace)
{fReturn = TRUE;}
else
{
iisDebugOutSafeParams((LOG_TYPE_ERROR, _T("GetDiskFreeSpace():Drive=DRIVE_REMOVABLE:Not Sufficient space on drive '%1!s!'. FAIL\n"), szRoot));
}
}
else
{
iisDebugOutSafeParams((LOG_TYPE_ERROR, _T("GetDiskFreeSpace(Drive=DRIVE_REMOVABLE) on %1!s! returns err: 0x%2!x!. FAILURE\n"), szRoot, GetLastError()));
}
}
return (fReturn);
}
// If lpszPath is a valid directory, return TRUE, and pass back the valid path in lpszPath to caller
// Otherwise, return FALSE.
BOOL IsValidDirectoryName(LPTSTR lpszPath)
{
DWORD err = 0;
BOOL bReturn = FALSE;
TCHAR szFullPath[_MAX_PATH];
LPTSTR p;
iisDebugOutSafeParams((LOG_TYPE_TRACE_WIN32_API, _T("IsValidDirectoryName %1!s!\n"), lpszPath));
err = GetFullPathName(lpszPath, _MAX_PATH, szFullPath, &p);
if (err != 0)
{
if (szFullPath[1] == _T(':')) { // good, not a UNC name
// make sure it is a FIXED drive
TCHAR szRoot[4];
_tcsncpy(szRoot, szFullPath, 3);
szRoot[3] = _T('\0');
if (IsValidDriveType(szRoot))
{
// OK, ready to create each layered directory
TCHAR szBuffer[_MAX_PATH];
LPTSTR token, tail;
CStringArray aDir;
int i, n;
tail = szBuffer;
token = _tcstok(szFullPath, _T("\\"));
if (token)
{
_tcscpy(tail, token);
tail += _tcslen(token);
bReturn = TRUE; /* return TRUE if in the form of C:\ */
while (token = _tcstok(NULL, _T("\\")))
{
*tail = _T('\\');
tail = _tcsinc(tail);
_tcscpy(tail, token);
// create it & rememeber it
err = GetFileAttributes(szBuffer);
if (err == 0xFFFFFFFF)
{
// szBuffer contains a non-existing path
// create it
if (CreateDirectory(szBuffer, NULL))
{
// succeed, remember the directory in an array
aDir.Add(szBuffer);
}
else
{
iisDebugOutSafeParams((LOG_TYPE_ERROR, _T("IsValidDirectory:CreateDirectory failed on %1!s!, err=%2!x!.\n"), szBuffer, GetLastError()));
bReturn = FALSE;
break;
}
} else {
// szBuffer contains an existing path,
// make sure it is a directory
if (!(err & FILE_ATTRIBUTE_DIRECTORY))
{
iisDebugOutSafeParams((LOG_TYPE_ERROR, _T("IsValidDirectory failure. %1!s! is not a valid directory.\n"), szBuffer));
bReturn = FALSE;
break;
}
}
tail += _tcslen(token);
}
if (bReturn)
{
// pass the valid directory to the caller
if (*(tail-1) == _T(':'))
{
*tail = _T('\\');
tail = _tcsinc(tail);
}
_tcscpy(lpszPath, szBuffer);
}
}
// remove the created directories we remembered in the array
n = (int)aDir.GetSize();
for (i = n-1; i >= 0; i--)
RemoveDirectory(aDir[i]);
} else {
iisDebugOutSafeParams((LOG_TYPE_ERROR, _T("IsValidDirectory failure. %1!s! is not on a valid drive.\n"), szFullPath));
}
} else {
iisDebugOutSafeParams((LOG_TYPE_ERROR, _T("IsValidDirectory failure. UNC name %1!s! is not allowed.\n"), szFullPath));
}
} else {
iisDebugOutSafeParams((LOG_TYPE_ERROR, _T("IsValidDirectory:GetFullPathName failed on %1!s!, err=%2!x!.\n"), lpszPath, GetLastError()));
}
return (bReturn);
}
BOOL IsValidNumber(LPCTSTR szValue)
{
LPTSTR p = (LPTSTR)szValue;
while (*p)
{
if ( *p >= _T('0') && *p <= _T('9') )
{
p = _tcsinc(p);
continue;
} else
return FALSE;
}
return TRUE;
}
// Calculate the size of a Multi-String in TCHAR, including the ending 2 '\0's.
int GetMultiStrSize(LPTSTR p)
{
int c = 0;
while (1) {
if (*p) {
p++;
c++;
} else {
c++;
if (*(p+1)) {
p++;
} else {
c++;
break;
}
}
}
return c;
}
BOOL IsFileExist(LPCTSTR szFile)
{
// Check if the file has expandable Environment strings
LPTSTR pch = NULL;
pch = _tcschr( (LPTSTR) szFile, _T('%'));
if (pch)
{
TCHAR szValue[_MAX_PATH];
_tcscpy(szValue,szFile);
if (!ExpandEnvironmentStrings( (LPCTSTR)szFile, szValue, sizeof(szValue)/sizeof(TCHAR)))
{_tcscpy(szValue,szFile);}
return (GetFileAttributes(szValue) != 0xFFFFFFFF);
}
else
{
return (GetFileAttributes(szFile) != 0xFFFFFFFF);
}
}
void InetGetFilePath(LPCTSTR szFile, LPTSTR szPath)
{
// if UNC name \\computer\share\local1\local2
if (*szFile == _T('\\') && *(_tcsinc(szFile)) == _T('\\')) {
TCHAR szTemp[_MAX_PATH], szLocal[_MAX_PATH];
TCHAR *p = NULL;
int i = 0;
_tcscpy(szTemp, szFile);
p = szTemp;
while (*p) {
if (*p == _T('\\'))
i++;
if (i == 4) {
*p = _T('\0');
p = _tcsinc(p); // p is now pointing at local1\local2
break;
}
p = _tcsinc(p);
}
_tcscpy(szPath, szTemp); // now szPath contains \\computer\share
if (i == 4 && *p) { // p is pointing the local path now
_tcscpy(szLocal, p);
p = _tcsrchr(szLocal, _T('\\'));
if (p)
*p = _T('\0');
_tcscat(szPath, _T("\\"));
_tcscat(szPath, szLocal); // szPath contains \\computer\share\local1
}
} else { // NOT UNC name
TCHAR *p;
if (GetFullPathName(szFile, _MAX_PATH, szPath, &p)) {
p = _tcsrchr(szPath, _T('\\'));
if (p)
{
TCHAR *p2 = NULL;
p2 = _tcsdec(szPath, p);
if (p2)
{
if (*p2 == _T(':') )
{p = _tcsinc(p);}
}
*p = _T('\0');
}
} else {
iisDebugOutSafeParams((LOG_TYPE_WARN, _T("GetFullPathName: szFile=%1!s!, err=%2!d!\n"), szFile, GetLastError()));
MyMessageBox(NULL, _T("GetFullPathName"), GetLastError(), MB_OK | MB_SETFOREGROUND);
}
}
return;
}
BOOL InetDeleteFile(LPCTSTR szFileName)
{
// if file exists but DeleteFile() fails
if ( IsFileExist(szFileName) && !(::DeleteFile(szFileName)) ) {
// if we cannot delete it, then move delay until reboot
// move it to top level dir on the same drive, and mark it as hidden
// Note: MoveFileEx() works only on the same drive if dealing with file-in-use
TCHAR TmpName[_MAX_PATH];
TCHAR csTmpPath[5] = _T("C:\\.");
csTmpPath[0] = *szFileName;
if ( GetTempFileName( (LPCTSTR)csTmpPath, _T("INT"), 0, TmpName ) == 0 ||
!MoveFileEx( szFileName, TmpName, MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED|MOVEFILE_WRITE_THROUGH ) ) {
return FALSE;
}
MoveFileEx( TmpName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT );
SetFileAttributes(TmpName, FILE_ATTRIBUTE_HIDDEN);
}
return TRUE;
}
BOOL InetCopyFile( LPCTSTR szSrc, LPCTSTR szDest)
{
INT err;
INT fSrc;
INT fDest;
OFSTRUCT ofstruct;
do {
// open source file
iisDebugOut_Start((_T("LZ32.dll:LZOpenFile()")));
if (( fSrc = LZOpenFile( (LPTSTR)szSrc, &ofstruct, OF_READ | OF_SHARE_DENY_NONE )) < 0 )
{
iisDebugOut_End((_T("LZ32.dll:LZOpenFile")));
// cannot open src file
LZClose(fSrc);
UINT iMsg = MyMessageBox( NULL, IDS_CANNOT_OPEN_SRC_FILE, szSrc, MB_ABORTRETRYIGNORE | MB_SETFOREGROUND );
switch ( iMsg )
{
case IDABORT:
return FALSE;
case IDRETRY:
break;
case IDIGNORE:
default:
return TRUE;
}
}
else
{
iisDebugOut_End((_T("LZ32.dll:LZOpenFile")));
break;
}
} while (TRUE);
// move the desintation file
CFileStatus status;
if ( CFile::GetStatus( szDest, status ))
{
// try to remove it
if ( !InetDeleteFile( szDest ))
{
LZClose( fSrc );
return TRUE;
}
}
// open desination file
do {
iisDebugOut_Start((_T("LZ32.dll:LZOpenFile()")));
if (( fDest = LZOpenFile( (LPTSTR)szDest, &ofstruct, OF_CREATE | OF_WRITE | OF_SHARE_DENY_NONE )) < 0 )
{
iisDebugOut_End((_T("LZ32.dll:LZOpenFile")));
LZClose(fDest);
UINT iMsg = MyMessageBox( NULL, IDS_CANNOT_OPEN_DEST_FILE, szDest, MB_ABORTRETRYIGNORE | MB_SETFOREGROUND );
switch ( iMsg )
{
case IDABORT:
LZClose(fSrc);
return FALSE;
case IDRETRY:
break;
case IDIGNORE:
default:
LZClose(fSrc);
return TRUE;
}
}
else
{
iisDebugOut_End((_T("LZ32.dll:LZOpenFile")));
break;
}
} while (TRUE);
do {
iisDebugOut_Start((_T("LZ32.dll:LZCopy()")));
if (( err = LZCopy( fSrc, fDest )) < 0 )
{
iisDebugOut_End((_T("LZ32.dll:LZCopy")));
LZClose( fSrc );
LZClose( fDest );
UINT iMsg = MyMessageBox( NULL, IDS_CANNOT_COPY_FILE, szSrc,szDest,ERROR_CANNOT_COPY, MB_ABORTRETRYIGNORE | MB_SETFOREGROUND );
switch ( iMsg )
{
case IDABORT:
return FALSE;
case IDRETRY:
break;
case IDIGNORE:
default:
return TRUE;
}
}
else
{
iisDebugOut_End((_T("LZ32.dll:LZCopy")));
LZClose( fSrc );
LZClose( fDest );
break;
}
} while (TRUE);
return TRUE;
}
// Given a fullpathname of a directory, remove any empty dirs under it including itself
BOOL RecRemoveEmptyDir(LPCTSTR szName)
{
BOOL fReturn = FALSE;
DWORD retCode;
BOOL fRemoveDir = TRUE;
WIN32_FIND_DATA FindFileData;
HANDLE hFile = INVALID_HANDLE_VALUE;
TCHAR szSubDir[_MAX_PATH] = _T("");
TCHAR szDirName[_MAX_PATH] = _T("");
retCode = GetFileAttributes(szName);
if (retCode == 0xFFFFFFFF || !(retCode & FILE_ATTRIBUTE_DIRECTORY))
return FALSE;
_stprintf(szDirName, _T("%s\\*"), szName);
hFile = FindFirstFile(szDirName, &FindFileData);
if (hFile != INVALID_HANDLE_VALUE) {
do {
if (_tcsicmp(FindFileData.cFileName, _T(".")) != 0 &&
_tcsicmp(FindFileData.cFileName, _T("..")) != 0 ) {
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
_stprintf(szSubDir, _T("%s\\%s"), szName, FindFileData.cFileName);
fRemoveDir = RecRemoveEmptyDir(szSubDir) && fRemoveDir;
} else {
CString csFileName = FindFileData.cFileName;
CString csPrefix = csFileName.Left(3);
CString csSuffix = csFileName.Right(4);
if (_tcsicmp(csPrefix, _T("INT")) == 0 &&
_tcsicmp(csSuffix, _T(".tmp")) == 0 ) { // this is an INT*.tmp created by IIS
_stprintf(szSubDir, _T("%s\\%s"), szName, FindFileData.cFileName);
if (!::DeleteFile(szSubDir))
fRemoveDir = FALSE; // this dir is not empty
} else
fRemoveDir = FALSE; // it is a file, this Dir is not empty
}
}
if (!FindNextFile(hFile, &FindFileData)) {
FindClose(hFile);
break;
}
} while (TRUE);
}
if (fRemoveDir) {
TCHAR szDirName[_MAX_PATH];
GetCurrentDirectory( _MAX_PATH, szDirName );
SetCurrentDirectory(g_pTheApp->m_csSysDir);
fReturn = ::RemoveDirectory(szName);
SetCurrentDirectory(szDirName);
}
return fReturn;
}
// Given a fullpathname of a directory, remove the directory node
BOOL RecRemoveDir(LPCTSTR szName)
{
DWORD retCode;
WIN32_FIND_DATA FindFileData;
HANDLE hFile = INVALID_HANDLE_VALUE;
TCHAR szSubDir[_MAX_PATH] = _T("");
TCHAR szDirName[_MAX_PATH] = _T("");
retCode = GetFileAttributes(szName);
if (retCode == 0xFFFFFFFF)
return FALSE;
if (!(retCode & FILE_ATTRIBUTE_DIRECTORY)) {
InetDeleteFile(szName);
return TRUE;
}
_stprintf(szDirName, _T("%s\\*"), szName);
hFile = FindFirstFile(szDirName, &FindFileData);
if (hFile != INVALID_HANDLE_VALUE) {
do {
if ( _tcsicmp(FindFileData.cFileName, _T(".")) != 0 &&
_tcsicmp(FindFileData.cFileName, _T("..")) != 0 ) {
_stprintf(szSubDir, _T("%s\\%s"), szName, FindFileData.cFileName);
RecRemoveDir(szSubDir);
}
if ( !FindNextFile(hFile, &FindFileData) ) {
FindClose(hFile);
break;
}
} while (TRUE);
}
return( ::RemoveDirectory(szName) );
}
//
// Given a directory path, this subroutine will create the direct layer by layer
//
BOOL CreateLayerDirectory( CString &str )
{
BOOL fReturn = TRUE;
iisDebugOutSafeParams((LOG_TYPE_TRACE_WIN32_API, _T("CreateLayerDirectory %1!s!\n"), (LPCTSTR)str));
do
{
INT index=0;
// INT iLength = str.GetLength();
INT iLength = _tcslen(str);
// first find the index for the first directory
if ( iLength > 2 )
{
if ( *_tcsninc(str,1) == _T(':'))
{
// assume the first character is driver letter
if ( *_tcsninc(str,2) == _T('\\'))
{
index = 2;
} else
{
index = 1;
}
} else if ( *_tcsninc(str,0) == _T('\\'))
{
if ( *_tcsninc(str,1) == _T('\\'))
{
BOOL fFound = FALSE;
INT i;
INT nNum = 0;
// unc name
for (i = 2; i < iLength; i++ )
{
if ( *_tcsninc(str,i) == _T('\\'))
{
// find it
nNum ++;
if ( nNum == 2 )
{
fFound = TRUE;
break;
}
}
}
if ( fFound )
{
index = i;
} else
{
// bad name
break;
}
} else
{
index = 1;
}
}
} else if ( *_tcsninc(str,0) == _T('\\'))
{
index = 0;
}
// okay ... build directory
do
{
// find next one
do
{
if ( index < ( iLength - 1))
{
index ++;
} else
{
break;
}
} while ( *_tcsninc(str,index) != _T('\\'));
TCHAR szCurrentDir[_MAX_PATH+1];
TCHAR szLeftDir[_MAX_PATH+1];
ZeroMemory( szLeftDir, _MAX_PATH+1 );
GetCurrentDirectory( _MAX_PATH+1, szCurrentDir );
_tcsncpy( szLeftDir, str, index + 1 );
if ( !SetCurrentDirectory(szLeftDir) )
{
if (( fReturn = CreateDirectory( szLeftDir, NULL )) != TRUE )
{
break;
}
}
SetCurrentDirectory( szCurrentDir );
if ( index >= ( iLength - 1 ))
{
fReturn = TRUE;
break;
}
} while ( TRUE );
} while (FALSE);
return(fReturn);
}
// szResult = szParentDir \ szSubDir
BOOL AppendDir(LPCTSTR szParentDir, LPCTSTR szSubDir, LPTSTR szResult)
{
LPTSTR p = (LPTSTR)szParentDir;
ASSERT(szParentDir);
ASSERT(szSubDir);
ASSERT(*szSubDir && *szSubDir != _T('\\'));
if (*szParentDir == _T('\0'))
_tcscpy(szResult, szSubDir);
else {
_tcscpy(szResult, szParentDir);
p = szResult;
while (*p)
p = _tcsinc(p);
if (*(_tcsdec(szResult, p)) != _T('\\'))
_tcscat(szResult, _T("\\"));
_tcscat(szResult, szSubDir);
}
return TRUE;
}
//***************************************************************************
//*
//* purpose: add's filename onto path
//*
//***************************************************************************
void AddPath(LPTSTR szPath, LPCTSTR szName )
{
LPTSTR p = szPath;
LPTSTR pPrev;
ASSERT(szPath);
ASSERT(szName);
// Find end of the string
while (*p){p = _tcsinc(p);}
// If no trailing backslash then add one
pPrev = _tcsdec(szPath, p);
if ( (!pPrev) ||
(*(pPrev) != _T('\\'))
)
{_tcscat(szPath, _T("\\"));}
// if there are spaces precluding szName, then skip
while ( *szName == ' ' ) szName = _tcsinc(szName);;
// Add new name to existing path string
_tcscat(szPath, szName);
}
CString AddPath(CString szPath, LPCTSTR szName )
{
TCHAR szPathCopy[_MAX_PATH] = _T("");
_tcscpy(szPathCopy,szPath);
LPTSTR p = szPathCopy;
ASSERT(szPathCopy);
ASSERT(szName);
// Find end of the string
while (*p){p = _tcsinc(p);}
// If no trailing backslash then add one
if (*(_tcsdec(szPathCopy, p)) != _T('\\'))
{_tcscat(szPathCopy, _T("\\"));}
// if there are spaces precluding szName, then skip
while ( *szName == _T(' ') ) szName = _tcsinc(szName);;
// make sure that the szName
// does not look like this "\filename"
CString csTempString = szName;
if (_tcsicmp(csTempString.Left(1), _T("\\")) == 0)
{
csTempString = csTempString.Right( csTempString.GetLength() - 1);
}
// Add new name to existing path string
_tcscat(szPathCopy, csTempString);
return szPathCopy;
//szPath = szPathCopy;
}
BOOL ReturnFileNameOnly(LPCTSTR lpFullPath, LPTSTR lpReturnFileName)
{
int iReturn = FALSE;
TCHAR pfilename_only[_MAX_FNAME];
TCHAR pextention_only[_MAX_EXT];
_tcscpy(lpReturnFileName, _T(""));
_tsplitpath( lpFullPath, NULL, NULL, pfilename_only, pextention_only);
if (pextention_only) {_tcscat(pfilename_only,pextention_only);}
if (pfilename_only)
{
_tcscpy(lpReturnFileName, pfilename_only);
iReturn = TRUE;
}
else
{
// well, we don't have anything in pfilename_only
// that's probably because we got some strange path name like:
// /??/c:\somethng\filename.txt
// so... let's just return everything after the last "\" character.
LPTSTR pszTheLastBackSlash = _tcsrchr((LPTSTR) lpFullPath, _T('\\'));
_tcscpy(lpReturnFileName, pszTheLastBackSlash);
iReturn = TRUE;
}
return iReturn;
}
BOOL ReturnFilePathOnly(LPCTSTR lpFullPath, LPTSTR lpReturnPathOnly)
{
int iReturn = FALSE;
TCHAR szDrive_only[_MAX_DRIVE];
TCHAR szPath_only[_MAX_PATH];
TCHAR szFilename_only[_MAX_PATH];
TCHAR szFilename_ext_only[_MAX_EXT];
_tcscpy(lpReturnPathOnly, _T(""));
_tsplitpath( lpFullPath, szDrive_only, szPath_only, szFilename_only, szFilename_ext_only);
_tcscpy(lpReturnPathOnly, szDrive_only);
_tcscat(lpReturnPathOnly, szPath_only);
iReturn = TRUE;
return iReturn;
}
void DeleteFilesWildcard(TCHAR *szDir, TCHAR *szFileName)
{
WIN32_FIND_DATA FindFileData;
HANDLE hFile = INVALID_HANDLE_VALUE;
TCHAR szFileToBeDeleted[_MAX_PATH];
_stprintf(szFileToBeDeleted, _T("%s\\%s"), szDir, szFileName);
hFile = FindFirstFile(szFileToBeDeleted, &FindFileData);
if (hFile != INVALID_HANDLE_VALUE)
{
do {
if ( _tcsicmp(FindFileData.cFileName, _T(".")) != 0 && _tcsicmp(FindFileData.cFileName, _T("..")) != 0 )
{
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// this is a directory, so let's skip it
}
else
{
// this is a file, so let's Delete it.
TCHAR szTempFileName[_MAX_PATH];
_stprintf(szTempFileName, _T("%s\\%s"), szDir, FindFileData.cFileName);
// set to normal attributes, so we can delete it
SetFileAttributes(szTempFileName, FILE_ATTRIBUTE_NORMAL);
// delete it, hopefully
InetDeleteFile(szTempFileName);
}
}
// get the next file
if ( !FindNextFile(hFile, &FindFileData) )
{
FindClose(hFile);
break;
}
} while (TRUE);
}
return;
}
int IsThisDriveNTFS(IN LPTSTR FileName)
{
BOOL Ntfs = FALSE;
TCHAR szDriveRootPath[_MAX_DRIVE + 5];
DWORD DontCare;
TCHAR NameBuffer[100];
// get the Drive only.
_tsplitpath( FileName, szDriveRootPath, NULL, NULL, NULL);
_tcscat(szDriveRootPath, _T("\\"));
//
// find out what the file system is
//
if (0 != GetVolumeInformation(szDriveRootPath,NULL,0,NULL,&DontCare,&DontCare,NameBuffer,sizeof(NameBuffer)/sizeof(TCHAR)))
{
if (0 == _tcsicmp(NameBuffer,_T("NTFS")))
{Ntfs = TRUE;}
}
return Ntfs;
}
// take something like
// e:\winnt\system32 and return back %systemroot%\system23
// e:\winnt\system32\inetsrv and return back %systemroot%\system23\inetsrv
int ReverseExpandEnvironmentStrings(LPTSTR szOriginalDir,LPTSTR szNewlyMungedDir)
{
int iReturn = FALSE;
int iWhere = 0;
TCHAR szSystemDir[_MAX_PATH];
CString csTempString;
CString csTempString2;
// default it with the input string
_tcscpy(szNewlyMungedDir, szOriginalDir);
// get the c:\winnt\system32 dir
if (0 == GetSystemDirectory(szSystemDir, _MAX_PATH))
{
// we weren't able to get the systemdirectory, so just return whatever was put in
iReturn = TRUE;
goto ReverseExpandEnvironmentStrings_Exit;
}
csTempString = szOriginalDir;
csTempString2 = szSystemDir;
// Find the "e:\winnt\system32"
iWhere = csTempString.Find(szSystemDir);
if (-1 != iWhere)
{
CString AfterString;
// there is a "e:\winnt\system32" in the string
// Get the after e:\winnt\system32 stuff
AfterString = csTempString.Right(csTempString.GetLength() - (iWhere + csTempString2.GetLength()));
// Take everything after the string and append it to our new string.
_tcscpy(szNewlyMungedDir, _T("%SystemRoot%\\System32"));
_tcscat(szNewlyMungedDir, AfterString);
// return true!
iReturn = TRUE;
}
ReverseExpandEnvironmentStrings_Exit:
return iReturn;
}
DWORD ReturnFileSize(LPCTSTR myFileName)
{
DWORD dwReturn = 0xFFFFFFFF;
HANDLE hFile = CreateFile(myFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
dwReturn = GetFileSize(hFile, NULL);
CloseHandle(hFile);
}
return dwReturn;
}
BOOL IsFileExist_NormalOrCompressed(LPCTSTR szFile)
{
int iReturn = FALSE;
TCHAR szDrive_only[_MAX_DRIVE];
TCHAR szPath_only[_MAX_PATH];
TCHAR szFilename_only[_MAX_PATH];
TCHAR szFilename_ext_only[_MAX_EXT];
TCHAR szCompressedName[_MAX_PATH];
// Check if the file exsts
// if it doesn't, check if maybe the compressed file exists.
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("IsFileExist_NormalOrCompressed:%s.\n"), szFile));
if (IsFileExist(szFile) != TRUE)
{
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("IsFileExist_NormalOrCompressed:%s not exist.\n"), szFile));
// check if maybe the compressed file exists
_tsplitpath( szFile, szDrive_only, szPath_only, szFilename_only, szFilename_ext_only);
// Replace the last character with an '_'
int nLen = 0;
nLen = _tcslen(szFilename_ext_only);
*_tcsninc(szFilename_ext_only, nLen-1) = _T('_');
_stprintf(szCompressedName,_T("%s%s%s%s"),szDrive_only, szPath_only, szFilename_only, szFilename_ext_only);
// see if it exists
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("IsFileExist_NormalOrCompressed:%s.\n"), szCompressedName));
if (IsFileExist(szCompressedName) != TRUE)
{
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("IsFileExist_NormalOrCompressed:%s. no exist.\n"), szCompressedName));
goto IsFileExist_RegOrCompressed_Exit;
}
else
{
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("IsFileExist_NormalOrCompressed:%s. exist.\n"), szCompressedName));
}
}
// we got this far, that must mean things are okay.
iReturn = TRUE;
IsFileExist_RegOrCompressed_Exit:
return iReturn;
}
// Clean leading & trailing spaces
// Clean trailing backslashes
BOOL CleanPathString(LPTSTR szPath)
{
CString csPath = szPath;
csPath.TrimLeft();
csPath.TrimRight();
_tcscpy(szPath, (LPCTSTR)csPath);
return TRUE;
}
//
// Return 0 if there was nothing to compare
// Return 1 if Source is Equal to Destination
// Return 2 if Source is Larger than Destination
// Return 3 if Source is Less than Destination
//
INT VerCmp(LPTSTR szSrcVerString, LPTSTR szDestVerString)
{
INT iReturn = 0;
const DWORD MAX_NUM_OF_VER_FIELDS = 32;
DWORD dwSrcVer[MAX_NUM_OF_VER_FIELDS], dwDestVer[MAX_NUM_OF_VER_FIELDS];
memset( (PVOID)dwSrcVer, 0, sizeof(dwSrcVer));
memset( (PVOID)dwDestVer, 0, sizeof(dwDestVer));
int i=0;
TCHAR szSeps[] = _T(".");
TCHAR *token;
BOOL bNotEqual = FALSE;
// expand src version string into a dword arrary
i = 0;
token = _tcstok(szSrcVerString, szSeps);
while ( token && (i < MAX_NUM_OF_VER_FIELDS) ) {
dwSrcVer[i++] = _ttoi(token);
token = _tcstok(NULL, szSeps);
}
// expand dest version string into a dword arrary
i = 0;
token = _tcstok(szDestVerString, szSeps);
while ( token && (i < MAX_NUM_OF_VER_FIELDS) ) {
dwDestVer[i++] = _ttoi(token);
token = _tcstok(NULL, szSeps);
}
// Check for Equality
for (i=0; i<MAX_NUM_OF_VER_FIELDS; i++)
{
if (dwSrcVer[i] != dwDestVer[i])
{
bNotEqual = TRUE;
break;
}
}
if (TRUE == bNotEqual)
{
// int compare each field
for (i=0; i<MAX_NUM_OF_VER_FIELDS; i++)
{
if (dwSrcVer[i] > dwDestVer[i])
{return 2;}
if (dwSrcVer[i] < dwDestVer[i])
{return 3;}
}
// if we haven't return here, then
// there probably wasn't anything to loop thru (for 0=0 till 0)
return 0;
}
else
{
// it is equal so return so
return 1;
}
}
DWORD atodw(LPCTSTR lpszData)
{
DWORD i = 0, sum = 0;
TCHAR *s, *t;
s = (LPTSTR)lpszData;
t = (LPTSTR)lpszData;
while (*t)
t = _tcsinc(t);
t = _tcsdec(lpszData, t);
if (*s == _T('0') && (*(_tcsinc(s)) == _T('x') || *(_tcsinc(s)) == _T('X')))
s = _tcsninc(s, 2);
while (s <= t) {
if ( *s >= _T('0') && *s <= _T('9') )
i = *s - _T('0');
else if ( *s >= _T('a') && *s <= _T('f') )
i = *s - _T('a') + 10;
else if ( *s >= _T('A') && *s <= _T('F') )
i = *s - _T('A') + 10;
else
break;
sum = sum * 16 + i;
s = _tcsinc(s);
}
return sum;
}
void MakePath(LPTSTR lpPath)
{
LPTSTR lpTmp;
lpTmp = CharPrev( lpPath, lpPath + _tcslen(lpPath));
// chop filename off
while ( (lpTmp > lpPath) && *lpTmp && (*lpTmp != '\\') )
lpTmp = CharPrev( lpPath, lpTmp );
if ( *CharPrev( lpPath, lpTmp ) != ':' )
*lpTmp = '\0';
else
*CharNext(lpTmp) = '\0';
return;
}
CString ReturnUniqueFileName(CString csInputFullName)
{
TCHAR szPathCopy[_MAX_PATH] = _T("");
_tcscpy(szPathCopy,csInputFullName);
long iNum = 1;
do
{
_stprintf(szPathCopy,TEXT("%s.%d"),csInputFullName,iNum);
// Check if the file exists
if (!IsFileExist(szPathCopy)){goto ReturnUniqueFileName_Exit;}
iNum++;
} while (iNum <= 50);
ReturnUniqueFileName_Exit:
// returns %s50 if there are fifty copies aleady!
return szPathCopy;
}
/*---------------------------------------------------------------------------*
Description: Displays the current running version of setup to the debug
output and setup log.
-----------------------------------------------------------------------------*/
void DisplayVerOnCurrentModule()
{
TCHAR tszModuleName[_MAX_PATH+1];
GetModuleFileName((HINSTANCE)g_MyModuleHandle, tszModuleName, _MAX_PATH+1);
LogFileVersion(tszModuleName, TRUE);
return;
}
void MyGetVersionFromFile(LPCTSTR lpszFilename, LPDWORD pdwMSVer, LPDWORD pdwLSVer, LPTSTR pszReturnLocalizedVersion)
{
struct TRANSARRAY {
WORD wLanguageID;
WORD wCharacterSet;
};
unsigned uiSize;
DWORD dwVerInfoSize;
DWORD dwHandle;
VS_FIXEDFILEINFO * lpVSFixedFileInfo;
LPTSTR lpBuffer = NULL;
LPVOID lpVerBuffer = NULL;
LPTSTR pszTheResult = NULL;
TCHAR QueryString[48] = _T("");
TRANSARRAY *lpTransArray;
*pdwMSVer = *pdwLSVer = 0L;
dwVerInfoSize = GetFileVersionInfoSize( (LPTSTR) lpszFilename, &dwHandle);
if (dwVerInfoSize)
{
// Alloc the memory for the version stamping
lpBuffer = (LPTSTR) LocalAlloc(LPTR, dwVerInfoSize);
if (lpBuffer)
{
int iTemp = 0;
iTemp = GetFileVersionInfo( (LPTSTR) lpszFilename, dwHandle, dwVerInfoSize, lpBuffer);
// Read version stamping info
if (iTemp)
{
// Get the value for Translation
if (VerQueryValue(lpBuffer, _T("\\"), (LPVOID*)&lpVSFixedFileInfo, &uiSize) && (uiSize))
{
*pdwMSVer = lpVSFixedFileInfo->dwFileVersionMS;
*pdwLSVer = lpVSFixedFileInfo->dwFileVersionLS;
}
// get a pointer to the translation table information
if (VerQueryValue(lpBuffer, _T("\\VarFileInfo\\Translation"), &lpVerBuffer, &uiSize) && (uiSize))
{
lpTransArray = (TRANSARRAY *) lpVerBuffer;
// lpTransArray points to the translation array. dwFixedLength has number of bytes in array
_stprintf(QueryString, _T("\\StringFileInfo\\%04x%04x\\FileVersion"), lpTransArray[0].wLanguageID, lpTransArray[0].wCharacterSet);
if (VerQueryValue(lpBuffer, QueryString, (LPVOID*) &pszTheResult, &uiSize))
{
_tcscpy(pszReturnLocalizedVersion, pszTheResult);
}
}
}
}
}
if(lpBuffer) {LocalFree(lpBuffer);lpBuffer=NULL;}
return ;
}
BOOL MyGetDescriptionFromFile(LPCTSTR lpszFilename, LPTSTR pszReturnDescription)
{
BOOL bRet = FALSE;
struct TRANSARRAY {
WORD wLanguageID;
WORD wCharacterSet;
};
unsigned uiSize;
DWORD dwVerInfoSize;
DWORD dwHandle;
VS_FIXEDFILEINFO * lpVSFixedFileInfo;
LPTSTR lpBuffer = NULL;
LPVOID lpTempBuffer = NULL;
LPTSTR pszTheResult = NULL;
TCHAR QueryString[52] = _T("");
TRANSARRAY *lpTransArray;
dwVerInfoSize = GetFileVersionInfoSize( (LPTSTR) lpszFilename, &dwHandle);
if (dwVerInfoSize)
{
// Alloc the memory for the version stamping
lpBuffer = (LPTSTR) LocalAlloc(LPTR, dwVerInfoSize);
if (lpBuffer)
{
int iTemp = 0;
iTemp = GetFileVersionInfo( (LPTSTR) lpszFilename, dwHandle, dwVerInfoSize, lpBuffer);
// Read version stamping info
if (iTemp)
{
// get a pointer to the translation table information
if (VerQueryValue(lpBuffer, _T("\\VarFileInfo\\Translation"), &lpTempBuffer, &uiSize) && (uiSize))
{
lpTransArray = (TRANSARRAY *) lpTempBuffer;
// lpTransArray points to the translation array. dwFixedLength has number of bytes in array
_stprintf(QueryString, _T("\\StringFileInfo\\%04x%04x\\FileDescription"), lpTransArray[0].wLanguageID, lpTransArray[0].wCharacterSet);
if (VerQueryValue(lpBuffer, QueryString, (LPVOID*) &pszTheResult, &uiSize))
{
_tcscpy(pszReturnDescription, pszTheResult);
bRet = TRUE;
}
}
}
}
}
if(lpBuffer) {LocalFree(lpBuffer);lpBuffer=NULL;}
return bRet;
}
//
// Returns True if the filename has a version stamp which is part of ntop4.0
//
int IsFileLessThanThisVersion(IN LPCTSTR lpszFullFilePath, IN DWORD dwNtopMSVer, IN DWORD dwNtopLSVer)
{
int iReturn = FALSE;
DWORD dwMSVer, dwLSVer;
TCHAR szLocalizedVersion[100] = _T("");
// if the filename has a version number
// and it's larger than the release version of ntop 4.2.622.1, 4.02.0622 (localized version)
// return back true! if not, then return back false.
// see if the file exists
if (!IsFileExist(lpszFullFilePath))
{goto iFileWasPartOfIIS4_Exit;}
// get the fileinformation
// includes version and localizedversion
MyGetVersionFromFile(lpszFullFilePath, &dwMSVer, &dwLSVer, szLocalizedVersion);
if (!dwMSVer)
{
iisDebugOut((LOG_TYPE_TRACE, _T("iFileWasPartOfIIS4:%s.No version."), lpszFullFilePath));
goto iFileWasPartOfIIS4_Exit;
}
// okay, there is a version on this.
iisDebugOut((LOG_TYPE_TRACE, _T("iFileWasPartOfIIS4:%d.%d.%d.%d, %s, %s"), HIWORD(dwMSVer), LOWORD(dwMSVer), HIWORD(dwLSVer), LOWORD(dwLSVer), szLocalizedVersion, lpszFullFilePath));
// Check if the version is smaller than what was shipped with iis4.0
// NTOP versions were 4.02.0622
if (dwMSVer < dwNtopMSVer)
{goto iFileWasPartOfIIS4_Exit;}
// check if the file has a smaller minor version number
if ( (dwMSVer == dwNtopMSVer) && (dwLSVer < dwNtopLSVer) )
{goto iFileWasPartOfIIS4_Exit;}
// this is a ntop 4.0 or greater versioned file
iReturn = TRUE;
iFileWasPartOfIIS4_Exit:
return iReturn;
}
void MakeSureDirAclsHaveAtLeastRead(LPTSTR lpszDirectoryPath)
{
iisDebugOut_Start1(_T("MakeSureDirAclsHaveAtLeastRead"),lpszDirectoryPath, LOG_TYPE_TRACE);
DWORD err;
TCHAR szThePath[_MAX_PATH];
if (FALSE == IsThisDriveNTFS(lpszDirectoryPath))
{
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("MakeSureDirAclsHaveAtLeastRead:filesys is not ntfs.")));
goto MakeSureDirAclsHaveAtLeastRead_Exit;
}
do
{
//
// Loop through all the files in the physical path
//
_tcscpy(szThePath, lpszDirectoryPath);
_tcscat(szThePath, _T("\\*"));
WIN32_FIND_DATA w32data;
HANDLE hFind = ::FindFirstFile(szThePath, &w32data);
if (hFind == INVALID_HANDLE_VALUE)
{
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("MakeSureDirAclsHaveAtLeastRead:WARNING.filenotfound:%s"),lpszDirectoryPath));
// No files...
break;
}
//
// First, set the new ACL on the folder itself.
//
err = SetAccessOnFile(lpszDirectoryPath, TRUE);
err = SetAccessOnFile(lpszDirectoryPath, FALSE);
err = ERROR_SUCCESS;
//if (err != ERROR_SUCCESS){iisDebugOut((LOG_TYPE_WARN, _T("MakeSureDirAclsHaveAtLeastRead:%s:FAILED WARNING.ret=0x%x."),lpszDirectoryPath,err));}
//
// Now do all the files in it
//
do
{
//
// Only set the acl on files, not sub-directories
//
if (w32data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
continue;
}
//
// Build the current file's full path name
//
_tcscpy(szThePath, lpszDirectoryPath);
_tcscat(szThePath, _T("\\"));
_tcscat(szThePath, w32data.cFileName);
err = SetAccessOnFile(szThePath, TRUE);
err = SetAccessOnFile(szThePath, FALSE);
err = ERROR_SUCCESS;
//if (err != ERROR_SUCCESS){iisDebugOut((LOG_TYPE_WARN, _T("MakeSureDirAclsHaveAtLeastRead:%s:FAILED WARNING.ret=0x%x."),szThePath,err));}
} while(SUCCEEDED(err) && FindNextFile(hFind, &w32data));
FindClose(hFind);
} while(FALSE);
MakeSureDirAclsHaveAtLeastRead_Exit:
return;
}
DWORD SetAccessOnFile(IN LPTSTR FileName, BOOL bDoForAdmin)
{
DWORD dwError = 0;
TCHAR TrusteeName[50];
PACL ExistingDacl = NULL;
PACL NewAcl = NULL;
PSECURITY_DESCRIPTOR psd = NULL;
// access stuff.
DWORD AccessMask = GENERIC_ALL;
EXPLICIT_ACCESS explicitaccess;
ACCESS_MODE option;
DWORD InheritFlag = NO_INHERITANCE;
// other
PSID principalSID = NULL;
BOOL bWellKnownSID = FALSE;
TRUSTEE myTrustee;
// other other
LPCTSTR ServerName = NULL; // local machine
DWORD cbName = 200;
TCHAR lpGuestGrpName[200];
TCHAR ReferencedDomainName[200];
DWORD cbReferencedDomainName = sizeof(ReferencedDomainName);
SID_NAME_USE sidNameUse = SidTypeUser;
// get current Dacl on specified file
dwError = GetNamedSecurityInfo(FileName,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,&ExistingDacl,NULL,&psd);
if(dwError != ERROR_SUCCESS)
{
iisDebugOut((LOG_TYPE_WARN, _T("SetAccessOnFile: GetNamedSecurityInfo failed on %s. err=0x%x\n"),FileName,dwError));
goto SetAccessOnFile_Exit;
}
// set defaults
option = GRANT_ACCESS;
InheritFlag = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
if (bDoForAdmin)
{
// Do for Administrators -- should be more access
AccessMask = SYNCHRONIZE ;
AccessMask |= GENERIC_ALL;
_tcscpy(TrusteeName,_T("BUILTIN\\ADMINISTRATORS"));
_tcscpy(TrusteeName,_T("administrators"));
}
else
{
// Do for Administrators -- should be more access
AccessMask = SYNCHRONIZE ;
AccessMask |= GENERIC_READ;
_tcscpy(TrusteeName,_T("EVERYONE"));
}
// Get the SID for the certain string (administrator or everyone)
dwError = GetPrincipalSID(TrusteeName, &principalSID, &bWellKnownSID);
if (dwError != ERROR_SUCCESS)
{
iisDebugOut((LOG_TYPE_WARN, _T("SetAccessOnFile:GetPrincipalSID(%s) FAILED. Error()= 0x%x\n"), TrusteeName, dwError));
goto SetAccessOnFile_Exit;
}
// using Sid, get the "localized" name
if (0 == LookupAccountSid(ServerName, principalSID, lpGuestGrpName, &cbName, ReferencedDomainName, &cbReferencedDomainName, &sidNameUse))
{
iisDebugOut((LOG_TYPE_WARN, _T("SetAccessOnFile:LookupAccountSid(%s) FAILED. GetLastError()= 0x%x\n"), TrusteeName, GetLastError()));
goto SetAccessOnFile_Exit;
}
// using the "localized" name, build explicit access structure
BuildExplicitAccessWithName(&explicitaccess,lpGuestGrpName,AccessMask,option,InheritFlag);
explicitaccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
explicitaccess.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
explicitaccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
// set the acl with this certain access stuff
dwError = SetEntriesInAcl(1,&explicitaccess,ExistingDacl,&NewAcl);
if(dwError != ERROR_SUCCESS)
{
// it may error because the user is already there
//iisDebugOut((LOG_TYPE_WARN, _T("SetAccessOnFile: SetEntriesInAcl failed on %s. for trustee=%s. err=0x%x\n"),FileName,explicitaccess.Trustee.ptstrName,dwError));
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("SetAccessOnFile: SetEntriesInAcl failed on %s. for trustee=%s. err=0x%x\n"),FileName,explicitaccess.Trustee.ptstrName,dwError));
goto SetAccessOnFile_Exit;
}
// apply new security to file
dwError = SetNamedSecurityInfo(FileName,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,NewAcl,NULL);
if(dwError != ERROR_SUCCESS)
{
iisDebugOut((LOG_TYPE_WARN, _T("SetAccessOnFile: SetNamedSecurityInfo failed on %s. err=0x%x\n"),FileName,dwError));
goto SetAccessOnFile_Exit;
}
// everything is kool!
dwError = ERROR_SUCCESS;
SetAccessOnFile_Exit:
if(NewAcl != NULL){LocalFree(NewAcl);}
if(psd != NULL){LocalFree(psd);}
if (principalSID)
{
if (bWellKnownSID)
FreeSid (principalSID);
else
free (principalSID);
}
return dwError;
}
int CreateAnEmptyFile(CString strTheFullPath)
{
int iReturn = FALSE;
HANDLE hFile = NULL;
if (IsFileExist(strTheFullPath) == TRUE)
{
return TRUE;
}
// Open existing file or create a new one.
hFile = CreateFile(strTheFullPath,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hFile = NULL;
iisDebugOutSafeParams((LOG_TYPE_WARN, _T("CreateAnEmptyFile:() failed to CreateFile %1!s!. POTENTIAL PROBLEM. FAILURE.\n"), strTheFullPath));
}
else
{
// write to the file
if (hFile)
{
iReturn = TRUE;
/*
DWORD dwBytesWritten = 0;
char szTestData[2];
strcpy(szTestData, " ");
if (WriteFile(hFile,szTestData,strlen(szTestData),&dwBytesWritten,NULL))
{
// everything is hunky dory. don't print anything
iReturn = TRUE;
}
else
{
// error writing to the file.
iisDebugOutSafeParams((LOG_TYPE_WARN, _T("CreateAnEmptyFile:WriteFile(%1!s!) Failed. POTENTIAL PROBLEM. FAILURE. Error=0x%2!x!.\n"), strTheFullPath, GetLastError()));
}
*/
}
}
if (hFile)
{
CloseHandle(hFile);
}
return iReturn;
}
DWORD GrantUserAccessToFile(IN LPTSTR FileName,IN LPTSTR TrusteeName)
{
iisDebugOut_Start1(_T("GrantUserAccessToFile"),FileName,LOG_TYPE_TRACE);
DWORD dwError = 0;
PACL ExistingDacl = NULL;
PACL NewAcl = NULL;
PSECURITY_DESCRIPTOR psd = NULL;
// access stuff.
DWORD AccessMask = GENERIC_ALL;
EXPLICIT_ACCESS explicitaccess;
ACCESS_MODE option;
DWORD InheritFlag = NO_INHERITANCE;
// other
PSID principalSID = NULL;
BOOL bWellKnownSID = FALSE;
TRUSTEE myTrustee;
// other other
LPCTSTR ServerName = NULL; // local machine
DWORD cbName = 200;
TCHAR lpGuestGrpName[200];
TCHAR ReferencedDomainName[200];
DWORD cbReferencedDomainName = sizeof(ReferencedDomainName);
SID_NAME_USE sidNameUse = SidTypeUser;
if (IsFileExist(FileName) != TRUE)
{
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("GrantUserAccessToFile:file doesn't exist.")));
goto GrantUserAccessToFile_Exit;
}
if (FALSE == IsThisDriveNTFS(FileName))
{
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("GrantUserAccessToFile:filesys is not ntfs.")));
goto GrantUserAccessToFile_Exit;
}
// get current Dacl on specified file
dwError = GetNamedSecurityInfo(FileName,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,&ExistingDacl,NULL,&psd);
if(dwError != ERROR_SUCCESS)
{
psd = NULL;
iisDebugOut((LOG_TYPE_WARN, _T("GrantUserAccessToFile: GetNamedSecurityInfo failed on %s.\n"),FileName));
goto GrantUserAccessToFile_Exit;
}
// set defaults
option = GRANT_ACCESS;
InheritFlag = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
// assign access
AccessMask = SYNCHRONIZE ;
AccessMask |= GENERIC_ALL;
//AccessMask = MAXIMUM_ALLOWED;
// Get the SID for the certain string (administrator or everyone)
dwError = GetPrincipalSID(TrusteeName, &principalSID, &bWellKnownSID);
if (dwError != ERROR_SUCCESS)
{
principalSID = NULL;
iisDebugOut((LOG_TYPE_WARN, _T("GrantUserAccessToFile:GetPrincipalSID(%s) FAILED. Error()= 0x%x\n"), TrusteeName, dwError));
goto GrantUserAccessToFile_Exit;
}
// using Sid, get the "localized" name
if (0 == LookupAccountSid(ServerName, principalSID, lpGuestGrpName, &cbName, ReferencedDomainName, &cbReferencedDomainName, &sidNameUse))
{
iisDebugOut((LOG_TYPE_WARN, _T("GrantUserAccessToFile:LookupAccountSid(%s) FAILED. GetLastError()= 0x%x\n"), TrusteeName, GetLastError()));
goto GrantUserAccessToFile_Exit;
}
// using the "localized" name, build explicit access structure
BuildExplicitAccessWithName(&explicitaccess,lpGuestGrpName,AccessMask,option,InheritFlag);
explicitaccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
explicitaccess.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
explicitaccess.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
if (_tcsicmp(TrusteeName, _T("administrators")) == 0 || _tcsicmp(TrusteeName, _T("everyone")) == 0)
{
explicitaccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
}
// set the acl with this certain access stuff
dwError = SetEntriesInAcl(1,&explicitaccess,ExistingDacl,&NewAcl);
if(dwError != ERROR_SUCCESS)
{
NewAcl = NULL;
// it may error because the user is already there
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("GrantUserAccessToFile: SetEntriesInAcl failed on %s. for trustee=%s. err=0x%x\n"),FileName,explicitaccess.Trustee.ptstrName,dwError));
goto GrantUserAccessToFile_Exit;
}
// apply new security to file
dwError = SetNamedSecurityInfo(FileName,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,NewAcl,NULL);
if(dwError != ERROR_SUCCESS)
{
iisDebugOut((LOG_TYPE_WARN, _T("GrantUserAccessToFile: SetNamedSecurityInfo failed on %s. err=0x%x\n"),FileName,dwError));
goto GrantUserAccessToFile_Exit;
}
// everything is kool!
dwError = ERROR_SUCCESS;
GrantUserAccessToFile_Exit:
if(NewAcl != NULL){LocalFree(NewAcl);}
if(psd != NULL){LocalFree(psd);}
if (principalSID)
{
if (bWellKnownSID)
FreeSid (principalSID);
else
free (principalSID);
}
iisDebugOut_End1(_T("GrantUserAccessToFile"),FileName);
return dwError;
}
#ifndef _CHICAGO_
DWORD SetDirectorySecurity(
IN LPCTSTR szDirPath,
IN LPCTSTR szPrincipal,
IN INT iAceType,
IN DWORD dwAccessMask,
IN DWORD dwInheritMask
)
{
DWORD dwStatus = ERROR_FILE_NOT_FOUND;
if (ACCESS_ALLOWED_ACE_TYPE == iAceType || ACCESS_DENIED_ACE_TYPE == iAceType)
{
if (IsFileExist(szDirPath) == TRUE)
{
PSID principalSID = NULL;
BOOL bWellKnownSID = FALSE;
dwStatus = GetPrincipalSID((LPTSTR) szPrincipal, &principalSID, &bWellKnownSID);
if (dwStatus == ERROR_SUCCESS)
{
PSECURITY_DESCRIPTOR psd = NULL;
dwStatus = SetAccessOnDirOrFile((TCHAR*) szDirPath,principalSID,iAceType,dwAccessMask,dwInheritMask,&psd);
//DumpAdminACL(INVALID_HANDLE_VALUE,psd);
if (psd) {free(psd);psd=NULL;}
}
}
}
return dwStatus;
}
// -------------------------------------------------------------------------------------
// Function: RemovePrincipalFromFileAcl
//
// Remove a Access Control Entry from an Access Control List for a file/directory for a
// particular SID
//
// -------------------------------------------------------------------------------------
DWORD RemovePrincipalFromFileAcl(IN TCHAR *pszFile,IN LPTSTR szPrincipal)
{
PACL pdacl;
SECURITY_DESCRIPTOR_CONTROL sdc;
PSECURITY_DESCRIPTOR psdRelative = NULL;
PSECURITY_DESCRIPTOR psdAbsolute = NULL;
DWORD cbSize = 0;
BOOL bRes = 0;
DWORD dwSecurityDescriptorRevision;
BOOL fHasDacl = FALSE;
BOOL fDaclDefaulted = FALSE;
BOOL bUserExistsToBeDeleted;
DWORD dwError = ERROR_SUCCESS;
// get the size of the security descriptor
if ( !(bRes = GetFileSecurity(pszFile,DACL_SECURITY_INFORMATION,psdRelative,0,&cbSize)) )
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
psdRelative = malloc(cbSize);
if (!psdRelative)
{
return ERROR_INSUFFICIENT_BUFFER;
}
bRes = GetFileSecurity(pszFile,DACL_SECURITY_INFORMATION,psdRelative,cbSize,&cbSize);
}
}
if (!bRes)
{
if (psdRelative)
{
free(psdRelative);
}
return (GetLastError());
}
// get security descriptor control from the security descriptor
if (!GetSecurityDescriptorControl(psdRelative, (PSECURITY_DESCRIPTOR_CONTROL) &sdc,(LPDWORD) &dwSecurityDescriptorRevision))
{
dwError = GetLastError();
}
else if (SE_DACL_PRESENT & sdc)
{
// Acl's are present, so we will attempt to remove the one passes in.
if (GetSecurityDescriptorDacl(psdRelative, (LPBOOL) &fHasDacl,(PACL *) &pdacl, (LPBOOL) &fDaclDefaulted))
{
// Remove ACE from Acl
dwError = RemovePrincipalFromACL(pdacl,szPrincipal,&bUserExistsToBeDeleted);
if (dwError == ERROR_SUCCESS)
{
psdAbsolute = (PSECURITY_DESCRIPTOR) malloc(GetSecurityDescriptorLength(psdRelative));
if (psdAbsolute)
{
if ( !(InitializeSecurityDescriptor(psdAbsolute, SECURITY_DESCRIPTOR_REVISION)) ||
!(SetSecurityDescriptorDacl(psdAbsolute, TRUE, pdacl, fDaclDefaulted)) ||
!(IsValidSecurityDescriptor(psdAbsolute)) ||
!(SetFileSecurity(pszFile,(SECURITY_INFORMATION)(DACL_SECURITY_INFORMATION),psdAbsolute))
)
{
dwError = GetLastError();
}
if (psdAbsolute)
{
free(psdAbsolute);
}
}
else
{
dwError = ERROR_INSUFFICIENT_BUFFER;
}
}
}
else
{
dwError = GetLastError();
}
}
if (psdRelative)
{
free(psdRelative);
}
return dwError;
}
DWORD SetAccessOnDirOrFile(IN TCHAR *pszFile,PSID psidGroup,INT iAceType,DWORD dwAccessMask,DWORD dwInheritMask,PSECURITY_DESCRIPTOR* ppsd)
{
PSECURITY_DESCRIPTOR psdAbsolute = NULL;
PACL pdacl;
DWORD cbSecurityDescriptor = 0;
DWORD dwSecurityDescriptorRevision;
DWORD cbDacl = 0;
SECURITY_DESCRIPTOR_CONTROL sdc;
PACL pdaclNew = NULL;
DWORD cbAddDaclLength = 0;
BOOL fAceFound = FALSE;
BOOL fHasDacl = FALSE;
BOOL fDaclDefaulted = FALSE;
ACCESS_ALLOWED_ACE* pAce;
DWORD i;
BOOL fAceForGroupPresent = FALSE;
DWORD dwMask;
PSECURITY_DESCRIPTOR psdRelative = NULL;
DWORD cbSize = 0;
BOOL bRes = 0;
// get the size of the security descriptor
bRes = GetFileSecurity(pszFile,DACL_SECURITY_INFORMATION,psdRelative,0,&cbSize);
DWORD dwError = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == dwError)
{
psdRelative = malloc(cbSize);
if (!psdRelative)
{
return ERROR_INSUFFICIENT_BUFFER;
}
bRes = GetFileSecurity(pszFile,DACL_SECURITY_INFORMATION,psdRelative,cbSize,&cbSize);
}
if (!bRes)
{
if (psdRelative){free(psdRelative);}
return (GetLastError());
}
// get security descriptor control from the security descriptor
if (!GetSecurityDescriptorControl(psdRelative, (PSECURITY_DESCRIPTOR_CONTROL) &sdc,(LPDWORD) &dwSecurityDescriptorRevision))
{
return (GetLastError());
}
// check if DACL is present
if (SE_DACL_PRESENT & sdc)
{
ACE_HEADER *pAceHeader;
// get dacl
if (!GetSecurityDescriptorDacl(psdRelative, (LPBOOL) &fHasDacl,(PACL *) &pdacl, (LPBOOL) &fDaclDefaulted))
{
return ( GetLastError());
}
// check if pdacl is null
// if it is then security is wide open -- this could be a fat drive.
if (NULL == pdacl)
{
return ERROR_SUCCESS;
}
// get dacl length
cbDacl = pdacl->AclSize;
// now check if SID's ACE is there
for (i = 0; i < pdacl->AceCount; i++)
{
if (!GetAce(pdacl, i, (LPVOID *) &pAce))
{
return ( GetLastError());
}
pAceHeader = (ACE_HEADER *)pAce;
// check if group sid is already there
if (EqualSid((PSID) &(pAce->SidStart), psidGroup))
{
if (ACCESS_DENIED_ACE_TYPE == iAceType)
{
if (pAceHeader->AceType == ACCESS_DENIED_ACE_TYPE)
{
// If the correct access is present, return success
if ((pAce->Mask & dwAccessMask) == dwAccessMask)
{
return ERROR_SUCCESS;
}
fAceForGroupPresent = TRUE;
break;
}
}
else
{
if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
{
// If the correct access is present, return success
if ((pAce->Mask & dwAccessMask) == dwAccessMask)
{
return ERROR_SUCCESS;
}
fAceForGroupPresent = TRUE;
break;
}
}
}
}
// if the group did not exist, we will need to add room
// for another ACE
if (!fAceForGroupPresent)
{
// get length of new DACL
cbAddDaclLength = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(psidGroup);
}
}
else
{
// get length of new DACL
cbAddDaclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid (psidGroup);
}
// get memory needed for new DACL
pdaclNew = (PACL) malloc (cbDacl + cbAddDaclLength);
if (!pdaclNew)
{
return (GetLastError());
}
// get the sd length
cbSecurityDescriptor = GetSecurityDescriptorLength(psdRelative);
// get memory for new SD
psdAbsolute = (PSECURITY_DESCRIPTOR) malloc(cbSecurityDescriptor + cbAddDaclLength);
if (!psdAbsolute)
{
dwError = GetLastError();
goto ErrorExit;
}
// change self-relative SD to absolute by making new SD
if (!InitializeSecurityDescriptor(psdAbsolute, SECURITY_DESCRIPTOR_REVISION))
{
dwError = GetLastError();
goto ErrorExit;
}
// init new DACL
if (!InitializeAcl(pdaclNew, cbDacl + cbAddDaclLength, ACL_REVISION))
{
dwError = GetLastError();
goto ErrorExit;
}
// Add a new ACE for our SID if one was not already present
if ( (!fAceForGroupPresent) && (ACCESS_DENIED_ACE_TYPE == iAceType) )
{
if (!AddAccessDeniedAce(pdaclNew, ACL_REVISION, dwAccessMask,psidGroup))
{
dwError = GetLastError();
goto ErrorExit;
}
}
// now add in all of the ACEs into the new DACL (if org DACL is there)
if (SE_DACL_PRESENT & sdc)
{
ACE_HEADER *pAceHeader;
for (i = 0; i < pdacl->AceCount; i++)
{
// get ace from original dacl
if (!GetAce(pdacl, i, (LPVOID*) &pAce))
{
dwError = GetLastError();
goto ErrorExit;
}
pAceHeader = (ACE_HEADER *)pAce;
if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
{
dwMask = pAce->Mask;
if (ACCESS_ALLOWED_ACE_TYPE == iAceType)
{
// If an ACE for our SID exists, we just need to bump
// up the access level instead of creating a new ACE
if (EqualSid((PSID) &(pAce->SidStart), psidGroup))
{
dwMask = dwAccessMask | pAce->Mask;
}
}
if (!AddAccessAllowedAceEx(pdaclNew, ACL_REVISION, pAce->Header.AceFlags,dwMask,(PSID) &(pAce->SidStart)))
{
dwError = GetLastError();
goto ErrorExit;
}
}
else if (pAceHeader->AceType == ACCESS_DENIED_ACE_TYPE)
{
dwMask = pAce->Mask;
if (ACCESS_DENIED_ACE_TYPE == iAceType)
{
// If an ACE for our SID exists, we just need to bump
// up the access level instead of creating a new ACE
if (EqualSid((PSID) &(pAce->SidStart), psidGroup))
{
dwMask = dwAccessMask | pAce->Mask;
}
}
if (!AddAccessDeniedAceEx(pdaclNew, ACL_REVISION, pAce->Header.AceFlags,dwMask,(PSID) &(pAce->SidStart)))
{
dwError = GetLastError();
goto ErrorExit;
}
}
else
{
// copy denied or audit ace.
if (!AddAce(pdaclNew, ACL_REVISION, 0xFFFFFFFF,pAce, pAceHeader->AceSize ))
{
dwError = GetLastError();
goto ErrorExit;
}
}
//iisDebugOut((LOG_TYPE_TRACE, _T("OrgAce[%d]=0x%x\n"),i,pAce->Header.AceFlags));
}
}
// Add a new ACE for our SID if one was not already present
if ( (!fAceForGroupPresent) && (ACCESS_ALLOWED_ACE_TYPE == iAceType) )
{
if (!AddAccessAllowedAce(pdaclNew, ACL_REVISION, dwAccessMask,psidGroup))
{
dwError = GetLastError();
goto ErrorExit;
}
}
// change the header on an existing ace to have inherit
for (i = 0; i < pdaclNew->AceCount; i++)
{
if (!GetAce(pdaclNew, i, (LPVOID *) &pAce))
{
return ( GetLastError());
}
// CONTAINER_INHERIT_ACE = Other containers that are contained by the primary object inherit the entry.
// INHERIT_ONLY_ACE = The ACE does not apply to the primary object to which the ACL is attached, but objects contained by the primary object inherit the entry.
// NO_PROPAGATE_INHERIT_ACE = The OBJECT_INHERIT_ACE and CONTAINER_INHERIT_ACE flags are not propagated to an inherited entry.
// OBJECT_INHERIT_ACE = Noncontainer objects contained by the primary object inherit the entry.
// SUB_CONTAINERS_ONLY_INHERIT = Other containers that are contained by the primary object inherit the entry. This flag corresponds to the CONTAINER_INHERIT_ACE flag.
// SUB_OBJECTS_ONLY_INHERIT = Noncontainer objects contained by the primary object inherit the entry. This flag corresponds to the OBJECT_INHERIT_ACE flag.
// SUB_CONTAINERS_AND_OBJECTS_INHERIT = Both containers and noncontainer objects that are contained by the primary object inherit the entry. This flag corresponds to the combination of the CONTAINER_INHERIT_ACE and OBJECT_INHERIT_ACE flags.
//iisDebugOut((LOG_TYPE_TRACE, _T("NewAce[%d]=0x%x\n"),i,pAce->Header.AceFlags));
// if it's our SID, then change the header to be inherited
if (EqualSid((PSID) &(pAce->SidStart), psidGroup))
{
pAce->Header.AceFlags |= dwInheritMask;
}
}
// check if everything went ok
if (!IsValidAcl(pdaclNew))
{
dwError = ERROR_INVALID_ACL;
goto ErrorExit;
}
// now set security descriptor DACL
if (!SetSecurityDescriptorDacl(psdAbsolute, TRUE, pdaclNew, fDaclDefaulted))
{
dwError = GetLastError();
goto ErrorExit;
}
// check if everything went ok
if (!IsValidSecurityDescriptor(psdAbsolute))
{
dwError = ERROR_INVALID_SECURITY_DESCR;
goto ErrorExit;
}
// now set the reg key security (this will overwrite any existing security)
bRes = SetFileSecurity(pszFile,(SECURITY_INFORMATION)(DACL_SECURITY_INFORMATION),psdAbsolute);
if (bRes)
{
dwError = ERROR_SUCCESS;
}
if (ppsd)
{
*ppsd = psdRelative;
}
ErrorExit:
// free memory
if (psdAbsolute)
{
free (psdAbsolute);
if (pdaclNew)
{
free((VOID*) pdaclNew);
}
}
return dwError;
}
//+--------------------------------------------------------------------------
//
// Function: SetAccessOnRegKey
//
// Purpose: Adds access for a specified SID to a registry key
//
// Arguments:
// hkey [in] The registry key that will receive the
// modified security descriptor
// psidGroup [in] The SID (in self-relative mode) that will be
// granted access to the key
// dwAccessMask [in] The access level to grant
// ppsd [out] The previous security descriptor
//
// Returns: DWORD. ERROR_SUCCESS or a failure code from winerror.h
//
//+--------------------------------------------------------------------------
DWORD
SetAccessOnRegKey(HKEY hkey, PSID psidGroup,
DWORD dwAccessMask,
DWORD dwInheritMask,
PSECURITY_DESCRIPTOR* ppsd)
{
PSECURITY_DESCRIPTOR psdAbsolute = NULL;
PACL pdacl;
DWORD cbSecurityDescriptor = 0;
DWORD dwSecurityDescriptorRevision;
DWORD cbDacl = 0;
SECURITY_DESCRIPTOR_CONTROL sdc;
PACL pdaclNew = NULL;
DWORD cbAddDaclLength = 0;
BOOL fAceFound = FALSE;
BOOL fHasDacl = FALSE;
BOOL fDaclDefaulted = FALSE;
ACCESS_ALLOWED_ACE* pAce;
DWORD i;
BOOL fAceForGroupPresent = FALSE;
DWORD dwMask;
PSECURITY_DESCRIPTOR psdRelative = NULL;
DWORD cbSize = 0;
// Get the current security descriptor for hkey
//
DWORD dwError = RegGetKeySecurity(hkey, DACL_SECURITY_INFORMATION, psdRelative, &cbSize);
if (ERROR_INSUFFICIENT_BUFFER == dwError)
{
psdRelative = malloc(cbSize);
if (!psdRelative)
{
return ERROR_INSUFFICIENT_BUFFER;
}
dwError = RegGetKeySecurity(hkey, DACL_SECURITY_INFORMATION, psdRelative, &cbSize);
}
// get security descriptor control from the security descriptor
if ( (!psdRelative) ||
(dwError != ERROR_SUCCESS) ||
(!GetSecurityDescriptorControl(psdRelative, (PSECURITY_DESCRIPTOR_CONTROL) &sdc,(LPDWORD) &dwSecurityDescriptorRevision))
)
{
return (GetLastError());
}
// check if DACL is present
if (SE_DACL_PRESENT & sdc)
{
ACE_HEADER *pAceHeader;
// get dacl
if (!GetSecurityDescriptorDacl(psdRelative, (LPBOOL) &fHasDacl,(PACL *) &pdacl, (LPBOOL) &fDaclDefaulted))
{
return ( GetLastError());
}
// check if pdacl is null
// if it is then security is wide open -- this could be a fat drive.
if (NULL == pdacl)
{
return ERROR_SUCCESS;
}
// get dacl length
cbDacl = pdacl->AclSize;
// now check if SID's ACE is there
for (i = 0; i < pdacl->AceCount; i++)
{
if (!GetAce(pdacl, i, (LPVOID *) &pAce))
{
return ( GetLastError());
}
pAceHeader = (ACE_HEADER *)pAce;
if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
{
// check if group sid is already there
if (EqualSid((PSID) &(pAce->SidStart), psidGroup))
{
// If the correct access is present, return success
if ((pAce->Mask & dwAccessMask) == dwAccessMask)
{
return ERROR_SUCCESS;
}
fAceForGroupPresent = TRUE;
break;
}
}
}
// if the group did not exist, we will need to add room
// for another ACE
if (!fAceForGroupPresent)
{
// get length of new DACL
cbAddDaclLength = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(psidGroup);
}
}
else
{
// get length of new DACL
cbAddDaclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid (psidGroup);
}
// get memory needed for new DACL
pdaclNew = (PACL) malloc (cbDacl + cbAddDaclLength);
if (!pdaclNew)
{
return (GetLastError());
}
// get the sd length
cbSecurityDescriptor = GetSecurityDescriptorLength(psdRelative);
// get memory for new SD
psdAbsolute = (PSECURITY_DESCRIPTOR) malloc(cbSecurityDescriptor + cbAddDaclLength);
if (!psdAbsolute)
{
dwError = GetLastError();
goto ErrorExit;
}
// change self-relative SD to absolute by making new SD
if (!InitializeSecurityDescriptor(psdAbsolute, SECURITY_DESCRIPTOR_REVISION))
{
dwError = GetLastError();
goto ErrorExit;
}
// init new DACL
if (!InitializeAcl(pdaclNew, cbDacl + cbAddDaclLength, ACL_REVISION))
{
dwError = GetLastError();
goto ErrorExit;
}
// now add in all of the ACEs into the new DACL (if org DACL is there)
if (SE_DACL_PRESENT & sdc)
{
ACE_HEADER *pAceHeader;
for (i = 0; i < pdacl->AceCount; i++)
{
// get ace from original dacl
if (!GetAce(pdacl, i, (LPVOID*) &pAce))
{
dwError = GetLastError();
goto ErrorExit;
}
pAceHeader = (ACE_HEADER *)pAce;
if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
{
// If an ACE for our SID exists, we just need to bump
// up the access level instead of creating a new ACE
//
if (EqualSid((PSID) &(pAce->SidStart), psidGroup))
{
dwMask = dwAccessMask | pAce->Mask;
}
else
{
dwMask = pAce->Mask;
}
//iisDebugOut((LOG_TYPE_TRACE, _T("OrgAce[%d]=0x%x\n"),i,pAce->Header.AceFlags));
// now add ace to new dacl
if (!AddAccessAllowedAceEx(pdaclNew, ACL_REVISION, pAce->Header.AceFlags,dwMask,(PSID) &(pAce->SidStart)))
{
dwError = GetLastError();
goto ErrorExit;
}
}
else
{
// copy denied or audit ace.
if (!AddAce(pdaclNew, ACL_REVISION, 0xFFFFFFFF, pAce, pAceHeader->AceSize ))
{
dwError = GetLastError();
goto ErrorExit;
}
}
}
}
// Add a new ACE for our SID if one was not already present
if (!fAceForGroupPresent)
{
// now add new ACE to new DACL
if (!AddAccessAllowedAce(pdaclNew, ACL_REVISION, dwAccessMask,psidGroup))
{
dwError = GetLastError();
goto ErrorExit;
}
}
// change the header on an existing ace to have inherit
for (i = 0; i < pdaclNew->AceCount; i++)
{
if (!GetAce(pdaclNew, i, (LPVOID *) &pAce))
{
return ( GetLastError());
}
// CONTAINER_INHERIT_ACE = Other containers that are contained by the primary object inherit the entry.
// INHERIT_ONLY_ACE = The ACE does not apply to the primary object to which the ACL is attached, but objects contained by the primary object inherit the entry.
// NO_PROPAGATE_INHERIT_ACE = The OBJECT_INHERIT_ACE and CONTAINER_INHERIT_ACE flags are not propagated to an inherited entry.
// OBJECT_INHERIT_ACE = Noncontainer objects contained by the primary object inherit the entry.
// SUB_CONTAINERS_ONLY_INHERIT = Other containers that are contained by the primary object inherit the entry. This flag corresponds to the CONTAINER_INHERIT_ACE flag.
// SUB_OBJECTS_ONLY_INHERIT = Noncontainer objects contained by the primary object inherit the entry. This flag corresponds to the OBJECT_INHERIT_ACE flag.
// SUB_CONTAINERS_AND_OBJECTS_INHERIT = Both containers and noncontainer objects that are contained by the primary object inherit the entry. This flag corresponds to the combination of the CONTAINER_INHERIT_ACE and OBJECT_INHERIT_ACE flags.
//iisDebugOut((LOG_TYPE_TRACE, _T("NewAce[%d]=0x%x\n"),i,pAce->Header.AceFlags));
// if it's our SID, then change the header to be inherited
if (EqualSid((PSID) &(pAce->SidStart), psidGroup))
{
//pAce->Header.AceFlags |= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE | INHERITED_ACE;
//pAce->Header.AceFlags |= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE | dwInheritMask;
pAce->Header.AceFlags |= dwInheritMask;
}
}
// check if everything went ok
if (!IsValidAcl(pdaclNew))
{
dwError = ERROR_INVALID_ACL;
goto ErrorExit;
}
// now set security descriptor DACL
if (!SetSecurityDescriptorDacl(psdAbsolute, TRUE, pdaclNew, fDaclDefaulted))
{
dwError = GetLastError();
goto ErrorExit;
}
// check if everything went ok
if (!IsValidSecurityDescriptor(psdAbsolute))
{
dwError = ERROR_INVALID_SECURITY_DESCR;
goto ErrorExit;
}
// now set the reg key security (this will overwrite any
// existing security)
dwError = RegSetKeySecurity(hkey, (SECURITY_INFORMATION)(DACL_SECURITY_INFORMATION), psdAbsolute);
if (ppsd)
{
*ppsd = psdRelative;
}
ErrorExit:
// free memory
if (psdAbsolute)
{
free (psdAbsolute);
if (pdaclNew)
{
free((VOID*) pdaclNew);
}
}
return dwError;
}
BOOL
AddUserAccessToSD(
IN PSECURITY_DESCRIPTOR pSd,
IN PSID pSid,
IN DWORD NewAccess,
IN UCHAR TheAceType,
OUT PSECURITY_DESCRIPTOR *ppSdNew
)
{
ULONG i;
BOOL bReturn = FALSE;
BOOL Result;
BOOL DaclPresent;
BOOL DaclDefaulted;
DWORD Length;
DWORD NewAclLength;
ACCESS_ALLOWED_ACE* OldAce;
PACE_HEADER NewAce;
ACL_SIZE_INFORMATION AclInfo;
PACL Dacl = NULL;
PACL NewDacl = NULL;
PACL NewAceDacl = NULL;
PSECURITY_DESCRIPTOR NewSD = NULL;
PSECURITY_DESCRIPTOR OldSD = NULL;
PSECURITY_DESCRIPTOR outpSD = NULL;
DWORD cboutpSD = 0;
BOOL fAceForGroupPresent = FALSE;
DWORD dwMask;
OldSD = pSd;
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("AddUserAccessToSD start\n")));
// only do if the ace is allowed/denied
if (ACCESS_ALLOWED_ACE_TYPE != TheAceType && ACCESS_DENIED_ACE_TYPE != TheAceType)
{
iisDebugOut((LOG_TYPE_TRACE, _T("AddUserAccessToSD useless param\n")));
goto AddUserAccessToSD_Exit;
}
// Convert SecurityDescriptor to absolute format. It generates
// a new SecurityDescriptor for its output which we must free.
if ( !MakeAbsoluteCopyFromRelative(OldSD, &NewSD) )
{
iisDebugOut((LOG_TYPE_ERROR, _T("MakeAbsoluteCopyFromRelative failed\n")));
goto AddUserAccessToSD_Exit;
}
// Must get DACL pointer from new (absolute) SD
if(!GetSecurityDescriptorDacl(NewSD,&DaclPresent,&Dacl,&DaclDefaulted))
{
iisDebugOut((LOG_TYPE_ERROR, _T("GetSecurityDescriptorDacl failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
// If no DACL, no need to add the user since no DACL
// means all accesss
if( !DaclPresent )
{
bReturn = TRUE;
goto AddUserAccessToSD_Exit;
}
// Code can return DaclPresent, but a NULL which means
// a NULL Dacl is present. This allows all access to the object.
if( Dacl == NULL )
{
bReturn = TRUE;
goto AddUserAccessToSD_Exit;
}
// Get the current ACL's size
if( !GetAclInformation(Dacl,&AclInfo,sizeof(AclInfo),AclSizeInformation) )
{
iisDebugOut((LOG_TYPE_ERROR, _T("GetAclInformation failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
// Check if access is already there
// --------------------------------
// Check to see if this SID already exists in there
// if it does (and it has the right access we want) then forget it, we don't have to do anything more.
for (i = 0; i < AclInfo.AceCount; i++)
{
ACE_HEADER *pAceHeader;
ACCESS_ALLOWED_ACE* pAce = NULL;
if (!GetAce(Dacl, i, (LPVOID *) &pAce))
{
iisDebugOut((LOG_TYPE_ERROR, _T("GetAce failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
pAceHeader = (ACE_HEADER *)pAce;
// check if group sid is already there
if (EqualSid((PSID) &(pAce->SidStart), pSid))
{
if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
{
// If the correct access is present, return success
if ((pAce->Mask & NewAccess) == NewAccess)
{
//iisDebugOut((LOG_TYPE_TRACE, _T("AddUserAccessToSD:correct access already present. Exiting,1=0x%x,2=0x%x,3=0x%x\n"),pAce->Mask,NewAccess,(pAce->Mask & NewAccess)));
bReturn = TRUE;
goto AddUserAccessToSD_Exit;
}
else
{
// the ace that exist doesn't have the permissions that we want.
// If an ACE for our SID exists, we just need to bump
// up the access level instead of creating a new ACE
fAceForGroupPresent = TRUE;
}
}
break;
}
}
// If we have to create a new ACE
// (because our user isn't listed in the existing ACL)
// then let's Create a new ACL to put the new access allowed ACE on
// --------------------------------
if (!fAceForGroupPresent)
{
NewAclLength = sizeof(ACL) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG) +
GetLengthSid( pSid );
NewAceDacl = (PACL) LocalAlloc( LMEM_FIXED, NewAclLength );
if ( NewAceDacl == NULL )
{
iisDebugOut((LOG_TYPE_ERROR, _T("LocalAlloc failed\n")));
goto AddUserAccessToSD_Exit;
}
if(!InitializeAcl( NewAceDacl, NewAclLength, ACL_REVISION ))
{
iisDebugOut((LOG_TYPE_ERROR, _T("InitializeAcl failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
if (ACCESS_DENIED_ACE_TYPE == TheAceType)
{
Result = AddAccessDeniedAce(NewAceDacl,ACL_REVISION,NewAccess,pSid);
}
else
{
Result = AddAccessAllowedAce(NewAceDacl,ACL_REVISION,NewAccess,pSid);
}
if( !Result )
{
iisDebugOut((LOG_TYPE_ERROR, _T("AddAccessAllowedAce failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
// Grab the 1st ace from the Newly created Dacl
if(!GetAce( NewAceDacl, 0, (void **)&NewAce ))
{
iisDebugOut((LOG_TYPE_ERROR, _T("GetAce failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
// add CONTAINER_INHERIT_ACE TO AceFlags
//NewAce->AceFlags |= CONTAINER_INHERIT_ACE;
Length = AclInfo.AclBytesInUse + NewAce->AceSize;
}
else
{
Length = AclInfo.AclBytesInUse;
}
// Allocate new DACL
NewDacl = (PACL) LocalAlloc( LMEM_FIXED, Length );
if(NewDacl == NULL)
{
iisDebugOut((LOG_TYPE_ERROR, _T("LocalAlloc failed\n")));
goto AddUserAccessToSD_Exit;
}
if(!InitializeAcl( NewDacl, Length, ACL_REVISION ))
{
iisDebugOut((LOG_TYPE_ERROR, _T("InitializeAcl failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
// Insert new ACE at the front of the new DACL
if (!fAceForGroupPresent)
{
if(!AddAce( NewDacl, ACL_REVISION, 0, NewAce, NewAce->AceSize ))
{
iisDebugOut((LOG_TYPE_ERROR, _T("AddAce failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
}
// ----------------------------------------
// Read thru the old Dacl and get the ACE's
// add it to the new Dacl
// ----------------------------------------
for ( i = 0; i < AclInfo.AceCount; i++ )
{
ACE_HEADER *pAceHeader;
Result = GetAce( Dacl, i, (LPVOID*) &OldAce );
if( !Result )
{
iisDebugOut((LOG_TYPE_ERROR, _T("GetAce failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
pAceHeader = (ACE_HEADER *)OldAce;
// If an ACE for our SID exists, we just need to bump
// up the access level instead of creating a new ACE
//
if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
{
dwMask = OldAce->Mask;
if (fAceForGroupPresent)
{
if (EqualSid((PSID) &(OldAce->SidStart), pSid))
{
dwMask = NewAccess | OldAce->Mask;
}
}
// now add ace to new dacl
Result = AddAccessAllowedAceEx(NewDacl, ACL_REVISION, OldAce->Header.AceFlags,dwMask,(PSID) &(OldAce->SidStart));
if( !Result )
{
iisDebugOut((LOG_TYPE_ERROR, _T("AddAccessAllowedAceEx failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
}
else
{
// copy denied or audit ace.
if (!AddAce(NewDacl, ACL_REVISION, 0xFFFFFFFF,OldAce, pAceHeader->AceSize ))
{
iisDebugOut((LOG_TYPE_ERROR, _T("AddAce failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
}
}
// Set new DACL for Security Descriptor
if(!SetSecurityDescriptorDacl(NewSD,TRUE,NewDacl,FALSE))
{
iisDebugOut((LOG_TYPE_ERROR, _T("SetSecurityDescriptorDacl failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
// The new SD is in absolute format. change it to Relative before we pass it back
cboutpSD = 0;
MakeSelfRelativeSD(NewSD, outpSD, &cboutpSD);
outpSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(GPTR, cboutpSD);
if ( !outpSD )
{
iisDebugOut((LOG_TYPE_ERROR, _T("GlobalAlloc failed\n")));
goto AddUserAccessToSD_Exit;
}
if (!MakeSelfRelativeSD(NewSD, outpSD, &cboutpSD))
{
iisDebugOut((LOG_TYPE_ERROR, _T("MakeSelfRelativeSD failed with 0x%x\n"),GetLastError()));
goto AddUserAccessToSD_Exit;
}
// The new SD is passed back in relative format,
*ppSdNew = outpSD;
bReturn = TRUE;
AddUserAccessToSD_Exit:
if (NewSD){free( NewSD );NewSD = NULL;}
if (NewDacl){LocalFree( NewDacl );NewDacl = NULL;}
if (NewAceDacl){LocalFree( NewAceDacl );NewAceDacl = NULL;}
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("AddUserAccessToSD end\n")));
return bReturn;
}
DWORD SetRegistryKeySecurityAdmin(HKEY hkey, DWORD samDesired,PSECURITY_DESCRIPTOR* ppsdOld)
{
PSID psid;
SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_NT_AUTHORITY;
DWORD dwError = ERROR_SUCCESS;
// Get sid for the local Administrators group
if (!AllocateAndInitializeSid(&sidAuth, 2,SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,0, 0, 0, 0, 0, 0, &psid) )
{
dwError = GetLastError();
}
if (ERROR_SUCCESS == dwError)
{
// Add all access privileges for the local administrators group
dwError = SetAccessOnRegKey(hkey, psid, samDesired, CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE | INHERITED_ACE, ppsdOld);
}
return dwError;
}
DWORD SetRegistryKeySecurity(
IN HKEY hkeyRootKey,
IN LPCTSTR szKeyPath,
IN LPCTSTR szPrincipal,
IN DWORD dwAccessMask,
IN DWORD dwInheritMask,
IN BOOL bDoSubKeys,
IN LPTSTR szExclusiveList
)
{
DWORD dwStatus;
HKEY hkeyThisKey;
DWORD dwKeyIndex;
DWORD dwSubKeyLen;
TCHAR szSubKeyName[_MAX_PATH];
FILETIME FileTime;
TCHAR *szExclusiveStart;
BOOL fSetSecurityRec;
dwStatus = RegOpenKeyEx(hkeyRootKey,szKeyPath,0L,KEY_ALL_ACCESS,&hkeyThisKey);
if (ERROR_SUCCESS == dwStatus)
{
PSID principalSID = NULL;
BOOL bWellKnownSID = FALSE;
if (ERROR_SUCCESS == GetPrincipalSID((LPTSTR) szPrincipal, &principalSID, &bWellKnownSID))
{
PSECURITY_DESCRIPTOR psd = NULL;
SetAccessOnRegKey(hkeyThisKey,principalSID,dwAccessMask,dwInheritMask,&psd);
if (psd) {free(psd);}
if (bDoSubKeys)
{
dwKeyIndex = 0;
dwSubKeyLen = sizeof(szSubKeyName) / sizeof(TCHAR);
while (RegEnumKeyEx (hkeyThisKey,dwKeyIndex,szSubKeyName,&dwSubKeyLen,NULL,NULL,NULL,&FileTime) == ERROR_SUCCESS)
{
// subkey found so set subkey security
// attach on the inherited ace attribute since everything under this will be inherited
dwInheritMask |= INHERITED_ACE;
fSetSecurityRec = TRUE;
szExclusiveStart = szExclusiveList;
while ( szExclusiveStart != NULL )
{
szExclusiveStart = _tcsstr(szExclusiveStart,szSubKeyName);
// If we have found the substring, and the character after it is a NULL terminator or a ',', and
// it is at the begining of the string, or it had a , before it, then it is a match.
if ( ( szExclusiveStart != NULL ) &&
( ( *(szExclusiveStart + dwSubKeyLen) == '\0' ) || ( *(szExclusiveStart + dwSubKeyLen) == ',' ) ) &&
( ( szExclusiveStart == szExclusiveList) || (*(szExclusiveStart - 1) == ',') )
)
{
fSetSecurityRec = FALSE;
break;
}
// Increment to move past current search result
if (szExclusiveStart)
{
szExclusiveStart = szExclusiveStart + dwSubKeyLen;
}
}
if ( fSetSecurityRec )
{
dwStatus = SetRegistryKeySecurity(hkeyThisKey,szSubKeyName,szPrincipal,dwAccessMask,dwInheritMask,bDoSubKeys,szExclusiveList);
}
// set variables for next call
dwKeyIndex++;
dwSubKeyLen = sizeof(szSubKeyName) / sizeof(TCHAR);
}
}
}
RegCloseKey(hkeyThisKey);
}
return dwStatus;
}
#endif