void StringSetAddSplit(StringSet *set, const char *str, char delimiter) { assert(set != NULL); if (str) // TODO: remove this inconsistency, add assert(str) { const char *prev = str; const char *cur = str; while (*cur != '\0') { if (*cur == delimiter) { size_t len = cur - prev; if (len > 0) { StringSetAdd(set, xstrndup(prev, len)); } else { StringSetAdd(set, xstrdup("")); } prev = cur + 1; } cur++; } if (cur > prev) { StringSetAdd(set, xstrndup(prev, cur - prev)); } } }
static int SelectOwnerMatch(EvalContext *ctx, char *path, struct stat *lstatptr, Rlist *crit) { Rlist *rp; char ownerName[CF_BUFSIZE]; int gotOwner; StringSet *leafattrib = StringSetNew(); #ifndef __MINGW32__ // no uids on Windows char buffer[CF_SMALLBUF]; snprintf(buffer, CF_SMALLBUF, "%jd", (uintmax_t) lstatptr->st_uid); StringSetAdd(leafattrib, xstrdup(buffer)); #endif /* __MINGW32__ */ gotOwner = GetOwnerName(path, lstatptr, ownerName, sizeof(ownerName)); if (gotOwner) { StringSetAdd(leafattrib, xstrdup(ownerName)); } else { StringSetAdd(leafattrib, xstrdup("none")); } for (rp = crit; rp != NULL; rp = rp->next) { if (EvalFileResult((char *) rp->item, leafattrib)) { Log(LOG_LEVEL_DEBUG, "Select owner match"); StringSetDestroy(leafattrib); return true; } if (gotOwner && (FullTextMatch(ctx, RlistScalarValue(rp), ownerName))) { Log(LOG_LEVEL_DEBUG, "Select owner match"); StringSetDestroy(leafattrib); return true; } #ifndef __MINGW32__ if (FullTextMatch(ctx, RlistScalarValue(rp), buffer)) { Log(LOG_LEVEL_DEBUG, "Select owner match"); StringSetDestroy(leafattrib); return true; } #endif /* !__MINGW32__ */ } StringSetDestroy(leafattrib); return false; }
static void TransformGidsToGroups(StringSet **list) { StringSet *new_list = StringSetNew(); StringSetIterator i = StringSetIteratorInit(*list); const char *data; for (data = StringSetIteratorNext(&i); data; data = StringSetIteratorNext(&i)) { if (strlen(data) != strspn(data, "0123456789")) { // Cannot possibly be a gid. StringSetAdd(new_list, xstrdup(data)); continue; } // In groups vs gids, groups take precedence. So check if it exists. struct group *group_info = GetGrEntry(data, &EqualGroupName); if (!group_info) { if (errno == 0) { group_info = GetGrEntry(data, &EqualGid); if (!group_info) { if (errno != 0) { Log(LOG_LEVEL_ERR, "Error while checking group name '%s': %s", data, GetErrorStr()); StringSetDestroy(new_list); return; } // Neither group nor gid is found. This will lead to an error later, but we don't // handle that here. } else { // Replace gid with group name. StringSetAdd(new_list, xstrdup(group_info->gr_name)); } } else { Log(LOG_LEVEL_ERR, "Error while checking group name '%s': '%s'", data, GetErrorStr()); StringSetDestroy(new_list); return; } } else { StringSetAdd(new_list, xstrdup(data)); } } StringSet *old_list = *list; *list = new_list; StringSetDestroy(old_list); }
static Policy *LoadPolicyFile(EvalContext *ctx, GenericAgentConfig *config, const char *policy_file, StringSet *parsed_files, StringSet *failed_files) { Policy *policy = Cf3ParseFile(config, policy_file); StringSetAdd(parsed_files, xstrdup(policy_file)); if (!policy) { StringSetAdd(failed_files, xstrdup(policy_file)); return NULL; } PolicyResolve(ctx, policy, config); Body *body_common_control = PolicyGetBody(policy, NULL, "common", "control"); Body *body_file_control = PolicyGetBody(policy, NULL, "file", "control"); if (body_common_control) { Seq *potential_inputs = BodyGetConstraint(body_common_control, "inputs"); Constraint *cp = EffectiveConstraint(ctx, potential_inputs); SeqDestroy(potential_inputs); if (cp) { Policy *aux_policy = LoadPolicyInputFiles(ctx, config, RvalRlistValue(cp->rval), parsed_files, failed_files); if (aux_policy) { policy = PolicyMerge(policy, aux_policy); } } } PolicyResolve(ctx, policy, config); if (body_file_control) { Seq *potential_inputs = BodyGetConstraint(body_file_control, "inputs"); Constraint *cp = EffectiveConstraint(ctx, potential_inputs); SeqDestroy(potential_inputs); if (cp) { Policy *aux_policy = LoadPolicyInputFiles(ctx, config, RvalRlistValue(cp->rval), parsed_files, failed_files); if (aux_policy) { policy = PolicyMerge(policy, aux_policy); } } } return policy; }
/** * @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")); } }
static bool GroupGetUserMembership (const char *user, StringSet *result) { bool ret = true; struct group *group_info; setgrent(); while (true) { errno = 0; group_info = getgrent(); if (!group_info) { if (errno) { Log(LOG_LEVEL_ERR, "Error while getting group list. (getgrent: '%s')", GetErrorStr()); ret = false; } break; } for (int i = 0; group_info->gr_mem[i] != NULL; i++) { if (strcmp(user, group_info->gr_mem[i]) == 0) { StringSetAdd(result, xstrdup(group_info->gr_name)); break; } } } endgrent(); return ret; }
void EvalContextStackFrameAddNegated(EvalContext *ctx, const char *context) { StackFrame *frame = LastStackFrameBundle(ctx); assert(frame); StringSetAdd(frame->data.bundle.contexts_negated, xstrdup(context)); }
static int SelectGroupMatch(EvalContext *ctx, struct stat *lstatptr, Rlist *crit) { char buffer[CF_SMALLBUF]; struct group *gr; Rlist *rp; StringSet *leafattrib = StringSetNew(); snprintf(buffer, CF_SMALLBUF, "%jd", (uintmax_t) lstatptr->st_gid); StringSetAdd(leafattrib, xstrdup(buffer)); if ((gr = getgrgid(lstatptr->st_gid)) != NULL) { StringSetAdd(leafattrib, xstrdup(gr->gr_name)); } else { StringSetAdd(leafattrib, xstrdup("none")); } for (rp = crit; rp != NULL; rp = rp->next) { if (EvalFileResult((char *) rp->item, leafattrib)) { Log(LOG_LEVEL_DEBUG, "Select group match"); StringSetDestroy(leafattrib); return true; } if (gr && (FullTextMatch(ctx, (char *) rp->item, gr->gr_name))) { Log(LOG_LEVEL_DEBUG, "Select group match"); StringSetDestroy(leafattrib); return true; } if (FullTextMatch(ctx, (char *) rp->item, buffer)) { Log(LOG_LEVEL_DEBUG, "Select group match"); StringSetDestroy(leafattrib); return true; } } StringSetDestroy(leafattrib); return false; }
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; } } } }
StringSet *StringSetAddAllMatchingIterator(StringSet* base, StringSetIterator it, const char *filter_regex) { const char *element = NULL; while ((element = SetIteratorNext(&it))) { if (StringMatch(filter_regex, element)) { StringSetAdd(base, xstrdup(element)); } } return base; }
void MarkPromiseHandleDone(EvalContext *ctx, const Promise *pp) { char name[CF_BUFSIZE]; const char *handle = PromiseGetHandle(pp); if (handle == NULL) { return; } snprintf(name, CF_BUFSIZE, "%s:%s", PromiseGetNamespace(pp), handle); StringSetAdd(ctx->dependency_handles, xstrdup(name)); }
static bool GroupGetUserMembership (const char *user, StringSet *result) { bool ret = true; struct group *group_info; FILE *fptr = fopen("/etc/group", "r"); if (!fptr) { Log(LOG_LEVEL_ERR, "Could not open '/etc/group': %s", GetErrorStr()); return false; } while (true) { errno = 0; // Use fgetgrent() instead of getgrent(), to guarantee that the // returned group is a local group, and not for example from LDAP. group_info = fgetgrent(fptr); if (!group_info) { // Documentation among Unices is conflicting on return codes. When there // are no more entries, this happens: // Linux = ENOENT // AIX = ESRCH if (errno && errno != ENOENT && errno != ESRCH) { Log(LOG_LEVEL_ERR, "Error while getting group list. (fgetgrent: '%s')", GetErrorStr()); ret = false; } break; } for (int i = 0; group_info->gr_mem[i] != NULL; i++) { if (strcmp(user, group_info->gr_mem[i]) == 0) { StringSetAdd(result, xstrdup(group_info->gr_name)); break; } } } fclose(fptr); return ret; }
StringSet *StringSetFromString(const char *str, char delimiter) { StringSet *set = StringSetNew(); char delimiters[2] = { 0 }; delimiters[0] = delimiter; char *copy = xstrdup(str); char *curr = NULL; while ((curr = strsep(©, delimiters))) { StringSetAdd(set, xstrdup(curr)); } free(copy); return set; }
void MarkPromiseHandleDone(EvalContext *ctx, const Promise *pp) { if (pp == NULL) { return; } char name[CF_BUFSIZE]; char *handle = ConstraintGetRvalValue(ctx, "handle", pp, RVAL_TYPE_SCALAR); if (handle == NULL) { return; } snprintf(name, CF_BUFSIZE, "%s:%s", PromiseGetNamespace(pp), handle); StringSetAdd(ctx->dependency_handles, xstrdup(name)); }
int SelectLeaf(EvalContext *ctx, char *path, struct stat *sb, FileSelect fs) { int result = true; Rlist *rp; StringSet *leaf_attr = StringSetNew(); #ifdef __MINGW32__ if (fs.issymlinkto != NULL) { Log(LOG_LEVEL_VERBOSE, "files_select.issymlinkto is ignored on Windows (symbolic links are not supported by Windows)"); } if (fs.groups != NULL) { Log(LOG_LEVEL_VERBOSE, "files_select.search_groups is ignored on Windows (file groups are not supported by Windows)"); } if (fs.bsdflags != NULL) { Log(LOG_LEVEL_VERBOSE, "files_select.search_bsdflags is ignored on Windows"); } #endif /* __MINGW32__ */ if (fs.name == NULL) { StringSetAdd(leaf_attr, xstrdup("leaf_name")); } for (rp = fs.name; rp != NULL; rp = rp->next) { if (SelectNameRegexMatch(ctx, path, rp->item)) { StringSetAdd(leaf_attr, xstrdup("leaf_name")); break; } } if (fs.path == NULL) { StringSetAdd(leaf_attr, xstrdup("leaf_path")); } for (rp = fs.path; rp != NULL; rp = rp->next) { if (SelectPathRegexMatch(ctx, path, rp->item)) { StringSetAdd(leaf_attr, xstrdup("path_name")); break; } } if (SelectTypeMatch(sb, fs.filetypes)) { StringSetAdd(leaf_attr, xstrdup("file_types")); } if ((fs.owners) && (SelectOwnerMatch(ctx, path, sb, fs.owners))) { StringSetAdd(leaf_attr, xstrdup("owner")); } if (fs.owners == NULL) { StringSetAdd(leaf_attr, xstrdup("owner")); } #ifdef __MINGW32__ StringSetAdd(leaf_attr, xstrdup("group")); #else /* !__MINGW32__ */ if ((fs.groups) && (SelectGroupMatch(ctx, sb, fs.groups))) { StringSetAdd(leaf_attr, xstrdup("group")); } if (fs.groups == NULL) { StringSetAdd(leaf_attr, xstrdup("group")); } #endif /* !__MINGW32__ */ if (SelectModeMatch(sb, fs.perms)) { StringSetAdd(leaf_attr, xstrdup("mode")); } #if defined HAVE_CHFLAGS if (SelectBSDMatch(sb, fs.bsdflags)) { StringSetAdd(leaf_attr, xstrdup("bsdflags")); } #endif if (SelectTimeMatch(sb->st_atime, fs.min_atime, fs.max_atime)) { StringSetAdd(leaf_attr, xstrdup("atime")); } if (SelectTimeMatch(sb->st_ctime, fs.min_ctime, fs.max_ctime)) { StringSetAdd(leaf_attr, xstrdup("ctime")); } if (SelectSizeMatch(sb->st_size, fs.min_size, fs.max_size)) { StringSetAdd(leaf_attr, xstrdup("size")); } if (SelectTimeMatch(sb->st_mtime, fs.min_mtime, fs.max_mtime)) { StringSetAdd(leaf_attr, xstrdup("mtime")); } if ((fs.issymlinkto) && (SelectIsSymLinkTo(ctx, path, fs.issymlinkto))) { StringSetAdd(leaf_attr, xstrdup("issymlinkto")); } if ((fs.exec_regex) && (SelectExecRegexMatch(ctx, path, fs.exec_regex, fs.exec_program))) { StringSetAdd(leaf_attr, xstrdup("exec_regex")); } if ((fs.exec_program) && (SelectExecProgram(path, fs.exec_program))) { StringSetAdd(leaf_attr, xstrdup("exec_program")); } result = EvalFileResult(fs.result, leaf_attr); Log(LOG_LEVEL_DEBUG, "Select result '%s' on '%s' was %d", fs.result, path, result); StringSetDestroy(leaf_attr); return result; }
PromiseResult VerifyVarPromise(EvalContext *ctx, const Promise *pp, bool allow_duplicates) { ConvergeVariableOptions opts = CollectConvergeVariableOptions(ctx, pp, allow_duplicates); if (!opts.should_converge) { return PROMISE_RESULT_NOOP; } Attributes a = { {0} }; // More consideration needs to be given to using these //a.transaction = GetTransactionConstraints(pp); a.classes = GetClassDefinitionConstraints(ctx, pp); VarRef *ref = VarRefParseFromBundle(pp->promiser, PromiseGetBundle(pp)); if (strcmp("meta", pp->parent_promise_type->name) == 0) { VarRefSetMeta(ref, true); } DataType existing_value_type = CF_DATA_TYPE_NONE; const void *const existing_value = IsExpandable(pp->promiser) ? NULL : EvalContextVariableGet(ctx, ref, &existing_value_type); PromiseResult result = PROMISE_RESULT_NOOP; Rval rval = opts.cp_save->rval; if (rval.item != NULL) { DataType data_type = DataTypeFromString(opts.cp_save->lval); if (opts.cp_save->rval.type == RVAL_TYPE_FNCALL) { FnCall *fp = RvalFnCallValue(rval); const FnCallType *fn = FnCallTypeGet(fp->name); if (!fn) { assert(false && "Canary: should have been caught before this point"); FatalError(ctx, "While setting variable '%s' in bundle '%s', unknown function '%s'", pp->promiser, PromiseGetBundle(pp)->name, fp->name); } if (fn->dtype != DataTypeFromString(opts.cp_save->lval)) { FatalError(ctx, "While setting variable '%s' in bundle '%s', variable declared type '%s' but function '%s' returns type '%s'", pp->promiser, PromiseGetBundle(pp)->name, opts.cp_save->lval, fp->name, DataTypeToString(fn->dtype)); } if (existing_value_type != CF_DATA_TYPE_NONE) { // Already did this VarRefDestroy(ref); return PROMISE_RESULT_NOOP; } FnCallResult res = FnCallEvaluate(ctx, PromiseGetPolicy(pp), fp, pp); if (res.status == FNCALL_FAILURE) { /* We do not assign variables to failed fn calls */ RvalDestroy(res.rval); VarRefDestroy(ref); return PROMISE_RESULT_NOOP; } else { rval = res.rval; } } else { Buffer *conv = BufferNew(); bool malformed = false, misprint = false; if (strcmp(opts.cp_save->lval, "int") == 0) { long int asint = IntFromString(opts.cp_save->rval.item); if (asint == CF_NOINT) { malformed = true; } else if (0 > BufferPrintf(conv, "%ld", asint)) { misprint = true; } else { rval = RvalNew(BufferData(conv), opts.cp_save->rval.type); } } else if (strcmp(opts.cp_save->lval, "real") == 0) { double real_value; if (!DoubleFromString(opts.cp_save->rval.item, &real_value)) { malformed = true; } else if (0 > BufferPrintf(conv, "%lf", real_value)) { misprint = true; } else { rval = RvalNew(BufferData(conv), opts.cp_save->rval.type); } } else { rval = RvalCopy(opts.cp_save->rval); } BufferDestroy(conv); if (malformed) { /* Arises when opts->cp_save->rval.item isn't yet expanded. */ /* Has already been logged by *FromString */ VarRefDestroy(ref); return PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } else if (misprint) { /* Even though no problems with memory allocation can * get here, there might be other problems. */ UnexpectedError("Problems writing to buffer"); VarRefDestroy(ref); return PROMISE_RESULT_NOOP; } else if (rval.type == RVAL_TYPE_LIST) { Rlist *rval_list = RvalRlistValue(rval); RlistFlatten(ctx, &rval_list); rval.item = rval_list; } } if (Epimenides(ctx, PromiseGetBundle(pp)->ns, PromiseGetBundle(pp)->name, pp->promiser, rval, 0)) { Log(LOG_LEVEL_ERR, "Variable '%s' contains itself indirectly - an unkeepable promise", pp->promiser); exit(EXIT_FAILURE); } else { /* See if the variable needs recursively expanding again */ Rval returnval = EvaluateFinalRval(ctx, PromiseGetPolicy(pp), ref->ns, ref->scope, rval, true, pp); RvalDestroy(rval); // freed before function exit rval = returnval; } if (existing_value_type != CF_DATA_TYPE_NONE) { if (!opts.ok_redefine) /* only on second iteration, else we ignore broken promises */ { if (THIS_AGENT_TYPE == AGENT_TYPE_COMMON && !CompareRval(existing_value, DataTypeToRvalType(existing_value_type), rval.item, rval.type)) { switch (rval.type) { case RVAL_TYPE_SCALAR: Log(LOG_LEVEL_VERBOSE, "Redefinition of a constant scalar '%s', was '%s' now '%s'", pp->promiser, (const char *)existing_value, RvalScalarValue(rval)); PromiseRef(LOG_LEVEL_VERBOSE, pp); break; case RVAL_TYPE_LIST: { Log(LOG_LEVEL_VERBOSE, "Redefinition of a constant list '%s'", pp->promiser); Writer *w = StringWriter(); RlistWrite(w, existing_value); char *oldstr = StringWriterClose(w); Log(LOG_LEVEL_VERBOSE, "Old value '%s'", oldstr); free(oldstr); w = StringWriter(); RlistWrite(w, rval.item); char *newstr = StringWriterClose(w); Log(LOG_LEVEL_VERBOSE, " New value '%s'", newstr); free(newstr); PromiseRef(LOG_LEVEL_VERBOSE, pp); } break; case RVAL_TYPE_CONTAINER: case RVAL_TYPE_FNCALL: case RVAL_TYPE_NOPROMISEE: break; } } RvalDestroy(rval); VarRefDestroy(ref); return result; } } if (IsCf3VarString(pp->promiser)) { // Unexpanded variables, we don't do anything with RvalDestroy(rval); VarRefDestroy(ref); return result; } if (!IsValidVariableName(pp->promiser)) { Log(LOG_LEVEL_ERR, "Variable identifier contains illegal characters"); PromiseRef(LOG_LEVEL_ERR, pp); RvalDestroy(rval); VarRefDestroy(ref); return result; } if (rval.type == RVAL_TYPE_LIST) { if (opts.drop_undefined) { for (Rlist *rp = RvalRlistValue(rval); rp; rp = rp->next) { if (IsNakedVar(RlistScalarValue(rp), '@')) { free(rp->val.item); rp->val.item = xstrdup(CF_NULL_VALUE); } } } for (const Rlist *rp = RvalRlistValue(rval); rp; rp = rp->next) { switch (rp->val.type) { case RVAL_TYPE_SCALAR: break; default: // Cannot assign variable because value is a list containing a non-scalar item VarRefDestroy(ref); RvalDestroy(rval); return result; } } } if (ref->num_indices > 0) { if (data_type == CF_DATA_TYPE_CONTAINER) { char *lval_str = VarRefToString(ref, true); Log(LOG_LEVEL_ERR, "Cannot assign a container to an indexed variable name '%s'. Should be assigned to '%s' instead", lval_str, ref->lval); free(lval_str); VarRefDestroy(ref); RvalDestroy(rval); return result; } else { DataType existing_type = CF_DATA_TYPE_NONE; VarRef *base_ref = VarRefCopyIndexless(ref); if (EvalContextVariableGet(ctx, ref, &existing_type) && existing_type == CF_DATA_TYPE_CONTAINER) { char *lval_str = VarRefToString(ref, true); char *base_ref_str = VarRefToString(base_ref, true); Log(LOG_LEVEL_ERR, "Cannot assign value to indexed variable name '%s', because a container is already assigned to the base name '%s'", lval_str, base_ref_str); free(lval_str); free(base_ref_str); VarRefDestroy(base_ref); VarRefDestroy(ref); RvalDestroy(rval); return result; } VarRefDestroy(base_ref); } } DataType required_datatype = DataTypeFromString(opts.cp_save->lval); if (rval.type != DataTypeToRvalType(required_datatype)) { char *ref_str = VarRefToString(ref, true); char *value_str = RvalToString(rval); Log(LOG_LEVEL_ERR, "Variable '%s' expected a variable of type '%s', but was given incompatible value '%s'", ref_str, DataTypeToString(required_datatype), value_str); PromiseRef(LOG_LEVEL_ERR, pp); free(ref_str); free(value_str); VarRefDestroy(ref); RvalDestroy(rval); return PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } if (!EvalContextVariablePut(ctx, ref, rval.item, required_datatype, "source=promise")) { Log(LOG_LEVEL_VERBOSE, "Unable to converge %s.%s value (possibly empty or infinite regression)", ref->scope, pp->promiser); PromiseRef(LOG_LEVEL_VERBOSE, pp); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } else { Rlist *promise_meta = PromiseGetConstraintAsList(ctx, "meta", pp); if (promise_meta) { StringSet *class_meta = EvalContextVariableTags(ctx, ref); Buffer *print; for (const Rlist *rp = promise_meta; rp; rp = rp->next) { StringSetAdd(class_meta, xstrdup(RlistScalarValue(rp))); print = StringSetToBuffer(class_meta, ','); Log(LOG_LEVEL_DEBUG, "Added tag %s to class %s, tags now [%s]", RlistScalarValue(rp), pp->promiser, BufferData(print)); BufferDestroy(print); } } } } else { Log(LOG_LEVEL_ERR, "Variable %s has no promised value", pp->promiser); Log(LOG_LEVEL_ERR, "Rule from %s at/before line %llu", PromiseGetBundle(pp)->source_path, (unsigned long long)opts.cp_save->offset.line); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); } /* * FIXME: Variable promise are exempt from normal evaluation logic still, so * they are not pushed to evaluation stack before being evaluated. Due to * this reason, we cannot call cfPS here to set classes, as it will error * out with ProgrammingError. * * In order to support 'classes' body for variables as well, we call * ClassAuditLog explicitly. */ ClassAuditLog(ctx, pp, a, result); VarRefDestroy(ref); RvalDestroy(rval); return result; }
void EvalContextStackFrameAddSoft(EvalContext *ctx, const char *context) { assert(SeqLength(ctx->stack) > 0); StackFrameBundle frame; { StackFrame *last_frame = LastStackFrameBundle(ctx); if (!last_frame) { ProgrammingError("Attempted to add a soft class on the stack, but stack had no bundle frame"); } frame = last_frame->data.bundle; } char copy[CF_BUFSIZE]; if (strcmp(frame.owner->ns, "default") != 0) { snprintf(copy, CF_MAXVARSIZE, "%s:%s", frame.owner->ns, context); } else { strncpy(copy, context, CF_MAXVARSIZE); } if (Chop(copy, CF_EXPANDSIZE) == -1) { CfOut(OUTPUT_LEVEL_ERROR, "", "Chop was called on a string that seemed to have no terminator"); } if (strlen(copy) == 0) { return; } CfDebug("NewBundleClass(%s)\n", copy); if (IsRegexItemIn(ctx, ctx->heap_abort_current_bundle, copy)) { CfOut(OUTPUT_LEVEL_ERROR, "", "Bundle %s aborted on defined class \"%s\"\n", frame.owner->name, copy); ABORTBUNDLE = true; } if (IsRegexItemIn(ctx, ctx->heap_abort, copy)) { CfOut(OUTPUT_LEVEL_ERROR, "", "cf-agent aborted on defined class \"%s\" defined in bundle %s\n", copy, frame.owner->name); exit(1); } if (EvalContextHeapContainsSoft(ctx, copy)) { CfOut(OUTPUT_LEVEL_ERROR, "", "WARNING - private class \"%s\" in bundle \"%s\" shadows a global class - you should choose a different name to avoid conflicts", copy, frame.owner->name); } if (EvalContextStackFrameContainsSoft(ctx, copy)) { return; } StringSetAdd(frame.contexts, xstrdup(copy)); for (const Item *ip = ctx->heap_abort; ip != NULL; ip = ip->next) { if (IsDefinedClass(ctx, ip->name, frame.owner->ns)) { CfOut(OUTPUT_LEVEL_ERROR, "", "cf-agent aborted on defined class \"%s\" defined in bundle %s\n", copy, frame.owner->name); exit(1); } } if (!ABORTBUNDLE) { for (const Item *ip = ctx->heap_abort_current_bundle; ip != NULL; ip = ip->next) { if (IsDefinedClass(ctx, ip->name, frame.owner->ns)) { CfOut(OUTPUT_LEVEL_ERROR, "", " -> Setting abort for \"%s\" when setting \"%s\"", ip->name, context); ABORTBUNDLE = true; break; } } } }
void EvalContextStackFrameAddSoft(EvalContext *ctx, const char *context) { StringSetAdd(EvalContextStackFrame(ctx)->contexts, xstrdup(context)); }
void EvalContextStackFrameAddNegated(EvalContext *ctx, const char *context) { StringSetAdd(EvalContextStackFrame(ctx)->contexts_negated, xstrdup(context)); }
void EvalContextHeapAddNegated(EvalContext *ctx, const char *context) { StringSetAdd(ctx->heap_negated, xstrdup(context)); }
static Policy *LoadPolicyFile(EvalContext *ctx, GenericAgentConfig *config, const char *policy_file, StringSet *parsed_files_and_checksums, StringSet *failed_files) { Policy *policy = NULL; unsigned char digest[EVP_MAX_MD_SIZE + 1] = { 0 }; char hashbuffer[EVP_MAX_MD_SIZE * 4] = { 0 }; char hashprintbuffer[CF_BUFSIZE] = { 0 }; HashFile(policy_file, digest, CF_DEFAULT_DIGEST); snprintf(hashprintbuffer, CF_BUFSIZE - 1, "{checksum}%s", HashPrintSafe(CF_DEFAULT_DIGEST, true, digest, hashbuffer)); Log(LOG_LEVEL_DEBUG, "Hashed policy file %s to %s", policy_file, hashprintbuffer); if (StringSetContains(parsed_files_and_checksums, policy_file)) { Log(LOG_LEVEL_VERBOSE, "Skipping loading of duplicate policy file %s", policy_file); return NULL; } else if (StringSetContains(parsed_files_and_checksums, hashprintbuffer)) { Log(LOG_LEVEL_VERBOSE, "Skipping loading of duplicate (detected by hash) policy file %s", policy_file); return NULL; } else { Log(LOG_LEVEL_DEBUG, "Loading policy file %s", policy_file); } policy = Cf3ParseFile(config, policy_file); // we keep the checksum and the policy file name to help debugging StringSetAdd(parsed_files_and_checksums, xstrdup(policy_file)); StringSetAdd(parsed_files_and_checksums, xstrdup(hashprintbuffer)); if (policy) { Seq *errors = SeqNew(10, free); if (!PolicyCheckPartial(policy, errors)) { Writer *writer = FileWriter(stderr); for (size_t i = 0; i < errors->length; i++) { PolicyErrorWrite(writer, errors->data[i]); } WriterClose(writer); SeqDestroy(errors); StringSetAdd(failed_files, xstrdup(policy_file)); return NULL; } SeqDestroy(errors); } else { StringSetAdd(failed_files, xstrdup(policy_file)); return NULL; } PolicyResolve(ctx, policy, config); Body *body_common_control = PolicyGetBody(policy, NULL, "common", "control"); Body *body_file_control = PolicyGetBody(policy, NULL, "file", "control"); if (body_common_control) { Seq *potential_inputs = BodyGetConstraint(body_common_control, "inputs"); Constraint *cp = EffectiveConstraint(ctx, potential_inputs); SeqDestroy(potential_inputs); if (cp) { Policy *aux_policy = LoadPolicyInputFiles(ctx, config, RvalRlistValue(cp->rval), parsed_files_and_checksums, failed_files); if (aux_policy) { policy = PolicyMerge(policy, aux_policy); } } } if (body_file_control) { Seq *potential_inputs = BodyGetConstraint(body_file_control, "inputs"); Constraint *cp = EffectiveConstraint(ctx, potential_inputs); SeqDestroy(potential_inputs); if (cp) { Policy *aux_policy = LoadPolicyInputFiles(ctx, config, RvalRlistValue(cp->rval), parsed_files_and_checksums, failed_files); if (aux_policy) { policy = PolicyMerge(policy, aux_policy); } } } return policy; }
static void ExecConfigResetDefault(ExecConfig *exec_config) { free(exec_config->log_facility); exec_config->log_facility = xstrdup("LOG_USER"); free(exec_config->exec_command); exec_config->exec_command = xstrdup(""); free(exec_config->mail_server); exec_config->mail_server = xstrdup(""); free(exec_config->mail_from_address); exec_config->mail_from_address = xstrdup(""); free(exec_config->mail_to_address); exec_config->mail_to_address = xstrdup(""); free(exec_config->mail_subject); exec_config->mail_subject = xstrdup(""); exec_config->mail_max_lines = 30; exec_config->agent_expireafter = 10800; exec_config->splay_time = 0; StringSetClear(exec_config->schedule); StringSetAdd(exec_config->schedule, xstrdup("Min00")); StringSetAdd(exec_config->schedule, xstrdup("Min05")); StringSetAdd(exec_config->schedule, xstrdup("Min10")); StringSetAdd(exec_config->schedule, xstrdup("Min15")); StringSetAdd(exec_config->schedule, xstrdup("Min20")); StringSetAdd(exec_config->schedule, xstrdup("Min25")); StringSetAdd(exec_config->schedule, xstrdup("Min30")); StringSetAdd(exec_config->schedule, xstrdup("Min35")); StringSetAdd(exec_config->schedule, xstrdup("Min40")); StringSetAdd(exec_config->schedule, xstrdup("Min45")); StringSetAdd(exec_config->schedule, xstrdup("Min50")); StringSetAdd(exec_config->schedule, xstrdup("Min55")); }
void ExecConfigUpdate(const EvalContext *ctx, const Policy *policy, ExecConfig *exec_config) { ExecConfigResetDefault(exec_config); Seq *constraints = ControlBodyConstraints(policy, AGENT_TYPE_EXECUTOR); if (constraints) { for (size_t i = 0; i < SeqLength(constraints); i++) { Constraint *cp = SeqAt(constraints, i); if (!IsDefinedClass(ctx, cp->classes, NULL)) { continue; } VarRef *ref = VarRefParseFromScope(cp->lval, "control_executor"); Rval retval; if (!EvalContextVariableGet(ctx, ref, &retval, NULL)) { // TODO: should've been checked before this point. change to programming error Log(LOG_LEVEL_ERR, "Unknown lval '%s' in exec control body", cp->lval); VarRefDestroy(ref); continue; } VarRefDestroy(ref); if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILFROM].lval) == 0) { free(exec_config->mail_from_address); exec_config->mail_from_address = xstrdup(retval.item); Log(LOG_LEVEL_DEBUG, "mailfrom '%s'", exec_config->mail_from_address); } else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILTO].lval) == 0) { free(exec_config->mail_to_address); exec_config->mail_to_address = xstrdup(retval.item); Log(LOG_LEVEL_DEBUG, "mailto '%s'", exec_config->mail_to_address); } else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILSUBJECT].lval) == 0) { free(exec_config->mail_subject); exec_config->mail_subject = xstrdup(retval.item); Log(LOG_LEVEL_DEBUG, "mailsubject '%s'", exec_config->mail_subject); } else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_SMTPSERVER].lval) == 0) { free(exec_config->mail_server); exec_config->mail_server = xstrdup(retval.item); Log(LOG_LEVEL_DEBUG, "smtpserver '%s'", exec_config->mail_server); } else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_EXECCOMMAND].lval) == 0) { free(exec_config->exec_command); exec_config->exec_command = xstrdup(retval.item); Log(LOG_LEVEL_DEBUG, "exec_command '%s'", exec_config->exec_command); } else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_AGENT_EXPIREAFTER].lval) == 0) { exec_config->agent_expireafter = IntFromString(retval.item); Log(LOG_LEVEL_DEBUG, "agent_expireafter %d", exec_config->agent_expireafter); } else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_EXECUTORFACILITY].lval) == 0) { exec_config->log_facility = xstrdup(retval.item); Log(LOG_LEVEL_DEBUG, "executorfacility '%s'", exec_config->log_facility); } else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILMAXLINES].lval) == 0) { exec_config->mail_max_lines = IntFromString(retval.item); Log(LOG_LEVEL_DEBUG, "maxlines %d", exec_config->mail_max_lines); } else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_SPLAYTIME].lval) == 0) { int time = IntFromString(RvalScalarValue(retval)); exec_config->splay_time = (int) (time * SECONDS_PER_MINUTE * GetSplay()); } else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_SCHEDULE].lval) == 0) { Log(LOG_LEVEL_DEBUG, "Loading user-defined schedule..."); StringSetClear(exec_config->schedule); for (const Rlist *rp = retval.item; rp; rp = rp->next) { StringSetAdd(exec_config->schedule, xstrdup(RlistScalarValue(rp))); Log(LOG_LEVEL_DEBUG, "Adding '%s'", RlistScalarValue(rp)); } } } } char ipbuf[CF_MAXVARSIZE] = ""; for (Item *iptr = EvalContextGetIpAddresses(ctx); iptr != NULL; iptr = iptr->next) { if ((SafeStringLength(ipbuf) + SafeStringLength(iptr->name)) < sizeof(ipbuf)) { strcat(ipbuf, iptr->name); strcat(ipbuf, " "); } else { break; } } Chop(ipbuf, sizeof(ipbuf)); free(exec_config->ip_addresses); exec_config->ip_addresses = xstrdup(ipbuf); }
static int SelectTypeMatch(struct stat *lstatptr, Rlist *crit) { Rlist *rp; StringSet *leafattrib = StringSetNew(); if (S_ISREG(lstatptr->st_mode)) { StringSetAdd(leafattrib, xstrdup("reg")); StringSetAdd(leafattrib, xstrdup("plain")); } if (S_ISDIR(lstatptr->st_mode)) { StringSetAdd(leafattrib, xstrdup("dir")); } #ifndef __MINGW32__ if (S_ISLNK(lstatptr->st_mode)) { StringSetAdd(leafattrib, xstrdup("symlink")); } if (S_ISFIFO(lstatptr->st_mode)) { StringSetAdd(leafattrib, xstrdup("fifo")); } if (S_ISSOCK(lstatptr->st_mode)) { StringSetAdd(leafattrib, xstrdup("socket")); } if (S_ISCHR(lstatptr->st_mode)) { StringSetAdd(leafattrib, xstrdup("char")); } if (S_ISBLK(lstatptr->st_mode)) { StringSetAdd(leafattrib, xstrdup("block")); } #endif /* !__MINGW32__ */ #ifdef HAVE_DOOR_CREATE if (S_ISDOOR(lstatptr->st_mode)) { StringSetAdd(leafattrib, xstrdup("door")); } #endif for (rp = crit; rp != NULL; rp = rp->next) { if (EvalFileResult((char *) rp->item, leafattrib)) { StringSetDestroy(leafattrib); return true; } } StringSetDestroy(leafattrib); return false; }
static int SelectProcess(char *procentry, char **names, int *start, int *end, ProcessSelect a) { int result = true, i; char *column[CF_PROCCOLS]; Rlist *rp; StringSet *proc_attr = StringSetNew(); if (!SplitProcLine(procentry, names, start, end, column)) { return false; } for (i = 0; names[i] != NULL; i++) { Log(LOG_LEVEL_DEBUG, "In SelectProcess, COL[%s] = '%s'", names[i], column[i]); } for (rp = a.owner; rp != NULL; rp = rp->next) { if (SelectProcRegexMatch("USER", "UID", (char *) rp->item, names, column)) { StringSetAdd(proc_attr, xstrdup("process_owner")); break; } } if (SelectProcRangeMatch("PID", "PID", a.min_pid, a.max_pid, names, column)) { StringSetAdd(proc_attr, xstrdup("pid")); } if (SelectProcRangeMatch("PPID", "PPID", a.min_ppid, a.max_ppid, names, column)) { StringSetAdd(proc_attr, xstrdup("ppid")); } if (SelectProcRangeMatch("PGID", "PGID", a.min_pgid, a.max_pgid, names, column)) { StringSetAdd(proc_attr, xstrdup("pgid")); } if (SelectProcRangeMatch("VSZ", "SZ", a.min_vsize, a.max_vsize, names, column)) { StringSetAdd(proc_attr, xstrdup("vsize")); } if (SelectProcRangeMatch("RSS", "RSS", a.min_rsize, a.max_rsize, names, column)) { StringSetAdd(proc_attr, xstrdup("rsize")); } if (SelectProcTimeCounterRangeMatch("TIME", "TIME", a.min_ttime, a.max_ttime, names, column)) { StringSetAdd(proc_attr, xstrdup("ttime")); } if (SelectProcTimeAbsRangeMatch ("STIME", "START", a.min_stime, a.max_stime, names, column)) { StringSetAdd(proc_attr, xstrdup("stime")); } if (SelectProcRangeMatch("NI", "PRI", a.min_pri, a.max_pri, names, column)) { StringSetAdd(proc_attr, xstrdup("priority")); } if (SelectProcRangeMatch("NLWP", "NLWP", a.min_thread, a.max_thread, names, column)) { StringSetAdd(proc_attr, xstrdup("threads")); } if (SelectProcRegexMatch("S", "STAT", a.status, names, column)) { StringSetAdd(proc_attr, xstrdup("status")); } if (SelectProcRegexMatch("CMD", "COMMAND", a.command, names, column)) { StringSetAdd(proc_attr, xstrdup("command")); } if (SelectProcRegexMatch("TTY", "TTY", a.tty, names, column)) { StringSetAdd(proc_attr, xstrdup("tty")); } result = EvalProcessResult(a.process_result, proc_attr); StringSetDestroy(proc_attr); for (i = 0; column[i] != NULL; i++) { free(column[i]); } return result; }
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; } } } }
static void TransformGidsToGroups(StringSet **list) { StringSet *new_list = StringSetNew(); StringSetIterator i = StringSetIteratorInit(*list); const char *data; for (data = StringSetIteratorNext(&i); data; data = StringSetIteratorNext(&i)) { if (strlen(data) != strspn(data, "0123456789")) { // Cannot possibly be a gid. StringSetAdd(new_list, xstrdup(data)); continue; } // In groups vs gids, groups take precedence. So check if it exists. errno = 0; struct group *group_info = getgrnam(data); if (!group_info) { switch (errno) { case 0: case ENOENT: case EBADF: case ESRCH: case EWOULDBLOCK: case EPERM: // POSIX is apparently ambiguous here. All values mean "not found". errno = 0; group_info = getgrgid(atoi(data)); if (!group_info) { switch (errno) { case 0: case ENOENT: case EBADF: case ESRCH: case EWOULDBLOCK: case EPERM: // POSIX is apparently ambiguous here. All values mean "not found". // // Neither group nor gid is found. This will lead to an error later, but we don't // handle that here. break; default: Log(LOG_LEVEL_ERR, "Error while checking group name '%s'. (getgrgid: '%s')", data, GetErrorStr()); StringSetDestroy(new_list); return; } } else { // Replace gid with group name. StringSetAdd(new_list, xstrdup(group_info->gr_name)); } break; default: Log(LOG_LEVEL_ERR, "Error while checking group name '%s'. (getgrnam: '%s')", data, GetErrorStr()); StringSetDestroy(new_list); return; } } else { StringSetAdd(new_list, xstrdup(data)); } } StringSet *old_list = *list; *list = new_list; StringSetDestroy(old_list); }
static bool SelectProcess(const char *procentry, time_t pstime, char **names, int *start, int *end, const char *process_regex, ProcessSelect a, bool attrselect) { bool result = true; char *column[CF_PROCCOLS]; Rlist *rp; assert(process_regex); StringSet *process_select_attributes = StringSetNew(); memset(column, 0, sizeof(column)); if (!SplitProcLine(procentry, pstime, names, start, end, PS_COLUMN_ALGORITHM[VPSHARDCLASS], column)) { result = false; goto cleanup; } ApplyPlatformExtraTable(names, column); for (int i = 0; names[i] != NULL; i++) { Log(LOG_LEVEL_DEBUG, "In SelectProcess, COL[%s] = '%s'", names[i], column[i]); } if (!SelectProcRegexMatch("CMD", "COMMAND", process_regex, false, names, column)) { result = false; goto cleanup; } if (!attrselect) { // If we are not considering attributes, then the matching is done. goto cleanup; } for (rp = a.owner; rp != NULL; rp = rp->next) { if (SelectProcRegexMatch("USER", "UID", RlistScalarValue(rp), true, names, column)) { StringSetAdd(process_select_attributes, xstrdup("process_owner")); break; } } if (SelectProcRangeMatch("PID", "PID", a.min_pid, a.max_pid, names, column)) { StringSetAdd(process_select_attributes, xstrdup("pid")); } if (SelectProcRangeMatch("PPID", "PPID", a.min_ppid, a.max_ppid, names, column)) { StringSetAdd(process_select_attributes, xstrdup("ppid")); } if (SelectProcRangeMatch("PGID", "PGID", a.min_pgid, a.max_pgid, names, column)) { StringSetAdd(process_select_attributes, xstrdup("pgid")); } if (SelectProcRangeMatch("VSZ", "SZ", a.min_vsize, a.max_vsize, names, column)) { StringSetAdd(process_select_attributes, xstrdup("vsize")); } if (SelectProcRangeMatch("RSS", "RSS", a.min_rsize, a.max_rsize, names, column)) { StringSetAdd(process_select_attributes, xstrdup("rsize")); } if (SelectProcTimeCounterRangeMatch("TIME", "TIME", a.min_ttime, a.max_ttime, names, column)) { StringSetAdd(process_select_attributes, xstrdup("ttime")); } if (SelectProcTimeAbsRangeMatch ("STIME", "START", a.min_stime, a.max_stime, names, column)) { StringSetAdd(process_select_attributes, xstrdup("stime")); } if (SelectProcRangeMatch("NI", "PRI", a.min_pri, a.max_pri, names, column)) { StringSetAdd(process_select_attributes, xstrdup("priority")); } if (SelectProcRangeMatch("NLWP", "NLWP", a.min_thread, a.max_thread, names, column)) { StringSetAdd(process_select_attributes, xstrdup("threads")); } if (SelectProcRegexMatch("S", "STAT", a.status, true, names, column)) { StringSetAdd(process_select_attributes, xstrdup("status")); } if (SelectProcRegexMatch("CMD", "COMMAND", a.command, true, names, column)) { StringSetAdd(process_select_attributes, xstrdup("command")); } if (SelectProcRegexMatch("TTY", "TTY", a.tty, true, names, column)) { StringSetAdd(process_select_attributes, xstrdup("tty")); } if (!a.process_result) { if (StringSetSize(process_select_attributes) == 0) { result = EvalProcessResult("", process_select_attributes); } else { Writer *w = StringWriter(); StringSetIterator iter = StringSetIteratorInit(process_select_attributes); char *attr = StringSetIteratorNext(&iter); WriterWrite(w, attr); while ((attr = StringSetIteratorNext(&iter))) { WriterWriteChar(w, '.'); WriterWrite(w, attr); } result = EvalProcessResult(StringWriterData(w), process_select_attributes); WriterClose(w); } } else { result = EvalProcessResult(a.process_result, process_select_attributes); } cleanup: StringSetDestroy(process_select_attributes); for (int i = 0; column[i] != NULL; i++) { free(column[i]); } return result; }
static bool VerifyIfUserNeedsModifs (const char *puser, const User *u, const struct passwd *passwd_info, uint32_t *changemap) { assert(u != NULL); if (u->description != NULL && strcmp (u->description, passwd_info->pw_gecos)) { CFUSR_SETBIT (*changemap, i_comment); } if (u->uid != NULL && (atoi (u->uid) != passwd_info->pw_uid)) { CFUSR_SETBIT (*changemap, i_uid); } if (u->home_dir != NULL && strcmp (u->home_dir, passwd_info->pw_dir)) { CFUSR_SETBIT (*changemap, i_home); } if (u->shell != NULL && strcmp (u->shell, passwd_info->pw_shell)) { CFUSR_SETBIT (*changemap, i_shell); } bool account_is_locked = IsAccountLocked(puser, passwd_info); if ((!account_is_locked && u->policy == USER_STATE_LOCKED) || (account_is_locked && u->policy != USER_STATE_LOCKED)) { CFUSR_SETBIT(*changemap, i_locked); } // Don't bother with passwords if the account is going to be locked anyway. if (u->password != NULL && strcmp (u->password, "") && u->policy != USER_STATE_LOCKED) { if (!IsPasswordCorrect(puser, u->password, u->password_format, passwd_info)) { CFUSR_SETBIT (*changemap, i_password); } } if (SafeStringLength(u->group_primary)) { bool group_could_be_gid = (strlen(u->group_primary) == strspn(u->group_primary, "0123456789")); int gid; // We try name first, even if it looks like a gid. Only fall back to gid. struct group *group_info; errno = 0; group_info = GetGrEntry(u->group_primary, &EqualGroupName); if (!group_info && errno != 0) { Log(LOG_LEVEL_ERR, "Could not obtain information about group '%s': %s", u->group_primary, GetErrorStr()); gid = -1; } else if (!group_info) { if (group_could_be_gid) { gid = atoi(u->group_primary); } else { Log(LOG_LEVEL_ERR, "No such group '%s'.", u->group_primary); gid = -1; } } else { gid = group_info->gr_gid; } if (gid != passwd_info->pw_gid) { CFUSR_SETBIT (*changemap, i_group); } } if (u->groups_secondary_given) { StringSet *wanted_groups = StringSetNew(); for (Rlist *ptr = u->groups_secondary; ptr; ptr = ptr->next) { StringSetAdd(wanted_groups, xstrdup(RvalScalarValue(ptr->val))); } TransformGidsToGroups(&wanted_groups); StringSet *current_groups = StringSetNew(); if (!GroupGetUserMembership (puser, current_groups)) { CFUSR_SETBIT (*changemap, i_groups); } else if (!StringSetIsEqual (current_groups, wanted_groups)) { CFUSR_SETBIT (*changemap, i_groups); } StringSetDestroy(current_groups); StringSetDestroy(wanted_groups); } //////////////////////////////////////////// if (*changemap == 0) { return false; } else { return true; } }
static int SelectProcess(EvalContext *ctx, char *procentry, char **names, int *start, int *end, ProcessSelect a) { int result = true, i; char *column[CF_PROCCOLS]; Rlist *rp; StringSet *process_select_attributes = StringSetNew(); if (!SplitProcLine(procentry, names, start, end, column)) { return false; } for (i = 0; names[i] != NULL; i++) { Log(LOG_LEVEL_DEBUG, "In SelectProcess, COL[%s] = '%s'", names[i], column[i]); } for (rp = a.owner; rp != NULL; rp = rp->next) { if (SelectProcRegexMatch(ctx, "USER", "UID", RlistScalarValue(rp), names, column)) { StringSetAdd(process_select_attributes, xstrdup("process_owner")); break; } } if (SelectProcRangeMatch("PID", "PID", a.min_pid, a.max_pid, names, column)) { StringSetAdd(process_select_attributes, xstrdup("pid")); } if (SelectProcRangeMatch("PPID", "PPID", a.min_ppid, a.max_ppid, names, column)) { StringSetAdd(process_select_attributes, xstrdup("ppid")); } if (SelectProcRangeMatch("PGID", "PGID", a.min_pgid, a.max_pgid, names, column)) { StringSetAdd(process_select_attributes, xstrdup("pgid")); } if (SelectProcRangeMatch("VSZ", "SZ", a.min_vsize, a.max_vsize, names, column)) { StringSetAdd(process_select_attributes, xstrdup("vsize")); } if (SelectProcRangeMatch("RSS", "RSS", a.min_rsize, a.max_rsize, names, column)) { StringSetAdd(process_select_attributes, xstrdup("rsize")); } if (SelectProcTimeCounterRangeMatch("TIME", "TIME", a.min_ttime, a.max_ttime, names, column)) { StringSetAdd(process_select_attributes, xstrdup("ttime")); } if (SelectProcTimeAbsRangeMatch ("STIME", "START", a.min_stime, a.max_stime, names, column)) { StringSetAdd(process_select_attributes, xstrdup("stime")); } if (SelectProcRangeMatch("NI", "PRI", a.min_pri, a.max_pri, names, column)) { StringSetAdd(process_select_attributes, xstrdup("priority")); } if (SelectProcRangeMatch("NLWP", "NLWP", a.min_thread, a.max_thread, names, column)) { StringSetAdd(process_select_attributes, xstrdup("threads")); } if (SelectProcRegexMatch(ctx, "S", "STAT", a.status, names, column)) { StringSetAdd(process_select_attributes, xstrdup("status")); } if (SelectProcRegexMatch(ctx, "CMD", "COMMAND", a.command, names, column)) { StringSetAdd(process_select_attributes, xstrdup("command")); } if (SelectProcRegexMatch(ctx, "TTY", "TTY", a.tty, names, column)) { StringSetAdd(process_select_attributes, xstrdup("tty")); } if (!a.process_result) { if (StringSetSize(process_select_attributes) == 0) { result = EvalProcessResult("", process_select_attributes); } else { Writer *w = StringWriter(); StringSetIterator iter = StringSetIteratorInit(process_select_attributes); char *attr = StringSetIteratorNext(&iter); WriterWrite(w, attr); while ((attr = StringSetIteratorNext(&iter))) { WriterWriteChar(w, '.'); WriterWrite(w, attr); } result = EvalProcessResult(StringWriterData(w), process_select_attributes); WriterClose(w); } } else { result = EvalProcessResult(a.process_result, process_select_attributes); } StringSetDestroy(process_select_attributes); for (i = 0; column[i] != NULL; i++) { free(column[i]); } return result; }