#include "stdafx.h" #include #include #include #include "lzexpand.h" #include "log.h" #include "dcomperm.h" #include "strfn.h" #include "other.h" #include #include 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 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