Item *SelectProcesses(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); pcre *rx = CompileRegex(process_name); if (rx) { /* 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) { int s, e; if (StringMatchWithPrecompiledRegex(rx, ip->name, &s, &e)) { if (NULL_OR_EMPTY(ip->name)) { continue; } if (attrselect && !SelectProcess(ip->name, pstime, 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; } } pcre_free(rx); } for (int i = 0; i < CF_PROCCOLS; i++) { free(names[i]); } return result; }
bool IsProcessNameRunning(char *procNameRegex) { char *colHeaders[CF_PROCCOLS]; int start[CF_PROCCOLS] = { 0 }; int end[CF_PROCCOLS] = { 0 }; bool matched = false; int i; memset(colHeaders, 0, sizeof(colHeaders)); if (PROCESSTABLE == NULL) { Log(LOG_LEVEL_ERR, "IsProcessNameRunning: PROCESSTABLE is empty"); return false; } /* TODO: use actual time of ps-run, not time(NULL), which may be later. */ time_t pstime = time(NULL); GetProcessColumnNames(PROCESSTABLE->name, colHeaders, start, end); for (const Item *ip = PROCESSTABLE->next; !matched && ip != NULL; ip = ip->next) // iterate over ps lines { char *lineSplit[CF_PROCCOLS]; memset(lineSplit, 0, sizeof(lineSplit)); if (NULL_OR_EMPTY(ip->name)) { continue; } if (!SplitProcLine(ip->name, pstime, colHeaders, start, end, PS_COLUMN_ALGORITHM[VPSHARDCLASS], lineSplit)) { Log(LOG_LEVEL_ERR, "IsProcessNameRunning: Could not split process line '%s'", ip->name); goto loop_cleanup; } ApplyPlatformExtraTable(colHeaders, lineSplit); if (SelectProcRegexMatch("CMD", "COMMAND", procNameRegex, true, colHeaders, lineSplit)) { matched = true; } loop_cleanup: for (i = 0; lineSplit[i] != NULL; i++) { free(lineSplit[i]); } } for (i = 0; colHeaders[i] != NULL; i++) { free(colHeaders[i]); } return matched; }
bool CompareStringOrRegex(const char *value, const char *compareTo, bool regex) { if (regex) { if (!NULL_OR_EMPTY(compareTo) && !StringMatchFull(compareTo, value)) { return false; } } else { if (!NULL_OR_EMPTY(compareTo) && strcmp(compareTo, value) != 0) { return false; } } return true; }
bool IsProcessNameRunning(EvalContext *ctx, char *procNameRegex) { char *colHeaders[CF_PROCCOLS]; Item *ip; int start[CF_PROCCOLS] = { 0 }; int end[CF_PROCCOLS] = { 0 }; bool matched = false; int i; if (PROCESSTABLE == NULL) { Log(LOG_LEVEL_ERR, "IsProcessNameRunning: PROCESSTABLE is empty"); return false; } GetProcessColumnNames(PROCESSTABLE->name, (char **) colHeaders, start, end); for (ip = PROCESSTABLE->next; ip != NULL; ip = ip->next) // iterate over ps lines { char *lineSplit[CF_PROCCOLS]; if (NULL_OR_EMPTY(ip->name)) { continue; } if (!SplitProcLine(ip->name, colHeaders, start, end, lineSplit)) { Log(LOG_LEVEL_ERR, "IsProcessNameRunning: Could not split process line '%s'", ip->name); continue; } if (SelectProcRegexMatch(ctx, "CMD", "COMMAND", procNameRegex, colHeaders, lineSplit)) { matched = true; break; } i = 0; while (lineSplit[i] != NULL) { free(lineSplit[i]); i++; } } i = 0; while (colHeaders[i] != NULL) { free(colHeaders[i]); i++; } return matched; }
void AnchorRegex(const char *regex, char *out, int outSz) { if (NULL_OR_EMPTY(regex)) { memset(out, 0, outSz); } else { snprintf(out, outSz, "^(%s)$", regex); } }
char *AnchorRegexNew(const char *regex) { if (NULL_OR_EMPTY(regex)) { return xstrdup("^$"); } char *ret = NULL; xasprintf(&ret, "^(%s)$", regex); return ret; }
int main(int argc, char *argv[]) { int ret = 0; GenericAgentConfig *config = CheckOpts(argc, argv); #ifdef HAVE_AVAHI_CLIENT_CLIENT_H #ifdef HAVE_AVAHI_COMMON_ADDRESS_H if (NULL_OR_EMPTY(POLICY_SERVER) && BOOTSTRAP) { int ret = AutomaticBootstrap(); if (ret < 0) { return 1; } } #endif #endif ReportContext *report_context = OpenReports(config->agent_type); GenericAgentDiscoverContext(config, report_context); Policy *policy = GenericAgentLoadPolicy(config, report_context, ALWAYS_VALIDATE); CheckLicenses(); ThisAgentInit(); BeginAudit(); KeepPromises(policy, config, report_context); CloseReports("agent", report_context); // only note class usage when default policy is run if (!config->input_file) { NoteClassUsage(VHEAP, true); NoteClassUsage(VHARDHEAP, true); } #ifdef HAVE_NOVA Nova_NoteVarUsageDB(); Nova_TrackExecution(config->input_file); #endif PurgeLocks(); if (BOOTSTRAP && !VerifyBootstrap()) { ret = 1; } EndAudit(CFA_BACKGROUND); GenericAgentConfigDestroy(config); return ret; }
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; }
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; }
DSN *dsn_create(const char *status, const char *action, const char *reason, const char *dtype, const char *dtext, const char *mtype, const char *mname) { const char *myname = "dsn_create"; DSN *dsn; dsn = (DSN *) mymalloc(sizeof(*dsn)); /* * Status and reason must not be empty. Other members may be empty * strings. * * Early implementations represented unavailable information with null * pointers. This resulted in code that was difficult to maintain. We now * use empty strings instead. For safety sake we keep the null pointer * test for input, but we always convert to empty string on output. */ #define NULL_OR_EMPTY(s) ((s) == 0 || *(s) == 0) if (NULL_OR_EMPTY(status)) msg_panic("%s: null dsn status", myname); else dsn->status = mystrdup(status); if (NULL_OR_EMPTY(action)) dsn->action = mystrdup(""); else dsn->action = mystrdup(action); if (NULL_OR_EMPTY(reason)) msg_panic("%s: null dsn reason", myname); else dsn->reason = mystrdup(reason); if (NULL_OR_EMPTY(dtype) || NULL_OR_EMPTY(dtext)) { dsn->dtype = mystrdup(""); dsn->dtext = mystrdup(""); } else { dsn->dtype = mystrdup(dtype); dsn->dtext = mystrdup(dtext); } if (NULL_OR_EMPTY(mtype) || NULL_OR_EMPTY(mname)) { dsn->mtype = mystrdup(""); dsn->mname = mystrdup(""); } else { dsn->mtype = mystrdup(mtype); dsn->mname = mystrdup(mname); } return (dsn); }
/** * @brief Sets both internal C variables as well as policy sys variables. * * Called at bootstrap and after reading policy_server.dat. * Changes sys.policy_hub and sys.policy_hub_port. * NULL is an acceptable value for new_policy_server. Could happen when an * already bootstrapped server re-parses its policies, and the * policy_server.dat file has been removed. Then this function will be called * with NULL as new_policy_server, and cf-serverd will keep running even * without a policy server set. * * @param ctx EvalContext is used to set related variables * @param new_policy_server can be 'host:port', same as policy_server.dat */ void EvalContextSetPolicyServer(EvalContext *ctx, const char *new_policy_server) { // Remove variables if undefined policy server: if ( NULL_OR_EMPTY(new_policy_server) ) { EvalContextVariableRemoveSpecial( ctx, SPECIAL_SCOPE_SYS, "policy_hub" ); EvalContextVariableRemoveSpecial( ctx, SPECIAL_SCOPE_SYS, "policy_hub_port" ); return; } PolicyServerSet(new_policy_server); const char *ip = PolicyServerGetIP(); // Set the sys.policy_hub variable: if ( ip != NULL ) { EvalContextVariablePutSpecial( ctx, SPECIAL_SCOPE_SYS, "policy_hub", ip, CF_DATA_TYPE_STRING, "source=bootstrap" ); } else { EvalContextVariableRemoveSpecial( ctx, SPECIAL_SCOPE_SYS, "policy_hub" ); } // Set the sys.policy_hub_port variable: if (PolicyServerGetPort() != NULL) { EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "policy_hub_port", PolicyServerGetPort(), CF_DATA_TYPE_STRING, "source=bootstrap" ); } else // Default value (CFENGINE_PORT_STR = "5308") is set { EvalContextVariablePutSpecial( ctx, SPECIAL_SCOPE_SYS, "policy_hub_port", CFENGINE_PORT_STR, CF_DATA_TYPE_STRING, "source=bootstrap" ); } }
static void RenameMainBundle(EvalContext *ctx, Policy *policy) { assert(policy != NULL); assert(ctx != NULL); assert(policy->bundles != NULL); char *const entry_point = GetRealPath(EvalContextGetEntryPoint(ctx)); if (NULL_OR_EMPTY(entry_point)) { free(entry_point); return; } Seq *bundles = policy->bundles; int length = SeqLength(bundles); bool removed = false; for (int i = 0; i < length; ++i) { Bundle *const bundle = SeqAt(bundles, i); if (StringSafeEqual(bundle->name, "__main__")) { char *abspath = GetRealPath(bundle->source_path); if (StringSafeEqual(abspath, entry_point)) { Log(LOG_LEVEL_VERBOSE, "Redefining __main__ bundle from file %s to be main", abspath); strncpy(bundle->name, "main", 4+1); // "__main__" is always big enough for "main" } else { Log(LOG_LEVEL_VERBOSE, "Dropping __main__ bundle from file %s (entry point: %s)", abspath, entry_point); removed = true; SeqSet(bundles, i, NULL); // SeqSet calls destroy function } free(abspath); } } if (removed) { SeqRemoveNulls(bundles); } free(entry_point); }
bool IsProcessNameRunning(char *procNameRegex) { char *colHeaders[CF_PROCCOLS]; Item *ip; int start[CF_PROCCOLS] = { 0 }; int end[CF_PROCCOLS] = { 0 }; bool matched = false; if (PROCESSTABLE == NULL) { CfOut(cf_error, "", "!! IsProcessNameRunning: PROCESSTABLE is empty"); return false; } GetProcessColumnNames(PROCESSTABLE->name, (char **) colHeaders, start, end); for (ip = PROCESSTABLE->next; ip != NULL; ip = ip->next) // iterate over ps lines { char *lineSplit[CF_PROCCOLS]; if (NULL_OR_EMPTY(ip->name)) { continue; } if (!SplitProcLine(ip->name, colHeaders, start, end, lineSplit)) { CfOut(cf_error, "", "!! IsProcessNameRunning: Could not split process line \"%s\"", ip->name); continue; } if (SelectProcRegexMatch("CMD", "COMMAND", procNameRegex, colHeaders, lineSplit)) { matched = true; break; } } return matched; }
static bool VerifyBootstrap(void) { struct stat sb; char filePath[CF_MAXVARSIZE]; if (NULL_OR_EMPTY(POLICY_SERVER)) { CfOut(cf_error, "", "!! Bootstrapping failed, no policy server is specified"); return false; } // we should at least have gotten promises.cf from the policy hub snprintf(filePath, sizeof(filePath), "%s/inputs/promises.cf", CFWORKDIR); MapName(filePath); if (cfstat(filePath, &sb) == -1) { CfOut(cf_error, "", "!! Bootstrapping failed, no input file at %s after bootstrap", filePath); return false; } // embedded failsafe.cf (bootstrap.c) contains a promise to start cf-execd (executed while running this cf-agent) DeleteItemList(PROCESSTABLE); PROCESSTABLE = NULL; LoadProcessTable(&PROCESSTABLE); if (!IsProcessNameRunning(".*cf-execd.*")) { CfOut(cf_error, "", "!! Bootstrapping failed, cf-execd is not running"); return false; } CfOut(cf_cmdout, "", "-> Bootstrap to %s completed successfully", POLICY_SERVER); return true; }
int main(int argc, char *argv[]) { int ret = 0; GenericAgentConfig *config = CheckOpts(argc, argv); #ifdef HAVE_AVAHI_CLIENT_CLIENT_H #ifdef HAVE_AVAHI_COMMON_ADDRESS_H if (NULL_OR_EMPTY(POLICY_SERVER) && BOOTSTRAP) { int ret = AutomaticBootstrap(); if (ret < 0) { return 1; } } #endif #endif ReportContext *report_context = OpenReports(config->agent_type); GenericAgentDiscoverContext(config, report_context); Policy *policy = NULL; if (GenericAgentCheckPolicy(config, report_context, ALWAYS_VALIDATE)) { policy = GenericAgentLoadPolicy(config->agent_type, config, report_context); } else if (config->tty_interactive) { FatalError("CFEngine was not able to get confirmation of promises from cf-promises, please verify input file\n"); } else { CfOut(OUTPUT_LEVEL_ERROR, "", "CFEngine was not able to get confirmation of promises from cf-promises, so going to failsafe\n"); HardClass("failsafe_fallback"); GenericAgentConfigSetInputFile(config, "failsafe.cf"); policy = GenericAgentLoadPolicy(config->agent_type, config, report_context); } CheckLicenses(); ThisAgentInit(); BeginAudit(); KeepPromises(policy, config, report_context); CloseReports("agent", report_context); // only note class usage when default policy is run if (!config->input_file) { NoteClassUsage(VHEAP, true); NoteClassUsage(VHARDHEAP, true); } #ifdef HAVE_NOVA Nova_NoteVarUsageDB(); Nova_TrackExecution(config->input_file); #endif PurgeLocks(); if (BOOTSTRAP && !VerifyBootstrap()) { ret = 1; } EndAudit(CFA_BACKGROUND); GenericAgentConfigDestroy(config); return ret; }
void SetPolicyServer(char *name) /* * If name contains a string, it's written to file, * if not, name is filled with the contents of file. */ { char file[CF_BUFSIZE]; FILE *fout, *fin; char fileContents[CF_MAXVARSIZE] = { 0 }; snprintf(file, CF_BUFSIZE - 1, "%s/policy_server.dat", CFWORKDIR); MapName(file); if ((fin = fopen(file, "r")) != NULL) { fscanf(fin, "%1023s", fileContents); fclose(fin); } // update file if different and we know what to put there if ((NULL_OR_EMPTY(name)) && (!NULL_OR_EMPTY(fileContents))) { snprintf(name, CF_MAXVARSIZE, "%s", fileContents); } else if ((!NULL_OR_EMPTY(name)) && (strcmp(name, fileContents) != 0)) { if ((fout = fopen(file, "w")) == NULL) { CfOut(cf_error, "fopen", "Unable to write policy server file! (%s)", file); return; } fprintf(fout, "%s", name); fclose(fout); } if (NULL_OR_EMPTY(name)) { // avoids "Scalar item in servers => { } in rvalue is out of bounds ..." // when NovaBase is checked with unprivileged (not bootstrapped) cf-promises NewScalar("sys", "policy_hub", "undefined", cf_str); } else { NewScalar("sys", "policy_hub", name, cf_str); } // Get the timestamp on policy update snprintf(file, CF_MAXVARSIZE, "%s/masterfiles/cf_promises_validated", CFWORKDIR); MapName(file); struct stat sb; if ((cfstat(file, &sb)) != 0) { return; } char timebuf[26]; cf_strtimestamp_local(sb.st_mtime, timebuf); NewScalar("sys", "last_policy_update", timebuf, cf_str); }
static int FindPidMatches(Item *procdata, Item **killlist, Attributes a, Promise *pp) { Item *ip; int pid = -1, matches = 0, i, s, e, promised_zero; pid_t cfengine_pid = getpid(); char *names[CF_PROCCOLS]; /* ps headers */ int start[CF_PROCCOLS]; int end[CF_PROCCOLS]; if (procdata == NULL) { return 0; } GetProcessColumnNames(procdata->name, (char **) names, start, end); for (ip = procdata->next; ip != NULL; ip = ip->next) { CF_OCCUR++; if (BlockTextMatch(pp->promiser, ip->name, &s, &e)) { if (NULL_OR_EMPTY(ip->name)) { continue; } if (!SelectProcess(ip->name, names, start, end, a, pp)) { continue; } pid = ExtractPid(ip->name, names, start, end); if (pid == -1) { CfOut(cf_verbose, "", "Unable to extract pid while looking for %s\n", pp->promiser); continue; } CfOut(cf_verbose, "", " -> Found matching pid %d\n (%s)", pid, ip->name); matches++; if (pid == 1) { if ((RlistLen(a.signals) == 1) && IsStringIn(a.signals, "hup")) { CfOut(cf_verbose, "", "(Okay to send only HUP to init)\n"); } else { continue; } } if (pid < 4 && a.signals) { CfOut(cf_verbose, "", "Will not signal or restart processes 0,1,2,3 (occurred while looking for %s)\n", pp->promiser); continue; } promised_zero = a.process_count.min_range == 0 && a.process_count.max_range == 0; if (a.transaction.action == cfa_warn && promised_zero) { CfOut(cf_error, "", "Process alert: %s\n", procdata->name); /* legend */ CfOut(cf_error, "", "Process alert: %s\n", ip->name); continue; } if (pid == cfengine_pid && a.signals) { CfOut(cf_verbose, "", " !! cf-agent will not signal itself!\n"); continue; } PrependItem(killlist, ip->name, ""); (*killlist)->counter = pid; } } // Free up allocated memory for (i = 0; i < CF_PROCCOLS; i++) { if (names[i] != NULL) { free(names[i]); } } return matches; }
static void HailExec(AgentConnection *conn, char *peer) { char sendbuf[CF_BUFSIZE - CF_INBAND_OFFSET] = "EXEC"; size_t sendbuf_len = strlen(sendbuf); if (!NULL_OR_EMPTY(DEFINECLASSES)) { StrCat(sendbuf, sizeof(sendbuf), &sendbuf_len, " -D", 0); StrCat(sendbuf, sizeof(sendbuf), &sendbuf_len, DEFINECLASSES, 0); } if (!NULL_OR_EMPTY(REMOTEBUNDLES)) { StrCat(sendbuf, sizeof(sendbuf), &sendbuf_len, " -b ", 0); StrCat(sendbuf, sizeof(sendbuf), &sendbuf_len, REMOTEBUNDLES, 0); } if (sendbuf_len >= sizeof(sendbuf)) { Log(LOG_LEVEL_ERR, "Command longer than maximum transaction packet"); DisconnectServer(conn); return; } if (SendTransaction(conn->conn_info, sendbuf, 0, CF_DONE) == -1) { Log(LOG_LEVEL_ERR, "Transmission rejected. (send: %s)", GetErrorStr()); DisconnectServer(conn); return; } /* TODO we are sending class data right after EXEC, when the server might * have already rejected us with BAD reply. So this class data with the * CFD_TERMINATOR will be interpreted by the server as a new, bogus * protocol command, and the server will complain. */ SendClassData(conn); char recvbuffer[CF_BUFSIZE]; FILE *fp = NewStream(peer); while (true) { memset(recvbuffer, 0, sizeof(recvbuffer)); if (ReceiveTransaction(conn->conn_info, recvbuffer, NULL) == -1) { break; } if (strncmp(recvbuffer, CFD_TERMINATOR, strlen(CFD_TERMINATOR)) == 0) { break; } const size_t recv_len = strlen(recvbuffer); const char *ipaddr = conn->remoteip; if (strncmp(recvbuffer, "BAD:", 4) == 0) { fprintf(fp, "%s> !! %s\n", ipaddr, recvbuffer + 4); } /* cf-serverd >= 3.7 quotes command output with "> ". */ else if (strncmp(recvbuffer, "> ", 2) == 0) { fprintf(fp, "%s> -> %s", ipaddr, &recvbuffer[2]); } else { fprintf(fp, "%s> %s", ipaddr, recvbuffer); } if (recv_len > 0 && recvbuffer[recv_len - 1] != '\n') { /* We'll be printing double newlines here with new cf-serverd * versions, so check for already trailing newlines. */ /* TODO deprecate this path in a couple of versions. cf-serverd is * supposed to munch the newlines so we must always append one. */ fputc('\n', fp); } } if (fp != stdout) { fclose(fp); } DisconnectServer(conn); }
void IPString2KeyDigest(char *ipv4, char *result) { CF_DB *dbp; CF_DBC *dbcp; char *key; void *value; KeyHostSeen entry; int ksize, vsize; unsigned char digest[EVP_MAX_MD_SIZE + 1]; result[0] = '\0'; if (strcmp(ipv4, "127.0.0.1") == 0 || strcmp(ipv4, "::1") == 0 || strcmp(ipv4, VIPADDRESS) == 0) { if (PUBKEY) { HashPubKey(PUBKEY, digest, CF_DEFAULT_DIGEST); snprintf(result, CF_MAXVARSIZE, "%s", HashPrint(CF_DEFAULT_DIGEST, digest)); } return; } if (!OpenDB(&dbp, dbid_lastseen)) { return; } if (!NewDBCursor(dbp, &dbcp)) { CfOut(cf_inform, "", " !! Unable to scan last-seen database"); CloseDB(dbp); return; } /* Initialize the key/data return pair. */ memset(&entry, 0, sizeof(entry)); /* Walk through the database and print out the key/data pairs. */ while (NextDB(dbp, dbcp, &key, &ksize, &value, &vsize)) { if (value != NULL) { memcpy(&entry, value, sizeof(entry)); // Warning this is not 1:1 if (strcmp(ipv4, MapAddress((char *) entry.address)) == 0) { CfOut(cf_verbose, "", " -> Matched IP %s to key %s", ipv4, key + 1); strncpy(result, key + 1, CF_MAXVARSIZE - 1); break; } } } DeleteDBCursor(dbp, dbcp); CloseDB(dbp); if (NULL_OR_EMPTY(result)) { CfOut(cf_verbose, "", "!! Unable to find a key for ip %s", ipv4); } }
void LoadSecretKeys() { FILE *fp; static char *passphrase = "Cfengine passphrase", name[CF_BUFSIZE], source[CF_BUFSIZE]; char guard[CF_MAXVARSIZE]; unsigned char digest[EVP_MAX_MD_SIZE + 1]; unsigned long err; struct stat sb; if ((fp = fopen(PrivateKeyFile(), "r")) == NULL) { CfOut(OUTPUT_LEVEL_INFORM, "fopen", "Couldn't find a private key (%s) - use cf-key to get one", PrivateKeyFile()); return; } if ((PRIVKEY = PEM_read_RSAPrivateKey(fp, (RSA **) NULL, NULL, passphrase)) == NULL) { err = ERR_get_error(); CfOut(OUTPUT_LEVEL_ERROR, "PEM_read", "Error reading Private Key = %s\n", ERR_reason_error_string(err)); PRIVKEY = NULL; fclose(fp); return; } fclose(fp); CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Loaded private key %s\n", PrivateKeyFile()); if ((fp = fopen(PublicKeyFile(), "r")) == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "fopen", "Couldn't find a public key (%s) - use cf-key to get one", PublicKeyFile()); return; } if ((PUBKEY = PEM_read_RSAPublicKey(fp, NULL, NULL, passphrase)) == NULL) { err = ERR_get_error(); CfOut(OUTPUT_LEVEL_ERROR, "PEM_read", "Error reading Private Key = %s\n", ERR_reason_error_string(err)); PUBKEY = NULL; fclose(fp); return; } CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Loaded public key %s\n", PublicKeyFile()); fclose(fp); if ((BN_num_bits(PUBKEY->e) < 2) || (!BN_is_odd(PUBKEY->e))) { FatalError("RSA Exponent too small or not odd"); } if (NULL_OR_EMPTY(POLICY_SERVER)) { snprintf(name, CF_MAXVARSIZE - 1, "%s%cpolicy_server.dat", CFWORKDIR, FILE_SEPARATOR); if ((fp = fopen(name, "r")) != NULL) { if (fscanf(fp, "%4095s", POLICY_SERVER) != 1) { CfDebug("Couldn't read string from policy_server.dat"); } fclose(fp); } } /* Check that we have our own SHA key form of the key in the IP on the hub */ char buffer[EVP_MAX_MD_SIZE * 4]; HashPubKey(PUBKEY, digest, CF_DEFAULT_DIGEST); snprintf(name, CF_MAXVARSIZE, "%s/ppkeys/%s-%s.pub", CFWORKDIR, "root", HashPrintSafe(CF_DEFAULT_DIGEST, digest, buffer)); MapName(name); snprintf(source, CF_MAXVARSIZE, "%s/ppkeys/localhost.pub", CFWORKDIR); MapName(source); // During bootstrap we need the pre-registered IP/hash pair on the hub snprintf(guard, sizeof(guard), "%s/state/am_policy_hub", CFWORKDIR); MapName(guard); // need to use cf_stat if ((stat(name, &sb) == -1) && (stat(guard, &sb) != -1)) // copy localhost.pub to root-HASH.pub on policy server { LastSaw(POLICY_SERVER, digest, LAST_SEEN_ROLE_CONNECT); if (!LinkOrCopy(source, name, false)) { CfOut(OUTPUT_LEVEL_ERROR, "", " -> Unable to clone server's key file as %s\n", name); } } }