/****************************************************************************** * * Copyright (c) 2000 Microsoft Corporation * * Module Name: * utils.cpp * * Abstract: * Definitions of commonly used util functions. * * Revision History: * Brijesh Krishnaswami (brijeshk) 03/17/2000 * created * *****************************************************************************/ #include #include #include #include #include #include "srdefs.h" #include "utils.h" #include #include #include #include #include #include #include #include #include "srapi.h" #ifdef THIS_FILE #undef THIS_FILE #endif static char __szTraceSourceFile[] = __FILE__; #define THIS_FILE __szTraceSourceFile #define WBEM_DIRECTORY L"wbem" #define FRAMEDYN_DLL L"framedyn.dll" // forward declaration for Delnode_Recurse BOOL SRGetAltFileName( LPCWSTR cszPath, LPWSTR szAltName ); #define TRACEID 1893 // this function converts an ANSI string to UNICODE. // this also allocates the memory for the new string WCHAR * ConvertToUnicode(CHAR * pszString) { WCHAR * pwszUnicodeString = NULL; DWORD dwBytesNeeded = 0; TENTER("ConvertToUnicode"); dwBytesNeeded = (lstrlenA(pszString) + 1) * sizeof(WCHAR); pwszUnicodeString = (PWCHAR) SRMemAlloc(dwBytesNeeded); if(NULL == pwszUnicodeString) { TRACE(0, "Not enough memory"); goto cleanup; } // Convert filename to Unicode if (!MultiByteToWideChar(CP_ACP, // code page 0, // no options pszString, // ANSI string -1, // NULL terminated string pwszUnicodeString, // output buffer dwBytesNeeded/sizeof(WCHAR))) // size in wide chars { DWORD dwReturnCode; dwReturnCode=GetLastError(); TRACE(0, "Failed to do conversion ec=%d", dwReturnCode); SRMemFree(pwszUnicodeString); goto cleanup; } cleanup: TLEAVE(); return pwszUnicodeString; } // this function converts a UNICODE string to ANSI. // this also allocates the memory for the new string CHAR * ConvertToANSI(WCHAR * pwszString) { CHAR * pszANSIString = NULL; DWORD dwBytesNeeded = lstrlenW(pwszString) + sizeof(char); TENTER("ConvertToANSI"); // note that the string may already be NULL terminated - however // we cannot assume this and will still allocate space to put a // NULL character in the end. pszANSIString = (PCHAR) SRMemAlloc(dwBytesNeeded); if(NULL == pszANSIString) { TRACE(0, "Not enough memory"); goto cleanup; } // Convert filename to Unicode if (!WideCharToMultiByte(CP_ACP, // code page 0, // no options pwszString, // Wide char string dwBytesNeeded, // no of wchars pszANSIString, // output buffer dwBytesNeeded, // size of buffer NULL, // address of default for unmappable // characters NULL)) // address of flag set when default // char. used { DWORD dwReturnCode; dwReturnCode=GetLastError(); TRACE(0, "Failed to do conversion ec=%d", dwReturnCode); SRMemFree(pszANSIString); //this sets pwszUnicodeString to NULL goto cleanup; } // set last char to NULL pszANSIString[dwBytesNeeded-1] = '\0'; cleanup: TraceFunctLeave(); return pszANSIString; } //+--------------------------------------------------------------------------- // // Function: TakeOwn // // Synopsis: attempts to take ACL ownership of the file for deletion // // Arguments: [pwszFile] -- file name // // Returns: Win32 error code // // History: 12-Apr-2000 HenryLee Created // //---------------------------------------------------------------------------- DWORD TakeOwn (const WCHAR *pwszFile) { SID * pSid = NULL; DWORD dwErr = ERROR_SUCCESS; SECURITY_DESCRIPTOR sd; InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION ); if (FALSE == SetSecurityDescriptorDacl (&sd, TRUE, NULL, FALSE )) { dwErr = GetLastError(); goto Err; } if (FALSE == SetFileSecurity (pwszFile, DACL_SECURITY_INFORMATION, &sd)) { dwErr = GetLastError(); goto Err; } // Okay, that didn't work, try to make Administrator the owner if (dwErr != ERROR_SUCCESS) { SID_IDENTIFIER_AUTHORITY SepNtAuthority = SECURITY_NT_AUTHORITY; if (FALSE == AllocateAndInitializeSid( &SepNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, (void **) &pSid )) { dwErr = GetLastError(); goto Err; } if (FALSE == SetSecurityDescriptorOwner (&sd, pSid, FALSE )) { dwErr = GetLastError(); goto Err; } if (FALSE == SetFileSecurity(pwszFile, OWNER_SECURITY_INFORMATION, &sd)) { dwErr = GetLastError(); goto Err; } } Err: if (pSid != NULL) FreeSid (pSid); return dwErr; } //+--------------------------------------------------------------------------- // // Function: CopyFile_Recurse // // Synopsis: attempt to copy disk space used by a file tree // // Arguments: [pwszSource] -- directory name // [pwszDest] -- destination directory name // // Returns: Win32 error code // // History: 12-Apr-2000 HenryLee Created // //---------------------------------------------------------------------------- DWORD CopyFile_Recurse (const WCHAR *pwszSource, const WCHAR *pwszDest) { DWORD dwErr = ERROR_SUCCESS; WIN32_FIND_DATA fd; HANDLE hFile; WCHAR wcsPath[MAX_PATH]; WCHAR wcsDest2[MAX_PATH]; if (lstrlenW(pwszSource) + 4 >= MAX_PATH) return ERROR_SUCCESS; lstrcpy (wcsPath, pwszSource); lstrcat (wcsPath, TEXT("\\*.*")); hFile = FindFirstFile(wcsPath, &fd); if (hFile == INVALID_HANDLE_VALUE) { dwErr = GetLastError(); return dwErr; } do { if (!lstrcmp(fd.cFileName, L".") || !lstrcmp(fd.cFileName, L"..")) { continue; } if (lstrlenW(pwszSource) + lstrlenW(fd.cFileName) + 1 >= MAX_PATH || lstrlenW(pwszDest) + lstrlenW(fd.cFileName) + 1 >= MAX_PATH) continue; // skip files with long paths lstrcpy (wcsPath, pwszSource); // construct the full path name lstrcat (wcsPath, TEXT("\\")); lstrcat (wcsPath, fd.cFileName); lstrcpy (wcsDest2, pwszDest); // construct the full path name lstrcat (wcsDest2, TEXT("\\")); lstrcat (wcsDest2, fd.cFileName); if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (FALSE == CreateDirectoryW (wcsDest2, NULL)) { dwErr = GetLastError(); if (dwErr != ERROR_ALREADY_EXISTS) { FindClose (hFile); return dwErr; } else dwErr = ERROR_SUCCESS; } dwErr = CopyFile_Recurse (wcsPath, wcsDest2); if (dwErr != ERROR_SUCCESS) { FindClose (hFile); return dwErr; } } else { // // We found a file. Copy it. // if (FALSE == CopyFileW (wcsPath, wcsDest2, FALSE)) { dwErr = GetLastError(); FindClose (hFile); return dwErr; } } } while (FindNextFile(hFile, &fd)); // Find the next entry FindClose(hFile); // Close the search handle return ERROR_SUCCESS; } //+--------------------------------------------------------------------------- // // Function: GetFileSize_Recurse // // Synopsis: attempt to count disk space used by a file tree // // Arguments: [pwszDir] -- directory name // [pllTotalBytes] -- output counter // [pfStop] -- TRUE if stop signalled // // Returns: Win32 error code // // History: 12-Apr-2000 HenryLee Created // //---------------------------------------------------------------------------- DWORD GetFileSize_Recurse (const WCHAR *pwszDir, INT64 *pllTotalBytes, BOOL *pfStop) { DWORD dwErr = ERROR_SUCCESS; WIN32_FIND_DATA fd; HANDLE hFile; WCHAR wcsPath[MAX_PATH]; if (lstrlenW(pwszDir) + 4 >= MAX_PATH) // skip paths too long return ERROR_SUCCESS; lstrcpy (wcsPath, pwszDir); lstrcat (wcsPath, TEXT("\\*.*")); hFile = FindFirstFile(wcsPath, &fd); if (hFile == INVALID_HANDLE_VALUE) { dwErr = GetLastError(); return dwErr; } do { if (pfStop != NULL && TRUE == *pfStop) { FindClose (hFile); return ERROR_OPERATION_ABORTED; } if (!lstrcmp(fd.cFileName, L".") || !lstrcmp(fd.cFileName, L"..")) { continue; } if (lstrlenW(pwszDir) + lstrlenW(fd.cFileName) + 1 >= MAX_PATH) continue; // skip files too long lstrcpy (wcsPath, pwszDir); // construct the full path name lstrcat (wcsPath, TEXT("\\")); lstrcat (wcsPath, fd.cFileName); if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // // Found a directory. Skip mount points // if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { continue; } dwErr = GetFileSize_Recurse(wcsPath, pllTotalBytes, pfStop); if (dwErr != ERROR_SUCCESS) { FindClose(hFile); return dwErr; } } else { // // We found a file. Update the counter // ULARGE_INTEGER ulTemp; ulTemp.LowPart = fd.nFileSizeLow; ulTemp.HighPart = fd.nFileSizeHigh; #if 0 ulTemp.LowPart = GetCompressedFileSize (wcsPath, &ulTemp.HighPart); dwErr = (ulTemp.LowPart == 0xFFFFFFFF) ? GetLastError() : ERROR_SUCCESS; if (dwErr != ERROR_SUCCESS) { FindClose (hFile); return dwErr; } #endif *pllTotalBytes += ulTemp.QuadPart; // The file size does not contain the size of the // NTFS alternate data streams } } while (FindNextFile(hFile, &fd)); // Find the next entry FindClose(hFile); // Close the search handle return ERROR_SUCCESS; } //+--------------------------------------------------------------------------- // // Function: CompressFile // // Synopsis: attempt to compress to decompress an NTFS file // // Arguments: [pwszPath] -- directory or file name // [fCompress] -- TRUE compress, FALSE decompress // [fDirectory] -- TRUE if directory, FALSE if file // // Returns: Win32 error code // // History: 12-Apr-2000 HenryLee Created // //---------------------------------------------------------------------------- DWORD CompressFile (const WCHAR *pwszPath, BOOL fCompress, BOOL fDirectory) { DWORD dwErr = ERROR_SUCCESS; DWORD dwReturned = 0; TENTER("CompressFile"); if (pwszPath == NULL) return ERROR_INVALID_PARAMETER; DWORD dwFileAttr = GetFileAttributes(pwszPath); if (dwFileAttr != 0xFFFFFFFF && (dwFileAttr & FILE_ATTRIBUTE_READONLY)) { dwFileAttr &= ~FILE_ATTRIBUTE_READONLY; if (FALSE == SetFileAttributes (pwszPath, dwFileAttr)) { TRACE(0, "SetFileAttributes ignoring %ld", GetLastError()); } else dwFileAttr |= FILE_ATTRIBUTE_READONLY; } USHORT usFormat = fCompress ? COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT_NONE; HANDLE hFile = CreateFile( pwszPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, fDirectory ? FILE_FLAG_BACKUP_SEMANTICS : 0, NULL ); if (hFile == INVALID_HANDLE_VALUE) { dwErr = GetLastError(); TRACE(0, "CompressFile: cannot open %ld %ws", dwErr, pwszPath); return dwErr; } if (FALSE == DeviceIoControl (hFile, FSCTL_SET_COMPRESSION, &usFormat, sizeof(usFormat), NULL, 0, &dwReturned, NULL)) { dwErr = GetLastError(); TRACE(0, "CompressFile: cannot compress/uncompress %ld %ws", dwErr, pwszPath); } CloseHandle (hFile); if (dwFileAttr != 0xFFFFFFFF && (dwFileAttr & FILE_ATTRIBUTE_READONLY)) { if (FALSE == SetFileAttributes (pwszPath, dwFileAttr)) { TRACE(0, "SetFileAttributes failed ignoring %ld", GetLastError()); } } TLEAVE(); return dwErr; } // returns system drive - as L"C:\\" if C: is the system drive BOOL GetSystemDrive(LPWSTR pszDrive) { if (pszDrive) return ExpandEnvironmentStrings(L"%SystemDrive%\\", pszDrive, MAX_SYS_DRIVE); else return FALSE; } // BUGBUG - pszDrive should have driveletter in caps, // and needs to be of format L"C:\\" if C: is the system drive BOOL IsSystemDrive(LPWSTR pszDriveOrGuid) { WCHAR szSystemDrive[MAX_PATH]; WCHAR szSystemGuid[MAX_PATH]; if (pszDriveOrGuid) { if (0 == ExpandEnvironmentStrings(L"%SystemDrive%\\", szSystemDrive, sizeof(szSystemDrive)/sizeof(WCHAR))) { return FALSE; } if (0 == wcsncmp(pszDriveOrGuid, L"\\\\?\\Volume", 10)) // guid { if (! GetVolumeNameForVolumeMountPoint(szSystemDrive, szSystemGuid, MAX_PATH)) { return FALSE; } return lstrcmpi(pszDriveOrGuid, szSystemGuid) ? FALSE : TRUE; } else // drive { return lstrcmpi(pszDriveOrGuid, szSystemDrive) ? FALSE : TRUE; } } else { return FALSE; } } DWORD RegReadDWORD(HKEY hKey, LPCWSTR pszName, PDWORD pdwValue) { DWORD dwType = REG_DWORD; DWORD dwSize = sizeof(DWORD); DWORD dwRc = RegQueryValueEx(hKey, pszName, 0, &dwType, (LPBYTE) pdwValue, &dwSize); return dwRc; } DWORD RegWriteDWORD(HKEY hKey, LPCWSTR pszName, PDWORD pdwValue) { DWORD dwType = REG_DWORD; DWORD dwSize = sizeof(DWORD); DWORD dwRc = RegSetValueEx(hKey, pszName, 0, dwType, (LPBYTE) pdwValue, dwSize); return dwRc; } // function that returns n where pszStr is of form n ULONG GetID( LPCWSTR pszStr) { ULONG ulID = 0; while (*pszStr && (*pszStr < L'0' || *pszStr > L'9')) pszStr++; ulID = (ULONG) _wtol(pszStr); return ulID; } LPWSTR GetMachineGuid() { HKEY hKey = NULL; static WCHAR s_szGuid[GUID_STRLEN] = L""; static LPWSTR s_pszGuid = NULL; if (! s_pszGuid) // first time { ULONG ulType, ulSize = sizeof(s_szGuid); DWORD dwErr; dwErr = RegOpenKeyEx (HKEY_LOCAL_MACHINE, s_cszSRCfgRegKey, 0, KEY_READ, &hKey); if (dwErr != ERROR_SUCCESS) goto Err; dwErr = RegQueryValueEx (hKey, s_cszSRMachineGuid, 0, &ulType, (BYTE *) &s_szGuid, &ulSize); if (dwErr != ERROR_SUCCESS) goto Err; s_pszGuid = (LPWSTR) s_szGuid; } Err: if (hKey) RegCloseKey(hKey); return s_pszGuid; } // util function to construct _Restore.{MachineGuid}\\pszSuffix LPWSTR MakeRestorePath(LPWSTR pszDest, LPCWSTR pszDrive, LPCWSTR pszSuffix) { LPWSTR pszGuid = GetMachineGuid(); wsprintf(pszDest, L"%s%s\\%s", pszDrive, s_cszSysVolInfo, s_cszRestoreDir); if (pszGuid) { // lstrcat(pszDest, L"."); lstrcat(pszDest, pszGuid); } if (pszSuffix && lstrlen(pszSuffix) > 0) { lstrcat(pszDest, L"\\"); lstrcat(pszDest, pszSuffix); } return pszDest; } // set start type of specified service directly in the registry DWORD SetServiceStartupRegistry(LPCWSTR pszName, DWORD dwStartType) { DWORD dwRc; HKEY hKey = NULL; WCHAR szKey[MAX_PATH]; lstrcpy(szKey, L"System\\CurrentControlSet\\Services\\"); lstrcat(szKey, pszName); dwRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, KEY_WRITE, NULL, &hKey); if (ERROR_SUCCESS != dwRc) goto done; dwRc = RegWriteDWORD(hKey, L"Start", &dwStartType); done: if (hKey) RegCloseKey(hKey); return dwRc; } // get start type of specified service directly from the registry DWORD GetServiceStartupRegistry(LPCWSTR pszName, PDWORD pdwStartType) { DWORD dwRc; HKEY hKey = NULL; WCHAR szKey[MAX_PATH]; lstrcpy(szKey, L"System\\CurrentControlSet\\Services\\"); lstrcat(szKey, pszName); dwRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, KEY_QUERY_VALUE, NULL, &hKey); if (ERROR_SUCCESS != dwRc) goto done; dwRc = RegReadDWORD(hKey, L"Start", pdwStartType); done: if (hKey) RegCloseKey(hKey); return dwRc; } DWORD SetServiceStartup(LPCWSTR pszName, DWORD dwStartType) { TraceFunctEnter("SetServiceStartup"); DWORD dwError=ERROR_INTERNAL_ERROR; SC_HANDLE hService=NULL; SC_HANDLE hSCManager=NULL; hSCManager = OpenSCManager(NULL, // computer name - local machine NULL,//SCM DB name - SERVICES_ACTIVE_DATABASE SC_MANAGER_ALL_ACCESS); // access type if( NULL == hSCManager) { dwError = GetLastError(); // file not found DebugTrace(TRACEID,"OpenSCManager failed 0x%x", dwError); goto done; } hService = OpenService(hSCManager, // handle to SCM database pszName, // service name SERVICE_CHANGE_CONFIG); // access if( NULL == hService) { dwError = GetLastError(); // file not found DebugTrace(TRACEID,"OpenService failed 0x%x", dwError); goto done; } if (FALSE==ChangeServiceConfig( hService, // handle to service SERVICE_NO_CHANGE, // type of service dwStartType, // when to start service SERVICE_NO_CHANGE, // severity of start failure NULL, // service binary file name NULL, // load ordering group name NULL, // tag identifier NULL, // array of dependency names NULL, // account name NULL, // account password NULL)) // display name { dwError = GetLastError(); // file not found DebugTrace(TRACEID,"ChangeServiceConfig failed 0x%x", dwError); goto done; } dwError = ERROR_SUCCESS; done: if (NULL != hService) { _VERIFY(CloseServiceHandle(hService)); // handle to service or // SCM object } if (NULL != hSCManager) { _VERIFY(CloseServiceHandle(hSCManager)); // handle to service or // SCM object } if ((dwError != ERROR_SUCCESS) && (dwError != ERROR_ACCESS_DENIED)) { // service control methods failed. Just update the registry // directly dwError = SetServiceStartupRegistry(pszName, dwStartType); } TraceFunctLeave(); return dwError; } DWORD GetServiceStartup(LPCWSTR pszName, PDWORD pdwStartType) { TraceFunctEnter("SetServiceStartup"); DWORD dwError=ERROR_INTERNAL_ERROR; SC_HANDLE hService=NULL; SC_HANDLE hSCManager=NULL; QUERY_SERVICE_CONFIG *pconfig = NULL; DWORD cbBytes = 0, cbBytes2 = 0; hSCManager = OpenSCManager(NULL, // computer name - local machine NULL,//SCM DB name - SERVICES_ACTIVE_DATABASE SC_MANAGER_ALL_ACCESS); // access type if( NULL == hSCManager) { dwError = GetLastError(); // file not found DebugTrace(TRACEID,"OpenSCManager failed 0x%x", dwError); goto done; } hService = OpenService(hSCManager, // handle to SCM database pszName, // service name SERVICE_QUERY_CONFIG); // access if( NULL == hService) { dwError = GetLastError(); // file not found DebugTrace(TRACEID,"OpenService failed 0x%x", dwError); goto done; } if (FALSE==QueryServiceConfig( hService, // handle to service NULL, 0, &cbBytes )) { dwError = GetLastError(); if (ERROR_INSUFFICIENT_BUFFER == dwError) { pconfig = (QUERY_SERVICE_CONFIG *) SRMemAlloc(cbBytes); if (!pconfig) { trace(TRACEID, "! SRMemAlloc"); goto done; } if (FALSE==QueryServiceConfig( hService, // handle to service pconfig, cbBytes, &cbBytes2 )) { dwError = GetLastError(); DebugTrace(TRACEID,"! QueryServiceConfig (second) : %ld", dwError); goto done; } if (pdwStartType) { *pdwStartType = pconfig->dwStartType; } dwError = ERROR_SUCCESS; } else { trace(TRACEID, "! QueryServiceConfig (first) : %ld", dwError); } } done: SRMemFree(pconfig); if (NULL != hService) { _VERIFY(CloseServiceHandle(hService)); // handle to service or // SCM object } if (NULL != hSCManager) { _VERIFY(CloseServiceHandle(hSCManager)); // handle to service or // SCM object } TraceFunctLeave(); return dwError; } // this function returns whether the SR service is running BOOL IsSRServiceRunning() { TraceFunctEnter("IsSRServiceRunning"); BOOL fReturn; DWORD dwError=ERROR_INTERNAL_ERROR; SC_HANDLE hService=NULL; SC_HANDLE hSCManager=NULL; SERVICE_STATUS ServiceStatus; // assume FALSE by default fReturn = FALSE; hSCManager = OpenSCManager(NULL, // computer name - local machine NULL,//SCM DB name - SERVICES_ACTIVE_DATABASE SC_MANAGER_ALL_ACCESS); // access type if( NULL == hSCManager) { dwError = GetLastError(); DebugTrace(TRACEID,"OpenSCManager failed 0x%x", dwError); goto done; } hService = OpenService(hSCManager, // handle to SCM database s_cszServiceName, // service name SERVICE_QUERY_STATUS); // access if( NULL == hService) { dwError = GetLastError(); DebugTrace(TRACEID,"OpenService failed 0x%x", dwError); goto done; } if (FALSE == QueryServiceStatus(hService, // handle to service &ServiceStatus)) // service status { dwError = GetLastError(); DebugTrace(TRACEID,"QueryServiceStatus failed 0x%x", dwError); goto done; } if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) { fReturn = TRUE; } else { DebugTrace(TRACEID,"SR Service is not running"); fReturn = FALSE; } done: if (NULL != hService) { _VERIFY(CloseServiceHandle(hService)); // handle to service or // SCM object } if (NULL != hSCManager) { _VERIFY(CloseServiceHandle(hSCManager)); // handle to service or // SCM object } TraceFunctLeave(); return fReturn; } // this function returns whether the SR service is running BOOL IsSRServiceStopped(SC_HANDLE hService) { TraceFunctEnter("IsSRServiceStopped"); SERVICE_STATUS ServiceStatus; BOOL fReturn; DWORD dwError; // assume FALSE by default fReturn = FALSE; if (FALSE == QueryServiceStatus(hService, // handle to service &ServiceStatus)) // service status { dwError = GetLastError(); DebugTrace(TRACEID,"QueryServiceStatus failed 0x%x", dwError); goto done; } if (ServiceStatus.dwCurrentState == SERVICE_STOPPED) { DebugTrace(TRACEID,"SR Service is not running"); fReturn = TRUE; } else { DebugTrace(TRACEID,"SR Service is running"); fReturn = FALSE; } done: TraceFunctLeave(); return fReturn; } // private function to stop the SR service // fWait - if TRUE : function is synchronous - waits till service is stopped completely // if FALSE : function is asynchronous - does not wait for service to complete stopping BOOL StopSRService(BOOL fWait) { TraceFunctEnter("StopSRService"); BOOL fReturn=FALSE; SC_HANDLE hSCManager; SERVICE_STATUS ServiceStatus; SC_HANDLE hService=NULL; DWORD dwError; hSCManager = OpenSCManager(NULL, // computer name - local machine NULL,//SCM DB name - SERVICES_ACTIVE_DATABASE SC_MANAGER_ALL_ACCESS); // access type if (NULL == hSCManager) { dwError = GetLastError(); DebugTrace(TRACEID,"OpenSCManager failed 0x%x", dwError); goto done; } hService = OpenService(hSCManager, // handle to SCM database s_cszServiceName, // service name SERVICE_ALL_ACCESS); // access if( NULL == hService) { dwError = GetLastError(); DebugTrace(TRACEID,"OpenService failed 0x%x", dwError); goto done; } fReturn = ControlService(hService, // handle to service SERVICE_CONTROL_STOP, // control code &ServiceStatus); // status information if (FALSE == fReturn) { dwError = GetLastError(); DebugTrace(TRACEID,"ControlService failed 0x%x", dwError); goto done; } if (fWait) { DWORD dwCount; // // query the service until it stops // try thrice // Sleep(500); for (dwCount=0; dwCount < 3; dwCount++) { if (TRUE == IsSRServiceStopped(hService)) { break; } Sleep(2000); } if (dwCount == 3) { fReturn=IsSRServiceStopped(hService); } else { fReturn=TRUE; } } done: if (NULL != hService) { _VERIFY(CloseServiceHandle(hService)); // handle to service or // SCM object } if (NULL != hSCManager) { _VERIFY(CloseServiceHandle(hSCManager)); // handle to service or // SCM object } TraceFunctLeave(); return fReturn; } //+--------------------------------------------------------------------------- // // Function: GetLsaSecret // // Synopsis: obtains the LSA secret info as Unicode strings // // Arguments: [hPolicy] -- LSA policy object handle // [wszSecret] -- secret name // [ppusSecretValue] -- dynamically allocated value // // Returns: Win32 error code // // History: 12-Apr-2000 HenryLee Created // //---------------------------------------------------------------------------- DWORD GetLsaSecret (LSA_HANDLE hPolicy, const WCHAR *wszSecret, UNICODE_STRING ** ppusSecretValue) { TENTER ("GetLsaSecret"); LSA_HANDLE hSecret; UNICODE_STRING usSecretName; DWORD dwErr = ERROR_SUCCESS; RtlInitUnicodeString (&usSecretName, wszSecret); if (LSA_SUCCESS (LsaOpenSecret (hPolicy, &usSecretName, SECRET_QUERY_VALUE, &hSecret))) { if (!LSA_SUCCESS (LsaQuerySecret (hSecret, ppusSecretValue, NULL, NULL, NULL))) { *ppusSecretValue = NULL; TRACE(0, "Cannot query secret %ws", wszSecret); } LsaClose (hSecret); } TLEAVE(); return dwErr; } //+--------------------------------------------------------------------------- // // Function: SetLsaSecret // // Synopsis: sets the LSA secret info // // Arguments: [hPolicy] -- LSA policy object handle // [wszSecret] -- secret name // [wszSecretValue] -- secret value // // Returns: Win32 error code // // History: 12-Apr-2000 HenryLee Created // //---------------------------------------------------------------------------- DWORD SetLsaSecret (PVOID hPolicy, const WCHAR *wszSecret, WCHAR * wszSecretValue) { TENTER ("SetLsaSecret"); LSA_HANDLE hSecret; UNICODE_STRING usSecretName; UNICODE_STRING usSecretValue; DWORD dwErr = ERROR_SUCCESS; hPolicy = (LSA_HANDLE) hPolicy; RtlInitUnicodeString (&usSecretName, wszSecret); RtlInitUnicodeString (&usSecretValue, wszSecretValue); if (LSA_SUCCESS (LsaOpenSecret (hPolicy, &usSecretName, SECRET_SET_VALUE, &hSecret))) { if (!LSA_SUCCESS (LsaSetSecret (hSecret, &usSecretValue, NULL))) { TRACE(0, "Cannot set secret %ws", wszSecret); } LsaClose (hSecret); } TLEAVE(); return dwErr; } //+--------------------------------------------------------------------------- // // Function: WriteNtUnicodeString // // Synopsis: writes a NT unicode string to disk // // Arguments: [hFile] -- file handle // [pus] -- NT unicode string // // Returns: Win32 error code // // History: 12-Apr-2000 HenryLee Created // //---------------------------------------------------------------------------- DWORD WriteNtUnicodeString (HANDLE hFile, UNICODE_STRING *pus) { DWORD dwErr = ERROR_SUCCESS; DWORD cb = 0; if (pus != NULL && FALSE == WriteFile (hFile, (BYTE *)pus->Buffer, pus->Length, &cb, NULL)) { dwErr = GetLastError(); } else if (FALSE == WriteFile (hFile, (BYTE *) L"", sizeof(WCHAR), &cb, NULL)) { dwErr = GetLastError(); } return dwErr; } //+--------------------------------------------------------------------------- // // Function: GetLsaRestoreState // // Synopsis: gets the LSA machine and autologon password // // Arguments: [hKeySoftware] -- Software registry key // // Returns: Win32 error code // // History: 12-Apr-2000 HenryLee Created // //---------------------------------------------------------------------------- DWORD GetLsaRestoreState (HKEY hKeySoftware) { TENTER ("GetLsaRestoreState"); HKEY hKey = NULL; LSA_OBJECT_ATTRIBUTES loa; LSA_HANDLE hLsa = NULL; DWORD dwErr = ERROR_SUCCESS; loa.Length = sizeof(LSA_OBJECT_ATTRIBUTES); loa.RootDirectory = NULL; loa.ObjectName = NULL; loa.Attributes = 0; loa.SecurityDescriptor = NULL; loa.SecurityQualityOfService = NULL; if (LSA_SUCCESS (LsaOpenPolicy(NULL, &loa, POLICY_VIEW_LOCAL_INFORMATION, &hLsa))) { UNICODE_STRING * pusSecret = NULL; dwErr = RegOpenKeyEx (hKeySoftware, hKeySoftware == HKEY_LOCAL_MACHINE ? s_cszSRRegKey : L"Microsoft\\Windows NT\\CurrentVersion\\SystemRestore", 0, KEY_READ | KEY_WRITE, &hKey); if (dwErr != ERROR_SUCCESS) goto Err; if (ERROR_SUCCESS==GetLsaSecret (hLsa, s_cszMachineSecret, &pusSecret)) { if (pusSecret != NULL && pusSecret->Length > 0) dwErr = RegSetValueEx (hKey, s_cszMachineSecret, 0, REG_BINARY, (BYTE *) pusSecret->Buffer, pusSecret->Length); LsaFreeMemory (pusSecret); pusSecret = NULL; } if (ERROR_SUCCESS==GetLsaSecret(hLsa, s_cszAutologonSecret, &pusSecret)) { if (pusSecret != NULL && pusSecret->Length > 0) dwErr = RegSetValueEx (hKey, s_cszAutologonSecret, 0, REG_BINARY, (BYTE *) pusSecret->Buffer, pusSecret->Length); LsaFreeMemory (pusSecret); pusSecret = NULL; } } Err: if (hLsa != NULL) LsaClose (hLsa); if (hKey != NULL) RegCloseKey (hKey); TLEAVE(); return dwErr; } //+--------------------------------------------------------------------------- // // Function: GetDomainMembershipInfo // // Synopsis: writes current domain and computer name into a file // // Arguments: [pwszPath] -- file name // [pwszzBuffer] -- output multistring buffer // // Returns: Win32 error code // // History: 12-Apr-2000 HenryLee Created // //---------------------------------------------------------------------------- DWORD GetDomainMembershipInfo (WCHAR *pwszPath, WCHAR *pwszzBuffer) { TENTER("GetDomainMembershipInfo"); POLICY_PRIMARY_DOMAIN_INFO* ppdi = NULL; LSA_OBJECT_ATTRIBUTES loa; LSA_HANDLE hLsa = NULL; HANDLE hFile = INVALID_HANDLE_VALUE; DWORD dwComputerLength = MAX_COMPUTERNAME_LENGTH + 1; DWORD dwRc = ERROR_SUCCESS; ULONG cbWritten; WCHAR wszComputer[MAX_COMPUTERNAME_LENGTH+1]; loa.Length = sizeof(LSA_OBJECT_ATTRIBUTES); loa.RootDirectory = NULL; loa.ObjectName = NULL; loa.Attributes = 0; loa.SecurityDescriptor = NULL; loa.SecurityQualityOfService = NULL; if (FALSE == GetComputerNameW (wszComputer, &dwComputerLength)) { dwRc = GetLastError(); trace(0, "! GetComputerNameW : %ld", dwRc); return dwRc; } if (LSA_SUCCESS (LsaOpenPolicy(NULL, &loa, POLICY_VIEW_LOCAL_INFORMATION, &hLsa))) { if (pwszPath != NULL) { hFile = CreateFileW ( pwszPath, // file name GENERIC_WRITE, // file access 0, // share mode NULL, // SD CREATE_ALWAYS, // how to create 0, // file attributes NULL); // handle to template file if (INVALID_HANDLE_VALUE == hFile) { dwRc = GetLastError(); trace(0, "! CreateFileW : %ld", dwRc); goto Err; } if (FALSE == WriteFile (hFile, (BYTE *) wszComputer, (dwComputerLength+1)*sizeof(WCHAR), &cbWritten, NULL)) { dwRc = GetLastError(); trace(0, "! WriteFile : %ld", dwRc); goto Err; } } if (pwszzBuffer != NULL) { lstrcpy (pwszzBuffer, wszComputer); pwszzBuffer += dwComputerLength + 1; } if (LSA_SUCCESS (LsaQueryInformationPolicy( hLsa, PolicyPrimaryDomainInformation, (VOID **) &ppdi ))) { const WCHAR *pwszFlag = (ppdi->Sid > 0) ? L"1" : L"0"; if (pwszPath != NULL) { dwRc = WriteNtUnicodeString (hFile, &ppdi->Name); if (dwRc != ERROR_SUCCESS) { trace(0, "! WriteNtUnicodeString : %ld", dwRc); } if (FALSE == WriteFile (hFile, (BYTE *) pwszFlag, (lstrlenW(pwszFlag)+1)*sizeof(WCHAR), &cbWritten, NULL)) { dwRc = GetLastError(); trace(0, "! WriteFile : %ld", dwRc); goto Err; } } if (pwszzBuffer != NULL) { ULONG ul = ppdi->Name.Length / sizeof(WCHAR); memcpy (pwszzBuffer, ppdi->Name.Buffer, ppdi->Name.Length); pwszzBuffer [ul] = L'\0'; lstrcpy (&pwszzBuffer[ul+1], pwszFlag); } } } Err: if (hLsa != NULL) LsaClose (hLsa); if (hFile != INVALID_HANDLE_VALUE) CloseHandle (hFile); TLEAVE(); return dwRc; } //++ // // Method: DoesFileExist // // Synopsis: Checks if a file by the specified exists // // Arguments:[pszFileName] File name // // Returns: TRUE if the specified string is a file // False otherwise // // History: AshishS Created 7/30/96 // //-- BOOL DoesFileExist(const TCHAR * pszFileName) { DWORD dwFileAttr, dwError; TraceFunctEnter("DoesFileExist"); DebugTrace(TRACEID, "Checking for %S", pszFileName); dwFileAttr = GetFileAttributes(pszFileName); if (dwFileAttr == 0xFFFFFFFF ) { dwError = GetLastError(); // file not found DebugTrace(TRACEID,"GetFileAttributes failed 0x%x", dwError); TraceFunctLeave(); return FALSE ; } if (dwFileAttr & FILE_ATTRIBUTE_DIRECTORY) { DebugTrace(TRACEID, "It is a Directory "); TraceFunctLeave(); return FALSE; } DebugTrace(TRACEID, "File exists"); TraceFunctLeave(); return TRUE; } //++ // // Method: DoesDirExist // // Synopsis: Checks if the specified string is a directory // // Arguments: [pszFileName] Directory name // // Returns: TRUE if the specified string is a directory, // False otherwise // // History: AshishS Created 7/30/96 // //-- BOOL DoesDirExist(const TCHAR * pszFileName ) { DWORD dwFileAttr; TraceFunctEnter("DoesDirExist"); //DebugTrace(TRACEID, " Checking for %S", pszFileName); dwFileAttr = GetFileAttributes(pszFileName); if (dwFileAttr == 0xFFFFFFFF ) { // file not found //DebugTrace(TRACEID,"GetFileAttributes failed 0x%x", //GetLastError()); TraceFunctLeave(); return FALSE ; } if (dwFileAttr & FILE_ATTRIBUTE_DIRECTORY) { //DebugTrace(TRACEID, "Directory exists "); TraceFunctLeave(); return TRUE ; } //DebugTrace(TRACEID, "Directory does not exist"); TraceFunctLeave(); return FALSE; } // sets acl allowing specific access to LocalSystem/Admin // and to everyone DWORD SetAclInObject(HANDLE hObject, DWORD dwObjectType, DWORD dwSystemMask, DWORD dwEveryoneMask, BOOL fInherit) { tenter("SetAclInObject"); DWORD dwRes, dwDisposition; PSID pEveryoneSID = NULL, pAdminSID = NULL, pSystemSID = NULL; PACL pACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; EXPLICIT_ACCESS ea[3]; SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY; LONG lRes; // Create a well-known SID for the Everyone group. if(! AllocateAndInitializeSid( &SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID) ) { dwRes = GetLastError(); trace(0, "AllocateAndInitializeSid Error %u\n", dwRes); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow Everyone read access to the key. ZeroMemory(&ea, 3 * sizeof(EXPLICIT_ACCESS)); ea[0].grfAccessPermissions = dwEveryoneMask; ea[0].grfAccessMode = SET_ACCESS; ea[0].grfInheritance = fInherit ? SUB_CONTAINERS_AND_OBJECTS_INHERIT : NO_INHERITANCE; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[0].Trustee.ptstrName = (LPTSTR) pEveryoneSID; // Create a SID for the BUILTIN\Administrators group. if(! AllocateAndInitializeSid( &SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSID) ) { dwRes = GetLastError(); trace(0, "AllocateAndInitializeSid Error %u\n", dwRes); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow the Administrators group full access to the key. ea[1].grfAccessPermissions = dwSystemMask; ea[1].grfAccessMode = SET_ACCESS; ea[1].grfInheritance= fInherit ? SUB_CONTAINERS_AND_OBJECTS_INHERIT : NO_INHERITANCE; ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea[1].Trustee.ptstrName = (LPTSTR) pAdminSID; // Create a SID for the LocalSystem account if(! AllocateAndInitializeSid( &SIDAuthNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSystemSID) ) { dwRes = GetLastError(); trace(0, "AllocateAndInitializeSid Error %u\n", dwRes ); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow the LocalSystem full access to the key. ea[2].grfAccessPermissions = dwSystemMask; ea[2].grfAccessMode = SET_ACCESS; ea[2].grfInheritance= fInherit ? SUB_CONTAINERS_AND_OBJECTS_INHERIT : NO_INHERITANCE; ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[2].Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea[2].Trustee.ptstrName = (LPTSTR) pSystemSID; // Create a new ACL that contains the new ACEs. dwRes = SetEntriesInAcl(3, ea, NULL, &pACL); if (ERROR_SUCCESS != dwRes) { dwRes = GetLastError(); trace(0, "SetEntriesInAcl Error %u\n", dwRes ); goto Cleanup; } // Initialize a security descriptor. pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (pSD == NULL) { trace(0, "LocalAlloc Error %u\n", GetLastError() ); goto Cleanup; } if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { dwRes = GetLastError(); trace(0, "InitializeSecurityDescriptor Error %u\n", dwRes ); goto Cleanup; } // Add the ACL to the security descriptor. if (!SetSecurityDescriptorDacl(pSD, TRUE, // fDaclPresent flag pACL, FALSE)) // not a default DACL { dwRes = GetLastError(); trace(0, "SetSecurityDescriptorDacl Error %u\n", dwRes ); goto Cleanup; } dwRes = SetSecurityInfo(hObject, (SE_OBJECT_TYPE) dwObjectType, DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, NULL, NULL, pACL, NULL); if (ERROR_SUCCESS != dwRes) { trace(0, "SetSecurityInfo Error %u\n", dwRes ); goto Cleanup; } Cleanup: if (pEveryoneSID) FreeSid(pEveryoneSID); if (pAdminSID) FreeSid(pAdminSID); if (pSystemSID) FreeSid(pSystemSID); if (pACL) LocalFree(pACL); if (pSD) LocalFree(pSD); tleave(); return dwRes; } // sets acl to a named object allowing specific access to // LocalSystem/Admin and to everyone DWORD SetAclInNamedObject(WCHAR * pszDirName, DWORD dwObjectType, DWORD dwSystemMask, DWORD dwEveryoneMask, DWORD dwSystemInherit, DWORD dwEveryOneInherit) { tenter("SetAclInNamedObject"); DWORD dwRes, dwDisposition; PSID pEveryoneSID = NULL, pAdminSID = NULL; PSID pSystemSID = NULL; PACL pACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; EXPLICIT_ACCESS ea[3]; SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY; LONG lRes; BOOL fReturn; // Create a well-known SID for the Everyone group. if(! AllocateAndInitializeSid( &SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID) ) { dwRes = GetLastError(); trace(0, "AllocateAndInitializeSid Error %u\n", dwRes); goto Cleanup; } // 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 = dwEveryoneMask; ea[0].grfAccessMode = SET_ACCESS; ea[0].grfInheritance = dwEveryOneInherit; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[0].Trustee.ptstrName = (LPTSTR) pEveryoneSID; // Create a SID for the BUILTIN\Administrators group. if(! AllocateAndInitializeSid( &SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSID) ) { dwRes = GetLastError(); trace(0, "AllocateAndInitializeSid Error %u\n", dwRes); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow the Administrators group full access to the key. ea[1].grfAccessPermissions = dwSystemMask; ea[1].grfAccessMode = SET_ACCESS; ea[1].grfInheritance= dwSystemInherit; ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea[1].Trustee.ptstrName = (LPTSTR) pAdminSID; // Create a SID for the LocalSystem account if(! AllocateAndInitializeSid( &SIDAuthNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSystemSID) ) { dwRes = GetLastError(); trace(0, "AllocateAndInitializeSid Error %u\n", dwRes ); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow the LocalSystem full access to the key. ea[2].grfAccessPermissions = dwSystemMask; ea[2].grfAccessMode = SET_ACCESS; ea[2].grfInheritance= dwSystemInherit; ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[2].Trustee.TrusteeType = TRUSTEE_IS_USER; ea[2].Trustee.ptstrName = (LPTSTR) pSystemSID; // Create a new ACL that contains the new ACEs. dwRes = SetEntriesInAcl(3, ea, NULL, &pACL); if (ERROR_SUCCESS != dwRes) { dwRes = GetLastError(); trace(0, "SetEntriesInAcl Error %u\n", dwRes ); goto Cleanup; } // Initialize a security descriptor. pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (pSD == NULL) { trace(0, "LocalAlloc Error %u\n", GetLastError() ); goto Cleanup; } if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { dwRes = GetLastError(); trace(0, "InitializeSecurityDescriptor Error %u\n", dwRes ); goto Cleanup; } // Add the ACL to the security descriptor. if (!SetSecurityDescriptorDacl(pSD, TRUE, // fDaclPresent flag pACL, FALSE)) // not a default DACL { dwRes = GetLastError(); trace(0, "SetSecurityDescriptorDacl Error %u\n", dwRes ); goto Cleanup; } dwRes = SetNamedSecurityInfo(pszDirName, (SE_OBJECT_TYPE) dwObjectType, DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, NULL, NULL, pACL, NULL); if (ERROR_SUCCESS != dwRes) { trace(0, "SetSecurityInfo Error %u\n", dwRes ); goto Cleanup; } dwRes = ERROR_SUCCESS; Cleanup: if (pEveryoneSID) FreeSid(pEveryoneSID); if (pAdminSID) FreeSid(pAdminSID); if (pSystemSID) FreeSid(pSystemSID); if (pACL) LocalFree(pACL); if (pSD) LocalFree(pSD); tleave(); return dwRes; } DWORD SetCorrectACLOnDSRoot(WCHAR * wcsPath) { return SetAclInNamedObject(wcsPath, // restore dir name SE_FILE_OBJECT, STANDARD_RIGHTS_ALL | GENERIC_ALL, // system and admin access FILE_WRITE_DATA|SYNCHRONIZE, // everyone - just the right // to create a file in the directory SUB_CONTAINERS_AND_OBJECTS_INHERIT, // Inherit system and admin // ACLs to children SUB_CONTAINERS_ONLY_INHERIT); //Inherit everyone ACL only //to subcontainers } DWORD GetWorldEffectivePermissions(PACL pDacl, ACCESS_MASK * pAccessMask) { TraceFunctEnter("GetWorldEffectivePermissions"); DWORD dwReturn; TRUSTEE WorldTrustee; SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; PSID pEveryoneSID = NULL; // 1. build the trustee structure for World // 1a Create a well-known SID for the Everyone group. if(! AllocateAndInitializeSid( &SIDAuthWorld, 1, // nSubAuthorityCount SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID) ) { dwReturn = GetLastError(); trace(0, "AllocateAndInitializeSid Error %u\n", dwReturn); goto cleanup; } ZeroMemory(&WorldTrustee, sizeof(WorldTrustee)); WorldTrustee.MultipleTrusteeOperation=NO_MULTIPLE_TRUSTEE; WorldTrustee.TrusteeForm = TRUSTEE_IS_SID; WorldTrustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; WorldTrustee.ptstrName = (LPTSTR) pEveryoneSID; // call the API to get rights for World dwReturn=GetEffectiveRightsFromAcl(pDacl, // ACL &WorldTrustee, pAccessMask); cleanup: if (pEveryoneSID) FreeSid(pEveryoneSID); TraceFunctLeave(); return dwReturn; } // returns if Everyone has write access to the directory BOOL IsDirectoryWorldAccessible(WCHAR * pszObjectName) { TraceFunctEnter("IsDirectoryWorldAccessible"); BOOL fReturn=FALSE; // Assume FALSE by default DWORD dwReturn; PACL pDacl; PSECURITY_DESCRIPTOR pSecurityDescriptor=NULL; ACCESS_MASK AccessMask; // Get Security Info from directory dwReturn=GetNamedSecurityInfo(pszObjectName, // object name SE_FILE_OBJECT, // object type DACL_SECURITY_INFORMATION, //information type NULL, // owner SID NULL, // primary group SID &pDacl, // DACL NULL, // SACL &pSecurityDescriptor);// SD if (ERROR_SUCCESS != dwReturn) { ErrorTrace(0, "GetNamedSecurityInfo error %u\n", dwReturn); pSecurityDescriptor=NULL; goto cleanup; } // Get Effective permissions of World from this ACL dwReturn=GetWorldEffectivePermissions(pDacl, &AccessMask); if (ERROR_SUCCESS != dwReturn) { ErrorTrace(0, "GetWorldEffectPermissions error %u\n", dwReturn); goto cleanup; } // Check if world has Access. We will just check for FILE_APPEND_DATA // which is the right to create a subdirectory. fReturn = (0 !=(AccessMask&FILE_APPEND_DATA)); cleanup: // release memory if (NULL!= pSecurityDescriptor) { _VERIFY(NULL==LocalFree(pSecurityDescriptor)); } TraceFunctLeave(); return fReturn; } // This function compares given SID with administrators group and system BOOL IsSidOfAdminOrSystem(PSID pSid) { TraceFunctEnter("IsFileOwnedByAdminOrSystem"); BOOL fReturn=FALSE; // Assume FALSE by default PSID pAdminSID = NULL; PSID pSystemSID = NULL; SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY; DWORD dwRes; // create SIDs of Admins and System // Create a SID for the BUILTIN\Administrators group. if(! AllocateAndInitializeSid( &SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSID) ) { dwRes = GetLastError(); trace(0, "AllocateAndInitializeSid Error %u", dwRes); goto cleanup; } if (EqualSid(pAdminSID, pSid)) { trace(0, "passed in SID is Admin SID"); fReturn=TRUE; goto cleanup; } // Create a SID for the LocalSystem account if(! AllocateAndInitializeSid( &SIDAuthNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSystemSID) ) { dwRes = GetLastError(); trace(0, "AllocateAndInitializeSid Error %u\n", dwRes ); goto cleanup; } if (EqualSid(pSystemSID, pSid)) { trace(0, "passed in SID is System SID"); fReturn=TRUE; goto cleanup; } cleanup: if (pAdminSID) FreeSid(pAdminSID); if (pSystemSID) FreeSid(pSystemSID); TraceFunctLeave(); return fReturn; } BOOL IsVolumeNTFS(WCHAR * pszFileName) { TENTER ("IsVolumeNTFS"); BOOL fReturn=FALSE; DWORD dwErr = ERROR_SUCCESS; WCHAR szFileNameCopy[2*MAX_PATH]; DWORD dwFsFlags; WCHAR * pszVolumeNameEnd; DWORD dwFileNameLength; dwFileNameLength = lstrlen(pszFileName); if ( (dwFileNameLength >= sizeof(szFileNameCopy)/sizeof(WCHAR)) || (dwFileNameLength < 4) ) { // file name too long. Cannot be a valid changelog TRACE(0, "Filename not of proper length %d", dwFileNameLength); fReturn=FALSE; // assume not NTFS goto cleanup; } lstrcpy(szFileNameCopy, pszFileName); pszVolumeNameEnd=ReturnPastVolumeName(szFileNameCopy); // NULL terminate after end of volume name to get just the volume name *pszVolumeNameEnd=L'\0'; // Get the volume label and flags if (TRUE == GetVolumeInformationW (szFileNameCopy,// root directory NULL,// volume name buffer 0, // length of name buffer NULL, // volume serial number NULL,// maximum file name length &dwFsFlags,// file system options NULL,// file system name buffer 0))// length of file system name buffer { if (dwFsFlags & FS_PERSISTENT_ACLS) { fReturn=TRUE; } else { fReturn=FALSE; } } else { dwErr = GetLastError(); TRACE(0, "GetVolumeInformation failed : %ld", dwErr); fReturn=FALSE; // assume not NTFS } cleanup: TLEAVE(); return fReturn; } // returns if the file is owned by the administrators group or system BOOL IsFileOwnedByAdminOrSystem(WCHAR * pszObjectName) { TraceFunctEnter("IsFileOwnedByAdminOrSystem"); BOOL fReturn=FALSE; // Assume FALSE by default DWORD dwReturn; PSID pSidOwner=NULL; PSECURITY_DESCRIPTOR pSecurityDescriptor=NULL; ACCESS_MASK AccessMask; if (FALSE == IsVolumeNTFS(pszObjectName)) { // if the volume is not NTFS, return success fReturn=TRUE; goto cleanup; } // Get Security Info from directory dwReturn=GetNamedSecurityInfo(pszObjectName, // object name SE_FILE_OBJECT, // object type OWNER_SECURITY_INFORMATION,//information type &pSidOwner, // owner SID NULL, // primary group SID NULL, // DACL NULL, // SACL &pSecurityDescriptor);// SD if (ERROR_SUCCESS != dwReturn) { ErrorTrace(0, "GetNamedSecurityInfo error %u\n", dwReturn); pSecurityDescriptor=NULL; goto cleanup; } // Compare SID with administrators group and system fReturn=IsSidOfAdminOrSystem(pSidOwner); cleanup: // release memory if (NULL!= pSecurityDescriptor) { _VERIFY(NULL==LocalFree(pSecurityDescriptor)); } TraceFunctLeave(); return fReturn; } //+--------------------------------------------------------------------------- // // Function: Delnode_Recurse // // Synopsis: attempt to delete a directory tree // // Arguments: [pwszDir] -- directory name // [fIncludeRoot] -- delete top level directory and files // [pfStop] -- TRUE if stop signaled // // Returns: Win32 error code // // History: 12-Apr-2000 HenryLee Created // //---------------------------------------------------------------------------- DWORD Delnode_Recurse (const WCHAR *pwszDir, BOOL fDeleteRoot, BOOL *pfStop) { tenter("Delnode_Recurse"); DWORD dwErr = ERROR_SUCCESS; WIN32_FIND_DATA *pfd = NULL; HANDLE hFile = INVALID_HANDLE_VALUE; WCHAR * pwcsPath = NULL; if (lstrlenW (pwszDir) > MAX_PATH-5) { dwErr = ERROR_INVALID_PARAMETER; trace (0, "Delnode_Recurse failed with %d", dwErr); goto cleanup; } if (NULL == (pfd = new WIN32_FIND_DATA)) { dwErr = ERROR_NOT_ENOUGH_MEMORY; trace (0, "Delnode_Recurse failed with %d", dwErr); goto cleanup; } if (NULL == (pwcsPath = new WCHAR[MAX_PATH])) { dwErr = ERROR_NOT_ENOUGH_MEMORY; trace (0, "Delnode_Recurse failed with %d", dwErr); goto cleanup; } lstrcpy (pwcsPath, pwszDir); lstrcat (pwcsPath, TEXT("\\*.*")); hFile = FindFirstFileW (pwcsPath, pfd); if (hFile == INVALID_HANDLE_VALUE) { // if the directory does not exist, then return success dwErr = ERROR_SUCCESS; goto cleanup; } do { if (pfStop != NULL && TRUE == *pfStop) { dwErr = ERROR_OPERATION_ABORTED; trace (0, "Delnode_Recurse failed with %d", dwErr); goto cleanup; } if (!lstrcmp(pfd->cFileName, L".") || !lstrcmp(pfd->cFileName, L"..")) { continue; } if (lstrlenW(pwszDir) + lstrlenW(pfd->cFileName) + 1 >= MAX_PATH) continue; // ignore excessively long names lstrcpy (pwcsPath, pwszDir); // construct the full path name lstrcat (pwcsPath, TEXT("\\")); lstrcat (pwcsPath, pfd->cFileName); if (pfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // // Found a directory. Skip mount points // if (pfd->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { continue; } dwErr = Delnode_Recurse (pwcsPath, TRUE, pfStop); if (dwErr != ERROR_SUCCESS) { trace (0, "Delnode_Recurse failed with %d, ignoring", dwErr); dwErr = ERROR_SUCCESS; // try to delete more directories } } else if (fDeleteRoot) { // // We found a file. Set the file attributes, // and try to delete it. // if ((pfd->dwFileAttributes & FILE_ATTRIBUTE_READONLY) || (pfd->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) { SetFileAttributesW (pwcsPath, FILE_ATTRIBUTE_NORMAL); } if (FALSE == DeleteFileW (pwcsPath)) { if (ERROR_SUCCESS == (dwErr = TakeOwn (pwcsPath))) { if (FALSE == DeleteFileW (pwcsPath)) { dwErr = GetLastError(); } } if (dwErr != ERROR_SUCCESS) { trace (0, "DeleteFile or TakeOwn failed with %d", dwErr); goto cleanup; } } } } while (FindNextFile(hFile, pfd)); // Find the next entry FindClose(hFile); // Close the search handle hFile = INVALID_HANDLE_VALUE; if (fDeleteRoot) { DWORD dwAttr = GetFileAttributes(pwszDir); if (dwAttr != 0xFFFFFFFF && (dwAttr & FILE_ATTRIBUTE_READONLY)) { dwAttr &= ~FILE_ATTRIBUTE_READONLY; if (FALSE == SetFileAttributes (pwszDir, dwAttr)) { TRACE(0, "SetFileAttributes ignoring %ld", GetLastError()); } } if (FALSE == RemoveDirectoryW (pwszDir)) { if (ERROR_SUCCESS == (dwErr = TakeOwn (pwszDir))) { if (FALSE == RemoveDirectoryW (pwszDir)) { LONG lLast = lstrlenW (pwszDir) - 1; if (lLast < 0) lLast = 0; dwErr = GetLastError(); if (pwszDir[lLast] != L')' && // already renamed TRUE == SRGetAltFileName (pwszDir, pwcsPath) && TRUE == MoveFile (pwszDir, pwcsPath)) dwErr = ERROR_SUCCESS; else trace (0, "RemoveDirectory failed with %d", dwErr); } } } } cleanup: if (hFile != INVALID_HANDLE_VALUE) FindClose (hFile); if (NULL != pfd) delete pfd; if (NULL != pwcsPath) delete [] pwcsPath; tleave(); return dwErr; } // // util function that checks the SR Stop event // to see if it has been signalled or not // will return TRUE if the event does not exist // BOOL IsStopSignalled(HANDLE hEvent) { TENTER("IsStopSignalled"); BOOL fRet, fOpened = FALSE; DWORD dwRc; if (! hEvent) { hEvent = OpenEvent(SYNCHRONIZE, FALSE, s_cszSRStopEvent); if (! hEvent) { // if cannot open, then assume that service is not stopped // if client is running on different desktop than service (multiple user magic) // then it cannot open the event, though service might be running dwRc = GetLastError(); TRACE(0, "! OpenEvent : %ld", dwRc); TLEAVE(); return FALSE; } fOpened = TRUE; } fRet = (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 0)); if (fOpened) CloseHandle(hEvent); TLEAVE(); return fRet; } void PostTestMessage(UINT msg, WPARAM wp, LPARAM lp) { HWINSTA hwinstaUser; HDESK hdeskUser = NULL; DWORD dwThreadId; HWINSTA hwinstaSave; HDESK hdeskSave; DWORD dwRc; TENTER("PostTestMessage"); // // save current values // GetDesktopWindow(); hwinstaSave = GetProcessWindowStation(); dwThreadId = GetCurrentThreadId(); hdeskSave = GetThreadDesktop(dwThreadId); // // change desktop and winstation to interactive user // hwinstaUser = OpenWindowStation(L"WinSta0", FALSE, MAXIMUM_ALLOWED); if (hwinstaUser == NULL) { dwRc = GetLastError(); trace(0, "! OpenWindowStation : %ld", dwRc); goto done; } SetProcessWindowStation(hwinstaUser); hdeskUser = OpenDesktop(L"Default", 0, FALSE, MAXIMUM_ALLOWED); if (hdeskUser == NULL) { dwRc = GetLastError(); trace(0, "! OpenDesktop : %ld", dwRc); goto done; } SetThreadDesktop(hdeskUser); if (FALSE == PostMessage(HWND_BROADCAST, msg, wp, lp)) { trace(0, "! PostMessage"); } done: // // restore old values // if (hdeskSave) SetThreadDesktop(hdeskSave); if (hwinstaSave) SetProcessWindowStation(hwinstaSave); // // close opened handles // if (hdeskUser) CloseDesktop(hdeskUser); if (hwinstaUser) CloseWindowStation(hwinstaUser); TLEAVE(); } //+------------------------------------------------------------------------- // // Function: RemoveTrailingFilename // // Synopsis: This function takes as input parameter a string which // contains a filename. It removes the last filename (or // directory ) from the string including the '\' or '/' // before the last filename. // // Arguments: IN/OUT pszString - string to be modified. // IN tchSlash - file name separator - must be '/' or'\' // // // Returns: nothing // // History: AshishS Created 5/22/96 // //------------------------------------------------------------------------ void RemoveTrailingFilename(WCHAR * pszString, WCHAR wchSlash) { WCHAR * pszStringStart; DWORD dwStrlen; pszStringStart = pszString; dwStrlen = lstrlen ( pszString); // first go the end of the string pszString += dwStrlen ; // now walk backwards till we see the first '\' // also maintain a count of how many characters we have // gone back. while ( (*pszString != wchSlash) && ( dwStrlen) ) { pszString--; dwStrlen --; } *pszString = TEXT('\0'); } // this function create the parent directory under the specified file // name if it already does not exist BOOL CreateParentDirectory(WCHAR * pszFileName) { TraceFunctEnter("CreateParentDirectory"); BOOL fReturn = FALSE; DWORD dwError; // get the parent directory RemoveTrailingFilename(pszFileName, L'\\'); if (FALSE == DoesDirExist(pszFileName)) { if (FALSE == CreateDirectory(pszFileName, // directory name NULL)) // SD { dwError = GetLastError(); ErrorTrace(TRACEID, "Could not create directory %S ec=%d", pszFileName, dwError); goto cleanup; } } fReturn = TRUE; cleanup: TraceFunctLeave(); return fReturn; } // this function creates all sub directories under the specified file // name. BOOL CreateBaseDirectory(const WCHAR * pszFileName) { BOOL fRetVal = FALSE; DWORD dwCurIndex,dwBufReqd; DWORD dwStrlen; TraceFunctEnter("CreateBaseDirectory"); DWORD dwError; WCHAR * pszFileNameCopy; dwBufReqd = (lstrlen(pszFileName) + 1) * sizeof(WCHAR); pszFileNameCopy = (WCHAR *) _alloca(dwBufReqd); if (NULL == pszFileNameCopy) { ErrorTrace(0, "alloca for size %d failed", dwBufReqd); goto cleanup; } lstrcpy(pszFileNameCopy, pszFileName); // do a fast check to see if the parent directory exists if (TRUE == CreateParentDirectory(pszFileNameCopy)) { fRetVal = TRUE; goto cleanup; } lstrcpy(pszFileNameCopy, pszFileName); dwStrlen = lstrlen(pszFileNameCopy); // check to see if this is a filename starting with the GUID if (0==wcsncmp( pszFileNameCopy, VOLUMENAME_FORMAT, lstrlen(VOLUMENAME_FORMAT))) { // this is of the format \\?\Volume // skip over the initial part dwCurIndex = lstrlen(VOLUMENAME_FORMAT)+1; // skip over the GUID part also while (dwCurIndex < dwStrlen) { dwCurIndex++; if (TEXT('\\') == pszFileNameCopy[dwCurIndex-1] ) { break; } } } else { // the filename is of the regular format // we start at index 1 and not at 0 because we want to handle // path name like \foo\abc.txt dwCurIndex = 1; } while (dwCurIndex < dwStrlen) { if (TEXT('\\') == pszFileNameCopy[dwCurIndex] ) { // NULL terminate at the '\' to get the sub directory // name. pszFileNameCopy[dwCurIndex] = TEXT('\0'); if (FALSE == DoesDirExist(pszFileNameCopy)) { if (FALSE == CreateDirectory(pszFileNameCopy, // directory name NULL)) // SD { dwError = GetLastError(); ErrorTrace(TRACEID, "Could not create directory %S ec=%d", pszFileNameCopy, dwError); pszFileNameCopy[dwCurIndex] = TEXT('\\'); goto cleanup; } DebugTrace(TRACEID, "Created directory %S", pszFileNameCopy); } // restore the \ to get the file name again. pszFileNameCopy[dwCurIndex] = TEXT('\\'); } dwCurIndex ++; } fRetVal = TRUE; cleanup: TraceFunctLeave(); return fRetVal; } // The following function logs the name of a file in the DS. The // problem right now is that the path of the DS is so long that the // relevant information is thrown away from the trace buffer. void LogDSFileTrace(DWORD dwTraceID, const WCHAR * pszPrefix, // Initial message to be traced const WCHAR * pszDSFile) { WCHAR * pszBeginName; TraceQuietEnter("LogDSFileTrace"); // first see if the file is in the DS pszBeginName = wcschr(pszDSFile, L'\\'); if (NULL == pszBeginName) { goto cleanup; } // skip over the first \ . pszBeginName++; // comapare if the first part is "system volume information" if (0!=_wcsnicmp(s_cszSysVolInfo, pszBeginName, lstrlen(s_cszSysVolInfo))) { goto cleanup; } // skip over the next \ . pszBeginName = wcschr(pszBeginName, L'\\'); if (NULL == pszBeginName) { goto cleanup; } pszBeginName++; // now skip over the _restore directory // first see if the file is in the DS pszBeginName = wcschr(pszBeginName, L'\\'); if (NULL == pszBeginName) { goto cleanup; } DebugTrace(dwTraceID, "%S %S", pszPrefix, pszBeginName); cleanup: // the file is not in the DS - or we are printing out the initial // part for debugging purposes. DebugTrace(dwTraceID, "%S%S", pszPrefix, pszDSFile); return; } // the following function calls pfnMethod on all the files specified // by the pszFindFileData filter. DWORD ProcessGivenFiles(WCHAR * pszBaseDir, PPROCESSFILEMETHOD pfnMethod, WCHAR * pszFindFileData) { TraceFunctEnter("ProcessGivenFiles"); WIN32_FIND_DATA FindFileData; HANDLE hFindFirstFile = INVALID_HANDLE_VALUE; DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR; BOOL fContinue; LogDSFileTrace(0, L"FileData is ", pszFindFileData); hFindFirstFile = FindFirstFile(pszFindFileData, &FindFileData); DebugTrace(0, "FindFirstFile returned %d", hFindFirstFile); if (INVALID_HANDLE_VALUE == hFindFirstFile) { dwErr = GetLastError(); DebugTrace(0, "FindFirstFile failed ec=%d. Filename is %S", dwErr, pszFindFileData); // what if even one file does not exist if ( (ERROR_FILE_NOT_FOUND == dwErr) || (ERROR_PATH_NOT_FOUND == dwErr) || (ERROR_NO_MORE_FILES == dwErr)) { // this is a success condition dwReturn = ERROR_SUCCESS; goto cleanup; } if (ERROR_SUCCESS != dwErr) { dwReturn = dwErr; } goto cleanup; } fContinue = TRUE; while (TRUE==fContinue) { LogDSFileTrace(0, L"FileName is ", FindFileData.cFileName); // now check to see if the file length is valid. This is // becuase a hacker can introduce a file in the datastore // that is too long and can cause us to overflow our buffers. if ( MAX_PATH <= lstrlen(pszBaseDir) +lstrlen(s_cszRegHiveCopySuffix)+ lstrlen(FindFileData.cFileName) + 2 ) { // Filename is too long. It cannot be a file created by // system restore. It probably is a file created by a hacker. // Ignore this file ErrorTrace(0, "Ignoring long file %S", FindFileData.cFileName); ErrorTrace(0, "Base dir %S", pszBaseDir ); dwErr = ERROR_SUCCESS; } else { dwErr = pfnMethod(pszBaseDir, FindFileData.cFileName); if (ERROR_SUCCESS != dwErr) { ErrorTrace(0, "pfnMethod failed. ec=%d.file=%S ", dwErr, FindFileData.cFileName); goto cleanup; } } fContinue = FindNextFile(hFindFirstFile, &FindFileData); } dwErr=GetLastError(); if (ERROR_NO_MORE_FILES != dwErr) { _ASSERT(0); ErrorTrace(0, "dwErr != ERROR_NO_MORE_FILES. It is %d", dwErr); goto cleanup; } dwReturn = ERROR_SUCCESS; cleanup: if (INVALID_HANDLE_VALUE != hFindFirstFile) { _VERIFY(TRUE == FindClose(hFindFirstFile)); } TraceFunctLeave(); return dwReturn; } DWORD DeleteGivenFile(WCHAR * pszBaseDir, // Base Directory const WCHAR * pszFile) // file to delete { TraceFunctEnter("DeleteGivenFile"); DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR; WCHAR szDataFile[MAX_PATH]; // construct the path name of the file wsprintf(szDataFile, L"%s\\%s", pszBaseDir, pszFile); if (TRUE != DeleteFile(szDataFile)) { dwErr = GetLastError(); if (ERROR_SUCCESS != dwErr) { dwReturn = dwErr; } ErrorTrace(0, "DeleteFile failed ec=%d", dwErr); LogDSFileTrace(0,L"File was ", szDataFile); goto cleanup; } dwReturn = ERROR_SUCCESS; cleanup: TraceFunctLeave(); return dwReturn; } //++----------------------------------------------------------------------- // // Function: WriteRegKey // // Synopsis: This function writes into a registry key. It also creates it // if it does not exist. // // Arguments: // // Returns: TRUE no error // FALSE a fatal error happened // // History: AshishS Created 5/22/96 //------------------------------------------------------------------------ BOOL WriteRegKey(BYTE * pbRegValue, DWORD dwNumBytes, const TCHAR * pszRegKey, const TCHAR * pszRegValueName, DWORD dwRegType) { HKEY hRegKey; LONG lResult; DWORD dwDisposition; TraceFunctEnter("WriteRegKey"); //read registry to find out name of the file if ( (lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszRegKey, // address of subkey name 0, // reserved NULL, // address of class string 0, // special options flag KEY_WRITE, // samDesired NULL, // address of key security structure &hRegKey, // address of handle of open key &dwDisposition // address of disposition value buffer )) != ERROR_SUCCESS ) { ErrorTrace(TRACEID, "RegCreateKeyEx error 0x%x", lResult); _ASSERT(0); goto cleanup; } if ( (lResult =RegSetValueEx( hRegKey, pszRegValueName, 0, // reserved dwRegType,// flag for value type pbRegValue, // address of value data dwNumBytes // size of value data )) != ERROR_SUCCESS ) { ErrorTrace(TRACEID, "RegSetValueEx error 0x%x", lResult); _ASSERT(0); _VERIFY(RegCloseKey(hRegKey)==ERROR_SUCCESS); goto cleanup; } _VERIFY(RegCloseKey(hRegKey)==ERROR_SUCCESS); TraceFunctLeave(); return TRUE; cleanup: TraceFunctLeave(); return FALSE; } //++------------------------------------------------------------------------ // // Function: ReadRegKey // // Synopsis: This function reads a registry key and creates it // if it does not exist with the default value. // // Arguments: // // Returns: TRUE no error // FALSE a fatal error happened // // History: AshishS Created 5/22/96 //------------------------------------------------------------------------ BOOL ReadRegKeyOrCreate(BYTE * pbRegValue, // The value of the reg key will be // stored here DWORD * pdwNumBytes, // Pointer to DWORD conataining // the number of bytes in the above buffer - will be // set to actual bytes stored. const TCHAR * pszRegKey, // Reg Key to be opened const TCHAR * pszRegValueName, // Reg Value to query DWORD dwRegTypeExpected, BYTE * pbDefaultValue, // default value DWORD dwDefaultValueSize) // size of default value { if (!ReadRegKey(pbRegValue,//Buffer to store value pdwNumBytes, // Length of above buffer pszRegKey, // Reg Key name pszRegValueName, // Value name dwRegTypeExpected) ) // Type expected { // read reg key failed - use default value and create this // key return WriteRegKey(pbDefaultValue, dwDefaultValueSize, pszRegKey, pszRegValueName, dwRegTypeExpected); } return TRUE; } //++------------------------------------------------------------------------ // // Function: ReadRegKey // // Synopsis: This function reads a registry key. // // Arguments: // // Returns: TRUE no error // FALSE a fatal error happened // // History: AshishS Created 5/22/96 //------------------------------------------------------------------------ BOOL ReadRegKey(BYTE * pbRegValue, // The value of the reg key will be // stored here DWORD * pdwNumBytes, // Pointer to DWORD conataining // the number of bytes in the above buffer - will be // set to actual bytes stored. const TCHAR * pszRegKey, // Reg Key to be opened const TCHAR * pszRegValueName, // Reg Value to query DWORD dwRegTypeExpected) // Expected type of Value { HKEY hRegKey; DWORD dwRegType; LONG lResult; TraceFunctEnter("ReadRegKey"); DebugTrace(TRACEID, "Trying to open %S %S", pszRegKey, pszRegValueName); //read registry to find out name of the file if ( (lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszRegKey, // address of subkey name 0, // reserved KEY_READ, // samDesired &hRegKey // address of handle of open key )) != ERROR_SUCCESS ) { ErrorTrace(TRACEID, "RegOpenKeyEx open error 0x%x", lResult); goto cleanup; } if ( (lResult =RegQueryValueEx( hRegKey, pszRegValueName, 0, // reserved &dwRegType,// address of buffer // for value type pbRegValue, pdwNumBytes)) != ERROR_SUCCESS ) { _VERIFY(RegCloseKey(hRegKey)==ERROR_SUCCESS); ErrorTrace(TRACEID, "RegQueryValueEx failed error 0x%x", lResult); goto cleanup; } _VERIFY(RegCloseKey(hRegKey)==ERROR_SUCCESS); if ( dwRegType != dwRegTypeExpected ) { ErrorTrace(TRACEID, "RegType is %d, not %d", dwRegType, dwRegTypeExpected); goto cleanup; } TraceFunctLeave(); return TRUE; cleanup: TraceFunctLeave(); return FALSE; } // this function sets the error hit by restore in the registry BOOL SetRestoreError(DWORD dwRestoreError) { TraceFunctEnter("SetDiskSpaceError"); DWORD dwNumBytes=sizeof(DWORD); BOOL fResult=FALSE; // assume FALSE by default DebugTrace(TRACEID, "Setting disk space error to %d", dwRestoreError); if (FALSE== WriteRegKey((BYTE*)&dwRestoreError, // The value of the // reg key will be set to this value dwNumBytes, // Pointer to DWORD containing // the number of bytes in the above buffer s_cszSRRegKey, // Reg Key to be opened s_cszRestoreDiskSpaceError, // Reg Value to query REG_DWORD)) // Expected type of Value { fResult = FALSE; goto cleanup; } fResult= TRUE; cleanup: TraceFunctLeave(); return fResult; } // this function checks to see of the restore failed because of disk space BOOL CheckForDiskSpaceError() { TraceFunctEnter("CheckForDiskSpaceError"); DWORD dwRestoreError; DWORD dwNumBytes=sizeof(DWORD); BOOL fResult=FALSE; // assume FALSE by default if (FALSE==ReadRegKey((BYTE*)&dwRestoreError, // The value of the // reg key will be stored here &dwNumBytes, // Pointer to DWORD containing // the number of bytes in the above buffer - will be // set to actual bytes stored. s_cszSRRegKey, // Reg Key to be opened s_cszRestoreDiskSpaceError, // Reg Value to query REG_DWORD)) // Expected type of Value { fResult = FALSE; } if (dwRestoreError == ERROR_DISK_FULL) { DebugTrace(TRACEID,"Restore failed because of disk space"); fResult= TRUE; } TraceFunctLeave(); return fResult; } // this function sets the status whether restore was done in safe mode BOOL SetRestoreSafeModeStatus(DWORD dwSafeModeStatus) { TraceFunctEnter("SetRestoreSafeModeStatus"); DWORD dwNumBytes=sizeof(DWORD); BOOL fResult=FALSE; // assume FALSE by default DebugTrace(TRACEID, "Setting restore safe mode status to %d", dwSafeModeStatus); if (FALSE== WriteRegKey((BYTE*)&dwSafeModeStatus, // The value of the // reg key will be set to this value dwNumBytes, // Pointer to DWORD containing // the number of bytes in the above buffer s_cszSRRegKey, // Reg Key to be opened s_cszRestoreSafeModeStatus, // Reg Value to query REG_DWORD)) // Expected type of Value { fResult = FALSE; goto cleanup; } fResult= TRUE; cleanup: TraceFunctLeave(); return fResult; } // this function checks to see is the last restore was done in safe mode BOOL WasLastRestoreInSafeMode() { TraceFunctEnter("WasLastRestoreInSafeMode"); DWORD dwRestoreSafeModeStatus; DWORD dwNumBytes=sizeof(DWORD); BOOL fResult=FALSE; // assume FALSE by default if (FALSE==ReadRegKey((BYTE*)&dwRestoreSafeModeStatus, // The value of the // reg key will be stored here &dwNumBytes, // Pointer to DWORD containing // the number of bytes in the above buffer - will be // set to actual bytes stored. s_cszSRRegKey, // Reg Key to be opened s_cszRestoreSafeModeStatus, // Reg Value to query REG_DWORD)) // Expected type of Value { fResult = FALSE; } if (dwRestoreSafeModeStatus != 0 ) { DebugTrace(TRACEID,"Last restore was done in safe mode"); fResult= TRUE; } else { DebugTrace(TRACEID,"Last restore was not done in safe mode"); } TraceFunctLeave(); return fResult; } #define MAX_LEN_SYSERR 1024 LPCWSTR GetSysErrStr() { LPCWSTR cszStr = GetSysErrStr( ::GetLastError() ); return( cszStr ); } LPCWSTR GetSysErrStr( DWORD dwErr ) { static WCHAR szErr[MAX_LEN_SYSERR+1]; ::FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), szErr, MAX_LEN_SYSERR, NULL ); return( szErr ); } /****************************************************************************/ LPWSTR SRGetRegMultiSz( HKEY hkRoot, LPCWSTR cszSubKey, LPCWSTR cszValue, LPDWORD pdwData ) { TraceFunctEnter("SRGetRegMultiSz"); LPCWSTR cszErr; DWORD dwRes; HKEY hKey = NULL; DWORD dwType; DWORD cbData = 0; LPWSTR szBuf = NULL; dwRes = ::RegOpenKeyEx( hkRoot, cszSubKey, 0, KEY_ALL_ACCESS, &hKey ); if ( dwRes != ERROR_SUCCESS ) { cszErr = ::GetSysErrStr( dwRes ); ErrorTrace(0, "::RegOpenKey() failed - %ls", cszErr); goto Exit; } dwRes = ::RegQueryValueEx( hKey, cszValue, 0, &dwType, NULL, &cbData ); if ( dwRes != ERROR_SUCCESS ) { cszErr = ::GetSysErrStr( dwRes ); ErrorTrace(0, "::RegQueryValueEx(len) failed - %ls", cszErr); goto Exit; } if ( dwType != REG_MULTI_SZ ) { ErrorTrace(0, "Type of '%ls' is %u (not REG_MULTI_SZ)...", cszValue, dwType); goto Exit; } if ( cbData == 0 ) { ErrorTrace(0, "Value '%ls' is empty...", cszValue); goto Exit; } szBuf = new WCHAR[cbData+2]; if (! szBuf) { ErrorTrace(0, "Cannot allocate memory"); goto Exit; } dwRes = ::RegQueryValueEx( hKey, cszValue, 0, &dwType, (LPBYTE)szBuf, &cbData ); if ( dwRes != ERROR_SUCCESS ) { cszErr = ::GetSysErrStr( dwRes ); ErrorTrace(0, "::RegQueryValueEx(data) failed - %ls", cszErr); delete [] szBuf; szBuf = NULL; } if ( pdwData != NULL ) *pdwData = cbData; Exit: if ( hKey != NULL ) ::RegCloseKey( hKey ); TraceFunctLeave(); return( szBuf ); } /****************************************************************************/ BOOL SRSetRegMultiSz( HKEY hkRoot, LPCWSTR cszSubKey, LPCWSTR cszValue, LPCWSTR cszData, DWORD cbData ) { TraceFunctEnter("SRSetRegMultiSz"); BOOL fRet = FALSE; LPCWSTR cszErr; DWORD dwRes; HKEY hKey = NULL; dwRes = ::RegOpenKeyEx( hkRoot, cszSubKey, 0, KEY_ALL_ACCESS, &hKey ); if ( dwRes != ERROR_SUCCESS ) { cszErr = ::GetSysErrStr( dwRes ); ErrorTrace(0, "::RegOpenKey() failed - %ls", cszErr); goto Exit; } dwRes = ::RegSetValueEx( hKey, cszValue, 0, REG_MULTI_SZ, (LPBYTE)cszData, cbData ); if ( dwRes != ERROR_SUCCESS ) { cszErr = ::GetSysErrStr( dwRes ); ErrorTrace(0, "::RegSetValueEx() failed - %ls", cszErr); goto Exit; } fRet = TRUE; Exit: if ( hKey != NULL ) ::RegCloseKey( hKey ); TraceFunctLeave(); return( fRet ); } // this returns the name after the volume name // For example input: c:\file output: file // input \\?\Volume{GUID}\file1 output: file1 WCHAR * ReturnPastVolumeName(const WCHAR * pszFileName) { DWORD dwStrlen, dwCurIndex; dwStrlen = lstrlen(pszFileName); // check to see if this is a filename starting with the GUID if (0==wcsncmp( pszFileName, VOLUMENAME_FORMAT, lstrlen(VOLUMENAME_FORMAT))) { // this is of the format \\?\Volume // skip over the initial part dwCurIndex = lstrlen(VOLUMENAME_FORMAT)+1; // skip over the GUID part also while (dwCurIndex < dwStrlen) { dwCurIndex++; if (TEXT('\\') == pszFileName[dwCurIndex-1] ) { break; } } } else { // the filename is of the regular format dwCurIndex = 3; } return (WCHAR *)pszFileName + dwCurIndex; } void SRLogEvent (HANDLE hEventSource, WORD wType, DWORD dwID, void * pRawData, DWORD dwDataSize, const WCHAR * pszS1, const WCHAR * pszS2, const WCHAR * pszS3) { const WCHAR* ps[3]; ps[0] = pszS1; ps[1] = pszS2; ps[2] = pszS3; WORD iStr = 0; for (int i = 0; i < 3; i++) { if (ps[i] != NULL) iStr++; } if (hEventSource) { ::ReportEvent( hEventSource, wType, 0, dwID, NULL, // sid iStr, dwDataSize, ps, pRawData); } } BOOL IsPowerUsers() { BOOL fReturn = FALSE; PSID psidPowerUsers; DWORD dwErr; SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; TENTER("IsPowerUsers"); if ( AllocateAndInitializeSid ( &SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &psidPowerUsers)) { if (! CheckTokenMembership(NULL, psidPowerUsers, &fReturn)) { dwErr = GetLastError(); TRACE(0, "! CheckTokenMembership : %ld", dwErr); } FreeSid (psidPowerUsers); } else { dwErr = GetLastError(); TRACE(0, "! AllocateAndInitializeSid : %ld", dwErr); } TLEAVE(); return fReturn; } // function to check if caller is running in admin context BOOL IsAdminOrSystem() { BOOL fReturn = FALSE; PSID psidAdmin, psidSystem; DWORD dwErr; SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; TENTER("IsAdminOrSystem"); // // check if caller is Admin // if ( AllocateAndInitializeSid ( &SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin) ) { if (! CheckTokenMembership(NULL, psidAdmin, &fReturn)) { dwErr = GetLastError(); TRACE(0, "! CheckTokenMembership : %ld", dwErr); } FreeSid (psidAdmin); // // if so, scoot // if (fReturn) { goto done; } // // check if caller is localsystem // if ( AllocateAndInitializeSid ( &SystemSidAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidSystem) ) { if (! CheckTokenMembership(NULL, psidSystem, &fReturn)) { dwErr = GetLastError(); TRACE(0, "! CheckTokenMembership : %ld", dwErr); } FreeSid(psidSystem); } else { dwErr = GetLastError(); TRACE(0, "! AllocateAndInitializeSid : %ld", dwErr); } } else { dwErr = GetLastError(); TRACE(0, "! AllocateAndInitializeSid : %ld", dwErr); } done: TLEAVE(); return (fReturn); } DWORD SRLoadString(LPCWSTR pszModule, DWORD dwStringId, LPWSTR pszString, DWORD cbBytes) { DWORD dwErr = ERROR_SUCCESS; HINSTANCE hModule = NULL; if (hModule = LoadLibraryEx(pszModule, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE)) { if (! LoadString(hModule, dwStringId, pszString, cbBytes)) { dwErr = GetLastError(); } FreeLibrary(hModule); } else dwErr = GetLastError(); return dwErr; } // // replace CurrentControlSet in pszString with ControlSetxxx // void ChangeCCS(HKEY hkMount, LPWSTR pszString) { tenter("ChangeCCS"); int nCS = lstrlen(L"CurrentControlSet"); if (_wcsnicmp(pszString, L"CurrentControlSet", nCS) == 0) { WCHAR szCS[20] = L"ControlSet001"; DWORD dwCurrent = 0; HKEY hKey = NULL; if (ERROR_SUCCESS == RegOpenKeyEx(hkMount, L"Select", 0, KEY_READ, &hKey)) { if (ERROR_SUCCESS == RegReadDWORD(hKey, L"Current", &dwCurrent)) { wsprintf(szCS, L"ControlSet%03d", (int) dwCurrent); } RegCloseKey(hKey); } else { trace(0, "! RegOpenKeyEx : %ld", GetLastError()); } WCHAR szTemp[MAX_PATH]; lstrcpy(szTemp, &(pszString[nCS])); wsprintf(pszString, L"%s%s", szCS, szTemp); trace(0, "ChangeCCS: pszString = %S", pszString); } tleave(); } WCHAR * SRPathFindExtension (WCHAR * pwszPath) { WCHAR *pwszDot = NULL; if (pwszPath != NULL) for (; *pwszPath; pwszPath++) { switch (*pwszPath) { case L'.': pwszDot = pwszPath; // remember the last dot break; case L'\\': case L' ': pwszDot = NULL; // extensions can't have spaces break; // forget last dot, it was in a directory } } return pwszDot; } // In order to prevent endless loop in case of disk failure, try only up to // a predefined number. #define MAX_ALT_INDEX 1000 // // This function makes an unique alternative name of given file name, keeping // path and extension. // BOOL SRGetAltFileName( LPCWSTR cszPath, LPWSTR szAltName ) { TraceFunctEnter("SRGetAltFileName"); BOOL fRet = FALSE; WCHAR szNewPath[SR_MAX_FILENAME_LENGTH]; LPWSTR szExtPos; WCHAR szExtBuf[SR_MAX_FILENAME_LENGTH]; int nAltIdx; if (lstrlenW (cszPath) >= SR_MAX_FILENAME_LENGTH) goto Exit; ::lstrcpy( szNewPath, cszPath ); szExtPos = SRPathFindExtension( szNewPath ); if ( szExtPos != NULL ) { ::lstrcpy( szExtBuf, szExtPos ); } else { szExtBuf[0] = L'\0'; szExtPos = &szNewPath[ lstrlen(szNewPath) ]; // end of string } for ( nAltIdx = 2; nAltIdx < MAX_ALT_INDEX; nAltIdx++ ) { ::wsprintf( szExtPos, L"(%d)%s", nAltIdx, szExtBuf ); if ( ::GetFileAttributes( szNewPath ) == 0xFFFFFFFF ) break; } if ( nAltIdx == MAX_ALT_INDEX ) { ErrorTrace(0, "Couldn't get alternative name."); goto Exit; } ::lstrcpy( szAltName, szNewPath ); fRet = TRUE; Exit: TraceFunctLeave(); return( fRet ); } CSRClientLoader::CSRClientLoader() { m_hSRClient=NULL; m_hFrameDyn=NULL; } CSRClientLoader::~CSRClientLoader() { // unload library here if (m_hFrameDyn != NULL) { _VERIFY(FreeLibrary(m_hFrameDyn)); } if (m_hSRClient != NULL) { _VERIFY(FreeLibrary(m_hSRClient)); } } BOOL CSRClientLoader::LoadFrameDyn() { TraceFunctEnter("LoadFrameDyn"); WCHAR szFrameDynPath[MAX_PATH+100]; DWORD dwCharsCopied, dwBufSize,dwError; BOOL fReturn=FALSE; m_hFrameDyn=LoadLibrary(FRAMEDYN_DLL); // file name of module if (m_hFrameDyn != NULL) { // we are done. fReturn = TRUE; goto cleanup; } // framedyn.dll could not be loaded. Try to load framedyn.dll // from the explicit path. (system32\wbem\framedyn.dll) dwError = GetLastError(); ErrorTrace(0,"Failed to load framedyn.dll on first attempt. ec=%d", dwError); // get the windows system32 directory // add wbem\framedyn.dll // Call LoadLibrary on this path dwBufSize = sizeof(szFrameDynPath)/sizeof(WCHAR); dwCharsCopied=GetSystemDirectory( szFrameDynPath, //buffer for system directory dwBufSize); // size of directory buffer if (dwCharsCopied == 0) { dwError = GetLastError(); ErrorTrace(0,"Failed to load system directory. ec=%d", dwError); goto cleanup; } // check if buffer is big enough. if (dwBufSize < dwCharsCopied + sizeof(FRAMEDYN_DLL)/sizeof(WCHAR) + sizeof(WBEM_DIRECTORY)/sizeof(WCHAR)+ 3 ) { ErrorTrace(0,"Buffer not big enough. WinSys is %d chars long", dwCharsCopied); goto cleanup; } lstrcat(szFrameDynPath, L"\\" WBEM_DIRECTORY L"\\" FRAMEDYN_DLL); m_hFrameDyn=LoadLibrary(szFrameDynPath); // file name of module if (m_hFrameDyn == NULL) { // we are done. fReturn = FALSE; dwError = GetLastError(); ErrorTrace(0,"Failed to load framedyn.dll on second attempt. ec=%d", dwError); goto cleanup; } fReturn=TRUE; cleanup: TraceFunctLeave(); return fReturn; } BOOL CSRClientLoader::LoadSrClient() { TraceFunctEnter("LoadSrClient"); DWORD dwError; BOOL fReturn=FALSE; if (m_hSRClient != NULL) { fReturn=TRUE; goto cleanup; } // sometimes srclient.dll cannot be loaded because framedyn.dll // cannot be loaded because of the PATH variable being messed up. // Explicitly load framedyn.dll from %windir%\system32\wbem // and then try again. if (FALSE == LoadFrameDyn()) { ErrorTrace(0,"Failed to load framedyn.dll"); // we can still try to load srclient.dll } m_hSRClient=LoadLibrary(L"srclient.dll"); // file name of module if (m_hSRClient == NULL) { dwError = GetLastError(); ErrorTrace(0,"Failed to load srclient.dll. ec=%d", dwError); goto cleanup; } fReturn=TRUE; cleanup: TraceFunctLeave(); return fReturn; }