/*Function to return agentId value from registry If registration has never been attempted on this machine, then this function returns an empty string and returns TRUE for shouldGenerateAgentId*/ MI_Result GetAgentIdFromRegistry( _Outptr_result_maybenull_z_ MI_Char** agentId, _Inout_ MI_Boolean *shouldGenerateAgentId) { if (File_ExistT(AGENTID_FILE_PATH) != 0) { // We are not able to get the agent Id. // We should generate a new agentId. *shouldGenerateAgentId = MI_TRUE ; return MI_RESULT_OK; } /* inhale contents fails into agentId */ *agentId = InhaleTextFile(AGENTID_FILE_PATH); if (Tcscasecmp(MI_T(" "), *agentId) == 0 || Tcscasecmp(MI_T(""), *agentId) == 0) { // We are not able to get the agent Id. // We should generate a new agentId. *shouldGenerateAgentId = MI_TRUE; return MI_RESULT_OK; } *shouldGenerateAgentId = MI_FALSE; (*agentId)[36] = '\0'; return MI_RESULT_OK; }
/*Function to return true if registration needs to be done*/ MI_Boolean ShouldDoRegistration( _In_ RegistrationManager* self, _In_ RegistrationRequest* request, _Outptr_result_maybenull_ MI_Instance **cimErrorDetails) { MI_Result result = MI_RESULT_OK; MI_Uint32 i = 0; MI_Value value; MI_Char* url = NULL; MI_Type type; MI_Uint32 flags; if (cimErrorDetails) { *cimErrorDetails = NULL; } MI_Instance *registrationDataInstance = request->registrationData; result = MI_Instance_GetElement(registrationDataInstance, MSFT_ServerURL_Name, &value, NULL, NULL, NULL); EH_CheckResult(result); url = value.string; result = DSC_MI_Instance_GetElement(registrationDataInstance, MSFT_RegistrationKey_Name, &value, &type, &flags, NULL); if (result == MI_RESULT_OK && type == MI_STRING && (!(flags & MI_FLAG_NULL))) { if (Tcscasecmp(value.string, MI_T("")) != 0) { // This means that a non-empty RegistrationKey is specified. Then, we always do registration. // If RegistrationKey is not specified, then we check the cache and do/skip registration based on ServerURL DSC_EventWriteLCMAgentAttemptRegistration(g_ConfigurationDetails.jobGuidString, self->agentId, url); return MI_TRUE; } } for (i = 0; i < self->numberOfServerURLs; i++) { if (Tcscasecmp(self->serverURLs[i], url) == 0) { DSC_EventWriteLCMServerURLRegistered(g_ConfigurationDetails.jobGuidString, self->agentId, url); return MI_FALSE; } } EH_UNWIND: return MI_TRUE; }
MI_Result ValidateInfrastructureSchema(_In_ MI_ClassA *miClassArray, _Outptr_result_maybenull_ MI_Instance **extendedError ) { MI_Result r = MI_RESULT_OK; MI_Uint32 xCount = 0, yCount = 0; if( extendedError ) *extendedError = NULL; SetJobId(); DSC_EventWriteValidatingInfrastructureSchema(miClassArray->size); //Validate various infrastructure classes for( xCount = 0 ; xCount < miClassArray->size ; xCount++) { for (yCount = 0; g_InfraSchemaValidators[yCount].wszClassName != NULL; yCount++) { if( Tcscasecmp(miClassArray->data[xCount]->classDecl->name, g_InfraSchemaValidators[yCount].wszClassName) == 0 ) { break; } } if( g_InfraSchemaValidators[yCount].wszClassName == NULL || NitsShouldFault(NitsHere(), NitsAutomatic)) { return GetCimMIError(MI_RESULT_INVALID_PARAMETER, extendedError, ID_MODMAN_VALIDATE_INFRASCHEMA); } r = g_InfraSchemaValidators[yCount].Validator(miClassArray->data[xCount], extendedError); if( r != MI_RESULT_OK) { return r; } } return r; }
MI_Result GetThumbprintForRegisteredServerURL( _In_ RegistrationManager* self, _In_ MI_Instance* registrationData, _Outptr_result_maybenull_z_ MI_Char** thumbprint, _Outptr_result_maybenull_ MI_Instance **cimErrorDetails) { size_t dwSize; MI_Value value; int retValue; MI_Uint32 i = 0; MI_Result result = MI_RESULT_OK; if (cimErrorDetails) { *cimErrorDetails = NULL; } *thumbprint = 0; if (self->serverURLs == NULL) { InitializeServerURLs(self, cimErrorDetails); } if (self->serverURLs != NULL) { result = MI_Instance_GetElement(registrationData, MSFT_ServerURL_Name, &value, NULL, NULL, NULL); EH_CheckResult(result); for (i = 0; i < self->numberOfServerURLs; i++) { if (self->serverURLs[i] != NULL && Tcscasecmp(self->serverURLs[i], value.string) == 0) { dwSize = Tcslen(self->serverCertificateThumbprints[i]) + 1; *thumbprint = (MI_Char*)DSC_malloc(dwSize*sizeof(MI_Char), NitsHere()); if (*thumbprint == NULL) { EH_Fail_(GetCimMIError(MI_RESULT_SERVER_LIMITS_EXCEEDED, cimErrorDetails, ID_LCMHELPER_MEMORY_ERROR)); } retValue = Stprintf(*thumbprint, dwSize, MI_T("%T"), self->serverCertificateThumbprints[i]); if (retValue == -1 || NitsShouldFault(NitsHere(), NitsAutomatic)) { DSC_free(*thumbprint); EH_Fail_(GetCimMIError(MI_RESULT_FAILED, cimErrorDetails, ID_LCMHELPER_PRINTF_ERROR)); } result = MI_RESULT_OK; break; } } } EH_UNWIND: return result; }
/// <summary> /// Try begin general method if another method is not running currently. General methods don't include StopConfiguration /// </summary> MI_Result TryBeginLcmOperation( _In_z_ const MI_Char* methodName, _Outptr_result_maybenull_ MI_Instance **cimErrorDetails) { MI_Char* originalMethodName; int waitResult = 0; *cimErrorDetails = NULL; originalMethodName = (MI_Char*)Atomic_CompareAndSwap(&g_activeOperationMethodName, (ptrdiff_t) NULL, (ptrdiff_t)methodName); if (originalMethodName != NULL) { // We silently let GetMetaConfiguration to go if the active operation is not SetMetaConfiguration if (Tcscasecmp(originalMethodName, MSFT_DSCLocalConfigManager_SendMetaConfigurationApply) == 0 || Tcscasecmp(methodName, MSFT_DSCLocalConfigManager_GetMetaConfiguration) != 0) { return GetCimMIError3Params(MI_RESULT_FAILED, cimErrorDetails, ID_LCM_MULTIPLE_METHOD_REQUEST, methodName, originalMethodName, methodName); } } waitResult = Sem_TimedWait(&g_h_ConfigurationStoppedEvent, (int)0); //Ignore the result return MI_RESULT_OK; }
ProvRegClassInheritanceNode* _FindClassNodeInTree( ProvRegClassInheritanceNode* root, const ZChar* cn) { while (root) { if (Tcscasecmp(cn,root->cn)==0) { return root; } root = _GetNextTreeNode(root); } return root; }
ProvRegNamespaceNode* _FindNamespace( ProvReg* self, MI_ConstString ns, MI_Boolean extraClass) { /* find namespace node in the list */ ProvRegNamespaceNode* current; if(extraClass) current = self->namespacesForExtraClasses; else current = self->namespaces; while (current && Tcscasecmp(ns,current->ns) != 0) current = current->next; return current; }
/* Find event steam provider under given namespace */ _Use_decl_annotations_ const ProvRegEntry* ProvReg_FindProviderForClassByType( ProvReg* self, const ZChar* nameSpace, const ZChar* className, ProvRegType type, MI_Result *findError) { ProvRegEntry* p; MI_Boolean namespaceFound = 0; unsigned int nameSpaceHash = Hash(nameSpace); unsigned int classNameHash = 0; if (!className) { if(findError) *findError = MI_RESULT_INVALID_PARAMETER; return NULL; } if (className) classNameHash = Hash(className); for (p = self->head; p; p = p->next) { // comparing namespace everytime may slightly affect perf // but it enables us to give right error back to the client if (nameSpaceHash == p->nameSpaceHash && Tcscasecmp(p->nameSpace, nameSpace) == 0) { if (p->regType == type) { if (className) { /* for normal and indication class */ if( classNameHash == p->classNameHash && Tcscasecmp(p->className, className) == 0) { if(findError) { *findError = MI_RESULT_OK; } return p; } } else { /* for event stream class */ if(findError) { *findError = MI_RESULT_OK; } return p; } namespaceFound = MI_TRUE; } } } if(findError) { *findError = (MI_TRUE == namespaceFound) ? MI_RESULT_INVALID_CLASS : MI_RESULT_INVALID_NAMESPACE; } /* Not found */ return NULL; }
MI_Boolean IsMatchedKeyProperties( _In_ MI_Instance* instance0, _In_ MI_Instance* instance1, _Outptr_result_maybenull_z_ MI_Char** keywords, _Out_ MI_Result* miResult, _Outptr_result_maybenull_ MI_Instance **extendedError) { MI_Uint32 i, j; MI_Result result0, result1; MI_Value value0, value1; MI_Type type0, type1; Intlstr intlstr = Intlstr_Null; MI_Char* tempKeywords = NULL; MI_Char* tempKeywordsBackup = NULL; size_t length; MI_PropertyDecl** properties; if (extendedError == NULL) { return MI_RESULT_INVALID_PARAMETER; } *extendedError = NULL; // Explicitly set *extendedError to NULL as _Outptr_ requires setting this at least once. *miResult = MI_RESULT_OK; *keywords = NULL; properties = (MI_PropertyDecl**)instance0->classDecl->properties; for (i = 0; i < instance0->classDecl->numProperties; i++) { for (j = 0; j < properties[i]->numQualifiers; j++) { if (Tcscasecmp(properties[i]->qualifiers[j]->name, MI_T("Key")) == 0) { result0 = DSC_MI_Instance_GetElement(instance0, properties[i]->name, &value0, &type0, NULL, NULL); result1 = DSC_MI_Instance_GetElement(instance1, properties[i]->name, &value1, &type1, NULL, NULL); if (result0 == MI_RESULT_OK && result1 == MI_RESULT_OK && type0 == type1 && IsSameMiValue(&value0, &value1, type0)) { // key is the same, building keywords list. length = Tcslen(properties[i]->name) + 1; if (tempKeywords == NULL) { // the first keyword. tempKeywords = (MI_Char*)DSC_malloc(length * sizeof (MI_Char), NitsHere()); if (tempKeywords == NULL) { *miResult = CreateMemoryError(extendedError); return MI_TRUE; } memcpy(tempKeywords, properties[i]->name, length * sizeof(MI_Char) ); } else { // the second or more keywords. if (intlstr.str == NULL) { // create separator string once. GetResourceString(ID_CA_COMMA_SEPARATOR, &intlstr); if (intlstr.str == NULL) { *miResult = CreateMemoryError(extendedError); DSC_free(tempKeywords); return MI_TRUE; } } length += Tcslen(tempKeywords) + Tcslen(intlstr.str); tempKeywordsBackup = tempKeywords; tempKeywords = (MI_Char*)DSC_realloc(tempKeywordsBackup, length * sizeof (MI_Char), NitsHere()); if (tempKeywords == NULL) { *miResult = CreateMemoryError(extendedError); DSC_free(tempKeywordsBackup); Intlstr_Free(intlstr); return MI_TRUE; } Stprintf(tempKeywords, length, MI_T("%T%T"), intlstr.str, properties[i]->name); } } else { if (tempKeywords) { DSC_free(tempKeywords); } if (intlstr.str) { Intlstr_Free(intlstr); } if(result0 != MI_RESULT_OK) { *miResult = result0; } else if(result1 != MI_RESULT_OK) { *miResult = result1; } return MI_FALSE; } break; } } } if (intlstr.str) { Intlstr_Free(intlstr); } // at least one key was found, and all matched. if (tempKeywords) { *keywords = tempKeywords; return MI_TRUE; } return MI_FALSE; }
MI_Result ValidateIfDuplicatedInstances( _In_ MI_InstanceA *instanceA, _Outptr_result_maybenull_ MI_Instance **extendedError) { MI_Result miResult = MI_RESULT_OK; MI_Instance* instance0; MI_Instance* instance1; MI_Char* keywords; const MI_Char* resourceId0; const MI_Char* resourceId1; MI_Uint32 i, j; if (extendedError == NULL) { return MI_RESULT_INVALID_PARAMETER; } *extendedError = NULL; // Explicitly set *extendedError to NULL as _Outptr_ requires setting this at least once. for (i = 0; i < instanceA->size; i++) { instance0 = instanceA->data[i]; if (instance0->classDecl->superClass != NULL &&Tcscasecmp(instance0->classDecl->superClass, BASE_RESOURCE_CLASSNAME) == 0) { for (j = i + 1; j < instanceA->size; j++) { instance1 = instanceA->data[j]; if (Tcscasecmp(instance0->classDecl->name, instance1->classDecl->name) == 0 && IsMatchedKeyProperties(instance0, instance1, &keywords, &miResult, extendedError)) { if (miResult != MI_RESULT_OK && *extendedError) { return miResult; } resourceId0 = GetResourceId(instance0); resourceId1 = GetResourceId(instance1); if (resourceId0 == NULL || resourceId1 == NULL) { miResult = CreateMemoryError(extendedError); DSC_free(keywords); return miResult; } miResult = GetCimMIError4Params(MI_RESULT_ALREADY_EXISTS, extendedError, ID_CA_DUPLICATE_KEYS, instance0->classDecl->name, resourceId0, resourceId1, keywords); if (keywords) { DSC_free(keywords); } return miResult; } else if (miResult != MI_RESULT_OK) { return miResult; } } } } return MI_RESULT_OK; }
/* ** ** Find ISA operator and its target classname; Take following query for example, ** Select * from CIM_InstCreation where SourceInstance isa "Win32_process" ** (1) It's a lifecycle indication query ** (2) It's target class is Win32_process ** ** Following query is invalid since OR operator makes the target class ambiguous, ** Select * from CIM_InstCreation where SourceInstance isa "Win32_process" OR (2>1) ** This query targets to all classes under the namespace, which is NOT a valid scenario ** to support; This function is to find whether an given query is a valid lifecycle ** indication query; If yes return 0 and output the target class name; otherwise return non 0; ** ** */ static MI_Result _FindLifecycleClass( _In_ SubscriptionTargetType stt, _In_ const WQL* wql, _Outptr_result_maybenull_z_ const ZChar** targetClassname, _Outptr_result_maybenull_z_ const MI_Char** errormessage) { static const ZChar* sSourceInstanceProperty = ZT("SourceInstance"); static const ZChar* sPreviousInstanceProperty = ZT("PreviousInstance"); size_t i; WQL_SymbolEx symbols[WQL_MAX_SYMBOLS]; size_t nsymbols = 0; MI_Boolean foundISA = MI_FALSE; MI_Result r = MI_RESULT_NOT_SUPPORTED; DEBUG_ASSERT (wql && wql->className && targetClassname && errormessage); *targetClassname = NULL; *errormessage = NULL; /* Fail if there is no WHERE clause */ if (wql->nsymbols == 0) return MI_RESULT_OK; /* Perform postfix evaluation */ for (i = 0; i < wql->nsymbols; i++) { const WQL_Symbol* sym = &wql->symbols[i]; WQL_Type type = sym->type; if (nsymbols >= WQL_MAX_SYMBOLS) return r; switch (type) { case WQL_TYPE_AND: case WQL_TYPE_OR: { if (nsymbols < 2) return r; { WQL_SymbolEx s2 = symbols[--nsymbols]; WQL_SymbolEx s1 = symbols[--nsymbols]; WQL_SymbolEx s; memset(&s, 0, sizeof(WQL_SymbolEx)); if (type == WQL_TYPE_OR) { if (s1.isa || s2.isa) { *errormessage = STR_LIFECYCLE_INDICATION_QUERY_ISA_OPERATOR_WITHIN_OR; trace_FindLifecycleClass_InvalidLifecycleQuery(); return r; } } if (s1.base.type != WQL_TYPE_BOOLEAN) return r; if (s2.base.type != WQL_TYPE_BOOLEAN) return r; s.base.type = WQL_TYPE_BOOLEAN; s.base.value.boolean = 0; s.isa = s1.isa || s2.isa; symbols[nsymbols++] = s; } break; } case WQL_TYPE_NOT: { if (nsymbols < 1) return r; { WQL_SymbolEx s1 = symbols[--nsymbols]; WQL_SymbolEx s; memset(&s, 0, sizeof(WQL_SymbolEx)); if (s1.base.type != WQL_TYPE_BOOLEAN) return r; s.base.type = WQL_TYPE_BOOLEAN; s.base.value.boolean = 0; s.isa = s1.isa; symbols[nsymbols++] = s; } break; } case WQL_TYPE_EQ: case WQL_TYPE_NE: case WQL_TYPE_LT: case WQL_TYPE_LE: case WQL_TYPE_GT: case WQL_TYPE_GE: case WQL_TYPE_LIKE: { if (nsymbols < 2) return r; { WQL_SymbolEx s2 = symbols[--nsymbols]; WQL_SymbolEx s1 = symbols[--nsymbols]; WQL_SymbolEx s; memset(&s, 0, sizeof(WQL_SymbolEx)); s.base.type = WQL_TYPE_BOOLEAN; s.base.value.boolean = 0; s.isa = s1.isa || s2.isa; symbols[nsymbols++] = s; } break; } case WQL_TYPE_IDENTIFIER: { WQL_SymbolEx s; memset(&s, 0, sizeof(WQL_SymbolEx)); s.base.type = WQL_TYPE_BOOLEAN; s.base.value.boolean = 0; s.isa = MI_FALSE; symbols[nsymbols++] = s; break; } case WQL_TYPE_BOOLEAN: case WQL_TYPE_INTEGER: case WQL_TYPE_REAL: case WQL_TYPE_STRING: case WQL_TYPE_NULL: case WQL_TYPE_ANY: { WQL_SymbolEx s; memcpy(&s.base, sym, sizeof(WQL_Symbol)); s.isa = MI_FALSE; symbols[nsymbols++] = s; break; } case WQL_TYPE_ISA: { WQL_SymbolEx s2; WQL_SymbolEx s1; if (foundISA == MI_TRUE) { *errormessage = STR_LIFECYCLE_INDICATION_QUERY_MORETHANONE_ISA_OPERATOR; trace_FindLifecycleClass_UnsupportedLifecycleQuery(); return r; } if (nsymbols < 2) { trace_FindLifecycleClass_TooFewOperandsISA(); return r; } s2 = symbols[--nsymbols]; s1 = symbols[--nsymbols]; if (s1.base.type != WQL_TYPE_STRING) { trace_FindLifecycleClass_InvalidTokenType(); return r; } if (s2.base.type != WQL_TYPE_STRING) { trace_FindLifecycleClass_InvalidTokenType(); return r; } /* Check Embedded property name is valid or not */ { int cmpresult = Tcscasecmp(sSourceInstanceProperty, s1.base.value.string); if (cmpresult != 0) { if (stt == SUBSCRIP_TARGET_LIFECYCLE_MODIFY) { cmpresult = Tcscasecmp(sPreviousInstanceProperty, s1.base.value.string); } } if (cmpresult != 0) { *errormessage = STR_LIFECYCLE_INDICATION_QUERY_ISA_HAS_WRONG_PROPERTYNAME; r = MI_RESULT_INVALID_QUERY; trace_FindLifecycleClass_InvalidEmbeddedProperty(s1.base.value.string); return r; } } /* Put ISA result symbol into stack */ { WQL_SymbolEx s; memset(&s, 0, sizeof(WQL_SymbolEx)); s.base.type = WQL_TYPE_BOOLEAN; s.base.value.boolean = MI_FALSE; s.isa = MI_TRUE; symbols[nsymbols++] = s; *targetClassname = s2.base.value.string; foundISA = MI_TRUE; trace_FindLifecycleClass_FoundISAOperator(s1.base.value.string, s2.base.value.string); } break; } } } /* There should be exactly 1 symbol left on stack */ if (nsymbols != 1) { trace_FindLifecycleClass_EvalHasMoreThanOneSymbol(nsymbols); return r; } /* There should be exactly 1 symbol left on stack */ /* Final token on stack should be boolean */ if (symbols[0].base.type != WQL_TYPE_BOOLEAN) { trace_FindLifecycleClass_EvalResultIsNotBool(); return r; } if ( MI_FALSE == foundISA ) { *errormessage = STR_LIFECYCLE_INDICATION_QUERY_NO_ISA_OPERATOR; return r; } else return MI_RESULT_OK; }
MI_Result ValidateProviderRegistrationAgainstSchema(_In_ MI_ClassA *miClassArray, _In_ MI_InstanceA *miRegistrationArray, _Outptr_result_maybenull_ MI_Instance **extendedError) { MI_Result r = MI_RESULT_OK; MI_Uint32 xCount=0 , yCount = 0; MI_Uint32 registrationFoundCount = 0, schemaFoundCount = 0; MI_Value value; if (extendedError == NULL) { return MI_RESULT_INVALID_PARAMETER; } *extendedError = NULL; // Explicitly set *extendedError to NULL as _Outptr_ requires setting this at least once. DSC_EventWriteValidatingProviderRegistration(miClassArray->size,miRegistrationArray->size); //Test1 : only 1 registration per class //Test2 : no class left out without registration(except for meta config), also validates that registration not targeting more than 1 class. //Test3: no registration instance left out without class //Test4 : no two classes with same name for (xCount = 0 ; xCount < miClassArray->size ; xCount++) { if (miClassArray->data[xCount]->classDecl->superClass && Tcscasecmp(miClassArray->data[xCount]->classDecl->superClass, BASE_RESOURCE_CLASSNAME) == 0) { schemaFoundCount++; } //Test4 for (yCount = xCount + 1 ; yCount < miClassArray->size ; yCount++) { if (Tcscasecmp(miClassArray->data[yCount]->classDecl->name, miClassArray->data[xCount]->classDecl->name) == 0 || NitsShouldFault(NitsHere(), NitsAutomatic)) { return GetCimMIError(MI_RESULT_INVALID_PARAMETER, extendedError, ID_MODMAN_VALIDATE_PROVREG_MULTI); } } } for (xCount = 0 ; xCount < miRegistrationArray->size ; xCount++) { for (yCount = 0 ; yCount < miClassArray->size ; yCount++) { if ((miClassArray->data[yCount]->classDecl->superClass && Tcscasecmp(miClassArray->data[yCount]->classDecl->superClass, BASE_RESOURCE_CLASSNAME) == 0) || Tcscasecmp(miClassArray->data[xCount]->classDecl->name, METACONFIG_CLASSNAME) == 0) { r = DSC_MI_Instance_GetElement(miRegistrationArray->data[xCount], MSFT_BaseConfigurationProviderRegistration_ClassName, &value, NULL, NULL, NULL); if (r != MI_RESULT_OK ) { return GetCimMIError(r, extendedError, ID_MODMAN_VALIDATE_PROVREG_MANDATORY); } if (Tcscasecmp(value.string, miClassArray->data[yCount]->classDecl->name) == 0 ) { // Test1 registrationFoundCount++; break; } } } // Test3 if (yCount == miClassArray->size || NitsShouldFault(NitsHere(), NitsAutomatic)) { return GetCimMIError(MI_RESULT_INVALID_PARAMETER, extendedError, ID_MODMAN_VALIDATE_PROVREG_NOCLASS); } } // Test2 if (registrationFoundCount != schemaFoundCount || NitsShouldFault(NitsHere(), NitsAutomatic)) { return GetCimMIError(MI_RESULT_INVALID_PARAMETER, extendedError, ID_MODMAN_VALIDATE_PROVREG_NOREG); } return r; }