static void SummarizeTransaction(EvalContext *ctx, TransactionContext tc, const char *logname) { if (logname && (tc.log_string)) { char buffer[CF_EXPANDSIZE]; ExpandScalar(ctx, ScopeGetCurrent()->scope, tc.log_string, buffer); if (strcmp(logname, "udp_syslog") == 0) { RemoteSysLog(tc.log_priority, buffer); } else if (strcmp(logname, "stdout") == 0) { Log(LOG_LEVEL_INFO, "L: %s", buffer); } else { FILE *fout = fopen(logname, "a"); if (fout == NULL) { Log(LOG_LEVEL_ERR, "Unable to open private log '%s'", logname); return; } Log(LOG_LEVEL_VERBOSE, "Logging string '%s' to '%s'", buffer, logname); fprintf(fout, "%s\n", buffer); fclose(fout); } tc.log_string = NULL; /* To avoid repetition */ } }
static void SummarizeTransaction(EvalContext *ctx, Attributes attr, const char *logname) { if (logname && (attr.transaction.log_string)) { char buffer[CF_EXPANDSIZE]; ExpandScalar(ctx, ScopeGetCurrent()->scope, attr.transaction.log_string, buffer); if (strcmp(logname, "udp_syslog") == 0) { RemoteSysLog(attr.transaction.log_priority, buffer); } else if (strcmp(logname, "stdout") == 0) { CfOut(OUTPUT_LEVEL_REPORTING, "", "L: %s\n", buffer); } else { FILE *fout = fopen(logname, "a"); if (fout == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "", "Unable to open private log %s", logname); return; } CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Logging string \"%s\" to %s\n", buffer, logname); fprintf(fout, "%s\n", buffer); fclose(fout); } attr.transaction.log_string = NULL; /* To avoid repetition */ } }
Rlist *NewExpArgs(EvalContext *ctx, const FnCall *fp, const Promise *pp) { int len; Rval rval; Rlist *newargs = NULL; FnCall *subfp; const FnCallType *fn = FnCallTypeGet(fp->name); len = RlistLen(fp->args); if (!fn->varargs) { if (len != FnNumArgs(fn)) { CfOut(OUTPUT_LEVEL_ERROR, "", "Arguments to function %s(.) do not tally. Expect %d not %d", fp->name, FnNumArgs(fn), len); PromiseRef(OUTPUT_LEVEL_ERROR, pp); exit(1); } } for (const Rlist *rp = fp->args; rp != NULL; rp = rp->next) { switch (rp->type) { case RVAL_TYPE_FNCALL: subfp = (FnCall *) rp->item; rval = FnCallEvaluate(ctx, subfp, pp).rval; break; default: rval = ExpandPrivateRval(ScopeGetCurrent()->scope, (Rval) {rp->item, rp->type}); break; } CfDebug("EXPARG: %s.%s\n", ScopeGetCurrent()->scope, (char *) rval.item); RlistAppend(&newargs, rval.item, rval.type); RvalDestroy(rval); } return newargs; }
void RlistFlatten(EvalContext *ctx, Rlist **list) { for (Rlist *rp = *list; rp != NULL;) { if (rp->type != RVAL_TYPE_SCALAR) { rp = rp->next; continue; } char naked[CF_BUFSIZE] = ""; if (IsNakedVar(rp->item, '@')) { GetNaked(naked, rp->item); Rval rv; if (EvalContextVariableGet(ctx, (VarRef) { NULL, ScopeGetCurrent()->scope, naked }, &rv, NULL)) { switch (rv.type) { case RVAL_TYPE_LIST: for (const Rlist *srp = rv.item; srp != NULL; srp = srp->next) { RlistAppend(list, srp->item, srp->type); } Rlist *next = rp->next; RlistDestroyEntry(list, rp); rp = next; continue; default: ProgrammingError("List variable does not resolve to a list"); RlistAppend(list, rp->item, rp->type); break; } } } rp = rp->next; } }
bool EvalContextVariablePut(EvalContext *ctx, VarRef lval, Rval rval, DataType type) { Scope *ptr; const Rlist *rp; CfAssoc *assoc; if (rval.type == RVAL_TYPE_SCALAR) { CfDebug("AddVariableHash(%s.%s=%s (%s) rtype=%c)\n", lval.scope, lval.lval, (const char *) rval.item, CF_DATATYPES[type], rval.type); } else { CfDebug("AddVariableHash(%s.%s=(list) (%s) rtype=%c)\n", lval.scope, lval.lval, CF_DATATYPES[type], rval.type); } if (lval.lval == NULL || lval.scope == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "", "scope.value = %s.%s", lval.scope, lval.lval); ProgrammingError("Bad variable or scope in a variable assignment, should not happen - forgotten to register a function call in fncall.c?"); } if (rval.item == NULL) { CfDebug("No value to assignment - probably a parameter in an unused bundle/body\n"); return false; } if (strlen(lval.lval) > CF_MAXVARSIZE) { char *lval_str = VarRefToString(lval); CfOut(OUTPUT_LEVEL_ERROR, "", "Variable %s cannot be added because its length exceeds the maximum length allowed: %d", lval_str, CF_MAXVARSIZE); free(lval_str); return false; } /* If we are not expanding a body template, check for recursive singularities */ if (strcmp(lval.scope, "body") != 0) { switch (rval.type) { case RVAL_TYPE_SCALAR: if (StringContainsVar((char *) rval.item, lval.lval)) { CfOut(OUTPUT_LEVEL_ERROR, "", "Scalar variable %s.%s contains itself (non-convergent): %s", lval.scope, lval.lval, (char *) rval.item); return false; } break; case RVAL_TYPE_LIST: for (rp = rval.item; rp != NULL; rp = rp->next) { if (StringContainsVar((char *) rp->item, lval.lval)) { CfOut(OUTPUT_LEVEL_ERROR, "", "List variable %s contains itself (non-convergent)", lval.lval); return false; } } break; default: break; } } ptr = ScopeGet(lval.scope); if (!ptr) { ptr = ScopeNew(lval.scope); if (!ptr) { return false; } } // Look for outstanding lists in variable rvals if (THIS_AGENT_TYPE == AGENT_TYPE_COMMON) { Rlist *listvars = NULL; if (ScopeGetCurrent() && strcmp(ScopeGetCurrent()->scope, "this") != 0) { MapIteratorsFromRval(ScopeGetCurrent()->scope, &listvars, rval); if (listvars != NULL) { CfOut(OUTPUT_LEVEL_ERROR, "", " !! Redefinition of variable \"%s\" (embedded list in RHS) in context \"%s\"", lval.lval, ScopeGetCurrent()->scope); } RlistDestroy(listvars); } } assoc = HashLookupElement(ptr->hashtable, lval.lval); if (assoc) { if (CompareVariableValue(rval, assoc) == 0) { /* Identical value, keep as is */ } else { /* Different value, bark and replace */ if (!UnresolvedVariables(assoc, rval.type)) { CfOut(OUTPUT_LEVEL_INFORM, "", " !! Duplicate selection of value for variable \"%s\" in scope %s", lval.lval, ptr->scope); } RvalDestroy(assoc->rval); assoc->rval = RvalCopy(rval); assoc->dtype = type; CfDebug("Stored \"%s\" in context %s\n", lval.lval, lval.scope); } } else { if (!HashInsertElement(ptr->hashtable, lval.lval, rval, type)) { ProgrammingError("Hash table is full"); } } CfDebug("Added Variable %s in scope %s with value (omitted)\n", lval.lval, lval.scope); return true; }
bool EvalContextVariablePut(EvalContext *ctx, VarRef lval, Rval rval, DataType type) { assert(type != DATA_TYPE_NONE); if (lval.lval == NULL || lval.scope == NULL) { ProgrammingError("Bad variable or scope in a variable assignment. scope.value = %s.%s", lval.scope, lval.lval); } if (rval.item == NULL) { return false; } if (strlen(lval.lval) > CF_MAXVARSIZE) { char *lval_str = VarRefToString(lval, true); Log(LOG_LEVEL_ERR, "Variable '%s'' cannot be added because its length exceeds the maximum length allowed '%d' characters", lval_str, CF_MAXVARSIZE); free(lval_str); return false; } // If we are not expanding a body template, check for recursive singularities if (strcmp(lval.scope, "body") != 0) { switch (rval.type) { case RVAL_TYPE_SCALAR: if (StringContainsVar((char *) rval.item, lval.lval)) { Log(LOG_LEVEL_ERR, "Scalar variable '%s.%s' contains itself (non-convergent), value '%s'", lval.scope, lval.lval, (char *) rval.item); return false; } break; case RVAL_TYPE_LIST: for (const Rlist *rp = rval.item; rp != NULL; rp = rp->next) { if (StringContainsVar(rp->item, lval.lval)) { Log(LOG_LEVEL_ERR, "List variable '%s' contains itself (non-convergent)", lval.lval); return false; } } break; default: break; } } else { assert(STACK_FRAME_TYPE_BODY == LastStackFrame(ctx, 0)->type); } Scope *put_scope = ScopeGet(lval.scope); if (!put_scope) { put_scope = ScopeNew(lval.scope); if (!put_scope) { return false; } } // Look for outstanding lists in variable rvals if (THIS_AGENT_TYPE == AGENT_TYPE_COMMON) { Rlist *listvars = NULL; Rlist *scalars = NULL; // TODO what do we do with scalars? if (ScopeGetCurrent() && strcmp(ScopeGetCurrent()->scope, "this") != 0) { MapIteratorsFromRval(ctx, ScopeGetCurrent()->scope, &listvars, &scalars, rval); if (listvars != NULL) { Log(LOG_LEVEL_ERR, "Redefinition of variable '%s' (embedded list in RHS) in context '%s'", lval.lval, ScopeGetCurrent()->scope); } RlistDestroy(listvars); RlistDestroy(scalars); } } // FIX: lval is stored with array params as part of the lval for legacy reasons. char *final_lval = VarRefToString(lval, false); CfAssoc *assoc = HashLookupElement(put_scope->hashtable, final_lval); if (assoc) { if (CompareVariableValue(rval, assoc) != 0) { /* Different value, bark and replace */ if (!UnresolvedVariables(assoc, rval.type)) { Log(LOG_LEVEL_INFO, "Replaced value of variable '%s' in scope '%s'", lval.lval, put_scope->scope); } RvalDestroy(assoc->rval); assoc->rval = RvalCopy(rval); assoc->dtype = type; } } else { if (!HashInsertElement(put_scope->hashtable, final_lval, rval, type)) { ProgrammingError("Hash table is full"); } } free(final_lval); return true; }
void LocateFilePromiserGroup(EvalContext *ctx, char *wildpath, Promise *pp, void (*fnptr) (EvalContext *ctx, char *path, Promise *ptr)) { Item *path, *ip, *remainder = NULL; char pbuffer[CF_BUFSIZE]; struct stat statbuf; int count = 0, lastnode = false, expandregex = false; uid_t agentuid = getuid(); int create = PromiseGetConstraintAsBoolean(ctx, "create", pp); char *pathtype = ConstraintGetRvalValue(ctx, "pathtype", pp, RVAL_TYPE_SCALAR); /* Do a search for promiser objects matching wildpath */ if ((!IsPathRegex(wildpath)) || (pathtype && (strcmp(pathtype, "literal") == 0))) { Log(LOG_LEVEL_VERBOSE, "Using literal pathtype for '%s'", wildpath); (*fnptr) (ctx, wildpath, pp); return; } else { Log(LOG_LEVEL_VERBOSE, "Using regex pathtype for '%s' (see pathtype)", wildpath); } pbuffer[0] = '\0'; path = SplitString(wildpath, '/'); // require forward slash in regex on all platforms for (ip = path; ip != NULL; ip = ip->next) { if ((ip->name == NULL) || (strlen(ip->name) == 0)) { continue; } if (ip->next == NULL) { lastnode = true; } /* No need to chdir as in recursive descent, since we know about the path here */ if (IsRegex(ip->name)) { remainder = ip->next; expandregex = true; break; } else { expandregex = false; } if (!JoinPath(pbuffer, ip->name)) { Log(LOG_LEVEL_ERR, "Buffer has limited size in LocateFilePromiserGroup"); return; } if (stat(pbuffer, &statbuf) != -1) { if ((S_ISDIR(statbuf.st_mode)) && ((statbuf.st_uid) != agentuid) && ((statbuf.st_uid) != 0)) { Log(LOG_LEVEL_INFO, "Directory '%s' in search path '%s' is controlled by another user (uid %ju) - trusting its content is potentially risky (possible race condition)", pbuffer, wildpath, (uintmax_t)statbuf.st_uid); PromiseRef(LOG_LEVEL_INFO, pp); } } } if (expandregex) /* Expand one regex link and hand down */ { char nextbuffer[CF_BUFSIZE], nextbufferOrig[CF_BUFSIZE], regex[CF_BUFSIZE]; const struct dirent *dirp; Dir *dirh; memset(regex, 0, CF_BUFSIZE); strncpy(regex, ip->name, CF_BUFSIZE - 1); if ((dirh = DirOpen(pbuffer)) == NULL) { // Could be a dummy directory to be created so this is not an error. Log(LOG_LEVEL_VERBOSE, "Using best-effort expanded (but non-existent) file base path '%s'", wildpath); (*fnptr) (ctx, wildpath, pp); DeleteItemList(path); return; } else { count = 0; for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh)) { if (!ConsiderLocalFile(dirp->d_name, pbuffer)) { continue; } if ((!lastnode) && (!S_ISDIR(statbuf.st_mode))) { Log(LOG_LEVEL_DEBUG, "Skipping non-directory '%s'", dirp->d_name); continue; } if (FullTextMatch(regex, dirp->d_name)) { Log(LOG_LEVEL_DEBUG, "Link '%s' matched regex '%s'", dirp->d_name, regex); } else { continue; } count++; strncpy(nextbuffer, pbuffer, CF_BUFSIZE - 1); AddSlash(nextbuffer); strcat(nextbuffer, dirp->d_name); for (ip = remainder; ip != NULL; ip = ip->next) { AddSlash(nextbuffer); strcat(nextbuffer, ip->name); } /* The next level might still contain regexs, so go again as long as expansion is not nullpotent */ if ((!lastnode) && (strcmp(nextbuffer, wildpath) != 0)) { LocateFilePromiserGroup(ctx, nextbuffer, pp, fnptr); } else { Promise *pcopy; Log(LOG_LEVEL_VERBOSE, "Using expanded file base path '%s'", nextbuffer); /* Now need to recompute any back references to get the complete path */ snprintf(nextbufferOrig, sizeof(nextbufferOrig), "%s", nextbuffer); MapNameForward(nextbuffer); if (!FullTextMatch(pp->promiser, nextbuffer)) { Log(LOG_LEVEL_DEBUG, "Error recomputing references for '%s' in '%s'", pp->promiser, nextbuffer); } /* If there were back references there could still be match.x vars to expand */ pcopy = ExpandDeRefPromise(ctx, ScopeGetCurrent()->scope, pp); (*fnptr) (ctx, nextbufferOrig, pcopy); PromiseDestroy(pcopy); } } DirClose(dirh); } } else { Log(LOG_LEVEL_VERBOSE, "Using file base path '%s'", pbuffer); (*fnptr) (ctx, pbuffer, pp); } if (count == 0) { Log(LOG_LEVEL_VERBOSE, "No promiser file objects matched as regular expression '%s'", wildpath); if (create) { (*fnptr)(ctx, pp->promiser, pp); } } DeleteItemList(path); }