657 lines
16 KiB
C
657 lines
16 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
attrib.c
|
|
|
|
Abstract:
|
|
|
|
Implements the v1 script application attributes.
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 08-Jun-2000
|
|
|
|
Revision History:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
#include "pch.h"
|
|
#include "v1p.h"
|
|
|
|
#define DBG_ATTRIB "Attrib"
|
|
|
|
//
|
|
// Strings
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macros
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Types
|
|
//
|
|
|
|
typedef struct _MIGDB_ATTRIB {
|
|
INT AttribIndex;
|
|
UINT ArgCount;
|
|
PCTSTR Arguments;
|
|
BOOL NotOperator;
|
|
struct _MIGDB_ATTRIB *Next;
|
|
} MIGDB_ATTRIB, *PMIGDB_ATTRIB;
|
|
|
|
typedef BOOL(ATTRIBUTE_FUNCTION)(PCTSTR ArgMultiSz, PATTRIB_DATA Content);
|
|
typedef ATTRIBUTE_FUNCTION *PATTRIBUTE_FUNCTION;
|
|
|
|
typedef struct {
|
|
PCTSTR AttributeName;
|
|
PATTRIBUTE_FUNCTION Function;
|
|
UINT RequiredArgs;
|
|
} ATTRIBUTE_FUNCTION_ITEM, *PATTRIBUTE_FUNCTION_ITEM;
|
|
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
extern BOOL g_VcmMode; // in sgmqueue.c
|
|
|
|
//
|
|
// Macro expansion list
|
|
//
|
|
|
|
#define ATTRIBUTE_LIST \
|
|
DEFMAC(EXISTS, pExists, 0) \
|
|
DEFMAC(SAMEOBJECTNAME, pSameObjectName, 1) \
|
|
DEFMAC(SAMEOBJECTCONTENT, pSameObjectContent, 2) \
|
|
DEFMAC(ISREGFLAGSET, pIsRegFlagSet, 1) \
|
|
DEFMAC(MATCHES, pMatches, 1) \
|
|
DEFMAC(SET_PERSIST_FLAG, pSetPersistFlag, 0) \
|
|
DEFMAC(NOTEMPTY, pNotEmpty, 0) \
|
|
DEFMAC(VERSION, pVersion, 2) \
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macro expansion definition
|
|
//
|
|
|
|
#define DEFMAC(name,fn,req_args) ATTRIBUTE_FUNCTION fn;
|
|
|
|
ATTRIBUTE_LIST
|
|
|
|
#undef DEFMAC
|
|
|
|
#define DEFMAC(name,fn,req_args) TEXT(#name), fn, req_args,
|
|
|
|
ATTRIBUTE_FUNCTION_ITEM g_FnList[] = {
|
|
|
|
ATTRIBUTE_LIST /* , */
|
|
NULL, NULL, 0
|
|
};
|
|
|
|
|
|
|
|
//
|
|
// Code
|
|
//
|
|
|
|
#define STATE_ATTRNAME 1
|
|
#define STATE_ATTRARG 2
|
|
|
|
INT
|
|
pGetAttribIndex (
|
|
IN PCTSTR AttribName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the index in attribute functions array for a specified
|
|
attribute.
|
|
|
|
Arguments:
|
|
|
|
AttribName - Attribute name
|
|
|
|
Return value:
|
|
|
|
-1 - no such attribute in attribute table
|
|
|
|
--*/
|
|
|
|
{
|
|
INT attribIndex;
|
|
INT rc = 0;
|
|
PTSTR attrEnd = NULL;
|
|
TCHAR savedChar = 0;
|
|
|
|
attrEnd = (PTSTR) SkipSpaceR (AttribName, GetEndOfString (AttribName));
|
|
if (attrEnd != NULL) {
|
|
attrEnd = _tcsinc (attrEnd);
|
|
savedChar = attrEnd [0];
|
|
attrEnd [0] = 0;
|
|
}
|
|
__try {
|
|
for (attribIndex = 0 ; g_FnList[attribIndex].AttributeName ; attribIndex++) {
|
|
if (StringIMatch (g_FnList[attribIndex].AttributeName, AttribName)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!g_FnList[attribIndex].AttributeName) {
|
|
attribIndex = -1;
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_DETECT_ATTRIB_NOT_FOUND, AttribName));
|
|
}
|
|
|
|
rc = attribIndex;
|
|
}
|
|
__finally {
|
|
if (attrEnd != NULL) {
|
|
attrEnd [0] = savedChar;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
UINT
|
|
pGetReqArgCount (
|
|
IN INT AttributeIndex
|
|
)
|
|
{
|
|
if (AttributeIndex < 0 || AttributeIndex > ARRAYSIZE(g_FnList)) {
|
|
return 0;
|
|
}
|
|
|
|
return g_FnList[AttributeIndex].RequiredArgs;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pValidateArg (
|
|
IN OUT PMIGDB_ATTRIB AttribStruct
|
|
)
|
|
{
|
|
//
|
|
// Validate all AttribStruct members
|
|
//
|
|
|
|
MYASSERT (AttribStruct);
|
|
|
|
if (AttribStruct->ArgCount != pGetReqArgCount (AttribStruct->AttribIndex)) {
|
|
AttribStruct->AttribIndex = -1;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PMIGDB_ATTRIB
|
|
pLoadAttribData (
|
|
IN PMHANDLE Pool,
|
|
IN PCTSTR MultiSzStr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a list of MIGDB_ATTRIBs from a multisz.
|
|
|
|
Arguments:
|
|
|
|
Pool - Specifies a pool that temporary structures and the return value
|
|
will be allocated from
|
|
|
|
MultiSzStr - Specifies the multisz to be processed. The multi-sz must
|
|
be in the form of ATTRIB or ATTRIB(arg[,arg,...])
|
|
|
|
Return value:
|
|
|
|
MIGDB_ATTRIB nodes
|
|
|
|
--*/
|
|
|
|
{
|
|
MULTISZ_ENUM multiSzEnum;
|
|
PMIGDB_ATTRIB result = NULL;
|
|
PMIGDB_ATTRIB tmpAttr = NULL;
|
|
INT state = STATE_ATTRNAME;
|
|
PTSTR currStrPtr = NULL;
|
|
PTSTR currArgPtr = NULL;
|
|
PTSTR endArgPtr = NULL;
|
|
TCHAR savedChar = 0;
|
|
GROWBUFFER argList = INIT_GROWBUFFER;
|
|
|
|
if (EnumFirstMultiSz (&multiSzEnum, MultiSzStr)) {
|
|
|
|
do {
|
|
currStrPtr = (PTSTR) SkipSpace (multiSzEnum.CurrentString);
|
|
|
|
if (state == STATE_ATTRNAME) {
|
|
tmpAttr = (PMIGDB_ATTRIB) PmGetMemory (Pool, sizeof (MIGDB_ATTRIB));
|
|
|
|
ZeroMemory (tmpAttr, sizeof (MIGDB_ATTRIB));
|
|
|
|
if (_tcsnextc (currStrPtr) == TEXT('!')) {
|
|
currStrPtr = _tcsinc (currStrPtr);
|
|
currStrPtr = (PTSTR) SkipSpace (currStrPtr);
|
|
tmpAttr->NotOperator = TRUE;
|
|
}
|
|
|
|
currArgPtr = _tcschr (currStrPtr, TEXT('('));
|
|
|
|
if (currArgPtr) {
|
|
endArgPtr = _tcsdec (currStrPtr, currArgPtr);
|
|
if (endArgPtr) {
|
|
endArgPtr = (PTSTR) SkipSpaceR (currStrPtr, endArgPtr);
|
|
endArgPtr = _tcsinc (endArgPtr);
|
|
}
|
|
else {
|
|
endArgPtr = currStrPtr;
|
|
}
|
|
|
|
savedChar = *endArgPtr;
|
|
*endArgPtr = 0;
|
|
tmpAttr->AttribIndex = pGetAttribIndex (currStrPtr);
|
|
*endArgPtr = savedChar;
|
|
currStrPtr = _tcsinc (currArgPtr);
|
|
state = STATE_ATTRARG;
|
|
}
|
|
else {
|
|
// this attribute has no arguments.
|
|
tmpAttr->AttribIndex = pGetAttribIndex (currStrPtr);
|
|
tmpAttr->Next = result;
|
|
result = tmpAttr;
|
|
|
|
pValidateArg (result);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (state == STATE_ATTRARG) {
|
|
currStrPtr = (PTSTR) SkipSpace (currStrPtr);
|
|
endArgPtr = _tcsrchr (currStrPtr, TEXT(')'));
|
|
if (endArgPtr && endArgPtr[1] == 0) {
|
|
endArgPtr = _tcsdec (currStrPtr, endArgPtr);
|
|
if (endArgPtr) {
|
|
endArgPtr = (PTSTR) SkipSpaceR (currStrPtr, endArgPtr);
|
|
endArgPtr = _tcsinc (endArgPtr);
|
|
}
|
|
else {
|
|
endArgPtr = currStrPtr;
|
|
}
|
|
savedChar = *endArgPtr;
|
|
*endArgPtr = 0;
|
|
} else {
|
|
endArgPtr = NULL;
|
|
}
|
|
|
|
GbMultiSzAppend (&argList, currStrPtr);
|
|
|
|
tmpAttr->ArgCount++;
|
|
|
|
if (endArgPtr) {
|
|
*endArgPtr = savedChar;
|
|
tmpAttr->Arguments = PmDuplicateMultiSz (Pool, (PTSTR) argList.Buf);
|
|
GbFree (&argList);
|
|
state = STATE_ATTRNAME;
|
|
tmpAttr->Next = result;
|
|
result = tmpAttr;
|
|
|
|
pValidateArg (result);
|
|
}
|
|
}
|
|
|
|
} while (EnumNextMultiSz (&multiSzEnum));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
TestAttributes (
|
|
IN PMHANDLE WorkPool,
|
|
IN PCTSTR ArgumentMultiSz,
|
|
IN PATTRIB_DATA AttribData
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TestAttributes executes the attribute functions specified in the
|
|
ArgumentMultiSz parameter. Each argument is tested until they all succeed
|
|
or until one fails.
|
|
|
|
Arguments:
|
|
|
|
WorkPool - Specifies a pool handle for fast allocations
|
|
ArgumentMultiSz - Specifies the multi-sz that contains argument
|
|
specifications
|
|
AttribData - Specifies the object name, script specifications and
|
|
object content
|
|
|
|
Return Value:
|
|
|
|
TRUE if all attributes pass (or if zero attributes were specified), FALSE
|
|
otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMIGDB_ATTRIB attrib;
|
|
PMIGDB_ATTRIB tmpAttrib;
|
|
BOOL result = TRUE;
|
|
|
|
attrib = pLoadAttribData (WorkPool, ArgumentMultiSz);
|
|
tmpAttrib = attrib;
|
|
|
|
while (result && attrib) {
|
|
if (attrib->AttribIndex < 0 || attrib->AttribIndex >= ARRAYSIZE(g_FnList)) {
|
|
DEBUGMSG ((DBG_WHOOPS, "Invalid attribute index %i", attrib->AttribIndex));
|
|
result = FALSE;
|
|
} else {
|
|
|
|
result = g_FnList[attrib->AttribIndex].Function (attrib->Arguments, AttribData);
|
|
|
|
if (attrib->NotOperator) {
|
|
result = !result;
|
|
}
|
|
}
|
|
|
|
attrib = attrib->Next;
|
|
}
|
|
|
|
// now free the attribute list
|
|
attrib = tmpAttrib;
|
|
while (attrib) {
|
|
tmpAttrib = attrib->Next;
|
|
if (attrib->Arguments) {
|
|
PmReleaseMemory (WorkPool, attrib->Arguments);
|
|
}
|
|
PmReleaseMemory (WorkPool, attrib);
|
|
attrib = tmpAttrib;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
//
|
|
// Attribute functions (see ATTRIBUTE_LIST)
|
|
//
|
|
|
|
BOOL
|
|
pExists (
|
|
IN PCTSTR FunctionArguments,
|
|
IN PATTRIB_DATA Data
|
|
)
|
|
{
|
|
return (Data->ReturnString != NULL);
|
|
}
|
|
|
|
BOOL
|
|
pSameObjectName (
|
|
IN PCTSTR FunctionArguments,
|
|
IN PATTRIB_DATA Data
|
|
)
|
|
{
|
|
return (StringIMatch (FunctionArguments, Data->ScriptSpecifiedObject));
|
|
}
|
|
|
|
BOOL
|
|
pSameObjectContent (
|
|
IN PCTSTR FunctionArguments,
|
|
IN PATTRIB_DATA Data
|
|
)
|
|
{
|
|
PCTSTR scriptObjectType = NULL;
|
|
PCTSTR scriptObjectName = NULL;
|
|
ATTRIB_DATA attribData;
|
|
BOOL result = FALSE;
|
|
|
|
scriptObjectType = FunctionArguments;
|
|
scriptObjectName = GetEndOfString (FunctionArguments);
|
|
if (scriptObjectName) {
|
|
scriptObjectName ++;
|
|
}
|
|
|
|
if (!scriptObjectType || !scriptObjectName) {
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMemory (&attribData, sizeof (ATTRIB_DATA));
|
|
attribData.ScriptSpecifiedType = scriptObjectType;
|
|
attribData.ScriptSpecifiedObject = scriptObjectName;
|
|
attribData.ApplicationName = Data->ApplicationName;
|
|
|
|
if (!AllocScriptType (&attribData)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// let's persist the object in VCM mode so we can look at it later
|
|
if (g_VcmMode && attribData.ObjectName) {
|
|
if (IsmDoesObjectExist (attribData.ObjectTypeId, attribData.ObjectName)) {
|
|
IsmMakePersistentObject (attribData.ObjectTypeId, attribData.ObjectName);
|
|
}
|
|
}
|
|
|
|
if (Data->ObjectContent && attribData.ObjectContent) {
|
|
if (Data->ObjectContent->ObjectTypeId == attribData.ObjectContent->ObjectTypeId) {
|
|
if (Data->ObjectContent->Details.DetailsSize == attribData.ObjectContent->Details.DetailsSize) {
|
|
if (!Data->ObjectContent->Details.DetailsSize ||
|
|
TestBuffer (
|
|
Data->ObjectContent->Details.DetailsData,
|
|
attribData.ObjectContent->Details.DetailsData,
|
|
Data->ObjectContent->Details.DetailsSize
|
|
)
|
|
) {
|
|
if (Data->ObjectContent->ContentInFile == attribData.ObjectContent->ContentInFile) {
|
|
if (Data->ObjectContent->ContentInFile) {
|
|
if (StringIMatch (
|
|
Data->ObjectContent->FileContent.ContentPath,
|
|
attribData.ObjectContent->FileContent.ContentPath
|
|
)
|
|
) {
|
|
result = TRUE;
|
|
}
|
|
} else {
|
|
if (Data->ObjectContent->MemoryContent.ContentSize == attribData.ObjectContent->MemoryContent.ContentSize) {
|
|
if (!Data->ObjectContent->MemoryContent.ContentSize ||
|
|
TestBuffer (
|
|
Data->ObjectContent->MemoryContent.ContentBytes,
|
|
attribData.ObjectContent->MemoryContent.ContentBytes,
|
|
Data->ObjectContent->MemoryContent.ContentSize
|
|
)
|
|
) {
|
|
result = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FreeScriptType (&attribData);
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
pIsRegFlagSet (
|
|
IN PCTSTR FunctionArguments,
|
|
IN PATTRIB_DATA Data
|
|
)
|
|
{
|
|
DWORD inValue;
|
|
DWORD value;
|
|
|
|
if (!Data) {
|
|
return FALSE;
|
|
}
|
|
if (!FunctionArguments) {
|
|
return FALSE;
|
|
}
|
|
if (!Data->ObjectContent) {
|
|
return FALSE;
|
|
}
|
|
if ((Data->ObjectContent->ObjectTypeId & ~PLATFORM_MASK) != MIG_REGISTRY_TYPE) {
|
|
return FALSE;
|
|
}
|
|
if (Data->ObjectContent->Details.DetailsSize != sizeof (DWORD)) {
|
|
return FALSE;
|
|
}
|
|
if ((*((PDWORD)(Data->ObjectContent->Details.DetailsData)) != REG_DWORD) &&
|
|
(*((PDWORD)(Data->ObjectContent->Details.DetailsData)) != REG_SZ)
|
|
) {
|
|
return FALSE;
|
|
}
|
|
if (Data->ObjectContent->ContentInFile) {
|
|
return FALSE;
|
|
}
|
|
if (Data->ObjectContent->MemoryContent.ContentSize == 0) {
|
|
return FALSE;
|
|
}
|
|
if (Data->ObjectContent->MemoryContent.ContentBytes == NULL) {
|
|
return FALSE;
|
|
}
|
|
if (*((PDWORD)(Data->ObjectContent->Details.DetailsData)) == REG_DWORD) {
|
|
inValue = *((PDWORD)(Data->ObjectContent->MemoryContent.ContentBytes));
|
|
} else {
|
|
_stscanf ((PCTSTR)Data->ObjectContent->MemoryContent.ContentBytes, TEXT("%ld"), &inValue);
|
|
}
|
|
_stscanf (FunctionArguments, TEXT("%lx"), &value);
|
|
if (!(inValue & value)) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
pMatches (
|
|
IN PCTSTR FunctionArguments,
|
|
IN PATTRIB_DATA Data
|
|
)
|
|
{
|
|
if (!Data->ReturnString) {
|
|
return FALSE;
|
|
}
|
|
|
|
return (StringIMatch (FunctionArguments, Data->ReturnString));
|
|
}
|
|
|
|
BOOL
|
|
pSetPersistFlag (
|
|
IN PCTSTR FunctionArguments,
|
|
IN PATTRIB_DATA Data
|
|
)
|
|
{
|
|
if (IsmDoesObjectExist (Data->ObjectTypeId, Data->ObjectName)) {
|
|
IsmMakePersistentObject (Data->ObjectTypeId, Data->ObjectName);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
pNotEmpty (
|
|
IN PCTSTR FunctionArguments,
|
|
IN PATTRIB_DATA Data
|
|
)
|
|
{
|
|
if (!Data->ReturnString) {
|
|
return FALSE;
|
|
}
|
|
|
|
return (Data->ReturnString[0] != 0);
|
|
}
|
|
|
|
BOOL
|
|
pVersion (
|
|
IN PCTSTR FunctionArguments,
|
|
IN PATTRIB_DATA Data
|
|
)
|
|
{
|
|
PCTSTR versionStr = NULL;
|
|
PCTSTR versionValue = NULL;
|
|
ATTRIB_DATA attribData;
|
|
BOOL result = FALSE;
|
|
|
|
versionStr = FunctionArguments;
|
|
if (!versionStr) {
|
|
return FALSE;
|
|
}
|
|
|
|
versionValue = GetEndOfString (FunctionArguments);
|
|
if (!versionValue) {
|
|
return FALSE;
|
|
}
|
|
versionValue ++;
|
|
|
|
if (!Data) {
|
|
return FALSE;
|
|
}
|
|
if (!Data->ReturnString) {
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMemory (&attribData, sizeof (ATTRIB_DATA));
|
|
attribData.ScriptSpecifiedType = TEXT("File");
|
|
attribData.ScriptSpecifiedObject = Data->ReturnString;
|
|
attribData.ApplicationName = Data->ApplicationName;
|
|
|
|
if (!AllocScriptType (&attribData)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// let's persist the object in VCM mode so we can look at it later
|
|
if (g_VcmMode && attribData.ObjectName) {
|
|
if (IsmDoesObjectExist (attribData.ObjectTypeId, attribData.ObjectName)) {
|
|
IsmMakePersistentObject (attribData.ObjectTypeId, attribData.ObjectName);
|
|
}
|
|
}
|
|
|
|
if (attribData.ObjectContent &&
|
|
attribData.ObjectContent->ContentInFile &&
|
|
attribData.ObjectContent->FileContent.ContentPath
|
|
) {
|
|
result = VrCheckFileVersion (attribData.ObjectContent->FileContent.ContentPath, versionStr, versionValue);
|
|
}
|
|
|
|
FreeScriptType (&attribData);
|
|
|
|
return result;
|
|
}
|
|
|