void VerifyProcesses(Attributes a, Promise *pp) { CfLock thislock; char lockname[CF_BUFSIZE]; if (a.restart_class) { snprintf(lockname, CF_BUFSIZE - 1, "proc-%s-%s", pp->promiser, a.restart_class); } else { snprintf(lockname, CF_BUFSIZE - 1, "proc-%s-norestart", pp->promiser); } thislock = AcquireLock(lockname, VUQNAME, CFSTARTTIME, a, pp, false); if (thislock.lock == NULL) { return; } DeleteScalar("this", "promiser"); NewScalar("this", "promiser", pp->promiser, cf_str); PromiseBanner(pp); VerifyProcessOp(PROCESSTABLE, a, pp); DeleteScalar("this", "promiser"); YieldCurrentLock(thislock); }
void NewScalar(const char *scope, const char *lval, const char *rval, enum cfdatatype dt) { Rval rvald; Scope *ptr; CfDebug("NewScalar(%s,%s,%s)\n", scope, lval, rval); ptr = GetScope(scope); if (ptr == NULL) { CfOut(cf_error, "", "!! Attempt to add variable \"%s\" to non-existant scope \"%s\" - ignored", lval, scope); return; } // Newscalar allocates memory through NewAssoc if (GetVariable(scope, lval, &rvald) != cf_notype) { DeleteScalar(scope, lval); } /* * We know AddVariableHash does not change passed Rval structure or its * contents, but we have no easy way to express it in C type system, hence cast. */ AddVariableHash(scope, lval, (Rval) {(char *) rval, CF_SCALAR}, dt, NULL, 0); }
void DefaultVarPromise(Promise *pp) { char *regex = GetConstraintValue("if_match_regex", pp, CF_SCALAR); Rval rval; enum cfdatatype dt; Rlist *rp; bool okay = true; dt = GetVariable("this", pp->promiser, &rval); switch (dt) { case cf_str: case cf_int: case cf_real: if (regex && !FullTextMatch(regex,rval.item)) { return; } if (regex == NULL) { return; } break; case cf_slist: case cf_ilist: case cf_rlist: if (regex) { for (rp = (Rlist *) rval.item; rp != NULL; rp = rp->next) { if (FullTextMatch(regex,rp->item)) { okay = false; break; } } if (okay) { return; } } break; default: break; } DeleteScalar(pp->bundle, pp->promiser); ConvergeVarHashPromise(pp->bundle, pp, true); }
void VerifyInterfacesPromise(Promise *pp) { Attributes a = { {0} }; a = GetInterfacesAttributes(pp); VerifyInterface(a, pp); DeleteScalar("this", "promiser"); }
void VerifyExecPromise(Promise *pp) { Attributes a = { {0} }; a = GetExecAttributes(pp); ExecSanityChecks(a, pp); VerifyExec(a, pp); DeleteScalar("this", "promiser"); }
void VerifyMethodsPromise(Promise *pp) { Attributes a = { {0} }; a = GetMethodAttributes(pp); VerifyMethod("usebundle", a, pp); DeleteScalar("this", "promiser"); }
void VerifyServices(Attributes a, Promise *pp, const ReportContext *report_context) { CfLock thislock; // allow to start Cfengine windows executor without license #ifdef __MINGW32__ if ((LICENSES == 0) && (strcmp(WINSERVICE_NAME, pp->promiser) != 0)) { return; } #endif thislock = AcquireLock(pp->promiser, VUQNAME, CFSTARTTIME, a, pp, false); if (thislock.lock == NULL) { return; } NewScalar("this", "promiser", pp->promiser, cf_str); PromiseBanner(pp); if (strcmp(a.service.service_type, "windows") == 0) { VerifyWindowsService(a, pp); } else { DoVerifyServices(a, pp, report_context); } DeleteScalar("this", "promiser"); YieldCurrentLock(thislock); }
void NewScalar(char *scope,char *lval,char *rval,enum cfdatatype dt) { struct Rval rvald; struct Scope *ptr; Debug("NewScalar(%s,%s,%s)\n",scope,lval,rval); ptr = GetScope(scope); if (ptr == NULL) { CfOut(cf_error, "", "!! Attempt to add variable \"%s\" to non-existant scope \"%s\" - ignored", lval, scope); return; } // Newscalar allocates memory through NewAssoc if (GetVariable(scope,lval,&rvald.item,&rvald.rtype) != cf_notype) { DeleteScalar(scope,lval); } AddVariableHash(scope,lval,rval,CF_SCALAR,dt,NULL,0); }
static void VerifyExec(Attributes a, Promise *pp) { CfLock thislock; char unsafeLine[CF_BUFSIZE], line[sizeof(unsafeLine) * 2], eventname[CF_BUFSIZE]; char comm[20]; char execstr[CF_EXPANDSIZE]; int outsourced, count = 0; mode_t maskval = 0; FILE *pfp; char cmdOutBuf[CF_BUFSIZE]; int cmdOutBufPos = 0; int lineOutLen; if (!IsExecutable(GetArg0(pp->promiser))) { cfPS(cf_error, CF_FAIL, "", pp, a, "%s promises to be executable but isn't\n", pp->promiser); if (strchr(pp->promiser, ' ')) { CfOut(cf_verbose, "", "Paths with spaces must be inside escaped quoutes (e.g. \\\"%s\\\")", pp->promiser); } return; } else { CfOut(cf_verbose, "", " -> Promiser string contains a valid executable (%s) - ok\n", GetArg0(pp->promiser)); } DeleteScalar("this", "promiser"); NewScalar("this", "promiser", pp->promiser, cf_str); if (a.args) { snprintf(execstr, CF_EXPANDSIZE - 1, "%s %s", pp->promiser, a.args); } else { strncpy(execstr, pp->promiser, CF_BUFSIZE); } thislock = AcquireLock(execstr, VUQNAME, CFSTARTTIME, a, pp, false); if (thislock.lock == NULL) { return; } PromiseBanner(pp); CfOut(cf_inform, "", " -> Executing \'%s\' ...(timeout=%d,owner=%ju,group=%ju)\n", execstr, a.contain.timeout, (uintmax_t)a.contain.owner, (uintmax_t)a.contain.group); BeginMeasure(); if (DONTDO && !a.contain.preview) { CfOut(cf_error, "", "-> Would execute script %s\n", execstr); } else if (a.transaction.action != cfa_fix) { cfPS(cf_error, CF_WARN, "", pp, a, " !! Command \"%s\" needs to be executed, but only warning was promised", execstr); } else { CommPrefix(execstr, comm); if (a.transaction.background) { #ifdef MINGW outsourced = true; #else CfOut(cf_verbose, "", " -> Backgrounding job %s\n", execstr); outsourced = fork(); #endif } else { outsourced = false; } if (outsourced || !a.transaction.background) // work done here: either by child or non-background parent { if (a.contain.timeout != CF_NOINT) { SetTimeOut(a.contain.timeout); } #ifndef MINGW CfOut(cf_verbose, "", " -> (Setting umask to %jo)\n", (uintmax_t)a.contain.umask); maskval = umask(a.contain.umask); if (a.contain.umask == 0) { CfOut(cf_verbose, "", " !! Programming %s running with umask 0! Use umask= to set\n", execstr); } #endif /* NOT MINGW */ if (a.contain.useshell) { pfp = cf_popen_shsetuid(execstr, "r", a.contain.owner, a.contain.group, a.contain.chdir, a.contain.chroot, a.transaction.background); } else { pfp = cf_popensetuid(execstr, "r", a.contain.owner, a.contain.group, a.contain.chdir, a.contain.chroot, a.transaction.background); } if (pfp == NULL) { cfPS(cf_error, CF_FAIL, "cf_popen", pp, a, "!! Couldn't open pipe to command %s\n", execstr); YieldCurrentLock(thislock); return; } while (!feof(pfp)) { if (ferror(pfp)) /* abortable */ { cfPS(cf_error, CF_TIMEX, "ferror", pp, a, "!! Command pipe %s\n", execstr); cf_pclose(pfp); YieldCurrentLock(thislock); return; } CfReadLine(unsafeLine, CF_BUFSIZE - 1, pfp); ReplaceStr(unsafeLine, line, sizeof(line), "%", "%%"); // escape format char if (strstr(line, "cfengine-die")) { break; } if (ferror(pfp)) /* abortable */ { cfPS(cf_error, CF_TIMEX, "ferror", pp, a, "!! Command pipe %s\n", execstr); cf_pclose(pfp); YieldCurrentLock(thislock); return; } if (a.contain.preview) { PreviewProtocolLine(line, execstr); } if (a.module) { ModuleProtocol(execstr, line, !a.contain.nooutput); } else if (!a.contain.nooutput && NonEmptyLine(line)) { lineOutLen = strlen(comm) + strlen(line) + 12; // if buffer is to small for this line, output it directly if (lineOutLen > sizeof(cmdOutBuf)) { CfOut(cf_cmdout, "", "Q: \"...%s\": %s\n", comm, line); } else { if (cmdOutBufPos + lineOutLen > sizeof(cmdOutBuf)) { CfOut(cf_cmdout, "", "%s", cmdOutBuf); cmdOutBufPos = 0; } sprintf(cmdOutBuf + cmdOutBufPos, "Q: \"...%s\": %s\n", comm, line); cmdOutBufPos += (lineOutLen - 1); } count++; } } #ifdef MINGW if (outsourced) // only get return value if we waited for command execution { cf_pclose(pfp); } else { cf_pclose_def(pfp, a, pp); } #else /* NOT MINGW */ cf_pclose_def(pfp, a, pp); #endif } if (count) { if (cmdOutBufPos) { CfOut(cf_cmdout, "", "%s", cmdOutBuf); } CfOut(cf_cmdout, "", "I: Last %d quoted lines were generated by promiser \"%s\"\n", count, execstr); } if (a.contain.timeout != CF_NOINT) { alarm(0); signal(SIGALRM, SIG_DFL); } CfOut(cf_inform, "", " -> Completed execution of %s\n", execstr); #ifndef MINGW umask(maskval); #endif YieldCurrentLock(thislock); snprintf(eventname, CF_BUFSIZE - 1, "Exec(%s)", execstr); #ifndef MINGW if (a.transaction.background && outsourced) { CfOut(cf_verbose, "", " -> Backgrounded command (%s) is done - exiting\n", execstr); exit(0); } #endif /* NOT MINGW */ } }
static void CheckControlPromises(char *scope,char *agent,struct Constraint *controllist) { struct Constraint *cp; struct BodySyntax *bp = NULL; struct Rlist *rp; int i = 0; struct Rval returnval; char rettype; void *retval; Debug("CheckControlPromises(%s)\n",agent); for (i = 0; CF_ALL_BODIES[i].bs != NULL; i++) { bp = CF_ALL_BODIES[i].bs; if (strcmp(agent,CF_ALL_BODIES[i].btype) == 0) { break; } } if (bp == NULL) { FatalError("Unknown agent"); } for (cp = controllist; cp != NULL; cp=cp->next) { if (IsExcluded(cp->classes)) { continue; } if (strcmp(cp->lval,CFG_CONTROLBODY[cfg_bundlesequence].lval) == 0) { returnval = ExpandPrivateRval(CONTEXTID,cp->rval,cp->type); } else { returnval = EvaluateFinalRval(CONTEXTID,cp->rval,cp->type,true,NULL); } DeleteVariable(scope,cp->lval); if (!AddVariableHash(scope,cp->lval,returnval.item,returnval.rtype,GetControlDatatype(cp->lval,bp),cp->audit->filename,cp->lineno)) { CfOut(cf_error,""," !! Rule from %s at/before line %d\n",cp->audit->filename,cp->lineno); } if (strcmp(cp->lval,CFG_CONTROLBODY[cfg_output_prefix].lval) == 0) { strncpy(VPREFIX,returnval.item,CF_MAXVARSIZE); } if (strcmp(cp->lval,CFG_CONTROLBODY[cfg_domain].lval) == 0) { strcpy(VDOMAIN,cp->rval); CfOut(cf_verbose,"","SET domain = %s\n",VDOMAIN); DeleteScalar("sys","domain"); DeleteScalar("sys","fqhost"); snprintf(VFQNAME,CF_MAXVARSIZE,"%s.%s",VUQNAME,VDOMAIN); NewScalar("sys","fqhost",VFQNAME,cf_str); NewScalar("sys","domain",VDOMAIN,cf_str); DeleteClass("undefined_domain"); NewClass(VDOMAIN); } if (strcmp(cp->lval,CFG_CONTROLBODY[cfg_ignore_missing_inputs].lval) == 0) { CfOut(cf_verbose,"","SET ignore_missing_inputs %s\n",cp->rval); IGNORE_MISSING_INPUTS = GetBoolean(cp->rval); } if (strcmp(cp->lval,CFG_CONTROLBODY[cfg_ignore_missing_bundles].lval) == 0) { CfOut(cf_verbose,"","SET ignore_missing_bundles %s\n",cp->rval); IGNORE_MISSING_BUNDLES = GetBoolean(cp->rval); } if (strcmp(cp->lval,CFG_CONTROLBODY[cfg_goalpatterns].lval) == 0) { GOALS = NULL; for (rp = (struct Rlist *)returnval.item; rp != NULL; rp=rp->next) { PrependRScalar(&GOALS,rp->item,CF_SCALAR); } CfOut(cf_verbose,"","SET goal_patterns list\n"); continue; } if (strcmp(cp->lval,CFG_CONTROLBODY[cfg_goalcategories].lval) == 0) { GOALCATEGORIES = NULL; for (rp = (struct Rlist *)returnval.item; rp != NULL; rp=rp->next) { PrependRScalar(&GOALCATEGORIES,rp->item,CF_SCALAR); } CfOut(cf_verbose,"","SET goal_categories list\n"); continue; } DeleteRvalItem(returnval.item,returnval.rtype); } }