Beispiel #1
0
static bool ScheduleRun(EvalContext *ctx, Policy **policy, GenericAgentConfig *config, ExecConfig *exec_config)
{
    CfOut(OUTPUT_LEVEL_VERBOSE, "", "Sleeping for pulse time %d seconds...\n", CFPULSETIME);
    sleep(CFPULSETIME);         /* 1 Minute resolution is enough */

    /*
     * FIXME: this logic duplicates the one from cf-serverd.c. Unify ASAP.
     */

    if (CheckNewPromises(ctx, config, InputFiles(ctx, *policy)) == RELOAD_FULL)
    {
        /* Full reload */

        CfOut(OUTPUT_LEVEL_INFORM, "", "Re-reading promise file %s..\n", config->input_file);

        EvalContextHeapClear(ctx);

        DeleteItemList(IPADDRESSES);
        IPADDRESSES = NULL;

        ScopeDeleteAll();

        strcpy(VDOMAIN, "undefined.domain");
        POLICY_SERVER[0] = '\0';

        PolicyDestroy(*policy);
        *policy = NULL;

        SetPolicyServer(ctx, POLICY_SERVER);
        ScopeNewSpecialScalar(ctx, "sys", "policy_hub", POLICY_SERVER, DATA_TYPE_STRING);

        GetNameInfo3(ctx, AGENT_TYPE_EXECUTOR);
        GetInterfacesInfo(ctx, AGENT_TYPE_EXECUTOR);
        Get3Environment(ctx, AGENT_TYPE_EXECUTOR);
        BuiltinClasses(ctx);
        OSClasses(ctx);

        EvalContextHeapAddHard(ctx, CF_AGENTTYPES[AGENT_TYPE_EXECUTOR]);

        SetReferenceTime(ctx, true);

        GenericAgentConfigSetBundleSequence(config, NULL);

        *policy = GenericAgentLoadPolicy(ctx, config);
        ExecConfigUpdate(ctx, *policy, exec_config);

        SetFacility(exec_config->log_facility);
    }
    else
    {
        /* Environment reload */

        EvalContextHeapClear(ctx);

        DeleteItemList(IPADDRESSES);
        IPADDRESSES = NULL;

        ScopeClear("this");
        ScopeClear("mon");
        ScopeClear("sys");

        GetInterfacesInfo(ctx, AGENT_TYPE_EXECUTOR);
        Get3Environment(ctx, AGENT_TYPE_EXECUTOR);
        BuiltinClasses(ctx);
        OSClasses(ctx);
        SetReferenceTime(ctx, true);
    }

    {
        StringSetIterator it = StringSetIteratorInit(exec_config->schedule);
        const char *time_context = NULL;
        while ((time_context = StringSetIteratorNext(&it)))
        {
            if (IsDefinedClass(ctx, time_context, NULL))
            {
                CfOut(OUTPUT_LEVEL_VERBOSE, "", "Waking up the agent at %s ~ %s \n", cf_ctime(&CFSTARTTIME), time_context);
                return true;
            }
        }
    }

    CfOut(OUTPUT_LEVEL_VERBOSE, "", "Nothing to do at %s\n", cf_ctime(&CFSTARTTIME));
    return false;
}
Beispiel #2
0
static bool ScheduleRun(Policy **policy, GenericAgentConfig *config, ExecConfig *exec_config, const ReportContext *report_context)
{
    Item *ip;

    CfOut(OUTPUT_LEVEL_VERBOSE, "", "Sleeping...\n");
    sleep(CFPULSETIME);         /* 1 Minute resolution is enough */

// recheck license (in case of license updates or expiry)

    if (EnterpriseExpiry())
    {
        CfOut(OUTPUT_LEVEL_ERROR, "", "Cfengine - autonomous configuration engine. This enterprise license is invalid.\n");
        exit(1);
    }

    /*
     * FIXME: this logic duplicates the one from cf-serverd.c. Unify ASAP.
     */

    if (CheckNewPromises(config->input_file, InputFiles(*policy), report_context) == RELOAD_FULL)
    {
        /* Full reload */

        CfOut(OUTPUT_LEVEL_INFORM, "", "Re-reading promise file %s..\n", config->input_file);

        DeleteAlphaList(&VHEAP);
        InitAlphaList(&VHEAP);
        DeleteAlphaList(&VHARDHEAP);
        InitAlphaList(&VHARDHEAP);
        DeleteAlphaList(&VADDCLASSES);
        InitAlphaList(&VADDCLASSES);

        DeleteItemList(IPADDRESSES);
        IPADDRESSES = NULL;

        DeleteItemList(VNEGHEAP);

        DeleteAllScope();

        strcpy(VDOMAIN, "undefinded.domain");
        POLICY_SERVER[0] = '\0';

        VNEGHEAP = NULL;

        PolicyDestroy(*policy);
        *policy = NULL;

        ERRORCOUNT = 0;

        NewScope("sys");

        SetPolicyServer(POLICY_SERVER);
        NewScalar("sys", "policy_hub", POLICY_SERVER, DATA_TYPE_STRING);

        NewScope("const");
        NewScope("this");
        NewScope("mon");
        NewScope("control_server");
        NewScope("control_common");
        NewScope("remote_access");

        GetNameInfo3();
        GetInterfacesInfo(AGENT_TYPE_EXECUTOR);
        Get3Environment();
        BuiltinClasses();
        OSClasses();

        HardClass(CF_AGENTTYPES[THIS_AGENT_TYPE]);

        SetReferenceTime(true);

        GenericAgentConfigSetBundleSequence(config, NULL);

        *policy = GenericAgentLoadPolicy(AGENT_TYPE_EXECUTOR, config, report_context);
        KeepPromises(*policy, exec_config);
    }
    else
    {
        /* Environment reload */

        DeleteAlphaList(&VHEAP);
        InitAlphaList(&VHEAP);
        DeleteAlphaList(&VADDCLASSES);
        InitAlphaList(&VADDCLASSES);
        DeleteAlphaList(&VHARDHEAP);
        InitAlphaList(&VHARDHEAP);

        DeleteItemList(IPADDRESSES);
        IPADDRESSES = NULL;


        DeleteScope("this");
        DeleteScope("mon");
        DeleteScope("sys");
        NewScope("this");
        NewScope("mon");
        NewScope("sys");

        GetInterfacesInfo(AGENT_TYPE_EXECUTOR);
        Get3Environment();
        BuiltinClasses();
        OSClasses();
        SetReferenceTime(true);
    }

    for (ip = SCHEDULE; ip != NULL; ip = ip->next)
    {
        CfOut(OUTPUT_LEVEL_VERBOSE, "", "Checking schedule %s...\n", ip->name);

        if (IsDefinedClass(ip->name, NULL))
        {
            CfOut(OUTPUT_LEVEL_VERBOSE, "", "Waking up the agent at %s ~ %s \n", cf_ctime(&CFSTARTTIME), ip->name);
            return true;
        }
    }

    CfOut(OUTPUT_LEVEL_VERBOSE, "", "Nothing to do at %s\n", cf_ctime(&CFSTARTTIME));
    return false;
}
Beispiel #3
0
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
}
Beispiel #4
0
void CheckFileChanges(Policy **policy, GenericAgentConfig *config, const ReportContext *report_context)
{
    if (EnterpriseExpiry())
    {
        CfOut(cf_error, "", "!! This enterprise license is invalid.");
    }

    CfDebug("Checking file updates on %s\n", config->input_file);

    if (NewPromiseProposals(config->input_file, InputFiles(*policy)))
    {
        CfOut(cf_verbose, "", " -> New promises detected...\n");

        if (CheckPromises(config->input_file, report_context))
        {
            CfOut(cf_inform, "", "Rereading config files %s..\n", config->input_file);

            /* Free & reload -- lock this to avoid access errors during reload */

            DeleteItemList(VNEGHEAP);
            
            DeleteAlphaList(&VHEAP);
            InitAlphaList(&VHEAP);
            DeleteAlphaList(&VHARDHEAP);
            InitAlphaList(&VHARDHEAP);
            
            DeleteAlphaList(&VADDCLASSES);
            InitAlphaList(&VADDCLASSES);

            DeleteItemList(IPADDRESSES);
            IPADDRESSES = NULL;

            DeleteItemList(SV.trustkeylist);
            DeleteItemList(SV.skipverify);
            DeleteItemList(SV.attackerlist);
            DeleteItemList(SV.nonattackerlist);
            DeleteItemList(SV.multiconnlist);

            DeleteAuthList(VADMIT);
            DeleteAuthList(VDENY);

            DeleteAuthList(VARADMIT);
            DeleteAuthList(VARDENY);

            DeleteAuthList(ROLES);

            //DeleteRlist(VINPUTLIST); This is just a pointer, cannot free it

            DeleteAllScope();

            strcpy(VDOMAIN, "undefined.domain");
            POLICY_SERVER[0] = '\0';

            VADMIT = VADMITTOP = NULL;
            VDENY = VDENYTOP = NULL;

            VARADMIT = VARADMITTOP = NULL;
            VARDENY = VARDENYTOP = NULL;

            ROLES = ROLESTOP = NULL;

            VNEGHEAP = NULL;
            SV.trustkeylist = NULL;
            SV.skipverify = NULL;
            SV.attackerlist = NULL;
            SV.nonattackerlist = NULL;
            SV.multiconnlist = NULL;

            PolicyDestroy(*policy);
            *policy = NULL;

            ERRORCOUNT = 0;

            NewScope("sys");

            SetPolicyServer(POLICY_SERVER);
            NewScalar("sys", "policy_hub", POLICY_SERVER, DATA_TYPE_STRING);

            if (EnterpriseExpiry())
            {
                CfOut(cf_error, "",
                      "Cfengine - autonomous configuration engine. This enterprise license is invalid.\n");
            }

            NewScope("const");
            NewScope("this");
            NewScope("control_server");
            NewScope("control_common");
            NewScope("mon");
            NewScope("remote_access");
            GetNameInfo3();
            GetInterfacesInfo(AGENT_TYPE_SERVER);
            Get3Environment();
            BuiltinClasses();
            OSClasses();
            KeepHardClasses();

            HardClass(CF_AGENTTYPES[THIS_AGENT_TYPE]);

            SetReferenceTime(true);
            *policy = ReadPromises(AGENT_TYPE_SERVER, config, report_context);
            KeepPromises(*policy, config, report_context);
            Summarize();

        }
        else
        {
            CfOut(cf_inform, "", " !! File changes contain errors -- ignoring");
            PROMISETIME = time(NULL);
        }
    }
    else
    {
        CfDebug(" -> No new promises found\n");
    }
}
int OpenReceiverChannel(void)
{
    struct addrinfo *response, *ap;
    struct addrinfo query = {
        .ai_flags = AI_PASSIVE,
        .ai_family = AF_UNSPEC,
        .ai_socktype = SOCK_STREAM
    };

    /* Listen to INADDR(6)_ANY if BINDINTERFACE unset. */
    char *ptr = NULL;
    if (BINDINTERFACE[0] != '\0')
    {
        ptr = BINDINTERFACE;
    }

    /* Resolve listening interface. */
    if (getaddrinfo(ptr, STR_CFENGINEPORT, &query, &response) != 0)
    {
        Log(LOG_LEVEL_ERR, "DNS/service lookup failure. (getaddrinfo: %s)", GetErrorStr());
        return -1;
    }

    int sd = -1;
    for (ap = response; ap != NULL; ap = ap->ai_next)
    {
        if ((sd = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol)) == -1)
        {
            continue;
        }

        int yes = 1;
        if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,
                       &yes, sizeof(yes)) == -1)
        {
            Log(LOG_LEVEL_ERR, "Socket option SO_REUSEADDR was not accepted. (setsockopt: %s)", GetErrorStr());
            exit(1);
        }

        struct linger cflinger = {
            .l_onoff = 1,
            .l_linger = 60
        };
        if (setsockopt(sd, SOL_SOCKET, SO_LINGER,
                       &cflinger, sizeof(cflinger)) == -1)
        {
            Log(LOG_LEVEL_ERR, "Socket option SO_LINGER was not accepted. (setsockopt: %s)", GetErrorStr());
            exit(1);
        }

        if (bind(sd, ap->ai_addr, ap->ai_addrlen) != -1)
        {
            if (LogGetGlobalLevel() >= LOG_LEVEL_DEBUG)
            {
                /* Convert IP address to string, no DNS lookup performed. */
                char txtaddr[CF_MAX_IP_LEN] = "";
                getnameinfo(ap->ai_addr, ap->ai_addrlen,
                            txtaddr, sizeof(txtaddr),
                            NULL, 0, NI_NUMERICHOST);
                Log(LOG_LEVEL_DEBUG, "Bound to address '%s' on '%s' = %d", txtaddr,
                    CLASSTEXT[VSYSTEMHARDCLASS], VSYSTEMHARDCLASS);
            }
            break;
        }
        else
        {
            Log(LOG_LEVEL_ERR, "Could not bind server address. (bind: %s)", GetErrorStr());
            cf_closesocket(sd);
        }
    }

    if (sd < 0)
    {
        Log(LOG_LEVEL_ERR, "Couldn't open/bind a socket");
        exit(1);
    }

    freeaddrinfo(response);
    return sd;
}

/*********************************************************************/
/* Level 3                                                           */
/*********************************************************************/

void CheckFileChanges(EvalContext *ctx, Policy **policy, GenericAgentConfig *config)
{
    Log(LOG_LEVEL_DEBUG, "Checking file updates for input file '%s'", config->input_file);

    if (NewPromiseProposals(ctx, config, InputFiles(ctx, *policy)))
    {
        Log(LOG_LEVEL_VERBOSE, "New promises detected...");

        if (CheckPromises(config))
        {
            Log(LOG_LEVEL_INFO, "Rereading policy file '%s'", config->input_file);

            /* Free & reload -- lock this to avoid access errors during reload */
            
            EvalContextHeapClear(ctx);

            DeleteItemList(IPADDRESSES);
            IPADDRESSES = NULL;

            DeleteItemList(SV.trustkeylist);
            DeleteItemList(SV.skipverify);
            DeleteItemList(SV.attackerlist);
            DeleteItemList(SV.nonattackerlist);
            DeleteItemList(SV.multiconnlist);

            DeleteAuthList(SV.admit);
            DeleteAuthList(SV.deny);

            DeleteAuthList(SV.varadmit);
            DeleteAuthList(SV.vardeny);

            DeleteAuthList(SV.roles);

            //DeleteRlist(VINPUTLIST); This is just a pointer, cannot free it

            ScopeDeleteAll();

            strcpy(VDOMAIN, "undefined.domain");
            POLICY_SERVER[0] = '\0';

            SV.admit = NULL;
            SV.admittop = NULL;

            SV.varadmit = NULL;
            SV.varadmittop = NULL;

            SV.deny = NULL;
            SV.denytop = NULL;

            SV.vardeny = NULL;
            SV.vardenytop = NULL;

            SV.roles = NULL;
            SV.rolestop = NULL;

            SV.trustkeylist = NULL;
            SV.skipverify = NULL;
            SV.attackerlist = NULL;
            SV.nonattackerlist = NULL;
            SV.multiconnlist = NULL;

            PolicyDestroy(*policy);
            *policy = NULL;

            {
                char *existing_policy_server = ReadPolicyServerFile(GetWorkDir());
                SetPolicyServer(ctx, existing_policy_server);
                free(existing_policy_server);
            }

            GetNameInfo3(ctx, AGENT_TYPE_SERVER);
            GetInterfacesInfo(ctx, AGENT_TYPE_SERVER);
            Get3Environment(ctx, AGENT_TYPE_SERVER);
            BuiltinClasses(ctx);
            OSClasses(ctx);
            KeepHardClasses(ctx);

            EvalContextHeapAddHard(ctx, CF_AGENTTYPES[config->agent_type]);

            SetReferenceTime(ctx, true);
            *policy = GenericAgentLoadPolicy(ctx, config);
            KeepPromises(ctx, *policy, config);
            Summarize();

        }
        else
        {
            Log(LOG_LEVEL_INFO, "File changes contain errors -- ignoring");
            PROMISETIME = time(NULL);
        }
    }
    else
    {
        Log(LOG_LEVEL_DEBUG, "No new promises found");
    }
}