/*++ 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: --*/ // // 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.Platform = Data->Platform; 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.Platform = Data->Platform; 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; }