static void test_purge_old_connections_purge_middle(void) { const time_t time_now = 100000; Item *connections = NULL; char time_str[64]; snprintf(time_str, sizeof(time_str), "%ld", time_now - CONNECTION_MAX_AGE_SECONDS); PrependItem(&connections, "123.123.123.3", time_str); snprintf(time_str, sizeof(time_str), "%ld", time_now - CONNECTION_MAX_AGE_SECONDS - 1); PrependItem(&connections, "123.123.123.2", time_str); snprintf(time_str, sizeof(time_str), "%ld", time_now - CONNECTION_MAX_AGE_SECONDS + 100); PrependItem(&connections, "123.123.123.1", time_str); assert_int_equal(ListLen(connections), 3); PurgeOldConnections(&connections, time_now); assert_int_equal(ListLen(connections), 2); assert_true(IsItemIn(connections, "123.123.123.1")); assert_false(IsItemIn(connections, "123.123.123.2")); assert_true(IsItemIn(connections, "123.123.123.3")); DeleteItemList(connections); }
void EvalContextHeapAddAbort(EvalContext *ctx, const char *context, const char *activated_on_context) { if (!IsItemIn(ctx->heap_abort, context)) { AppendItem(&ctx->heap_abort, context, activated_on_context); } }
static SyntaxTypeMatch CheckParseOpts(const char *lval, const char *s, const char *range) { Item *split; /* List/menu types are separated by comma str "a,b,c,..." */ CfDebug("\nCheckParseOpts(%s => %s/%s)\n", lval, s, range); if (IsNakedVar(s, '@') || IsNakedVar(s, '$')) { return SYNTAX_TYPE_MATCH_ERROR_UNEXPANDED; } split = SplitString(range, ','); if (!IsItemIn(split, s)) { DeleteItemList(split); return SYNTAX_TYPE_MATCH_ERROR_OPTS_OUT_OF_RANGE; } DeleteItemList(split); return SYNTAX_TYPE_MATCH_OK; }
void EvalContextHeapAddAbortCurrentBundle(EvalContext *ctx, const char *context, const char *activated_on_context) { if (!IsItemIn(ctx->heap_abort_current_bundle, context)) { AppendItem(&ctx->heap_abort_current_bundle, context, activated_on_context); } }
int RelevantBundle(char *agent,char *blocktype) { struct Item *ip; if (strcmp(agent,CF_AGENTTYPES[cf_common]) == 0 || strcmp(CF_COMMONC,P.blocktype) == 0) { return true; } /* Here are some additional bundle types handled by cfAgent */ ip = SplitString("edit_line,edit_xml",','); if (strcmp(agent,CF_AGENTTYPES[cf_agent]) == 0) { if (IsItemIn(ip,blocktype)) { DeleteItemList(ip); return true; } } DeleteItemList(ip); return false; }
void AddInstallable(char *classlist) { char *sp, currentitem[CF_MAXVARSIZE]; if (classlist == NULL) { return; } Debug("AddInstallable(%s)\n",classlist); for (sp = classlist; *sp != '\0'; sp++) { currentitem[0] = '\0'; sscanf(sp,"%[^,:.]",currentitem); sp += strlen(currentitem); if (! IsItemIn(VALLADDCLASSES,currentitem)) { AppendItem(&VALLADDCLASSES,currentitem,NULL); } if (*sp == '\0') { break; } } }
int ArchiveToRepository(const char *file, Attributes attr, Promise *pp, const ReportContext *report_context) /* Returns true if the file was backup up and false if not */ { char destination[CF_BUFSIZE]; struct stat sb, dsb; if (!GetRepositoryPath(file, attr, destination)) { return false; } if (attr.copy.backup == cfa_nobackup) { return true; } if (IsItemIn(VREPOSLIST, file)) { CfOut(OUTPUT_LEVEL_INFORM, "", "The file %s has already been moved to the repository once. Multiple update will cause loss of backup.", file); return true; } ThreadLock(cft_getaddr); PrependItemList(&VREPOSLIST, file); ThreadUnlock(cft_getaddr); CfDebug("Repository(%s)\n", file); JoinPath(destination, CanonifyName(file)); if (!MakeParentDirectory(destination, attr.move_obstructions, report_context)) { } if (cfstat(file, &sb) == -1) { CfDebug("File %s promised to archive to the repository but it disappeared!\n", file); return true; } cfstat(destination, &dsb); CheckForFileHoles(&sb, pp); if (pp && CopyRegularFileDisk(file, destination, pp->makeholes)) { CfOut(OUTPUT_LEVEL_INFORM, "", "Moved %s to repository location %s\n", file, destination); return true; } else { CfOut(OUTPUT_LEVEL_INFORM, "", "Failed to move %s to repository location %s\n", file, destination); return false; } }
static void IncrementCounter(Item **list, char *name) { if (!IsItemIn(*list, name)) { AppendItem(list, name, ""); } IncrementItemListCounter(*list, name); }
int AllowedUser(char *user) { if (IsItemIn(SV.allowuserlist, user)) { Log(LOG_LEVEL_VERBOSE, "User %s granted connection privileges", user); return true; } Log(LOG_LEVEL_VERBOSE, "User %s is not allowed on this server", user); return false; }
int ArchiveToRepository(const char *file, Attributes attr) /* Returns true if the file was backup up and false if not */ { char destination[CF_BUFSIZE]; struct stat sb, dsb; if (!GetRepositoryPath(file, attr, destination)) { return false; } if (attr.copy.backup == BACKUP_OPTION_NO_BACKUP) { return true; } if (IsItemIn(VREPOSLIST, file)) { Log(LOG_LEVEL_INFO, "The file '%s' has already been moved to the repository once. Multiple update will cause loss of backup.", file); return true; } ThreadLock(cft_getaddr); PrependItemList(&VREPOSLIST, file); ThreadUnlock(cft_getaddr); JoinPath(destination, CanonifyName(file)); if (!MakeParentDirectory(destination, attr.move_obstructions)) { } if (stat(file, &sb) == -1) { Log(LOG_LEVEL_DEBUG, "File '%s' promised to archive to the repository but it disappeared!", file); return true; } stat(destination, &dsb); if (CopyRegularFileDisk(file, destination)) { Log(LOG_LEVEL_INFO, "Moved '%s' to repository location '%s'", file, destination); return true; } else { Log(LOG_LEVEL_INFO, "Failed to move '%s' to repository location '%s'", file, destination); return false; } }
static bool GetSysUsers( int *userListSz, int *numRootProcs, int *numOtherProcs) { FILE *fp; char user[CF_BUFSIZE]; char vbuff[CF_BUFSIZE]; char cbuff[CF_BUFSIZE]; #if defined(__sun) xsnprintf(cbuff, CF_BUFSIZE, "/bin/ps -eo user > %s/users.txt", CFWORKDIR); #elif defined(_AIX) xsnprintf(cbuff, CF_BUFSIZE, "/bin/ps -N -eo user > %s/users.txt", CFWORKDIR); #elif defined(__linux__) xsnprintf(cbuff, CF_BUFSIZE, "/bin/ps -eo user > %s/users.txt", CFWORKDIR); #else assert_true(1); return false; #endif Item *userList = NULL; system(cbuff); xsnprintf(cbuff, CF_BUFSIZE, "%s/users.txt", CFWORKDIR); if ((fp = fopen(cbuff, "r")) == NULL) { return false; } while (fgets(vbuff, CF_BUFSIZE, fp) != NULL) { sscanf(vbuff, "%s", user); if (strcmp(user, "USER") == 0) { continue; } if (!IsItemIn(userList, user)) { PrependItem(&userList, user, NULL); (*userListSz)++; } if (strcmp(user, "root") == 0) { (*numRootProcs)++; } else { (*numOtherProcs)++; } } fclose(fp); return true; }
static void SetNetworkEntropyClasses(const char *service, const char *direction, const Item *list) { const Item *ip; Item *addresses = NULL; double entropy; for (ip = list; ip != NULL; ip = ip->next) { if (strlen(ip->name) > 0) { char local[CF_BUFSIZE]; char remote[CF_BUFSIZE]; char vbuff[CF_BUFSIZE]; char *sp; if (strncmp(ip->name, "tcp", 3) == 0) { sscanf(ip->name, "%*s %*s %*s %s %s", local, remote); /* linux-like */ } else { sscanf(ip->name, "%s %s", local, remote); /* solaris-like */ } strncpy(vbuff, remote, CF_BUFSIZE - 1); vbuff[CF_BUFSIZE-1] = '\0'; for (sp = vbuff + strlen(vbuff) - 1; isdigit((int) *sp) && (sp > vbuff); sp--) { } *sp = '\0'; if (!IsItemIn(addresses, vbuff)) { AppendItem(&addresses, vbuff, ""); } IncrementItemListCounter(addresses, vbuff); } } entropy = MonEntropyCalculate(addresses); MonEntropyClassesSet(service, direction, entropy); DeleteItemList(addresses); }
bool ListsCompare(const Item *list1, const Item *list2) { if (ListLen(list1) != ListLen(list2)) { return false; } for (const Item *ptr = list1; ptr != NULL; ptr = ptr->next) { if (IsItemIn(list2, ptr->name) == false) { return false; } } return true; }
static int Unix_GatherProcessUsers(struct Item **userList, int *userListSz, int *numRootProcs, int *numOtherProcs) { FILE *pp; char pscomm[CF_BUFSIZE]; char user[CF_MAXVARSIZE]; char vbuff[CF_BUFSIZE]; snprintf(pscomm,CF_BUFSIZE,"%s %s",VPSCOMM[VSYSTEMHARDCLASS],VPSOPTS[VSYSTEMHARDCLASS]); if ((pp = cf_popen(pscomm,"r")) == NULL) { return false; } CfReadLine(vbuff,CF_BUFSIZE,pp); while (!feof(pp)) { CfReadLine(vbuff,CF_BUFSIZE,pp); sscanf(vbuff,"%s",user); if (strcmp(user,"USER") == 0) { continue; } if (!IsItemIn(*userList,user)) { PrependItem(userList,user,NULL); (*userListSz)++; } if (strcmp(user,"root") == 0) { (*numRootProcs)++; } else { (*numOtherProcs)++; } } cf_pclose(pp); return true; }
/** * Checks whether list1 is a subset of list2, i.e. every entry in list1 must * be found in list2. */ bool ListSubsetOfList(const Item *list1, const Item *list2) { const Item *list1_ptr = list1; CYCLE_DECLARE(list1_ptr, slow, toggle); while (list1_ptr != NULL) { if (!IsItemIn(list2, list1_ptr->name)) { return false; } list1_ptr = list1_ptr->next; CYCLE_CHECK(list1_ptr, slow, toggle); } return true; /* all elements of list1 were found in list2 */ }
bool ListsCompare(const Item *list1, const Item *list2) { if (ListLen(list1) != ListLen(list2)) { return false; } const Item *ptr = list1; CYCLE_DECLARE(ptr, slow, toggle); while (ptr != NULL) { if (IsItemIn(list2, ptr->name) == false) { return false; } ptr = ptr->next; CYCLE_CHECK(ptr, slow, toggle); } return true; }
static void CheckParseOpts(char *lval, char *s, const char *range) { Item *split; int err = false; char output[CF_BUFSIZE]; /* List/menu types are separated by comma str "a,b,c,..." */ CfDebug("\nCheckParseOpts(%s => %s/%s)\n", lval, s, range); if (s == NULL) { return; } if (IsNakedVar(s, '@') || IsNakedVar(s, '$')) { CfDebug("Validation: Unable to verify variable expansion of %s at this stage\n", s); return; } split = SplitString(range, ','); if (!IsItemIn(split, s)) { snprintf(output, CF_BUFSIZE, "Selection on rhs of lval \'%s\' given as \'%s\' is out of bounds, should be in [%s]", lval, s, range); ReportError(output); err = true; } DeleteItemList(split); if (!err) { CfDebug("CheckParseOpts - syntax verified\n\n"); } }
static void ShowState(char *type) { struct stat statbuf; char buffer[CF_BUFSIZE], vbuff[CF_BUFSIZE], assemble[CF_BUFSIZE]; Item *addresses = NULL, *saddresses = NULL, *ip; int i = 0, tot = 0, min_signal_diversity = 1, conns = 1; int maxlen = 0, count; double *dist = NULL, S = 0.0; char *offset = NULL; FILE *fp; CfDebug("ShowState(%s)\n", type); snprintf(buffer, CF_BUFSIZE - 1, "%s/state/cf_%s", CFWORKDIR, type); if (cfstat(buffer, &statbuf) == 0) { if ((fp = fopen(buffer, "r")) == NULL) { CfOut(cf_inform, "fopen", "Could not open state memory %s\n", buffer); return; } while (!feof(fp)) { char local[CF_BUFSIZE], remote[CF_BUFSIZE]; buffer[0] = local[0] = remote[0] = '\0'; memset(vbuff, 0, CF_BUFSIZE); fgets(buffer, CF_BUFSIZE, fp); if (strlen(buffer) > 0) { CfOut(cf_verbose, "", "(%2d) %s", conns, buffer); if (IsSocketType(type)) { if (strncmp(type, "incoming", 8) == 0 || strncmp(type, "outgoing", 8) == 0) { if (strncmp(buffer, "tcp", 3) == 0) { sscanf(buffer, "%*s %*s %*s %s %s", local, remote); /* linux-like */ } else { sscanf(buffer, "%s %s", local, remote); /* solaris-like */ } strncpy(vbuff, remote, CF_BUFSIZE - 1); DePort(vbuff); } } else if (IsTCPType(type)) { count = 1; sscanf(buffer, "%d %[^\n]", &count, remote); AppendItem(&addresses, remote, ""); SetItemListCounter(addresses, remote, count); conns += count; continue; } else { /* If we get here this is a process thing */ if (offset == NULL) { if ((offset = strstr(buffer, "CMD"))) { } else if ((offset = strstr(buffer, "COMMAND"))) { } if (offset == NULL) { continue; } } strncpy(vbuff, offset, CF_BUFSIZE - 1); Chop(vbuff); } if (!IsItemIn(addresses, vbuff)) { conns++; AppendItem(&addresses, vbuff, ""); IncrementItemListCounter(addresses, vbuff); } else { conns++; IncrementItemListCounter(addresses, vbuff); } } } fclose(fp); conns--; CfOut(cf_error, "", "\n"); CfOut(cf_error, "", "R: The peak measured state was q = %d:\n", conns); if (IsSocketType(type) || IsTCPType(type)) { for (ip = addresses; ip != NULL; ip = ip->next) { tot += ip->counter; buffer[0] = '\0'; sscanf(ip->name, "%s", buffer); if (!IsIPV4Address(buffer) && !IsIPV6Address(buffer)) { CfOut(cf_verbose, "", "Rejecting address %s\n", ip->name); continue; } CfOut(cf_error, "", "R: DNS key: %s = %s (%d/%d)\n", buffer, IPString2Hostname(buffer), ip->counter, conns); if (strlen(ip->name) > maxlen) { maxlen = strlen(ip->name); } } if (addresses != NULL) { printf("R: -\n"); } } else { for (ip = addresses; ip != NULL; ip = ip->next) { tot += ip->counter; } } addresses = SortItemListCounters(addresses); saddresses = addresses; for (ip = saddresses; ip != NULL; ip = ip->next) { int s; if (maxlen > 17) /* ipv6 */ { snprintf(assemble, CF_BUFSIZE, "Frequency: %-40s|", ip->name); } else { snprintf(assemble, CF_BUFSIZE, "Frequency: %-17s|", ip->name); } for (s = 0; (s < ip->counter) && (s < 50); s++) { if (s < 48) { strcat(assemble, "*"); } else { strcat(assemble, "+"); } } CfOut(cf_error, "", "R: %s \t(%d/%d)\n", assemble, ip->counter, conns); } dist = xmalloc((tot + 1) * sizeof(double)); if (conns > min_signal_diversity) { for (i = 0, ip = addresses; ip != NULL; i++, ip = ip->next) { dist[i] = ((double) (ip->counter)) / ((double) tot); S -= dist[i] * log(dist[i]); } CfOut(cf_error, "", "R: Variability/entropy of addresses = %.1f %%\n", S / log((double) tot) * 100.0); CfOut(cf_error, "", "R: (Entropy = 0 for single source, 100 for flatly distributed source)\n -\n"); } CfOut(cf_error, "", "\n"); CfOut(cf_error, "", "R: State of %s peaked at %s\n", type, cf_ctime(&statbuf.st_mtime)); } else { CfOut(cf_inform, "", "R: State parameter %s is not known or recorded\n", type); } DeleteItemList(addresses); if (dist) { free((char *) dist); } }
bool FileInRepository(const char *filename) { return IsItemIn(VREPOSLIST, filename); }
void KeepPromises(Policy *policy, ExecConfig *config) { bool schedule_is_specified = false; Seq *constraints = ControlBodyConstraints(policy, AGENT_TYPE_EXECUTOR); if (constraints) { for (size_t i = 0; i < SeqLength(constraints); i++) { Constraint *cp = SeqAt(constraints, i); if (IsExcluded(cp->classes, NULL)) { continue; } Rval retval; if (GetVariable("control_executor", cp->lval, &retval) == DATA_TYPE_NONE) { CfOut(OUTPUT_LEVEL_ERROR, "", "Unknown lval %s in exec control body", cp->lval); continue; } if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_mailfrom].lval) == 0) { free(config->mail_from_address); config->mail_from_address = SafeStringDuplicate(retval.item); CfDebug("mailfrom = %s\n", config->mail_from_address); } if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_mailto].lval) == 0) { free(config->mail_to_address); config->mail_to_address = SafeStringDuplicate(retval.item); CfDebug("mailto = %s\n", config->mail_to_address); } if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_smtpserver].lval) == 0) { free(config->mail_server); config->mail_server = SafeStringDuplicate(retval.item); CfDebug("smtpserver = %s\n", config->mail_server); } if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_execcommand].lval) == 0) { free(config->exec_command); config->exec_command = SafeStringDuplicate(retval.item); CfDebug("exec_command = %s\n", config->exec_command); } if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_agent_expireafter].lval) == 0) { config->agent_expireafter = IntFromString(retval.item); CfDebug("agent_expireafter = %d\n", config->agent_expireafter); } if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_executorfacility].lval) == 0) { SetFacility(retval.item); continue; } if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_mailmaxlines].lval) == 0) { config->mail_max_lines = IntFromString(retval.item); CfDebug("maxlines = %d\n", config->mail_max_lines); } if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_splaytime].lval) == 0) { int time = IntFromString(RvalScalarValue(retval)); SPLAYTIME = (int) (time * SECONDS_PER_MINUTE * GetSplay()); } if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_schedule].lval) == 0) { CfDebug("Loading user-defined schedule...\n"); DeleteItemList(SCHEDULE); SCHEDULE = NULL; schedule_is_specified = true; for (const Rlist *rp = retval.item; rp; rp = rp->next) { if (!IsItemIn(SCHEDULE, rp->item)) { AppendItem(&SCHEDULE, rp->item, NULL); } } } } } if (!schedule_is_specified) { LoadDefaultSchedule(); } }
static bool GetSysUsers( int *userListSz, int *numRootProcs, int *numOtherProcs) { FILE *fp; char user[CF_BUFSIZE]; char vbuff[CF_BUFSIZE]; char cbuff[CF_BUFSIZE]; /* * The best would be to ask only "user" field from ps, but we are asking * for "user,pid". The reason is that we try to mimic cf-monitord's * behaviour, else a different number of users might be detected by the * test, as printing "user,pid" truncates the user column. TODO fix the * ps command to use only "-o user" in both mon_processes.c and this test. */ #if defined(__sun) xsnprintf(cbuff, CF_BUFSIZE, "/bin/ps -eo user,pid > %s/users.txt", CFWORKDIR); #elif defined(_AIX) xsnprintf(cbuff, CF_BUFSIZE, "/bin/ps -N -eo user,pid > %s/users.txt", CFWORKDIR); #elif defined(__hpux) xsnprintf(cbuff, CF_BUFSIZE, "UNIX95=1 /bin/ps -eo user,pid > %s/users.txt", CFWORKDIR); /* SKIP on HP-UX since cf-monitord doesn't count processes correctly! */ return false; #else xsnprintf(cbuff, CF_BUFSIZE, "ps -eo user:30,pid > %s/users.txt", CFWORKDIR); #endif Item *userList = NULL; system(cbuff); xsnprintf(cbuff, CF_BUFSIZE, "%s/users.txt", CFWORKDIR); if ((fp = fopen(cbuff, "r")) == NULL) { return false; } while (fgets(vbuff, CF_BUFSIZE, fp) != NULL) { int ret = sscanf(vbuff, " %s ", user); if (ret != 1 || strcmp(user, "") == 0 || strcmp(user, "USER") == 0 || isdigit(user[0])) { continue; } if (!IsItemIn(userList, user)) { PrependItem(&userList, user, NULL); (*userListSz)++; } if (strcmp(user, "root") == 0) { (*numRootProcs)++; } else { (*numOtherProcs)++; } } fclose(fp); if (LogGetGlobalLevel() >= LOG_LEVEL_DEBUG) { char *s = ItemList2CSV(userList); Log(LOG_LEVEL_DEBUG, "Users in the process table detected from the test: (%s)", s); free(s); } DeleteItemList(userList); return true; }
/** * @brief check whether the lastseen DB is coherent or not * * A DB is coherent mainly if all the entries are valid and if there is * a strict one-to-one correspondance between hosts and key digests * (whether in MD5 or SHA1 format). * * @retval true if the lastseen DB is coherent, false otherwise */ bool IsLastSeenCoherent(void) { DBHandle *db; DBCursor *cursor; bool res = true; if (!OpenDB(&db, dbid_lastseen)) { Log(LOG_LEVEL_ERR, "Unable to open lastseen database"); return false; } if (!NewDBCursor(db, &cursor)) { Log(LOG_LEVEL_ERR, "Unable to create lastseen database cursor"); CloseDB(db); return false; } char *key; void *value; int ksize, vsize; Item *qkeys=NULL; Item *akeys=NULL; Item *kkeys=NULL; Item *ahosts=NULL; Item *khosts=NULL; char val[CF_BUFSIZE]; while (NextDB(cursor, &key, &ksize, &value, &vsize)) { if (key[0] != 'k' && key[0] != 'q' && key[0] != 'a' ) { continue; } if (key[0] == 'q' ) { if (strncmp(key,"qiSHA=",5)==0 || strncmp(key,"qoSHA=",5)==0 || strncmp(key,"qiMD5=",5)==0 || strncmp(key,"qoMD5=",5)==0) { if (IsItemIn(qkeys, key+2)==false) { PrependItem(&qkeys, key+2, NULL); } } } if (key[0] == 'k' ) { if (strncmp(key, "kSHA=", 4)==0 || strncmp(key, "kMD5=", 4)==0) { if (IsItemIn(kkeys, key+1)==false) { PrependItem(&kkeys, key+1, NULL); } if (ReadDB(db, key, &val, vsize)) { if (IsItemIn(khosts, val)==false) { PrependItem(&khosts, val, NULL); } } } } if (key[0] == 'a' ) { if (IsItemIn(ahosts, key+1)==false) { PrependItem(&ahosts, key+1, NULL); } if (ReadDB(db, key, &val, vsize)) { if (IsItemIn(akeys, val)==false) { PrependItem(&akeys, val, NULL); } } } } DeleteDBCursor(cursor); CloseDB(db); if (ListsCompare(ahosts, khosts) == false) { res = false; goto clean; } if (ListsCompare(akeys, kkeys) == false) { res = false; goto clean; } clean: DeleteItemList(qkeys); DeleteItemList(akeys); DeleteItemList(kkeys); DeleteItemList(ahosts); DeleteItemList(khosts); return res; }
int ArchiveToRepository(char *file,struct Attributes attr,struct Promise *pp) /* Returns true if the file was backup up and false if not */ { char destination[CF_BUFSIZE]; char localrepository[CF_BUFSIZE]; char node[CF_BUFSIZE]; struct stat sb, dsb; char *sp; if (attr.repository == NULL && VREPOSITORY == NULL) { return false; } if (attr.repository != NULL) { strncpy(localrepository,attr.repository,CF_BUFSIZE); } else if (VREPOSITORY != NULL) { strncpy(localrepository,VREPOSITORY,CF_BUFSIZE); } if (attr.copy.backup == cfa_nobackup) { return true; } if (IsItemIn(VREPOSLIST,file)) { CfOut(cf_inform,"","The file %s has already been moved to the repository once. Multiple update will cause loss of backup.",file); return true; } ThreadLock(cft_getaddr); PrependItemList(&VREPOSLIST,file); ThreadUnlock(cft_getaddr); Debug("Repository(%s)\n",file); strcpy (node,file); destination[0] = '\0'; for (sp = node; *sp != '\0'; sp++) { if (*sp == FILE_SEPARATOR) { *sp = REPOSCHAR; } } strncpy(destination,localrepository,CF_BUFSIZE-2); if (!JoinPath(destination,node)) { CfOut(cf_error,"","Internal limit: Buffer ran out of space for long filename\n"); return false; } if (!MakeParentDirectory(destination,attr.move_obstructions)) { } if (cfstat(file,&sb) == -1) { Debug("File %s promised to archive to the repository but it disappeared!\n",file); return true; } cfstat(destination,&dsb); attr.copy.servers = NULL; attr.copy.backup = cfa_repos_store; // cfa_nobackup; attr.copy.stealth = false; attr.copy.verify = false; attr.copy.preserve = false; CheckForFileHoles(&sb,pp); if (CopyRegularFileDisk(file,destination,attr,pp)) { CfOut(cf_inform,"","Moved %s to repository location %s\n",file,destination); return true; } else { CfOut(cf_inform,"","Failed to move %s to repository location %s\n",file,destination); return false; } }
static void KeepControlPromises(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config) { CFD_MAXPROCESSES = 30; MAXTRIES = 5; DENYBADCLOCKS = true; CFRUNCOMMAND[0] = '\0'; SetChecksumUpdatesDefault(ctx, true); /* Keep promised agent behaviour - control bodies */ Banner("Server control promises.."); PolicyResolve(ctx, policy, config); /* Now expand */ Seq *constraints = ControlBodyConstraints(policy, AGENT_TYPE_SERVER); if (constraints) { for (size_t i = 0; i < SeqLength(constraints); i++) { Constraint *cp = SeqAt(constraints, i); #define IsControlBody(e) (strcmp(cp->lval, CFS_CONTROLBODY[e].lval) == 0) if (!IsDefinedClass(ctx, cp->classes)) { continue; } VarRef *ref = VarRefParseFromScope(cp->lval, "control_server"); const void *value = EvalContextVariableGet(ctx, ref, NULL); VarRefDestroy(ref); if (!value) { Log(LOG_LEVEL_ERR, "Unknown lval '%s' in server control body", cp->lval); } else if (IsControlBody(SERVER_CONTROL_SERVER_FACILITY)) { SetFacility(value); } else if (IsControlBody(SERVER_CONTROL_DENY_BAD_CLOCKS)) { DENYBADCLOCKS = BooleanFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting denybadclocks to '%s'", DENYBADCLOCKS ? "true" : "false"); } else if (IsControlBody(SERVER_CONTROL_LOG_ENCRYPTED_TRANSFERS)) { LOGENCRYPT = BooleanFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting logencrypt to '%s'", LOGENCRYPT ? "true" : "false"); } else if (IsControlBody(SERVER_CONTROL_LOG_ALL_CONNECTIONS)) { SV.logconns = BooleanFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting logconns to %d", SV.logconns); } else if (IsControlBody(SERVER_CONTROL_MAX_CONNECTIONS)) { CFD_MAXPROCESSES = (int) IntFromString(value); MAXTRIES = CFD_MAXPROCESSES / 3; Log(LOG_LEVEL_VERBOSE, "Setting maxconnections to %d", CFD_MAXPROCESSES); /* The handling of max_readers in LMDB is not ideal, but * here is how it is right now: We know that both cf-serverd and * cf-hub will access the lastseen database. Worst case every * single thread and process will do it at the same time, and * this has in fact been observed. So we add the maximum of * those two values together to provide a safe ceiling. In * addition, cf-agent can access the database occasionally as * well, so add a few extra for that too. */ DBSetMaximumConcurrentTransactions(CFD_MAXPROCESSES + EnterpriseGetMaxCfHubProcesses() + 10); continue; } else if (IsControlBody(SERVER_CONTROL_CALL_COLLECT_INTERVAL)) { COLLECT_INTERVAL = (int) 60 * IntFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting call_collect_interval to %d (seconds)", COLLECT_INTERVAL); } else if (IsControlBody(SERVER_CONTROL_LISTEN)) { SERVER_LISTEN = BooleanFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting server listen to '%s' ", SERVER_LISTEN ? "true" : "false"); } else if (IsControlBody(SERVER_CONTROL_CALL_COLLECT_WINDOW)) { COLLECT_WINDOW = (int) IntFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting collect_window to %d (seconds)", COLLECT_INTERVAL); } else if (IsControlBody(SERVER_CONTROL_CF_RUN_COMMAND)) { strlcpy(CFRUNCOMMAND, value, sizeof(CFRUNCOMMAND)); Log(LOG_LEVEL_VERBOSE, "Setting cfruncommand to '%s'", CFRUNCOMMAND); } else if (IsControlBody(SERVER_CONTROL_ALLOW_CONNECTS)) { Log(LOG_LEVEL_VERBOSE, "Setting allowing connections from ..."); for (const Rlist *rp = value; rp != NULL; rp = rp->next) { if (!IsItemIn(SV.nonattackerlist, RlistScalarValue(rp))) { PrependItem(&SV.nonattackerlist, RlistScalarValue(rp), cp->classes); } } } else if (IsControlBody(SERVER_CONTROL_DENY_CONNECTS)) { Log(LOG_LEVEL_VERBOSE, "Setting denying connections from ..."); for (const Rlist *rp = value; rp != NULL; rp = rp->next) { if (!IsItemIn(SV.attackerlist, RlistScalarValue(rp))) { PrependItem(&SV.attackerlist, RlistScalarValue(rp), cp->classes); } } } else if (IsControlBody(SERVER_CONTROL_SKIP_VERIFY)) { /* Skip. */ } else if (IsControlBody(SERVER_CONTROL_ALLOW_ALL_CONNECTS)) { Log(LOG_LEVEL_VERBOSE, "Setting allowing multiple connections from ..."); for (const Rlist *rp = value; rp != NULL; rp = rp->next) { if (!IsItemIn(SV.multiconnlist, RlistScalarValue(rp))) { PrependItem(&SV.multiconnlist, RlistScalarValue(rp), cp->classes); } } } else if (IsControlBody(SERVER_CONTROL_ALLOW_USERS)) { Log(LOG_LEVEL_VERBOSE, "SET Allowing users ..."); for (const Rlist *rp = value; rp != NULL; rp = rp->next) { if (!IsItemIn(SV.allowuserlist, RlistScalarValue(rp))) { PrependItem(&SV.allowuserlist, RlistScalarValue(rp), cp->classes); } } } else if (IsControlBody(SERVER_CONTROL_TRUST_KEYS_FROM)) { Log(LOG_LEVEL_VERBOSE, "Setting trust keys from ..."); for (const Rlist *rp = value; rp != NULL; rp = rp->next) { if (!IsItemIn(SV.trustkeylist, RlistScalarValue(rp))) { PrependItem(&SV.trustkeylist, RlistScalarValue(rp), cp->classes); } } } else if (IsControlBody(SERVER_CONTROL_ALLOWLEGACYCONNECTS)) { Log(LOG_LEVEL_VERBOSE, "Setting allowing legacy connections from ..."); for (const Rlist *rp = value; rp != NULL; rp = rp->next) { if (!IsItemIn(SV.allowlegacyconnects, RlistScalarValue(rp))) { PrependItem(&SV.allowlegacyconnects, RlistScalarValue(rp), cp->classes); } } } else if (IsControlBody(SERVER_CONTROL_PORT_NUMBER)) { CFENGINE_PORT = IntFromString(value); strlcpy(CFENGINE_PORT_STR, value, sizeof(CFENGINE_PORT_STR)); Log(LOG_LEVEL_VERBOSE, "Setting default port number to %d", CFENGINE_PORT); } else if (IsControlBody(SERVER_CONTROL_BIND_TO_INTERFACE)) { strlcpy(BINDINTERFACE, value, sizeof(BINDINTERFACE)); Log(LOG_LEVEL_VERBOSE, "Setting bindtointerface to '%s'", BINDINTERFACE); } else if (IsControlBody(SERVER_CONTROL_ALLOWCIPHERS)) { SV.allowciphers = xstrdup(value); Log(LOG_LEVEL_VERBOSE, "Setting allowciphers to '%s'", SV.allowciphers); } #undef IsControlBody } } const void *value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_SYSLOG_HOST); if (value) { /* Don't resolve syslog_host now, better do it per log request. */ if (!SetSyslogHost(value)) { Log(LOG_LEVEL_ERR, "Failed to set syslog_host, '%s' too long", (const char *)value); } else { Log(LOG_LEVEL_VERBOSE, "Setting syslog_host to '%s'", (const char *)value); } } value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_SYSLOG_PORT); if (value) { SetSyslogPort(IntFromString(value)); } value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_FIPS_MODE); if (value) { FIPS_MODE = BooleanFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting FIPS mode to to '%s'", FIPS_MODE ? "true" : "false"); } value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_LASTSEEN_EXPIRE_AFTER); if (value) { LASTSEENEXPIREAFTER = IntFromString(value) * 60; } value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_BWLIMIT); if (value) { double bval; if (DoubleFromString(value, &bval)) { bwlimit_kbytes = (uint32_t) ( bval / 1000.0); Log(LOG_LEVEL_VERBOSE, "Setting rate limit to %d kBytes/sec", bwlimit_kbytes); } } }
SyntaxTypeMatch CheckConstraintTypeMatch(const char *lval, Rval rval, DataType dt, const char *range, int level) { Rlist *rp; Item *checklist; /* Get type of lval */ switch (rval.type) { case RVAL_TYPE_SCALAR: switch (dt) { case CF_DATA_TYPE_STRING_LIST: case CF_DATA_TYPE_INT_LIST: case CF_DATA_TYPE_REAL_LIST: case CF_DATA_TYPE_CONTEXT_LIST: case CF_DATA_TYPE_OPTION_LIST: if (level == 0) { return SYNTAX_TYPE_MATCH_ERROR_GOT_SCALAR; } break; default: /* Only lists are incompatible with scalars */ break; } break; case RVAL_TYPE_LIST: switch (dt) { case CF_DATA_TYPE_STRING_LIST: case CF_DATA_TYPE_INT_LIST: case CF_DATA_TYPE_REAL_LIST: case CF_DATA_TYPE_CONTEXT_LIST: case CF_DATA_TYPE_OPTION_LIST: break; default: return SYNTAX_TYPE_MATCH_ERROR_GOT_LIST; } for (rp = (Rlist *) rval.item; rp != NULL; rp = rp->next) { SyntaxTypeMatch err = CheckConstraintTypeMatch(lval, rp->val, dt, range, 1); switch (err) { case SYNTAX_TYPE_MATCH_OK: case SYNTAX_TYPE_MATCH_ERROR_UNEXPANDED: break; default: return err; } } return SYNTAX_TYPE_MATCH_OK; case RVAL_TYPE_FNCALL: /* Fn-like objects are assumed to be parameterized bundles in these... */ checklist = SplitString("bundlesequence,edit_line,edit_xml,usebundle,service_bundle,home_bundle", ','); if (!IsItemIn(checklist, lval)) { SyntaxTypeMatch err = CheckFnCallType(RvalFnCallValue(rval)->name, dt); DeleteItemList(checklist); return err; } DeleteItemList(checklist); return SYNTAX_TYPE_MATCH_OK; case RVAL_TYPE_CONTAINER: break; case RVAL_TYPE_NOPROMISEE: return SYNTAX_TYPE_MATCH_ERROR_GOT_NULL; } /* If we get here, we have a literal scalar type */ switch (dt) { case CF_DATA_TYPE_STRING: case CF_DATA_TYPE_STRING_LIST: return CheckParseString(lval, (const char *) rval.item, range); case CF_DATA_TYPE_INT: case CF_DATA_TYPE_INT_LIST: return CheckParseInt(lval, (const char *) rval.item, range); case CF_DATA_TYPE_REAL: case CF_DATA_TYPE_REAL_LIST: return CheckParseReal(lval, (const char *) rval.item, range); case CF_DATA_TYPE_BODY: case CF_DATA_TYPE_BUNDLE: case CF_DATA_TYPE_CONTAINER: break; case CF_DATA_TYPE_OPTION: case CF_DATA_TYPE_OPTION_LIST: return CheckParseOpts(RvalScalarValue(rval), range); case CF_DATA_TYPE_CONTEXT: case CF_DATA_TYPE_CONTEXT_LIST: return CheckParseContext((const char *) rval.item, range); case CF_DATA_TYPE_INT_RANGE: return CheckParseIntRange(lval, (const char *) rval.item, range); case CF_DATA_TYPE_REAL_RANGE: return CheckParseRealRange(lval, (char *) rval.item, range); default: ProgrammingError("Unknown (unhandled) datatype for lval = %s (CheckConstraintTypeMatch)", lval); break; } return SYNTAX_TYPE_MATCH_OK; }
void ServerEntryPoint(EvalContext *ctx, char *ipaddr, ConnectionInfo *info) { char intime[64]; time_t now; Log(LOG_LEVEL_VERBOSE, "Obtained IP address of '%s' on socket %d from accept", ipaddr, ConnectionInfoSocket(info)); if ((SV.nonattackerlist) && (!IsMatchItemIn(SV.nonattackerlist, MapAddress(ipaddr)))) { Log(LOG_LEVEL_ERR, "Not allowing connection from non-authorized IP '%s'", ipaddr); cf_closesocket(ConnectionInfoSocket(info)); ConnectionInfoDestroy(&info); return; } if (IsMatchItemIn(SV.attackerlist, MapAddress(ipaddr))) { Log(LOG_LEVEL_ERR, "Denying connection from non-authorized IP '%s'", ipaddr); cf_closesocket(ConnectionInfoSocket(info)); ConnectionInfoDestroy(&info); return; } if ((now = time((time_t *) NULL)) == -1) { now = 0; } PurgeOldConnections(&SV.connectionlist, now); if (!IsMatchItemIn(SV.multiconnlist, MapAddress(ipaddr))) { if (!ThreadLock(cft_count)) { return; } if (IsItemIn(SV.connectionlist, MapAddress(ipaddr))) { ThreadUnlock(cft_count); Log(LOG_LEVEL_ERR, "Denying repeated connection from '%s'", ipaddr); cf_closesocket(ConnectionInfoSocket(info)); ConnectionInfoDestroy(&info); return; } ThreadUnlock(cft_count); } if (SV.logconns) { Log(LOG_LEVEL_INFO, "Accepting connection from %s", ipaddr); } else { Log(LOG_LEVEL_INFO, "Accepting connection from %s", ipaddr); } snprintf(intime, 63, "%d", (int) now); if (!ThreadLock(cft_count)) { cf_closesocket(ConnectionInfoSocket(info)); ConnectionInfoDestroy(&info); return; } PrependItem(&SV.connectionlist, MapAddress(ipaddr), intime); if (!ThreadUnlock(cft_count)) { cf_closesocket(ConnectionInfoSocket(info)); ConnectionInfoDestroy(&info); return; } SpawnConnection(ctx, ipaddr, info); }
static void KeepControlPromises(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config) { CFD_MAXPROCESSES = 30; MAXTRIES = 5; DENYBADCLOCKS = true; CFRUNCOMMAND[0] = '\0'; SetChecksumUpdatesDefault(ctx, true); /* Keep promised agent behaviour - control bodies */ Banner("Server control promises.."); PolicyResolve(ctx, policy, config); /* Now expand */ Seq *constraints = ControlBodyConstraints(policy, AGENT_TYPE_SERVER); if (constraints) { for (size_t i = 0; i < SeqLength(constraints); i++) { Constraint *cp = SeqAt(constraints, i); if (!IsDefinedClass(ctx, cp->classes)) { continue; } VarRef *ref = VarRefParseFromScope(cp->lval, "control_server"); const void *value = EvalContextVariableGet(ctx, ref, NULL); VarRefDestroy(ref); if (!value) { Log(LOG_LEVEL_ERR, "Unknown lval '%s' in server control body", cp->lval); continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_SERVER_FACILITY].lval) == 0) { SetFacility(value); continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_DENY_BAD_CLOCKS].lval) == 0) { DENYBADCLOCKS = BooleanFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting denybadclocks to '%s'", DENYBADCLOCKS ? "true" : "false"); continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_LOG_ENCRYPTED_TRANSFERS].lval) == 0) { LOGENCRYPT = BooleanFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting logencrypt to '%s'", LOGENCRYPT ? "true" : "false"); continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_LOG_ALL_CONNECTIONS].lval) == 0) { SV.logconns = BooleanFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting logconns to %d", SV.logconns); continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_MAX_CONNECTIONS].lval) == 0) { CFD_MAXPROCESSES = (int) IntFromString(value); MAXTRIES = CFD_MAXPROCESSES / 3; Log(LOG_LEVEL_VERBOSE, "Setting maxconnections to %d", CFD_MAXPROCESSES); #ifdef LMDB static int LSD_MAXREADERS = 0; if (LSD_MAXREADERS < CFD_MAXPROCESSES) { int rc = UpdateLastSeenMaxReaders(CFD_MAXPROCESSES); if (rc == 0) { LSD_MAXREADERS = CFD_MAXPROCESSES; } } #endif continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_CALL_COLLECT_INTERVAL].lval) == 0) { COLLECT_INTERVAL = (int) 60 * IntFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting call_collect_interval to %d (seconds)", COLLECT_INTERVAL); continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_LISTEN].lval) == 0) { SERVER_LISTEN = BooleanFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting server listen to '%s' ", (SERVER_LISTEN)? "true":"false"); continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_CALL_COLLECT_WINDOW].lval) == 0) { COLLECT_WINDOW = (int) IntFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting collect_window to %d (seconds)", COLLECT_INTERVAL); continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_CF_RUN_COMMAND].lval) == 0) { strlcpy(CFRUNCOMMAND, value, sizeof(CFRUNCOMMAND)); Log(LOG_LEVEL_VERBOSE, "Setting cfruncommand to '%s'", CFRUNCOMMAND); continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_ALLOW_CONNECTS].lval) == 0) { Log(LOG_LEVEL_VERBOSE, "Setting allowing connections from ..."); for (const Rlist *rp = value; rp != NULL; rp = rp->next) { if (!IsItemIn(SV.nonattackerlist, RlistScalarValue(rp))) { AppendItem(&SV.nonattackerlist, RlistScalarValue(rp), cp->classes); } } continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_DENY_CONNECTS].lval) == 0) { Log(LOG_LEVEL_VERBOSE, "Setting denying connections from ..."); for (const Rlist *rp = value; rp != NULL; rp = rp->next) { if (!IsItemIn(SV.attackerlist, RlistScalarValue(rp))) { AppendItem(&SV.attackerlist, RlistScalarValue(rp), cp->classes); } } continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_SKIP_VERIFY].lval) == 0) { continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_ALLOW_ALL_CONNECTS].lval) == 0) { Log(LOG_LEVEL_VERBOSE, "Setting allowing multiple connections from ..."); for (const Rlist *rp = value; rp != NULL; rp = rp->next) { if (!IsItemIn(SV.multiconnlist, RlistScalarValue(rp))) { AppendItem(&SV.multiconnlist, RlistScalarValue(rp), cp->classes); } } continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_ALLOW_USERS].lval) == 0) { Log(LOG_LEVEL_VERBOSE, "SET Allowing users ..."); for (const Rlist *rp = value; rp != NULL; rp = rp->next) { if (!IsItemIn(SV.allowuserlist, RlistScalarValue(rp))) { AppendItem(&SV.allowuserlist, RlistScalarValue(rp), cp->classes); } } continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_TRUST_KEYS_FROM].lval) == 0) { Log(LOG_LEVEL_VERBOSE, "Setting trust keys from ..."); for (const Rlist *rp = value; rp != NULL; rp = rp->next) { if (!IsItemIn(SV.trustkeylist, RlistScalarValue(rp))) { AppendItem(&SV.trustkeylist, RlistScalarValue(rp), cp->classes); } } continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_ALLOWLEGACYCONNECTS].lval) == 0) { Log(LOG_LEVEL_VERBOSE, "Setting allowing legacy connections from ..."); for (const Rlist *rp = value; rp != NULL; rp = rp->next) { if (!IsItemIn(SV.allowlegacyconnects, RlistScalarValue(rp))) { AppendItem(&SV.allowlegacyconnects, RlistScalarValue(rp), cp->classes); } } continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_PORT_NUMBER].lval) == 0) { CFENGINE_PORT = IntFromString(value); strlcpy(CFENGINE_PORT_STR, value, sizeof(CFENGINE_PORT_STR)); Log(LOG_LEVEL_VERBOSE, "Setting default port number to %d", CFENGINE_PORT); continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_BIND_TO_INTERFACE].lval) == 0) { strlcpy(BINDINTERFACE, value, sizeof(BINDINTERFACE)); Log(LOG_LEVEL_VERBOSE, "Setting bindtointerface to '%s'", BINDINTERFACE); continue; } if (strcmp(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_ALLOWCIPHERS].lval) == 0) { SV.allowciphers = xstrdup(value); Log(LOG_LEVEL_VERBOSE, "Setting allowciphers to '%s'", SV.allowciphers); continue; } } } const void *value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_SYSLOG_HOST); if (value) { /* Don't resolve syslog_host now, better do it per log request. */ if (!SetSyslogHost(value)) { Log(LOG_LEVEL_ERR, "Failed to set syslog_host, '%s' too long", (const char *)value); } else { Log(LOG_LEVEL_VERBOSE, "Setting syslog_host to '%s'", (const char *)value); } } value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_SYSLOG_PORT); if (value) { SetSyslogPort(IntFromString(value)); } value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_FIPS_MODE); if (value) { FIPS_MODE = BooleanFromString(value); Log(LOG_LEVEL_VERBOSE, "Setting FIPS mode to to '%s'", FIPS_MODE ? "true" : "false"); } value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_LASTSEEN_EXPIRE_AFTER); if (value) { LASTSEENEXPIREAFTER = IntFromString(value) * 60; } }
void NoteClassUsage(AlphaList baselist, int purge) { CF_DB *dbp; CF_DBC *dbcp; void *stored; char *key; int ksize, vsize; Event e, entry, newe; double lsea = SECONDS_PER_WEEK * 52; /* expire after (about) a year */ time_t now = time(NULL); Item *list = NULL; const Item *ip; double lastseen; double vtrue = 1.0; /* end with a rough probability */ /* Only do this for the default policy, too much "downgrading" otherwise */ if (MINUSF) { return; } AlphaListIterator it = AlphaListIteratorInit(&baselist); for (ip = AlphaListIteratorNext(&it); ip != NULL; ip = AlphaListIteratorNext(&it)) { if ((IGNORECLASS(ip->name))) { CfDebug("Ignoring class %s (not packing)", ip->name); continue; } IdempPrependItem(&list, ip->name, NULL); } if (!OpenDB(&dbp, dbid_classes)) { return; } /* First record the classes that are in use */ for (ip = list; ip != NULL; ip = ip->next) { if (ReadDB(dbp, ip->name, &e, sizeof(e))) { CfDebug("FOUND %s with %lf\n", ip->name, e.Q.expect); lastseen = now - e.t; newe.t = now; newe.Q = QAverage(e.Q, vtrue, 0.7); } else { lastseen = 0.0; newe.t = now; /* With no data it's 50/50 what we can say */ newe.Q = QDefinite(0.5 * vtrue); } if (lastseen > lsea) { CfDebug("Class usage record %s expired\n", ip->name); DeleteDB(dbp, ip->name); } else { WriteDB(dbp, ip->name, &newe, sizeof(newe)); } } /* Then update with zero the ones we know about that are not active */ if (purge) { /* Acquire a cursor for the database and downgrade classes that did not get defined this time*/ if (!NewDBCursor(dbp, &dbcp)) { CfOut(cf_inform, "", " !! Unable to scan class db"); CloseDB(dbp); DeleteItemList(list); return; } memset(&entry, 0, sizeof(entry)); while (NextDB(dbp, dbcp, &key, &ksize, &stored, &vsize)) { time_t then; char eventname[CF_BUFSIZE]; memset(eventname, 0, CF_BUFSIZE); strncpy(eventname, (char *) key, ksize); if (stored != NULL) { memcpy(&entry, stored, sizeof(entry)); then = entry.t; lastseen = now - then; if (lastseen > lsea) { CfDebug("Class usage record %s expired\n", eventname); DBCursorDeleteEntry(dbcp); } else if (!IsItemIn(list, eventname)) { newe.t = then; newe.Q = QAverage(entry.Q, 0, 0.5); if (newe.Q.expect <= 0.0001) { CfDebug("Deleting class %s as %lf is zero\n", eventname, newe.Q.expect); DBCursorDeleteEntry(dbcp); } else { CfDebug("Downgrading class %s from %lf to %lf\n", eventname, entry.Q.expect, newe.Q.expect); DBCursorWriteEntry(dbcp, &newe, sizeof(newe)); } } } } DeleteDBCursor(dbp, dbcp); } CloseDB(dbp); DeleteItemList(list); }
void RotateFiles(char *name, int number) { int i, fd; struct stat statbuf; char from[CF_BUFSIZE], to[CF_BUFSIZE]; if (IsItemIn(ROTATED, name)) { return; } PrependItem(&ROTATED, name, NULL); if (stat(name, &statbuf) == -1) { Log(LOG_LEVEL_VERBOSE, "No access to file %s", name); return; } for (i = number - 1; i > 0; i--) { snprintf(from, CF_BUFSIZE, "%s.%d", name, i); snprintf(to, CF_BUFSIZE, "%s.%d", name, i + 1); if (rename(from, to) == -1) { Log(LOG_LEVEL_DEBUG, "Rename failed in RotateFiles '%s' -> '%s'", name, from); } snprintf(from, CF_BUFSIZE, "%s.%d.gz", name, i); snprintf(to, CF_BUFSIZE, "%s.%d.gz", name, i + 1); if (rename(from, to) == -1) { Log(LOG_LEVEL_DEBUG, "Rename failed in RotateFiles '%s' -> '%s'", name, from); } snprintf(from, CF_BUFSIZE, "%s.%d.Z", name, i); snprintf(to, CF_BUFSIZE, "%s.%d.Z", name, i + 1); if (rename(from, to) == -1) { Log(LOG_LEVEL_DEBUG, "Rename failed in RotateFiles '%s' -> '%s'", name, from); } snprintf(from, CF_BUFSIZE, "%s.%d.bz", name, i); snprintf(to, CF_BUFSIZE, "%s.%d.bz", name, i + 1); if (rename(from, to) == -1) { Log(LOG_LEVEL_DEBUG, "Rename failed in RotateFiles '%s' -> '%s'", name, from); } snprintf(from, CF_BUFSIZE, "%s.%d.bz2", name, i); snprintf(to, CF_BUFSIZE, "%s.%d.bz2", name, i + 1); if (rename(from, to) == -1) { Log(LOG_LEVEL_DEBUG, "Rename failed in RotateFiles '%s' -> '%s'", name, from); } } snprintf(to, CF_BUFSIZE, "%s.1", name); if (CopyRegularFileDisk(name, to) == false) { Log(LOG_LEVEL_DEBUG, "Copy failed in RotateFiles '%s' -> '%s'", name, to); return; } safe_chmod(to, statbuf.st_mode); if (safe_chown(to, statbuf.st_uid, statbuf.st_gid)) { UnexpectedError("Failed to chown %s", to); } safe_chmod(name, 0600); /* File must be writable to empty .. */ if ((fd = safe_creat(name, statbuf.st_mode)) == -1) { Log(LOG_LEVEL_ERR, "Failed to create new '%s' in disable(rotate). (creat: %s)", name, GetErrorStr()); } else { if (safe_chown(name, statbuf.st_uid, statbuf.st_gid)) /* NT doesn't have fchown */ { UnexpectedError("Failed to chown '%s'", name); } fchmod(fd, statbuf.st_mode); close(fd); } }
int ConsiderFile(const char *nodename, char *path, Attributes attr, Promise *pp) { int i; struct stat statbuf; char vbuff[CF_BUFSIZE]; const char *sp; static char *skipfiles[] = { ".", "..", "lost+found", ".cfengine.rm", NULL }; if (strlen(nodename) < 1) { CfOut(cf_error, "", "Empty (null) filename detected in %s\n", path); return true; } if (IsItemIn(SUSPICIOUSLIST, nodename)) { struct stat statbuf; if (cfstat(nodename, &statbuf) != -1) { if (S_ISREG(statbuf.st_mode)) { CfOut(cf_error, "", "Suspicious file %s found in %s\n", nodename, path); return false; } } } if (strcmp(nodename, "...") == 0) { CfOut(cf_verbose, "", "Possible DFS/FS cell node detected in %s...\n", path); return true; } for (i = 0; skipfiles[i] != NULL; i++) { if (strcmp(nodename, skipfiles[i]) == 0) { CfDebug("Filename %s/%s is classified as ignorable\n", path, nodename); return false; } } if ((strcmp("[", nodename) == 0) && (strcmp("/usr/bin", path) == 0)) { if (VSYSTEMHARDCLASS == linuxx) { return true; } } for (sp = nodename; *sp != '\0'; sp++) { if ((*sp > 31) && (*sp < 127)) { break; } } strcpy(vbuff, path); AddSlash(vbuff); strcat(vbuff, nodename); for (sp = nodename; *sp != '\0'; sp++) /* Check for files like ".. ." */ { if ((*sp != '.') && !isspace(*sp)) { return true; } } if (cf_lstat(vbuff, &statbuf, attr, pp) == -1) { CfOut(cf_verbose, "lstat", "Couldn't stat %s", vbuff); return true; } if (statbuf.st_size == 0 && !(VERBOSE || INFORM)) /* No sense in warning about empty files */ { return false; } CfOut(cf_error, "", "Suspicious looking file object \"%s\" masquerading as hidden file in %s\n", nodename, path); CfDebug("Filename looks suspicious\n"); if (S_ISLNK(statbuf.st_mode)) { CfOut(cf_inform, "", " %s is a symbolic link\n", nodename); } else if (S_ISDIR(statbuf.st_mode)) { CfOut(cf_inform, "", " %s is a directory\n", nodename); } CfOut(cf_verbose, "", "[%s] has size %ld and full mode %o\n", nodename, (unsigned long) (statbuf.st_size), (unsigned int) (statbuf.st_mode)); return true; }