/** * @param #tags is a comma separated string of words. * Both "" or NULL are equivalent. */ static void ClassInit(Class *cls, const char *ns, const char *name, bool is_soft, ContextScope scope, const char *tags) { if (ns == NULL || strcmp(ns, "default") == 0) { cls->ns = NULL; } else { cls->ns = xstrdup(ns); } cls->name = xstrdup(name); CanonifyNameInPlace(cls->name); cls->is_soft = is_soft; cls->scope = scope; cls->tags = StringSetFromString(tags, ','); if (!is_soft && !StringSetContains(cls->tags, "hardclass")) { StringSetAdd(cls->tags, xstrdup("hardclass")); } }
void EvalContextHeapAddHard(EvalContext *ctx, const char *context) { char context_copy[CF_MAXVARSIZE]; strcpy(context_copy, context); if (Chop(context_copy, CF_EXPANDSIZE) == -1) { CfOut(OUTPUT_LEVEL_ERROR, "", "Chop was called on a string that seemed to have no terminator"); } CanonifyNameInPlace(context_copy); CfDebug("EvalContextHeapAddHard(%s)\n", context_copy); if (strlen(context_copy) == 0) { return; } if (IsRegexItemIn(ctx, ctx->heap_abort_current_bundle, context_copy)) { CfOut(OUTPUT_LEVEL_ERROR, "", "Bundle aborted on defined class \"%s\"\n", context_copy); ABORTBUNDLE = true; } if (IsRegexItemIn(ctx, ctx->heap_abort, context_copy)) { CfOut(OUTPUT_LEVEL_ERROR, "", "cf-agent aborted on defined class \"%s\"\n", context_copy); exit(1); } if (EvalContextHeapContainsHard(ctx, context_copy)) { return; } StringSetAdd(ctx->heap_hard, xstrdup(context_copy)); for (const Item *ip = ctx->heap_abort; ip != NULL; ip = ip->next) { if (IsDefinedClass(ctx, ip->name, NULL)) { CfOut(OUTPUT_LEVEL_ERROR, "", "cf-agent aborted on defined class \"%s\" defined in bundle %s\n", ip->name, StackFrameOwnerName(LastStackFrame(ctx, 0))); exit(1); } } if (!ABORTBUNDLE) { for (const Item *ip = ctx->heap_abort_current_bundle; ip != NULL; ip = ip->next) { if (IsDefinedClass(ctx, ip->name, NULL)) { CfOut(OUTPUT_LEVEL_ERROR, "", " -> Setting abort for \"%s\" when setting \"%s\"", ip->name, context_copy); ABORTBUNDLE = true; break; } } } }
char *CanonifyName(const char *str) { static char buffer[CF_BUFSIZE]; strncpy(buffer, str, CF_BUFSIZE); CanonifyNameInPlace(buffer); return buffer; }
/* TODO remove, kill, burn this function! */ char *CanonifyName(const char *str) { static char buffer[CF_BUFSIZE]; /* GLOBAL_R, no initialization needed */ strlcpy(buffer, str, CF_BUFSIZE); CanonifyNameInPlace(buffer); return buffer; }
void BufferCanonify(Buffer *buffer) { assert(buffer); if (buffer != NULL && buffer->buffer != NULL) { CanonifyNameInPlace(buffer->buffer); } }
static PromiseResult ExpandPromiseAndDo(EvalContext *ctx, const Promise *pp, Rlist *lists, Rlist *containers, PromiseActuator *ActOnPromise, void *param) { const char *handle = PromiseGetHandle(pp); EvalContextStackPushPromiseFrame(ctx, pp, true); PromiseIterator *iter_ctx = NULL; size_t i = 0; PromiseResult result = PROMISE_RESULT_NOOP; Buffer *expbuf = BufferNew(); for (iter_ctx = PromiseIteratorNew(ctx, pp, lists, containers); PromiseIteratorHasMore(iter_ctx); i++, PromiseIteratorNext(iter_ctx)) { if (handle) { // This ordering is necessary to get automated canonification BufferClear(expbuf); ExpandScalar(ctx, NULL, "this", handle, expbuf); CanonifyNameInPlace(BufferGet(expbuf)); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "handle", BufferData(expbuf), CF_DATA_TYPE_STRING, "source=promise"); } else { EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "handle", PromiseID(pp), CF_DATA_TYPE_STRING, "source=promise"); } const Promise *pexp = EvalContextStackPushPromiseIterationFrame(ctx, i, iter_ctx); if (!pexp) { // excluded result = PromiseResultUpdate(result, PROMISE_RESULT_SKIPPED); continue; } PromiseResult iteration_result = ActOnPromise(ctx, pexp, param); NotifyDependantPromises(ctx, pexp, iteration_result); result = PromiseResultUpdate(result, iteration_result); if (strcmp(pp->parent_promise_type->name, "vars") == 0 || strcmp(pp->parent_promise_type->name, "meta") == 0) { VerifyVarPromise(ctx, pexp, true); } EvalContextStackPopFrame(ctx); } BufferDestroy(expbuf); PromiseIteratorDestroy(iter_ctx); EvalContextStackPopFrame(ctx); return result; }
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; } } } }
static void PutHandleVariable(EvalContext *ctx, const Promise *pp) { char *handle_s; const char *existing_handle = PromiseGetHandle(pp); if (existing_handle != NULL) { // This ordering is necessary to get automated canonification handle_s = ExpandScalar(ctx, NULL, "this", existing_handle, NULL); CanonifyNameInPlace(handle_s); } else { handle_s = xstrdup(PromiseID(pp)); /* default handle */ } EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "handle", handle_s, CF_DATA_TYPE_STRING, "source=promise"); free(handle_s); }
void EvalContextHeapAddSoft(EvalContext *ctx, const char *context, const char *ns) { char context_copy[CF_MAXVARSIZE]; char canonified_context[CF_MAXVARSIZE]; strcpy(canonified_context, context); if (Chop(canonified_context, CF_EXPANDSIZE) == -1) { Log(LOG_LEVEL_ERR, "Chop was called on a string that seemed to have no terminator"); } CanonifyNameInPlace(canonified_context); if (ns && strcmp(ns, "default") != 0) { snprintf(context_copy, CF_MAXVARSIZE, "%s:%s", ns, canonified_context); } else { strncpy(context_copy, canonified_context, CF_MAXVARSIZE); } if (strlen(context_copy) == 0) { return; } if (IsRegexItemIn(ctx, ctx->heap_abort_current_bundle, context_copy)) { Log(LOG_LEVEL_ERR, "Bundle aborted on defined class '%s'", context_copy); ABORTBUNDLE = true; } if (IsRegexItemIn(ctx, ctx->heap_abort, context_copy)) { Log(LOG_LEVEL_ERR, "cf-agent aborted on defined class '%s'", context_copy); exit(1); } if (EvalContextHeapContainsSoft(ctx, context_copy)) { return; } StringSetAdd(ctx->heap_soft, xstrdup(context_copy)); for (const Item *ip = ctx->heap_abort; ip != NULL; ip = ip->next) { if (IsDefinedClass(ctx, ip->name, ns)) { Log(LOG_LEVEL_ERR, "cf-agent aborted on defined class '%s' defined in bundle '%s'", ip->name, StackFrameOwnerName(LastStackFrame(ctx, 0))); exit(1); } } if (!ABORTBUNDLE) { for (const Item *ip = ctx->heap_abort_current_bundle; ip != NULL; ip = ip->next) { if (IsDefinedClass(ctx, ip->name, ns)) { Log(LOG_LEVEL_ERR, "Setting abort for '%s' when setting '%s'", ip->name, context_copy); ABORTBUNDLE = true; break; } } } }
void LocalExec(const ExecConfig *config) { FILE *pp; char line[CF_BUFSIZE], line_escaped[sizeof(line) * 2], filename[CF_BUFSIZE], *sp; char cmd[CF_BUFSIZE], esc_command[CF_BUFSIZE]; int print, count = 0; void *thread_name; time_t starttime = time(NULL); char starttime_str[64]; FILE *fp; char canonified_fq_name[CF_BUFSIZE]; thread_name = ThreadUniqueName(); cf_strtimestamp_local(starttime, starttime_str); CfOut(cf_verbose, "", "------------------------------------------------------------------\n\n"); CfOut(cf_verbose, "", " LocalExec(%sscheduled) at %s\n", config->scheduled_run ? "" : "not ", starttime_str); CfOut(cf_verbose, "", "------------------------------------------------------------------\n"); /* Need to make sure we have LD_LIBRARY_PATH here or children will die */ if (strlen(config->exec_command) > 0) { strncpy(cmd, config->exec_command, CF_BUFSIZE - 1); if (!strstr(cmd, "-Dfrom_cfexecd")) { strcat(cmd, " -Dfrom_cfexecd"); } } else { ConstructFailsafeCommand(config->scheduled_run, cmd); } strncpy(esc_command, MapName(cmd), CF_BUFSIZE - 1); snprintf(line, CF_BUFSIZE - 1, "_%jd_%s", (intmax_t) starttime, CanonifyName(cf_ctime(&starttime))); strlcpy(canonified_fq_name, config->fq_name, CF_BUFSIZE); CanonifyNameInPlace(canonified_fq_name); snprintf(filename, CF_BUFSIZE - 1, "%s/outputs/cf_%s_%s_%p", CFWORKDIR, canonified_fq_name, line, thread_name); MapName(filename); /* What if no more processes? Could sacrifice and exec() - but we need a sentinel */ if ((fp = fopen(filename, "w")) == NULL) { CfOut(cf_error, "fopen", "!! Couldn't open \"%s\" - aborting exec\n", filename); return; } #if !defined(__MINGW32__) /* * Don't inherit this file descriptor on fork/exec */ if (fileno(fp) != -1) { fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); } #endif CfOut(cf_verbose, "", " -> Command => %s\n", cmd); if ((pp = cf_popen_sh(esc_command, "r")) == NULL) { CfOut(cf_error, "cf_popen", "!! Couldn't open pipe to command \"%s\"\n", cmd); fclose(fp); return; } CfOut(cf_verbose, "", " -> Command is executing...%s\n", esc_command); while (!feof(pp)) { if(!IsReadReady(fileno(pp), (config->agent_expireafter * SECONDS_PER_MINUTE))) { char errmsg[CF_MAXVARSIZE]; snprintf(errmsg, sizeof(errmsg), "cf-execd: !! Timeout waiting for output from agent (agent_expireafter=%d) - terminating it", config->agent_expireafter); CfOut(cf_error, "", "%s", errmsg); fprintf(fp, "%s\n", errmsg); count++; pid_t pid_agent; if(PipeToPid(&pid_agent, pp)) { ProcessSignalTerminate(pid_agent); } else { CfOut(cf_error, "", "!! Could not get PID of agent"); } break; } { ssize_t num_read = CfReadLine(line, CF_BUFSIZE, pp); if (num_read == -1) { FatalError("Cannot continue on CfReadLine error"); } else if (num_read == 0) { break; } } if(!CfReadLine(line, CF_BUFSIZE, pp)) { break; } if (ferror(pp)) { fflush(pp); break; } print = false; for (sp = line; *sp != '\0'; sp++) { if (!isspace((int) *sp)) { print = true; break; } } if (print) { // we must escape print format chars (%) from output ReplaceStr(line, line_escaped, sizeof(line_escaped), "%", "%%"); fprintf(fp, "%s\n", line_escaped); count++; /* If we can't send mail, log to syslog */ if (strlen(config->mail_to_address) == 0) { strncat(line_escaped, "\n", sizeof(line_escaped) - 1 - strlen(line_escaped)); if ((strchr(line_escaped, '\n')) == NULL) { line_escaped[sizeof(line_escaped) - 2] = '\n'; } CfOut(cf_inform, "", "%s", line_escaped); } line[0] = '\0'; line_escaped[0] = '\0'; } } cf_pclose(pp); CfDebug("Closing fp\n"); fclose(fp); CfOut(cf_verbose, "", " -> Command is complete\n"); if (count) { CfOut(cf_verbose, "", " -> Mailing result\n"); MailResult(config, filename); } else { CfOut(cf_verbose, "", " -> No output\n"); unlink(filename); } }
static bool IsReadReady(int fd, int timeout_sec) { fd_set rset; FD_ZERO(&rset); FD_SET(fd, &rset); struct timeval tv = { .tv_sec = timeout_sec, .tv_usec = 0, }; int ret = select(fd + 1, &rset, NULL, NULL, &tv); if(ret < 0) { Log(LOG_LEVEL_ERR, "IsReadReady: Failed checking for data. (select: %s)", GetErrorStr()); return false; } if(FD_ISSET(fd, &rset)) { return true; } if(ret == 0) // timeout { return false; } // can we get here? Log(LOG_LEVEL_ERR, "IsReadReady: Unknown outcome (ret > 0 but our only fd is not set). (select: %s)", GetErrorStr()); return false; } #if defined(__hpux) && defined(__GNUC__) #pragma GCC diagnostic warning "-Wstrict-aliasing" #endif #endif /* __MINGW32__ */ void LocalExec(const ExecConfig *config) { time_t starttime = time(NULL); void *thread_name = ThreadUniqueName(); { char starttime_str[64]; cf_strtimestamp_local(starttime, starttime_str); if (LEGACY_OUTPUT) { Log(LOG_LEVEL_VERBOSE, "------------------------------------------------------------------"); Log(LOG_LEVEL_VERBOSE, " LocalExec(%sscheduled) at %s", config->scheduled_run ? "" : "not ", starttime_str); Log(LOG_LEVEL_VERBOSE, "------------------------------------------------------------------"); } else { Log(LOG_LEVEL_VERBOSE, "LocalExec(%sscheduled) at %s", config->scheduled_run ? "" : "not ", starttime_str); } } /* Need to make sure we have LD_LIBRARY_PATH here or children will die */ char cmd[CF_BUFSIZE]; if (strlen(config->exec_command) > 0) { strncpy(cmd, config->exec_command, CF_BUFSIZE - 1); if (!strstr(cmd, "-Dfrom_cfexecd")) { strcat(cmd, " -Dfrom_cfexecd"); } } else { ConstructFailsafeCommand(config->scheduled_run, cmd); } char esc_command[CF_BUFSIZE]; strncpy(esc_command, MapName(cmd), CF_BUFSIZE - 1); char line[CF_BUFSIZE]; snprintf(line, CF_BUFSIZE - 1, "_%jd_%s", (intmax_t) starttime, CanonifyName(ctime(&starttime))); char filename[CF_BUFSIZE]; { char canonified_fq_name[CF_BUFSIZE]; strlcpy(canonified_fq_name, config->fq_name, CF_BUFSIZE); CanonifyNameInPlace(canonified_fq_name); snprintf(filename, CF_BUFSIZE - 1, "%s/outputs/cf_%s_%s_%p", CFWORKDIR, canonified_fq_name, line, thread_name); MapName(filename); } /* What if no more processes? Could sacrifice and exec() - but we need a sentinel */ FILE *fp = fopen(filename, "w"); if (!fp) { Log(LOG_LEVEL_ERR, "Couldn't open '%s' - aborting exec. (fopen: %s)", filename, GetErrorStr()); return; } #if !defined(__MINGW32__) /* * Don't inherit this file descriptor on fork/exec */ if (fileno(fp) != -1) { fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); } #endif Log(LOG_LEVEL_VERBOSE, "Command => %s", cmd); FILE *pp = cf_popen_sh(esc_command, "r"); if (!pp) { Log(LOG_LEVEL_ERR, "Couldn't open pipe to command '%s'. (cf_popen: %s)", cmd, GetErrorStr()); fclose(fp); return; } Log(LOG_LEVEL_VERBOSE, "Command is executing...%s", esc_command); int count = 0; for (;;) { if(!IsReadReady(fileno(pp), (config->agent_expireafter * SECONDS_PER_MINUTE))) { char errmsg[CF_MAXVARSIZE]; snprintf(errmsg, sizeof(errmsg), "cf-execd: !! Timeout waiting for output from agent (agent_expireafter=%d) - terminating it", config->agent_expireafter); Log(LOG_LEVEL_ERR, "%s", errmsg); fprintf(fp, "%s\n", errmsg); count++; pid_t pid_agent; if(PipeToPid(&pid_agent, pp)) { ProcessSignalTerminate(pid_agent); } else { Log(LOG_LEVEL_ERR, "Could not get PID of agent"); } break; } ssize_t res = CfReadLine(line, CF_BUFSIZE, pp); if (res == 0) { break; } if (res == -1) { Log(LOG_LEVEL_ERR, "Unable to read output from command '%s'. (cfread: %s)", cmd, GetErrorStr()); cf_pclose(pp); return; } bool print = false; for (const char *sp = line; *sp != '\0'; sp++) { if (!isspace((int) *sp)) { print = true; break; } } if (print) { char line_escaped[sizeof(line) * 2]; // we must escape print format chars (%) from output ReplaceStr(line, line_escaped, sizeof(line_escaped), "%", "%%"); fprintf(fp, "%s\n", line_escaped); count++; /* If we can't send mail, log to syslog */ if (strlen(config->mail_to_address) == 0) { strncat(line_escaped, "\n", sizeof(line_escaped) - 1 - strlen(line_escaped)); if ((strchr(line_escaped, '\n')) == NULL) { line_escaped[sizeof(line_escaped) - 2] = '\n'; } Log(LOG_LEVEL_INFO, "%s", line_escaped); } line[0] = '\0'; line_escaped[0] = '\0'; } } cf_pclose(pp); Log(LOG_LEVEL_DEBUG, "Closing fp"); fclose(fp); Log(LOG_LEVEL_VERBOSE, "Command is complete"); if (count) { Log(LOG_LEVEL_VERBOSE, "Mailing result"); MailResult(config, filename); } else { Log(LOG_LEVEL_VERBOSE, "No output"); unlink(filename); } }
CfLock AcquireLock(char *operand, char *host, time_t now, Attributes attr, Promise *pp, int ignoreProcesses) { unsigned int pid; int i, err, sum = 0; time_t lastcompleted = 0, elapsedtime; char *promise, cc_operator[CF_BUFSIZE], cc_operand[CF_BUFSIZE]; char cflock[CF_BUFSIZE], cflast[CF_BUFSIZE], cflog[CF_BUFSIZE]; char str_digest[CF_BUFSIZE]; CfLock this; unsigned char digest[EVP_MAX_MD_SIZE + 1]; this.last = (char *) CF_UNDEFINED; this.lock = (char *) CF_UNDEFINED; this.log = (char *) CF_UNDEFINED; if (now == 0) { return this; } this.last = NULL; this.lock = NULL; this.log = NULL; /* Indicate as done if we tried ... as we have passed all class constraints now but we should only do this for level 0 promises. Sub routine bundles cannot be marked as done or it will disallow iteration over bundles */ if (pp->done) { return this; } if (CF_STCKFRAME == 1) { *(pp->donep) = true; /* Must not set pp->done = true for editfiles etc */ } HashPromise(operand, pp, digest, CF_DEFAULT_DIGEST); strcpy(str_digest, HashPrint(CF_DEFAULT_DIGEST, digest)); /* As a backup to "done" we need something immune to re-use */ if (THIS_AGENT_TYPE == cf_agent) { if (IsItemIn(DONELIST, str_digest)) { CfOut(cf_verbose, "", " -> This promise has already been verified"); return this; } PrependItem(&DONELIST, str_digest, NULL); } /* Finally if we're supposed to ignore locks ... do the remaining stuff */ if (IGNORELOCK) { this.lock = xstrdup("dummy"); return this; } promise = BodyName(pp); snprintf(cc_operator, CF_MAXVARSIZE - 1, "%s-%s", promise, host); strncpy(cc_operand, operand, CF_BUFSIZE - 1); CanonifyNameInPlace(cc_operand); RemoveDates(cc_operand); free(promise); CfDebug("AcquireLock(%s,%s), ExpireAfter=%d, IfElapsed=%d\n", cc_operator, cc_operand, attr.transaction.expireafter, attr.transaction.ifelapsed); for (i = 0; cc_operator[i] != '\0'; i++) { sum = (CF_MACROALPHABET * sum + cc_operator[i]) % CF_HASHTABLESIZE; } for (i = 0; cc_operand[i] != '\0'; i++) { sum = (CF_MACROALPHABET * sum + cc_operand[i]) % CF_HASHTABLESIZE; } snprintf(cflog, CF_BUFSIZE, "%s/cf3.%.40s.runlog", CFWORKDIR, host); snprintf(cflock, CF_BUFSIZE, "lock.%.100s.%s.%.100s_%d_%s", pp->bundle, cc_operator, cc_operand, sum, str_digest); snprintf(cflast, CF_BUFSIZE, "last.%.100s.%s.%.100s_%d_%s", pp->bundle, cc_operator, cc_operand, sum, str_digest); CfDebug("LOCK(%s)[%s]\n", pp->bundle, cflock); // Now see if we can get exclusivity to edit the locks CFINITSTARTTIME = time(NULL); WaitForCriticalSection(); /* Look for non-existent (old) processes */ lastcompleted = FindLock(cflast); elapsedtime = (time_t) (now - lastcompleted) / 60; if (elapsedtime < 0) { CfOut(cf_verbose, "", " XX Another cf-agent seems to have done this since I started (elapsed=%jd)\n", (intmax_t) elapsedtime); ReleaseCriticalSection(); return this; } if (elapsedtime < attr.transaction.ifelapsed) { CfOut(cf_verbose, "", " XX Nothing promised here [%.40s] (%jd/%u minutes elapsed)\n", cflast, (intmax_t) elapsedtime, attr.transaction.ifelapsed); ReleaseCriticalSection(); return this; } /* Look for existing (current) processes */ if (!ignoreProcesses) { lastcompleted = FindLock(cflock); elapsedtime = (time_t) (now - lastcompleted) / 60; if (lastcompleted != 0) { if (elapsedtime >= attr.transaction.expireafter) { CfOut(cf_inform, "", "Lock %s expired (after %jd/%u minutes)\n", cflock, (intmax_t) elapsedtime, attr.transaction.expireafter); pid = FindLockPid(cflock); if (pid == -1) { CfOut(cf_error, "", "Illegal pid in corrupt lock %s - ignoring lock\n", cflock); } #ifdef MINGW // killing processes with e.g. task manager does not allow for termination handling else if (!NovaWin_IsProcessRunning(pid)) { CfOut(cf_verbose, "", "Process with pid %d is not running - ignoring lock (Windows does not support graceful processes termination)\n", pid); LogLockCompletion(cflog, pid, "Lock expired, process not running", cc_operator, cc_operand); unlink(cflock); } #endif /* MINGW */ else { CfOut(cf_verbose, "", "Trying to kill expired process, pid %d\n", pid); err = GracefulTerminate(pid); if (err || errno == ESRCH) { LogLockCompletion(cflog, pid, "Lock expired, process killed", cc_operator, cc_operand); unlink(cflock); } else { ReleaseCriticalSection(); FatalError("Unable to kill expired cfagent process %d from lock %s, exiting this time..\n", pid, cflock); } } } else { ReleaseCriticalSection(); CfOut(cf_verbose, "", "Couldn't obtain lock for %s (already running!)\n", cflock); return this; } } WriteLock(cflock); } ReleaseCriticalSection(); this.lock = xstrdup(cflock); this.last = xstrdup(cflast); this.log = xstrdup(cflog); /* Keep this as a global for signal handling */ strcpy(CFLOCK, cflock); strcpy(CFLAST, cflast); strcpy(CFLOG, cflog); return this; }
static void ExpandPromiseAndDo(EvalContext *ctx, const Promise *pp, Rlist *lists, Rlist *containers, PromiseActuator *ActOnPromise, void *param) { const char *handle = PromiseGetHandle(pp); char v[CF_MAXVARSIZE]; EvalContextStackPushPromiseFrame(ctx, pp, true); PromiseIterator *iter_ctx = NULL; for (iter_ctx = PromiseIteratorNew(ctx, pp, lists, containers); PromiseIteratorHasMore(iter_ctx); PromiseIteratorNext(iter_ctx)) { EvalContextStackPushPromiseIterationFrame(ctx, iter_ctx); char number[CF_SMALLBUF]; /* Allow $(this.handle) etc variables */ if (PromiseGetBundle(pp)->source_path) { EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promise_filename",PromiseGetBundle(pp)->source_path, DATA_TYPE_STRING); snprintf(number, CF_SMALLBUF, "%zu", pp->offset.line); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promise_linenumber", number, DATA_TYPE_STRING); } snprintf(v, CF_MAXVARSIZE, "%d", (int) getuid()); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser_uid", v, DATA_TYPE_INT); snprintf(v, CF_MAXVARSIZE, "%d", (int) getgid()); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser_gid", v, DATA_TYPE_INT); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "bundle", PromiseGetBundle(pp)->name, DATA_TYPE_STRING); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "namespace", PromiseGetNamespace(pp), DATA_TYPE_STRING); /* Must expand $(this.promiser) here for arg dereferencing in things like edit_line and methods, but we might have to adjust again later if the value changes -- need to qualify this so we don't expand too early for some other promsies */ if (pp->has_subbundles) { EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser", pp->promiser, DATA_TYPE_STRING); } if (handle) { char tmp[CF_EXPANDSIZE]; // This ordering is necessary to get automated canonification ExpandScalar(ctx, NULL, "this", handle, tmp); CanonifyNameInPlace(tmp); Log(LOG_LEVEL_DEBUG, "Expanded handle to '%s'", tmp); EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "handle", tmp, DATA_TYPE_STRING); } else { EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "handle", PromiseID(pp), DATA_TYPE_STRING); } Promise *pexp = ExpandDeRefPromise(ctx, pp); assert(ActOnPromise); ActOnPromise(ctx, pexp, param); if (strcmp(pp->parent_promise_type->name, "vars") == 0 || strcmp(pp->parent_promise_type->name, "meta") == 0) { VerifyVarPromise(ctx, pexp, true); } PromiseDestroy(pexp); EvalContextStackPopFrame(ctx); } PromiseIteratorDestroy(iter_ctx); EvalContextStackPopFrame(ctx); }
void KeepControlPromises() { struct Constraint *cp; char rettype; void *retval; struct Rlist *rp; for (cp = ControlBodyConstraints(cf_agent); cp != NULL; cp=cp->next) { if (IsExcluded(cp->classes)) { continue; } if (GetVariable("control_common",cp->lval,&retval,&rettype) != cf_notype) { /* Already handled in generic_agent */ continue; } if (GetVariable("control_agent",cp->lval,&retval,&rettype) == cf_notype) { CfOut(cf_error,"","Unknown lval %s in agent control body",cp->lval); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_maxconnections].lval) == 0) { CFA_MAXTHREADS = (int)Str2Int(retval); CfOut(cf_verbose,"","SET maxconnections = %d\n",CFA_MAXTHREADS); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_checksum_alert_time].lval) == 0) { CF_PERSISTENCE = (int)Str2Int(retval); CfOut(cf_verbose,"","SET checksum_alert_time = %d\n",CF_PERSISTENCE); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_agentfacility].lval) == 0) { SetFacility(retval); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_agentaccess].lval) == 0) { ACCESSLIST = (struct Rlist *) retval; CheckAgentAccess(ACCESSLIST); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_refresh_processes].lval) == 0) { struct Rlist *rp; if (VERBOSE) { printf("%s> SET refresh_processes when starting: ",VPREFIX); for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next) { printf(" %s",(char *)rp->item); PrependItem(&PROCESSREFRESH,rp->item,NULL); } printf("\n"); } continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_abortclasses].lval) == 0) { struct Rlist *rp; CfOut(cf_verbose,"","SET Abort classes from ...\n"); for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next) { char name[CF_MAXVARSIZE] = ""; strncpy(name, rp->item, CF_MAXVARSIZE - 1); CanonifyNameInPlace(name); if (!IsItemIn(ABORTHEAP,name)) { AppendItem(&ABORTHEAP,name,cp->classes); } } continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_abortbundleclasses].lval) == 0) { struct Rlist *rp; CfOut(cf_verbose,"","SET Abort bundle classes from ...\n"); for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next) { char name[CF_MAXVARSIZE] = ""; strncpy(name, rp->item, CF_MAXVARSIZE - 1); CanonifyNameInPlace(name); if (!IsItemIn(ABORTBUNDLEHEAP,name)) { AppendItem(&ABORTBUNDLEHEAP,name,cp->classes); } } continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_addclasses].lval) == 0) { struct Rlist *rp; CfOut(cf_verbose,"","-> Add classes ...\n"); for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next) { CfOut(cf_verbose,""," -> ... %s\n",rp->item); NewClass(rp->item); } continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_auditing].lval) == 0) { AUDIT = GetBoolean(retval); CfOut(cf_verbose,"","SET auditing = %d\n",AUDIT); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_alwaysvalidate].lval) == 0) { ALWAYS_VALIDATE = GetBoolean(retval); CfOut(cf_verbose,"","SET alwaysvalidate = %d\n",ALWAYS_VALIDATE); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_secureinput].lval) == 0) { CFPARANOID = GetBoolean(retval); CfOut(cf_verbose,"","SET secure input = %d\n",CFPARANOID); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_binarypaddingchar].lval) == 0) { PADCHAR = *(char *)retval; CfOut(cf_verbose,"","SET binarypaddingchar = %c\n",PADCHAR); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_bindtointerface].lval) == 0) { strncpy(BINDINTERFACE,retval,CF_BUFSIZE-1); CfOut(cf_verbose,"","SET bindtointerface = %s\n",BINDINTERFACE); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_hashupdates].lval) == 0) { CHECKSUMUPDATES = GetBoolean(retval); CfOut(cf_verbose,"","SET ChecksumUpdates %d\n",CHECKSUMUPDATES); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_exclamation].lval) == 0) { EXCLAIM = GetBoolean(retval); CfOut(cf_verbose,"","SET exclamation %d\n",EXCLAIM); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_childlibpath].lval) == 0) { char output[CF_BUFSIZE]; snprintf(output,CF_BUFSIZE,"LD_LIBRARY_PATH=%s",(char *)retval); if (putenv(strdup(output)) == 0) { CfOut(cf_verbose,"","Setting %s\n",output); } continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_defaultcopytype].lval) == 0) { DEFAULT_COPYTYPE = (char *)retval; CfOut(cf_verbose,"","SET defaultcopytype = %c\n",DEFAULT_COPYTYPE); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_fsinglecopy].lval) == 0) { SINGLE_COPY_LIST = (struct Rlist *)retval; CfOut(cf_verbose,"","SET file single copy list\n"); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_fautodefine].lval) == 0) { AUTO_DEFINE_LIST = (struct Rlist *)retval; CfOut(cf_verbose,"","SET file auto define list\n"); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_dryrun].lval) == 0) { DONTDO = GetBoolean(retval); CfOut(cf_verbose,"","SET dryrun = %c\n",DONTDO); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_inform].lval) == 0) { INFORM = GetBoolean(retval); CfOut(cf_verbose,"","SET inform = %c\n",INFORM); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_verbose].lval) == 0) { VERBOSE = GetBoolean(retval); CfOut(cf_verbose,"","SET inform = %c\n",VERBOSE); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_repository].lval) == 0) { VREPOSITORY = strdup(retval); CfOut(cf_verbose,"","SET repository = %s\n",VREPOSITORY); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_skipidentify].lval) == 0) { SKIPIDENTIFY = GetBoolean(retval); CfOut(cf_verbose,"","SET skipidentify = %d\n",SKIPIDENTIFY); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_suspiciousnames].lval) == 0) { for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next) { PrependItem(&SUSPICIOUSLIST,rp->item,NULL); CfOut(cf_verbose,"", "-> Concidering %s as suspicious file", rp->item); } continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_repchar].lval) == 0) { REPOSCHAR = *(char *)retval; CfOut(cf_verbose,"","SET repchar = %c\n",REPOSCHAR); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_mountfilesystems].lval) == 0) { CF_MOUNTALL = GetBoolean(retval); CfOut(cf_verbose,"","SET mountfilesystems = %d\n",CF_MOUNTALL); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_editfilesize].lval) == 0) { EDITFILESIZE = Str2Int(retval); CfOut(cf_verbose,"","SET EDITFILESIZE = %d\n",EDITFILESIZE); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_ifelapsed].lval) == 0) { VIFELAPSED = Str2Int(retval); CfOut(cf_verbose,"","SET ifelapsed = %d\n",VIFELAPSED); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_expireafter].lval) == 0) { VEXPIREAFTER = Str2Int(retval); CfOut(cf_verbose,"","SET ifelapsed = %d\n",VEXPIREAFTER); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_timeout].lval) == 0) { CONNTIMEOUT = Str2Int(retval); CfOut(cf_verbose,"","SET timeout = %d\n",CONNTIMEOUT); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_max_children].lval) == 0) { CFA_BACKGROUND_LIMIT = Str2Int(retval); CfOut(cf_verbose,"","SET MAX_CHILDREN = %d\n",CFA_BACKGROUND_LIMIT); if (CFA_BACKGROUND_LIMIT > 10) { CfOut(cf_error,"","Silly value for max_children in agent control promise (%d > 10)",CFA_BACKGROUND_LIMIT); CFA_BACKGROUND_LIMIT = 1; } continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_syslog].lval) == 0) { LOGGING = GetBoolean(retval); CfOut(cf_verbose,"","SET syslog = %d\n",LOGGING); continue; } if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_environment].lval) == 0) { struct Rlist *rp; CfOut(cf_verbose,"","SET environment variables from ...\n"); for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next) { if (putenv(rp->item) != 0) { CfOut(cf_error, "putenv", "Failed to set environment variable %s", rp->item); } } continue; } } if (GetVariable("control_common",CFG_CONTROLBODY[cfg_lastseenexpireafter].lval,&retval,&rettype) != cf_notype) { LASTSEENEXPIREAFTER = Str2Int(retval); } if (GetVariable("control_common",CFG_CONTROLBODY[cfg_fips_mode].lval,&retval,&rettype) != cf_notype) { FIPS_MODE = GetBoolean(retval); CfOut(cf_verbose,"","SET FIPS_MODE = %d\n",FIPS_MODE); } if (GetVariable("control_common",CFG_CONTROLBODY[cfg_syslog_port].lval,&retval,&rettype) != cf_notype) { SYSLOGPORT = (unsigned short)Str2Int(retval); CfOut(cf_verbose,"","SET syslog_port to %d",SYSLOGPORT); } if (GetVariable("control_common",CFG_CONTROLBODY[cfg_syslog_host].lval,&retval,&rettype) != cf_notype) { strncpy(SYSLOGHOST,Hostname2IPString(retval),CF_MAXVARSIZE-1); CfOut(cf_verbose,"","SET syslog_host to %s",SYSLOGHOST); } #ifdef HAVE_NOVA Nova_Initialize(); #endif }