bool GenericAgentArePromisesValid(const GenericAgentConfig *config) { char cmd[CF_BUFSIZE]; Log(LOG_LEVEL_VERBOSE, "Verifying the syntax of the inputs..."); { char cfpromises[CF_MAXVARSIZE]; snprintf(cfpromises, sizeof(cfpromises), "%s%cbin%ccf-promises%s", CFWORKDIR, FILE_SEPARATOR, FILE_SEPARATOR, EXEC_SUFFIX); struct stat sb; if (stat(cfpromises, &sb) == -1) { Log(LOG_LEVEL_ERR, "cf-promises%s needs to be installed in %s%cbin for pre-validation of full configuration", EXEC_SUFFIX, CFWORKDIR, FILE_SEPARATOR); return false; } if (config->bundlesequence) { snprintf(cmd, sizeof(cmd), "\"%s\" \"", cfpromises); } else { snprintf(cmd, sizeof(cmd), "\"%s\" -c \"", cfpromises); } } strlcat(cmd, config->input_file, CF_BUFSIZE); strlcat(cmd, "\"", CF_BUFSIZE); if (config->bundlesequence) { strlcat(cmd, " -b \"", CF_BUFSIZE); for (const Rlist *rp = config->bundlesequence; rp; rp = rp->next) { const char *bundle_ref = RlistScalarValue(rp); strlcat(cmd, bundle_ref, CF_BUFSIZE); if (rp->next) { strlcat(cmd, ",", CF_BUFSIZE); } } strlcat(cmd, "\"", CF_BUFSIZE); } Log(LOG_LEVEL_VERBOSE, "Checking policy with command '%s'", cmd); if (!ShellCommandReturnsZero(cmd, true)) { Log(LOG_LEVEL_ERR, "Policy failed validation with command '%s'", cmd); return false; } return true; }
static int SelectExecProgram(char *filename, char *command) /* command can include $(this.promiser) for the name of the file */ { char buf[CF_MAXVARSIZE]; // insert real value of $(this.promiser) in command ReplaceStr(command, buf, sizeof(buf), "$(this.promiser)", filename); ReplaceStr(command, buf, sizeof(buf), "${this.promiser}", filename); if (ShellCommandReturnsZero(buf, false)) { CfDebug(" - ? Select ExecProgram match for %s\n", buf); return true; } else { return false; } }
static int SelectExecProgram(char *filename, char *command) /* command can include $(this.promiser) for the name of the file */ { char buf[CF_MAXVARSIZE]; // insert real value of $(this.promiser) in command ReplaceStr(command, buf, sizeof(buf), "$(this.promiser)", filename); ReplaceStr(command, buf, sizeof(buf), "${this.promiser}", filename); if (ShellCommandReturnsZero(buf, SHELL_TYPE_NONE)) { Log(LOG_LEVEL_DEBUG, "Select ExecProgram match for '%s'", buf); return true; } else { return false; } }
static int SelectExecProgram(char *filename, char *command) /* command can include $(this.promiser) for the name of the file */ { // insert real value of $(this.promiser) in command char *buf_tmp = SearchAndReplace(command, "$(this.promiser)", filename); char *buf = SearchAndReplace(buf_tmp, "${this.promiser}", filename); free(buf_tmp); bool returns_zero = ShellCommandReturnsZero(buf, SHELL_TYPE_NONE); if (returns_zero) { Log(LOG_LEVEL_DEBUG, "Select ExecProgram match for '%s'", buf); free(buf); return true; } else { free(buf); return false; } }
static void VerifyProcessOp(EvalContext *ctx, Item *procdata, Attributes a, Promise *pp) { int matches = 0, do_signals = true, out_of_range, killed = 0, need_to_restart = true; Item *killlist = NULL; matches = FindPidMatches(ctx, procdata, &killlist, a, pp->promiser); /* promise based on number of matches */ if (a.process_count.min_range != CF_NOINT) /* if a range is specified */ { if ((matches < a.process_count.min_range) || (matches > a.process_count.max_range)) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_CHANGE, pp, a, "Process count for '%s' was out of promised range (%d found)", pp->promiser, matches); for (const Rlist *rp = a.process_count.out_of_range_define; rp != NULL; rp = rp->next) { if (!EvalContextHeapContainsSoft(ctx, rp->item)) { EvalContextHeapAddSoft(ctx, rp->item, PromiseGetNamespace(pp)); } } out_of_range = true; } else { for (const Rlist *rp = a.process_count.in_range_define; rp != NULL; rp = rp->next) { if (!EvalContextHeapContainsSoft(ctx, rp->item)) { EvalContextHeapAddSoft(ctx, rp->item, PromiseGetNamespace(pp)); } } cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "Process promise for '%s' is kept", pp->promiser); out_of_range = false; } } else { out_of_range = true; } if (!out_of_range) { return; } if (a.transaction.action == cfa_warn) { do_signals = false; } else { do_signals = true; } /* signal/kill promises for existing matches */ if (do_signals && (matches > 0)) { if (a.process_stop != NULL) { if (DONTDO) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "Need to keep process-stop promise for '%s', but only a warning is promised", pp->promiser); } else { if (IsExecutable(CommandArg0(a.process_stop))) { ShellCommandReturnsZero(a.process_stop, SHELL_TYPE_NONE); } else { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_FAIL, pp, a, "Process promise to stop '%s' could not be kept because '%s' the stop operator failed", pp->promiser, a.process_stop); DeleteItemList(killlist); return; } } } killed = DoAllSignals(ctx, killlist, a, pp); } /* delegated promise to restart killed or non-existent entries */ need_to_restart = (a.restart_class != NULL) && (killed || (matches == 0)); DeleteItemList(killlist); if (!need_to_restart) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "No restart promised for %s", pp->promiser); return; } else { if (a.transaction.action == cfa_warn) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "Need to keep restart promise for '%s', but only a warning is promised", pp->promiser); } else { cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "Making a one-time restart promise for '%s'", pp->promiser); EvalContextHeapAddSoft(ctx, a.restart_class, PromiseGetNamespace(pp)); } } }
static PromiseResult VerifyProcessOp(EvalContext *ctx, Item *procdata, Attributes a, const Promise *pp) { bool do_signals = true; int out_of_range; int killed = 0; bool need_to_restart = true; Item *killlist = NULL; int matches = FindPidMatches(procdata, &killlist, a, pp->promiser); /* promise based on number of matches */ PromiseResult result = PROMISE_RESULT_NOOP; if (a.process_count.min_range != CF_NOINT) /* if a range is specified */ { if ((matches < a.process_count.min_range) || (matches > a.process_count.max_range)) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_CHANGE, pp, a, "Process count for '%s' was out of promised range (%d found)", pp->promiser, matches); result = PromiseResultUpdate(result, PROMISE_RESULT_CHANGE); for (const Rlist *rp = a.process_count.out_of_range_define; rp != NULL; rp = rp->next) { ClassRef ref = ClassRefParse(RlistScalarValue(rp)); EvalContextClassPutSoft(ctx, RlistScalarValue(rp), CONTEXT_SCOPE_NAMESPACE, "source=promise"); ClassRefDestroy(ref); } out_of_range = true; } else { for (const Rlist *rp = a.process_count.in_range_define; rp != NULL; rp = rp->next) { ClassRef ref = ClassRefParse(RlistScalarValue(rp)); EvalContextClassPutSoft(ctx, RlistScalarValue(rp), CONTEXT_SCOPE_NAMESPACE, "source=promise"); ClassRefDestroy(ref); } cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "Process promise for '%s' is kept", pp->promiser); out_of_range = false; } } else { out_of_range = true; } if (!out_of_range) { DeleteItemList(killlist); return result; } if (a.transaction.action == cfa_warn) { do_signals = false; result = PromiseResultUpdate(result, PROMISE_RESULT_WARN); } else { do_signals = true; } /* signal/kill promises for existing matches */ if (do_signals && (matches > 0)) { if (a.process_stop != NULL) { if (DONTDO) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "Need to keep process-stop promise for '%s', but only a warning is promised", pp->promiser); result = PromiseResultUpdate(result, PROMISE_RESULT_WARN); } else { if (IsExecutable(CommandArg0(a.process_stop))) { ShellCommandReturnsZero(a.process_stop, SHELL_TYPE_NONE); } else { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Process promise to stop '%s' could not be kept because '%s' the stop operator failed", pp->promiser, a.process_stop); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); DeleteItemList(killlist); return result; } } } killed = DoAllSignals(ctx, killlist, a, pp, &result); } /* delegated promise to restart killed or non-existent entries */ need_to_restart = (a.restart_class != NULL) && (killed || (matches == 0)); DeleteItemList(killlist); if (!need_to_restart) { cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "No restart promised for %s", pp->promiser); return result; } else { if (a.transaction.action == cfa_warn) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "Need to keep restart promise for '%s', but only a warning is promised", pp->promiser); result = PromiseResultUpdate(result, PROMISE_RESULT_WARN); } else { cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "Making a one-time restart promise for '%s'", pp->promiser); result = PromiseResultUpdate(result, PROMISE_RESULT_CHANGE); EvalContextClassPutSoft(ctx, a.restart_class, CONTEXT_SCOPE_NAMESPACE, "source=promise"); } } return result; }
bool GenericAgentCheckPromises(const GenericAgentConfig *config) { char cmd[CF_BUFSIZE]; Log(LOG_LEVEL_VERBOSE, "Verifying the syntax of the inputs..."); { char cfpromises[CF_MAXVARSIZE]; snprintf(cfpromises, sizeof(cfpromises), "%s%cbin%ccf-promises%s", CFWORKDIR, FILE_SEPARATOR, FILE_SEPARATOR, EXEC_SUFFIX); struct stat sb; if (stat(cfpromises, &sb) == -1) { Log(LOG_LEVEL_ERR, "cf-promises%s needs to be installed in %s%cbin for pre-validation of full configuration", EXEC_SUFFIX, CFWORKDIR, FILE_SEPARATOR); return false; } if (config->bundlesequence) { snprintf(cmd, sizeof(cmd), "\"%s\" \"", cfpromises); } else { snprintf(cmd, sizeof(cmd), "\"%s\" -c \"", cfpromises); } } strlcat(cmd, config->input_file, CF_BUFSIZE); strlcat(cmd, "\"", CF_BUFSIZE); if (config->bundlesequence) { strlcat(cmd, " -b \"", CF_BUFSIZE); for (const Rlist *rp = config->bundlesequence; rp; rp = rp->next) { const char *bundle_ref = rp->item; strlcat(cmd, bundle_ref, CF_BUFSIZE); if (rp->next) { strlcat(cmd, ",", CF_BUFSIZE); } } strlcat(cmd, "\"", CF_BUFSIZE); } if (config->agent_specific.agent.bootstrap_policy_server) { // avoids license complains from commercial cf-promises during bootstrap - see Nova_CheckLicensePromise strlcat(cmd, " -D bootstrap_mode", CF_BUFSIZE); } Log(LOG_LEVEL_VERBOSE, "Checking policy with command '%s'", cmd); if (!ShellCommandReturnsZero(cmd, true)) { Log(LOG_LEVEL_ERR, "Policy failed validation with command '%s'", cmd); return false; } if (!IsFileOutsideDefaultRepository(config->original_input_file)) { WritePolicyValidatedFile(config); } return true; }
int CheckPromises(enum cfagenttype ag) { char cmd[CF_BUFSIZE], cfpromises[CF_MAXVARSIZE]; char filename[CF_MAXVARSIZE]; struct stat sb; int fd; if ((ag != cf_agent) && (ag != cf_executor) && (ag != cf_server)) { return true; } CfOut(cf_verbose,""," -> Verifying the syntax of the inputs...\n"); snprintf(cfpromises,sizeof(cfpromises),"%s%cbin%ccf-promises%s",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR,EXEC_SUFFIX); if (cfstat(cfpromises,&sb) == -1) { CfOut(cf_error,"","cf-promises%s needs to be installed in %s%cbin for pre-validation of full configuration",EXEC_SUFFIX,CFWORKDIR,FILE_SEPARATOR); return false; } /* If we are cf-agent, check syntax before attempting to run */ snprintf(cmd, sizeof(cmd), "\"%s\" -f \"", cfpromises); if (IsFileOutsideDefaultRepository(VINPUTFILE)) { strlcat(cmd, VINPUTFILE, CF_BUFSIZE); } else { strlcat(cmd, CFWORKDIR, CF_BUFSIZE); strlcat(cmd, FILE_SEPARATOR_STR "inputs" FILE_SEPARATOR_STR, CF_BUFSIZE); strlcat(cmd, VINPUTFILE, CF_BUFSIZE); } strlcat(cmd, "\"", CF_BUFSIZE); if (CBUNDLESEQUENCE) { strlcat(cmd, " -b \"", CF_BUFSIZE); strlcat(cmd, CBUNDLESEQUENCE_STR, CF_BUFSIZE); strlcat(cmd, "\"", CF_BUFSIZE); } if(BOOTSTRAP) { // avoids license complains from commercial cf-promises during bootstrap - see Nova_CheckLicensePromise strlcat(cmd, " -D bootstrap_mode", CF_BUFSIZE); } /* Check if reloading policy will succeed */ CfOut(cf_verbose, "", "Checking policy with command \"%s\"", cmd); if (ShellCommandReturnsZero(cmd,true)) { if (MINUSF) { snprintf(filename,CF_MAXVARSIZE,"%s/state/validated_%s",CFWORKDIR,CanonifyName(VINPUTFILE)); MapName(filename); } else { snprintf(filename,CF_MAXVARSIZE,"%s/masterfiles/cf_promises_validated",CFWORKDIR); MapName(filename); } MakeParentDirectory(filename,true); if ((fd = creat(filename,0600)) != -1) { close(fd); CfOut(cf_verbose,""," -> Caching the state of validation\n"); } else { CfOut(cf_verbose,"creat"," -> Failed to cache the state of validation\n"); } return true; } else { return false; } }
void SetDefaultRoute() { int sk, defaultokay = 1; struct sockaddr_in sindst,singw; char oldroute[INET_ADDRSTRLEN]; char routefmt[CF_MAXVARSIZE]; /* These OSes have these structs defined but use the route command */ # if defined DARWIN || defined FREEBSD || defined OPENBSD || defined SOLARIS # undef HAVE_RTENTRY # undef HAVE_ORTENTRY # endif # ifdef HAVE_ORTENTRY struct ortentry route; # else # if HAVE_RTENTRY struct rtentry route; # endif # endif FILE *pp; Verbose("Looking for a default route...\n"); if (!IsPrivileged()) { snprintf(OUTPUT,CF_BUFSIZE*2,"Only root can set a default route."); CfLog(cfinform,OUTPUT,""); return; } if (VDEFAULTROUTE == NULL) { Verbose("cfengine: No default route is defined. Ignoring the routing tables.\n"); return; } if ((pp = cfpopen(VNETSTAT[VSYSTEMHARDCLASS],"r")) == NULL) { snprintf(OUTPUT,CF_BUFSIZE*2,"Failed to open pipe from %s\n",VNETSTAT[VSYSTEMHARDCLASS]); CfLog(cferror,OUTPUT,"popen"); return; } while (!feof(pp)) { ReadLine(VBUFF,CF_BUFSIZE,pp); Debug("LINE: %s = %s?\n",VBUFF,VDEFAULTROUTE->name); if ((strncmp(VBUFF,"default",7) == 0)||(strncmp(VBUFF,"0.0.0.0",7) == 0)) { /* extract the default route */ /* format: default|0.0.0.0 <whitespace> route <whitespace> etc */ if ((sscanf(VBUFF, "%*[default0. ]%s%*[ ]", &oldroute)) == 1) { if ((strncmp(VDEFAULTROUTE->name, oldroute, INET_ADDRSTRLEN)) == 0) { Verbose("cfengine: default route is already set to %s\n",VDEFAULTROUTE->name); defaultokay = 1; break; } else { Verbose("cfengine: default route is set to %s, but should be %s.\n",oldroute,VDEFAULTROUTE->name); defaultokay = 2; break; } } } else { Debug("No default route is yet registered\n"); defaultokay = 0; } } cfpclose(pp); if (defaultokay == 1) { Verbose("Default route is set and agrees with conditional policy\n"); return; } if (defaultokay == 0) { AddMultipleClasses("no_default_route"); } if (IsExcluded(VDEFAULTROUTE->classes)) { Verbose("cfengine: No default route is applicable. Ignoring the routing tables.\n"); return; } CfLog(cferror,"The default route is incorrect, trying to correct\n",""); if ( strcmp(VROUTE[VSYSTEMHARDCLASS], "-") != 0 ) { Debug ("Using route shell commands to set default route\n"); if (defaultokay == 2) { if (! DONTDO) { /* get the route command and the format for the delete argument */ snprintf(routefmt,CF_MAXVARSIZE,"%s %s",VROUTE[VSYSTEMHARDCLASS],VROUTEDELFMT[VSYSTEMHARDCLASS]); snprintf(VBUFF,CF_MAXVARSIZE,routefmt,"default",VDEFAULTROUTE->name); if (ShellCommandReturnsZero(VBUFF,false)) { CfLog(cfinform,"Removing old default route",""); CfLog(cfinform,VBUFF,""); } else { CfLog(cferror,"Error removing route",""); } } } if (! DONTDO) { snprintf(routefmt,CF_MAXVARSIZE,"%s %s",VROUTE[VSYSTEMHARDCLASS],VROUTEADDFMT[VSYSTEMHARDCLASS]); snprintf(VBUFF,CF_MAXVARSIZE,routefmt,"default",VDEFAULTROUTE->name); if (ShellCommandReturnsZero(VBUFF,false)) { CfLog(cfinform,"Setting default route",""); CfLog(cfinform,VBUFF,""); } else { CfLog(cferror,"Error setting route",""); } } return; } else { #if defined HAVE_RTENTRY || defined HAVE_ORTENTRY Debug ("Using route ioctl to set default route\n"); if ((sk = socket(AF_INET,SOCK_RAW,0)) == -1) { CfLog(cferror,"System class: ", CLASSTEXT[VSYSTEMHARDCLASS]); CfLog(cferror,"","Error in SetDefaultRoute():"); perror("cfengine: socket"); } else { sindst.sin_family = AF_INET; singw.sin_family = AF_INET; sindst.sin_addr.s_addr = INADDR_ANY; singw.sin_addr.s_addr = inet_addr(VDEFAULTROUTE->name); route.rt_dst = *(struct sockaddr *)&sindst; /* This disgusting method is necessary */ route.rt_gateway = *(struct sockaddr *)&singw; route.rt_flags = RTF_GATEWAY; if (! DONTDO) { if (ioctl(sk,SIOCADDRT, (caddr_t) &route) == -1) /* Get the device status flags */ { CfLog(cferror,"Error setting route:",""); perror("cfengine: ioctl SIOCADDRT:"); } else { CfLog(cferror,"Setting default route.\n",""); snprintf(OUTPUT,CF_BUFSIZE*2,"I'm setting it to %s\n",VDEFAULTROUTE->name); CfLog(cferror,OUTPUT,""); } } } #else /* Socket routing - don't really know how to do this yet */ Verbose("Sorry don't know how to do routing on this platform\n"); #endif } }
static void VerifyProcessOp(Item *procdata, Attributes a, Promise *pp) { int matches = 0, do_signals = true, out_of_range, killed = 0, need_to_restart = true; Item *killlist = NULL; CfDebug("VerifyProcessOp\n"); matches = FindPidMatches(procdata, &killlist, a, pp); /* promise based on number of matches */ if (a.process_count.min_range != CF_NOINT) /* if a range is specified */ { if (matches < a.process_count.min_range || matches > a.process_count.max_range) { cfPS(cf_error, CF_CHG, "", pp, a, " !! Process count for \'%s\' was out of promised range (%d found)\n", pp->promiser, matches); AddEphemeralClasses(a.process_count.out_of_range_define); out_of_range = true; } else { AddEphemeralClasses(a.process_count.in_range_define); cfPS(cf_verbose, CF_NOP, "", pp, a, " -> Process promise for %s is kept", pp->promiser); out_of_range = false; } } else { out_of_range = true; } if (!out_of_range) { return; } if (a.transaction.action == cfa_warn) { do_signals = false; } else { do_signals = true; } /* signal/kill promises for existing matches */ if (do_signals && matches > 0) { if (a.process_stop != NULL) { if (DONTDO) { cfPS(cf_error, CF_WARN, "", pp, a, " -- Need to keep process-stop promise for %s, but only a warning is promised", pp->promiser); } else { if (IsExecutable(GetArg0(a.process_stop))) { ShellCommandReturnsZero(a.process_stop, false); } else { cfPS(cf_verbose, CF_FAIL, "", pp, a, "Process promise to stop %s could not be kept because %s the stop operator failed", pp->promiser, a.process_stop); DeleteItemList(killlist); return; } } } killed = DoAllSignals(killlist, a, pp); } /* delegated promise to restart killed or non-existent entries */ need_to_restart = (a.restart_class != NULL) && (killed || matches == 0); DeleteItemList(killlist); if (!need_to_restart) { cfPS(cf_verbose, CF_NOP, "", pp, a, " -> No restart promised for %s\n", pp->promiser); return; } else { if (a.transaction.action == cfa_warn) { cfPS(cf_error, CF_WARN, "", pp, a, " -- Need to keep restart promise for %s, but only a warning is promised", pp->promiser); } else { cfPS(cf_inform, CF_CHG, "", pp, a, " -> Making a one-time restart promise for %s", pp->promiser); NewClass(a.restart_class); } } }