2981 lines
97 KiB
C++
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
|
|
|