Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

590 lines
18 KiB

#include "pch.h"
#include "iedetect.h"
#define VALID_SIGNATURE 0x5c3f3f5c // string "\??\"
#define REMOVE_QUOTES 0x01
#define IGNORE_QUOTES 0x02
CONST CHAR g_cszWininit[] = "wininit.ini";
CONST CHAR g_cszRenameSec[] = "Rename";
CONST CHAR g_cszPFROKey[] = REGSTR_PATH_CURRENT_CONTROL_SET "\\SESSION MANAGER";
CONST CHAR g_cszPFRO[] = "PendingFileRenameOperations";
DWORD CheckFileEx(LPSTR szDir, DETECT_FILES Detect_Files);
DWORD GetStringField(LPSTR szStr, UINT uField, char cDelimiter, LPSTR szBuf, UINT cBufSize)
{
LPSTR pszBegin = szStr;
LPSTR pszEnd;
UINT i = 0;
DWORD dwToCopy;
if(cBufSize == 0)
return 0;
szBuf[0] = 0;
if(szStr == NULL)
return 0;
while(*pszBegin != 0 && i < uField)
{
pszBegin = FindChar(pszBegin, cDelimiter);
if(*pszBegin != 0)
pszBegin++;
i++;
}
// we reached end of string, no field
if(*pszBegin == 0)
{
return 0;
}
pszEnd = FindChar(pszBegin, cDelimiter);
while(pszBegin <= pszEnd && *pszBegin == ' ')
pszBegin++;
while(pszEnd > pszBegin && *(pszEnd - 1) == ' ')
pszEnd--;
if(pszEnd > (pszBegin + 1) && *pszBegin == '"' && *(pszEnd-1) == '"')
{
pszBegin++;
pszEnd--;
}
dwToCopy = (DWORD)(pszEnd - pszBegin + 1);
if(dwToCopy > cBufSize)
dwToCopy = cBufSize;
lstrcpynA(szBuf, pszBegin, dwToCopy);
return dwToCopy - 1;
}
DWORD GetIntField(LPSTR szStr, char cDelimiter, UINT uField, DWORD dwDefault)
{
char szNumBuf[16];
if(GetStringField(szStr, uField, cDelimiter, szNumBuf, sizeof(szNumBuf)) == 0)
return dwDefault;
else
return AtoL(szNumBuf);
}
int CompareLocales(LPCSTR pcszLoc1, LPCSTR pcszLoc2)
{
int ret;
if(pcszLoc1[0] == '*' || pcszLoc2[0] == '*')
ret = 0;
else
ret = lstrcmpi(pcszLoc1, pcszLoc2);
return ret;
}
void ConvertVersionStrToDwords(LPSTR pszVer, char cDelimiter, LPDWORD pdwVer, LPDWORD pdwBuild)
{
DWORD dwTemp1,dwTemp2;
dwTemp1 = GetIntField(pszVer, cDelimiter, 0, 0);
dwTemp2 = GetIntField(pszVer, cDelimiter, 1, 0);
*pdwVer = (dwTemp1 << 16) + dwTemp2;
dwTemp1 = GetIntField(pszVer, cDelimiter, 2, 0);
dwTemp2 = GetIntField(pszVer, cDelimiter, 3, 0);
*pdwBuild = (dwTemp1 << 16) + dwTemp2;
}
LPSTR FindChar(LPSTR pszStr, char ch)
{
while( *pszStr != 0 && *pszStr != ch )
pszStr++;
return pszStr;
}
DWORD CompareVersions(DWORD dwAskVer, DWORD dwAskBuild, DWORD dwInstalledVer, DWORD dwInstalledBuild)
{
DWORD dwRet = DET_NOTINSTALLED;
if((dwInstalledVer == dwAskVer) && (dwInstalledBuild == dwAskBuild))
{
dwRet = DET_INSTALLED;
}
else if( (dwInstalledVer > dwAskVer) ||
((dwInstalledVer == dwAskVer) && (dwInstalledBuild > dwAskBuild)) )
{
dwRet = DET_NEWVERSIONINSTALLED;
}
else if( (dwInstalledVer < dwAskVer) ||
((dwInstalledVer == dwAskVer) && (dwInstalledBuild < dwAskBuild)) )
{
dwRet = DET_OLDVERSIONINSTALLED;
}
return dwRet;
}
BOOL FRunningOnNT(void)
{
static BOOL fIsNT = 2 ;
OSVERSIONINFO VerInfo;
// If we have calculated this before just pass that back.
// else find it now.
//
if (fIsNT == 2)
{
VerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&VerInfo);
// Note: We don't check for Win32S on Win 3.1 here -- that should
// have been a blocking check earlier in fn CheckWinVer().
// Also, we don't check for failure on the above call as it
// should succeed if we are on NT 4.0 or Win 9X!
//
fIsNT = (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
}
return fIsNT;
}
BOOL GetVersionFromGuid(LPSTR pszGuid, LPDWORD pdwVer, LPDWORD pdwBuild)
{
HKEY hKey;
char szValue[MAX_PATH];
DWORD dwValue = 0;
DWORD dwSize;
BOOL bVersion = FALSE;
if (pdwVer && pdwBuild)
{
*pdwVer = 0;
*pdwBuild = 0;
lstrcpy(szValue, COMPONENT_KEY);
AddPath(szValue, pszGuid);
if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, szValue, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
dwSize = sizeof(dwValue);
if(RegQueryValueEx(hKey, ISINSTALLED_KEY, 0, NULL, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS)
{
if (dwValue != 0)
{
dwSize = sizeof(szValue);
if(RegQueryValueEx(hKey, VERSION_KEY, 0, NULL, (LPBYTE)szValue, &dwSize) == ERROR_SUCCESS)
{
ConvertVersionStrToDwords(szValue, ',', pdwVer, pdwBuild);
bVersion = TRUE;
}
}
}
RegCloseKey(hKey);
}
}
return bVersion;
}
BOOL CompareLocal(LPCSTR pszGuid, LPCSTR pszLocal)
{
HKEY hKey;
char szValue[MAX_PATH];
DWORD dwSize;
BOOL bLocal = FALSE;
if (lstrcmpi(pszLocal, "*") == 0)
{
bLocal = TRUE;
}
else
{
lstrcpy(szValue, COMPONENT_KEY);
AddPath(szValue, pszGuid);
if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, szValue, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
dwSize = sizeof(szValue);
if(RegQueryValueEx(hKey, LOCALE_KEY, 0, NULL, (LPBYTE)szValue, &dwSize) == ERROR_SUCCESS)
{
bLocal = (lstrcmpi(szValue, pszLocal) == 0);
}
RegCloseKey(hKey);
}
}
return bLocal;
}
PSTR GetNextField(PSTR *ppszData, PCSTR pcszDeLims, DWORD dwFlags)
// If (dwFlags & IGNORE_QUOTES) is TRUE, then look for any char in pcszDeLims in *ppszData. If found,
// replace it with the '\0' char and set *ppszData to point to the beginning of the next field and return
// pointer to current field.
//
// If (dwFlags & IGNORE_QUOTES) is FALSE, then look for any char in pcszDeLims outside of balanced quoted sub-strings
// in *ppszData. If found, replace it with the '\0' char and set *ppszData to point to the beginning of
// the next field and return pointer to current field.
//
// If (dwFlags & REMOVE_QUOTES) is TRUE, then remove the surrounding quotes and replace two consecutive quotes by one.
//
// NOTE: If IGNORE_QUOTES and REMOVE_QUOTES are both specified, then IGNORE_QUOTES takes precedence over REMOVE_QUOTES.
//
// If you just want to remove the quotes from a string, call this function as
// GetNextField(&pszData, "\"" or "'" or "", REMOVE_QUOTES).
//
// If you call this function as GetNextField(&pszData, "\"" or "'" or "", 0), you will get back the
// entire pszData as the field.
//
{
PSTR pszRetPtr, pszPtr;
BOOL fWithinQuotes = FALSE, fRemoveQuote;
CHAR chQuote;
if (ppszData == NULL || *ppszData == NULL || **ppszData == '\0')
return NULL;
for (pszRetPtr = pszPtr = *ppszData; *pszPtr; pszPtr = CharNext(pszPtr))
{
if (!(dwFlags & IGNORE_QUOTES) && (*pszPtr == '"' || *pszPtr == '\''))
{
fRemoveQuote = FALSE;
if (*pszPtr == *(pszPtr + 1)) // two consecutive quotes become one
{
pszPtr++;
if (dwFlags & REMOVE_QUOTES)
fRemoveQuote = TRUE;
else
{
// if pcszDeLims is '"' or '\'', then *pszPtr == pcszDeLims would
// be TRUE and we would break out of the loop against the design specs;
// to prevent this just continue
continue;
}
}
else if (!fWithinQuotes)
{
fWithinQuotes = TRUE;
chQuote = *pszPtr; // save the quote char
fRemoveQuote = dwFlags & REMOVE_QUOTES;
}
else
{
if (*pszPtr == chQuote) // match the correct quote char
{
fWithinQuotes = FALSE;
fRemoveQuote = dwFlags & REMOVE_QUOTES;
}
}
if (fRemoveQuote)
{
// shift the entire string one char to the left to get rid of the quote char
MoveMemory(pszPtr, pszPtr + 1, lstrlen(pszPtr));
}
}
// BUGBUG: Is type casting pszPtr to UNALIGNED necessary? -- copied it from ANSIStrChr
// check if pszPtr is pointing to one of the chars in pcszDeLims
if (!fWithinQuotes &&
ANSIStrChr(pcszDeLims, (WORD) (IsDBCSLeadByte(*pszPtr) ? *((UNALIGNED WORD *) pszPtr) : *pszPtr)) != NULL)
break;
}
// NOTE: if fWithinQuotes is TRUE here, then we have an unbalanced quoted string; but we don't care!
// the entire string after the beginning quote becomes the field
if (*pszPtr) // pszPtr is pointing to a char in pcszDeLims
{
*ppszData = CharNext(pszPtr); // save the pointer to the beginning of next field in *ppszData
*pszPtr = '\0'; // replace the DeLim char with the '\0' char
}
else
*ppszData = pszPtr; // we have reached the end of the string; next call to this function
// would return NULL
return pszRetPtr;
}
PSTR GetDataFromWininitOrPFRO(PCSTR pcszWininit, HKEY hkPFROKey, PDWORD pdwLen)
{
PSTR pszData, pszPtr;
*pdwLen = 0;
if (!FRunningOnNT())
{
HANDLE hFile;
WIN32_FIND_DATA FileData;
// find the size of pcszWininit
if ((hFile = FindFirstFile(pcszWininit, &FileData)) != INVALID_HANDLE_VALUE)
{
*pdwLen = FileData.nFileSizeLow;
FindClose(hFile);
}
if (*pdwLen == 0 || (pszData = (PSTR) LocalAlloc(LPTR, *pdwLen)) == NULL)
return NULL;
GetPrivateProfileSection(g_cszRenameSec, pszData, *pdwLen, pcszWininit);
// replace the ='s by \0's
// BUGBUG: assuming that all the lines in wininit.ini have the correct format, i.e., to=from
for (pszPtr = pszData; *pszPtr; pszPtr += lstrlen(pszPtr) + 1)
GetNextField(&pszPtr, "=", IGNORE_QUOTES);
}
else
{
if (hkPFROKey == NULL)
return NULL;
// get the length of value data
RegQueryValueEx(hkPFROKey, g_cszPFRO, NULL, NULL, NULL, pdwLen);
if (*pdwLen == 0 || (pszData = (PSTR) LocalAlloc(LPTR, *pdwLen)) == NULL)
return NULL;
// get the data
RegQueryValueEx(hkPFROKey, g_cszPFRO, NULL, NULL, (PBYTE) pszData, pdwLen);
}
return pszData;
}
VOID ReadFromWininitOrPFRO(PCSTR pcszKey, PSTR pszValue)
{
CHAR szShortName[MAX_PATH];
CHAR szWininit[MAX_PATH];
PSTR pszData, pszLine, pszFrom, pszTo;
DWORD dwLen;
HKEY hkPFROKey = NULL;
if (!FRunningOnNT())
{
GetWindowsDirectory(szWininit, sizeof(szWininit));
AddPath(szWininit, g_cszWininit);
}
else
RegOpenKeyEx(HKEY_LOCAL_MACHINE, g_cszPFROKey, 0, KEY_READ, &hkPFROKey);
// return empty string if pcszKey could not be found
*pszValue = '\0';
if ((pszData = GetDataFromWininitOrPFRO(szWininit, hkPFROKey, &dwLen)) == NULL)
{
if (hkPFROKey != NULL)
RegCloseKey(hkPFROKey);
return;
}
if (!FRunningOnNT())
{
GetShortPathName(pcszKey, szShortName, sizeof(szShortName));
pcszKey = szShortName;
}
pszLine = pszData;
while (*pszLine)
{
// NOTE: On Win95, the format is (To, From) but on NT4.0, the format is (From, To)
if (!FRunningOnNT())
{
// format of GetPrivateProfileSection data is:
//
// to1=from1\0 ; from1 is the Value and to1 is the Key
// to2=from2\0
// NUL=del1\0 ; del1 is the Key
// NUL=del2\0
// .
// .
// .
// to<n>=from<n>\0\0
pszTo = pszLine; // key
pszFrom = pszLine + lstrlen(pszLine) + 1;
pszLine = pszFrom + lstrlen(pszFrom) + 1; // point to the next line
}
else
{
// format of the value data for PFRO value name is:
//
// from1\0to1\0 ; from1 is the Value and to1 is the Key
// from2\0to2\0
// del1\0\0 ; del1 is the Key
// del2\0\0
// .
// .
// .
// from<n>\0to<n>\0\0
pszFrom = pszLine;
pszTo = pszLine + lstrlen(pszLine) + 1; // key
pszLine = pszTo + lstrlen(pszTo) + 1; // point to the next line
// skip over "\??\"
if (*pszFrom == '\\') // '\\' is not a Leading DBCS byte
{
if (*((PDWORD) pszFrom) == VALID_SIGNATURE)
pszFrom += 4;
else
continue;
}
if (*pszTo == '!') // '!' is neither a Leading nor a Trailing DBCS byte
pszTo++;
if (*pszTo == '\\')
{
if (*((PDWORD) pszTo) == VALID_SIGNATURE)
pszTo += 4;
else
continue;
}
}
if (lstrcmpi(pcszKey, pszTo) == 0) // if there is more than one entry, return the last one
lstrcpy(pszValue, pszFrom);
}
LocalFree(pszData);
if (hkPFROKey != NULL)
RegCloseKey(hkPFROKey);
}
DWORD CheckFile(DETECT_FILES Detect_Files)
{
char szFile[MAX_PATH] = { 0 };
DWORD dwRet = DET_NOTINSTALLED;
DWORD dwRetLast = DET_NOTINSTALLED;
int i =0;
while (Detect_Files.cPath[i])
{
switch (Detect_Files.cPath[i])
{
case 'S':
case 's':
GetSystemDirectory( szFile, sizeof(szFile) );
break;
case 'W':
case 'w':
GetWindowsDirectory( szFile, sizeof(szFile) );
break;
// Windows command folder
case 'C':
case 'c':
GetWindowsDirectory( szFile, sizeof(szFile) );
AddPath(szFile, "Command");
break;
default:
*szFile = '\0';
}
if (*szFile)
{
dwRet = CheckFileEx(szFile, Detect_Files);
switch (dwRet)
{
case DET_NOTINSTALLED:
break;
case DET_OLDVERSIONINSTALLED:
if (dwRetLast == DET_NOTINSTALLED)
dwRetLast = dwRet;
break;
case DET_INSTALLED:
if ((dwRetLast == DET_NOTINSTALLED) ||
(dwRetLast == DET_OLDVERSIONINSTALLED))
dwRetLast = dwRet;
break;
case DET_NEWVERSIONINSTALLED:
if ((dwRetLast == DET_NOTINSTALLED) ||
(dwRetLast == DET_OLDVERSIONINSTALLED) ||
(dwRetLast == DET_INSTALLED))
dwRetLast = dwRet;
break;
}
}
// go to the next directory letter.
while ((Detect_Files.cPath[i]) && (Detect_Files.cPath[i] != ','))
i++;
if (Detect_Files.cPath[i] == ',')
i++;
}
return dwRetLast;
}
DWORD CheckFileEx(LPSTR szDir, DETECT_FILES Detect_Files)
{
char szFile[MAX_PATH];
char szRenameFile[MAX_PATH];
DWORD dwInstalledVer, dwInstalledBuild;
DWORD dwRet = DET_NOTINSTALLED;
if (*szDir)
{
lstrcpy(szFile, szDir);
AddPath(szFile, Detect_Files.szFilename);
if (Detect_Files.dwMSVer == (DWORD)-1)
{
if (GetFileAttributes(szFile) != 0xFFFFFFFF)
dwRet = DET_INSTALLED;
}
else
{
ReadFromWininitOrPFRO(szFile, szRenameFile);
if (*szRenameFile != '\0')
GetVersionFromFile(szRenameFile, &dwInstalledVer, &dwInstalledBuild, TRUE);
else
GetVersionFromFile(szFile, &dwInstalledVer, &dwInstalledBuild, TRUE);
if (dwInstalledVer != 0)
dwRet = CompareVersions(Detect_Files.dwMSVer, Detect_Files.dwLSVer, dwInstalledVer, dwInstalledBuild);
}
}
return dwRet;
}
DWORD WINAPI DetectFile(DETECTION_STRUCT *pDet, LPSTR pszFilename)
{
DWORD dwRet = DET_NOTINSTALLED;
DWORD dwInstalledVer, dwInstalledBuild;
char szFile[MAX_PATH];
char szRenameFile[MAX_PATH];
dwInstalledVer = (DWORD) -1;
dwInstalledBuild = (DWORD) -1;
GetSystemDirectory(szFile, sizeof(szFile));
AddPath(szFile, pszFilename);
ReadFromWininitOrPFRO(szFile, szRenameFile);
if (*szRenameFile != '\0')
GetVersionFromFile(szRenameFile, &dwInstalledVer, &dwInstalledBuild, TRUE);
else
GetVersionFromFile(szFile, &dwInstalledVer, &dwInstalledBuild, TRUE);
if (dwInstalledVer != 0)
dwRet = CompareVersions(pDet->dwAskVer, pDet->dwAskBuild, dwInstalledVer, dwInstalledBuild);
if (pDet->pdwInstalledVer && pDet->pdwInstalledBuild)
{
*(pDet->pdwInstalledVer) = dwInstalledVer;
*(pDet->pdwInstalledBuild) = dwInstalledBuild;
}
return dwRet;
}