示例#1
0
static PromiseResult VerifyServices(EvalContext *ctx, Attributes a, const Promise *pp)
{
    CfLock thislock;

    thislock = AcquireLock(ctx, pp->promiser, VUQNAME, CFSTARTTIME, a.transaction, pp, false);
    if (thislock.lock == NULL)
    {
        return PROMISE_RESULT_SKIPPED;
    }

    PromiseBanner(ctx, pp);

    PromiseResult result = PROMISE_RESULT_SKIPPED;
    if (strcmp(a.service.service_type, "windows") == 0)
    {
#ifdef __MINGW32__
        result = PromiseResultUpdate(result, VerifyWindowsService(ctx, a, pp));
#else
        Log(LOG_LEVEL_INFO, "Service type windows not supported on this platform.");
#endif
    }
    else
    {
        result = PromiseResultUpdate(result, DoVerifyServices(ctx, a, pp));
    }

    YieldCurrentLock(thislock);

    return result;
}
示例#2
0
static void VerifyProcesses(EvalContext *ctx, Attributes a, Promise *pp)
{
    CfLock thislock;
    char lockname[CF_BUFSIZE];

    if (a.restart_class)
    {
        snprintf(lockname, CF_BUFSIZE - 1, "proc-%s-%s", pp->promiser, a.restart_class);
    }
    else
    {
        snprintf(lockname, CF_BUFSIZE - 1, "proc-%s-norestart", pp->promiser);
    }

    thislock = AcquireLock(ctx, lockname, VUQNAME, CFSTARTTIME, a.transaction, pp, false);

    if (thislock.lock == NULL)
    {
        return;
    }

    EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser", pp->promiser, DATA_TYPE_STRING);
    PromiseBanner(pp);
    VerifyProcessOp(ctx, PROCESSTABLE, a, pp);
    EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser");

    YieldCurrentLock(thislock);
}
示例#3
0
static PromiseResult VerifyProcesses(EvalContext *ctx, Attributes a, const Promise *pp)
{
    CfLock thislock;
    char lockname[CF_BUFSIZE];

    if (a.restart_class)
    {
        snprintf(lockname, CF_BUFSIZE - 1, "proc-%s-%s", pp->promiser, a.restart_class);
    }
    else
    {
        snprintf(lockname, CF_BUFSIZE - 1, "proc-%s-norestart", pp->promiser);
    }

    thislock = AcquireLock(ctx, lockname, VUQNAME, CFSTARTTIME, a.transaction, pp, false);
    if (thislock.lock == NULL)
    {
        return PROMISE_RESULT_SKIPPED;
    }

    PromiseBanner(pp);
    PromiseResult result = VerifyProcessOp(ctx, PROCESSTABLE, a, pp);

    YieldCurrentLock(thislock);

    return result;
}
示例#4
0
void VerifyEnvironmentsPromise(EvalContext *ctx, Promise *pp)
{
    Attributes a = { {0} };
    CfLock thislock;
    Promise *pexp;

    a = GetEnvironmentsAttributes(ctx, pp);

    if (EnvironmentsSanityChecks(a, pp))
    {
        thislock = AcquireLock(ctx, "virtual", VUQNAME, CFSTARTTIME, a.transaction, pp, false);

        if (thislock.lock == NULL)
        {
            return;
        }

        PromiseBanner(pp);
        ScopeNewSpecialScalar(ctx, "this", "promiser", pp->promiser, DATA_TYPE_STRING);

        pexp = ExpandDeRefPromise(ctx, "this", pp);
        VerifyEnvironments(ctx, a, pp);
        PromiseDestroy(pexp);
    }

    YieldCurrentLock(thislock);
}
示例#5
0
static PromiseResult VerifyServices(EvalContext *ctx, Attributes a, Promise *pp)
{
    CfLock thislock;

    thislock = AcquireLock(ctx, pp->promiser, VUQNAME, CFSTARTTIME, a.transaction, pp, false);
    if (thislock.lock == NULL)
    {
        return PROMISE_RESULT_SKIPPED;
    }

    EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser", pp->promiser, DATA_TYPE_STRING, "goal=state,source=promise");
    PromiseBanner(pp);

    PromiseResult result = PROMISE_RESULT_NOOP;
    if (strcmp(a.service.service_type, "windows") == 0)
    {
        result = PromiseResultUpdate(result, VerifyWindowsService(ctx, a, pp));
    }
    else
    {
        result = PromiseResultUpdate(result, DoVerifyServices(ctx, a, pp));
    }

    EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser");
    YieldCurrentLock(thislock);

    return result;
}
示例#6
0
void VerifyEnvironmentsPromise(Promise *pp)
{
    Attributes a = { {0} };
    CfLock thislock;
    Promise *pexp;

    a = GetEnvironmentsAttributes(pp);

    if (EnvironmentsSanityChecks(a, pp))
    {
        thislock = AcquireLock("virtual", VUQNAME, CFSTARTTIME, a, pp, false);

        if (thislock.lock == NULL)
        {
            return;
        }

        CF_OCCUR++;

        PromiseBanner(pp);
        NewScalar("this", "promiser", pp->promiser, cf_str);

        pexp = ExpandDeRefPromise("this", pp);
        VerifyEnvironments(a, pp);
        DeletePromise(pexp);
    }

    YieldCurrentLock(thislock);
}
示例#7
0
static PromiseResult VerifyServices(EvalContext *ctx, Attributes a, const Promise *pp)
{
    CfLock thislock;

    thislock = AcquireLock(ctx, pp->promiser, VUQNAME, CFSTARTTIME, a.transaction, pp, false);
    if (thislock.lock == NULL)
    {
        return PROMISE_RESULT_SKIPPED;
    }

    EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser", pp->promiser, CF_DATA_TYPE_STRING, "source=promise");
    PromiseBanner(pp);

    PromiseResult result = PROMISE_RESULT_NOOP;
    if (strcmp(a.service.service_type, "windows") == 0)
    {
#ifdef __MINGW32__
        result = PromiseResultUpdate(result, VerifyWindowsService(ctx, a, pp));
#else
        Log(LOG_LEVEL_INFO, "Service type windows not supported on this platform.");
#endif
    }
    else
    {
        result = PromiseResultUpdate(result, DoVerifyServices(ctx, a, pp));
    }

    EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser");
    YieldCurrentLock(thislock);

    return result;
}
示例#8
0
void VerifyProcesses(Attributes a, Promise *pp)
{
    CfLock thislock;
    char lockname[CF_BUFSIZE];

    if (a.restart_class)
    {
        snprintf(lockname, CF_BUFSIZE - 1, "proc-%s-%s", pp->promiser, a.restart_class);
    }
    else
    {
        snprintf(lockname, CF_BUFSIZE - 1, "proc-%s-norestart", pp->promiser);
    }

    thislock = AcquireLock(lockname, VUQNAME, CFSTARTTIME, a, pp, false);

    if (thislock.lock == NULL)
    {
        return;
    }

    DeleteScalar("this", "promiser");
    NewScalar("this", "promiser", pp->promiser, cf_str);
    PromiseBanner(pp);
    VerifyProcessOp(PROCESSTABLE, a, pp);
    DeleteScalar("this", "promiser");

    YieldCurrentLock(thislock);
}
示例#9
0
void VerifyExecPromise(EvalContext *ctx, Promise *pp)
{
    Attributes a = { {0} };

    a = GetExecAttributes(ctx, pp);

    ScopeNewSpecial(ctx, "this", "promiser", pp->promiser, DATA_TYPE_STRING);

    if (!SyntaxCheckExec(a, pp))
    {
        // cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "");
        ScopeDeleteSpecial("this", "promiser");
        return;
    }

    if (PromiseKeptExec(a, pp))
    {
        // cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_NOOP, pp, a, "");
        ScopeDeleteSpecial("this", "promiser");
        return;
    }

    char *lock_name = GetLockNameExec(a, pp);
    CfLock thislock = AcquireLock(ctx, lock_name, VUQNAME, CFSTARTTIME, a.transaction, pp, false);
    free(lock_name);

    if (thislock.lock == NULL)
    {
        // cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_FAIL, pp, a, "");
        ScopeDeleteSpecial("this", "promiser");
        return;
    }

    PromiseBanner(pp);

    switch (RepairExec(ctx, a, pp))
    {
    case ACTION_RESULT_OK:
        // cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "");
        break;

    case ACTION_RESULT_TIMEOUT:
        // cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_TIMEOUT, pp, a, "");
        break;

    case ACTION_RESULT_FAILED:
        // cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_FAIL, pp, a, "");
        break;

    default:
        ProgrammingError("Unexpected ActionResult value");
    }

    YieldCurrentLock(thislock);
    ScopeDeleteSpecial("this", "promiser");
}
示例#10
0
void VerifyReportPromise(struct Promise *pp)

{ struct Attributes a = {{0}};
  struct CfLock thislock;
  struct Rlist *rp;
  char unique_name[CF_EXPANDSIZE];

a = GetReportsAttributes(pp);

if (strcmp(pp->classes,"any") == 0)
   {
   CfOut(cf_verbose,""," --> Reports promises may not be in class \"any\"");
   return;
   }

snprintf(unique_name,CF_EXPANDSIZE-1,"%s_%d",pp->promiser,pp->lineno);
thislock = AcquireLock(unique_name,VUQNAME,CFSTARTTIME,a,pp,false);

if (thislock.lock == NULL)
   {
   return;
   }

PromiseBanner(pp);

cfPS(cf_verbose,CF_CHG,"",pp,a,"Report: %s", pp->promiser);

if (a.report.to_file)
   {
   CfFOut(a.report.to_file,cf_error,"","%s",pp->promiser);
   }
else
   {
   CfOut(cf_reporting,"","R: %s",pp->promiser);
   }

if (a.report.haveprintfile)
   {
   PrintFile(a,pp);
   }

if (a.report.showstate)
   {
   for (rp = a.report.showstate; rp != NULL; rp=rp->next)
      {
      ShowState(rp->item,a,pp);
      }
   }

if (a.report.havelastseen)
   {
   FriendStatus(a,pp);
   }
    
YieldCurrentLock(thislock);
}
示例#11
0
文件: locks.c 项目: shaunamarie/core
static void LocksCleanup(void)
{
    if (strlen(CFLOCK) > 0)
    {
        CfLock best_guess;
        best_guess.lock = xstrdup(CFLOCK);
        best_guess.last = xstrdup(CFLAST);
        best_guess.log = xstrdup(CFLOG);
        YieldCurrentLock(best_guess);
    }
}
示例#12
0
文件: verify_exec.c 项目: tzz/core
PromiseResult VerifyExecPromise(EvalContext *ctx, const Promise *pp)
{
    Attributes a = GetExecAttributes(ctx, pp);

    EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser", pp->promiser, DATA_TYPE_STRING, "source=promise");

    if (!SyntaxCheckExec(a, pp))
    {
        EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser");
        return PROMISE_RESULT_FAIL;
    }

    if (PromiseKeptExec(a, pp))
    {
        EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser");
        return PROMISE_RESULT_NOOP;
    }

    char *lock_name = GetLockNameExec(a, pp);
    CfLock thislock = AcquireLock(ctx, lock_name, VUQNAME, CFSTARTTIME, a.transaction, pp, false);
    free(lock_name);
    if (thislock.lock == NULL)
    {
        EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser");
        return PROMISE_RESULT_SKIPPED;
    }

    PromiseBanner(pp);

    PromiseResult result = PROMISE_RESULT_NOOP;
    switch (RepairExec(ctx, a, pp, &result))
    {
    case ACTION_RESULT_OK:
        result = PromiseResultUpdate(result, PROMISE_RESULT_CHANGE);
        break;

    case ACTION_RESULT_TIMEOUT:
        result = PromiseResultUpdate(result, PROMISE_RESULT_TIMEOUT);
        break;

    case ACTION_RESULT_FAILED:
        result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
        break;

    default:
        ProgrammingError("Unexpected ActionResult value");
    }

    YieldCurrentLock(thislock);
    EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser");

    return result;
}
示例#13
0
void VerifyReportPromise(Promise *pp)
{
    Attributes a = { {0} };
    CfLock thislock;
    Rlist *rp;
    char unique_name[CF_EXPANDSIZE];

    a = GetReportsAttributes(pp);

    snprintf(unique_name, CF_EXPANDSIZE - 1, "%s_%zu", pp->promiser, pp->offset.line);
    thislock = AcquireLock(unique_name, VUQNAME, CFSTARTTIME, a, pp, false);

    if (thislock.lock == NULL)
    {
        return;
    }

    PromiseBanner(pp);

    cfPS(cf_verbose, CF_CHG, "", pp, a, "Report: %s", pp->promiser);

    if (a.report.to_file)
    {
        CfFOut(a.report.to_file, cf_error, "", "%s", pp->promiser);
    }
    else
    {
        CfOut(cf_reporting, "", "R: %s", pp->promiser);
    }

    if (a.report.haveprintfile)
    {
        PrintFile(a, pp);
    }

    if (a.report.showstate)
    {
        for (rp = a.report.showstate; rp != NULL; rp = rp->next)
        {
            ShowState(rp->item);
        }
    }

    if (a.report.havelastseen)
    {
        /* Do nothing. Deprecated. */
    }

    YieldCurrentLock(thislock);
}
示例#14
0
PromiseResult VerifyUsersPromise(EvalContext *ctx, Promise *pp)
{
    Attributes a = { {0} };
    CfLock thislock;
    char lockname[CF_BUFSIZE];

    a = GetUserAttributes(ctx, pp);

    if (!UserSanityCheck(a, pp))
    {
        return PROMISE_RESULT_FAIL;
    }

    PromiseBanner(pp);

    snprintf(lockname, CF_BUFSIZE - 1, "user-%s-%d", pp->promiser, a.users.policy);

    thislock = AcquireLock(ctx, lockname, VUQNAME, CFSTARTTIME, a.transaction, pp, false);
    if (thislock.lock == NULL)
    {
        return PROMISE_RESULT_SKIPPED;
    }

    PromiseResult result = PROMISE_RESULT_NOOP;
    VerifyOneUsersPromise(pp->promiser, a.users, &result, a.transaction.action, ctx, &a, pp);

    switch (result) {
    case PROMISE_RESULT_NOOP:
        cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_NOOP, pp, a, "User promise kept");
        break;
    case PROMISE_RESULT_FAIL:
    case PROMISE_RESULT_DENIED:
    case PROMISE_RESULT_TIMEOUT:
    case PROMISE_RESULT_INTERRUPTED:
    case PROMISE_RESULT_WARN:
        cfPS(ctx, LOG_LEVEL_INFO, result, pp, a, "User promise not kept");
        break;
    case PROMISE_RESULT_CHANGE:
        cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "User promise repaired");
        break;
    default:
        ProgrammingError("Unknown promise result");
        break;
    }
 

    YieldCurrentLock(thislock);
    return result;
}
示例#15
0
文件: signals.c 项目: frerich/core
void SelfTerminatePrelude(void)
{
    CfLock best_guess;

    CfOut(cf_verbose, "", "Trying to remove lock - try %s", CFLOCK);
    best_guess.lock = xstrdup(CFLOCK);
    best_guess.last = xstrdup(CFLAST);
    best_guess.log = xstrdup(CFLOG);
    YieldCurrentLock(best_guess);
    unlink(PIDFILE);

    if (THIS_AGENT_TYPE == cf_agent)
    {
        EndAudit();
    }

    GenericDeInitialize();
}
示例#16
0
void VerifyServices(EvalContext *ctx, Attributes a, Promise *pp, const ReportContext *report_context)
{
    CfLock thislock;

    // allow to start Cfengine windows executor without license
#ifdef __MINGW32__

    if ((LICENSES == 0) && (strcmp(WINSERVICE_NAME, pp->promiser) != 0))
    {
        return;
    }

#endif

    thislock = AcquireLock(pp->promiser, VUQNAME, CFSTARTTIME, a, pp, false);

    if (thislock.lock == NULL)
    {
        return;
    }

    ScopeNewScalar("this", "promiser", pp->promiser, DATA_TYPE_STRING);
    PromiseBanner(ctx, pp);

    if (strcmp(a.service.service_type, "windows") == 0)
    {
        VerifyWindowsService(ctx, a, pp);
    }
    else
    {
        DoVerifyServices(ctx, a, pp, report_context);
    }

    ScopeDeleteScalar("this", "promiser");
    YieldCurrentLock(thislock);
}
示例#17
0
PromiseResult VerifyEnvironmentsPromise(EvalContext *ctx, const Promise *pp)
{
    CfLock thislock;

    Attributes a = GetEnvironmentsAttributes(ctx, pp);

    PromiseResult result = PROMISE_RESULT_NOOP;
    if (EnvironmentsSanityChecks(a, pp))
    {
        thislock = AcquireLock(ctx, "virtual", VUQNAME, CFSTARTTIME, a.transaction, pp, false);

        if (thislock.lock == NULL)
        {
            return PROMISE_RESULT_NOOP;
        }

        PromiseBanner(ctx, pp);

        bool excluded = false;
        Promise *pexp = ExpandDeRefPromise(ctx, pp, &excluded);
        if (excluded)
        {
            result = PROMISE_RESULT_SKIPPED;
        }
        else
        {
            result = VerifyEnvironments(ctx, a, pp);
        }

        PromiseDestroy(pexp);
    }

    YieldCurrentLock(thislock);

    return result;
}
示例#18
0
void VerifyReportPromise(EvalContext *ctx, Promise *pp)
{
    Attributes a = { {0} };
    CfLock thislock;
    char unique_name[CF_EXPANDSIZE];

    a = GetReportsAttributes(ctx, pp);

    snprintf(unique_name, CF_EXPANDSIZE - 1, "%s_%zu", pp->promiser, pp->offset.line);
    thislock = AcquireLock(ctx, unique_name, VUQNAME, CFSTARTTIME, a.transaction, pp, false);

    // Handle return values before locks, as we always do this

    if (a.report.result)
    {
        // User-unwritable value last-result contains the useresult
        if (strlen(a.report.result) > 0)
        {
            snprintf(unique_name, CF_BUFSIZE, "last-result[%s]", a.report.result);
        }
        else
        {
            snprintf(unique_name, CF_BUFSIZE, "last-result");
        }

        VarRef *ref = VarRefParseFromBundle(unique_name, PromiseGetBundle(pp));
        EvalContextVariablePut(ctx, ref, (Rval) {
            pp->promiser, RVAL_TYPE_SCALAR
        }, DATA_TYPE_STRING);
        VarRefDestroy(ref);
        return;
    }

    // Now do regular human reports

    if (thislock.lock == NULL)
    {
        return;
    }

    PromiseBanner(pp);

    if (a.transaction.action == cfa_warn)
    {
        cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_WARN, pp, a, "Need to repair reports promise: %s", pp->promiser);
        YieldCurrentLock(thislock);
        return;
    }

    cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_CHANGE, pp, a, "Report: %s", pp->promiser);

    if (a.report.to_file)
    {
        ReportToFile(a.report.to_file, pp->promiser);
    }
    else
    {
        Log(LOG_LEVEL_NOTICE, "R: %s", pp->promiser);
    }

    if (a.report.haveprintfile)
    {
        PrintFile(ctx, a, pp);
    }

    if (a.report.showstate)
    {
        /* Do nothing. Deprecated. */
    }

    if (a.report.havelastseen)
    {
        /* Do nothing. Deprecated. */
    }

    YieldCurrentLock(thislock);
}
示例#19
0
PromiseResult ScheduleEditOperation(EvalContext *ctx, char *filename, Attributes a, Promise *pp)
{
    void *vp;
    FnCall *fp;
    Rlist *args = NULL;
    char edit_bundle_name[CF_BUFSIZE], lockname[CF_BUFSIZE], qualified_edit[CF_BUFSIZE], *method_deref;
    CfLock thislock;

    snprintf(lockname, CF_BUFSIZE - 1, "fileedit-%s", filename);
    thislock = AcquireLock(ctx, lockname, VUQNAME, CFSTARTTIME, a.transaction, pp, false);

    if (thislock.lock == NULL)
    {
        return PROMISE_RESULT_NOOP;
    }

    EditContext *edcontext = NewEditContext(filename, a);

    PromiseResult result = PROMISE_RESULT_NOOP;
    if (edcontext == NULL)
    {
        cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "File '%s' was marked for editing but could not be opened", filename);
        result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
        goto exit;
    }

    Policy *policy = PolicyFromPromise(pp);

    if (a.haveeditline)
    {
        if ((vp = ConstraintGetRvalValue(ctx, "edit_line", pp, RVAL_TYPE_FNCALL)))
        {
            fp = (FnCall *) vp;
            strcpy(edit_bundle_name, fp->name);
            args = fp->args;
        }
        else if ((vp = ConstraintGetRvalValue(ctx, "edit_line", pp, RVAL_TYPE_SCALAR)))
        {
            strcpy(edit_bundle_name, (char *) vp);
            args = NULL;
        }             
        else
        {
            goto exit;
        }

        if (strncmp(edit_bundle_name,"default:",strlen("default:")) == 0) // CF_NS == ':'
        {
            method_deref = strchr(edit_bundle_name, CF_NS) + 1;
        }
        else if ((strchr(edit_bundle_name, CF_NS) == NULL) && (strcmp(PromiseGetNamespace(pp), "default") != 0))
        {
            snprintf(qualified_edit, CF_BUFSIZE, "%s%c%s", PromiseGetNamespace(pp), CF_NS, edit_bundle_name);
            method_deref = qualified_edit;
        }
        else            
        {
            method_deref = edit_bundle_name;
        }        

        Log(LOG_LEVEL_VERBOSE, "Handling file edits in edit_line bundle '%s'", method_deref);

        Bundle *bp = NULL;
        if ((bp = PolicyGetBundle(policy, NULL, "edit_line", method_deref)))
        {
            BannerSubBundle(bp, args);

            EvalContextStackPushBundleFrame(ctx, bp, args, a.edits.inherit);

            BundleResolve(ctx, bp);

            ScheduleEditLineOperations(ctx, bp, a, pp, edcontext);

            EvalContextStackPopFrame(ctx);
        }
        else
        {
            Log(LOG_LEVEL_ERR, "Did not find method '%s' in bundle '%s' for edit operation", method_deref, edit_bundle_name);
        }
    }


    if (a.haveeditxml)
    {
        if ((vp = ConstraintGetRvalValue(ctx, "edit_xml", pp, RVAL_TYPE_FNCALL)))
        {
            fp = (FnCall *) vp;
            strcpy(edit_bundle_name, fp->name);
            args = fp->args;
        }
        else if ((vp = ConstraintGetRvalValue(ctx, "edit_xml", pp, RVAL_TYPE_SCALAR)))
        {
            strcpy(edit_bundle_name, (char *) vp);
            args = NULL;
        }
        else
        {
            goto exit;
        }

        if (strncmp(edit_bundle_name,"default:",strlen("default:")) == 0) // CF_NS == ':'
        {
            method_deref = strchr(edit_bundle_name, CF_NS) + 1;
        }
        else
        {
            method_deref = edit_bundle_name;
        }
        
        Log(LOG_LEVEL_VERBOSE, "Handling file edits in edit_xml bundle '%s'", method_deref);

        Bundle *bp = NULL;
        if ((bp = PolicyGetBundle(policy, NULL, "edit_xml", method_deref)))
        {
            BannerSubBundle(bp, args);

            EvalContextStackPushBundleFrame(ctx, bp, args, a.edits.inherit);
            BundleResolve(ctx, bp);

            ScheduleEditXmlOperations(ctx, bp, a, pp, edcontext);

            EvalContextStackPopFrame(ctx);
        }
    }

    
    if (a.edit_template)
    {
        if (!a.template_method || strcmp("cfengine", a.template_method) == 0)
        {
            Policy *tmp_policy = PolicyNew();
            Bundle *bp = NULL;
            if ((bp = MakeTemporaryBundleFromTemplate(ctx, tmp_policy, a, pp, &result)))
            {
                BannerSubBundle(bp, args);
                a.haveeditline = true;

                EvalContextStackPushBundleFrame(ctx, bp, args, a.edits.inherit);
                BundleResolve(ctx, bp);

                ScheduleEditLineOperations(ctx, bp, a, pp, edcontext);

                EvalContextStackPopFrame(ctx);
            }

            PolicyDestroy(tmp_policy);
        }
        else if (strcmp("mustache", a.template_method) == 0)
        {
            if (!FileCanOpen(a.edit_template, "r"))
            {
                cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Template file '%s' could not be opened for reading", a.edit_template);
                result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
                goto exit;
            }

            Writer *ouput_writer = NULL;
            {
                FILE *output_file = fopen(pp->promiser, "w");
                if (!output_file)
                {
                    cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Output file '%s' could not be opened for writing", pp->promiser);
                    result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
                    goto exit;
                }

                ouput_writer = FileWriter(output_file);
            }

            Writer *template_writer = FileRead(a.edit_template, SIZE_MAX, NULL);
            if (!template_writer)
            {
                cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Could not read template file '%s'", a.edit_template);
                result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
                WriterClose(ouput_writer);
                goto exit;
            }

            JsonElement *default_template_data = NULL;
            if (!a.template_data)
            {
                a.template_data = default_template_data = DefaultTemplateData(ctx);
            }

            if (!MustacheRender(ouput_writer, StringWriterData(template_writer), a.template_data))
            {
                cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Error rendering mustache template '%s'", a.edit_template);
                result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
                WriterClose(template_writer);
                WriterClose(ouput_writer);
                goto exit;
            }

            JsonDestroy(default_template_data);
            WriterClose(template_writer);
            WriterClose(ouput_writer);
        }
    }

exit:
    result = PromiseResultUpdate(result, FinishEditContext(ctx, edcontext, a, pp));
    YieldCurrentLock(thislock);
    return result;
}
示例#20
0
static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, Promise *pp)
{
    struct stat osb, oslb, dsb;
    Attributes a = { {0} };
    CfLock thislock;
    int exists;

    a = GetFilesAttributes(ctx, pp);

    if (!FileSanityChecks(ctx, path, a, pp))
    {
        return PROMISE_RESULT_NOOP;
    }

    EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser", path, DATA_TYPE_STRING);

    thislock = AcquireLock(ctx, path, VUQNAME, CFSTARTTIME, a.transaction, pp, false);

    if (thislock.lock == NULL)
    {
        return PROMISE_RESULT_NOOP;
    }

    LoadSetuid(a);

    PromiseResult result = PROMISE_RESULT_NOOP;
    if (lstat(path, &oslb) == -1)       /* Careful if the object is a link */
    {
        if ((a.create) || (a.touch))
        {
            if (!CfCreateFile(ctx, path, pp, a, &result))
            {
                goto exit;
            }
            else
            {
                exists = (lstat(path, &oslb) != -1);
            }
        }

        exists = false;
    }
    else
    {
        if ((a.create) || (a.touch))
        {
            cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "File '%s' exists as promised", path);
        }
        exists = true;
    }

    if ((a.havedelete) && (!exists))
    {
        cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "File '%s' does not exist as promised", path);
        goto exit;
    }

    if (!a.havedepthsearch)     /* if the search is trivial, make sure that we are in the parent dir of the leaf */
    {
        char basedir[CF_BUFSIZE];

        Log(LOG_LEVEL_DEBUG, "Direct file reference '%s', no search implied", path);
        snprintf(basedir, sizeof(basedir), "%s", path);

        if (strcmp(ReadLastNode(basedir), ".") == 0)
        {
            // Handle /.  notation for deletion of directories
            ChopLastNode(basedir);
            ChopLastNode(path);
        }

        ChopLastNode(basedir);
        if (chdir(basedir))
        {
            Log(LOG_LEVEL_ERR, "Failed to chdir into '%s'", basedir);
        }
    }

    if (exists && (!VerifyFileLeaf(ctx, path, &oslb, a, pp, &result)))
    {
        if (!S_ISDIR(oslb.st_mode))
        {
            goto exit;
        }
    }

    if (stat(path, &osb) == -1)
    {
        if ((a.create) || (a.touch))
        {
            if (!CfCreateFile(ctx, path, pp, a, &result))
            {
                goto exit;
            }
            else
            {
                exists = true;
            }
        }
        else
        {
            exists = false;
        }
    }
    else
    {
        if (!S_ISDIR(osb.st_mode))
        {
            if (a.havedepthsearch)
            {
                Log(LOG_LEVEL_WARNING,
                    "depth_search (recursion) is promised for a base object '%s' that is not a directory",
                      path);
                goto exit;
            }
        }

        exists = true;
    }

    if (a.link.link_children)
    {
        if (stat(a.link.source, &dsb) != -1)
        {
            if (!S_ISDIR(dsb.st_mode))
            {
                Log(LOG_LEVEL_ERR, "Cannot promise to link the children of '%s' as it is not a directory!",
                      a.link.source);
                goto exit;
            }
        }
    }

/* Phase 1 - */

    if (exists && ((a.havedelete) || (a.haverename) || (a.haveperms) || (a.havechange) || (a.transformer)))
    {
        lstat(path, &oslb);     /* if doesn't exist have to stat again anyway */

        DepthSearch(ctx, path, &oslb, 0, a, pp, oslb.st_dev, &result);

        /* normally searches do not include the base directory */

        if (a.recursion.include_basedir)
        {
            int save_search = a.havedepthsearch;

            /* Handle this node specially */

            a.havedepthsearch = false;
            DepthSearch(ctx, path, &oslb, 0, a, pp, oslb.st_dev, &result);
            a.havedepthsearch = save_search;
        }
        else
        {
            /* unless child nodes were repaired, set a promise kept class */
            if (!IsDefinedClass(ctx, "repaired" , PromiseGetNamespace(pp)))
            {
                cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a, "Basedir '%s' not promising anything", path);
            }
        }

        if (((a.change.report_changes) == FILE_CHANGE_REPORT_CONTENT_CHANGE) || ((a.change.report_changes) == FILE_CHANGE_REPORT_ALL))
        {
            if (a.havedepthsearch)
            {
                PurgeHashes(ctx, NULL, a, pp);
            }
            else
            {
                PurgeHashes(ctx, path, a, pp);
            }
        }
    }

/* Phase 2a - copying is potentially threadable if no followup actions */

    if (a.havecopy)
    {
        result = PromiseResultUpdate(result, ScheduleCopyOperation(ctx, path, a, pp));
    }

/* Phase 2b link after copy in case need file first */

    if ((a.havelink) && (a.link.link_children))
    {
        result = PromiseResultUpdate(result, ScheduleLinkChildrenOperation(ctx, path, a.link.source, 1, a, pp));
    }
    else if (a.havelink)
    {
        result = PromiseResultUpdate(result, ScheduleLinkOperation(ctx, path, a.link.source, a, pp));
    }

/* Phase 3 - content editing */

    if (a.haveedit)
    {
        result = PromiseResultUpdate(result, ScheduleEditOperation(ctx, path, a, pp));
    }

// Once more in case a file has been created as a result of editing or copying

    exists = (stat(path, &osb) != -1);

    if (exists && (S_ISREG(osb.st_mode)))
    {
        VerifyFileLeaf(ctx, path, &osb, a, pp, &result);
    }

    if (!exists && a.havechange)
    {
        cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Promised to monitor '%s' for changes, but file does not exist", path);
        result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
    }

exit:
    result = PromiseResultUpdate(result, SaveSetuid(ctx, a, pp));
    YieldCurrentLock(thislock);

    return result;
}
示例#21
0
/* Might be called back from NovaWin_StartExecService */
void StartServer(Policy *policy, GenericAgentConfig *config, ExecConfig *exec_config, const ReportContext *report_context)
{
#if !defined(__MINGW32__)
    time_t now = time(NULL);
#endif
    Promise *pp = NewPromise("exec_cfengine", "the executor agent");
    Attributes dummyattr;
    CfLock thislock;

    pthread_attr_init(&threads_attrs);
    pthread_attr_setdetachstate(&threads_attrs, PTHREAD_CREATE_DETACHED);
    pthread_attr_setstacksize(&threads_attrs, (size_t)2048*1024);

    Banner("Starting executor");
    memset(&dummyattr, 0, sizeof(dummyattr));

    dummyattr.restart_class = "nonce";
    dummyattr.transaction.ifelapsed = CF_EXEC_IFELAPSED;
    dummyattr.transaction.expireafter = CF_EXEC_EXPIREAFTER;

    if (!ONCE)
    {
        thislock = AcquireLock(pp->promiser, VUQNAME, CFSTARTTIME, dummyattr, pp, false);

        if (thislock.lock == NULL)
        {
            PromiseDestroy(pp);
            return;
        }

        /* Kill previous instances of cf-execd if those are still running */
        Apoptosis();

        /* FIXME: kludge. This code re-sets "last" lock to the one we have
           acquired a few lines before. If the cf-execd is terminated, this lock
           will be removed, and subsequent restart of cf-execd won't fail.

           The culprit is Apoptosis(), which creates a promise and executes it,
           taking locks during it, so CFLOCK/CFLAST/CFLOG get reset.

           Proper fix is to keep all the taken locks in the memory, and release
           all of them during process termination.
         */
        strcpy(CFLOCK, thislock.lock);
        strcpy(CFLAST, thislock.last ? thislock.last : "");
        strcpy(CFLOG, thislock.log ? thislock.log : "");
    }

#ifdef __MINGW32__

    if (!NO_FORK)
    {
        CfOut(OUTPUT_LEVEL_VERBOSE, "", "Windows does not support starting processes in the background - starting in foreground");
    }

#else /* !__MINGW32__ */

    if ((!NO_FORK) && (fork() != 0))
    {
        CfOut(OUTPUT_LEVEL_INFORM, "", "cf-execd starting %.24s\n", cf_ctime(&now));
        _exit(0);
    }

    if (!NO_FORK)
    {
        ActAsDaemon(0);
    }

#endif /* !__MINGW32__ */

    WritePID("cf-execd.pid");
    signal(SIGINT, HandleSignalsForDaemon);
    signal(SIGTERM, HandleSignalsForDaemon);
    signal(SIGHUP, SIG_IGN);
    signal(SIGPIPE, SIG_IGN);
    signal(SIGUSR1, HandleSignalsForDaemon);
    signal(SIGUSR2, HandleSignalsForDaemon);

    umask(077);

    if (ONCE)
    {
        CfOut(OUTPUT_LEVEL_VERBOSE, "", "Sleeping for splaytime %d seconds\n\n", SPLAYTIME);
        sleep(SPLAYTIME);
        LocalExec(exec_config);
        CloseLog();
    }
    else
    {
        while (!IsPendingTermination())
        {
            if (ScheduleRun(&policy, config, exec_config, report_context))
            {
                CfOut(OUTPUT_LEVEL_VERBOSE, "", "Sleeping for splaytime %d seconds\n\n", SPLAYTIME);
                sleep(SPLAYTIME);

                if (!LocalExecInThread(exec_config))
                {
                    CfOut(OUTPUT_LEVEL_INFORM, "", "Unable to run agent in thread, falling back to blocking execution");
                    LocalExec(exec_config);
                }
            }
        }

        YieldCurrentLock(thislock);
    }
}
示例#22
0
void VerifyStoragePromise(char *path, Promise *pp, const ReportContext *report_context)
{
    Attributes a = { {0} };
    CfLock thislock;

    a = GetStorageAttributes(pp);

    CF_OCCUR++;

#ifdef MINGW
    if (!a.havemount)
    {
        CfOut(cf_verbose, "", "storage.mount is not supported on Windows");
    }
#endif

/* No parameter conflicts here */

    if (a.mount.unmount)
    {
        if (a.mount.mount_source || a.mount.mount_server)
        {
            CfOut(cf_verbose, "", " !! An unmount promise indicates a mount-source information - probably in error\n");
        }
    }
    else if (a.havemount)
    {
        if (a.mount.mount_source == NULL || a.mount.mount_server == NULL)
        {
            CfOut(cf_error, "", " !! Insufficient specification in mount promise - need source and server\n");
            return;
        }
    }

    thislock = AcquireLock(path, VUQNAME, CFSTARTTIME, a, pp, false);

    if (thislock.lock == NULL)
    {
        return;
    }

/* Do mounts first */

#ifndef MINGW
    if (!MOUNTEDFSLIST && !LoadMountInfo(&MOUNTEDFSLIST))
    {
        CfOut(cf_error, "", "Couldn't obtain a list of mounted filesystems - aborting\n");
        YieldCurrentLock(thislock);
        return;
    }

    if (a.havemount)
    {
        VerifyMountPromise(path, a, pp, report_context);
    }
#endif /* NOT MINGW */

/* Then check file system */

    if (a.havevolume)
    {
        VerifyFileSystem(path, a, pp);

        if (a.volume.freespace != CF_NOINT)
        {
            VerifyFreeSpace(path, a, pp);
        }

        if (a.volume.scan_arrivals)
        {
            VolumeScanArrivals(path, a, pp);
        }
    }

    YieldCurrentLock(thislock);
}
示例#23
0
/**
 *  @retval >0 Number of threads still working
 *  @retval 0  All threads are done
 *  @retval -1 Server didn't run
 */
int StartServer(EvalContext *ctx, Policy **policy, GenericAgentConfig *config)
{
    InitSignals();
    ServerTLSInitialize();
    int sd = SetServerListenState(ctx, QUEUESIZE, SERVER_LISTEN, &InitServer);

    /* Necessary for our use of select() to work in WaitForIncoming(): */
    assert(sd < sizeof(fd_set) * CHAR_BIT &&
           GetSignalPipe() < sizeof(fd_set) * CHAR_BIT);

    Policy *server_cfengine_policy = PolicyNew();
    CfLock thislock = AcquireServerLock(ctx, config, server_cfengine_policy);
    if (thislock.lock == NULL)
    {
        PolicyDestroy(server_cfengine_policy);
        if (sd >= 0)
        {
            cf_closesocket(sd);
        }
        return -1;
    }

    PrepareServer(sd);
    CollectCallStart(COLLECT_INTERVAL);

    while (!IsPendingTermination())
    {
        CollectCallIfDue(ctx);

        int selected = WaitForIncoming(sd);

        Log(LOG_LEVEL_DEBUG, "select(): %d", selected);
        if (selected == -1)
        {
            Log(LOG_LEVEL_ERR,
                "Error while waiting for connections. (select: %s)",
                GetErrorStr());
            break;
        }
        else if (selected >= 0) /* timeout or success */
        {
            PolicyUpdateIfSafe(ctx, policy, config);

            /* Is there a new connection pending at our listening socket? */
            if (selected > 0)
            {
                AcceptAndHandle(ctx, sd);
            }
        } /* else: interrupted, maybe pending termination. */
    }
    Log(LOG_LEVEL_NOTICE, "Cleaning up and exiting...");

    CollectCallStop();
    if (sd != -1)
    {
        Log(LOG_LEVEL_VERBOSE, "Closing listening socket");
        cf_closesocket(sd);                       /* Close listening socket */
    }

    /* This is a graceful exit, give 2 seconds chance to threads. */
    int threads_left = WaitOnThreads();
    YieldCurrentLock(thislock);
    PolicyDestroy(server_cfengine_policy);

    return threads_left;
}
示例#24
0
PromiseResult VerifyReportPromise(EvalContext *ctx, const Promise *pp)
{
    CfLock thislock;
    char unique_name[CF_EXPANDSIZE];

    Attributes a = GetReportsAttributes(ctx, pp);

    // We let AcquireLock worry about making a unique name
    snprintf(unique_name, CF_EXPANDSIZE - 1, "%s", pp->promiser);
    thislock = AcquireLock(ctx, unique_name, VUQNAME, CFSTARTTIME, a.transaction, pp, false);

    // Handle return values before locks, as we always do this

    if (a.report.result)
    {
        // User-unwritable value last-result contains the useresult
        if (strlen(a.report.result) > 0)
        {
            snprintf(unique_name, CF_BUFSIZE, "last-result[%s]", a.report.result);
        }
        else
        {
            snprintf(unique_name, CF_BUFSIZE, "last-result");
        }

        VarRef *ref = VarRefParseFromBundle(unique_name, PromiseGetBundle(pp));
        EvalContextVariablePut(ctx, ref, pp->promiser, CF_DATA_TYPE_STRING, "source=bundle");
        VarRefDestroy(ref);

        if (thislock.lock)
        {
            YieldCurrentLock(thislock);
        }
        return PROMISE_RESULT_NOOP;
    }

    if (thislock.lock == NULL)
    {
        return PROMISE_RESULT_SKIPPED;
    }

    PromiseBanner(ctx, pp);

    if (a.transaction.action == cfa_warn)
    {
        cfPS(ctx, LOG_LEVEL_WARNING, PROMISE_RESULT_WARN, pp, a, "Need to repair reports promise: %s", pp->promiser);
        YieldCurrentLock(thislock);
        return PROMISE_RESULT_WARN;
    }

    if (a.report.to_file)
    {
        ReportToFile(a.report.to_file, pp->promiser);
    }
    else
    {
        ReportToLog(pp->promiser);
    }

    PromiseResult result = PROMISE_RESULT_NOOP;
    if (a.report.haveprintfile)
    {
        if (!PrintFile(a.report.filename, a.report.numlines))
        {
            result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
        }
    }

    YieldCurrentLock(thislock);

    ClassAuditLog(ctx, pp, a, result);
    return result;
}
示例#25
0
PromiseResult VerifyStoragePromise(EvalContext *ctx, char *path, Promise *pp)
{
    Attributes a = { {0} };
    CfLock thislock;

    a = GetStorageAttributes(ctx, pp);

#ifdef __MINGW32__
    if (!a.havemount)
    {
        Log(LOG_LEVEL_VERBOSE, "storage.mount is not supported on Windows");
    }
#endif

/* No parameter conflicts here */

    if (a.mount.unmount)
    {
        if ((a.mount.mount_source))
        {
            Log(LOG_LEVEL_VERBOSE, "An unmount promise indicates a mount-source information - probably an error");
        }
        if ((a.mount.mount_server))
        {
            Log(LOG_LEVEL_VERBOSE, "An unmount promise indicates a mount-server information - probably an error");
        }
    }
    else if (a.havemount)
    {
        if ((a.mount.mount_source == NULL) || (a.mount.mount_server == NULL))
        {
            Log(LOG_LEVEL_ERR, "Insufficient specification in mount promise - need source and server");
            return PROMISE_RESULT_NOOP;
        }
    }

    thislock = AcquireLock(ctx, path, VUQNAME, CFSTARTTIME, a.transaction, pp, false);

    if (thislock.lock == NULL)
    {
        return PROMISE_RESULT_NOOP;
    }

/* Do mounts first */

    PromiseResult result = PROMISE_RESULT_NOOP;

#ifndef __MINGW32__
    if ((SeqLength(GetGlobalMountedFSList())) && (!LoadMountInfo(GetGlobalMountedFSList())))
    {
        Log(LOG_LEVEL_ERR, "Couldn't obtain a list of mounted filesystems - aborting");
        YieldCurrentLock(thislock);
        return PROMISE_RESULT_NOOP;
    }

    if (a.havemount)
    {
        result = PromiseResultUpdate(result, VerifyMountPromise(ctx, path, a, pp));
    }
#endif /* !__MINGW32__ */

/* Then check file system */

    if (a.havevolume)
    {
        result = PromiseResultUpdate(result, VerifyFileSystem(ctx, path, a, pp));

        if (a.volume.freespace != CF_NOINT)
        {
            result = PromiseResultUpdate(result, VerifyFreeSpace(ctx, path, a, pp));
        }

        if (a.volume.scan_arrivals)
        {
            result = PromiseResultUpdate(result, VolumeScanArrivals(path, a, pp));
        }
    }

    YieldCurrentLock(thislock);
    return result;
}
示例#26
0
void StartServer(Policy *policy, GenericAgentConfig config, const ReportContext *report_context)
{
    int sd = -1, sd_reply;
    fd_set rset;
    struct timeval timeout;
    int ret_val;
    Promise *pp = NewPromise("server_cfengine", "the server daemon");
    Attributes dummyattr = { {0} };
    CfLock thislock;
    time_t starttime = time(NULL), last_collect = 0;

#if defined(HAVE_GETADDRINFO)
    socklen_t addrlen = sizeof(struct sockaddr_in6);
    struct sockaddr_in6 cin;
#else
    socklen_t addrlen = sizeof(struct sockaddr_in);
    struct sockaddr_in cin;
#endif

    memset(&dummyattr, 0, sizeof(dummyattr));

    signal(SIGINT, HandleSignals);
    signal(SIGTERM, HandleSignals);
    signal(SIGHUP, SIG_IGN);
    signal(SIGPIPE, SIG_IGN);
    signal(SIGUSR1, HandleSignals);
    signal(SIGUSR2, HandleSignals);

    sd = SetServerListenState(QUEUESIZE);

    dummyattr.transaction.ifelapsed = 0;
    dummyattr.transaction.expireafter = 1;

    thislock = AcquireLock(pp->promiser, VUQNAME, CFSTARTTIME, dummyattr, pp, false);

    if (thislock.lock == NULL)
    {
        return;
    }

    CfOut(cf_inform, "", "cf-serverd starting %.24s\n", cf_ctime(&starttime));

    if (sd != -1)
    {
        CfOut(cf_verbose, "", "Listening for connections ...\n");
    }

#ifdef MINGW

    if (!NO_FORK)
    {
        CfOut(cf_verbose, "", "Windows does not support starting processes in the background - starting in foreground");
    }

#else /* NOT MINGW */

    if ((!NO_FORK) && (fork() != 0))
    {
        exit(0);
    }

    if (!NO_FORK)
    {
        ActAsDaemon(sd);
    }

#endif /* NOT MINGW */

    WritePID("cf-serverd.pid");

/* Andrew Stribblehill <*****@*****.**> -- close sd on exec */
#ifndef MINGW
    fcntl(sd, F_SETFD, FD_CLOEXEC);
#endif

    while (true)
    {
        time_t now = time(NULL);

        /* Note that this loop logic is single threaded, but ACTIVE_THREADS
           might still change in threads pertaining to service handling */

        if (ThreadLock(cft_server_children))
        {
            if (ACTIVE_THREADS == 0)
            {
                CheckFileChanges(&policy, config, report_context);
            }
            ThreadUnlock(cft_server_children);
        }

        // Check whether we should try to establish peering with a hub

        if ((COLLECT_INTERVAL > 0) && ((now - last_collect) > COLLECT_INTERVAL))
        {
            TryCollectCall();
            last_collect = now;
            continue;
        }

        /* check if listening is working */
        if (sd != -1)
        {
            // Look for normal incoming service requests

            FD_ZERO(&rset);
            FD_SET(sd, &rset);

            timeout.tv_sec = 10;    /* Set a 10 second timeout for select */
            timeout.tv_usec = 0;

            CfDebug(" -> Waiting at incoming select...\n");

            ret_val = select((sd + 1), &rset, NULL, NULL, &timeout);

            if (ret_val == -1)      /* Error received from call to select */
            {
                if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    CfOut(cf_error, "select", "select failed");
                    exit(1);
                }
            }
            else if (!ret_val) /* No data waiting, we must have timed out! */
            {
                continue;
            }

            CfOut(cf_verbose, "", " -> Accepting a connection\n");

            if ((sd_reply = accept(sd, (struct sockaddr *) &cin, &addrlen)) != -1)
            {
                char ipaddr[CF_MAXVARSIZE];

                memset(ipaddr, 0, CF_MAXVARSIZE);
                ThreadLock(cft_getaddr);
                snprintf(ipaddr, CF_MAXVARSIZE - 1, "%s", sockaddr_ntop((struct sockaddr *) &cin));
                ThreadUnlock(cft_getaddr);

                ServerEntryPoint(sd_reply, ipaddr, SV);
            }
        }
    }

    YieldCurrentLock(thislock); /* We never get here - this is done by a signal handler */
}
示例#27
0
void VerifyReportPromise(Promise *pp)
{
    Attributes a = { {0} };
    CfLock thislock;
    Rlist *rp;
    char unique_name[CF_EXPANDSIZE];

    a = GetReportsAttributes(pp);

    snprintf(unique_name, CF_EXPANDSIZE - 1, "%s_%zu", pp->promiser, pp->offset.line);
    thislock = AcquireLock(unique_name, VUQNAME, CFSTARTTIME, a, pp, false);

    // Handle return values before locks, as we always do this

    if (a.report.result)
    {
        // User-unwritable value last-result contains the useresult
        if (strlen(a.report.result) > 0)
        {
            snprintf(unique_name, CF_BUFSIZE, "last-result[%s]", a.report.result);
        }
        else
        {
            snprintf(unique_name, CF_BUFSIZE, "last-result");
        }

        NewScalar(pp->bundle, unique_name, pp->promiser, cf_str);
        return;
    }
       
    // Now do regular human reports
    
    if (thislock.lock == NULL)
    {
        return;
    }

    PromiseBanner(pp);

    cfPS(cf_verbose, CF_CHG, "", pp, a, "Report: %s", pp->promiser);

    if (a.report.to_file)
    {
        CfFOut(a.report.to_file, cf_error, "", "%s", pp->promiser);
    }
    else
    {
        CfOut(cf_reporting, "", "R: %s", pp->promiser);
    }

    if (a.report.haveprintfile)
    {
        PrintFile(a, pp);
    }

    if (a.report.showstate)
    {
        for (rp = a.report.showstate; rp != NULL; rp = rp->next)
        {
            ShowState(rp->item);
        }
    }

    if (a.report.havelastseen)
    {
        /* Do nothing. Deprecated. */
    }

    YieldCurrentLock(thislock);
}
示例#28
0
void VerifyStoragePromise(EvalContext *ctx, char *path, Promise *pp, ARG_UNUSED const ReportContext *report_context) /* FIXME: unused param */
{
    Attributes a = { {0} };
    CfLock thislock;

    a = GetStorageAttributes(ctx, pp);

    CF_OCCUR++;

#ifdef __MINGW32__
    if (!a.havemount)
    {
        CfOut(OUTPUT_LEVEL_VERBOSE, "", "storage.mount is not supported on Windows");
    }
#endif

/* No parameter conflicts here */

    if (a.mount.unmount)
    {
        if ((a.mount.mount_source))
        {
            CfOut(OUTPUT_LEVEL_VERBOSE, "", " !! An unmount promise indicates a mount-source information - probably an error\n");
        }
        if ((a.mount.mount_server))
        {
            CfOut(OUTPUT_LEVEL_VERBOSE, "", " !! An unmount promise indicates a mount-server information - probably an error\n");
        }
    }
    else if (a.havemount)
    {
        if ((a.mount.mount_source == NULL) || (a.mount.mount_server == NULL))
        {
            CfOut(OUTPUT_LEVEL_ERROR, "", " !! Insufficient specification in mount promise - need source and server\n");
            return;
        }
    }

    thislock = AcquireLock(ctx, path, VUQNAME, CFSTARTTIME, a, pp, false);

    if (thislock.lock == NULL)
    {
        return;
    }

/* Do mounts first */

#ifndef __MINGW32__
    if ((!MOUNTEDFSLIST) && (!LoadMountInfo(&MOUNTEDFSLIST)))
    {
        CfOut(OUTPUT_LEVEL_ERROR, "", "Couldn't obtain a list of mounted filesystems - aborting\n");
        YieldCurrentLock(thislock);
        return;
    }

    if (a.havemount)
    {
        VerifyMountPromise(ctx, path, a, pp);
    }
#endif /* !__MINGW32__ */

/* Then check file system */

    if (a.havevolume)
    {
        VerifyFileSystem(ctx, path, a, pp);

        if (a.volume.freespace != CF_NOINT)
        {
            VerifyFreeSpace(ctx, path, a, pp);
        }

        if (a.volume.scan_arrivals)
        {
            VolumeScanArrivals(path, a, pp);
        }
    }

    YieldCurrentLock(thislock);
}
示例#29
0
static void VerifySQLPromise(Attributes a, Promise *pp)
{
    char database[CF_MAXVARSIZE], table[CF_MAXVARSIZE], query[CF_BUFSIZE];
    char *sp;
    int count = 0;
    CfdbConn cfdb;
    CfLock thislock;
    char lockname[CF_BUFSIZE];

    snprintf(lockname, CF_BUFSIZE - 1, "db-%s", pp->promiser);

    thislock = AcquireLock(lockname, VUQNAME, CFSTARTTIME, a, pp, false);

    if (thislock.lock == NULL)
    {
        return;
    }

    database[0] = '\0';
    table[0] = '\0';

    for (sp = pp->promiser; *sp != '\0'; sp++)
    {
        if (strchr("./\\", *sp))
        {
            count++;
            strncpy(table, sp + 1, CF_MAXVARSIZE - 1);
            sscanf(pp->promiser, "%[^.\\/]", database);

            if (strlen(database) == 0)
            {
                cfPS(cf_error, CF_FAIL, "", pp, a,
                     "SQL database promiser syntax should be of the form \"database.table\"");
                PromiseRef(cf_error, pp);
                YieldCurrentLock(thislock);
                return;
            }
        }
    }

    if (count > 1)
    {
        cfPS(cf_error, CF_FAIL, "", pp, a, "SQL database promiser syntax should be of the form \"database.table\"");
        PromiseRef(cf_error, pp);
    }

    if (strlen(database) == 0)
    {
        strncpy(database, pp->promiser, CF_MAXVARSIZE - 1);
    }

    if (a.database.operation == NULL)
    {
        cfPS(cf_error, CF_FAIL, "", pp, a ,
             "Missing database_operation in database promise");
        PromiseRef(cf_error, pp);
        YieldCurrentLock(thislock);
        return;
    }

    if (strcmp(a.database.operation, "delete") == 0)
    {
        /* Just deal with one */
        strcpy(a.database.operation, "drop");
    }

/* Connect to the server */

    CfConnectDB(&cfdb, a.database.db_server_type, a.database.db_server_host, a.database.db_server_owner,
                a.database.db_server_password, database);

    if (!cfdb.connected)
    {
        /* If we haven't said create then db should already exist */

        if ((a.database.operation) && (strcmp(a.database.operation, "create") != 0))
        {
            CfOut(cf_error, "", "Could not connect an existing database %s - check server configuration?\n", database);
            PromiseRef(cf_error, pp);
            CfCloseDB(&cfdb);
            YieldCurrentLock(thislock);
            return;
        }
    }

/* Check change of existential constraints */

    if ((a.database.operation) && (strcmp(a.database.operation, "create") == 0))
    {
        CfConnectDB(&cfdb, a.database.db_server_type, a.database.db_server_host, a.database.db_server_owner,
                    a.database.db_server_password, a.database.db_connect_db);

        if (!cfdb.connected)
        {
            CfOut(cf_error, "", "Could not connect to the sql_db server for %s\n", database);
            return;
        }

        /* Don't drop the db if we really want to drop a table */

        if ((strlen(table) == 0) || ((strlen(table) > 0) && (strcmp(a.database.operation, "drop") != 0)))
        {
            VerifyDatabasePromise(&cfdb, database, a, pp);
        }

        /* Close the database here to commit the change - might have to reopen */

        CfCloseDB(&cfdb);
    }

/* Now check the structure of the named table, if any */

    if (strlen(table) == 0)
    {
        YieldCurrentLock(thislock);
        return;
    }

    CfConnectDB(&cfdb, a.database.db_server_type, a.database.db_server_host, a.database.db_server_owner,
                a.database.db_server_password, database);

    if (!cfdb.connected)
    {
        CfOut(cf_inform, "", "Database %s is not connected\n", database);
    }
    else
    {
        snprintf(query, CF_MAXVARSIZE - 1, "%s.%s", database, table);

        if (VerifyTablePromise(&cfdb, query, a.database.columns, a, pp))
        {
            cfPS(cf_inform, CF_NOP, "", pp, a, " -> Table \"%s\" is as promised", query);
        }
        else
        {
            cfPS(cf_inform, CF_FAIL, "", pp, a, " -> Table \"%s\" is not as promised", query);
        }

/* Finally check any row constraints on this table */

        if (a.database.rows)
        {
            CfOut(cf_inform, "",
                  " !! Database row operations are not currently supported. Please contact cfengine with suggestions.");
        }

        CfCloseDB(&cfdb);
    }

    YieldCurrentLock(thislock);
}
示例#30
0
static void VerifyExec(Attributes a, Promise *pp)
{
    CfLock thislock;
    char unsafeLine[CF_BUFSIZE], line[sizeof(unsafeLine) * 2], eventname[CF_BUFSIZE];
    char comm[20];
    char execstr[CF_EXPANDSIZE];
    int outsourced, count = 0;
    mode_t maskval = 0;
    FILE *pfp;
    char cmdOutBuf[CF_BUFSIZE];
    int cmdOutBufPos = 0;
    int lineOutLen;

    if (!IsExecutable(GetArg0(pp->promiser)))
    {
        cfPS(cf_error, CF_FAIL, "", pp, a, "%s promises to be executable but isn't\n", pp->promiser);

        if (strchr(pp->promiser, ' '))
        {
            CfOut(cf_verbose, "", "Paths with spaces must be inside escaped quoutes (e.g. \\\"%s\\\")", pp->promiser);
        }

        return;
    }
    else
    {
        CfOut(cf_verbose, "", " -> Promiser string contains a valid executable (%s) - ok\n", GetArg0(pp->promiser));
    }

    DeleteScalar("this", "promiser");
    NewScalar("this", "promiser", pp->promiser, cf_str);

    if (a.args)
    {
        snprintf(execstr, CF_EXPANDSIZE - 1, "%s %s", pp->promiser, a.args);
    }
    else
    {
        strncpy(execstr, pp->promiser, CF_BUFSIZE);
    }

    thislock = AcquireLock(execstr, VUQNAME, CFSTARTTIME, a, pp, false);

    if (thislock.lock == NULL)
    {
        return;
    }

    PromiseBanner(pp);

    CfOut(cf_inform, "", " -> Executing \'%s\' ...(timeout=%d,owner=%ju,group=%ju)\n", execstr, a.contain.timeout,
          (uintmax_t)a.contain.owner, (uintmax_t)a.contain.group);

    BeginMeasure();

    if (DONTDO && !a.contain.preview)
    {
        CfOut(cf_error, "", "-> Would execute script %s\n", execstr);
    }
    else if (a.transaction.action != cfa_fix)
    {
        cfPS(cf_error, CF_WARN, "", pp, a, " !! Command \"%s\" needs to be executed, but only warning was promised",
             execstr);
    }
    else
    {
        CommPrefix(execstr, comm);

        if (a.transaction.background)
        {
#ifdef MINGW
            outsourced = true;
#else
            CfOut(cf_verbose, "", " -> Backgrounding job %s\n", execstr);
            outsourced = fork();
#endif
        }
        else
        {
            outsourced = false;
        }

        if (outsourced || !a.transaction.background)    // work done here: either by child or non-background parent
        {
            if (a.contain.timeout != CF_NOINT)
            {
                SetTimeOut(a.contain.timeout);
            }

#ifndef MINGW
            CfOut(cf_verbose, "", " -> (Setting umask to %jo)\n", (uintmax_t)a.contain.umask);
            maskval = umask(a.contain.umask);

            if (a.contain.umask == 0)
            {
                CfOut(cf_verbose, "", " !! Programming %s running with umask 0! Use umask= to set\n", execstr);
            }
#endif /* NOT MINGW */

            if (a.contain.useshell)
            {
                pfp =
                    cf_popen_shsetuid(execstr, "r", a.contain.owner, a.contain.group, a.contain.chdir, a.contain.chroot,
                                      a.transaction.background);
            }
            else
            {
                pfp =
                    cf_popensetuid(execstr, "r", a.contain.owner, a.contain.group, a.contain.chdir, a.contain.chroot,
                                   a.transaction.background);
            }

            if (pfp == NULL)
            {
                cfPS(cf_error, CF_FAIL, "cf_popen", pp, a, "!! Couldn't open pipe to command %s\n", execstr);
                YieldCurrentLock(thislock);
                return;
            }

            while (!feof(pfp))
            {
                if (ferror(pfp))        /* abortable */
                {
                    cfPS(cf_error, CF_TIMEX, "ferror", pp, a, "!! Command pipe %s\n", execstr);
                    cf_pclose(pfp);
                    YieldCurrentLock(thislock);
                    return;
                }

                CfReadLine(unsafeLine, CF_BUFSIZE - 1, pfp);
                ReplaceStr(unsafeLine, line, sizeof(line), "%", "%%");  // escape format char

                if (strstr(line, "cfengine-die"))
                {
                    break;
                }

                if (ferror(pfp))        /* abortable */
                {
                    cfPS(cf_error, CF_TIMEX, "ferror", pp, a, "!! Command pipe %s\n", execstr);
                    cf_pclose(pfp);
                    YieldCurrentLock(thislock);
                    return;
                }

                if (a.contain.preview)
                {
                    PreviewProtocolLine(line, execstr);
                }

                if (a.module)
                {
                    ModuleProtocol(execstr, line, !a.contain.nooutput);
                }
                else if (!a.contain.nooutput && NonEmptyLine(line))
                {
                    lineOutLen = strlen(comm) + strlen(line) + 12;

                    // if buffer is to small for this line, output it directly
                    if (lineOutLen > sizeof(cmdOutBuf))
                    {
                        CfOut(cf_cmdout, "", "Q: \"...%s\": %s\n", comm, line);
                    }
                    else
                    {
                        if (cmdOutBufPos + lineOutLen > sizeof(cmdOutBuf))
                        {
                            CfOut(cf_cmdout, "", "%s", cmdOutBuf);
                            cmdOutBufPos = 0;
                        }
                        sprintf(cmdOutBuf + cmdOutBufPos, "Q: \"...%s\": %s\n", comm, line);
                        cmdOutBufPos += (lineOutLen - 1);
                    }
                    count++;
                }
            }
#ifdef MINGW
            if (outsourced)     // only get return value if we waited for command execution
            {
                cf_pclose(pfp);
            }
            else
            {
                cf_pclose_def(pfp, a, pp);
            }
#else /* NOT MINGW */
            cf_pclose_def(pfp, a, pp);
#endif
        }

        if (count)
        {
            if (cmdOutBufPos)
            {
                CfOut(cf_cmdout, "", "%s", cmdOutBuf);
            }

            CfOut(cf_cmdout, "", "I: Last %d quoted lines were generated by promiser \"%s\"\n", count, execstr);
        }

        if (a.contain.timeout != CF_NOINT)
        {
            alarm(0);
            signal(SIGALRM, SIG_DFL);
        }

        CfOut(cf_inform, "", " -> Completed execution of %s\n", execstr);
#ifndef MINGW
        umask(maskval);
#endif
        YieldCurrentLock(thislock);

        snprintf(eventname, CF_BUFSIZE - 1, "Exec(%s)", execstr);

#ifndef MINGW
        if (a.transaction.background && outsourced)
        {
            CfOut(cf_verbose, "", " -> Backgrounded command (%s) is done - exiting\n", execstr);
            exit(0);
        }
#endif /* NOT MINGW */
    }
}