Item *SelectProcesses(EvalContext *ctx, const Item *processes, const char *process_name, ProcessSelect a, bool attrselect) { Item *result = NULL; if (processes == NULL) { return result; } char *names[CF_PROCCOLS]; int start[CF_PROCCOLS]; int end[CF_PROCCOLS]; GetProcessColumnNames(processes->name, &names[0], start, end); for (Item *ip = processes->next; ip != NULL; ip = ip->next) { int s, e; if (BlockTextMatch(ctx, process_name, ip->name, &s, &e)) { if (NULL_OR_EMPTY(ip->name)) { continue; } if (attrselect && !SelectProcess(ctx, ip->name, names, start, end, a)) { continue; } pid_t pid = ExtractPid(ip->name, names, end); if (pid == -1) { Log(LOG_LEVEL_VERBOSE, "Unable to extract pid while looking for %s", process_name); continue; } PrependItem(&result, ip->name, ""); result->counter = (int)pid; } } for (int i = 0; i < CF_PROCCOLS; i++) { free(names[i]); } return result; }
Item *SelectProcesses(const char *process_name, const ProcessSelect *a, bool attrselect) { assert(a != NULL); const Item *processes = PROCESSTABLE; Item *result = NULL; if (processes == NULL) { return result; } char *names[CF_PROCCOLS]; int start[CF_PROCCOLS]; int end[CF_PROCCOLS]; GetProcessColumnNames(processes->name, names, start, end); /* TODO: use actual time of ps-run, as time(NULL) may be later. */ time_t pstime = time(NULL); for (Item *ip = processes->next; ip != NULL; ip = ip->next) { if (NULL_OR_EMPTY(ip->name)) { continue; } if (!SelectProcess(ip->name, pstime, names, start, end, process_name, a, attrselect)) { continue; } pid_t pid = ExtractPid(ip->name, names, end); if (pid == -1) { Log(LOG_LEVEL_VERBOSE, "Unable to extract pid while looking for %s", process_name); continue; } PrependItem(&result, ip->name, ""); result->counter = (int)pid; } for (int i = 0; i < CF_PROCCOLS; i++) { free(names[i]); } return result; }
static void KeepServerRolePromise(struct Promise *pp) { struct Constraint *cp; struct Rlist *rp; struct Auth *ap; if (!GetAuthPath(pp->promiser,ROLES)) { InstallServerAuthPath(pp->promiser,&ROLES,&ROLESTOP); } ap = GetAuthPath(pp->promiser,ROLES); for (cp = pp->conlist; cp != NULL; cp = cp->next) { if (!IsDefinedClass(cp->classes)) { continue; } switch (cp->type) { case CF_LIST: for (rp = (struct Rlist *)cp->rval; rp != NULL; rp=rp->next) { if (strcmp(cp->lval,CF_REMROLE_BODIES[cfs_authorize].lval) == 0) { PrependItem(&(ap->accesslist),rp->item,NULL); continue; } } break; case CF_FNCALL: /* Shouldn't happen */ break; default: if (strcmp(cp->lval,"comment") == 0 || strcmp(cp->lval,"handle") == 0) { } else { CfOut(cf_error,"","RHS of authorize promise for %s should be a list\n",pp->promiser); } break; } } }
Item *IdempPrependItemClass(Item **liststart, const char *itemstring, const char *classes) { Item *ip; ip = ReturnItemInClass(*liststart, itemstring, classes); if (ip) // already exists { return ip; } PrependItem(liststart, itemstring, classes); return *liststart; }
Item *IdempPrependItem(Item **liststart, const char *itemstring, const char *classes) { Item *ip; ip = ReturnItemIn(*liststart, itemstring); if (ip) { return ip; } PrependItem(liststart, itemstring, classes); return *liststart; }
void IdempItemCount(Item **liststart, const char *itemstring, const char *classes) { Item *ip = ReturnItemIn(*liststart, itemstring); if (ip) { ip->counter++; } else { PrependItem(liststart, itemstring, classes); } // counter+1 is the histogram of occurrences }
static void KeepServerRolePromise(EvalContext *ctx, const Promise *pp) { Rlist *rp; Auth *ap; ap = GetOrCreateAuth(pp->promiser, &SV.roles, &SV.rolestail); for (size_t i = 0; i < SeqLength(pp->conlist); i++) { Constraint *cp = SeqAt(pp->conlist, i); if (!IsDefinedClass(ctx, cp->classes)) { continue; } switch (cp->rval.type) { case RVAL_TYPE_LIST: for (rp = (Rlist *) cp->rval.item; rp != NULL; rp = rp->next) { /* This is for remote class activation by means of cf-runagent.*/ if (strcmp(cp->lval, CF_REMROLE_BODIES[REMOTE_ROLE_AUTHORIZE].lval) == 0) { PrependItem(&(ap->accesslist), RlistScalarValue(rp), NULL); continue; } } break; case RVAL_TYPE_FNCALL: UnexpectedError("Constraint of type FNCALL is invalid in this context!"); break; default: if ((strcmp(cp->lval, "comment") == 0) || (strcmp(cp->lval, "handle") == 0)) { } else { Log(LOG_LEVEL_ERR, "Right-hand side of authorize promise for '%s' should be a list", pp->promiser); } break; } } }
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; }
void JXPathHistoryMenu::UpdateMenu() { if (GetFirstIndex() == 1) { JMountPointList list(JPtrArrayT::kDeleteAll); time_t t; if (JGetUserMountPointList(&list, &t)) { const JSize count = list.GetElementCount(); SetFirstIndex(count+1); for (JIndex i=count; i>=1; i--) { const JMountPoint mp = list.GetElement(i); PrependItem(*(mp.path)); if (i == count) { ShowSeparatorAfter(1); } if (mp.type == kJHardDisk) { SetItemImage(1, jx_hard_disk_small); } else if (mp.type == kJZipDisk) { SetItemImage(1, jx_zip_disk_small); } else if (mp.type == kJFloppyDisk) { SetItemImage(1, jx_floppy_disk_small); } else if (mp.type == kJCDROM) { SetItemImage(1, jx_cdrom_disk_small); } } } } RemoveInvalidPaths(); JXStringHistoryMenu::UpdateMenu(); }
bool CocaSystemTree::moveUp( const coca::INode& node ) { wxTreeItemId id = findId( node ); if ( !id.IsOk() ) { return false; } wxTreeItemId parentId = GetItemParent( id ); if ( !parentId.IsOk() ) { return false; } wxTreeItemId previousId = GetPrevSibling( id ); if ( !previousId.IsOk() ) { return false; } // ready to move bool wasSelected = ( id == GetSelection() ); Delete( id ); previousId = GetPrevSibling( previousId ); if ( !previousId.IsOk() ) { id = PrependItem( parentId, EditorTools::getName( node ), EditorTools::getImageIndex( node ), -1, new ItemData( node ) ); } else { id = InsertItem( parentId, previousId, EditorTools::getName( node ), EditorTools::getImageIndex( node ), -1, new ItemData( node ) ); } COCA_ASSERT( id.IsOk() ); SetItemTextColour( id, EditorTools::getTextColour( node ) ); addChildren( node, id ); if ( wasSelected ) { SelectItem( id ); } return true; }
static void KeepServerRolePromise(EvalContext *ctx, const Promise *pp) { Auth *ap = GetOrCreateAuth(pp->promiser, &SV.roles, &SV.rolestail); const char *const authorizer = CF_REMROLE_BODIES[REMOTE_ROLE_AUTHORIZE].lval; size_t i = SeqLength(pp->conlist); while (i > 0) { i--; Constraint *cp = SeqAt(pp->conlist, i); if (strcmp(cp->lval, authorizer) == 0) { if (cp->rval.type != RVAL_TYPE_LIST) { Log(LOG_LEVEL_ERR, "Right-hand side of authorize promise for '%s' should be a list", pp->promiser); } else if (IsDefinedClass(ctx, cp->classes)) { /* This is for remote class activation by means of cf-runagent.*/ for (const Rlist *rp = cp->rval.item; rp != NULL; rp = rp->next) { PrependItem(&(ap->accesslist), RlistScalarValue(rp), NULL); } } } else if (strcmp(cp->lval, "comment") != 0 && strcmp(cp->lval, "handle") != 0 && /* Are there other known list constraints ? if not, skip this: */ cp->rval.type != RVAL_TYPE_LIST) { Log(LOG_LEVEL_WARNING, "Unrecognised promise '%s' for %s", cp->lval, pp->promiser); } } }
Item *SplitStringAsItemList(const char *string, char sep) /* Splits a string containing a separator like : into a linked list of separate items, */ { Item *liststart = NULL; char node[256]; char format[] = "%255[^\0]"; /* Overwrite format's internal \0 with sep: */ format[strlen(format)] = sep; assert(strlen(format) + 1 == sizeof(format) || sep == '\0'); for (const char *sp = string; *sp != '\0'; sp++) { if (sscanf(sp, format, node) == 1 && node[0] != '\0') { sp += strlen(node) - 1; PrependItem(&liststart, node, NULL); } } return ReverseItemList(liststart); }
static bool GetLMSensors(double *cf_this) { FILE *pp; Item *ip, *list = NULL; double temp = 0; char name[CF_BUFSIZE]; int count; cf_this[ob_temp0] = 0.0; cf_this[ob_temp1] = 0.0; cf_this[ob_temp2] = 0.0; cf_this[ob_temp3] = 0.0; if ((pp = cf_popen("/usr/bin/sensors", "r", true)) == NULL) { LMSENSORS = false; /* Broken */ return false; } { size_t vbuff_size = CF_BUFSIZE; char *vbuff = xmalloc(vbuff_size); ssize_t res = CfReadLine(&vbuff, &vbuff_size, pp); if (res <= 0) { /* FIXME: do we need to log anything here? */ cf_pclose(pp); free(vbuff); return false; } for (;;) { ssize_t res = CfReadLine(&vbuff, &vbuff_size, pp); if (res == -1) { if (!feof(pp)) { /* FIXME: Do we need to log anything here? */ cf_pclose(pp); free(vbuff); return false; } else { break; } } if (strstr(vbuff, "Temp") || strstr(vbuff, "temp")) { PrependItem(&list, vbuff, NULL); } } cf_pclose(pp); free(vbuff); } if (ListLen(list) > 0) { Log(LOG_LEVEL_DEBUG, "LM Sensors seemed to return ok data"); } else { return false; } /* lmsensor names are hopelessly inconsistent - so try a few things */ for (ip = list; ip != NULL; ip = ip->next) { for (count = 0; count < 4; count++) { snprintf(name, 16, "CPU%d Temp:", count); if (strncmp(ip->name, name, strlen(name)) == 0) { sscanf(ip->name, "%*[^:]: %lf", &temp); switch (count) { case 0: cf_this[ob_temp0] = temp; break; case 1: cf_this[ob_temp1] = temp; break; case 2: cf_this[ob_temp2] = temp; break; case 3: cf_this[ob_temp3] = temp; break; } Log(LOG_LEVEL_DEBUG, "Set temp%d to %lf from what looks like cpu temperature", count, temp); } } } if (cf_this[ob_temp0] != 0) { /* We got something plausible */ return true; } /* Alternative name Core x: */ for (ip = list; ip != NULL; ip = ip->next) { for (count = 0; count < 4; count++) { snprintf(name, 16, "Core %d:", count); if (strncmp(ip->name, name, strlen(name)) == 0) { sscanf(ip->name, "%*[^:]: %lf", &temp); switch (count) { case 0: cf_this[ob_temp0] = temp; break; case 1: cf_this[ob_temp1] = temp; break; case 2: cf_this[ob_temp2] = temp; break; case 3: cf_this[ob_temp3] = temp; break; } Log(LOG_LEVEL_DEBUG, "Set temp%d to %lf from what looks like core temperatures", count, temp); } } } if (cf_this[ob_temp0] != 0) { /* We got something plausible */ return true; } for (ip = list; ip != NULL; ip = ip->next) { if (strncmp(ip->name, "CPU Temp:", strlen("CPU Temp:")) == 0) { sscanf(ip->name, "%*[^:]: %lf", &temp); Log(LOG_LEVEL_DEBUG, "Setting temp0 to CPU Temp"); cf_this[ob_temp0] = temp; } if (strncmp(ip->name, "M/B Temp:", strlen("M/B Temp:")) == 0) { sscanf(ip->name, "%*[^:]: %lf", &temp); Log(LOG_LEVEL_DEBUG, "Setting temp0 to M/B Temp"); cf_this[ob_temp1] = temp; } if (strncmp(ip->name, "Sys Temp:", strlen("Sys Temp:")) == 0) { sscanf(ip->name, "%*[^:]: %lf", &temp); Log(LOG_LEVEL_DEBUG, "Setting temp0 to Sys Temp"); cf_this[ob_temp2] = temp; } if (strncmp(ip->name, "AUX Temp:", strlen("AUX Temp:")) == 0) { sscanf(ip->name, "%*[^:]: %lf", &temp); Log(LOG_LEVEL_DEBUG, "Setting temp0 to AUX Temp"); cf_this[ob_temp3] = temp; } } if (cf_this[ob_temp0] != 0) { /* We got something plausible */ return true; } /* Alternative name Core x: */ for (ip = list; ip != NULL; ip = ip->next) { for (count = 0; count < 4; count++) { snprintf(name, 16, "temp%d:", count); if (strncmp(ip->name, name, strlen(name)) == 0) { sscanf(ip->name, "%*[^:]: %lf", &temp); switch (count) { case 0: cf_this[ob_temp0] = temp; break; case 1: cf_this[ob_temp1] = temp; break; case 2: cf_this[ob_temp2] = temp; break; case 3: cf_this[ob_temp3] = temp; break; } Log(LOG_LEVEL_DEBUG, "Set temp%d to %lf", count, temp); } } } /* Give up? */ DeleteItemList(list); return true; }
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); }
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); } }
void KeepControlPromises(Policy *policy) { Rval retval; Rlist *rp; Seq *constraints = ControlBodyConstraints(policy, AGENT_TYPE_AGENT); if (constraints) { for (size_t i = 0; i < SeqLength(constraints); i++) { Constraint *cp = SeqAt(constraints, i); if (IsExcluded(cp->classes, NULL)) { continue; } if (GetVariable("control_common", cp->lval, &retval) != DATA_TYPE_NONE) { /* Already handled in generic_agent */ continue; } if (GetVariable("control_agent", cp->lval, &retval) == DATA_TYPE_NONE) { CfOut(cf_error, "", "Unknown lval %s in agent control body", cp->lval); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_maxconnections].lval) == 0) { CFA_MAXTHREADS = (int) Str2Int(retval.item); CfOut(cf_verbose, "", "SET maxconnections = %d\n", CFA_MAXTHREADS); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_checksum_alert_time].lval) == 0) { CF_PERSISTENCE = (int) Str2Int(retval.item); CfOut(cf_verbose, "", "SET checksum_alert_time = %d\n", CF_PERSISTENCE); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_agentfacility].lval) == 0) { SetFacility(retval.item); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_agentaccess].lval) == 0) { ACCESSLIST = (Rlist *) retval.item; CheckAgentAccess(ACCESSLIST, InputFiles(policy)); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_refresh_processes].lval) == 0) { Rlist *rp; if (VERBOSE) { printf("%s> SET refresh_processes when starting: ", VPREFIX); for (rp = (Rlist *) retval.item; rp != NULL; rp = rp->next) { printf(" %s", (char *) rp->item); PrependItem(&PROCESSREFRESH, rp->item, NULL); } printf("\n"); } continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_abortclasses].lval) == 0) { Rlist *rp; CfOut(cf_verbose, "", "SET Abort classes from ...\n"); for (rp = (Rlist *) retval.item; rp != NULL; rp = rp->next) { char name[CF_MAXVARSIZE] = ""; strncpy(name, rp->item, CF_MAXVARSIZE - 1); AddAbortClass(name, cp->classes); } continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_abortbundleclasses].lval) == 0) { Rlist *rp; CfOut(cf_verbose, "", "SET Abort bundle classes from ...\n"); for (rp = (Rlist *) retval.item; rp != NULL; rp = rp->next) { char name[CF_MAXVARSIZE] = ""; strncpy(name, rp->item, CF_MAXVARSIZE - 1); if (!IsItemIn(ABORTBUNDLEHEAP, name)) { AppendItem(&ABORTBUNDLEHEAP, name, cp->classes); } } continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_addclasses].lval) == 0) { Rlist *rp; CfOut(cf_verbose, "", "-> Add classes ...\n"); for (rp = (Rlist *) retval.item; rp != NULL; rp = rp->next) { CfOut(cf_verbose, "", " -> ... %s\n", ScalarValue(rp)); NewClass(rp->item, NULL); } continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_auditing].lval) == 0) { CfOut(cf_verbose, "", "This option does nothing and is retained for compatibility reasons"); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_alwaysvalidate].lval) == 0) { ALWAYS_VALIDATE = GetBoolean(retval.item); CfOut(cf_verbose, "", "SET alwaysvalidate = %d\n", ALWAYS_VALIDATE); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_allclassesreport].lval) == 0) { ALLCLASSESREPORT = GetBoolean(retval.item); CfOut(cf_verbose, "", "SET allclassesreport = %d\n", ALLCLASSESREPORT); } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_secureinput].lval) == 0) { CFPARANOID = GetBoolean(retval.item); CfOut(cf_verbose, "", "SET secure input = %d\n", CFPARANOID); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_binarypaddingchar].lval) == 0) { CfOut(cf_verbose, "", "binarypaddingchar is obsolete and does nothing\n"); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_bindtointerface].lval) == 0) { strncpy(BINDINTERFACE, retval.item, CF_BUFSIZE - 1); CfOut(cf_verbose, "", "SET bindtointerface = %s\n", BINDINTERFACE); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_hashupdates].lval) == 0) { bool enabled = GetBoolean(retval.item); SetChecksumUpdates(enabled); CfOut(cf_verbose, "", "SET ChecksumUpdates %d\n", enabled); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_exclamation].lval) == 0) { CfOut(cf_verbose, "", "exclamation control is deprecated and does not do anything\n"); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_childlibpath].lval) == 0) { char output[CF_BUFSIZE]; snprintf(output, CF_BUFSIZE, "LD_LIBRARY_PATH=%s", (char *) retval.item); if (putenv(xstrdup(output)) == 0) { CfOut(cf_verbose, "", "Setting %s\n", output); } continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_defaultcopytype].lval) == 0) { DEFAULT_COPYTYPE = (char *) retval.item; CfOut(cf_verbose, "", "SET defaultcopytype = %s\n", DEFAULT_COPYTYPE); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_fsinglecopy].lval) == 0) { SINGLE_COPY_LIST = (Rlist *) retval.item; CfOut(cf_verbose, "", "SET file single copy list\n"); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_fautodefine].lval) == 0) { SetFileAutoDefineList(ListRvalValue(retval)); CfOut(cf_verbose, "", "SET file auto define list\n"); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_dryrun].lval) == 0) { DONTDO = GetBoolean(retval.item); CfOut(cf_verbose, "", "SET dryrun = %c\n", DONTDO); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_inform].lval) == 0) { INFORM = GetBoolean(retval.item); CfOut(cf_verbose, "", "SET inform = %c\n", INFORM); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_verbose].lval) == 0) { VERBOSE = GetBoolean(retval.item); CfOut(cf_verbose, "", "SET inform = %c\n", VERBOSE); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_repository].lval) == 0) { SetRepositoryLocation(retval.item); CfOut(cf_verbose, "", "SET repository = %s\n", ScalarRvalValue(retval)); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_skipidentify].lval) == 0) { bool enabled = GetBoolean(retval.item); SetSkipIdentify(enabled); CfOut(cf_verbose, "", "SET skipidentify = %d\n", (int) enabled); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_suspiciousnames].lval) == 0) { for (rp = (Rlist *) retval.item; rp != NULL; rp = rp->next) { AddFilenameToListOfSuspicious(ScalarValue(rp)); CfOut(cf_verbose, "", "-> Considering %s as suspicious file", ScalarValue(rp)); } continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_repchar].lval) == 0) { char c = *(char *) retval.item; SetRepositoryChar(c); CfOut(cf_verbose, "", "SET repchar = %c\n", c); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_mountfilesystems].lval) == 0) { CF_MOUNTALL = GetBoolean(retval.item); CfOut(cf_verbose, "", "SET mountfilesystems = %d\n", CF_MOUNTALL); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_editfilesize].lval) == 0) { EDITFILESIZE = Str2Int(retval.item); CfOut(cf_verbose, "", "SET EDITFILESIZE = %d\n", EDITFILESIZE); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_ifelapsed].lval) == 0) { VIFELAPSED = Str2Int(retval.item); CfOut(cf_verbose, "", "SET ifelapsed = %d\n", VIFELAPSED); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_expireafter].lval) == 0) { VEXPIREAFTER = Str2Int(retval.item); CfOut(cf_verbose, "", "SET ifelapsed = %d\n", VEXPIREAFTER); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_timeout].lval) == 0) { CONNTIMEOUT = Str2Int(retval.item); CfOut(cf_verbose, "", "SET timeout = %jd\n", (intmax_t) CONNTIMEOUT); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_max_children].lval) == 0) { CFA_BACKGROUND_LIMIT = Str2Int(retval.item); CfOut(cf_verbose, "", "SET MAX_CHILDREN = %d\n", CFA_BACKGROUND_LIMIT); if (CFA_BACKGROUND_LIMIT > 10) { CfOut(cf_error, "", "Silly value for max_children in agent control promise (%d > 10)", CFA_BACKGROUND_LIMIT); CFA_BACKGROUND_LIMIT = 1; } continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_syslog].lval) == 0) { CfOut(cf_verbose, "", "SET syslog = %d\n", GetBoolean(retval.item)); continue; } if (strcmp(cp->lval, CFA_CONTROLBODY[cfa_environment].lval) == 0) { Rlist *rp; CfOut(cf_verbose, "", "SET environment variables from ...\n"); for (rp = (Rlist *) retval.item; rp != NULL; rp = rp->next) { if (putenv(rp->item) != 0) { CfOut(cf_error, "putenv", "Failed to set environment variable %s", ScalarValue(rp)); } } continue; } } } if (GetVariable("control_common", CFG_CONTROLBODY[cfg_lastseenexpireafter].lval, &retval) != DATA_TYPE_NONE) { LASTSEENEXPIREAFTER = Str2Int(retval.item) * 60; } if (GetVariable("control_common", CFG_CONTROLBODY[cfg_fips_mode].lval, &retval) != DATA_TYPE_NONE) { FIPS_MODE = GetBoolean(retval.item); CfOut(cf_verbose, "", "SET FIPS_MODE = %d\n", FIPS_MODE); } if (GetVariable("control_common", CFG_CONTROLBODY[cfg_syslog_port].lval, &retval) != DATA_TYPE_NONE) { SetSyslogPort(Str2Int(retval.item)); CfOut(cf_verbose, "", "SET syslog_port to %s", ScalarRvalValue(retval)); } if (GetVariable("control_common", CFG_CONTROLBODY[cfg_syslog_host].lval, &retval) != DATA_TYPE_NONE) { SetSyslogHost(Hostname2IPString(retval.item)); CfOut(cf_verbose, "", "SET syslog_host to %s", Hostname2IPString(retval.item)); } #ifdef HAVE_NOVA Nova_Initialize(); #endif }
static int FindPidMatches(EvalContext *ctx, Item *procdata, Item **killlist, Attributes a, const char *promiser) { int matches = 0; pid_t cfengine_pid = getpid(); Item *matched = SelectProcesses(ctx, procdata, promiser, a.process_select, a.haveselect); for (Item *ip = matched; ip != NULL; ip = ip->next) { pid_t pid = ip->counter; if (pid == 1) { if ((RlistLen(a.signals) == 1) && (RlistIsStringIn(a.signals, "hup"))) { Log(LOG_LEVEL_VERBOSE, "Okay to send only HUP to init"); } else { continue; } } if ((pid < 4) && (a.signals)) { Log(LOG_LEVEL_VERBOSE, "Will not signal or restart processes 0,1,2,3 (occurred while looking for %s)", promiser); continue; } bool promised_zero = (a.process_count.min_range == 0) && (a.process_count.max_range == 0); if ((a.transaction.action == cfa_warn) && promised_zero) { Log(LOG_LEVEL_ERR, "Process alert '%s'", procdata->name); /* legend */ Log(LOG_LEVEL_ERR, "Process alert '%s'", ip->name); continue; } if ((pid == cfengine_pid) && (a.signals)) { Log(LOG_LEVEL_VERBOSE, "cf-agent will not signal itself!"); continue; } if (a.transaction.action == cfa_warn) { Log(LOG_LEVEL_ERR, "Matched '%s'", ip->name); } else { Log(LOG_LEVEL_VERBOSE, "Matched '%s'", ip->name); } PrependItem(killlist, ip->name, ""); (*killlist)->counter = pid; matches++; } DeleteItemList(matched); return matches; }
/** * Add access rules to the given ACL #acl according to the constraints in the * particular access promise. * * For legacy reasons (non-TLS connections), build also the #ap (access Auth) * and #dp (deny Auth). */ static void AccessPromise_AddAccessConstraints(const EvalContext *ctx, const Promise *pp, struct resource_acl *racl, Auth *ap, Auth *dp) { for (size_t i = 0; i < SeqLength(pp->conlist); i++) { const Constraint *cp = SeqAt(pp->conlist, i); size_t ret = -2; if (!IsDefinedClass(ctx, cp->classes)) { continue; } switch (cp->rval.type) { #define IsAccessBody(e) (strcmp(cp->lval, CF_REMACCESS_BODIES[e].lval) == 0) case RVAL_TYPE_SCALAR: if (IsAccessBody(REMOTE_ACCESS_IFENCRYPTED)) { ap->encrypt = BooleanFromString(cp->rval.item); } else if (IsAccessBody(REMOTE_ACCESS_SHORTCUT)) { const char *shortcut = cp->rval.item; if (strchr(shortcut, FILE_SEPARATOR) != NULL) { Log(LOG_LEVEL_ERR, "slashes are forbidden in ACL shortcut: %s", shortcut); } else if (StringMapHasKey(SV.path_shortcuts, shortcut)) { Log(LOG_LEVEL_WARNING, "Already existing shortcut for path '%s' was replaced", pp->promiser); } else { StringMapInsert(SV.path_shortcuts, xstrdup(shortcut), xstrdup(pp->promiser)); Log(LOG_LEVEL_DEBUG, "Added shortcut '%s' for path: %s", shortcut, pp->promiser); } } break; case RVAL_TYPE_LIST: for (const Rlist *rp = (const Rlist *) cp->rval.item; rp != NULL; rp = rp->next) { /* TODO keys, ips, hostnames are valid such strings. */ if (IsAccessBody(REMOTE_ACCESS_ADMITIPS)) { ret = StrList_Append(&racl->admit.ips, RlistScalarValue(rp)); PrependItem(&(ap->accesslist), RlistScalarValue(rp), NULL); } else if (IsAccessBody(REMOTE_ACCESS_DENYIPS)) { ret = StrList_Append(&racl->deny.ips, RlistScalarValue(rp)); PrependItem(&(dp->accesslist), RlistScalarValue(rp), NULL); } else if (IsAccessBody(REMOTE_ACCESS_ADMITHOSTNAMES)) { ret = StrList_Append(&racl->admit.hostnames, RlistScalarValue(rp)); /* If any hostname rule got added, * turn on reverse DNS lookup in the new protocol. */ if (ret != (size_t) -1) { TurnOnReverseLookups(); } NewHostToOldACL(ap, RlistScalarValue(rp)); } else if (IsAccessBody(REMOTE_ACCESS_DENYHOSTNAMES)) { ret = StrList_Append(&racl->deny.hostnames, RlistScalarValue(rp)); /* If any hostname rule got added, * turn on reverse DNS lookup in the new protocol. */ if (ret != (size_t) -1) { TurnOnReverseLookups(); } NewHostToOldACL(dp, RlistScalarValue(rp)); } else if (IsAccessBody(REMOTE_ACCESS_ADMITKEYS)) { ret = StrList_Append(&racl->admit.keys, RlistScalarValue(rp)); } else if (IsAccessBody(REMOTE_ACCESS_DENYKEYS)) { ret = StrList_Append(&racl->deny.keys, RlistScalarValue(rp)); } /* Legacy stuff */ else if (IsAccessBody(REMOTE_ACCESS_ADMIT)) { ret = racl_SmartAppend(&racl->admit, RlistScalarValue(rp)); PrependItem(&(ap->accesslist), RlistScalarValue(rp), NULL); } else if (IsAccessBody(REMOTE_ACCESS_DENY)) { ret = racl_SmartAppend(&racl->deny, RlistScalarValue(rp)); PrependItem(&(dp->accesslist), RlistScalarValue(rp), NULL); } else if (IsAccessBody(REMOTE_ACCESS_MAPROOT)) { PrependItem(&(ap->maproot), RlistScalarValue(rp), NULL); } } if (ret == (size_t) -1) { /* Should never happen, besides when allocation fails. */ Log(LOG_LEVEL_CRIT, "StrList_Append: %s", GetErrorStr()); exit(255); } break; default: UnexpectedError("Unknown constraint type!"); break; #undef IsAccessBody } } StrList_Finalise(&racl->admit.ips); StrList_Sort(racl->admit.ips, string_Compare); StrList_Finalise(&racl->admit.hostnames); StrList_Sort(racl->admit.hostnames, string_CompareFromEnd); StrList_Finalise(&racl->admit.keys); StrList_Sort(racl->admit.keys, string_Compare); StrList_Finalise(&racl->deny.ips); StrList_Sort(racl->deny.ips, string_Compare); StrList_Finalise(&racl->deny.hostnames); StrList_Sort(racl->deny.hostnames, string_CompareFromEnd); StrList_Finalise(&racl->deny.keys); StrList_Sort(racl->deny.keys, string_Compare); }
int LoadProcessTable(EvalContext *ctx, Item **procdata) { FILE *prp; char pscomm[CF_MAXLINKSIZE], vbuff[CF_BUFSIZE], *sp; Item *rootprocs = NULL; Item *otherprocs = NULL; if (PROCESSTABLE) { Log(LOG_LEVEL_VERBOSE, "Reusing cached process table"); return true; } const char *psopts = GetProcessOptions(); snprintf(pscomm, CF_MAXLINKSIZE, "%s %s", VPSCOMM[VSYSTEMHARDCLASS], psopts); Log(LOG_LEVEL_VERBOSE, "Observe process table with %s", pscomm); if ((prp = cf_popen(pscomm, "r", false)) == NULL) { Log(LOG_LEVEL_ERR, "Couldn't open the process list with command '%s'. (popen: %s)", pscomm, GetErrorStr()); return false; } for (;;) { ssize_t res = CfReadLine(vbuff, CF_BUFSIZE, prp); if (res == 0) { break; } if (res == -1) { Log(LOG_LEVEL_ERR, "Unable to read process list with command '%s'. (fread: %s)", pscomm, GetErrorStr()); cf_pclose(prp); return false; } for (sp = vbuff + strlen(vbuff) - 1; (sp > vbuff) && (isspace((int)*sp)); sp--) { *sp = '\0'; } if (ForeignZone(vbuff)) { continue; } AppendItem(procdata, vbuff, ""); } cf_pclose(prp); /* Now save the data */ snprintf(vbuff, CF_MAXVARSIZE, "%s/state/cf_procs", CFWORKDIR); RawSaveItemList(*procdata, vbuff); CopyList(&rootprocs, *procdata); CopyList(&otherprocs, *procdata); while (DeleteItemNotContaining(ctx, &rootprocs, "root")) { } while (DeleteItemContaining(ctx, &otherprocs, "root")) { } if (otherprocs) { PrependItem(&rootprocs, otherprocs->name, NULL); } snprintf(vbuff, CF_MAXVARSIZE, "%s/state/cf_rootprocs", CFWORKDIR); RawSaveItemList(rootprocs, vbuff); DeleteItemList(rootprocs); snprintf(vbuff, CF_MAXVARSIZE, "%s/state/cf_otherprocs", CFWORKDIR); RawSaveItemList(otherprocs, vbuff); DeleteItemList(otherprocs); return true; }
void TexinfoManual(const char *source_dir, const char *output_file) { char filename[CF_BUFSIZE]; const SubTypeSyntax *st; Item *done = NULL; FILE *fout; int i; if ((fout = fopen(output_file, "w")) == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "fopen", "Unable to open %s for writing\n", filename); return; } TexinfoHeader(fout); /* General background */ fprintf(fout, "@c *****************************************************\n"); fprintf(fout, "@c * CHAPTER \n"); fprintf(fout, "@c *****************************************************\n"); fprintf(fout, "@node Getting started\n@chapter CFEngine %s -- Getting started\n\n", Version()); IncludeManualFile(source_dir, fout, "reference_basics.texinfo"); /* Control promises */ fprintf(fout, "@c *****************************************************\n"); fprintf(fout, "@c * CHAPTER \n"); fprintf(fout, "@c *****************************************************\n"); fprintf(fout, "@node Control Promises\n@chapter Control promises\n\n"); IncludeManualFile(source_dir, fout, "reference_control_intro.texinfo"); fprintf(fout, "@menu\n"); for (i = 0; CF_ALL_BODIES[i].bundle_type != NULL; ++i) { fprintf(fout, "* control %s::\n", CF_ALL_BODIES[i].bundle_type); } fprintf(fout, "@end menu\n"); for (i = 0; CF_ALL_BODIES[i].bundle_type != NULL; i++) { fprintf(fout, "@node control %s\n@section @code{%s} control promises\n\n", CF_ALL_BODIES[i].bundle_type, CF_ALL_BODIES[i].bundle_type); snprintf(filename, CF_BUFSIZE - 1, "control/%s_example.texinfo", CF_ALL_BODIES[i].bundle_type); IncludeManualFile(source_dir, fout, filename); snprintf(filename, CF_BUFSIZE - 1, "control/%s_notes.texinfo", CF_ALL_BODIES[i].bundle_type); IncludeManualFile(source_dir, fout, filename); TexinfoBodyParts(source_dir, fout, CF_ALL_BODIES[i].bs, CF_ALL_BODIES[i].bundle_type); } /* Components */ for (i = 0; i < CF3_MODULES; i++) { st = (CF_ALL_SUBTYPES[i]); if ((st == CF_COMMON_SUBTYPES) || (st == CF_EXEC_SUBTYPES) || (st == CF_REMACCESS_SUBTYPES) || (st == CF_KNOWLEDGE_SUBTYPES) || (st == CF_MEASUREMENT_SUBTYPES)) { CfOut(OUTPUT_LEVEL_VERBOSE, "", "Dealing with chapter / bundle type %s\n", st->bundle_type); fprintf(fout, "@c *****************************************************\n"); fprintf(fout, "@c * CHAPTER \n"); fprintf(fout, "@c *****************************************************\n"); if (strcmp(st->bundle_type, "*") == 0) { fprintf(fout, "@node Bundles for common\n@chapter Bundles of @code{common}\n\n"); } else { fprintf(fout, "@node Bundles for %s\n@chapter Bundles of @code{%s}\n\n", st->bundle_type, st->bundle_type); } } if (!IsItemIn(done, st->bundle_type)) /* Avoid multiple reading if several modules */ { char bundle_filename[CF_BUFSIZE]; if (strcmp(st->bundle_type, "*") == 0) { strcpy(bundle_filename, "common"); } else { strlcpy(bundle_filename, st->bundle_type, CF_BUFSIZE); } PrependItem(&done, st->bundle_type, NULL); snprintf(filename, CF_BUFSIZE - 1, "bundletypes/%s_example.texinfo", bundle_filename); IncludeManualFile(source_dir, fout, filename); snprintf(filename, CF_BUFSIZE - 1, "bundletypes/%s_notes.texinfo", bundle_filename); IncludeManualFile(source_dir, fout, filename); fprintf(fout, "@menu\n"); for (int k = 0; k < CF3_MODULES; ++k) { for (int j = 0; CF_ALL_SUBTYPES[k][j].bundle_type != NULL; ++j) { const char *constraint_type_name; if (strcmp(CF_ALL_SUBTYPES[k][j].subtype, "*") == 0) { constraint_type_name = "Miscellaneous"; } else { constraint_type_name = CF_ALL_SUBTYPES[k][j].subtype; } const char *bundle_type_name; if (strcmp(CF_ALL_SUBTYPES[k][j].bundle_type, "*") == 0) { bundle_type_name = "common"; } else { bundle_type_name = CF_ALL_SUBTYPES[k][j].bundle_type; } fprintf(fout, "* %s in %s promises: %s in %s promises\n", CF_ALL_SUBTYPES[k][j].subtype, bundle_type_name, constraint_type_name, bundle_type_name); } } fprintf(fout, "@end menu\n"); } TexinfoPromiseTypesFor(source_dir, fout, st); } /* Special functions */ CfOut(OUTPUT_LEVEL_VERBOSE, "", "Dealing with chapter / bundle type - special functions\n"); fprintf(fout, "@c *****************************************************\n"); fprintf(fout, "@c * CHAPTER \n"); fprintf(fout, "@c *****************************************************\n"); fprintf(fout, "@node Special functions\n@chapter Special functions\n\n"); fprintf(fout, "@menu\n"); fprintf(fout, "* Introduction to functions::\n"); for (i = 0; CF_FNCALL_TYPES[i].name != NULL; ++i) { fprintf(fout, "* Function %s::\n", CF_FNCALL_TYPES[i].name); } fprintf(fout, "@end menu\n"); fprintf(fout, "@node Introduction to functions\n@section Introduction to functions\n\n"); IncludeManualFile(source_dir, fout, "functions_intro.texinfo"); for (i = 0; CF_FNCALL_TYPES[i].name != NULL; i++) { fprintf(fout, "@node Function %s\n@section Function %s \n\n", CF_FNCALL_TYPES[i].name, CF_FNCALL_TYPES[i].name); TexinfoSpecialFunction(source_dir, fout, CF_FNCALL_TYPES[i]); } /* Special variables */ CfOut(OUTPUT_LEVEL_VERBOSE, "", "Dealing with chapter / bundle type - special variables\n"); fprintf(fout, "@c *****************************************************\n"); fprintf(fout, "@c * CHAPTER \n"); fprintf(fout, "@c *****************************************************\n"); fprintf(fout, "@node Special Variables\n@chapter Special Variables\n\n"); static const char *scopes[] = { "const", "edit", "match", "mon", "sys", "this", NULL, }; fprintf(fout, "@menu\n"); for (const char **s = scopes; *s != NULL; ++s) { fprintf(fout, "* Variable context %s::\n", *s); } fprintf(fout, "@end menu\n"); // scopes const and sys NewScope("edit"); NewScalar("edit", "filename", "x", DATA_TYPE_STRING); NewScope("match"); NewScalar("match", "0", "x", DATA_TYPE_STRING); for (const char **s = scopes; *s != NULL; ++s) { TexinfoVariables(source_dir, fout, (char *) *s); } // Log files CfOut(OUTPUT_LEVEL_VERBOSE, "", "Dealing with chapter / bundle type - Logs and records\n"); fprintf(fout, "@c *****************************************************\n"); fprintf(fout, "@c * CHAPTER \n"); fprintf(fout, "@c *****************************************************\n"); fprintf(fout, "@node Logs and records\n@chapter Logs and records\n\n"); IncludeManualFile(source_dir, fout, "reference_logs.texinfo"); TexinfoFooter(fout); fclose(fout); }
void AddFilenameToListOfSuspicious(const char *pattern) { PrependItem(&SUSPICIOUSLIST, pattern, NULL); }
void KeepQueryAccessPromise(EvalContext *ctx, Promise *pp, char *type) { Rlist *rp; Auth *ap, *dp; if (!GetAuthPath(pp->promiser, SV.varadmit)) { InstallServerAuthPath(pp->promiser, &SV.varadmit, &SV.varadmittop); } RegisterLiteralServerData(ctx, pp->promiser, pp); if (!GetAuthPath(pp->promiser, SV.vardeny)) { InstallServerAuthPath(pp->promiser, &SV.vardeny, &SV.vardenytop); } ap = GetAuthPath(pp->promiser, SV.varadmit); dp = GetAuthPath(pp->promiser, SV.vardeny); if (strcmp(type, "query") == 0) { ap->literal = true; } for (size_t i = 0; i < SeqLength(pp->conlist); i++) { Constraint *cp = SeqAt(pp->conlist, i); if (!IsDefinedClass(ctx, cp->classes, PromiseGetNamespace(pp))) { continue; } switch (cp->rval.type) { case RVAL_TYPE_SCALAR: if (strcmp(cp->lval, CF_REMACCESS_BODIES[REMOTE_ACCESS_ENCRYPTED].lval) == 0) { ap->encrypt = true; } break; case RVAL_TYPE_LIST: for (rp = (Rlist *) cp->rval.item; rp != NULL; rp = rp->next) { if (strcmp(cp->lval, CF_REMACCESS_BODIES[REMOTE_ACCESS_ADMIT].lval) == 0) { PrependItem(&(ap->accesslist), rp->item, NULL); continue; } if (strcmp(cp->lval, CF_REMACCESS_BODIES[REMOTE_ACCESS_DENY].lval) == 0) { PrependItem(&(dp->accesslist), rp->item, NULL); continue; } if (strcmp(cp->lval, CF_REMACCESS_BODIES[REMOTE_ACCESS_MAPROOT].lval) == 0) { PrependItem(&(ap->maproot), rp->item, NULL); continue; } } break; default: /* Shouldn't happen */ break; } } }
void KeepLiteralAccessPromise(EvalContext *ctx, Promise *pp, char *type) { Rlist *rp; Auth *ap = NULL, *dp = NULL; const char *handle = PromiseGetHandle(pp); if ((handle == NULL) && (strcmp(type,"literal") == 0)) { Log(LOG_LEVEL_ERR, "Access to literal server data requires you to define a promise handle for reference"); return; } if (strcmp(type, "literal") == 0) { Log(LOG_LEVEL_VERBOSE,"Looking at literal access promise '%s', type '%s'", pp->promiser, type); if (!GetAuthPath(handle, SV.varadmit)) { InstallServerAuthPath(handle, &SV.varadmit, &SV.varadmittop); } if (!GetAuthPath(handle, SV.vardeny)) { InstallServerAuthPath(handle, &SV.vardeny, &SV.vardenytop); } RegisterLiteralServerData(ctx, handle, pp); ap = GetAuthPath(handle, SV.varadmit); dp = GetAuthPath(handle, SV.vardeny); ap->literal = true; } else { Log(LOG_LEVEL_VERBOSE,"Looking at context/var access promise '%s', type '%s'", pp->promiser, type); if (!GetAuthPath(pp->promiser, SV.varadmit)) { InstallServerAuthPath(pp->promiser, &SV.varadmittop, &SV.varadmittop); } if (!GetAuthPath(pp->promiser, SV.vardeny)) { InstallServerAuthPath(pp->promiser, &SV.vardeny, &SV.vardenytop); } if (strcmp(type, "context") == 0) { ap = GetAuthPath(pp->promiser, SV.varadmit); dp = GetAuthPath(pp->promiser, SV.vardeny); ap->classpattern = true; } if (strcmp(type, "variable") == 0) { ap = GetAuthPath(pp->promiser, SV.varadmit); // Allow the promiser (preferred) as well as handle as variable name dp = GetAuthPath(pp->promiser, SV.vardeny); ap->variable = true; } } for (size_t i = 0; i < SeqLength(pp->conlist); i++) { Constraint *cp = SeqAt(pp->conlist, i); if (!IsDefinedClass(ctx, cp->classes, PromiseGetNamespace(pp))) { continue; } switch (cp->rval.type) { case RVAL_TYPE_SCALAR: if (strcmp(cp->lval, CF_REMACCESS_BODIES[REMOTE_ACCESS_ENCRYPTED].lval) == 0) { ap->encrypt = true; } break; case RVAL_TYPE_LIST: for (rp = (Rlist *) cp->rval.item; rp != NULL; rp = rp->next) { if (strcmp(cp->lval, CF_REMACCESS_BODIES[REMOTE_ACCESS_ADMIT].lval) == 0) { PrependItem(&(ap->accesslist), rp->item, NULL); continue; } if (strcmp(cp->lval, CF_REMACCESS_BODIES[REMOTE_ACCESS_DENY].lval) == 0) { PrependItem(&(dp->accesslist), rp->item, NULL); continue; } if (strcmp(cp->lval, CF_REMACCESS_BODIES[REMOTE_ACCESS_MAPROOT].lval) == 0) { PrependItem(&(ap->maproot), rp->item, NULL); continue; } } break; default: /* Shouldn't happen */ break; } } }
int Unix_LoadProcessTable(Item **procdata) { FILE *prp; char pscomm[CF_MAXLINKSIZE], vbuff[CF_BUFSIZE], *sp; Item *rootprocs = NULL; Item *otherprocs = NULL; const char *psopts = GetProcessOptions(); snprintf(pscomm, CF_MAXLINKSIZE, "%s %s", VPSCOMM[VSYSTEMHARDCLASS], psopts); CfOut(cf_verbose, "", "Observe process table with %s\n", pscomm); if ((prp = cf_popen(pscomm, "r")) == NULL) { CfOut(cf_error, "popen", "Couldn't open the process list with command %s\n", pscomm); return false; } while (!feof(prp)) { memset(vbuff, 0, CF_BUFSIZE); CfReadLine(vbuff, CF_BUFSIZE, prp); for (sp = vbuff + strlen(vbuff) - 1; sp > vbuff && isspace(*sp); sp--) { *sp = '\0'; } if (ForeignZone(vbuff)) { continue; } AppendItem(procdata, vbuff, ""); } cf_pclose(prp); /* Now save the data */ snprintf(vbuff, CF_MAXVARSIZE, "%s/state/cf_procs", CFWORKDIR); RawSaveItemList(*procdata, vbuff); CopyList(&rootprocs, *procdata); CopyList(&otherprocs, *procdata); while (DeleteItemNotContaining(&rootprocs, "root")) { } while (DeleteItemContaining(&otherprocs, "root")) { } if (otherprocs) { PrependItem(&rootprocs, otherprocs->name, NULL); } snprintf(vbuff, CF_MAXVARSIZE, "%s/state/cf_rootprocs", CFWORKDIR); RawSaveItemList(rootprocs, vbuff); DeleteItemList(rootprocs); snprintf(vbuff, CF_MAXVARSIZE, "%s/state/cf_otherprocs", CFWORKDIR); RawSaveItemList(otherprocs, vbuff); DeleteItemList(otherprocs); return true; }
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); } } }
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; }
void KeepFileAccessPromise(EvalContext *ctx, const Promise *pp) { Rlist *rp; Auth *ap, *dp; if (strlen(pp->promiser) != 1) { DeleteSlash(pp->promiser); } if (!GetAuthPath(pp->promiser, SV.admit)) { InstallServerAuthPath(pp->promiser, &SV.admit, &SV.admittop); } if (!GetAuthPath(pp->promiser, SV.deny)) { InstallServerAuthPath(pp->promiser, &SV.deny, &SV.denytop); } ap = GetAuthPath(pp->promiser, SV.admit); dp = GetAuthPath(pp->promiser, SV.deny); for (size_t i = 0; i < SeqLength(pp->conlist); i++) { Constraint *cp = SeqAt(pp->conlist, i); if (!IsDefinedClass(ctx, cp->classes, PromiseGetNamespace(pp))) { continue; } switch (cp->rval.type) { case RVAL_TYPE_SCALAR: if (strcmp(cp->lval, CF_REMACCESS_BODIES[REMOTE_ACCESS_ENCRYPTED].lval) == 0) { ap->encrypt = true; } break; case RVAL_TYPE_LIST: for (rp = (Rlist *) cp->rval.item; rp != NULL; rp = rp->next) { if (strcmp(cp->lval, CF_REMACCESS_BODIES[REMOTE_ACCESS_ADMIT].lval) == 0) { PrependItem(&(ap->accesslist), RlistScalarValue(rp), NULL); continue; } if (strcmp(cp->lval, CF_REMACCESS_BODIES[REMOTE_ACCESS_DENY].lval) == 0) { PrependItem(&(dp->accesslist), RlistScalarValue(rp), NULL); continue; } if (strcmp(cp->lval, CF_REMACCESS_BODIES[REMOTE_ACCESS_MAPROOT].lval) == 0) { PrependItem(&(ap->maproot), RlistScalarValue(rp), NULL); continue; } } break; default: UnexpectedError("Unknown constraint type!"); break; } } }
int LoadProcessTable() { FILE *prp; char pscomm[CF_MAXLINKSIZE]; Item *rootprocs = NULL; Item *otherprocs = NULL; if (PROCESSTABLE) { Log(LOG_LEVEL_VERBOSE, "Reusing cached process table"); return true; } LoadPlatformExtraTable(); CheckPsLineLimitations(); const char *psopts = GetProcessOptions(); snprintf(pscomm, CF_MAXLINKSIZE, "%s %s", VPSCOMM[VPSHARDCLASS], psopts); Log(LOG_LEVEL_VERBOSE, "Observe process table with %s", pscomm); if ((prp = cf_popen(pscomm, "r", false)) == NULL) { Log(LOG_LEVEL_ERR, "Couldn't open the process list with command '%s'. (popen: %s)", pscomm, GetErrorStr()); return false; } size_t vbuff_size = CF_BUFSIZE; char *vbuff = xmalloc(vbuff_size); # ifdef HAVE_GETZONEID char *names[CF_PROCCOLS]; int start[CF_PROCCOLS]; int end[CF_PROCCOLS]; Seq *pidlist = SeqNew(1, NULL); Seq *rootpidlist = SeqNew(1, NULL); bool global_zone = IsGlobalZone(); if (global_zone) { int res = ZLoadProcesstable(pidlist, rootpidlist); if (res == false) { Log(LOG_LEVEL_ERR, "Unable to load solaris zone process table."); return false; } } # endif ARG_UNUSED bool header = true; /* used only if HAVE_GETZONEID */ for (;;) { ssize_t res = CfReadLine(&vbuff, &vbuff_size, prp); if (res == -1) { if (!feof(prp)) { Log(LOG_LEVEL_ERR, "Unable to read process list with command '%s'. (fread: %s)", pscomm, GetErrorStr()); cf_pclose(prp); free(vbuff); return false; } else { break; } } Chop(vbuff, vbuff_size); # ifdef HAVE_GETZONEID if (global_zone) { if (header) { /* this is the banner so get the column header names for later use*/ GetProcessColumnNames(vbuff, &names[0], start, end); } else { int gpid = ExtractPid(vbuff, names, end); if (!IsGlobalProcess(gpid, pidlist, rootpidlist)) { continue; } } } # endif AppendItem(&PROCESSTABLE, vbuff, ""); header = false; } cf_pclose(prp); /* Now save the data */ const char* const statedir = GetStateDir(); snprintf(vbuff, CF_MAXVARSIZE, "%s%ccf_procs", statedir, FILE_SEPARATOR); RawSaveItemList(PROCESSTABLE, vbuff, NewLineMode_Unix); # ifdef HAVE_GETZONEID if (global_zone) /* pidlist and rootpidlist are empty if we're not in the global zone */ { Item *ip = PROCESSTABLE; while (ip != NULL) { ZCopyProcessList(&rootprocs, ip, rootpidlist, names, end); ip = ip->next; } ReverseItemList(rootprocs); ip = PROCESSTABLE; while (ip != NULL) { ZCopyProcessList(&otherprocs, ip, pidlist, names, end); ip = ip->next; } ReverseItemList(otherprocs); } else # endif { CopyList(&rootprocs, PROCESSTABLE); CopyList(&otherprocs, PROCESSTABLE); while (DeleteItemNotContaining(&rootprocs, "root")) { } while (DeleteItemContaining(&otherprocs, "root")) { } } if (otherprocs) { PrependItem(&rootprocs, otherprocs->name, NULL); } snprintf(vbuff, CF_MAXVARSIZE, "%s%ccf_rootprocs", statedir, FILE_SEPARATOR); RawSaveItemList(rootprocs, vbuff, NewLineMode_Unix); DeleteItemList(rootprocs); snprintf(vbuff, CF_MAXVARSIZE, "%s%ccf_otherprocs", statedir, FILE_SEPARATOR); RawSaveItemList(otherprocs, vbuff, NewLineMode_Unix); DeleteItemList(otherprocs); free(vbuff); return true; }
CfLock AcquireLock(char *operand, char *host, time_t now, Attributes attr, Promise *pp, int ignoreProcesses) { unsigned int pid; int i, err, sum = 0; time_t lastcompleted = 0, elapsedtime; char *promise, cc_operator[CF_BUFSIZE], cc_operand[CF_BUFSIZE]; char cflock[CF_BUFSIZE], cflast[CF_BUFSIZE], cflog[CF_BUFSIZE]; char str_digest[CF_BUFSIZE]; CfLock this; unsigned char digest[EVP_MAX_MD_SIZE + 1]; this.last = (char *) CF_UNDEFINED; this.lock = (char *) CF_UNDEFINED; this.log = (char *) CF_UNDEFINED; if (now == 0) { return this; } this.last = NULL; this.lock = NULL; this.log = NULL; /* Indicate as done if we tried ... as we have passed all class constraints now but we should only do this for level 0 promises. Sub routine bundles cannot be marked as done or it will disallow iteration over bundles */ if (pp->done) { return this; } if (CF_STCKFRAME == 1) { *(pp->donep) = true; /* Must not set pp->done = true for editfiles etc */ } HashPromise(operand, pp, digest, CF_DEFAULT_DIGEST); strcpy(str_digest, HashPrint(CF_DEFAULT_DIGEST, digest)); /* As a backup to "done" we need something immune to re-use */ if (THIS_AGENT_TYPE == cf_agent) { if (IsItemIn(DONELIST, str_digest)) { CfOut(cf_verbose, "", " -> This promise has already been verified"); return this; } PrependItem(&DONELIST, str_digest, NULL); } /* Finally if we're supposed to ignore locks ... do the remaining stuff */ if (IGNORELOCK) { this.lock = xstrdup("dummy"); return this; } promise = BodyName(pp); snprintf(cc_operator, CF_MAXVARSIZE - 1, "%s-%s", promise, host); strncpy(cc_operand, operand, CF_BUFSIZE - 1); CanonifyNameInPlace(cc_operand); RemoveDates(cc_operand); free(promise); CfDebug("AcquireLock(%s,%s), ExpireAfter=%d, IfElapsed=%d\n", cc_operator, cc_operand, attr.transaction.expireafter, attr.transaction.ifelapsed); for (i = 0; cc_operator[i] != '\0'; i++) { sum = (CF_MACROALPHABET * sum + cc_operator[i]) % CF_HASHTABLESIZE; } for (i = 0; cc_operand[i] != '\0'; i++) { sum = (CF_MACROALPHABET * sum + cc_operand[i]) % CF_HASHTABLESIZE; } snprintf(cflog, CF_BUFSIZE, "%s/cf3.%.40s.runlog", CFWORKDIR, host); snprintf(cflock, CF_BUFSIZE, "lock.%.100s.%s.%.100s_%d_%s", pp->bundle, cc_operator, cc_operand, sum, str_digest); snprintf(cflast, CF_BUFSIZE, "last.%.100s.%s.%.100s_%d_%s", pp->bundle, cc_operator, cc_operand, sum, str_digest); CfDebug("LOCK(%s)[%s]\n", pp->bundle, cflock); // Now see if we can get exclusivity to edit the locks CFINITSTARTTIME = time(NULL); WaitForCriticalSection(); /* Look for non-existent (old) processes */ lastcompleted = FindLock(cflast); elapsedtime = (time_t) (now - lastcompleted) / 60; if (elapsedtime < 0) { CfOut(cf_verbose, "", " XX Another cf-agent seems to have done this since I started (elapsed=%jd)\n", (intmax_t) elapsedtime); ReleaseCriticalSection(); return this; } if (elapsedtime < attr.transaction.ifelapsed) { CfOut(cf_verbose, "", " XX Nothing promised here [%.40s] (%jd/%u minutes elapsed)\n", cflast, (intmax_t) elapsedtime, attr.transaction.ifelapsed); ReleaseCriticalSection(); return this; } /* Look for existing (current) processes */ if (!ignoreProcesses) { lastcompleted = FindLock(cflock); elapsedtime = (time_t) (now - lastcompleted) / 60; if (lastcompleted != 0) { if (elapsedtime >= attr.transaction.expireafter) { CfOut(cf_inform, "", "Lock %s expired (after %jd/%u minutes)\n", cflock, (intmax_t) elapsedtime, attr.transaction.expireafter); pid = FindLockPid(cflock); if (pid == -1) { CfOut(cf_error, "", "Illegal pid in corrupt lock %s - ignoring lock\n", cflock); } #ifdef MINGW // killing processes with e.g. task manager does not allow for termination handling else if (!NovaWin_IsProcessRunning(pid)) { CfOut(cf_verbose, "", "Process with pid %d is not running - ignoring lock (Windows does not support graceful processes termination)\n", pid); LogLockCompletion(cflog, pid, "Lock expired, process not running", cc_operator, cc_operand); unlink(cflock); } #endif /* MINGW */ else { CfOut(cf_verbose, "", "Trying to kill expired process, pid %d\n", pid); err = GracefulTerminate(pid); if (err || errno == ESRCH) { LogLockCompletion(cflog, pid, "Lock expired, process killed", cc_operator, cc_operand); unlink(cflock); } else { ReleaseCriticalSection(); FatalError("Unable to kill expired cfagent process %d from lock %s, exiting this time..\n", pid, cflock); } } } else { ReleaseCriticalSection(); CfOut(cf_verbose, "", "Couldn't obtain lock for %s (already running!)\n", cflock); return this; } } WriteLock(cflock); } ReleaseCriticalSection(); this.lock = xstrdup(cflock); this.last = xstrdup(cflast); this.log = xstrdup(cflog); /* Keep this as a global for signal handling */ strcpy(CFLOCK, cflock); strcpy(CFLAST, cflast); strcpy(CFLOG, cflog); return this; }