static void AddAllClasses(EvalContext *ctx, const char *ns, const Rlist *list, bool persist, ContextStatePolicy policy, ContextScope context_scope) { for (const Rlist *rp = list; rp != NULL; rp = rp->next) { char *classname = xstrdup(rp->item); CanonifyNameInPlace(classname); if (EvalContextHeapContainsHard(ctx, classname)) { Log(LOG_LEVEL_ERR, "You cannot use reserved hard class '%s' as post-condition class", classname); // TODO: ok.. but should we take any action? continue; maybe? } if (persist > 0) { if (context_scope != CONTEXT_SCOPE_NAMESPACE) { Log(LOG_LEVEL_INFO, "Automatically promoting context scope for '%s' to namespace visibility, due to persistence", classname); } Log(LOG_LEVEL_VERBOSE, "Defining persistent promise result class '%s'", classname); EvalContextHeapPersistentSave(CanonifyName(rp->item), ns, persist, policy); EvalContextHeapAddSoft(ctx, classname, ns); } else { Log(LOG_LEVEL_VERBOSE, "Defining promise result class '%s'", classname); switch (context_scope) { case CONTEXT_SCOPE_BUNDLE: EvalContextStackFrameAddSoft(ctx, classname); break; default: case CONTEXT_SCOPE_NAMESPACE: EvalContextHeapAddSoft(ctx, classname, ns); break; } } } }
void VerifyClassPromise(EvalContext *ctx, Promise *pp, ARG_UNUSED void *param) { assert(param == NULL); Attributes a; a = GetClassContextAttributes(ctx, pp); if (!FullTextMatch("[a-zA-Z0-9_]+", pp->promiser)) { Log(LOG_LEVEL_VERBOSE, "Class identifier '%s' contains illegal characters - canonifying", pp->promiser); snprintf(pp->promiser, strlen(pp->promiser) + 1, "%s", CanonifyName(pp->promiser)); } if (a.context.nconstraints == 0) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "No constraints for class promise '%s'", pp->promiser); return; } if (a.context.nconstraints > 1) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Irreconcilable constraints in classes for '%s'", pp->promiser); return; } bool global_class; if (a.context.persistent > 0) /* Persistent classes are always global */ { global_class = true; } else if (a.context.scope == CONTEXT_SCOPE_NONE) { /* If there is no explicit scope, common bundles define global classes, other bundles define local classes */ if (strcmp(PromiseGetBundle(pp)->type, "common") == 0) { global_class = true; } else { global_class = false; } } else if (a.context.scope == CONTEXT_SCOPE_NAMESPACE) { global_class = true; } else if (a.context.scope == CONTEXT_SCOPE_BUNDLE) { global_class = false; } if (EvalClassExpression(ctx, a.context.expression, pp)) { if (!ValidClassName(pp->promiser)) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Attempted to name a class '%s', which is an illegal class identifier", pp->promiser); } else { if (global_class) { Log(LOG_LEVEL_VERBOSE, "Adding global class '%s'", pp->promiser); EvalContextHeapAddSoft(ctx, pp->promiser, PromiseGetNamespace(pp)); } else { Log(LOG_LEVEL_VERBOSE, "Adding local bundle class '%s'", pp->promiser); EvalContextStackFrameAddSoft(ctx, pp->promiser); } if (a.context.persistent > 0) { Log(LOG_LEVEL_VERBOSE, "Adding persistent class '%s'. (%d minutes)", pp->promiser, a.context.persistent); EvalContextHeapPersistentSave(pp->promiser, PromiseGetNamespace(pp), a.context.persistent, CONTEXT_STATE_POLICY_RESET); } } } }
void KeepClassContextPromise(EvalContext *ctx, Promise *pp, ARG_UNUSED const ReportContext *report_context) { Attributes a; a = GetClassContextAttributes(ctx, pp); if (!FullTextMatch("[a-zA-Z0-9_]+", pp->promiser)) { CfOut(OUTPUT_LEVEL_VERBOSE, "", "Class identifier \"%s\" contains illegal characters - canonifying", pp->promiser); snprintf(pp->promiser, strlen(pp->promiser) + 1, "%s", CanonifyName(pp->promiser)); } if (a.context.nconstraints == 0) { cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_FAIL, "", pp, a, "No constraints for class promise %s", pp->promiser); return; } if (a.context.nconstraints > 1) { cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_FAIL, "", pp, a, "Irreconcilable constraints in classes for %s", pp->promiser); return; } // If this is a common bundle ... if (strcmp(PromiseGetBundle(pp)->type, "common") == 0) { if (EvalClassExpression(ctx, a.context.expression, pp)) { CfOut(OUTPUT_LEVEL_VERBOSE, "", " ?> defining additional global class %s\n", pp->promiser); if (!ValidClassName(pp->promiser)) { cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_FAIL, "", pp, a, " !! Attempted to name a class \"%s\", which is an illegal class identifier", pp->promiser); } else { if (a.context.persistent > 0) { CfOut(OUTPUT_LEVEL_VERBOSE, "", " ?> defining explicit persistent class %s (%d mins)\n", pp->promiser, a.context.persistent); EvalContextHeapPersistentSave(pp->promiser, PromiseGetNamespace(pp), a.context.persistent, CONTEXT_STATE_POLICY_RESET); EvalContextHeapAddSoft(ctx, pp->promiser, PromiseGetNamespace(pp)); } else { CfOut(OUTPUT_LEVEL_VERBOSE, "", " ?> defining explicit global class %s\n", pp->promiser); EvalContextHeapAddSoft(ctx, pp->promiser, PromiseGetNamespace(pp)); } } } /* These are global and loaded once */ /* *(pp->donep) = true; */ return; } // If this is some other kind of bundle (else here??) if (strcmp(PromiseGetBundle(pp)->type, CF_AGENTTYPES[THIS_AGENT_TYPE]) == 0 || FullTextMatch("edit_.*", PromiseGetBundle(pp)->type)) { if (EvalClassExpression(ctx, a.context.expression, pp)) { if (!ValidClassName(pp->promiser)) { cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_FAIL, "", pp, a, " !! Attempted to name a class \"%s\", which is an illegal class identifier", pp->promiser); } else { if (a.context.persistent > 0) { CfOut(OUTPUT_LEVEL_VERBOSE, "", " ?> defining explicit persistent class %s (%d mins)\n", pp->promiser, a.context.persistent); CfOut(OUTPUT_LEVEL_VERBOSE, "", " ?> Warning: persistent classes are global in scope even in agent bundles\n"); EvalContextHeapPersistentSave(pp->promiser, PromiseGetNamespace(pp), a.context.persistent, CONTEXT_STATE_POLICY_RESET); EvalContextHeapAddSoft(ctx, pp->promiser, PromiseGetNamespace(pp)); } else { CfOut(OUTPUT_LEVEL_VERBOSE, "", " ?> defining explicit local bundle class %s\n", pp->promiser); EvalContextStackFrameAddSoft(ctx, pp->promiser); } } } // Private to bundle, can be reloaded *(pp->donep) = false; return; } }
static double SetClasses(char *name, double variable, double av_expect, double av_var, double localav_expect, double localav_var, Item **classlist, char *timekey) { char buffer[CF_BUFSIZE], buffer2[CF_BUFSIZE]; double dev, delta, sigma, ldelta, lsigma, sig; delta = variable - av_expect; sigma = sqrt(av_var); ldelta = variable - localav_expect; lsigma = sqrt(localav_var); sig = sqrt(sigma * sigma + lsigma * lsigma); Log(LOG_LEVEL_DEBUG, "delta = %lf, sigma = %lf, lsigma = %lf, sig = %lf", delta, sigma, lsigma, sig); if ((sigma == 0.0) || (lsigma == 0.0)) { Log(LOG_LEVEL_DEBUG, "No sigma variation .. can't measure class"); snprintf(buffer, CF_MAXVARSIZE, "entropy_%s.*", name); MonEntropyPurgeUnused(buffer); return sig; } Log(LOG_LEVEL_DEBUG, "Setting classes for '%s'...", name); if (fabs(delta) < cf_noise_threshold) /* Arbitrary limits on sensitivity */ { Log(LOG_LEVEL_DEBUG, "Sensitivity too high"); buffer[0] = '\0'; strcpy(buffer, name); if ((delta > 0) && (ldelta > 0)) { strcat(buffer, "_high"); } else if ((delta < 0) && (ldelta < 0)) { strcat(buffer, "_low"); } else { strcat(buffer, "_normal"); } AppendItem(classlist, buffer, "0"); dev = sqrt(delta * delta / (1.0 + sigma * sigma) + ldelta * ldelta / (1.0 + lsigma * lsigma)); if (dev > 2.0 * sqrt(2.0)) { strcpy(buffer2, buffer); strcat(buffer2, "_microanomaly"); AppendItem(classlist, buffer2, "2"); EvalContextHeapPersistentSave(buffer2, "measurements", CF_PERSISTENCE, CONTEXT_STATE_POLICY_PRESERVE); } return sig; /* Granularity makes this silly */ } else { buffer[0] = '\0'; strcpy(buffer, name); if ((delta > 0) && (ldelta > 0)) { strcat(buffer, "_high"); } else if ((delta < 0) && (ldelta < 0)) { strcat(buffer, "_low"); } else { strcat(buffer, "_normal"); } dev = sqrt(delta * delta / (1.0 + sigma * sigma) + ldelta * ldelta / (1.0 + lsigma * lsigma)); if (dev <= sqrt(2.0)) { strcpy(buffer2, buffer); strcat(buffer2, "_normal"); AppendItem(classlist, buffer2, "0"); } else { strcpy(buffer2, buffer); strcat(buffer2, "_dev1"); AppendItem(classlist, buffer2, "0"); } /* Now use persistent classes so that serious anomalies last for about 2 autocorrelation lengths, so that they can be cross correlated and seen by normally scheduled cfagent processes ... */ if (dev > 2.0 * sqrt(2.0)) { strcpy(buffer2, buffer); strcat(buffer2, "_dev2"); AppendItem(classlist, buffer2, "2"); EvalContextHeapPersistentSave(buffer2, "measurements", CF_PERSISTENCE, CONTEXT_STATE_POLICY_PRESERVE); } if (dev > 3.0 * sqrt(2.0)) { strcpy(buffer2, buffer); strcat(buffer2, "_anomaly"); AppendItem(classlist, buffer2, "3"); EvalContextHeapPersistentSave(buffer2, "measurements", CF_PERSISTENCE, CONTEXT_STATE_POLICY_PRESERVE); } return sig; } }
static void ArmClasses(Averages av, char *timekey) { double sigma; Item *ip,*classlist = NULL; int i, j, k; char buff[CF_BUFSIZE], ldt_buff[CF_BUFSIZE], name[CF_MAXVARSIZE]; static int anomaly[CF_OBSERVABLES][LDT_BUFSIZE]; extern Item *ALL_INCOMING; extern Item *MON_UDP4, *MON_UDP6, *MON_TCP4, *MON_TCP6; for (i = 0; i < CF_OBSERVABLES; i++) { char desc[CF_BUFSIZE]; GetObservable(i, name, desc); sigma = SetClasses(name, CF_THIS[i], av.Q[i].expect, av.Q[i].var, LOCALAV.Q[i].expect, LOCALAV.Q[i].var, &classlist, timekey); SetVariable(name, CF_THIS[i], av.Q[i].expect, sigma, &classlist); /* LDT */ ldt_buff[0] = '\0'; anomaly[i][LDT_POS] = false; if (!LDT_FULL) { anomaly[i][LDT_POS] = false; } if (LDT_FULL && (CHI[i] > CHI_LIMIT[i])) { anomaly[i][LDT_POS] = true; /* Remember the last anomaly value */ Log(LOG_LEVEL_VERBOSE, "LDT(%d) in %s chi = %.2f thresh %.2f ", LDT_POS, name, CHI[i], CHI_LIMIT[i]); /* Last printed element is now */ for (j = LDT_POS + 1, k = 0; k < LDT_BUFSIZE; j++, k++) { if (j == LDT_BUFSIZE) /* Wrap */ { j = 0; } if (anomaly[i][j]) { snprintf(buff, CF_BUFSIZE, " *%.2f*", LDT_BUF[i][j]); } else { snprintf(buff, CF_BUFSIZE, " %.2f", LDT_BUF[i][j]); } strcat(ldt_buff, buff); } if (CF_THIS[i] > av.Q[i].expect) { snprintf(buff, CF_BUFSIZE, "%s_high_ldt", name); } else { snprintf(buff, CF_BUFSIZE, "%s_high_ldt", name); } AppendItem(&classlist, buff, "2"); EvalContextHeapPersistentSave(buff, "measurements", CF_PERSISTENCE, CONTEXT_STATE_POLICY_PRESERVE); } else { for (j = LDT_POS + 1, k = 0; k < LDT_BUFSIZE; j++, k++) { if (j == LDT_BUFSIZE) /* Wrap */ { j = 0; } if (anomaly[i][j]) { snprintf(buff, CF_BUFSIZE, " *%.2f*", LDT_BUF[i][j]); } else { snprintf(buff, CF_BUFSIZE, " %.2f", LDT_BUF[i][j]); } strcat(ldt_buff, buff); } } } SetMeasurementPromises(&classlist); // Report on the open ports, in various ways AddOpenPortsClasses("listening_ports", ALL_INCOMING, &classlist); AddOpenPortsClasses("listening_udp6_ports", MON_UDP6, &classlist); AddOpenPortsClasses("listening_udp4_ports", MON_UDP4, &classlist); AddOpenPortsClasses("listening_tcp6_ports", MON_TCP6, &classlist); AddOpenPortsClasses("listening_tcp4_ports", MON_TCP4, &classlist); // Port addresses if (ListLen(MON_TCP6) + ListLen(MON_TCP4) > 512) { Log(LOG_LEVEL_INFO, "Disabling address information of TCP ports in LISTEN state: more than 512 listening ports are detected"); } else { for (ip = MON_TCP6; ip != NULL; ip=ip->next) { snprintf(buff,CF_BUFSIZE,"tcp6_port_addr[%s]=%s",ip->name,ip->classes); AppendItem(&classlist,buff,NULL); } for (ip = MON_TCP4; ip != NULL; ip=ip->next) { snprintf(buff,CF_BUFSIZE,"tcp4_port_addr[%s]=%s",ip->name,ip->classes); AppendItem(&classlist,buff,NULL); } } for (ip = MON_UDP6; ip != NULL; ip=ip->next) { snprintf(buff,CF_BUFSIZE,"udp6_port_addr[%s]=%s",ip->name,ip->classes); AppendItem(&classlist,buff,NULL); } for (ip = MON_UDP4; ip != NULL; ip=ip->next) { snprintf(buff,CF_BUFSIZE,"udp4_port_addr[%s]=%s",ip->name,ip->classes); AppendItem(&classlist,buff,NULL); } PublishEnvironment(classlist); DeleteItemList(classlist); }
PromiseResult VerifyClassPromise(EvalContext *ctx, const Promise *pp, ARG_UNUSED void *param) { assert(param == NULL); Attributes a = GetClassContextAttributes(ctx, pp); if (!StringMatchFull("[a-zA-Z0-9_]+", pp->promiser)) { Log(LOG_LEVEL_VERBOSE, "Class identifier '%s' contains illegal characters - canonifying", pp->promiser); xsnprintf(pp->promiser, strlen(pp->promiser) + 1, "%s", CanonifyName(pp->promiser)); } if (a.context.nconstraints == 0) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "No constraints for class promise '%s'", pp->promiser); return PROMISE_RESULT_FAIL; } if (a.context.nconstraints > 1) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Irreconcilable constraints in classes for '%s'", pp->promiser); return PROMISE_RESULT_FAIL; } if (EvalClassExpression(ctx, a.context.expression, pp)) { if (!ValidClassName(pp->promiser)) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Attempted to name a class '%s', which is an illegal class identifier", pp->promiser); return PROMISE_RESULT_FAIL; } else { char *tags = NULL; { Buffer *tag_buffer = BufferNew(); BufferAppendString(tag_buffer, "classes promise,attribute_name=label,source=promise"); for (const Rlist *rp = PromiseGetConstraintAsList(ctx, "meta", pp); rp; rp = rp->next) { BufferAppendChar(tag_buffer, ','); BufferAppendString(tag_buffer, RlistScalarValue(rp)); } tags = BufferClose(tag_buffer); } if (/* Persistent classes are always global: */ a.context.persistent > 0 || /* Namespace-scope is global: */ a.context.scope == CONTEXT_SCOPE_NAMESPACE || /* If there is no explicit scope, common bundles define global * classes, other bundles define local classes: */ (a.context.scope == CONTEXT_SCOPE_NONE && 0 == strcmp(PromiseGetBundle(pp)->type, "common"))) { Log(LOG_LEVEL_VERBOSE, "C: + Global class: %s ", pp->promiser); EvalContextClassPutSoft(ctx, pp->promiser, CONTEXT_SCOPE_NAMESPACE, tags); } else { Log(LOG_LEVEL_VERBOSE, "C: + Private class: %s ", pp->promiser); EvalContextClassPutSoft(ctx, pp->promiser, CONTEXT_SCOPE_BUNDLE, tags); } if (a.context.persistent > 0) { Log(LOG_LEVEL_VERBOSE, "C: + Persistent class: '%s'. (%d minutes)", pp->promiser, a.context.persistent); EvalContextHeapPersistentSave(ctx, pp->promiser, a.context.persistent, CONTEXT_STATE_POLICY_RESET, tags); } free(tags); return PROMISE_RESULT_NOOP; } } return PROMISE_RESULT_NOOP; }
static void test_class_persistence(void) { EvalContext *ctx = EvalContextNew(); // simulate old version { CF_DB *dbp; PersistentClassInfo i; assert_true(OpenDB(&dbp, dbid_state)); i.expires = UINT_MAX; i.policy = CONTEXT_STATE_POLICY_RESET; WriteDB(dbp, "old", &i, sizeof(PersistentClassInfo)); CloseDB(dbp); } // e.g. by monitoring EvalContextHeapPersistentSave(ctx, "class1", 3, CONTEXT_STATE_POLICY_PRESERVE, "a,b"); // e.g. by a class promise in a bundle with a namespace { Policy *p = PolicyNew(); Bundle *bp = PolicyAppendBundle(p, "ns1", "bundle1", "agent", NULL, NULL); EvalContextStackPushBundleFrame(ctx, bp, NULL, false); EvalContextHeapPersistentSave(ctx, "class2", 5, CONTEXT_STATE_POLICY_PRESERVE, "x"); EvalContextStackPopFrame(ctx); PolicyDestroy(p); } EvalContextHeapPersistentLoadAll(ctx); { const Class *cls = EvalContextClassGet(ctx, "default", "old"); assert_true(cls != NULL); assert_string_equal("old", cls->name); assert_true(cls->tags != NULL); assert_int_equal(1, StringSetSize(cls->tags)); assert_true(StringSetContains(cls->tags, "source=persistent")); } { const Class *cls = EvalContextClassGet(ctx, "default", "class1"); assert_true(cls != NULL); assert_string_equal("class1", cls->name); assert_true(cls->tags != NULL); assert_int_equal(3, StringSetSize(cls->tags)); assert_true(StringSetContains(cls->tags, "source=persistent")); assert_true(StringSetContains(cls->tags, "a")); assert_true(StringSetContains(cls->tags, "b")); } { const Class *cls = EvalContextClassGet(ctx, "ns1", "class2"); assert_true(cls != NULL); assert_string_equal("ns1", cls->ns); assert_string_equal("class2", cls->name); assert_true(cls->tags != NULL); assert_int_equal(2, StringSetSize(cls->tags)); assert_true(StringSetContains(cls->tags, "source=persistent")); assert_true(StringSetContains(cls->tags, "x")); } EvalContextDestroy(ctx); }