#include "stdafx.h" #include #include #include "setupapi.h" #include "log.h" #include "iiscnfg.h" #include "iadmw.h" #include "mdkey.h" #define DBL_UNDEFINED ((DWORD)-1) DWORD gDebugLevel = DBL_UNDEFINED; extern MyLogFile g_MyLogFile; // Forward references DWORD SetAdminACL_wrap(LPCTSTR szKeyPath, DWORD dwAccessForEveryoneAccount, BOOL bDisplayMsgOnErrFlag); DWORD WriteSDtoMetaBase(PSECURITY_DESCRIPTOR outpSD, LPCTSTR szKeyPath); DWORD GetPrincipalSID (LPTSTR Principal, PSID *Sid, BOOL *pbWellKnownSID); DWORD SetAdminACL(LPCTSTR szKeyPath, DWORD dwAccessForEveryoneAccount); void DebugOutputFile(TCHAR* pszTemp) { // // NT5 doesn't want us to put all the debug string // in debugger. So we skip them based on a regkey. // See GetDebugLevel(). // Todo: Log strings to a logfile!!! // See IIS log.h, log.cpp for examples! // g_MyLogFile.LogFileWrite(pszTemp); if (gDebugLevel == DBL_UNDEFINED) {gDebugLevel = GetDebugLevel();} if (gDebugLevel) { OutputDebugString(pszTemp); } } void DebugOutput(LPCTSTR szFormat, ...) { va_list marker; TCHAR szTemp[1024]; // Encompass this whole iisdebugout deal in a try-catch. // not too good to have this one access violating. // when trying to produce a debugoutput! __try { va_start( marker, szFormat ); vswprintf(szTemp, szFormat, marker ); lstrcat(szTemp, _T("\n")); va_end( marker ); } __except(EXCEPTION_EXECUTE_HANDLER) { TCHAR szErrorString[100]; _stprintf(szErrorString, _T("\r\n\r\nException Caught in DebugOutput(). GetExceptionCode()=0x%x.\r\n\r\n"), GetExceptionCode()); OutputDebugString(szErrorString); g_MyLogFile.LogFileWrite(szErrorString); } // output to log file and the screen. DebugOutputFile(szTemp); return; } // This function requires inputs like this: // iisDebugOutSafeParams2("this %1!s! is %2!s! and has %3!d! args", "function", "kool", 3); // you must specify the %1 deals. this is so that // if something like this is passed in "this %SYSTEMROOT% %1!s!", it will put the string into %1 not %s! void DebugOutputSafe(TCHAR *pszfmt, ...) { // The count of parameters do not match va_list va; TCHAR *pszFullErrMsg = NULL; va_start(va, pszfmt); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_STRING, (LPCVOID) pszfmt, 0, 0, (LPTSTR) &pszFullErrMsg, 0, &va); if (pszFullErrMsg) { // output to log file and the screen. DebugOutputFile(pszFullErrMsg); } va_end(va); if (pszFullErrMsg) {LocalFree(pszFullErrMsg);pszFullErrMsg=NULL;} return; } BOOL IsFileExist(LPCTSTR szFile) { return (GetFileAttributes(szFile) != 0xFFFFFFFF); } 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; } // Given a fullpathname of a directory, remove any empty dirs under it including itself BOOL RecRemoveEmptyDir(LPCTSTR szName) { 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) return( ::RemoveDirectory(szName) ); else return FALSE; } // 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) ); } INT InstallPerformance( CString nlsRegPerf, CString nlsDll, CString nlsOpen, CString nlsClose, CString nlsCollect ) { INT err = NERR_Success; if (theApp.m_eOS != OS_W95) { CRegKey regPerf( nlsRegPerf, HKEY_LOCAL_MACHINE ); if (regPerf) { regPerf.SetValue(_T("Library"), nlsDll ); regPerf.SetValue(_T("Open"), nlsOpen ); regPerf.SetValue(_T("Close"), nlsClose ); regPerf.SetValue(_T("Collect"), nlsCollect ); } } return(err); } // // Add eventlog to the registry // INT AddEventLog(CString nlsService, CString nlsMsgFile, DWORD dwType) { INT err = NERR_Success; CString nlsLog = REG_EVENTLOG; nlsLog += _T("\\"); nlsLog += nlsService; CRegKey regService( nlsLog, HKEY_LOCAL_MACHINE ); if ( regService ) { regService.SetValue( _T("EventMessageFile"), nlsMsgFile, TRUE ); regService.SetValue( _T("TypesSupported"), dwType ); } return(err); } // // Remove eventlog from the registry // INT RemoveEventLog( CString nlsService ) { INT err = NERR_Success; CString nlsLog = REG_EVENTLOG; CRegKey regService( HKEY_LOCAL_MACHINE, nlsLog ); if ( regService ) regService.DeleteTree( nlsService ); return(err); } // // Install SNMP agent to the registry // INT InstallAgent( CString nlsName, CString nlsPath ) { INT err = NERR_Success; do { CString nlsSnmpParam = REG_SNMPPARAMETERS; CRegKey regSnmpParam( HKEY_LOCAL_MACHINE, nlsSnmpParam ); if ( regSnmpParam == (HKEY)NULL ) break; CString nlsSoftwareMSFT = REG_SOFTWAREMSFT; CRegKey regSoftwareMSFT( HKEY_LOCAL_MACHINE, nlsSoftwareMSFT ); if ( (HKEY) NULL == regSoftwareMSFT ) break; // add agent key CRegKey regAgent( nlsName, regSoftwareMSFT ); if ( (HKEY) NULL == regAgent ) break; CString nlsCurVersion = REG_CURVERSION; CRegKey regAgentCurVersion( nlsCurVersion, regAgent ); if ((HKEY) NULL == regAgentCurVersion ) break; regAgentCurVersion.SetValue(_T("Pathname"), nlsPath ); CRegKey regAgentParam( nlsName, regSnmpParam ); if ((HKEY) NULL == regAgentParam ) break; CString nlsSnmpExt = REG_SNMPEXTAGENT; CRegKey regSnmpExt( nlsSnmpExt, HKEY_LOCAL_MACHINE ); if ((HKEY) NULL == regSnmpExt ) break; // find the first available number slot for ( INT i=0; ;i++ ) { CString nlsPos; nlsPos.Format( _T("%d"),i); CString nlsValue; if ( regSnmpExt.QueryValue( nlsPos, nlsValue ) != NERR_Success ) { // okay, an empty spot nlsValue.Format(_T("%s\\%s\\%s"), REG_SOFTWAREMSFT, (LPCTSTR)nlsName, REG_CURVERSION ); regSnmpExt.SetValue( nlsPos, nlsValue ); break; } else { if ( nlsValue.Find( nlsName) != (-1)) { break; } } } } while (FALSE); return(err); } // // Remove an SNMP agent from the registry // INT RemoveAgent( CString nlsServiceName ) { INT err = NERR_Success; do { CString nlsSoftwareAgent = REG_SOFTWAREMSFT; CRegKey regSoftwareAgent( HKEY_LOCAL_MACHINE, nlsSoftwareAgent ); if ((HKEY)NULL == regSoftwareAgent ) break; regSoftwareAgent.DeleteTree( nlsServiceName ); CString nlsSnmpParam = REG_SNMPPARAMETERS; CRegKey regSnmpParam( HKEY_LOCAL_MACHINE, nlsSnmpParam ); if ((HKEY) NULL == regSnmpParam ) break; regSnmpParam.DeleteTree( nlsServiceName ); CString nlsSnmpExt = REG_SNMPEXTAGENT; CRegKey regSnmpExt( HKEY_LOCAL_MACHINE, nlsSnmpExt ); if ((HKEY) NULL == regSnmpExt ) break; CRegValueIter enumSnmpExt( regSnmpExt ); CString strName; DWORD dwType; CString csServiceName; csServiceName = _T("\\") + nlsServiceName; csServiceName += _T("\\"); while ( enumSnmpExt.Next( &strName, &dwType ) == NERR_Success ) { CString nlsValue; regSnmpExt.QueryValue( strName, nlsValue ); if ( nlsValue.Find( csServiceName ) != (-1)) { // found it regSnmpExt.DeleteValue( (LPCTSTR)strName ); break; } } } while (FALSE); return(err); } LONG lodctr(LPCTSTR lpszIniFile) { CString csCmdLine = _T("lodctr "); csCmdLine += theApp.m_csSysDir; csCmdLine += _T("\\"); csCmdLine += lpszIniFile; return (LONG)(LoadPerfCounterTextStrings((LPTSTR)(LPCTSTR)csCmdLine, TRUE)); } LONG unlodctr(LPCTSTR lpszDriver) { CString csCmdLine = _T("unlodctr "); csCmdLine += lpszDriver; return (LONG)(UnloadPerfCounterTextStrings((LPTSTR)(LPCTSTR)csCmdLine, TRUE)); } // // Given a directory path, set everyone full control security // BOOL SetEveryoneACL (CString &str, BOOL fAddAnonymousLogon) { DWORD dwRes, dwDisposition; PSID pEveryoneSID = NULL; PSID pAnonymousLogonSID = NULL; PACL pACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; const int cMaxExplicitAccess = 4; EXPLICIT_ACCESS ea[cMaxExplicitAccess]; int cExplicitAccess = 0; SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY; SECURITY_ATTRIBUTES sa; LONG lRes; BOOL fRet = FALSE; // Create a security descriptor for the files // Create a well-known SID for the Everyone group. if(! AllocateAndInitializeSid( &SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID) ) { goto Exit; } // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow Everyone read access to the key. ZeroMemory(&ea, sizeof(ea)); ea[0].grfAccessPermissions = WRITE_DAC | WRITE_OWNER; ea[0].grfAccessMode = DENY_ACCESS; ea[0].grfInheritance= SUB_CONTAINERS_AND_OBJECTS_INHERIT; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[0].Trustee.ptstrName = (LPTSTR) pEveryoneSID; ea[1].grfAccessPermissions = GENERIC_ALL; ea[1].grfAccessMode = SET_ACCESS; ea[1].grfInheritance= SUB_CONTAINERS_AND_OBJECTS_INHERIT; ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[1].Trustee.ptstrName = (LPTSTR) pEveryoneSID; cExplicitAccess = 2; if (fAddAnonymousLogon) { if(! AllocateAndInitializeSid( &SIDAuthNT, 1, SECURITY_ANONYMOUS_LOGON_RID, 0, 0, 0, 0, 0, 0, 0, &pAnonymousLogonSID) ) { goto Exit; } ea[2].grfAccessPermissions = WRITE_DAC | WRITE_OWNER; ea[2].grfAccessMode = DENY_ACCESS; ea[2].grfInheritance= SUB_CONTAINERS_AND_OBJECTS_INHERIT; ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[2].Trustee.TrusteeType = TRUSTEE_IS_USER; ea[2].Trustee.ptstrName = (LPTSTR) pAnonymousLogonSID; ea[3].grfAccessPermissions = GENERIC_ALL; ea[3].grfAccessMode = SET_ACCESS; ea[3].grfInheritance= SUB_CONTAINERS_AND_OBJECTS_INHERIT; ea[3].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[3].Trustee.TrusteeType = TRUSTEE_IS_USER; ea[3].Trustee.ptstrName = (LPTSTR) pAnonymousLogonSID; cExplicitAccess = 4; } // Create a new ACL that contains the new ACEs. dwRes = SetEntriesInAcl(cExplicitAccess, ea, NULL, &pACL); if (ERROR_SUCCESS != dwRes) { goto Exit; } // Initialize a security descriptor. pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (pSD == NULL) { goto Exit; } if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { goto Exit; } // Add the ACL to the security descriptor. if (!SetSecurityDescriptorDacl(pSD, TRUE, // fDaclPresent flag pACL, FALSE)) // not a default DACL { goto Exit; } // Initialize a security attributes structure. sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = pSD; sa.bInheritHandle = FALSE; fRet = SetFileSecurity (str, DACL_SECURITY_INFORMATION, pSD); Exit: if (pEveryoneSID) FreeSid(pEveryoneSID); if (pAnonymousLogonSID) FreeSid(pAnonymousLogonSID); if (pACL) LocalFree(pACL); if (pSD) LocalFree(pSD); return fRet; } // // Given a directory path, this subroutine will create the direct layer by layer // BOOL CreateLayerDirectory( CString &str ) { BOOL fReturn = TRUE; do { INT index=0; INT iLength = str.GetLength(); // first find the index for the first directory if ( iLength > 2 ) { if ( str[1] == _T(':')) { // assume the first character is driver letter if ( str[2] == _T('\\')) { index = 2; } else { index = 1; } } else if ( str[0] == _T('\\')) { if ( str[1] == _T('\\')) { BOOL fFound = FALSE; INT i; INT nNum = 0; // unc name for (i = 2; i < iLength; i++ ) { if ( 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 ( str[0] == _T('\\')) { index = 0; } // okay ... build directory do { // find next one do { if ( index < ( iLength - 1)) { index ++; } else { break; } } while ( str[index] != _T('\\')); TCHAR szCurrentDir[MAX_PATH+1]; GetCurrentDirectory( MAX_PATH+1, szCurrentDir ); if ( !SetCurrentDirectory( str.Left( index + 1 ))) { if (( fReturn = CreateDirectory( str.Left( index + 1 ), NULL )) != TRUE ) { break; } } SetCurrentDirectory( szCurrentDir ); if ( index >= ( iLength - 1 )) { fReturn = TRUE; break; } } while ( TRUE ); } while (FALSE); return(fReturn); } // // Used when the strings are passed in. // int MyMessageBox(HWND hWnd, LPCTSTR lpszTheMessage, LPCTSTR lpszTheTitle, UINT style) { int iReturn = IDOK; // make sure it goes to DebugOutput DebugOutput(_T("MyMessageBox: Title:%s, Msg:%s"), lpszTheTitle, lpszTheMessage); if (style & MB_ABORTRETRYIGNORE) { iReturn = IDIGNORE; } // Check global variable to see if we can even display the popup! if (theApp.m_bAllowMessageBoxPopups) { // Suppress the message if unattened or remove all // Who cares the user can't do anything about it anyway? // no use upsetting them, we do log to the OCM though // //if (! theApp.m_fUnattended || theApp.m_dwSetupMode != SETUPMODE_REMOVEALL) { iReturn = ::MessageBox(hWnd, lpszTheMessage, lpszTheTitle, style | MB_SETFOREGROUND); } } return iReturn; } void GetErrorMsg(int errCode, LPCTSTR szExtraMsg) { TCHAR pMsg[_MAX_PATH]; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, errCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), pMsg, _MAX_PATH, NULL); lstrcat(pMsg, szExtraMsg); MyMessageBox(NULL, pMsg, _T(""), MB_OK | MB_SETFOREGROUND); return; } DWORD GetDebugLevel(void) { DWORD rc; DWORD err; DWORD size; DWORD type; HKEY hkey; err = RegOpenKey(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\microsoft\\windows\\currentversion\\setup"), &hkey); if (err != ERROR_SUCCESS) {return 0;} size = sizeof(DWORD); err = RegQueryValueEx(hkey,_T("OC Manager Debug Level"),0,&type,(LPBYTE)&rc,&size); if (err != ERROR_SUCCESS || type != REG_DWORD) {rc = 0;} RegCloseKey(hkey); return rc; } void MyLoadString(int nID, CString &csResult) { TCHAR buf[MAX_STR_LEN]; if (LoadString(theApp.m_hDllHandle, nID, buf, MAX_STR_LEN)) csResult = buf; return; } static TCHAR six2pr[64] = { _T('A'), _T('B'), _T('C'), _T('D'), _T('E'), _T('F'), _T('G'), _T('H'), _T('I'), _T('J'), _T('K'), _T('L'), _T('M'), _T('N'), _T('O'), _T('P'), _T('Q'), _T('R'), _T('S'), _T('T'), _T('U'), _T('V'), _T('W'), _T('X'), _T('Y'), _T('Z'), _T('a'), _T('b'), _T('c'), _T('d'), _T('e'), _T('f'), _T('g'), _T('h'), _T('i'), _T('j'), _T('k'), _T('l'), _T('m'), _T('n'), _T('o'), _T('p'), _T('q'), _T('r'), _T('s'), _T('t'), _T('u'), _T('v'), _T('w'), _T('x'), _T('y'), _T('z'), _T('0'), _T('1'), _T('2'), _T('3'), _T('4'), _T('5'), _T('6'), _T('7'), _T('8'), _T('9'), _T('%'), _T('_') }; typedef void (*P_SslGenerateRandomBits)( PUCHAR pRandomData, LONG size ); P_SslGenerateRandomBits ProcSslGenerateRandomBits = NULL; int GetRandomNum() { int RandomNum; UCHAR cRandomByte; if ( ProcSslGenerateRandomBits != NULL ) { (*ProcSslGenerateRandomBits)( &cRandomByte, 1 ); RandomNum = cRandomByte; } else { RandomNum = rand(); } return(RandomNum); } 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; } void AddPath(LPTSTR szPath, LPCTSTR szName ) { LPTSTR p = szPath; ASSERT(szPath); ASSERT(szName); // Find end of the string while (*p){p = _tcsinc(p);} // If no trailing backslash then add one if (*(_tcsdec(szPath, p)) != _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; } // GetPrincipalSID is from \nt\private\inet\iis\ui\setup\osrc\dcomperm.cpp DWORD GetPrincipalSID ( LPTSTR Principal, PSID *Sid, BOOL *pbWellKnownSID ) { DebugOutput(_T("GetPrincipalSID:Principal=%s\n"), Principal); DWORD returnValue=ERROR_SUCCESS; CString csPrincipal = Principal; SID_IDENTIFIER_AUTHORITY SidIdentifierNTAuthority = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY SidIdentifierWORLDAuthority = SECURITY_WORLD_SID_AUTHORITY; PSID_IDENTIFIER_AUTHORITY pSidIdentifierAuthority; BYTE Count; DWORD dwRID[8]; *pbWellKnownSID = TRUE; memset(&(dwRID[0]), 0, 8 * sizeof(DWORD)); csPrincipal.MakeLower(); if ( csPrincipal.Find(_T("administrators")) != -1 ) { // Administrators group pSidIdentifierAuthority = &SidIdentifierNTAuthority; Count = 2; dwRID[0] = SECURITY_BUILTIN_DOMAIN_RID; dwRID[1] = DOMAIN_ALIAS_RID_ADMINS; } else if (csPrincipal.Find(_T("system")) != -1) { // SYSTEM pSidIdentifierAuthority = &SidIdentifierNTAuthority; Count = 1; dwRID[0] = SECURITY_LOCAL_SYSTEM_RID; } else if (csPrincipal.Find(_T("interactive")) != -1) { // INTERACTIVE pSidIdentifierAuthority = &SidIdentifierNTAuthority; Count = 1; dwRID[0] = SECURITY_INTERACTIVE_RID; } else if (csPrincipal.Find(_T("everyone")) != -1) { // Everyone pSidIdentifierAuthority = &SidIdentifierWORLDAuthority; Count = 1; dwRID[0] = SECURITY_WORLD_RID; } else { *pbWellKnownSID = FALSE; } if (*pbWellKnownSID) { if ( !AllocateAndInitializeSid(pSidIdentifierAuthority, (BYTE)Count, dwRID[0], dwRID[1], dwRID[2], dwRID[3], dwRID[4], dwRID[5], dwRID[6], dwRID[7], Sid) ) { returnValue = GetLastError(); } } else { // get regular account sid DWORD sidSize; TCHAR refDomain [256]; DWORD refDomainSize; SID_NAME_USE snu; sidSize = 0; refDomainSize = 255; LookupAccountName (NULL, Principal, *Sid, &sidSize, refDomain, &refDomainSize, &snu); returnValue = GetLastError(); if (returnValue == ERROR_INSUFFICIENT_BUFFER) { *Sid = (PSID) malloc (sidSize); refDomainSize = 255; if (!LookupAccountName (NULL, Principal, *Sid, &sidSize, refDomain, &refDomainSize, &snu)) { returnValue = GetLastError(); } else { returnValue = ERROR_SUCCESS; } } } return returnValue; } // SetAdminACL taken from \nt\private\inet\iis\ui\setup\osrc\helper.cpp DWORD SetAdminACL(LPCTSTR szKeyPath, DWORD dwAccessForEveryoneAccount) { DebugOutputSafe(_T("SetAdminACL(%1!s!) Start.\n"), szKeyPath); int iErr=0; DWORD dwErr=ERROR_SUCCESS; BOOL b = FALSE; DWORD dwLength = 0; PSECURITY_DESCRIPTOR pSD = NULL; PSECURITY_DESCRIPTOR outpSD = NULL; DWORD cboutpSD = 0; PACL pACLNew = NULL; DWORD cbACL = 0; PSID pAdminsSID = NULL, pEveryoneSID = NULL; BOOL bWellKnownSID = FALSE; // Initialize a new security descriptor pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (NULL == pSD) { dwErr = ERROR_NOT_ENOUGH_MEMORY; DebugOutput(_T("LocalAlloc failed")); goto Cleanup; } iErr = InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION); if (iErr == 0) { dwErr=GetLastError(); DebugOutput(_T("SetAdminACL:InitializeSecurityDescriptor FAILED. GetLastError()= 0x%x\n"), dwErr); goto Cleanup; } // Get Local Admins Sid dwErr = GetPrincipalSID (_T("Administrators"), &pAdminsSID, &bWellKnownSID); if (dwErr != ERROR_SUCCESS) { DebugOutput(_T("SetAdminACL:GetPrincipalSID(Administrators) FAILED. GetLastError()= 0x%x\n"), dwErr); goto Cleanup; } // Get everyone Sid dwErr = GetPrincipalSID (_T("Everyone"), &pEveryoneSID, &bWellKnownSID); if (dwErr != ERROR_SUCCESS) { DebugOutput(_T("SetAdminACL:GetPrincipalSID(Everyone) FAILED. GetLastError()= 0x%x\n"), dwErr); goto Cleanup; } // Initialize a new ACL, which only contains 2 aaace cbACL = sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pAdminsSID) - sizeof(DWORD)) + (sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pEveryoneSID) - sizeof(DWORD)) ; pACLNew = (PACL) LocalAlloc(LPTR, cbACL); if ( !pACLNew ) { dwErr=ERROR_NOT_ENOUGH_MEMORY; DebugOutput(_T("SetAdminACL:pACLNew LocalAlloc(LPTR, FAILED. size = %u GetLastError()= 0x%x\n"), cbACL, dwErr); goto Cleanup; } if (!InitializeAcl(pACLNew, cbACL, ACL_REVISION)) { dwErr=GetLastError(); DebugOutput(_T("SetAdminACL:InitializeAcl FAILED. GetLastError()= 0x%x\n"), dwErr); goto Cleanup; } if (!AddAccessAllowedAce(pACLNew,ACL_REVISION,(MD_ACR_READ |MD_ACR_WRITE |MD_ACR_RESTRICTED_WRITE |MD_ACR_UNSECURE_PROPS_READ |MD_ACR_ENUM_KEYS |MD_ACR_WRITE_DAC),pAdminsSID)) { dwErr=GetLastError(); DebugOutput(_T("SetAdminACL:AddAccessAllowedAce(pAdminsSID) FAILED. GetLastError()= 0x%x\n"), dwErr); goto Cleanup; } if (!AddAccessAllowedAce(pACLNew,ACL_REVISION,dwAccessForEveryoneAccount,pEveryoneSID)) { dwErr=GetLastError(); DebugOutput(_T("SetAdminACL:AddAccessAllowedAce(pEveryoneSID) FAILED. GetLastError()= 0x%x\n"), dwErr); goto Cleanup; } // Add the ACL to the security descriptor b = SetSecurityDescriptorDacl(pSD, TRUE, pACLNew, FALSE); if (!b) { dwErr=GetLastError(); DebugOutput(_T("SetAdminACL:SetSecurityDescriptorDacl(pACLNew) FAILED. GetLastError()= 0x%x\n"), dwErr); goto Cleanup; } b = SetSecurityDescriptorOwner(pSD, pAdminsSID, TRUE); if (!b) { dwErr=GetLastError(); DebugOutput(_T("SetAdminACL:SetSecurityDescriptorOwner(pAdminsSID) FAILED. GetLastError()= 0x%x\n"), dwErr); goto Cleanup; } b = SetSecurityDescriptorGroup(pSD, pAdminsSID, TRUE); if (!b) { dwErr=GetLastError(); DebugOutput(_T("SetAdminACL:SetSecurityDescriptorGroup(pAdminsSID) FAILED. GetLastError()= 0x%x\n"), dwErr); goto Cleanup; } // Security descriptor blob must be self relative b = MakeSelfRelativeSD(pSD, outpSD, &cboutpSD); if (!b && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) { dwErr=GetLastError(); DebugOutput(_T("SetAdminACL:MakeSelfRelativeSD FAILED. GetLastError()= 0x%x\n"), dwErr); goto Cleanup; } outpSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(GPTR, cboutpSD); if ( !outpSD ) { dwErr=GetLastError(); DebugOutput(_T("SetAdminACL:GlobalAlloc FAILED. cboutpSD = %u GetLastError()= 0x%x\n"), cboutpSD, dwErr); goto Cleanup; } b = MakeSelfRelativeSD( pSD, outpSD, &cboutpSD ); if (!b) { dwErr=GetLastError(); DebugOutput(_T("SetAdminACL:MakeSelfRelativeSD() FAILED. cboutpSD = %u GetLastError()= 0x%x\n"),cboutpSD, dwErr); goto Cleanup; } // Apply the new security descriptor to the metabase DebugOutput(_T("SetAdminACL:Write the new security descriptor to the Metabase. Start.")); DebugOutput(_T("SetAdminACL: At this point we have already been able to write basic entries to the metabase, so...")); DebugOutput(_T("SetAdminACL: If this fails then there is a problem with setting up encryption for the metabase (RsaBase.dll).")); dwErr = WriteSDtoMetaBase(outpSD, szKeyPath); DebugOutput(_T("SetAdminACL:Write the new security descriptor to the Metabase. End.")); Cleanup: // both of Administrators and Everyone are well-known SIDs, use FreeSid() to free them. if (outpSD){GlobalFree(outpSD);} if (pAdminsSID){FreeSid(pAdminsSID);} if (pEveryoneSID){FreeSid(pEveryoneSID);} if (pSD){LocalFree((HLOCAL) pSD);} if (pACLNew){LocalFree((HLOCAL) pACLNew);} DebugOutputSafe(_T("SetAdminACL(%1!s!) End.\n"), szKeyPath); return (dwErr); } DWORD SetAdminACL_wrap(LPCTSTR szKeyPath, DWORD dwAccessForEveryoneAccount, BOOL bDisplayMsgOnErrFlag) { int bFinishedFlag = FALSE; UINT iMsg = NULL; DWORD dwReturn = ERROR_SUCCESS; // LogHeapState(FALSE, __FILE__, __LINE__); do { dwReturn = SetAdminACL(szKeyPath, dwAccessForEveryoneAccount); // LogHeapState(FALSE, __FILE__, __LINE__); if (FAILED(dwReturn)) { // SetErrorFlag(__FILE__, __LINE__); if (bDisplayMsgOnErrFlag == TRUE) { CString msg; MyLoadString(IDS_RETRY, msg); iMsg = MyMessageBox( NULL, msg, _T(""), MB_ABORTRETRYIGNORE | MB_SETFOREGROUND ); switch ( iMsg ) { case IDIGNORE: dwReturn = ERROR_SUCCESS; goto SetAdminACL_wrap_Exit; case IDABORT: dwReturn = ERROR_OPERATION_ABORTED; goto SetAdminACL_wrap_Exit; case IDRETRY: break; default: break; } } else { // return whatever err happened goto SetAdminACL_wrap_Exit; } } else { break; } } while ( FAILED(dwReturn) ); SetAdminACL_wrap_Exit: return dwReturn; } DWORD WriteSDtoMetaBase(PSECURITY_DESCRIPTOR outpSD, LPCTSTR szKeyPath) { DebugOutput(_T("WriteSDtoMetaBase: Start")); DWORD dwReturn = E_FAIL; DWORD dwLength = 0; CMDKey cmdKey; if (!outpSD) { dwReturn = ERROR_INVALID_SECURITY_DESCR; goto WriteSDtoMetaBase_Exit; } // Apply the new security descriptor to the metabase dwLength = GetSecurityDescriptorLength(outpSD); // open the metabase // stick it into the metabase. warning those hoses a lot because // it uses encryption. rsabase.dll cmdKey.CreateNode(METADATA_MASTER_ROOT_HANDLE, szKeyPath); if ( (METADATA_HANDLE)cmdKey ) { DebugOutput(_T("WriteSDtoMetaBase:cmdKey():SetData(MD_ADMIN_ACL), dwdata = %u; outpSD = %p, Start\n"), dwLength, outpSD ); dwReturn = cmdKey.SetData(MD_ADMIN_ACL,METADATA_INHERIT | METADATA_REFERENCE | METADATA_SECURE,IIS_MD_UT_SERVER,BINARY_METADATA,dwLength,(LPBYTE)outpSD); if (FAILED(dwReturn)) { // SetErrorFlag(__FILE__, __LINE__); DebugOutput(_T("WriteSDtoMetaBase:cmdKey():SetData(MD_ADMIN_ACL), FAILED. Code=0x%x. End.\n"), dwReturn); } else { dwReturn = ERROR_SUCCESS; DebugOutput(_T("WriteSDtoMetaBase:cmdKey():SetData(MD_ADMIN_ACL), Success. End.\n")); } cmdKey.Close(); } else { dwReturn = E_FAIL; } WriteSDtoMetaBase_Exit: DebugOutput(_T("WriteSDtoMetaBase: End. Return=0x%x"), dwReturn); return dwReturn; } void SetupSetStringId_Wrapper(HINF hInf) { // Note, we only care about the intel variants since they're the only ones // special cased in the .INFs // Not anymore, we handles the [SourceDisksName] section as well SYSTEM_INFO SystemInfo; GetSystemInfo( &SystemInfo ); TCHAR szSourceCatOSName[20]; _tcscpy(szSourceCatOSName, _T("\\i386")); switch(SystemInfo.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_AMD64: _tcscpy(szSourceCatOSName, _T("\\AMD64")); break; case PROCESSOR_ARCHITECTURE_IA64: _tcscpy(szSourceCatOSName, _T("\\IA64")); break; case PROCESSOR_ARCHITECTURE_INTEL: if (IsNEC_98) { _tcscpy(szSourceCatOSName, _T("\\Nec98")); } break; default: break; } // 34000 is no longer used //SetupSetDirectoryIdEx(hInf, 34000, szSourceCatOSName, SETDIRID_NOT_FULL_PATH, 0, 0); SetupSetDirectoryIdEx(hInf, 34001, szSourceCatOSName, SETDIRID_NOT_FULL_PATH, 0, 0); }