//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1998. // // File: util.cpp // // Contents: Miscellaneous utility functions // // History: // //--------------------------------------------------------------------------- #include "stdafx.h" #include "util.h" #include "wrapper.h" #include "defvals.h" #include "resource.h" #include #include "snapmgr.h" extern "C" { #include "getuser.h" } #define ILLEGAL_FILENAME_CHARS L"\"+,;<=>" #define ILLEGAL_FILENAME_CHARS1 L"\\\\ \\/ // /\\" #define ILLEGAL_FILENAME_CHARS2 L"\\ /" ////////////////////////////////////////////////////////////////////////////////////////// // CWriteHmtlFile body. // //+------------------------------------------------------------------------------------------- // CWriteHtmlFile::CWriteHtmlFile // // Initialize the class. // //-------------------------------------------------------------------------------------------- CWriteHtmlFile::CWriteHtmlFile() { m_hFileHandle = INVALID_HANDLE_VALUE; m_bErrored = FALSE; } //+------------------------------------------------------------------------------------------- // CWriteHtmlFile::~CWriteHtmlFile // // Write the end of the html file and close the handle. // //-------------------------------------------------------------------------------------------- CWriteHtmlFile::~CWriteHtmlFile() { // // Close the file handle, but don't delete the HTML file, unless there was an // error during some write proccess. // Close(m_bErrored); } //+------------------------------------------------------------------------------------------- // CWriteHtmlFile::Close // // Closes the HTML file handle, if [bDelete] is true then the file is deleted. // // Arguments: [bDelete] - Close and delete the file. // // Returns: ERROR_SUCCESS; //-------------------------------------------------------------------------------------------- DWORD CWriteHtmlFile::Close( BOOL bDelete ) { if(m_hFileHandle == INVALID_HANDLE_VALUE){ return ERROR_SUCCESS; } if(bDelete){ CloseHandle(m_hFileHandle); DeleteFile(m_strFileName ); } else { Write( IDS_HTMLERR_END ); CloseHandle( m_hFileHandle ); } m_hFileHandle = INVALID_HANDLE_VALUE; return ERROR_SUCCESS; } //+------------------------------------------------------------------------------------------- // CWriteHtmlFile::GetFileName // // Copies the file name associated with this class to [pstrFileName]. // // Arguments: [pstrFileName] - A CString object which will contain the file name // on return. // // Returns: 0 - If Create has not been called, or the HTML file is invalid for // some reason. This could be caused by a bad write. // The size in characters of the file name. // //-------------------------------------------------------------------------------------------- int CWriteHtmlFile::GetFileName( LPTSTR pszFileName, UINT nSize ) { if(m_strFileName.IsEmpty() || m_hFileHandle == INVALID_HANDLE_VALUE || m_bErrored){ return 0; } if(pszFileName && (int)nSize > m_strFileName.GetLength()){ //This is a safe usage. lstrcpy(pszFileName, m_strFileName); } return m_strFileName.GetLength(); } //+------------------------------------------------------------------------------------------- // CWriteHtmlFile::Write // // Writes a string resource to the html file at the current file position. // // Arguments: [uRes] - The String resource to load and write to the html. // // Returns: If the string can't be loaded then an error will be returned. // See CWriteHtmlFile::Write( LPCTSTR ) for other errors. //-------------------------------------------------------------------------------------------- DWORD CWriteHtmlFile::Write( UINT uRes ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CString str; if( !str.LoadString(uRes) ){ return GetLastError(); } #if defined(UNICODE) || defined(_UNICODE) if ( uRes == IDS_HTMLERR_HEADER ){ WCHAR wszByteOrderMark[2] = {0xFEFF, 0x0000}; CString strByteOrderMark = wszByteOrderMark; return Write( strByteOrderMark + str ); } else #endif return Write( str ); } //+------------------------------------------------------------------------------------------- // CWriteHtmlFile::Write // // Writes a string to an html file. // // Arguments: [pszString] - The string to write. // // Returns: ERROR_NOT_READ - if Create has not been called, or the file could not // not be created. // Other errors returned by WriteFile(); //-------------------------------------------------------------------------------------------- DWORD CWriteHtmlFile::Write(LPCTSTR pszString, ... ) { if(m_hFileHandle == INVALID_HANDLE_VALUE) { return ERROR_NOT_READY; } CString szWrite; va_list marker; va_start(marker, pszString); //This is not a safe usage. Avoid using vswprintf(). Raid #555867. Yanggao. szWrite.FormatV(pszString, marker); va_end(marker); DWORD dwRight; if( !WriteFile( m_hFileHandle, szWrite, sizeof(TCHAR) * szWrite.GetLength(), &dwRight, NULL) ) { // // Check the error state of the right. Set m_bErrored if there was something wrong // with the write. // dwRight = GetLastError(); if(dwRight != ERROR_SUCCESS) { m_bErrored = TRUE; } } else { dwRight = ERROR_SUCCESS; } return dwRight; } DWORD CWriteHtmlFile::CopyTextFile( LPCTSTR pszFile, DWORD dwPosLow, BOOL bInterpret ) { HANDLE handle; // // Try to open the file for reading. // handle = ExpandAndCreateFile( pszFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL ); if(handle == INVALID_HANDLE_VALUE) { return GetLastError(); } LONG dwPosHigh = 0; WCHAR szText[256]; char szRead[256]; BOOL IsMulti; DWORD isUnicode; // // Determine if the file is a unicode text file. // if( ReadFile(handle, szText, 100 * sizeof(WCHAR), (DWORD *)&dwPosHigh, NULL ) == 0 ) //Raid #prefast { CloseHandle(handle ); return GetLastError(); } if(dwPosHigh ) { isUnicode = IsTextUnicode( szText, dwPosHigh, NULL ); } // // Set the pos we want to start from // dwPosHigh = 0; SetFilePointer( handle, dwPosLow, &dwPosHigh, FILE_BEGIN ); if( GetLastError() != ERROR_SUCCESS ) { CloseHandle(handle ); return GetLastError(); } DWORD dwErr = ERROR_SUCCESS; do { start: // // Read 254 total bytes from the file. We don't care about the error returned // by read, as long as read does not set dwPosHigh to something. // dwPosHigh = 0; if( ReadFile( handle, szRead, 254, (DWORD *)&dwPosHigh, NULL ) == 0 || dwPosHigh == 0) //Raid #prefast { CloseHandle(handle ); return GetLastError(); } // // If the file is not considered unicode then convert it to a unicode file. // ZeroMemory(szText, sizeof(WCHAR) * 256); if(!isUnicode) { //This is a safe usage. dwPosHigh = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szRead, dwPosHigh, szText, 255 ); } else { // // Just copy the text to the szText buffer and get the number of UNICODE // characters. // //This is a safe usage. memcpy(szText, szRead, dwPosHigh); dwPosHigh = wcslen(szText); } PWSTR pszWrite = szText; LONG i = 0; if( bInterpret ) { // // Write out line breaks. // for(;i < dwPosHigh; i++) { //Bug 141526, Yanggao, 3/20/2001 if( L'<' == szText[i] ) { szText[i] = 0; Write(pszWrite); Write(L"<"); pszWrite = &(szText[i + 1]); } if( L'%' == szText[i] ) //Raid #624384,Yanggao { szText[i] = 0; Write(pszWrite); Write(L"%%"); pszWrite = &(szText[i + 1]); } if( L'\r' == szText[i] || L'\n' == szText[i] ) { if( i + 1 >= dwPosHigh ) { szText[i] = 0; Write(pszWrite); SetFilePointer( handle, -(isUnicode ? 2:1), NULL, FILE_CURRENT); // // Read once again. // goto start; } // // Check to see if this is a valid line break // i++; if( L'\r' == szText[i] || L'\n' == szText[i] && szText[i] != szText[i - 1] ) { szText[i - 1] = 0; dwErr = Write( pszWrite ); if( dwErr != ERROR_SUCCESS) { break; } dwErr = Write( L"
" ); if( dwErr != ERROR_SUCCESS) { break; } pszWrite = &(szText[i + 1]); } else { // // This is not a valid line break, contintue with check with next character // i--; } } } } // // Write the rest of the text. // if(dwErr == ERROR_SUCCESS) { Write( pszWrite ); } else { break; } } while( dwPosHigh ); CloseHandle(handle ); return ERROR_SUCCESS; } //+------------------------------------------------------------------------------------------- // CWriteHtmlFile::Create // // Creates an html file, and starts the write proccess. If [pszFile] is null, then // this function creates a temporary file in the GetTempPath() directory with a name // like SCE###.HTM // // Arguments: [pszFile] - Optional parameter for file name // // returns: ERROR_SUCCESS - If creating the file was successful. // If the file exists then ERROR_FILE_EXISTS is returned. // //-------------------------------------------------------------------------------------------- DWORD CWriteHtmlFile::Create(LPCTSTR pszFile ) { if(!pszFile){ // // Create a temporary file name. // DWORD dwSize = GetTempPath(0, NULL); if(dwSize){ TCHAR szTempFile[512]; // // Get the temp path. // LPTSTR pszPath = (LPTSTR)LocalAlloc( 0, (dwSize + 1) * sizeof(TCHAR)); if(!pszPath){ return ERROR_OUTOFMEMORY; } GetTempPath( dwSize + 1, pszPath ); pszPath[dwSize - 1] = 0; if( GetTempFileName( pszPath, TEXT("SCE"), 0, szTempFile) ){ //This is not safe usage. Raid #555912, yanggao. LocalFree(pszPath); // // Create the temporary file. // DeleteFile( szTempFile ); int i = lstrlen(szTempFile); while(i--){ if( szTempFile[i] == L'.' ){ break; } } if(i + 3 >= lstrlen(szTempFile)){ return ERROR_OUTOFMEMORY; } // // We want to create an html file. // i++; szTempFile[i] = L'h'; szTempFile[i + 1] = L't'; szTempFile[i + 2] = L'm'; m_strFileName = szTempFile; } else { LocalFree(pszPath); } } } else { m_strFileName = pszFile; } if(m_strFileName.IsEmpty()){ return ERROR_FILE_NOT_FOUND; } // // Open the file for writing // m_hFileHandle = ExpandAndCreateFile( m_strFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL ); if(m_hFileHandle == INVALID_HANDLE_VALUE){ return GetLastError(); } // // Write HTML header // return Write( IDS_HTMLERR_HEADER ); } //+-------------------------------------------------------------------------- // // Function: MyRegQueryValue // // Synopsis: Reads a registry value into [*Value] // // // Arguments: [hKeyRoot] - // [SubKey] - // [ValueName] - // [Value] - // [pRegType] - // // Modifies: *[Value] // *[pRegType] // // History: // //--------------------------------------------------------------------------- DWORD MyRegQueryValue( HKEY hKeyRoot, LPCTSTR SubKey, LPCTSTR ValueName, PVOID *Value, LPDWORD pRegType ) { DWORD Rcode; DWORD dSize=0; HKEY hKey=NULL; BOOL FreeMem=FALSE; if (( Rcode = RegOpenKeyEx(hKeyRoot, SubKey, 0, KEY_READ, &hKey )) == ERROR_SUCCESS ) { //This is a safe usage. It only queries data type. if (( Rcode = RegQueryValueEx(hKey, ValueName, 0, pRegType, NULL, &dSize )) == ERROR_SUCCESS ) { switch (*pRegType) { case REG_DWORD: case REG_DWORD_BIG_ENDIAN: //This is a safe usage. The data type is not REG_SZ. Rcode = RegQueryValueEx(hKey, ValueName, 0, pRegType, (BYTE *)(*Value), &dSize ); if ( Rcode != ERROR_SUCCESS ) { if ( *Value != NULL ) *((BYTE *)(*Value)) = 0; } break; case REG_SZ: case REG_EXPAND_SZ: case REG_MULTI_SZ: if ( *Value == NULL ) { *Value = (PVOID)LocalAlloc( LPTR, (dSize+1)*sizeof(TCHAR)); FreeMem = TRUE; } if ( *Value == NULL ) { Rcode = ERROR_NOT_ENOUGH_MEMORY; } else { //This is not a safe usage. make sure *Value is terminated. Raid #555873. yanggao. Rcode = RegQueryValueEx(hKey,ValueName,0, pRegType,(BYTE *)(*Value), &dSize ); if ( (Rcode != ERROR_SUCCESS) && FreeMem ) { LocalFree(*Value); *Value = NULL; } } break; default: Rcode = ERROR_INVALID_DATATYPE; break; } } } if ( hKey ) { RegCloseKey( hKey ); } return(Rcode); } //+-------------------------------------------------------------------------- // // Function: MyRegSetValue // // Synopsis: Writes a registry value into [*Value] // // // Arguments: [hKeyRoot] - // [SubKey] - // [ValueName] - // [Value] - // [cbValue] - // [pRegType] - // // // History: // //--------------------------------------------------------------------------- DWORD MyRegSetValue( HKEY hKeyRoot, LPCTSTR SubKey, LPCTSTR ValueName, const BYTE *Value, const DWORD cbValue, const DWORD pRegType ) { DWORD Rcode=0; HKEY hKey=NULL; BOOL FreeMem=FALSE; if (( Rcode = RegCreateKeyEx(hKeyRoot, SubKey, 0, 0, 0, KEY_READ|KEY_SET_VALUE|KEY_CREATE_SUB_KEY, NULL, &hKey, NULL)) == ERROR_SUCCESS ) { Rcode = RegSetValueEx(hKey, ValueName, 0, pRegType, Value, cbValue ); } if ( hKey ) { RegCloseKey( hKey ); } return(Rcode); } BOOL FilePathExist(LPCTSTR Name, BOOL IsPath, int Flag) // Flag = 0 - check file, Flag = 1 - check path { // TODO: struct _wfinddata_t FileInfo; intptr_t hFile; BOOL bExist = FALSE; if ( (IsPath && Flag == 1) || (!IsPath && Flag == 0) ) { // must be exact match hFile = _wfindfirst((LPTSTR)Name, &FileInfo); if ( hFile != -1 ) {// find it if ( FileInfo.attrib & _A_SUBDIR ) { if ( Flag == 1) bExist = TRUE; } else if ( Flag == 0 ) bExist = TRUE; } _findclose(hFile); return bExist; } if ( IsPath && Flag == 0 ) { // invalid parameter return bExist; } // IsPath = FALSE and Flag == 1 (a file name is passed in and search for its path) CString tmpstr = CString(Name); int nPos = tmpstr.ReverseFind(L'\\'); if ( nPos > 2 ) { hFile = _wfindfirst(tmpstr.GetBufferSetLength(nPos), &FileInfo); if ( hFile != -1 && FileInfo.attrib & _A_SUBDIR ) bExist = TRUE; _findclose(hFile); } else if ( nPos == 2 && Name[1] == L':') bExist = TRUE; return bExist; } //+-------------------------------------------------------------------------- // // Function: MyFormatResMessage // // Synopsis: Creates an error message combining a description of an error // returned from an SCE function (in rc), the extended description // of that error (in errBuf), and a custom error message // (in residMessage) // // Arguments: [rc] - The return code of an SCE function // [residMessage] - the resource id of the base error message // [errBuf] - Extended error info returned from an SCE function // [strOut] - A CString to hold the formatted message // // Modifies: [strOut] // // History: // //--------------------------------------------------------------------------- void MyFormatResMessage(SCESTATUS rc, // in UINT residMessage, // in PSCE_ERROR_LOG_INFO errBuf,// in, optional CString& strOut) // out { CString strMessage; AFX_MANAGE_STATE(AfxGetStaticModuleState()); // // If the LoadResource fails then strMessage will be empty // It'll still be better to format the rest of the message than // to return an empty strOut. // strMessage.LoadString(residMessage); MyFormatMessage(rc,strMessage,errBuf,strOut); } //+-------------------------------------------------------------------------- // // Function: MyFormatMessage // // Synopsis: Creates an error message combining a description of an error // returned from an SCE function (in rc), the extended description // of that error (in errBuf), and a custom error message (in mes) // // Arguments: [rc] - The return code of an SCE function // [mes] - The base message // [errBuf] - Extended error info returned from an SCE function // [strOut] - A CString to hold the formatted message // // Modifies: [strOut] // // History: // //--------------------------------------------------------------------------- void MyFormatMessage(SCESTATUS rc, // in LPCTSTR mes, // in PSCE_ERROR_LOG_INFO errBuf, // in, optional CString& strOut) // out { LPVOID lpMsgBuf=NULL; if ( rc != SCESTATUS_SUCCESS ) { // // translate SCESTATUS into DWORD // DWORD win32 = SceStatusToDosError(rc); // // get error description of rc // //This is a safe usage. The function is responsible to allocate memery. FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, win32, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR)&lpMsgBuf, 0, NULL ); } if ( lpMsgBuf != NULL ) { strOut = (LPTSTR)lpMsgBuf; LocalFree(lpMsgBuf); lpMsgBuf = NULL; } else { strOut.Empty(); } CString strEx; //Raid #485372, yanggao, 11/30/2001 switch(rc) { case SCESTATUS_INVALID_PARAMETER: case SCESTATUS_RECORD_NOT_FOUND: case SCESTATUS_INVALID_DATA: case SCESTATUS_OBJECT_EXIST: case SCESTATUS_PROFILE_NOT_FOUND: strEx.LoadString(IDS_OBJECT_FAILED_NOTE); break; case SCESTATUS_ACCESS_DENIED: case SCESTATUS_CANT_DELETE: strEx.LoadString(IDS_SAVE_FAILED_NOTE); break; case SCESTATUS_PREFIX_OVERFLOW: case SCESTATUS_ALREADY_RUNNING: case SCESTATUS_OTHER_ERROR: case SCESTATUS_BUFFER_TOO_SMALL: case SCESTATUS_BAD_FORMAT: case SCESTATUS_NOT_ENOUGH_RESOURCE: default: strEx.Empty(); break; } if( strEx.IsEmpty() ) { strOut += mes; } else { strOut = strOut + mes + L" " + strEx; } strOut += L"\n"; // // Loop through the error buffers and append each of them to strOut // for (PSCE_ERROR_LOG_INFO pErr = errBuf; pErr != NULL; pErr = pErr->next) { if (NULL == pErr) { continue; } if ( pErr->rc != NO_ERROR) { //This is a safe usage. The function is responsible to allocate memery. FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, pErr->rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR)&lpMsgBuf, 0, NULL ); if ( lpMsgBuf ) { strOut += (LPTSTR)lpMsgBuf; LocalFree(lpMsgBuf); lpMsgBuf = NULL; } } if (pErr->buffer) { strOut += pErr->buffer; strOut += L"\n"; } } } DWORD FormatDBErrorMessage( SCESTATUS sceStatus, LPCTSTR pszDatabase, CString &strOut ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); UINT uErr = 0; switch (sceStatus) { case SCESTATUS_SUCCESS: return ERROR_INVALID_PARAMETER; case SCESTATUS_INVALID_DATA: uErr = IDS_DBERR_INVALID_DATA; break; case SCESTATUS_PROFILE_NOT_FOUND: uErr = IDS_DBERR5_PROFILE_NOT_FOUND; break; case SCESTATUS_BAD_FORMAT: uErr = IDS_DBERR_BAD_FORMAT; break; case SCESTATUS_BUFFER_TOO_SMALL: case SCESTATUS_NOT_ENOUGH_RESOURCE: uErr = IDS_DBERR_NOT_ENOUGH_RESOURCE; break; case SCESTATUS_ACCESS_DENIED: uErr = IDS_DBERR5_ACCESS_DENIED; break; case SCESTATUS_NO_TEMPLATE_GIVEN: uErr = IDS_DBERR_NO_TEMPLATE_GIVEN; break; case SCESTATUS_SPECIAL_ACCOUNT: //Raid #589139, DCR, yanggao, 4/10/2002. uErr = IDS_ERR_PRIVILEGE; //.Net use IDS_ERR_PRIVILEGE instead of IDS_DBERR5_ACCESS_DENIED which is used for XPSP1. break; case ERROR_NONE_MAPPED: //Raid #625342 uErr = IDS_NO_ACCOUNT_MAP; break; default: uErr = IDS_DBERR_OTHER_ERROR; } if ( strOut.LoadString(uErr) ) { return ERROR_SUCCESS; } return ERROR_INVALID_PARAMETER; } DWORD SceStatusToDosError(SCESTATUS SceStatus) { switch (SceStatus) { case SCESTATUS_SUCCESS: return(NO_ERROR); case SCESTATUS_OTHER_ERROR: return(ERROR_EXTENDED_ERROR); case SCESTATUS_INVALID_PARAMETER: return(ERROR_INVALID_PARAMETER); case SCESTATUS_RECORD_NOT_FOUND: return(ERROR_RESOURCE_DATA_NOT_FOUND); case SCESTATUS_INVALID_DATA: return(ERROR_INVALID_DATA); case SCESTATUS_OBJECT_EXIST: return(ERROR_FILE_EXISTS); case SCESTATUS_BUFFER_TOO_SMALL: return(ERROR_INSUFFICIENT_BUFFER); case SCESTATUS_PROFILE_NOT_FOUND: return(ERROR_FILE_NOT_FOUND); case SCESTATUS_BAD_FORMAT: return(ERROR_BAD_FORMAT); case SCESTATUS_NOT_ENOUGH_RESOURCE: return(ERROR_NOT_ENOUGH_MEMORY); case SCESTATUS_ACCESS_DENIED: case SCESTATUS_SPECIAL_ACCOUNT: //Raid #589139, DCR, yanggao, 4/10/2002. return(ERROR_ACCESS_DENIED); case SCESTATUS_CANT_DELETE: return(ERROR_CURRENT_DIRECTORY); case SCESTATUS_PREFIX_OVERFLOW: return(ERROR_BUFFER_OVERFLOW); case SCESTATUS_ALREADY_RUNNING: return(ERROR_SERVICE_ALREADY_RUNNING); default: return(ERROR_EXTENDED_ERROR); } } //+-------------------------------------------------------------------------- // // Function: CreateNewProfile // // Synopsis: Create a new tempate with default values in the ProfileName location // // Returns: TRUE if a template ends up in the ProfileName file // FALSE otherwise // // History: // //--------------------------------------------------------------------------- BOOL CreateNewProfile(CString ProfileName,PSCE_PROFILE_INFO *ppspi) { SCESTATUS status; SCE_PROFILE_INFO *pTemplate; // // profile name must end with .inf // int nLen = ProfileName.GetLength (); // start searching at the last 4 position if ( ProfileName.Find (L".inf", nLen-4) != nLen-4 ) { return FALSE; } // // if the profile already exists then we don't need to do anything // if ( FilePathExist( (LPCTSTR)ProfileName, FALSE, 0) ) { return TRUE; } // // Make sure the directory for the profile exists // status = SceCreateDirectory(ProfileName,FALSE,NULL); if (SCESTATUS_SUCCESS != status) { return FALSE; } pTemplate = (SCE_PROFILE_INFO*)LocalAlloc(LPTR,sizeof(SCE_PROFILE_INFO)); if (!pTemplate) { return FALSE; } #ifdef FILL_WITH_DEFAULT_VALUES SCE_PROFILE_INFO *pDefault = GetDefaultTemplate(); // // Fill with default values // pTemplate->Type = SCE_ENGINE_SCP; #define CD(X) pTemplate->X = pDefault->X; #else // !FILL_WITH_DEFAULT_VALUES #define CD(X) pTemplate->X = SCE_NO_VALUE; #endif // !FILL_WITH_DEFAULT_VALUES CD(MinimumPasswordAge); CD(MaximumPasswordAge); CD(MinimumPasswordLength); CD(PasswordComplexity); CD(PasswordHistorySize); CD(LockoutBadCount); CD(ResetLockoutCount); CD(LockoutDuration); CD(RequireLogonToChangePassword); CD(ForceLogoffWhenHourExpire); CD(EnableAdminAccount); CD(EnableGuestAccount); // These members aren't declared in NT4 CD(ClearTextPassword); CD(AuditDSAccess); CD(AuditAccountLogon); CD(LSAAnonymousNameLookup); CD(MaximumLogSize[0]); CD(MaximumLogSize[1]); CD(MaximumLogSize[2]); CD(AuditLogRetentionPeriod[0]); CD(AuditLogRetentionPeriod[1]); CD(AuditLogRetentionPeriod[2]); CD(RetentionDays[0]); CD(RetentionDays[1]); CD(RetentionDays[2]); CD(RestrictGuestAccess[0]); CD(RestrictGuestAccess[1]); CD(RestrictGuestAccess[2]); CD(AuditSystemEvents); CD(AuditLogonEvents); CD(AuditObjectAccess); CD(AuditPrivilegeUse); CD(AuditPolicyChange); CD(AuditAccountManage); CD(AuditProcessTracking); #ifdef FILL_WITH_DEFAULT_VALUES // // These two are strings rather than DWORDs // if (pDefault->NewAdministratorName) { pTemplate->NewAdministratorName = (LPTSTR) LocalAlloc(LPTR,(lstrlen(pDefault->NewAdministratorName)+1)*sizeof(TCHAR)); if (pTemplate->NewAdministratorName) { //This may not be a safe usage. pTemplate->NewAdministratorName and pDefault->NewAdministratorName are both PWSTR. Consider fix. lstrcpy(pTemplate->NewAdministratorName, pDefault->NewAdministratorName); } } if (pDefault->NewGuestName) { pTemplate->NewGuestName = (LPTSTR) LocalAlloc(LPTR,(lstrlen(pDefault->NewGuestName)+1)*sizeof(TCHAR)); if (pTemplate->NewGuestName) { //This may not be a safe usage. pTemplate->NewGuestName and pDefault->NewGuestName are both PWSTR. Consider fix. lstrcpy(pTemplate->NewGuestName, pDefault->NewGuestName); } } #endif // FILL_WITH_DEFAULT_VALUES #undef CD status = SceWriteSecurityProfileInfo(ProfileName, AREA_ALL, pTemplate, NULL); if (ppspi) { *ppspi = pTemplate; } else { SceFreeProfileMemory(pTemplate); } return (SCESTATUS_SUCCESS == status); } BOOL VerifyKerberosInfo(PSCE_PROFILE_INFO pspi) { if (pspi->pKerberosInfo) { return TRUE; } pspi->pKerberosInfo = (PSCE_KERBEROS_TICKET_INFO) LocalAlloc(LPTR,sizeof(SCE_KERBEROS_TICKET_INFO)); if (pspi->pKerberosInfo) { pspi->pKerberosInfo->MaxTicketAge = SCE_NO_VALUE; pspi->pKerberosInfo->MaxRenewAge = SCE_NO_VALUE; pspi->pKerberosInfo->MaxServiceAge = SCE_NO_VALUE; pspi->pKerberosInfo->MaxClockSkew = SCE_NO_VALUE; pspi->pKerberosInfo->TicketValidateClient = SCE_NO_VALUE; return TRUE; } return FALSE; } BOOL SetProfileInfo(LONG_PTR dwItem,LONG_PTR dwNew,PEDITTEMPLATE pEdit) { if (!pEdit) { return FALSE; } pEdit->SetDirty(AREA_SECURITY_POLICY); switch (dwItem) { case IDS_MAX_PAS_AGE: pEdit->pTemplate->MaximumPasswordAge = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_MIN_PAS_AGE: pEdit->pTemplate->MinimumPasswordAge = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_MIN_PAS_LEN: pEdit->pTemplate->MinimumPasswordLength = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_PAS_UNIQUENESS: pEdit->pTemplate->PasswordHistorySize = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_PAS_COMPLEX: pEdit->pTemplate->PasswordComplexity = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_REQ_LOGON: pEdit->pTemplate->RequireLogonToChangePassword = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_LOCK_COUNT: pEdit->pTemplate->LockoutBadCount = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_LOCK_RESET_COUNT: pEdit->pTemplate->ResetLockoutCount = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_LOCK_DURATION: pEdit->pTemplate->LockoutDuration = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_FORCE_LOGOFF: pEdit->pTemplate->ForceLogoffWhenHourExpire = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_ENABLE_ADMIN: pEdit->pTemplate->EnableAdminAccount = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_ENABLE_GUEST: pEdit->pTemplate->EnableGuestAccount = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_LSA_ANON_LOOKUP: pEdit->pTemplate->LSAAnonymousNameLookup = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_NEW_ADMIN: if (pEdit->pTemplate->NewAdministratorName) { LocalFree(pEdit->pTemplate->NewAdministratorName); } if (dwNew && (dwNew != (LONG_PTR)ULongToPtr(SCE_NO_VALUE))) { pEdit->pTemplate->NewAdministratorName = (PWSTR)LocalAlloc(LPTR,(lstrlen((PWSTR)dwNew)+1)*sizeof(WCHAR)); if (pEdit->pTemplate->NewAdministratorName) { //This may not be a safe usage. pTemplate->NewAdministratorName and dwNew are both PWSTR. Consider fix. lstrcpy(pEdit->pTemplate->NewAdministratorName,(PWSTR)dwNew); } } else { pEdit->pTemplate->NewAdministratorName = NULL; } break; case IDS_NEW_GUEST: if (pEdit->pTemplate->NewGuestName) { LocalFree(pEdit->pTemplate->NewGuestName); } if (dwNew && (dwNew != (LONG_PTR)ULongToPtr(SCE_NO_VALUE))) { pEdit->pTemplate->NewGuestName = (PWSTR)LocalAlloc(LPTR,(lstrlen((PWSTR)dwNew)+1)*sizeof(WCHAR)); if (pEdit->pTemplate->NewGuestName) { //This may not be a safe usage. pTemplate->NewGuestName and dwNew are both PWSTR. Consider fix. lstrcpy(pEdit->pTemplate->NewGuestName,(PWSTR)dwNew); } } else { pEdit->pTemplate->NewGuestName = NULL; } break; case IDS_SYS_LOG_MAX: pEdit->pTemplate->MaximumLogSize[EVENT_TYPE_SYSTEM] = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_SYS_LOG_RET: pEdit->pTemplate->AuditLogRetentionPeriod[EVENT_TYPE_SYSTEM] = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_SYS_LOG_DAYS: pEdit->pTemplate->RetentionDays[EVENT_TYPE_SYSTEM] = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_SEC_LOG_MAX: pEdit->pTemplate->MaximumLogSize[EVENT_TYPE_SECURITY] = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_SEC_LOG_RET: pEdit->pTemplate->AuditLogRetentionPeriod[EVENT_TYPE_SECURITY] = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_SEC_LOG_DAYS: pEdit->pTemplate->RetentionDays[EVENT_TYPE_SECURITY] = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_APP_LOG_MAX: pEdit->pTemplate->MaximumLogSize[EVENT_TYPE_APP] = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_APP_LOG_RET: pEdit->pTemplate->AuditLogRetentionPeriod[EVENT_TYPE_APP] = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_APP_LOG_DAYS: pEdit->pTemplate->RetentionDays[EVENT_TYPE_APP] = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_SYSTEM_EVENT: pEdit->pTemplate->AuditSystemEvents = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_LOGON_EVENT: pEdit->pTemplate->AuditLogonEvents = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_OBJECT_ACCESS: pEdit->pTemplate->AuditObjectAccess = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_PRIVILEGE_USE: pEdit->pTemplate->AuditPrivilegeUse = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_POLICY_CHANGE: pEdit->pTemplate->AuditPolicyChange = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_ACCOUNT_MANAGE: pEdit->pTemplate->AuditAccountManage = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_PROCESS_TRACK: pEdit->pTemplate->AuditProcessTracking = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_DIRECTORY_ACCESS: pEdit->pTemplate->AuditDSAccess = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_ACCOUNT_LOGON: pEdit->pTemplate->AuditAccountLogon = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_SYS_LOG_GUEST: pEdit->pTemplate->RestrictGuestAccess[EVENT_TYPE_SYSTEM] = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_SEC_LOG_GUEST: pEdit->pTemplate->RestrictGuestAccess[EVENT_TYPE_SECURITY] = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_APP_LOG_GUEST: pEdit->pTemplate->RestrictGuestAccess[EVENT_TYPE_APP] = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_CLEAR_PASSWORD: pEdit->pTemplate->ClearTextPassword = (DWORD)PtrToUlong((PVOID)dwNew); break; case IDS_KERBEROS_MAX_SERVICE: if (VerifyKerberosInfo(pEdit->pTemplate)) { pEdit->pTemplate->pKerberosInfo->MaxServiceAge = (DWORD)PtrToUlong((PVOID)dwNew); } break; case IDS_KERBEROS_MAX_CLOCK: if (VerifyKerberosInfo( pEdit->pTemplate)) { pEdit->pTemplate->pKerberosInfo->MaxClockSkew = (DWORD)PtrToUlong((PVOID)dwNew); } break; case IDS_KERBEROS_VALIDATE_CLIENT: if (VerifyKerberosInfo( pEdit->pTemplate)) { pEdit->pTemplate->pKerberosInfo->TicketValidateClient = (DWORD)PtrToUlong((PVOID)dwNew); } break; case IDS_KERBEROS_MAX_AGE: if (VerifyKerberosInfo( pEdit->pTemplate)) { pEdit->pTemplate->pKerberosInfo->MaxTicketAge = (DWORD)PtrToUlong((PVOID)dwNew); } break; case IDS_KERBEROS_RENEWAL: if (VerifyKerberosInfo( pEdit->pTemplate)) { pEdit->pTemplate->pKerberosInfo->MaxRenewAge = (DWORD)PtrToUlong((PVOID)dwNew); } break; default: return FALSE; } return TRUE; } // // FUNCTION: ErrorHandlerEx(WORD, LPSTR) // // PURPOSE: Calls GetLastError() and uses FormatMessage() to display the // textual information of the error code along with the file // and line number. // // PARAMETERS: // wLine - line number where the error occured // lpszFile - file where the error occured // // RETURN VALUE: // none // // COMMENTS: // This function has a macro ErrorHandler() which handles filling in // the line number and file name where the error occured. ErrorHandler() // is always used instead of calling this function directly. // void ErrorHandlerEx( WORD wLine, LPTSTR lpszFile ) { LPVOID lpvMessage; DWORD dwError; CString szBuffer; // The the text of the error message //This is a safe usage. dwError = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPTSTR)&lpvMessage, 0, NULL); // Check to see if an error occured calling FormatMessage() if (0 == dwError) { //This is not a safe usage. avoid using wsprintf. Raid #555867. Yanggao. szBuffer.Format(TEXT("An error occured calling FormatMessage().") TEXT("Error Code %d"), GetLastError()); MessageBox(NULL, szBuffer, TEXT("Security Configuration Editor"), MB_ICONSTOP | MB_ICONEXCLAMATION); return; } // Display the error message //This is not a safe usage. avoid using wsprinf. Raid #555867. Yanggao. szBuffer.Format(TEXT("Generic, Line=%d, File=%s"), wLine, lpszFile); MessageBox(NULL, (LPTSTR)lpvMessage, szBuffer, MB_ICONEXCLAMATION | MB_OK); return; } BOOL GetSceStatusString(SCESTATUS status, CString *strStatus) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); if (!strStatus || (status > SCESTATUS_SERVICE_NOT_SUPPORT)) { return false; } return strStatus->LoadString(status + IDS_SCESTATUS_SUCCESS); } //+--------------------------------------------------------------------------------------------- // EnumLangProc // // Creates the lanuage ID for the resource attached to the DLL. The function only enumerates // on lanuage. // // Arguments: - See help on EnumResLangProc in the SDK Doc. // // Returns: - Returns FALSE because we only want the very first lanuage enumerated. // //+--------------------------------------------------------------------------------------------- BOOL CALLBACK EnumLangProc( HMODULE hMod, LPCTSTR pszType, LPCTSTR pszName, WORD wIDLanguage, LONG_PTR lParam ) { // // We only want the very first enumerated type, so create the language ID // and exit this enumeration. // *((DWORD *)lParam) = wIDLanguage; return FALSE; } bool GetRightDisplayName(LPCTSTR szSystemName, LPCTSTR szName, LPTSTR szDisp, LPDWORD lpcbDisp) { LPTSTR szLCName; DWORD dwLang; int i; if (!szDisp || !szName) { return false; } // // Enumerate our resource to find out what language the resource is in. // DWORD dwDefaultLang; dwDefaultLang = GetUserDefaultUILanguage(); LCID localeID = MAKELCID(dwDefaultLang, SORT_DEFAULT); LCID langDefault = GetThreadLocale(); SetThreadLocale( localeID ); *lpcbDisp = dwDefaultLang; DWORD cBufSize=*lpcbDisp; BOOL bFound; bFound = LookupPrivilegeDisplayName(szSystemName,szName,szDisp,lpcbDisp,&dwLang); if ( bFound && dwDefaultLang != dwLang && szSystemName ) { // not the language I am looking for // search on local system *lpcbDisp = cBufSize; bFound = LookupPrivilegeDisplayName(NULL,szName,szDisp,lpcbDisp,&dwLang); } SetThreadLocale(langDefault); //Prefast warning 400: Using 'lstrcmpiW' to perform a case-insensitive compare to constant string. //Yields unexpected result in non-English locales. Currently they are always English locale. if (!bFound) { if (0 == _wcsicmp(szName,L"senetworklogonright")) { LoadString(AfxGetInstanceHandle(),IDS_SE_NETWORK_LOGON_RIGHT,szDisp,*lpcbDisp); } else if (0 == _wcsicmp(szName,L"seinteractivelogonright")) { LoadString(AfxGetInstanceHandle(),IDS_SE_INTERACTIVE_LOGON_RIGHT,szDisp,*lpcbDisp); } else if (0 == _wcsicmp(szName,L"sebatchlogonright")) { LoadString(AfxGetInstanceHandle(),IDS_SE_BATCH_LOGON_RIGHT,szDisp,*lpcbDisp); } else if (0 == _wcsicmp(szName,L"seservicelogonright")) { LoadString(AfxGetInstanceHandle(),IDS_SE_SERVICE_LOGON_RIGHT,szDisp,*lpcbDisp); } else if (0 == _wcsicmp(szName,L"sedenyinteractivelogonright")) { LoadString(AfxGetInstanceHandle(),IDS_DENY_LOGON_LOCALLY,szDisp,*lpcbDisp); } else if (0 == _wcsicmp(szName,L"sedenynetworklogonright")) { LoadString(AfxGetInstanceHandle(),IDS_DENY_LOGON_NETWORK,szDisp,*lpcbDisp); } else if (0 == _wcsicmp(szName,L"sedenyservicelogonright")) { LoadString(AfxGetInstanceHandle(),IDS_DENY_LOGON_SERVICE,szDisp,*lpcbDisp); } else if (0 == _wcsicmp(szName,L"sedenybatchlogonright")) { LoadString(AfxGetInstanceHandle(),IDS_DENY_LOGON_BATCH,szDisp,*lpcbDisp); } else if (0 == _wcsicmp(szName,L"sedenyremoteinteractivelogonright")) { LoadString(AfxGetInstanceHandle(),IDS_DENY_REMOTE_INTERACTIVE_LOGON,szDisp,*lpcbDisp); } else if (0 == _wcsicmp(szName,L"seremoteinteractivelogonright")) { LoadString(AfxGetInstanceHandle(),IDS_REMOTE_INTERACTIVE_LOGON,szDisp,*lpcbDisp); } else { //This is not a safe usage. Make sure szDisp is terminated. Raid #553113, yanggao lstrcpyn(szDisp,szName,*lpcbDisp-1); } } return true; } #define DPI(X) {str.Format(L"%S: %d\n",#X,pInfo->X);OutputDebugString(str);} void DumpProfileInfo(PSCE_PROFILE_INFO pInfo) { CString str; PSCE_PRIVILEGE_ASSIGNMENT ppa; PSCE_NAME_LIST pName; PSCE_GROUP_MEMBERSHIP pgm; if (!pInfo) { return; } DPI(MinimumPasswordAge); DPI(MaximumPasswordAge); DPI(MinimumPasswordLength); DPI(PasswordComplexity); DPI(PasswordHistorySize); DPI(LockoutBadCount); DPI(ResetLockoutCount); DPI(LockoutDuration); DPI(RequireLogonToChangePassword); DPI(ForceLogoffWhenHourExpire); DPI(EnableAdminAccount); DPI(EnableGuestAccount); DPI(ClearTextPassword); DPI(AuditDSAccess); DPI(AuditAccountLogon); DPI(LSAAnonymousNameLookup); // DPI(EventAuditingOnOff); DPI(AuditSystemEvents); DPI(AuditLogonEvents); DPI(AuditObjectAccess); DPI(AuditPrivilegeUse); DPI(AuditPolicyChange); DPI(AuditAccountManage); DPI(AuditProcessTracking); if (pInfo->NewGuestName) { OutputDebugString(L"NewGuestName: "); if ((DWORD_PTR)ULongToPtr(SCE_NO_VALUE) == (DWORD_PTR)pInfo->NewGuestName) { OutputDebugString(L"[[undefined]]"); } else { OutputDebugString(pInfo->NewGuestName); } OutputDebugString(L"\n"); } else { OutputDebugString(L"NewGuestName: [[absent]]\n"); } if (pInfo->NewAdministratorName) { OutputDebugString(L"NewAdministratorName: "); if ((DWORD_PTR)ULongToPtr(SCE_NO_VALUE) == (DWORD_PTR)pInfo->NewAdministratorName) { OutputDebugString(L"[[undefined]]"); } else { OutputDebugString(pInfo->NewAdministratorName); } OutputDebugString(L"\n"); } else { OutputDebugString(L"NewGuestName: [[absent]]\n"); } OutputDebugString(L"\n"); switch(pInfo->Type) { case SCE_ENGINE_SCP: ppa = pInfo->OtherInfo.scp.u.pInfPrivilegeAssignedTo; break; case SCE_ENGINE_SAP: ppa = pInfo->OtherInfo.sap.pPrivilegeAssignedTo; break; case SCE_ENGINE_SMP: ppa = pInfo->OtherInfo.smp.pPrivilegeAssignedTo; break; case SCE_ENGINE_SYSTEM: ppa = NULL; break; default: OutputDebugString(L"!!!Unknown Template Type!!!\n"); ppa = NULL; break; } while(ppa) { OutputDebugString(ppa->Name); OutputDebugString(L":"); pName = ppa->AssignedTo; while(pName) { OutputDebugString(pName->Name); OutputDebugString(L","); pName = pName->Next; } ppa = ppa->Next; OutputDebugString(L"\n"); } OutputDebugString(L"\n"); PSCE_REGISTRY_VALUE_INFO aRegValues; for(DWORD i = 0; i< pInfo->RegValueCount;i++) { OutputDebugString(pInfo->aRegValues[i].FullValueName); OutputDebugString(L":"); switch(pInfo->aRegValues[i].ValueType) { case SCE_REG_DISPLAY_STRING: OutputDebugString(pInfo->aRegValues[i].Value); break; default: str.Format(L"%d",(ULONG_PTR)pInfo->aRegValues[i].Value); OutputDebugString(str); } OutputDebugString(L"\n"); } OutputDebugString(L"\n"); pgm = pInfo->pGroupMembership; while(pgm) { OutputDebugString(L"\nGROUP: "); OutputDebugString(pgm->GroupName); OutputDebugString(L"\nMembers: "); pName = pgm->pMembers; while(pName) { OutputDebugString(pName->Name); OutputDebugString(L","); pName = pName->Next; } OutputDebugString(L"\nMember Of: "); pName = pgm->pMemberOf; while(pName) { OutputDebugString(pName->Name); OutputDebugString(L","); pName = pName->Next; } OutputDebugString(L"\n"); pgm = pgm->Next; } OutputDebugString(L"\nGROUP: "); } HRESULT MyMakeSelfRelativeSD( PSECURITY_DESCRIPTOR psdOriginal, PSECURITY_DESCRIPTOR* ppsdNew ) { ASSERT( NULL != psdOriginal ); if ( NULL == psdOriginal || NULL == ppsdNew ) { return E_INVALIDARG; } // we have to find out whether the original is already self-relative SECURITY_DESCRIPTOR_CONTROL sdc = 0; DWORD dwRevision = 0; if ( !GetSecurityDescriptorControl( psdOriginal, &sdc, &dwRevision ) ) { ASSERT( FALSE ); DWORD err = GetLastError(); return HRESULT_FROM_WIN32( err ); } DWORD cb = GetSecurityDescriptorLength( psdOriginal ) + 20; PSECURITY_DESCRIPTOR psdSelfRelativeCopy = (PSECURITY_DESCRIPTOR)LocalAlloc( LMEM_ZEROINIT, cb ); if (NULL == psdSelfRelativeCopy) { return E_UNEXPECTED; // just in case the exception is ignored } if ( sdc & SE_SELF_RELATIVE ) // the original is in self-relative format, just byte-copy it { //This is a safe usage. memcpy( psdSelfRelativeCopy, psdOriginal, cb - 20 ); } else if ( !MakeSelfRelativeSD( psdOriginal, psdSelfRelativeCopy, &cb ) ) // the original is in absolute format, convert-copy it { ASSERT( FALSE ); VERIFY( NULL == LocalFree( psdSelfRelativeCopy ) ); DWORD err = GetLastError(); return HRESULT_FROM_WIN32( err ); } *ppsdNew = psdSelfRelativeCopy; return S_OK; } PSCE_NAME_STATUS_LIST MergeNameStatusList(PSCE_NAME_LIST pTemplate, PSCE_NAME_LIST pInspect) { PSCE_NAME_LIST pTemp1; PSCE_NAME_STATUS_LIST plMerge=NULL, pTemp2; SCESTATUS rc=SCESTATUS_SUCCESS; for ( pTemp1=pTemplate; pTemp1; pTemp1=pTemp1->Next ) { rc = SceAddToNameStatusList(&plMerge, pTemp1->Name, 0, MERGED_TEMPLATE ); if ( SCESTATUS_SUCCESS != rc ) break; } if ( SCESTATUS_SUCCESS == rc ) { for ( pTemp1=pInspect; pTemp1; pTemp1=pTemp1->Next ) { for ( pTemp2=plMerge; pTemp2 != NULL ; pTemp2=pTemp2->Next ) { if ( pTemp2->Status & MERGED_INSPECT ) { // this one is processed continue; } else if ( _wcsicmp(pTemp1->Name, pTemp2->Name) == 0 ) { // find a match pTemp2->Status = MERGED_TEMPLATE | MERGED_INSPECT; break; } } if ( !pTemp2 ) { // did not find the match, add this one in rc = SceAddToNameStatusList(&plMerge, pTemp1->Name, 0, MERGED_INSPECT ); if ( SCESTATUS_SUCCESS != rc ) break; } } } if ( SCESTATUS_SUCCESS == rc ) { return plMerge; } else { SceFreeMemory(plMerge, SCE_STRUCT_NAME_STATUS_LIST); return NULL; } } SCESTATUS ConvertMultiSzToDelim( IN PWSTR pValue, IN DWORD Len, IN WCHAR DelimFrom, IN WCHAR Delim ) /* Convert the multi-sz delimiter \0 to space */ { DWORD i; for ( i=0; i 0 ) { PWSTR szName = (PWSTR)LocalAlloc(0, (nMaxLen+2)*sizeof(WCHAR)); if ( !szName ) { Win32Rc = ERROR_NOT_ENOUGH_MEMORY; } else { DWORD BufSize; DWORD index = 0; DWORD RegType; do { BufSize = nMaxLen+1; Win32Rc = RegEnumKeyEx( hKey, index, szName, &BufSize, NULL, NULL, NULL, NULL); if ( ERROR_SUCCESS == Win32Rc ) { index++; // // get the full registry key name and Valuetype // cSubKeys = REG_SZ; PDWORD pType = &cSubKeys; // // query ValueType, if error, default REG_SZ // MyRegQueryValue( hKey, szName, SCE_REG_VALUE_TYPE, (PVOID *)&pType, &RegType ); if ( cSubKeys < REG_SZ || cSubKeys > REG_MULTI_SZ ) { cSubKeys = REG_SZ; } // // convert the path name // ConvertMultiSzToDelim(szName, BufSize, L'/', L'\\'); // // compare with the input array, if not exist, // add it // for ( DWORD i=0; i<*pCount; i++ ) { if ( (*paRegValues)[i].FullValueName && _wcsicmp(szName, (*paRegValues)[i].FullValueName) == 0 ) { break; } } if ( i >= *pCount ) { // // did not find a match, add it // if ( SCESTATUS_SUCCESS != SceAddToNameStatusList(&pnsList, szName, BufSize, cSubKeys) ) { Win32Rc = ERROR_NOT_ENOUGH_MEMORY; break; } nAdded++; } } else if ( ERROR_NO_MORE_ITEMS != Win32Rc ) { break; } } while ( Win32Rc != ERROR_NO_MORE_ITEMS ); if ( Win32Rc == ERROR_NO_MORE_ITEMS ) { Win32Rc = ERROR_SUCCESS; } // // free the enumeration buffer // LocalFree(szName); } } if ( hKey ) { RegCloseKey(hKey); } if ( ERROR_SUCCESS == Win32Rc ) { // // add the name list to the output arrays // DWORD nNewCount = *pCount + nAdded; PSCE_REGISTRY_VALUE_INFO aNewArray; if ( nNewCount ) { aNewArray = (PSCE_REGISTRY_VALUE_INFO)LocalAlloc(0, nNewCount*sizeof(SCE_REGISTRY_VALUE_INFO)); if ( aNewArray ) { ZeroMemory(aNewArray, nNewCount * sizeof(SCE_REGISTRY_VALUE_INFO)); //This is a safe usage. memcpy( aNewArray, *paRegValues, *pCount * sizeof( SCE_REGISTRY_VALUE_INFO ) ); DWORD i; i=0; for ( PSCE_NAME_STATUS_LIST pns=pnsList; pns; pns=pns->Next ) { if ( pns->Name && i < nAdded ) { aNewArray[*pCount+i].FullValueName = pns->Name; pns->Name = NULL; aNewArray[*pCount+i].Value = NULL; aNewArray[*pCount+i].ValueType = pns->Status; aNewArray[*pCount+i].Status = SCE_STATUS_NOT_CONFIGURED; i++; } } // // free the original array // all components in the array are already transferred to the new array // LocalFree(*paRegValues); *pCount = nNewCount; *paRegValues = aNewArray; } else { Win32Rc = ERROR_NOT_ENOUGH_MEMORY; } } } // // free the name status list // SceFreeMemory(pnsList, SCE_STRUCT_NAME_STATUS_LIST); return( Win32Rc ); } DWORD GetGroupStatus( DWORD status, int flag ) { DWORD NewStatus; switch ( flag ) { case STATUS_GROUP_RECORD: if (status & SCE_GROUP_STATUS_NC_MEMBERS) { NewStatus = SCE_STATUS_NOT_CONFIGURED; } else if ( (status & SCE_GROUP_STATUS_MEMBERS_MISMATCH) || (status & SCE_GROUP_STATUS_MEMBEROF_MISMATCH)) { NewStatus = SCE_STATUS_MISMATCH; } else if (status & SCE_GROUP_STATUS_NOT_ANALYZED) { NewStatus = SCE_STATUS_NOT_ANALYZED; } else if (status & SCE_GROUP_STATUS_ERROR_ANALYZED) { NewStatus = SCE_STATUS_ERROR_NOT_AVAILABLE; } else { NewStatus = SCE_STATUS_GOOD; } break; case STATUS_GROUP_MEMBERS: if ( status & SCE_GROUP_STATUS_NOT_ANALYZED ) { NewStatus = SCE_STATUS_NOT_ANALYZED; //do not display any status; } else { if ( status & SCE_GROUP_STATUS_NC_MEMBERS ) { NewStatus = SCE_STATUS_NOT_CONFIGURED; } else if ( status & SCE_GROUP_STATUS_MEMBERS_MISMATCH ) { NewStatus = SCE_STATUS_MISMATCH; } else if (status & SCE_GROUP_STATUS_ERROR_ANALYZED) { NewStatus = SCE_STATUS_ERROR_NOT_AVAILABLE; } else { NewStatus = SCE_STATUS_GOOD; } } break; case STATUS_GROUP_MEMBEROF: if ( status & SCE_GROUP_STATUS_NOT_ANALYZED ) { NewStatus = SCE_STATUS_NOT_ANALYZED; // do not display any status; } else { if ( status & SCE_GROUP_STATUS_NC_MEMBEROF ) { NewStatus = SCE_STATUS_NOT_CONFIGURED; } else if ( status & SCE_GROUP_STATUS_MEMBEROF_MISMATCH ) { NewStatus = SCE_STATUS_MISMATCH; } else if (status & SCE_GROUP_STATUS_ERROR_ANALYZED) { NewStatus = SCE_STATUS_ERROR_NOT_AVAILABLE; } else { NewStatus = SCE_STATUS_GOOD; } } break; default: NewStatus = 0; break; } return NewStatus; } //+-------------------------------------------------------------------------- // // Function: AllocGetTempFileName // // Synopsis: Allocate and return a string with a temporary file name. // // Returns: The temporary file name, or 0 if a temp file can't be found // // History: // //--------------------------------------------------------------------------- LPTSTR AllocGetTempFileName() { DWORD dw; CString strPath; CString strFile; LPTSTR szPath; LPTSTR szFile; // // Get a temporary directory path in strPath // If our buffer isn't large enough then keep reallocating until it is // dw = MAX_PATH; do { szPath = strPath.GetBuffer(dw); dw = GetTempPath(MAX_PATH,szPath); strPath.ReleaseBuffer(); } while (dw > (DWORD)strPath.GetLength() ); // // Can't get a path to the temporary directory // if (!dw) { return 0; } // // Get a temporary file in that directory // szFile = strFile.GetBuffer(dw+MAX_PATH); if (!GetTempFileName(szPath,L"SCE",0,szFile)) { return 0; } strFile.ReleaseBuffer(); szFile = (LPTSTR)LocalAlloc(LPTR,(strFile.GetLength()+1)*sizeof(TCHAR)); if (!szFile) { return 0; } //This is a safe usage. lstrcpy(szFile,(LPCTSTR)strFile); return szFile; } // If the given environment variable exists as the first part of the path, // then the environment variable is inserted into the output buffer. // // Returns TRUE if pszResult is filled in. // // Example: Input -- C:\WINNT\SYSTEM32\FOO.TXT -and- lpEnvVar = %SYSTEMROOT% // Output -- %SYSTEMROOT%\SYSTEM32\FOO.TXT BOOL UnExpandEnvironmentString(LPCTSTR pszPath, LPCTSTR pszEnvVar, LPTSTR pszResult, UINT cbResult) { TCHAR szEnvVar[MAX_PATH]; if( !pszPath || !pszEnvVar || !pszResult ) //Raid #553113, yanggao. return FALSE; //This is not a safe usage. Make sure szEnvVar is terminated. Raid #553113, Yanggao. memset(szEnvVar, '\0', (MAX_PATH)*sizeof(TCHAR)); DWORD dwEnvVar = ExpandEnvironmentStrings(pszEnvVar, szEnvVar, ARRAYSIZE(szEnvVar)) - 1; // don't count the NULL if (CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, szEnvVar, dwEnvVar, pszPath, dwEnvVar) == 2) { if (lstrlen(pszPath) + dwEnvVar < cbResult) { //This is not a safe usage. validate pszPath, dwEnvVar, pszResult. lstrcpy(pszResult, pszEnvVar); lstrcat(pszResult, pszPath + dwEnvVar); return TRUE; } } return FALSE; } //+-------------------------------------------------------------------------- // // Function: UnexpandEnvironmentVariables // // Synopsis: Given a path, contract any leading members to use matching // environment variables, if any // // Arguments: // [szPath] - The path to expand // // Returns: The newly allocated path (NULL if no changes are made) // // History: // //--------------------------------------------------------------------------- LPTSTR UnexpandEnvironmentVariables(LPCTSTR szPath) { UINT cbNew; LPTSTR szNew; LPTSTR mszEnvVars; LPTSTR szEnvVar; DWORD dwEnvType; BOOL bExpanded; CString strKey; CString strValueName; CString str; AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (!strKey.LoadString(IDS_SECEDIT_KEY) || !strValueName.LoadString(IDS_ENV_VARS_REG_VALUE)) { return NULL; } // // Allocate memory for the new path // cbNew = lstrlen(szPath)+MAX_PATH+1; szNew = (LPTSTR) LocalAlloc(LPTR,cbNew * sizeof(TCHAR)); if (!szNew) { return NULL; } // // Get Vars to expand from the registry // mszEnvVars = NULL; if (ERROR_SUCCESS != MyRegQueryValue(HKEY_LOCAL_MACHINE, // hKeyRoot strKey, // SubKey strValueName, // ValueName (LPVOID *)&mszEnvVars, // Value &dwEnvType)) { // Reg Type // // Can't get any variables to expand // LocalFree(szNew); return NULL; } // // We need a multi-sz with the variables to replace in it // if (REG_MULTI_SZ != dwEnvType || mszEnvVars == NULL) //Bug350194, Yang Gao, 3/23/2001 { LocalFree(szNew); return NULL; } bExpanded = FALSE; // // Start at the beginning of the multi-sz block // szEnvVar = mszEnvVars; while (*szEnvVar) { if (UnExpandEnvironmentString(szPath,szEnvVar,szNew,cbNew)) { // // We can only unexpand (successfully) once // bExpanded = TRUE; break; } // // Advance szEnvVar to the end of this string // while (*szEnvVar) { szEnvVar++; } // // And the beginning of the next // szEnvVar++; } if (mszEnvVars) { LocalFree(mszEnvVars); } if (!bExpanded) { LocalFree(szNew); szNew = NULL; } return szNew; } //+-------------------------------------------------------------------------- // // Function: IsSystemDatabase // // Synopsis: Determine if a specific databse is the system database or a private one // // Arguments: // [szDBPath] - The database path to check // // Returns: True if szDBPath is the system database, false otherwise // // History: // //--------------------------------------------------------------------------- BOOL IsSystemDatabase(LPCTSTR szDBPath) { CString szSysDB; BOOL bIsSysDB; DWORD rc; DWORD RegType; if (!szDBPath) { return FALSE; } //Raid bug 261450, Yang Gao, 3/30/2001 if (FAILED(GetSystemDatabase(&szSysDB))) { return FALSE; } // // We found an appropriate szSysDB, so compare it with szDBPath // if (lstrcmp(szDBPath,szSysDB) == 0) { bIsSysDB = TRUE; } else { bIsSysDB = FALSE; } return bIsSysDB; } //+-------------------------------------------------------------------------- // // Function: GetSystemDatabase // // Synopsis: Get the name of the current system database // // Arguments: // [szDBPath] - [in/out] a pointer for the name of the system database // The caller is responsible for freeing it. // // // Returns: S_OK if the system database is found, otherwise an error // // History: // //--------------------------------------------------------------------------- HRESULT GetSystemDatabase(CString *szDBPath) { if (!szDBPath) { return E_INVALIDARG; } //Raid bug 261450, Yang Gao, 3/30/2001 CString sAppend; sAppend.LoadString( IDS_DB_DEFAULT ); PWSTR pszPath = (LPTSTR)LocalAlloc( 0, (MAX_PATH + sAppend.GetLength() + 1) * sizeof(WCHAR)); if ( pszPath == NULL ) //Raid bug 427956, Yanggao, 7/2/2001 { return E_FAIL; } if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_WINDOWS, NULL, 0, pszPath))) { //This is a safe usage. wcscpy( &(pszPath[lstrlen(pszPath)]), sAppend ); *szDBPath = pszPath; if (pszPath) { LocalFree(pszPath); pszPath = NULL; } return S_OK; } if (pszPath) { LocalFree(pszPath); pszPath = NULL; } return E_FAIL; } //+-------------------------------------------------------------------------- // // Function: ObjectStatusToString // // Synopsis: Convert an object status value to a printable string // // Arguments: // [status] - [in] The status value to convert // [str] - [out] The string to store the value in // // //--------------------------------------------------------------------------- UINT ObjectStatusToString(DWORD status, CString *strStatus) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); if ( status & SCE_STATUS_PERMISSION_MISMATCH ) { status = IDS_MISMATCH; } else if (status & SCE_STATUS_AUDIT_MISMATCH) { status = IDS_MISMATCH; } else { status &= 0x0F; switch(status){ case SCE_STATUS_NOT_ANALYZED: status = IDS_NOT_ANALYZED; break; case SCE_STATUS_GOOD: status = IDS_OK ; break; case SCE_STATUS_MISMATCH: status = IDS_MISMATCH; break; case SCE_STATUS_NOT_CONFIGURED: // // BUG 119215: The Analysis UI should never show "Not Defined" // for the security of existing system objects // status = IDS_NOT_ANALYZED; break; case SCE_STATUS_CHILDREN_CONFIGURED: status = IDS_CHILDREN_CONFIGURED; break; case SCE_STATUS_ERROR_NOT_AVAILABLE: status = IDS_NOT_AVAILABLE; break; case SCE_STATUS_NEW_SERVICE: status = IDS_NEW_SERVICE; break; default: // // We shouldn't get here, but for some reason we keep doing so // status = IDS_MISMATCH; break; } } if(strStatus){ strStatus->LoadString(status); } return status; } //+-------------------------------------------------------------------------- // // Function: IsSecurityTemplate // // Synopsis: Validates a file to see if the file is a security template. // // Arguments: [pszFileName] - The full path to the file to check. // // Returns: FALSE if the file does not exist or is not a valid // security template. // // TRUE if successful. // History: // //--------------------------------------------------------------------------- BOOL IsSecurityTemplate( LPCTSTR pszFileName ) { if(!pszFileName){ return FALSE; } HANDLE hProfile; SCESTATUS rc; // // Open the profile. // rc = SceOpenProfile( pszFileName, SCE_INF_FORMAT, &hProfile ); if(rc == SCESTATUS_SUCCESS && hProfile){ PSCE_PROFILE_INFO ProfileInfo = NULL; PSCE_ERROR_LOG_INFO ErrBuf = NULL; // // The profile will be validated by trying to load all the security areas. // rc = SceGetSecurityProfileInfo(hProfile, SCE_ENGINE_SCP, AREA_ALL, &ProfileInfo, &ErrBuf); if(ErrBuf){ rc = SCESTATUS_INVALID_DATA; } // // Free up the memory. // SceFreeMemory((PVOID)ErrBuf, SCE_STRUCT_ERROR_LOG_INFO); ErrBuf = NULL; if ( ProfileInfo != NULL ) { SceFreeMemory((PVOID)ProfileInfo, AREA_ALL); LocalFree(ProfileInfo); } SceCloseProfile(&hProfile); // // return TRUE if everything is successful. // if(rc != SCESTATUS_INVALID_DATA){ return TRUE; } } return FALSE; } //+-------------------------------------------------------------------------- // // Function: WriteSprintf // // Synopsis: Writes formated [pszStr] to [pStm]. // // Arguments: [pStm] - Stream to write to. // [pszStr] - Format string to write. // [...] - printf formating // // Returns: The total number of bytes written. // // History: // //--------------------------------------------------------------------------- int WriteSprintf( IStream *pStm, LPCTSTR pszStr, ...) { TCHAR szWrite[512]; va_list marker; va_start(marker, pszStr); vswprintf(szWrite, pszStr, marker); va_end(marker); ULONG nBytesWritten; int iLen = lstrlen(szWrite); if(pStm){ pStm->Write( szWrite, iLen * sizeof(TCHAR), &nBytesWritten ); return nBytesWritten; } return iLen; } //+-------------------------------------------------------------------------- // // Function: ReadSprintf // // Synopsis: Reads formated [pszStr] from [pStm]. // supported character switches are // 'd' - integer pointer. // // Arguments: [pStm] - Stream to read from. // [pszStr] - Format string to test. // [...] - pointer to the types defined by format // specification types. // // Returns: Total number of bytes read from the stream // // History: // //--------------------------------------------------------------------------- int ReadSprintf( IStream *pStm, LPCTSTR pszStr, ...) { if(!pStm || !pszStr){ return -1; } va_list marker; va_start(marker, pszStr); TCHAR szRead[256]; TCHAR szConv[512]; ULONG uRead = 0; int i = 0; LPCTSTR pszNext = szRead; int iTotalRead = 0; // Get the current seek position. ULARGE_INTEGER liBack = { 0 }; LARGE_INTEGER liCur = { 0 }; pStm->Seek( liCur, STREAM_SEEK_CUR, &liBack); #define INCBUFFER(sz)\ if(uRead){\ (sz)++;\ uRead--;\ } else {\ pStm->Read(szRead, 256 * sizeof(TCHAR), &uRead);\ uRead = uRead/sizeof(TCHAR);\ (sz) = szRead;\ }\ iTotalRead++; while(*pszStr){ if(!uRead){ // Read information into buffer. pStm->Read( szRead, 256 * sizeof(TCHAR), &uRead); pszNext = szRead; uRead = uRead/sizeof(TCHAR); if(!uRead){ iTotalRead = -1; break; } } if(*pszStr == '%'){ pszStr++; switch( *pszStr ){ case 'd': // read integer. pszStr++; i = 0; // copy number to our own buffer. while( (*pszNext >= L'0' && *pszNext <= L'9') ){ szConv[i++] = *pszNext; INCBUFFER( pszNext ); } szConv[i] = 0; // convert string to integer. *(va_arg(marker, int *)) = _wtol(szConv); continue; case 's': pszStr++; i = 0; // we have to have some kind of terminating character se we will use the // next value in pszStr. while( *pszNext && (*pszNext != *pszStr) ){ szConv[i++] = *pszNext; INCBUFFER( pszNext ); } if(*pszNext == *pszStr){ INCBUFFER( pszNext ); } // copy the string value. szConv[i] = 0; if( i ){ LPTSTR pNew = (LPTSTR)LocalAlloc(0, sizeof(TCHAR) * (i + 1)); if(NULL != pNew){ //This is a safe usage. lstrcpy(pNew, szConv); } LPTSTR *pArg; pArg = (va_arg(marker, LPTSTR *)); if (pArg) { *pArg = pNew; } } else { LPTSTR *pArg = va_arg(marker, LPTSTR *); //Prefast warning 269: Incorrect order of operations: dereference ignored. Comments: It is not necessary. } pszStr++; continue; } } // check to make sure we are at the correct position in the file. if(*pszStr != *pszNext){ iTotalRead = -1; break; } pszStr++; // increment buffer pointer. INCBUFFER( pszNext ); } va_end(marker); // Reset streem seek pointer. liCur.LowPart = liBack.LowPart; if(iTotalRead >= 0){ liCur.LowPart += iTotalRead * sizeof(TCHAR); } liCur.HighPart = liBack.HighPart; pStm->Seek(liCur, STREAM_SEEK_SET, NULL); return iTotalRead; #undef INCBUFFER } //+-------------------------------------------------------------------------------- // FileCreateError // // This function tries to create a new file use [pszFile]. It will display a // message to the user if the file cannot be created. // // Arguments: [pszFile] - Full path of file to create. // [dwFlags] - Flags // FCE_IGNORE_FILEEXISTS - Ignore File exists error, and // delete the file. // // Returns: IDYES the file can be created // IDNo The file cannot be created DWORD FileCreateError( LPCTSTR pszFile, DWORD dwFlags ) { if(!pszFile){ return ERROR_INVALID_PARAMETER; } HANDLE hFile; DWORD dwErr = IDNO; // // Try to create the file. // hFile = ExpandAndCreateFile( pszFile, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_ARCHIVE, NULL ); if(hFile == INVALID_HANDLE_VALUE){ // // Post error message to user. // dwErr = GetLastError(); LPTSTR pszErr; CString strErr; //This is a safe usage. FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, 0, (LPTSTR)&pszErr, 0, NULL ); strErr = pszErr; strErr += pszFile; if(pszErr){ LocalFree(pszErr); } switch(dwErr){ case ERROR_ALREADY_EXISTS: case ERROR_FILE_EXISTS: if( dwFlags & FCE_IGNORE_FILEEXISTS ){ dwErr = IDYES; break; } // // Confirm overwrite. // strErr.Format(IDS_FILE_EXISTS_FMT, pszFile); dwErr = AfxMessageBox( strErr, MB_YESNO ); break; default: // // The file cannot be created. // AfxMessageBox( strErr, MB_OK ); dwErr = IDNO; break; } } else { // // It's OK to create the file. // ::CloseHandle( hFile ); DeleteFile(pszFile); dwErr = IDYES; } return dwErr; } //+-------------------------------------------------------------------------- // // Function: IsDBCSPath // // Synopsis: Check if a path contains DBCS characters // // Arguments: [pszFile] - [in] The path to check // // Returns: TRUE if pszFile contains characters that can't be // represented by a LPSTR // // FALSE if pszFile only contains characters that can // be represented by a LPSTR // // //+-------------------------------------------------------------------------- BOOL IsDBCSPath(LPCTSTR szWideFile) { while(*szWideFile) { if (*szWideFile >= 256) { return TRUE; } szWideFile++; } return FALSE; /* LPSTR szMBFile; int nMBFile; BOOL bUsedDefaultChar = FALSE; nMBFile = sizeof(LPSTR)*(lstrlen(szWideFile)); szMBFile = (LPSTR)LocalAlloc(LPTR,nMBFile+1); if (szMBFile) { WideCharToMultiByte( CP_ACP, 0, szWideFile, -1, szMBFile, nMBFile, NULL, &bUsedDefaultChar); LocalFree(szMBFile); } return bUsedDefaultChar; */ } //+-------------------------------------------------------------------------- // // Function: GetSeceditHelpFilename // // Synopsis: Return the fully qualified path the help file for Secedit // // Arguments: None // // Returns: a CString containing the fully qualified help file name. // // //+-------------------------------------------------------------------------- CString GetSeceditHelpFilename() { static CString helpFileName; if ( helpFileName.IsEmpty () ) { UINT result = ::GetSystemWindowsDirectory ( helpFileName.GetBufferSetLength (MAX_PATH+1), MAX_PATH); ASSERT(result != 0 && result <= MAX_PATH); //Bogus assert. Yanggao. helpFileName.ReleaseBuffer (); helpFileName += L"\\help\\wsecedit.hlp"; } return helpFileName; } //+-------------------------------------------------------------------------- // // Function: GetGpeditHelpFilename // // Synopsis: Return the fully qualified path the help file for Secedit // // Arguments: None // // Returns: a CString containing the fully qualified help file name. // // //+-------------------------------------------------------------------------- CString GetGpeditHelpFilename() { static CString helpFileName; if ( helpFileName.IsEmpty () ) { UINT result = ::GetSystemWindowsDirectory ( helpFileName.GetBufferSetLength (MAX_PATH+1), MAX_PATH); ASSERT(result != 0 && result <= MAX_PATH); //Bogus Assert. Yanggao. helpFileName.ReleaseBuffer (); helpFileName += L"\\help\\gpedit.hlp"; } return helpFileName; } //+-------------------------------------------------------------------------- // // Function: ExpandEnvironmentStringWrapper // // Synopsis: Takes an LPTSTR and expands the enviroment variables in it // // Arguments: Pointer to the string to expand. // // Returns: a CString containing the fully expanded string. // //+-------------------------------------------------------------------------- CString ExpandEnvironmentStringWrapper(LPCTSTR psz) { LPTSTR pszBuffer = NULL; DWORD dwExpanded = 0; CString sz; dwExpanded = ExpandEnvironmentStrings(psz, NULL, 0); pszBuffer = sz.GetBuffer(dwExpanded); ExpandEnvironmentStrings(psz, pszBuffer, dwExpanded); sz.ReleaseBuffer(); return (sz); } //+-------------------------------------------------------------------------- // // Function: ExpandAndCreateFile // // Synopsis: Just does a normal CreateFile(), but expands the filename before // creating the file. // // Arguments: Same as CreateFile(). // // Returns: HANDLE to the created file. // //+-------------------------------------------------------------------------- HANDLE WINAPI ExpandAndCreateFile ( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ) { HANDLE hRet = INVALID_HANDLE_VALUE; CString sz; sz = ExpandEnvironmentStringWrapper(lpFileName); //This is a safe usage. sz is full path. return (CreateFile( sz, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile)); } //********************************************************************** // // FUNCTION: IsAdmin - This function checks the token of the // calling thread to see if the caller belongs to // the Administrators group. // // PARAMETERS: none // // RETURN VALUE: TRUE if the caller is an administrator on the local // machine. Otherwise, FALSE. // //********************************************************************** BOOL IsAdmin(void) { HANDLE hAccessToken = NULL; PTOKEN_GROUPS ptgGroups = NULL; DWORD cbGroups = 0; PSID psidAdmin = NULL; UINT i; SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY; // assume the caller is not an administrator BOOL bIsAdmin = FALSE; __try { if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hAccessToken)) { if (GetLastError() != ERROR_NO_TOKEN) __leave; // retry against process token if no thread token exists if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hAccessToken)) __leave; } // determine required size of buffer for token information if (GetTokenInformation(hAccessToken, TokenGroups, NULL, 0, &cbGroups)) { // call should have failed due to zero-length buffer __leave; } else { // call should have failed due to zero-length buffer if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) __leave; } // allocate a buffer to hold the token groups ptgGroups = (PTOKEN_GROUPS) HeapAlloc(GetProcessHeap(), 0, cbGroups); if (!ptgGroups) __leave; // call GetTokenInformation() again to actually retrieve the groups if (!GetTokenInformation(hAccessToken, TokenGroups, ptgGroups, cbGroups, &cbGroups)) __leave; // create a SID for the local administrators group // This is a safe usage. if (!AllocateAndInitializeSid(&siaNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin)) __leave; // scan the token's groups and compare the SIDs to the admin SID for (i = 0; i < ptgGroups->GroupCount; i++) { //This is a safe usage. psidAdmin is a local admin SID. if (EqualSid(psidAdmin, ptgGroups->Groups[i].Sid)) { bIsAdmin = TRUE; break; } } } __finally { // free resources if (hAccessToken) CloseHandle(hAccessToken); if (ptgGroups) HeapFree(GetProcessHeap(), 0, ptgGroups); if (psidAdmin) FreeSid(psidAdmin); } return bIsAdmin; } //+-------------------------------------------------------------------------- // // Function: MultiSZToSZ // // Synopsis: Converts a multiline string to a comma delimited normal string // // Returns: The converted string // //+-------------------------------------------------------------------------- PWSTR MultiSZToSZ(PCWSTR sz) { PWSTR szOut = NULL; ASSERT(sz); if (!sz) { return NULL; } //Bug 349000, Yang Gao, 3/23/2001 long i = 0; long j = 0; while( L'\0' != sz[i] ) { if( L',' == sz[i] ) j++; i++; } szOut = (PWSTR) LocalAlloc(LPTR,(lstrlen(sz)+j*2+1)*sizeof(wchar_t)); //Raid #376228, 4/25/2001 if (!szOut) { return NULL; } BOOL newline = FALSE; //raid #464335, Yang Gao, 9/7/2001 for(i=0,j=0; sz[i] != L'\0'; i++) { if( L'\n' == sz[i] ) { if( newline ) { szOut[j++] = MULTISZ_DELIMITER; } newline = FALSE; continue; } if( L'\r' == sz[i] ) { continue; // ignore it } if( L' ' == sz[i] && !newline ) //raid #464335, Yang Gao, 9/7/2001 { continue; //delete it if it occurs before any char of each line. } newline = TRUE; if( L',' == sz[i] ) { szOut[j++] = MULTISZ_QUOTE; szOut[j++] = sz[i]; szOut[j++] = MULTISZ_QUOTE; continue; } szOut[j++] = sz[i]; } return szOut; } //+-------------------------------------------------------------------------- // // Function: SZToMultiSZ // // Synopsis: Converts a comma delimited string to a multiline string // // Returns: The converted string // //+-------------------------------------------------------------------------- PWSTR SZToMultiSZ(PCWSTR sz) { PWSTR szOut = NULL; ASSERT(sz); if (!sz) { return NULL; } // // Calculate the length of the expanded string // int cSZ = 0; for (int i = 0;sz[i] != L'\0'; i++) { if (MULTISZ_DELIMITER == sz[i]) { // // Delimiter expands into an extra character so count it twice // cSZ++; } cSZ++; } szOut = (PWSTR) LocalAlloc(LPTR,(cSZ+1)*sizeof(wchar_t)); if (!szOut) { return NULL; } BOOL qflag = FALSE; for(int i=0, c=0; sz[i] != L'\0'; i++) { //Bug 349000, Yang Gao, 3/23/2001 if( MULTISZ_QUOTE == sz[i] && MULTISZ_DELIMITER == sz[i+1] ) { qflag = TRUE; continue; } if( MULTISZ_DELIMITER == sz[i] && MULTISZ_QUOTE == sz[i+1] && qflag ) { szOut[c++] = sz[i]; i++; qflag = FALSE; continue; } qflag = FALSE; if (MULTISZ_DELIMITER == sz[i]) { szOut[c++] = L'\r'; szOut[c++] = L'\n'; } else { szOut[c++] = sz[i]; } } return szOut; } //+-------------------------------------------------------------------------- // // Function: MultiSZToDisp // // Synopsis: Converts a comma delimited multiline string to a display string // // Returns: The converted string // Bug 349000, Yang Gao, 3/23/2001 //+-------------------------------------------------------------------------- void MultiSZToDisp(PCWSTR sz, CString &pszOut) { ASSERT(sz); if (!sz) { return; } // // Calculate the length of the expanded string // int cSZ = 0; for (int i = 0;sz[i] != L'\0'; i++) { if (MULTISZ_DELIMITER == sz[i]) { // // Delimiter expands into an extra character so count it twice // cSZ++; } cSZ++; } PWSTR szOut; szOut = (PWSTR) LocalAlloc(LPTR,(cSZ+1)*sizeof(wchar_t)); if (!szOut) { return; } BOOL qflag = FALSE; for(int i=0, c=0; sz[i] != L'\0'; i++) { if( MULTISZ_QUOTE == sz[i] && MULTISZ_DELIMITER == sz[i+1] ) { qflag = TRUE; continue; } if( MULTISZ_DELIMITER == sz[i] && MULTISZ_QUOTE == sz[i+1] && qflag ) { szOut[c++] = sz[i]; i++; qflag = FALSE; continue; } qflag = FALSE; szOut[c++] = sz[i]; } pszOut = szOut; LocalFree(szOut); return; } SCE_PROFILE_INFO *g_pDefaultTemplate = NULL; SCE_PROFILE_INFO * GetDefaultTemplate() { SCE_PROFILE_INFO *pspi = NULL; DWORD RegType = 0; SCESTATUS rc = 0; LPTSTR szInfFile = NULL; PVOID pHandle = NULL; if (g_pDefaultTemplate) { return g_pDefaultTemplate; } rc = MyRegQueryValue(HKEY_LOCAL_MACHINE, SCE_REGISTRY_KEY, SCE_REGISTRY_DEFAULT_TEMPLATE, (PVOID *)&szInfFile, &RegType ); if (ERROR_SUCCESS != rc) { if (szInfFile) { LocalFree(szInfFile); szInfFile = NULL; } return NULL; } if (EngineOpenProfile(szInfFile,OPEN_PROFILE_CONFIGURE,&pHandle) != SCESTATUS_SUCCESS) { LocalFree(szInfFile); szInfFile = NULL; return NULL; } LocalFree(szInfFile); szInfFile = NULL; rc = SceGetSecurityProfileInfo(pHandle, SCE_ENGINE_SCP, AREA_ALL, &pspi, NULL ); SceCloseProfile(&pHandle); if (SCESTATUS_SUCCESS != rc) { // // expand registry value section based on registry values list on local machine // SceRegEnumAllValues( &(pspi->RegValueCount), &(pspi->aRegValues) ); #define PD(X,Y) if (pspi->X == SCE_NO_VALUE) { pspi->X = Y; } PD(MaximumPasswordAge,MAX_PASS_AGE_DEFAULT) PD(MinimumPasswordAge,MIN_PASS_AGE_DEFAULT) PD(MinimumPasswordLength,MIN_PASS_LENGTH_DEFAULT) PD(PasswordHistorySize,PASS_HISTORY_SIZE_DEFAULT) PD(PasswordComplexity,PASS_COMPLEXITY_DEFAULT) PD(RequireLogonToChangePassword,REQUIRE_LOGIN_DEFAULT) PD(LockoutBadCount,LOCKOUT_BAD_COUNT_DEFAULT) PD(ResetLockoutCount,RESET_LOCKOUT_COUNT_DEFAULT) PD(LockoutDuration,LOCKOUT_DURATION_DEFAULT) PD(AuditSystemEvents,AUDIT_SYSTEM_EVENTS_DEFAULT) PD(AuditLogonEvents,AUDIT_LOGON_EVENTS_DEFAULT) PD(AuditObjectAccess,AUDIT_OBJECT_ACCESS_DEFAULT) PD(AuditPrivilegeUse,AUDIT_PRIVILEGE_USE_DEFAULT) PD(AuditPolicyChange,AUDIT_POLICY_CHANGE_DEFAULT) PD(AuditAccountManage,AUDIT_ACCOUNT_MANAGE_DEFAULT) PD(AuditProcessTracking,AUDIT_PROCESS_TRACKING_DEFAULT) PD(AuditDSAccess,AUDIT_DS_ACCESS_DEFAULT) PD(AuditAccountLogon,AUDIT_ACCOUNT_LOGON_DEFAULT) PD(ForceLogoffWhenHourExpire,FORCE_LOGOFF_DEFAULT) PD(EnableAdminAccount,ENABLE_ADMIN_DEFAULT) PD(EnableGuestAccount,ENABLE_GUEST_DEFAULT) PD(LSAAnonymousNameLookup,LSA_ANON_LOOKUP_DEFAULT) PD(MaximumLogSize[EVENT_TYPE_SYSTEM],SYS_MAX_LOG_SIZE_DEFAULT) PD(MaximumLogSize[EVENT_TYPE_APP],APP_MAX_LOG_SIZE_DEFAULT) PD(MaximumLogSize[EVENT_TYPE_SECURITY],SEC_MAX_LOG_SIZE_DEFAULT) PD(AuditLogRetentionPeriod[EVENT_TYPE_SYSTEM],SYS_LOG_RETENTION_PERIOD_DEFAULT) PD(AuditLogRetentionPeriod[EVENT_TYPE_APP],APP_LOG_RETENTION_PERIOD_DEFAULT) PD(AuditLogRetentionPeriod[EVENT_TYPE_SECURITY],SEC_LOG_RETENTION_PERIOD_DEFAULT) PD(RetentionDays[EVENT_TYPE_APP],APP_LOG_RETENTION_DAYS_DEFAULT) PD(RetentionDays[EVENT_TYPE_SYSTEM],SYS_LOG_RETENTION_DAYS_DEFAULT) PD(RetentionDays[EVENT_TYPE_SECURITY],SEC_LOG_RETENTION_DAYS_DEFAULT) PD(RestrictGuestAccess[EVENT_TYPE_APP],APP_RESTRICT_GUEST_ACCESS_DEFAULT) PD(RestrictGuestAccess[EVENT_TYPE_SYSTEM],SYS_RESTRICT_GUEST_ACCESS_DEFAULT) PD(RestrictGuestAccess[EVENT_TYPE_SECURITY],SEC_RESTRICT_GUEST_ACCESS_DEFAULT) if (pspi->pFiles.pAllNodes->Count == 0) { DWORD SDSize = 0; pspi->pFiles.pAllNodes->Count = 1; pspi->pFiles.pAllNodes->pObjectArray[0] = (PSCE_OBJECT_SECURITY) LocalAlloc(LPTR,sizeof(SCE_OBJECT_SECURITY)); if (pspi->pFiles.pAllNodes->pObjectArray[0]) { SceSvcConvertTextToSD ( FILE_SYSTEM_SECURITY_DEFAULT, &(pspi->pFiles.pAllNodes->pObjectArray[0]->pSecurityDescriptor), &SDSize, &(pspi->pFiles.pAllNodes->pObjectArray[0]->SeInfo) ); } } if (pspi->pRegistryKeys.pAllNodes->Count == 0) { DWORD SDSize = 0; pspi->pRegistryKeys.pAllNodes->Count = 1; pspi->pRegistryKeys.pAllNodes->pObjectArray[0] = (PSCE_OBJECT_SECURITY) LocalAlloc(LPTR,sizeof(SCE_OBJECT_SECURITY)); if (pspi->pRegistryKeys.pAllNodes->pObjectArray[0]) { SceSvcConvertTextToSD ( REGISTRY_SECURITY_DEFAULT, &(pspi->pRegistryKeys.pAllNodes->pObjectArray[0]->pSecurityDescriptor), &SDSize, &(pspi->pRegistryKeys.pAllNodes->pObjectArray[0]->SeInfo) ); } } if (pspi->pServices->General.pSecurityDescriptor == NULL) { DWORD SDSize = 0; SceSvcConvertTextToSD ( SERVICE_SECURITY_DEFAULT, &(pspi->pServices->General.pSecurityDescriptor), &SDSize, &(pspi->pServices->SeInfo) ); } } g_pDefaultTemplate = pspi; return pspi; } HRESULT GetDefaultFileSecurity(PSECURITY_DESCRIPTOR *ppSD, SECURITY_INFORMATION *pSeInfo) { SCE_PROFILE_INFO *pspi = NULL; ASSERT(ppSD); ASSERT(pSeInfo); if (!ppSD || !pSeInfo) { return E_INVALIDARG; } pspi = GetDefaultTemplate(); *ppSD = NULL; *pSeInfo = 0; if (!pspi) { return E_FAIL; } if (!pspi->pFiles.pAllNodes) { return E_FAIL; } if (pspi->pFiles.pAllNodes->Count == 0) { return E_FAIL; } *pSeInfo = pspi->pFiles.pAllNodes->pObjectArray[0]->SeInfo; return MyMakeSelfRelativeSD(pspi->pFiles.pAllNodes->pObjectArray[0]->pSecurityDescriptor, ppSD); } HRESULT GetDefaultRegKeySecurity(PSECURITY_DESCRIPTOR *ppSD, SECURITY_INFORMATION *pSeInfo) { SCE_PROFILE_INFO *pspi = NULL; ASSERT(ppSD); ASSERT(pSeInfo); if (!ppSD || !pSeInfo) { return E_INVALIDARG; } pspi = GetDefaultTemplate(); *ppSD = NULL; *pSeInfo = 0; if (!pspi) { return E_FAIL; } if (!pspi->pRegistryKeys.pAllNodes) { return E_FAIL; } if (pspi->pRegistryKeys.pAllNodes->Count == 0) { return E_FAIL; } *pSeInfo = pspi->pRegistryKeys.pAllNodes->pObjectArray[0]->SeInfo; return MyMakeSelfRelativeSD(pspi->pRegistryKeys.pAllNodes->pObjectArray[0]->pSecurityDescriptor, ppSD); } HRESULT GetDefaultServiceSecurity(PSECURITY_DESCRIPTOR *ppSD, SECURITY_INFORMATION *pSeInfo) { SCE_PROFILE_INFO *pspi = NULL; ASSERT(ppSD); ASSERT(pSeInfo); if (!ppSD || !pSeInfo) { return E_INVALIDARG; } pspi = GetDefaultTemplate(); *ppSD = NULL; *pSeInfo = 0; if (!pspi) { return E_FAIL; } if (!pspi->pServices) { return E_FAIL; } *pSeInfo = pspi->pServices->SeInfo; return MyMakeSelfRelativeSD(pspi->pServices->General.pSecurityDescriptor, ppSD); } BOOL GetSecureWizardName( OUT LPTSTR *ppstrPathName OPTIONAL, OUT LPTSTR *ppstrDisplayName OPTIONAL ) { BOOL b=FALSE; if ( ppstrPathName == NULL && ppstrDisplayName == NULL) return FALSE; if ( ppstrPathName ) *ppstrPathName = NULL; if ( ppstrDisplayName ) *ppstrDisplayName = NULL; #define SCE_WIZARD_PATH SCE_ROOT_PATH TEXT("\\Wizard") DWORD rc; DWORD RegType; LPVOID pValue=NULL; PWSTR pPathName = NULL; rc = MyRegQueryValue(HKEY_LOCAL_MACHINE, SCE_WIZARD_PATH, TEXT("Path"), &pValue, &RegType ); if ( ERROR_SUCCESS == rc && pValue && (RegType == REG_SZ || RegType == REG_EXPAND_SZ) ) { if ( RegType == REG_EXPAND_SZ ) { // // Expand the environment variable // DWORD dSize = ExpandEnvironmentStrings((LPTSTR)pValue, NULL, 0); if ( dSize > 0 ) { pPathName = (PWSTR)LocalAlloc(LPTR, (dSize+1)*sizeof(WCHAR)); if ( pPathName ) { ExpandEnvironmentStrings((LPTSTR)pValue, pPathName, dSize); } else { LocalFree(pValue); return FALSE; } } else { LocalFree(pValue); return FALSE; } } else { // // just simply take the string // pPathName = (LPTSTR)pValue; pValue = NULL; } if ( ppstrDisplayName ) { // // now query the display name (menu name) from the binary // binary name is stored in pPathName (can't be NULL) // DWORD dwHandle=0; DWORD dwSize = GetFileVersionInfoSize(pPathName, &dwHandle); if ( dwSize > 0 ) { LPVOID pBuffer = (LPVOID)LocalAlloc(LPTR, dwSize+1); if ( pBuffer ) { if ( GetFileVersionInfo(pPathName, 0, dwSize, pBuffer) ) { PVOID lpInfo = 0; UINT cch = 0; CString key; WCHAR szBuffer[10]; CString keyBase; //This is a safe usage. wsprintf (szBuffer, L"%04X", GetUserDefaultLangID ()); wcscat (szBuffer, L"04B0"); keyBase = L"\\StringFileInfo\\"; keyBase += szBuffer; keyBase += L"\\"; key = keyBase + L"FileDescription"; if ( VerQueryValue (pBuffer, const_cast ((PCWSTR) key), &lpInfo, &cch) ) { *ppstrDisplayName = (PWSTR)LocalAlloc(LPTR,(cch+1)*sizeof(WCHAR)); if ( *ppstrDisplayName ) { //This may not be a safe usage. ppstrDisplayName is PTSTR. Consider fix. wcscpy(*ppstrDisplayName, (PWSTR)lpInfo); b=TRUE; } } } LocalFree(pBuffer); } } } // // get the binary name // if ( ppstrPathName ) { *ppstrPathName = pPathName; pPathName = NULL; b=TRUE; } } if ( pPathName && (pPathName != pValue ) ) { LocalFree(pPathName); } if ( pValue ) { LocalFree(pValue); } return b; } BOOL IsValidFileName(CString& str) { CString text; CString charsWithSpaces; UINT nIndex = 0; PCWSTR szInvalidCharSet = ILLEGAL_FILENAME_CHARS; if( str == L'.' || str == L"..") //Raid #617915, Yanggao return FALSE; if( -1 != str.FindOneOf(szInvalidCharSet) ) { while (szInvalidCharSet[nIndex]) { charsWithSpaces += szInvalidCharSet[nIndex]; charsWithSpaces += L" "; nIndex++; } //This is a sage usage. text.FormatMessage (IDS_INVALID_FILENAME, charsWithSpaces); AfxMessageBox(text, MB_OK|MB_ICONEXCLAMATION); return FALSE; } //Raid 484084, Yanggao, 10/24/2001 int strlength = str.GetLength(); if( 1==strlength && (str.GetAt(0) == L'/' || str.GetAt(0) == L'\\') ) { szInvalidCharSet = ILLEGAL_FILENAME_CHARS2; //Raid #526397, 2/26/2002, yanggao while (szInvalidCharSet[nIndex]) { charsWithSpaces += szInvalidCharSet[nIndex]; charsWithSpaces += L" "; nIndex++; } //This is a safe usage. text.FormatMessage (IDS_INVALID_FILENAMEPATH, charsWithSpaces); AfxMessageBox(text, MB_OK|MB_ICONEXCLAMATION); return FALSE; } int pos1 = str.Find(L"\\\\"); int pos2 = str.Find(L"//"); int pos3 = str.Find(L"\\/"); int pos4 = str.Find(L"/\\"); if( pos1>=0 || pos2>=0 || pos3>=0 || pos4>=0 ) //Raid #498480, yanggao, do not accept "\\". { szInvalidCharSet = ILLEGAL_FILENAME_CHARS1; while (szInvalidCharSet[nIndex]) { charsWithSpaces += szInvalidCharSet[nIndex]; charsWithSpaces += L" "; nIndex++; } //This is a safe usage. text.FormatMessage (IDS_INVALID_FILENAME, charsWithSpaces); AfxMessageBox(text, MB_OK|MB_ICONEXCLAMATION); return FALSE; } return TRUE; } /////////////////////////////////////////////////////////////////// //Raid #533432, yanggao, 4/3/2002 //Currently pextension should include '.' /////////////////////////////////////////////////////////////////// #define IsDigit(c) ((c) >= L'0' && c <= L'9') BOOL IsNameReserved(LPCWSTR pszName, LPCWSTR pextension) { static const WCHAR *rgszPorts3[] = { TEXT("NUL"), TEXT("PRN"), TEXT("CON"), TEXT("AUX"), }; static const WCHAR *rgszPorts4[] = { TEXT("LPT"), // LPT# TEXT("COM"), // COM# }; if( !pszName || !pextension ) return FALSE; CString sz = pszName; CString tempsz = pextension; if( _wcsicmp(sz.Right(tempsz.GetLength()), tempsz) == 0 ) //Remove extension { tempsz = sz.Left(sz.GetLength() - tempsz.GetLength()); } else { tempsz = sz; } int cch = tempsz.ReverseFind(L'\\'); //Remove path int iMax = tempsz.ReverseFind(L'/'); if( cch < iMax ) { cch = iMax; } if( cch >= 0 ) { cch = tempsz.GetLength() - cch - 1; sz = tempsz.Right(cch); } else { sz = tempsz; } LPCTSTR* rgszPorts = rgszPorts3; cch = sz.GetLength(); tempsz = sz; iMax = ARRAYSIZE(rgszPorts3); if (cch == 4 && IsDigit(sz.GetAt(3))) { // if 4 chars start with LPT checks // need to filter out: // COM1, COM2, etc. LPT1, LPT2, etc // but not: // COM or LPT or LPT10 or COM10 // COM == 1 and LPT == 0 iMax = ARRAYSIZE(rgszPorts4); rgszPorts = rgszPorts4; sz.SetAt(3, L'\0'); cch = 3; } if (cch == 3) { int i = 0; for (i; i < iMax; i++) { if (!lstrcmpi(rgszPorts[i], sz)) { break; } } if( i != iMax ) { sz.FormatMessage(IDS_RESERVED_NAME, tempsz); AfxMessageBox(sz, MB_OK|MB_ICONEXCLAMATION); return TRUE; } } return FALSE; }