static int ServicesSanityChecks(Attributes a, const Promise *pp) { Rlist *dep; for (dep = a.service.service_depend; dep != NULL; dep = dep->next) { if (strcmp(pp->promiser, RlistScalarValue(dep)) == 0) { Log(LOG_LEVEL_ERR, "Service promiser '%s' has itself as dependency", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); return false; } } if (a.service.service_type == NULL) { Log(LOG_LEVEL_ERR, "Service type for service '%s' is not known", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); return false; } #ifdef __MINGW32__ if (strcmp(a.service.service_type, "windows") != 0) { Log(LOG_LEVEL_ERR, "Service type for promiser '%s' must be 'windows' on this system, but is '%s'", pp->promiser, a.service.service_type); PromiseRef(LOG_LEVEL_ERR, pp); return false; } #endif /* __MINGW32__ */ return true; }
static int UserSanityCheck(Attributes a, Promise *pp) { User *u = &a.users; switch (u->policy) { case USER_STATE_PRESENT: case USER_STATE_ABSENT: case USER_STATE_LOCKED: break; default: Log(LOG_LEVEL_ERR, "No policy specified for 'users' promise '%s'", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); return false; } if ((SafeStringLength(u->password) == 0 && u->password_format != PASSWORD_FORMAT_NONE) || (SafeStringLength(u->password) != 0 && u->password_format == PASSWORD_FORMAT_NONE)) { Log(LOG_LEVEL_ERR, "Both 'data' and 'format' must be specified in password body for 'users' promise '%s'", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); return false; } return true; }
static int ServicesSanityChecks(Attributes a, const Promise *pp) { Rlist *dep; switch (a.service.service_policy) { case SERVICE_POLICY_START: break; case SERVICE_POLICY_STOP: case SERVICE_POLICY_DISABLE: case SERVICE_POLICY_RESTART: case SERVICE_POLICY_RELOAD: if (strcmp(a.service.service_autostart_policy, "none") != 0) { Log(LOG_LEVEL_ERR, "!! Autostart policy of service promiser '%s' needs to be 'none' when service policy is not 'start', but is '%s'", pp->promiser, a.service.service_autostart_policy); PromiseRef(LOG_LEVEL_ERR, pp); return false; } break; default: Log(LOG_LEVEL_ERR, "Invalid service policy for service '%s'", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); return false; } for (dep = a.service.service_depend; dep != NULL; dep = dep->next) { if (strcmp(pp->promiser, RlistScalarValue(dep)) == 0) { Log(LOG_LEVEL_ERR, "Service promiser '%s' has itself as dependency", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); return false; } } if (a.service.service_type == NULL) { Log(LOG_LEVEL_ERR, "Service type for service '%s' is not known", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); return false; } #ifdef __MINGW32__ if (strcmp(a.service.service_type, "windows") != 0) { Log(LOG_LEVEL_ERR, "Service type for promiser '%s' must be 'windows' on this system, but is '%s'", pp->promiser, a.service.service_type); PromiseRef(LOG_LEVEL_ERR, pp); return false; } #endif /* __MINGW32__ */ return true; }
static int ValidateRegistryPromiser(char *key, const Promise *pp) { static char *const valid[] = { "HKEY_CLASSES_ROOT", "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_LOCAL_MACHINE", "HKEY_USERS", NULL }; char root_key[CF_MAXVARSIZE]; char *sp; int i; /* First remove the root key */ strlcpy(root_key, key, CF_MAXVARSIZE ); sp = strchr(root_key, '\\'); if (sp == NULL) { Log(LOG_LEVEL_ERR, "Cannot locate '\\' in '%s'", root_key); Log(LOG_LEVEL_ERR, "Failed validating registry promiser"); PromiseRef(LOG_LEVEL_ERR, pp); return false; } *sp = '\0'; for (i = 0; valid[i] != NULL; i++) { if (strcmp(root_key, valid[i]) == 0) { return true; } } Log(LOG_LEVEL_ERR, "Non-editable registry prefix '%s'", root_key); PromiseRef(LOG_LEVEL_ERR, pp); return false; }
static int ServicesSanityChecks(Attributes a, Promise *pp) { Rlist *dep; switch (a.service.service_policy) { case SERVICE_POLICY_START: break; case SERVICE_POLICY_STOP: case SERVICE_POLICY_DISABLE: if (strcmp(a.service.service_autostart_policy, "none") != 0) { CfOut(OUTPUT_LEVEL_ERROR, "", "!! Autostart policy of service promiser \"%s\" needs to be \"none\" when service policy is not \"start\", but is \"%s\"", pp->promiser, a.service.service_autostart_policy); PromiseRef(OUTPUT_LEVEL_ERROR, pp); return false; } break; default: CfOut(OUTPUT_LEVEL_ERROR, "", "!! Invalid service policy for service \"%s\"", pp->promiser); PromiseRef(OUTPUT_LEVEL_ERROR, pp); return false; } for (dep = a.service.service_depend; dep != NULL; dep = dep->next) { if (strcmp(pp->promiser, dep->item) == 0) { CfOut(OUTPUT_LEVEL_ERROR, "", "!! Service promiser \"%s\" has itself as dependency", pp->promiser); PromiseRef(OUTPUT_LEVEL_ERROR, pp); return false; } } if (a.service.service_type == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "", "!! Service type for service \"%s\" is not known", pp->promiser); PromiseRef(OUTPUT_LEVEL_ERROR, pp); return false; } #ifdef __MINGW32__ if (strcmp(a.service.service_type, "windows") != 0) { CfOut(OUTPUT_LEVEL_ERROR, "", "!! Service type for promiser \"%s\" must be \"windows\" on this system, but is \"%s\"", pp->promiser, a.service.service_type); PromiseRef(OUTPUT_LEVEL_ERROR, pp); return false; } #endif /* __MINGW32__ */ return true; }
static bool DistributeClass(EvalContext *ctx, const Rlist *dist, const Promise *pp) { int total = 0; const Rlist *rp; for (rp = dist; rp != NULL; rp = rp->next) { int result = IntFromString(RlistScalarValue(rp)); if (result < 0) { Log(LOG_LEVEL_ERR, "Negative integer in class distribution"); PromiseRef(LOG_LEVEL_ERR, pp); return false; } total += result; } if (total == 0) { Log(LOG_LEVEL_ERR, "An empty distribution was specified on RHS"); PromiseRef(LOG_LEVEL_ERR, pp); return false; } double fluct = drand48() * total; assert(0 <= fluct && fluct < total); for (rp = dist; rp != NULL; rp = rp->next) { fluct -= IntFromString(RlistScalarValue(rp)); if (fluct < 0) { break; } } assert(rp); char buffer[CF_MAXVARSIZE]; snprintf(buffer, CF_MAXVARSIZE, "%s_%s", pp->promiser, RlistScalarValue(rp)); if (strcmp(PromiseGetBundle(pp)->type, "common") == 0) { EvalContextClassPutSoft(ctx, buffer, CONTEXT_SCOPE_NAMESPACE, "source=promise"); } else { EvalContextClassPutSoft(ctx, buffer, CONTEXT_SCOPE_BUNDLE, "source=promise"); } return true; }
static bool SelectClass(EvalContext *ctx, const Rlist *list, const Promise *pp) { int count = 0; for (const Rlist *rp = list; rp != NULL; rp = rp->next) { count++; } if (count == 0) { Log(LOG_LEVEL_ERR, "No classes to select on RHS"); PromiseRef(LOG_LEVEL_ERR, pp); return false; } assert(list); char splay[CF_MAXVARSIZE]; snprintf(splay, CF_MAXVARSIZE, "%s+%s+%ju", VFQNAME, VIPADDRESS, (uintmax_t)getuid()); double hash = (double) StringHash(splay, 0, CF_HASHTABLESIZE); assert(hash < CF_HASHTABLESIZE); int n = (int) (count * hash / (double) CF_HASHTABLESIZE); assert(n < count); while (n > 0 && list->next != NULL) { n--; list = list->next; } EvalContextClassPutSoft(ctx, RlistScalarValue(list), CONTEXT_SCOPE_NAMESPACE, "source=promise"); return true; }
int CheckPosixLinuxACL(char *file_path, Acl acl, Attributes a, Promise *pp) { cfPS(OUTPUT_LEVEL_ERROR, CF_FAIL, "", pp, a, "!! Posix ACLs are not supported on this Linux system - install the Posix acl library"); PromiseRef(OUTPUT_LEVEL_ERROR, pp); return true; }
PromiseResult CheckPosixLinuxACL(EvalContext *ctx, ARG_UNUSED const char *file_path, ARG_UNUSED Acl acl, Attributes a, const Promise *pp) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Posix ACLs are not supported on this Linux system - install the Posix acl library"); PromiseRef(LOG_LEVEL_ERR, pp); return PROMISE_RESULT_FAIL; }
static int SelectBSDMatch(struct stat *lstatptr,struct Rlist *bsdflags,struct Promise *pp) { #if defined HAVE_CHFLAGS u_long newflags,plus,minus; struct Rlist *rp; if (!ParseFlagString(bsdflags,&plus,&minus)) { CfOut(cf_error,""," !! Problem validating a BSD flag string"); PromiseRef(cf_error,pp); } newflags = (lstatptr->st_flags & CHFLAGS_MASK) ; newflags |= plus; newflags &= ~minus; if ((newflags & CHFLAGS_MASK) == (lstatptr->st_flags & CHFLAGS_MASK)) /* file okay */ { return true; } #endif return false; }
static int ValidateRegistryPromiser(char *key, Attributes a, Promise *pp) { static char *valid[] = { "HKEY_CLASSES_ROOT", "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_LOCAL_MACHINE", "HKEY_USERS", NULL }; char root_key[CF_MAXVARSIZE]; char *sp; int i; /* First remove the root key */ strncpy(root_key, key, CF_MAXVARSIZE - 1); sp = strchr(root_key, '\\'); *sp = '\0'; for (i = 0; valid[i] != NULL; i++) { if (strcmp(root_key, valid[i]) == 0) { return true; } } CfOut(cf_error, "", "Non-editable registry prefix \"%s\"", root_key); PromiseRef(cf_error, pp); return false; }
static int CheckPermTypeSyntax(char *permt, int deny_support, Promise *pp) /* Checks if the given string corresponds to the perm_type syntax. Only "allow" or "deny", followed by NULL-termination are valid. In addition, "deny" is only valid for ACL types supporting it. */ { int valid; valid = false; if (strcmp(permt, "allow") == 0) { valid = true; } else if (strcmp(permt, "deny") == 0) { if (deny_support) { valid = true; } else { CfOut(cf_error, "", "Deny permission not supported by this ACL type"); PromiseRef(cf_error, pp); } } return valid; }
static int ProcessSanityChecks(Attributes a, Promise *pp) { int promised_zero, ret = true; promised_zero = ((a.process_count.min_range == 0) && (a.process_count.max_range == 0)); if (a.restart_class) { if ((RlistIsStringIn(a.signals, "term")) || (RlistIsStringIn(a.signals, "kill"))) { Log(LOG_LEVEL_WARNING, "Promise '%s' kills then restarts - never strictly converges", pp->promiser); PromiseRef(LOG_LEVEL_INFO, pp); } if (a.haveprocess_count) { Log(LOG_LEVEL_ERR, "process_count and restart_class should not be used in the same promise as this makes no sense"); PromiseRef(LOG_LEVEL_INFO, pp); ret = false; } } if (promised_zero && (a.restart_class)) { Log(LOG_LEVEL_ERR, "Promise constraint conflicts - '%s' processes cannot have zero count if restarted", pp->promiser); PromiseRef(LOG_LEVEL_ERR, pp); ret = false; } if ((a.haveselect) && (!a.process_select.process_result)) { Log(LOG_LEVEL_ERR, "Process select constraint body promised no result (check body definition)"); PromiseRef(LOG_LEVEL_ERR, pp); return false; } return ret; }
static int ProcessSanityChecks(Attributes a, Promise *pp) { int promised_zero, ret = true; promised_zero = (a.process_count.min_range == 0 && a.process_count.max_range == 0); if (a.restart_class) { if (IsStringIn(a.signals, "term") || IsStringIn(a.signals, "kill")) { CfOut(cf_inform, "", " -> (warning) Promise %s kills then restarts - never strictly converges", pp->promiser); PromiseRef(cf_inform, pp); } if (a.haveprocess_count) { CfOut(cf_error, "", " !! process_count and restart_class should not be used in the same promise as this makes no sense"); PromiseRef(cf_inform, pp); ret = false; } } if (promised_zero && a.restart_class) { CfOut(cf_error, "", "Promise constraint conflicts - %s processes cannot have zero count if restarted", pp->promiser); PromiseRef(cf_error, pp); ret = false; } if (a.haveselect && !a.process_select.process_result) { CfOut(cf_error, "", " !! Process select constraint body promised no result (check body definition)"); PromiseRef(cf_error, pp); return false; } return ret; }
int CheckPosixLinuxACL(char *file_path, Acl acl, Attributes a, Promise *pp) { if (!CheckPosixLinuxAccessACEs(acl.acl_entries, acl.acl_method, file_path, a, pp)) { cfPS(OUTPUT_LEVEL_ERROR, CF_FAIL, "", pp, a, " !! Failed checking access ACL on %s", file_path); PromiseRef(OUTPUT_LEVEL_ERROR, pp); return false; } if (IsDir(file_path)) { if (!CheckPosixLinuxInheritACEs (acl.acl_inherit_entries, acl.acl_method, acl.acl_directory_inherit, file_path, a, pp)) { cfPS(OUTPUT_LEVEL_ERROR, CF_FAIL, "", pp, a, " !! Failed checking inheritance ACL on %s", file_path); PromiseRef(OUTPUT_LEVEL_ERROR, pp); return false; } } return true; }
static int EnvironmentsSanityChecks(Attributes a, const Promise *pp) { if (a.env.spec) { if (a.env.cpus != CF_NOINT || a.env.memory != CF_NOINT || a.env.disk != CF_NOINT) { Log(LOG_LEVEL_ERR, "Conflicting promise of both a spec and cpu/memory/disk resources"); return false; } } if (a.env.host == NULL) { Log(LOG_LEVEL_ERR, "No environment_host defined for environment promise"); PromiseRef(LOG_LEVEL_ERR, pp); return false; } switch (Str2Hypervisors(a.env.type)) { case cfv_virt_xen_net: case cfv_virt_kvm_net: case cfv_virt_esx_net: case cfv_virt_test_net: if (a.env.cpus != CF_NOINT || a.env.memory != CF_NOINT || a.env.disk != CF_NOINT || a.env.name || a.env.addresses) { Log(LOG_LEVEL_ERR, "Network environment promises computational resources (%d,%d,%d,%s)", a.env.cpus, a.env.memory, a.env.disk, a.env.name); PromiseRef(LOG_LEVEL_ERR, pp); } break; default: break; } return true; }
PromiseResult CheckPosixLinuxACL(EvalContext *ctx, const char *file_path, Acl acl, Attributes a, const Promise *pp) { PromiseResult result = PROMISE_RESULT_NOOP; if (!CheckPosixLinuxAccessACEs(ctx, acl.acl_entries, acl.acl_method, file_path, a, pp, &result)) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Failed checking access ACL on %s", file_path); PromiseRef(LOG_LEVEL_ERR, pp); return PROMISE_RESULT_FAIL; } if (IsDir(file_path)) { if (!CheckPosixLinuxDefaultACEs(ctx, acl.acl_default_entries, acl.acl_method, acl.acl_default, file_path, a, pp, &result)) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Failed checking default ACL on '%s'", file_path); PromiseRef(LOG_LEVEL_ERR, pp); return PROMISE_RESULT_FAIL; } } return PROMISE_RESULT_NOOP; }
void VerifyACL(char *file, Attributes a, Promise *pp) { if (!CheckACLSyntax(file, a.acl, pp)) { cfPS(cf_error, CF_INTERPT, "", pp, a, " !! Syntax error in access control list for \"%s\"", file); PromiseRef(cf_error, pp); return; } SetACLDefaults(file, &a.acl); // decide which ACL API to use switch (a.acl.acl_type) { case cfacl_notype: // fallthrough: acl_type defaults to generic case cfacl_generic: #if defined(__linux__) CheckPosixLinuxACL(file, a.acl, a, pp); #elif defined(__MINGW32__) Nova_CheckNtACL(file, a.acl, a, pp); #else CfOut(cf_inform, "", "!! ACLs are not yet supported on this system."); #endif break; case cfacl_posix: #if defined(__linux__) CheckPosixLinuxACL(file, a.acl, a, pp); #else CfOut(cf_inform, "", "!! Posix ACLs are not supported on this system"); #endif break; case cfacl_ntfs: #if defined(__MINGW32__) Nova_CheckNtACL(file, a.acl, a, pp); #else CfOut(cf_inform, "", "!! NTFS ACLs are not supported on this system"); #endif break; default: CfOut(cf_error, "", "!! Unknown ACL type - software error"); break; } }
void VerifyACL(EvalContext *ctx, char *file, Attributes a, Promise *pp) { if (!CheckACLSyntax(file, a.acl, pp)) { cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_INTERRUPTED, "", pp, a, " !! Syntax error in access control list for \"%s\"", file); PromiseRef(OUTPUT_LEVEL_ERROR, pp); return; } SetACLDefaults(file, &a.acl); // decide which ACL API to use switch (a.acl.acl_type) { case ACL_TYPE_NONE: // fallthrough: acl_type defaults to generic case ACL_TYPE_GENERIC: #if defined(__linux__) CheckPosixLinuxACL(ctx, file, a.acl, a, pp); #elif defined(__MINGW32__) Nova_CheckNtACL(ctx, file, a.acl, a, pp); #else CfOut(OUTPUT_LEVEL_INFORM, "", "!! ACLs are not yet supported on this system."); #endif break; case ACL_TYPE_POSIX: #if defined(__linux__) CheckPosixLinuxACL(ctx, file, a.acl, a, pp); #else CfOut(OUTPUT_LEVEL_INFORM, "", "!! Posix ACLs are not supported on this system"); #endif break; case ACL_TYPE_NTFS_: #if defined(__MINGW32__) Nova_CheckNtACL(ctx, file, a.acl, a, pp); #else CfOut(OUTPUT_LEVEL_INFORM, "", "!! NTFS ACLs are not supported on this system"); #endif break; default: CfOut(OUTPUT_LEVEL_ERROR, "", "!! Unknown ACL type - software error"); break; } }
static Rlist *NewExpArgs(EvalContext *ctx, const Policy *policy, const FnCall *fp) { { const FnCallType *fn = FnCallTypeGet(fp->name); int len = RlistLen(fp->args); if (!(fn->options & FNCALL_OPTION_VARARG)) { if (len != FnNumArgs(fn)) { Log(LOG_LEVEL_ERR, "Arguments to function '%s' do not tally. Expected %d not %d", fp->name, FnNumArgs(fn), len); PromiseRef(LOG_LEVEL_ERR, fp->caller); exit(EXIT_FAILURE); } } } Rlist *expanded_args = NULL; for (const Rlist *rp = fp->args; rp != NULL; rp = rp->next) { Rval rval; switch (rp->val.type) { case RVAL_TYPE_FNCALL: { FnCall *subfp = RlistFnCallValue(rp); rval = FnCallEvaluate(ctx, policy, subfp, fp->caller).rval; assert(rval.item); } break; default: rval = ExpandPrivateRval(ctx, NULL, NULL, rp->val.item, rp->val.type); assert(rval.item); break; } RlistAppend(&expanded_args, rval.item, rval.type); RvalDestroy(rval); } return expanded_args; }
static void VerifyOccurrenceGroup(char *file, Promise *pp) { Attributes a = { {0} }; struct stat sb; char *sp, url[CF_BUFSIZE]; Rval retval; a = GetOccurrenceAttributes(pp); if (cfstat(file, &sb) == -1) { CfOut(cf_verbose, "", " !! File %s matched but could not be read", file); return; } if (a.path_root == NULL || a.web_root == NULL) { CfOut(cf_error, "", " !! No pathroot/webroot defined in representation"); PromiseRef(cf_error, pp); return; } Chop(a.path_root); DeleteSlash(a.path_root); sp = file + strlen(a.path_root) + 1; FullTextMatch(pp->promiser, sp); retval = ExpandPrivateRval("this", (Rval) {a.represents, CF_LIST}); DeleteScope("match"); if (strlen(a.web_root) > 0) { snprintf(url, CF_BUFSIZE - 1, "%s/%s", a.web_root, sp); } else { snprintf(url, CF_BUFSIZE - 1, "%s", sp); } AddOccurrence(&OCCURRENCES, url, retval.item, cfk_url, pp->classes); CfOut(cf_verbose, "", " -> File %s matched and being logged at %s", file, url); DeleteRlist((Rlist *) retval.item); }
PromiseResult VerifyAbsoluteLink(EvalContext *ctx, char *destination, const char *source, Attributes attr, const Promise *pp) { char absto[CF_BUFSIZE]; char expand[CF_BUFSIZE]; char linkto[CF_BUFSIZE]; if (*source == '.') { strcpy(linkto, destination); ChopLastNode(linkto); AddSlash(linkto); strcat(linkto, source); } else { strcpy(linkto, source); } CompressPath(absto, linkto); expand[0] = '\0'; if (attr.link.when_no_file == cfa_force) { if (!ExpandLinks(expand, absto, 0)) /* begin at level 1 and beam out at 15 */ { Log(LOG_LEVEL_ERR, "Failed to make absolute link in"); PromiseRef(LOG_LEVEL_ERR, pp); return PROMISE_RESULT_FAIL; } else { Log(LOG_LEVEL_DEBUG, "ExpandLinks returned '%s'", expand); } } else { strcpy(expand, absto); } CompressPath(linkto, expand); return VerifyLink(ctx, destination, linkto, attr, pp); }
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; }
static Rlist *NewExpArgs(EvalContext *ctx, const FnCall *fp) { int len; Rval rval; Rlist *newargs = NULL; FnCall *subfp; const FnCallType *fn = FnCallTypeGet(fp->name); len = RlistLen(fp->args); if (!(fn->options & FNCALL_OPTION_VARARG)) { if (len != FnNumArgs(fn)) { Log(LOG_LEVEL_ERR, "Arguments to function '%s' do not tally. Expected %d not %d", fp->name, FnNumArgs(fn), len); PromiseRef(LOG_LEVEL_ERR, fp->caller); exit(1); } } for (const Rlist *rp = fp->args; rp != NULL; rp = rp->next) { switch (rp->val.type) { case RVAL_TYPE_FNCALL: subfp = RlistFnCallValue(rp); rval = FnCallEvaluate(ctx, subfp, fp->caller).rval; assert(rval.item); break; default: rval = ExpandPrivateRval(ctx, NULL, NULL, (Rval) { rp->val.item, rp->val.type}); assert(rval.item); break; } RlistAppendRval(&newargs, rval); } return newargs; }
Rlist *NewExpArgs(const FnCall *fp, const Promise *pp) { int len; Rval rval; Rlist *newargs = NULL; FnCall *subfp; const FnCallType *fn = FindFunction(fp->name); len = RlistLen(fp->args); if (!fn->varargs) { if (len != FnNumArgs(fn)) { CfOut(cf_error, "", "Arguments to function %s(.) do not tally. Expect %d not %d", fp->name, FnNumArgs(fn), len); PromiseRef(cf_error, pp); exit(1); } } for (const Rlist *rp = fp->args; rp != NULL; rp = rp->next) { switch (rp->type) { case CF_FNCALL: subfp = (FnCall *) rp->item; rval = EvaluateFunctionCall(subfp, pp).rval; break; default: rval = ExpandPrivateRval(CONTEXTID, (Rval) {rp->item, rp->type}); break; } CfDebug("EXPARG: %s.%s\n", CONTEXTID, (char *) rval.item); AppendRlist(&newargs, rval.item, rval.rtype); DeleteRvalItem(rval); } return newargs; }
gid_t Str2Gid(const char *gidbuff, char *groupcopy, const Promise *pp) { struct group *gr; int gid = -2, tmp = -2; if (StringIsNumeric(gidbuff)) { sscanf(gidbuff, "%d", &tmp); gid = (gid_t) tmp; } else { if (strcmp(gidbuff, "*") == 0) { gid = CF_SAME_GROUP; /* signals wildcard */ } else if ((gr = getgrnam(gidbuff)) == NULL) { Log(LOG_LEVEL_INFO, "Unknown group '%s' in promise", gidbuff); if (pp) { PromiseRef(LOG_LEVEL_INFO, pp); } gid = CF_UNKNOWN_GROUP; } else { gid = gr->gr_gid; if (groupcopy != NULL) { strcpy(groupcopy, gidbuff); } } } return gid; }
static int CheckAclDefault(char *path, Acl *acl, Promise *pp) /* Checks that acl_default is set to a valid value for this acl type. Returns true if so, or false otherwise. */ { int valid = false; switch (acl->acl_default) { case ACL_DEFAULT_NONE: // unset is always valid valid = true; break; case ACL_DEFAULT_SPECIFY: // NOTE: we assume all acls support specify // fallthrough case ACL_DEFAULT_ACCESS: // fallthrough default: if (IsDir(path)) { valid = true; } else { Log(LOG_LEVEL_ERR, "acl_default can only be set on directories."); PromiseRef(LOG_LEVEL_ERR, pp); valid = false; } break; } return valid; }
static bool SyntaxCheckExec(Attributes a, Promise *pp) { if ((a.contain.nooutput) && (a.contain.preview)) { Log(LOG_LEVEL_ERR, "no_output and preview are mutually exclusive (broken promise)"); PromiseRef(LOG_LEVEL_ERR, pp); return false; } #ifdef __MINGW32__ if (a.contain.umask != (mode_t)CF_UNDEFINED) { Log(LOG_LEVEL_VERBOSE, "contain.umask is ignored on Windows"); } if (a.contain.owner != CF_UNDEFINED) { Log(LOG_LEVEL_VERBOSE, "contain.exec_owner is ignored on Windows"); } if (a.contain.group != CF_UNDEFINED) { Log(LOG_LEVEL_VERBOSE, "contain.exec_group is ignored on Windows"); } if (a.contain.chroot != NULL) { Log(LOG_LEVEL_VERBOSE, "contain.chroot is ignored on Windows"); } #else /* !__MINGW32__ */ if (a.contain.umask == (mode_t)CF_UNDEFINED) { a.contain.umask = 077; } #endif /* !__MINGW32__ */ return true; }
static int CheckDirectoryInherit(char *path, Acl *acl, Promise *pp) /* Checks that acl_directory_inherit is set to a valid value for this acl type. Returns true if so, or false otherwise. */ { int valid = false; switch (acl->acl_directory_inherit) { case cfacl_noinherit: // unset is always valid valid = true; break; case cfacl_specify: // NOTE: we assume all acls support specify // fallthrough case cfacl_parent: // fallthrough default: if (IsDir(path)) { valid = true; } else { CfOut(cf_error, "", "acl_directory_inherit can only be set on directories."); PromiseRef(cf_error, pp); valid = false; } break; } return valid; }
static int ExecSanityChecks(Attributes a, Promise *pp) { if (a.contain.nooutput && a.contain.preview) { CfOut(cf_error, "", "no_output and preview are mutually exclusive (broken promise)"); PromiseRef(cf_error, pp); return false; } #ifdef MINGW if (a.contain.umask != CF_UNDEFINED) // TODO: Always true (077 != -1?, compare positive and negative number), make false when umask not set { CfOut(cf_verbose, "", "contain.umask is ignored on Windows"); } if (a.contain.owner != CF_UNDEFINED) { CfOut(cf_verbose, "", "contain.exec_owner is ignored on Windows"); } if (a.contain.group != CF_UNDEFINED) { CfOut(cf_verbose, "", "contain.exec_group is ignored on Windows"); } if (a.contain.chroot != NULL) { CfOut(cf_verbose, "", "contain.chroot is ignored on Windows"); } #else /* NOT MINGW */ if (a.contain.umask == CF_UNDEFINED) { a.contain.umask = 077; } #endif /* NOT MINGW */ return true; }