Пример #1
0
static void PrependAuditFile(char *file)

{ struct stat statbuf;

if ((AUDITPTR = (struct Audit *)malloc(sizeof(struct Audit))) == NULL)
   {
   FatalError("Memory allocation failure in PrependAuditFile");
   }

if (cfstat(file,&statbuf) == -1)
   {
   /* shouldn't happen */
   return;
   }

HashFile(file,AUDITPTR->digest,CF_DEFAULT_DIGEST);

AUDITPTR->next = VAUDIT;
AUDITPTR->filename = strdup(file);
AUDITPTR->date = strdup(cf_ctime(&statbuf.st_mtime));
Chop(AUDITPTR->date);
AUDITPTR->version = NULL;
VAUDIT = AUDITPTR;
}
Пример #2
0
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;
}
Пример #3
0
static int VerifyFileSystem(EvalContext *ctx, char *name, Attributes a, Promise *pp)
{
    struct stat statbuf, localstat;
    Dir *dirh;
    const struct dirent *dirp;
    off_t sizeinbytes = 0;
    long filecount = 0;
    char buff[CF_BUFSIZE];

    CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Checking required filesystem %s\n", name);

    if (cfstat(name, &statbuf) == -1)
    {
        return (false);
    }

    if (S_ISLNK(statbuf.st_mode))
    {
        KillGhostLink(ctx, name, a, pp);
        return (true);
    }

    if (S_ISDIR(statbuf.st_mode))
    {
        if ((dirh = DirOpen(name)) == NULL)
        {
            CfOut(OUTPUT_LEVEL_ERROR, "opendir", "Can't open directory %s which checking required/disk\n", name);
            return false;
        }

        for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh))
        {
            if (!ConsiderFile(ctx, dirp->d_name, name, a, pp))
            {
                continue;
            }

            filecount++;

            strcpy(buff, name);

            if (buff[strlen(buff)] != FILE_SEPARATOR)
            {
                strcat(buff, FILE_SEPARATOR_STR);
            }

            strcat(buff, dirp->d_name);

            if (lstat(buff, &localstat) == -1)
            {
                if (S_ISLNK(localstat.st_mode))
                {
                    KillGhostLink(ctx, buff, a, pp);
                    continue;
                }

                CfOut(OUTPUT_LEVEL_ERROR, "lstat", "Can't stat volume %s\n", buff);
                continue;
            }

            sizeinbytes += localstat.st_size;
        }

        DirClose(dirh);

        if (sizeinbytes < 0)
        {
            CfOut(OUTPUT_LEVEL_VERBOSE, "", "Internal error: count of byte size was less than zero!\n");
            return true;
        }

        if (sizeinbytes < a.volume.sensible_size)
        {
            cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_INTERRUPTED, "", pp, a, " !! File system %s is suspiciously small! (%jd bytes)\n", name,
                 (intmax_t) sizeinbytes);
            return (false);
        }

        if (filecount < a.volume.sensible_count)
        {
            cfPS(ctx, OUTPUT_LEVEL_ERROR, PROMISE_RESULT_INTERRUPTED, "", pp, a, " !! Filesystem %s has only %ld files/directories.\n", name,
                 filecount);
            return (false);
        }
    }

    cfPS(ctx, OUTPUT_LEVEL_INFORM, PROMISE_RESULT_NOOP, "", pp, a, " -> Filesystem %s's content seems to be sensible as promised\n", name);
    return (true);
}
Пример #4
0
void CheckAutoBootstrap(EvalContext *ctx)
{
    struct stat sb;
    char name[CF_BUFSIZE];
    int have_policy = false, am_appliance = false;

    printf("** CFEngine BOOTSTRAP probe initiated\n");

    PrintVersion();
    printf("\n");

    printf(" -> This host is: %s\n", VSYSNAME.nodename);
    printf(" -> Operating System Type is %s\n", VSYSNAME.sysname);
    printf(" -> Operating System Release is %s\n", VSYSNAME.release);
    printf(" -> Architecture = %s\n", VSYSNAME.machine);
    printf(" -> Internal soft-class is %s\n", CLASSTEXT[VSYSTEMHARDCLASS]);

    if (!BootstrapAllowed())
    {
        FatalError(ctx, " !! Not enough privileges to bootstrap CFEngine");
    }

    snprintf(name, CF_BUFSIZE - 1, "%s/inputs/failsafe.cf", CFWORKDIR);
    MapName(name);

    CreateFailSafe(name);

    snprintf(name, CF_BUFSIZE - 1, "%s/inputs/promises.cf", CFWORKDIR);
    MapName(name);

    if (cfstat(name, &sb) == -1)
    {
        printf(" -> No previous policy has been cached on this host\n");
    }
    else
    {
        printf(" -> An existing policy was cached on this host in %s/inputs\n", CFWORKDIR);
        have_policy = true;
    }

    if (strlen(POLICY_SERVER) > 0)
    {
        printf(" -> Assuming the policy distribution point at: %s:%s/masterfiles\n", CFWORKDIR,
              POLICY_SERVER);
    }
    else
    {
        if (have_policy)
        {
            printf(" -> No policy distribution host was discovered - it might be contained in the existing policy, otherwise this will function autonomously\n");
        }
        else
        {
            printf(" -> No policy distribution host was defined - use --policy-server to set one\n");
        }
    }

    printf(" -> Attempting to initiate promised autonomous services...\n\n");

    am_appliance = IsDefinedClass(ctx, CanonifyName(POLICY_SERVER), NULL);
    snprintf(name, CF_MAXVARSIZE, "ipv4_%s", CanonifyName(POLICY_SERVER));
    am_appliance |= IsDefinedClass(ctx, name, NULL);

    if (strlen(POLICY_SERVER) == 0)
    {
        am_appliance = false;
    }

    snprintf(name, sizeof(name), "%s/state/am_policy_hub", CFWORKDIR);
    MapName(name);

    if (am_appliance)
    {
        EvalContextHeapAddHard(ctx, "am_policy_hub");
        printf
            (" ** This host recognizes itself as a CFEngine policy server, with policy distribution from %s/masterfiles.\n", WORKDIR);
        creat(name, 0600);
    }
    else
    {
        unlink(name);
    }

}
Пример #5
0
int ArchiveToRepository(char *file,struct Attributes attr,struct Promise *pp)

 /* Returns true if the file was backup up and false if not */

{ char destination[CF_BUFSIZE];
  char localrepository[CF_BUFSIZE]; 
  char node[CF_BUFSIZE];
  struct stat sb, dsb;
  char *sp;

if (attr.repository == NULL && VREPOSITORY == NULL)
   {
   return false;
   }

if (attr.repository != NULL)
   {
   strncpy(localrepository,attr.repository,CF_BUFSIZE);
   }
else if (VREPOSITORY != NULL)
   {
   strncpy(localrepository,VREPOSITORY,CF_BUFSIZE);
   }

if (attr.copy.backup == cfa_nobackup)
   {
   return true;
   }

if (IsItemIn(VREPOSLIST,file))
   {
   CfOut(cf_inform,"","The file %s has already been moved to the repository once. Multiple update will cause loss of backup.",file);
   return true;
   }

ThreadLock(cft_getaddr);
PrependItemList(&VREPOSLIST,file);
ThreadUnlock(cft_getaddr);

Debug("Repository(%s)\n",file);

strcpy (node,file);

destination[0] = '\0';

for (sp = node; *sp != '\0'; sp++)
   {
   if (*sp == FILE_SEPARATOR)
      {
      *sp = REPOSCHAR;
      }
   }

strncpy(destination,localrepository,CF_BUFSIZE-2);

if (!JoinPath(destination,node))
   {
   CfOut(cf_error,"","Internal limit: Buffer ran out of space for long filename\n");
   return false;
   }

if (!MakeParentDirectory(destination,attr.move_obstructions))
   {
   }

if (cfstat(file,&sb) == -1)
   {
   Debug("File %s promised to archive to the repository but it disappeared!\n",file);
   return true;
   }

cfstat(destination,&dsb);

attr.copy.servers = NULL;
attr.copy.backup = cfa_repos_store; // cfa_nobackup;
attr.copy.stealth = false;
attr.copy.verify = false;
attr.copy.preserve = false;

CheckForFileHoles(&sb,pp);

if (CopyRegularFileDisk(file,destination,attr,pp))
   {
   CfOut(cf_inform,"","Moved %s to repository location %s\n",file,destination);
   return true;
   }
else
   {
   CfOut(cf_inform,"","Failed to move %s to repository location %s\n",file,destination);
   return false;
   }
}
Пример #6
0
void *CopyFileSources(char *destination, Attributes attr, Promise *pp, const ReportContext *report_context)
{
    char *source = attr.copy.source;
    char *server = pp->this_server;
    char vbuff[CF_BUFSIZE];
    struct stat ssb, dsb;
    struct timespec start;
    char eventname[CF_BUFSIZE];

    CfDebug("CopyFileSources(%s,%s)", source, destination);

    if (pp->conn != NULL && !pp->conn->authenticated)
    {
        cfPS(cf_verbose, CF_FAIL, "", pp, attr, "No authenticated source %s in files.copyfrom promise\n", source);
        return NULL;
    }

    if (cf_stat(attr.copy.source, &ssb, attr, pp) == -1)
    {
        cfPS(cf_inform, CF_FAIL, "", pp, attr, "Can't stat %s in files.copyfrom promise\n", source);
        return NULL;
    }

    start = BeginMeasure();

    strncpy(vbuff, destination, CF_BUFSIZE - 4);

    if (S_ISDIR(ssb.st_mode))   /* could be depth_search */
    {
        AddSlash(vbuff);
        strcat(vbuff, ".");
    }

    if (!MakeParentDirectory(vbuff, attr.move_obstructions, report_context))
    {
        cfPS(cf_inform, CF_FAIL, "", pp, attr, "Can't make directories for %s in files.copyfrom promise\n", vbuff);
        return NULL;
    }

    if (S_ISDIR(ssb.st_mode))   /* could be depth_search */
    {
        if (attr.copy.purge)
        {
            CfOut(cf_verbose, "", " !! (Destination purging enabled)\n");
        }

        CfOut(cf_verbose, "", " ->>  Entering %s\n", source);
        SetSearchDevice(&ssb, pp);
        SourceSearchAndCopy(source, destination, attr.recursion.depth, attr, pp, report_context);

        if (cfstat(destination, &dsb) != -1)
        {
            if (attr.copy.check_root)
            {
                VerifyCopiedFileAttributes(destination, &dsb, &ssb, attr, pp, report_context);
            }
        }
    }
    else
    {
        VerifyCopy(source, destination, attr, pp, report_context);
    }

    snprintf(eventname, CF_BUFSIZE - 1, "Copy(%s:%s > %s)", server, source, destination);
    EndMeasure(eventname, start);

    return NULL;
}
Пример #7
0
void MountAll()
{
    char line[CF_BUFSIZE];
    FILE *pp;

    if (DONTDO)
    {
        CfOut(cf_verbose, "", "Promised to mount filesystem, but not on this trial run\n");
        return;
    }
    else
    {
        CfOut(cf_verbose, "", " -> Attempting to mount all filesystems.\n");
    }

#if defined(__CYGWIN__)
    /* This is a shell script. Make sure it hasn't been compromised. */

    struct stat sb;

    if (cfstat("/etc/fstab", &sb) == -1)
    {
        int fd;
        if ((fd = creat("/etc/fstab", 0755)) > 0)
        {
            if (write(fd, "#!/bin/sh\n\n", 10) != 10)
            {
                UnexpectedError("Failed to write to file '/etc/fstab'");
            }
            close(fd);
        }
        else
        {
            if (sb.st_mode & (S_IWOTH | S_IWGRP))
            {
                CfOut(cf_error, "", "File /etc/fstab was insecure. Cannot mount filesystems.\n");
                return;
            }
        }
    }
#endif

    SetTimeOut(RPCTIMEOUT);

    if ((pp = cf_popen(VMOUNTCOMM[VSYSTEMHARDCLASS], "r")) == NULL)
    {
        CfOut(cf_error, "cf_popen", "Failed to open pipe from %s\n", VMOUNTCOMM[VSYSTEMHARDCLASS]);
        return;
    }

    while (!feof(pp))
    {
        if (ferror(pp))         /* abortable */
        {
            CfOut(cf_inform, "ferror", "Error mounting filesystems\n");
            break;
        }

        if (CfReadLine(line, CF_BUFSIZE, pp) == -1)
        {
            FatalError("Error in CfReadLine");
        }

        if (ferror(pp))         /* abortable */
        {
            CfOut(cf_inform, "ferror", "Error mounting filesystems\n");
            break;
        }

        if ((strstr(line, "already mounted")) || (strstr(line, "exceeded")) || (strstr(line, "determined")))
        {
            continue;
        }

        if (strstr(line, "not supported"))
        {
            continue;
        }

        if ((strstr(line, "denied")) || (strstr(line, "RPC")))
        {
            CfOut(cf_error, "", "There was a mount error, trying to mount one of the filesystems on this host.\n");
            break;
        }

        if ((strstr(line, "trying")) && (!strstr(line, "NFS version 2")) && (!strstr(line, "vers 3")))
        {
            CfOut(cf_error, "", "Attempting abort because mount went into a retry loop.\n");
            break;
        }
    }

    alarm(0);
    signal(SIGALRM, SIG_DFL);
    cf_pclose(pp);
}
Пример #8
0
int ConsiderFile(const char *nodename, char *path, Attributes attr, Promise *pp)
{
    int i;
    struct stat statbuf;
    char vbuff[CF_BUFSIZE];
    const char *sp;

    static char *skipfiles[] =
{
        ".",
        "..",
        "lost+found",
        ".cfengine.rm",
        NULL
    };

    if (strlen(nodename) < 1)
    {
        CfOut(cf_error, "", "Empty (null) filename detected in %s\n", path);
        return true;
    }

    if (IsItemIn(SUSPICIOUSLIST, nodename))
    {
        struct stat statbuf;

        if (cfstat(nodename, &statbuf) != -1)
        {
            if (S_ISREG(statbuf.st_mode))
            {
                CfOut(cf_error, "", "Suspicious file %s found in %s\n", nodename, path);
                return false;
            }
        }
    }

    if (strcmp(nodename, "...") == 0)
    {
        CfOut(cf_verbose, "", "Possible DFS/FS cell node detected in %s...\n", path);
        return true;
    }

    for (i = 0; skipfiles[i] != NULL; i++)
    {
        if (strcmp(nodename, skipfiles[i]) == 0)
        {
            CfDebug("Filename %s/%s is classified as ignorable\n", path, nodename);
            return false;
        }
    }

    if ((strcmp("[", nodename) == 0) && (strcmp("/usr/bin", path) == 0))
    {
        if (VSYSTEMHARDCLASS == linuxx)
        {
            return true;
        }
    }

    for (sp = nodename; *sp != '\0'; sp++)
    {
        if ((*sp > 31) && (*sp < 127))
        {
            break;
        }
    }

    strcpy(vbuff, path);
    AddSlash(vbuff);
    strcat(vbuff, nodename);

    for (sp = nodename; *sp != '\0'; sp++)      /* Check for files like ".. ." */
    {
        if ((*sp != '.') && !isspace(*sp))
        {
            return true;
        }
    }

    if (cf_lstat(vbuff, &statbuf, attr, pp) == -1)
    {
        CfOut(cf_verbose, "lstat", "Couldn't stat %s", vbuff);
        return true;
    }

    if (statbuf.st_size == 0 && !(VERBOSE || INFORM))   /* No sense in warning about empty files */
    {
        return false;
    }

    CfOut(cf_error, "", "Suspicious looking file object \"%s\" masquerading as hidden file in %s\n", nodename, path);
    CfDebug("Filename looks suspicious\n");

    if (S_ISLNK(statbuf.st_mode))
    {
        CfOut(cf_inform, "", "   %s is a symbolic link\n", nodename);
    }
    else if (S_ISDIR(statbuf.st_mode))
    {
        CfOut(cf_inform, "", "   %s is a directory\n", nodename);
    }

    CfOut(cf_verbose, "", "[%s] has size %ld and full mode %o\n", nodename, (unsigned long) (statbuf.st_size),
          (unsigned int) (statbuf.st_mode));
    return true;
}
Пример #9
0
static void ShowState(char *type)
{
    struct stat statbuf;
    char buffer[CF_BUFSIZE], vbuff[CF_BUFSIZE], assemble[CF_BUFSIZE];
    Item *addresses = NULL, *saddresses = NULL, *ip;
    int i = 0, tot = 0, min_signal_diversity = 1, conns = 1;
    int maxlen = 0, count;
    double *dist = NULL, S = 0.0;
    char *offset = NULL;
    FILE *fp;

    CfDebug("ShowState(%s)\n", type);

    snprintf(buffer, CF_BUFSIZE - 1, "%s/state/cf_%s", CFWORKDIR, type);

    if (cfstat(buffer, &statbuf) == 0)
    {
        if ((fp = fopen(buffer, "r")) == NULL)
        {
            CfOut(cf_inform, "fopen", "Could not open state memory %s\n", buffer);
            return;
        }

        while (!feof(fp))
        {
            char local[CF_BUFSIZE], remote[CF_BUFSIZE];

            buffer[0] = local[0] = remote[0] = '\0';

            memset(vbuff, 0, CF_BUFSIZE);
            fgets(buffer, CF_BUFSIZE, fp);

            if (strlen(buffer) > 0)
            {
                CfOut(cf_verbose, "", "(%2d) %s", conns, buffer);

                if (IsSocketType(type))
                {
                    if (strncmp(type, "incoming", 8) == 0 || strncmp(type, "outgoing", 8) == 0)
                    {
                        if (strncmp(buffer, "tcp", 3) == 0)
                        {
                            sscanf(buffer, "%*s %*s %*s %s %s", local, remote); /* linux-like */
                        }
                        else
                        {
                            sscanf(buffer, "%s %s", local, remote);     /* solaris-like */
                        }

                        strncpy(vbuff, remote, CF_BUFSIZE - 1);
                        DePort(vbuff);
                    }
                }
                else if (IsTCPType(type))
                {
                    count = 1;
                    sscanf(buffer, "%d %[^\n]", &count, remote);
                    AppendItem(&addresses, remote, "");
                    SetItemListCounter(addresses, remote, count);
                    conns += count;
                    continue;
                }
                else
                {
                    /* If we get here this is a process thing */
                    if (offset == NULL)
                    {
                        if ((offset = strstr(buffer, "CMD")))
                        {
                        }
                        else if ((offset = strstr(buffer, "COMMAND")))
                        {
                        }

                        if (offset == NULL)
                        {
                            continue;
                        }
                    }

                    strncpy(vbuff, offset, CF_BUFSIZE - 1);
                    Chop(vbuff);
                }

                if (!IsItemIn(addresses, vbuff))
                {
                    conns++;
                    AppendItem(&addresses, vbuff, "");
                    IncrementItemListCounter(addresses, vbuff);
                }
                else
                {
                    conns++;
                    IncrementItemListCounter(addresses, vbuff);
                }
            }
        }

        fclose(fp);
        conns--;

        CfOut(cf_error, "", "\n");
        CfOut(cf_error, "", "R: The peak measured state was q = %d:\n", conns);

        if (IsSocketType(type) || IsTCPType(type))
        {
            for (ip = addresses; ip != NULL; ip = ip->next)
            {
                tot += ip->counter;

                buffer[0] = '\0';
                sscanf(ip->name, "%s", buffer);

                if (!IsIPV4Address(buffer) && !IsIPV6Address(buffer))
                {
                    CfOut(cf_verbose, "", "Rejecting address %s\n", ip->name);
                    continue;
                }

                CfOut(cf_error, "", "R: DNS key: %s = %s (%d/%d)\n", buffer, IPString2Hostname(buffer), ip->counter,
                      conns);

                if (strlen(ip->name) > maxlen)
                {
                    maxlen = strlen(ip->name);
                }
            }

            if (addresses != NULL)
            {
                printf("R: -\n");
            }
        }
        else
        {
            for (ip = addresses; ip != NULL; ip = ip->next)
            {
                tot += ip->counter;
            }
        }

        addresses = SortItemListCounters(addresses);
        saddresses = addresses;

        for (ip = saddresses; ip != NULL; ip = ip->next)
        {
            int s;

            if (maxlen > 17)    /* ipv6 */
            {
                snprintf(assemble, CF_BUFSIZE, "Frequency: %-40s|", ip->name);
            }
            else
            {
                snprintf(assemble, CF_BUFSIZE, "Frequency: %-17s|", ip->name);
            }

            for (s = 0; (s < ip->counter) && (s < 50); s++)
            {
                if (s < 48)
                {
                    strcat(assemble, "*");
                }
                else
                {
                    strcat(assemble, "+");
                }
            }

            CfOut(cf_error, "", "R: %s \t(%d/%d)\n", assemble, ip->counter, conns);
        }

        dist = xmalloc((tot + 1) * sizeof(double));

        if (conns > min_signal_diversity)
        {
            for (i = 0, ip = addresses; ip != NULL; i++, ip = ip->next)
            {
                dist[i] = ((double) (ip->counter)) / ((double) tot);

                S -= dist[i] * log(dist[i]);
            }

            CfOut(cf_error, "", "R: Variability/entropy of addresses = %.1f %%\n", S / log((double) tot) * 100.0);
            CfOut(cf_error, "", "R: (Entropy = 0 for single source, 100 for flatly distributed source)\n -\n");
        }

        CfOut(cf_error, "", "\n");
        CfOut(cf_error, "", "R: State of %s peaked at %s\n", type, cf_ctime(&statbuf.st_mtime));
    }
    else
    {
        CfOut(cf_inform, "", "R: State parameter %s is not known or recorded\n", type);
    }

    DeleteItemList(addresses);

    if (dist)
    {
        free((char *) dist);
    }
}
Пример #10
0
static void Cf3ParseFile(char *filename)

{
  struct stat statbuf;
  char wfilename[CF_BUFSIZE];

strncpy(wfilename,InputLocation(filename),CF_BUFSIZE);

if (cfstat(wfilename,&statbuf) == -1)
   {
   if (IGNORE_MISSING_INPUTS)
      {
      return;
      }

   CfOut(cf_error,"stat","Can't stat file \"%s\" for parsing\n",wfilename);
   exit(1);
   }

#ifndef NT
if (statbuf.st_mode & (S_IWGRP | S_IWOTH))
   {
   CfOut(cf_error,"","File %s (owner %d) is writable by others (security exception)",wfilename,statbuf.st_uid);
   exit(1);
   }
#endif

Debug("+++++++++++++++++++++++++++++++++++++++++++++++\n");
CfOut(cf_verbose,"","  > Parsing file %s\n",wfilename);
Debug("+++++++++++++++++++++++++++++++++++++++++++++++\n");

PrependAuditFile(wfilename);

if ((yyin = fopen(wfilename,"r")) == NULL)      /* Open root file */
   {
   printf("Can't open file %s for parsing\n",wfilename);
   exit (1);
   }

P.line_no = 1;
P.line_pos = 1;
P.list_nesting = 0;
P.arg_nesting = 0;
strncpy(P.filename,wfilename,CF_MAXVARSIZE);

P.currentid[0] = '\0';
P.currentstring = NULL;
P.currenttype[0] = '\0';
P.currentclasses = NULL;
P.currentRlist = NULL;
P.currentpromise = NULL;
P.promiser = NULL;
P.blockid[0] = '\0';
P.blocktype[0] = '\0';

while (!feof(yyin))
   {
   yyparse();

   if (ferror(yyin))  /* abortable */
      {
      perror("cfengine");
      exit(1);
      }
   }

fclose (yyin);
}
Пример #11
0
int NewPromiseProposals()

{ struct Rlist *rp,*sl;
  struct stat sb;
  int result = false;
  char filename[CF_MAXVARSIZE];

if (MINUSF)
   {
   snprintf(filename,CF_MAXVARSIZE,"%s/state/validated_%s",CFWORKDIR,CanonifyName(VINPUTFILE));
   MapName(filename);   
   }
else
   {
   snprintf(filename,CF_MAXVARSIZE,"%s/masterfiles/cf_promises_validated",CFWORKDIR);
   MapName(filename);
   }
  
if (stat(filename,&sb) != -1)
   {
   PROMISETIME = sb.st_mtime;
   }
else
   {
   PROMISETIME = 0;
   }


// sanity check

if(PROMISETIME > time(NULL))
   {
   CfOut(cf_inform, "", "!! Clock seems to have jumped back in time - mtime of %s is newer than current time - touching it", filename);
   
   if(utime(filename,NULL) == -1)
      {
      CfOut(cf_error, "utime", "!! Could not touch %s", filename);
      }

   PROMISETIME = 0;
   return true;
   }

if (cfstat(InputLocation(VINPUTFILE),&sb) == -1)
   {
   CfOut(cf_verbose,"stat","There is no readable input file at %s",VINPUTFILE);
   return true;
   }

if (sb.st_mtime > PROMISETIME)
   {
   CfOut(cf_verbose,""," -> Promises seem to change");
   return true;
   }

// Check the directories first for speed and because non-input/data files should trigger an update

snprintf(filename,CF_MAXVARSIZE,"%s/inputs",CFWORKDIR);
MapName(filename);

if (IsNewerFileTree(filename,PROMISETIME))
   {
   CfOut(cf_verbose,""," -> Quick search detected file changes");
   return true;
   }

// Check files in case there are any abs paths

if (VINPUTLIST != NULL)
   {
   for (rp = VINPUTLIST; rp != NULL; rp=rp->next)
      {
      if (rp->type != CF_SCALAR)
         {
         CfOut(cf_error,"","Non file object %s in list\n",(char *)rp->item);
         }
      else
         {
         struct Rval returnval = EvaluateFinalRval("sys",rp->item,rp->type,true,NULL);

         switch (returnval.rtype)
            {
            case CF_SCALAR:

                if (cfstat(InputLocation((char *)returnval.item),&sb) == -1)
                   {
                   CfOut(cf_error,"stat","Unreadable promise proposals at %s",(char *)returnval.item);
                   result = true;
                   break;
                   }

                if (sb.st_mtime > PROMISETIME)
                   {
                   result = true;
                   }

                break;

            case CF_LIST:

                for (sl = (struct Rlist *)returnval.item; sl != NULL; sl=sl->next)
                   {
                   if (cfstat(InputLocation((char *)sl->item),&sb) == -1)
                      {
                      CfOut(cf_error,"stat","Unreadable promise proposals at %s",(char *)sl->item);
                      result = true;
                      break;
                      }

                   if (sb.st_mtime > PROMISETIME)
                      {
                      result = true;
                      break;
                      }
                   }

                break;
            }

         DeleteRvalItem(returnval.item,returnval.rtype);

         if (result)
            {
            break;
            }
         }
      }
   }

// did policy server change (used in $(sys.policy_hub))?
snprintf(filename,CF_MAXVARSIZE,"%s/policy_server.dat",CFWORKDIR);
MapName(filename);

if ((cfstat(filename,&sb) != -1) && (sb.st_mtime > PROMISETIME))
   {
   result = true;
   }

return result | ALWAYS_VALIDATE;
}
Пример #12
0
void InitializeGA(int argc,char *argv[])

{
  int seed,force = false;
  struct stat statbuf,sb;
  unsigned char s[16];
  char vbuff[CF_BUFSIZE];
  char ebuff[CF_EXPANDSIZE];

SHORT_CFENGINEPORT =  htons((unsigned short)5308);
snprintf(STR_CFENGINEPORT,15,"5308");

NewClass("any");

#if defined HAVE_CONSTELLATION
NewClass("constellation_edition");
#elif defined HAVE_NOVA
NewClass("nova_edition");
#else
NewClass("community_edition");
#endif

strcpy(VPREFIX,GetConsolePrefix());

if (VERBOSE)
   {
   NewClass("verbose_mode");
   }

if (INFORM)
   {
   NewClass("inform_mode");
   }

if (DEBUG)
   {
   NewClass("debug_mode");
   }

CfOut(cf_verbose,"","Cfengine - autonomous configuration engine - commence self-diagnostic prelude\n");
CfOut(cf_verbose,"","------------------------------------------------------------------------\n");

/* Define trusted directories */

#ifdef MINGW
if(NovaWin_GetProgDir(CFWORKDIR, CF_BUFSIZE - sizeof("Cfengine")))
  {
  strcat(CFWORKDIR, "\\Cfengine");
  }
else
  {
  CfOut(cf_error, "", "!! Could not get CFWORKDIR from Windows environment variable, falling back to compile time dir (%s)", WORKDIR);
  strcpy(CFWORKDIR,WORKDIR);
  }
Debug("Setting CFWORKDIR=%s\n", CFWORKDIR);
#elif defined(CFCYG)
strcpy(CFWORKDIR,WORKDIR);
MapName(CFWORKDIR);
#else
if (getuid() > 0)
   {
   strncpy(CFWORKDIR,GetHome(getuid()),CF_BUFSIZE-10);
   strcat(CFWORKDIR,"/.cfagent");

   if (strlen(CFWORKDIR) > CF_BUFSIZE/2)
      {
      FatalError("Suspicious looking home directory. The path is too long and will lead to problems.");
      }
   }
else
   {
   strcpy(CFWORKDIR,WORKDIR);
   }
#endif

/* On windows, use 'binary mode' as default for files */

#ifdef MINGW
_fmode = _O_BINARY;
#endif

strcpy(SYSLOGHOST,"localhost");
SYSLOGPORT = htons(514);

Cf3OpenLog(LOG_USER);

if (!LOOKUP) /* cf-know should not do this in lookup mode */
   {
   CfOut(cf_verbose,"","Work directory is %s\n",CFWORKDIR);

   snprintf(HASHDB,CF_BUFSIZE-1,"%s%c%s",CFWORKDIR,FILE_SEPARATOR,CF_CHKDB);

   snprintf(vbuff,CF_BUFSIZE,"%s%cinputs%cupdate.conf",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
   MakeParentDirectory(vbuff,force);
   snprintf(vbuff,CF_BUFSIZE,"%s%cbin%ccf-agent -D from_cfexecd",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
   MakeParentDirectory(vbuff,force);
   snprintf(vbuff,CF_BUFSIZE,"%s%coutputs%cspooled_reports",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
   MakeParentDirectory(vbuff,force);
   snprintf(vbuff,CF_BUFSIZE,"%s%clastseen%cintermittencies",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
   MakeParentDirectory(vbuff,force);
   snprintf(vbuff,CF_BUFSIZE,"%s%creports%cvarious",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
   MakeParentDirectory(vbuff,force);

   snprintf(vbuff,CF_BUFSIZE,"%s%cinputs",CFWORKDIR,FILE_SEPARATOR);

   if (cfstat(vbuff,&sb) == -1)
      {
      FatalError(" !!! No access to WORKSPACE/inputs dir");
      }
   else
      {
      cf_chmod(vbuff,sb.st_mode | 0700);
      }

   snprintf(vbuff,CF_BUFSIZE,"%s%coutputs",CFWORKDIR,FILE_SEPARATOR);

   if (cfstat(vbuff,&sb) == -1)
      {
      FatalError(" !!! No access to WORKSPACE/outputs dir");
      }
   else
      {
      cf_chmod(vbuff,sb.st_mode | 0700);
      }

   sprintf(ebuff,"%s%cstate%ccf_procs",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
   MakeParentDirectory(ebuff,force);

   if (cfstat(ebuff,&statbuf) == -1)
      {
      CreateEmptyFile(ebuff);
      }

   sprintf(ebuff,"%s%cstate%ccf_rootprocs",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);

   if (cfstat(ebuff,&statbuf) == -1)
      {
      CreateEmptyFile(ebuff);
      }

   sprintf(ebuff,"%s%cstate%ccf_otherprocs",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);

   if (cfstat(ebuff,&statbuf) == -1)
      {
      CreateEmptyFile(ebuff);
      }
   }

OpenNetwork();

/* Init crypto stuff */

OpenSSL_add_all_algorithms();
OpenSSL_add_all_digests();
ERR_load_crypto_strings();

if(!LOOKUP)
  {
  CheckWorkingDirectories();
  }

RandomSeed();

RAND_bytes(s,16);
s[15] = '\0';
seed = ElfHash(s);
srand48((long)seed);

LoadSecretKeys();

/* CheckOpts(argc,argv); - MacOS can't handle this back reference */

if (!MINUSF)
   {
   snprintf(VINPUTFILE,CF_BUFSIZE-1,"promises.cf");
   }

AUDITDBP = NULL;

DetermineCfenginePort();

VIFELAPSED = 1;
VEXPIREAFTER = 1;

setlinebuf(stdout);

if (BOOTSTRAP)
   {
   snprintf(vbuff,CF_BUFSIZE,"%s%cinputs%cfailsafe.cf",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);

   if (!IsEnterprise() && cfstat(vbuff,&statbuf) == -1)
      {
      snprintf(VINPUTFILE,CF_BUFSIZE-1,".%cfailsafe.cf",FILE_SEPARATOR);
      }
   else
      {
      strncpy(VINPUTFILE,vbuff,CF_BUFSIZE-1);
      }
   }
}
Пример #13
0
int CheckPromises(enum cfagenttype ag)

{ char cmd[CF_BUFSIZE], cfpromises[CF_MAXVARSIZE];
  char filename[CF_MAXVARSIZE];
  struct stat sb;
  int fd;

if ((ag != cf_agent) && (ag != cf_executor) && (ag != cf_server))
   {
   return true;
   }

CfOut(cf_verbose,""," -> Verifying the syntax of the inputs...\n");

snprintf(cfpromises,sizeof(cfpromises),"%s%cbin%ccf-promises%s",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR,EXEC_SUFFIX);

if (cfstat(cfpromises,&sb) == -1)
   {
   CfOut(cf_error,"","cf-promises%s needs to be installed in %s%cbin for pre-validation of full configuration",EXEC_SUFFIX,CFWORKDIR,FILE_SEPARATOR);
   return false;
   }

/* If we are cf-agent, check syntax before attempting to run */

snprintf(cmd, sizeof(cmd), "\"%s\" -f \"", cfpromises);


if (IsFileOutsideDefaultRepository(VINPUTFILE))
   {
   strlcat(cmd, VINPUTFILE, CF_BUFSIZE);
   }
else
   {
   strlcat(cmd, CFWORKDIR, CF_BUFSIZE);
   strlcat(cmd, FILE_SEPARATOR_STR "inputs" FILE_SEPARATOR_STR, CF_BUFSIZE);
   strlcat(cmd, VINPUTFILE, CF_BUFSIZE);
   }

strlcat(cmd, "\"", CF_BUFSIZE);

if (CBUNDLESEQUENCE)
   {
   strlcat(cmd, " -b \"", CF_BUFSIZE);
   strlcat(cmd, CBUNDLESEQUENCE_STR, CF_BUFSIZE);
   strlcat(cmd, "\"", CF_BUFSIZE);
   }

if(BOOTSTRAP)
   {
   // avoids license complains from commercial cf-promises during bootstrap - see Nova_CheckLicensePromise
   strlcat(cmd, " -D bootstrap_mode", CF_BUFSIZE);
   }

/* Check if reloading policy will succeed */

CfOut(cf_verbose, "", "Checking policy with command \"%s\"", cmd);

if (ShellCommandReturnsZero(cmd,true))
   {
   if (MINUSF)
      {
      snprintf(filename,CF_MAXVARSIZE,"%s/state/validated_%s",CFWORKDIR,CanonifyName(VINPUTFILE));
      MapName(filename);   
      }
   else
      {
      snprintf(filename,CF_MAXVARSIZE,"%s/masterfiles/cf_promises_validated",CFWORKDIR);
      MapName(filename);
      }
   
   MakeParentDirectory(filename,true);
   
   if ((fd = creat(filename,0600)) != -1)
      {
      close(fd);
      CfOut(cf_verbose,""," -> Caching the state of validation\n");
      }
   else
      {
      CfOut(cf_verbose,"creat"," -> Failed to cache the state of validation\n");
      }
   
   return true;
   }
else
   {
   return false;
   }
}
Пример #14
0
static void CheckWorkingDirectories()
    
/* NOTE: We do not care about permissions (ACLs) in windows */

{ struct stat statbuf;
  char vbuff[CF_BUFSIZE];
  char output[CF_BUFSIZE];

Debug("CheckWorkingDirectories()\n");

if (uname(&VSYSNAME) == -1)
   {
   CfOut(cf_error, "uname", "!!! Couldn't get kernel name info!");
   memset(&VSYSNAME, 0, sizeof(VSYSNAME));
   }
else
   {
   snprintf(LOGFILE,CF_BUFSIZE,"%s%ccfagent.%s.log",CFWORKDIR,FILE_SEPARATOR,VSYSNAME.nodename);
   }


snprintf(vbuff,CF_BUFSIZE,"%s%c.",CFWORKDIR,FILE_SEPARATOR);
MakeParentDirectory(vbuff,false);

CfOut(cf_verbose,"","Making sure that locks are private...\n");

if (chown(CFWORKDIR,getuid(),getgid()) == -1)
   {
   CfOut(cf_error,"chown","Unable to set owner on %s to %d.%d",CFWORKDIR,getuid(),getgid());
   }

if (cfstat(CFWORKDIR,&statbuf) != -1)
   {
   /* change permissions go-w */
   cf_chmod(CFWORKDIR,(mode_t)(statbuf.st_mode & ~022));
   }

snprintf(vbuff,CF_BUFSIZE,"%s%cstate%c.",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
MakeParentDirectory(vbuff,false);

if (strlen(CFPRIVKEYFILE) == 0)
   {
   snprintf(CFPRIVKEYFILE,CF_BUFSIZE,"%s%cppkeys%clocalhost.priv",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
   snprintf(CFPUBKEYFILE,CF_BUFSIZE,"%s%cppkeys%clocalhost.pub",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
   }

CfOut(cf_verbose,"","Checking integrity of the state database\n");
snprintf(vbuff,CF_BUFSIZE,"%s%cstate",CFWORKDIR,FILE_SEPARATOR);

if (cfstat(vbuff,&statbuf) == -1)
   {
   snprintf(vbuff,CF_BUFSIZE,"%s%cstate%c.",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
   MakeParentDirectory(vbuff,false);

   if (chown(vbuff,getuid(),getgid()) == -1)
      {
      CfOut(cf_error,"chown","Unable to set owner on %s to %d.%d",vbuff,getuid(),getgid());
      }

   cf_chmod(vbuff,(mode_t)0755);
   }
else
   {
#ifndef MINGW
   if (statbuf.st_mode & 022)
      {
      CfOut(cf_error,"","UNTRUSTED: State directory %s (mode %o) was not private!\n",CFWORKDIR,statbuf.st_mode & 0777);
      }
#endif  /* NOT MINGW */
   }

CfOut(cf_verbose,"","Checking integrity of the module directory\n");

snprintf(vbuff,CF_BUFSIZE,"%s%cmodules",CFWORKDIR,FILE_SEPARATOR);

if (cfstat(vbuff,&statbuf) == -1)
   {
   snprintf(vbuff,CF_BUFSIZE,"%s%cmodules%c.",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
   MakeParentDirectory(vbuff,false);

   if (chown(vbuff,getuid(),getgid()) == -1)
      {
      CfOut(cf_error,"chown","Unable to set owner on %s to %d.%d",vbuff,getuid(),getgid());
      }

   cf_chmod(vbuff,(mode_t)0700);
   }
else
   {
#ifndef MINGW
   if (statbuf.st_mode & 022)
      {
      CfOut(cf_error,"","UNTRUSTED: Module directory %s (mode %o) was not private!\n",vbuff,statbuf.st_mode & 0777);
      }
#endif  /* NOT MINGW */
   }

CfOut(cf_verbose,"","Checking integrity of the PKI directory\n");

snprintf(vbuff,CF_BUFSIZE,"%s%cppkeys",CFWORKDIR,FILE_SEPARATOR);

if (cfstat(vbuff,&statbuf) == -1)
   {
   snprintf(vbuff,CF_BUFSIZE,"%s%cppkeys%c.",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
   MakeParentDirectory(vbuff,false);

   cf_chmod(vbuff,(mode_t)0700); /* Keys must be immutable to others */
   }
else
   {
#ifndef MINGW
   if (statbuf.st_mode & 077)
      {
      snprintf(output,CF_BUFSIZE-1,"UNTRUSTED: Private key directory %s%cppkeys (mode %o) was not private!\n",CFWORKDIR,FILE_SEPARATOR,statbuf.st_mode & 0777);
      FatalError(output);
      }
#endif  /* NOT MINGW */
   }
}
Пример #15
0
int ConsiderFile(const char *nodename, char *path, Attributes attr, Promise *pp)
{
    int i;
    struct stat statbuf;
    const char *sp;


    if (strlen(nodename) < 1)
    {
        CfOut(cf_error, "", "Empty (null) filename detected in %s\n", path);
        return true;
    }

    if (SuspiciousFile(nodename))
    {
        struct stat statbuf;

        if (cfstat(nodename, &statbuf) != -1)
        {
            if (S_ISREG(statbuf.st_mode))
            {
                CfOut(cf_error, "", "Suspicious file %s found in %s\n", nodename, path);
                return false;
            }
        }
    }

    if (strcmp(nodename, "...") == 0)
    {
        CfOut(cf_verbose, "", "Possible DFS/FS cell node detected in %s...\n", path);
        return true;
    }

    for (i = 0; SKIPFILES[i] != NULL; i++)
    {
        if (strcmp(nodename, SKIPFILES[i]) == 0)
        {
            CfDebug("Filename %s/%s is classified as ignorable\n", path, nodename);
            return false;
        }
    }

    if ((strcmp("[", nodename) == 0) && (strcmp("/usr/bin", path) == 0))
    {
#if defined(__linux__)
            return true;
#endif
    }

    for (sp = nodename; *sp != '\0'; sp++)
    {
        if ((*sp > 31) && (*sp < 127))
        {
            break;
        }
    }

    char buf[CF_BUFSIZE];

    snprintf(buf, sizeof(buf), "%s/%s", path, nodename);
    MapName(buf);

    for (sp = nodename; *sp != '\0'; sp++)      /* Check for files like ".. ." */
    {
        if ((*sp != '.') && (!isspace((int)*sp)))
        {
            return true;
        }
    }

    if (cf_lstat(buf, &statbuf, attr, pp) == -1)
    {
        CfOut(cf_verbose, "lstat", "Couldn't stat %s", buf);
        return true;
    }

    if ((statbuf.st_size == 0) && (!(VERBOSE || INFORM)))   /* No sense in warning about empty files */
    {
        return false;
    }

    CfOut(cf_error, "", "Suspicious looking file object \"%s\" masquerading as hidden file in %s\n", nodename, path);
    CfDebug("Filename looks suspicious\n");

    if (S_ISLNK(statbuf.st_mode))
    {
        CfOut(cf_inform, "", "   %s is a symbolic link\n", nodename);
    }
    else if (S_ISDIR(statbuf.st_mode))
    {
        CfOut(cf_inform, "", "   %s is a directory\n", nodename);
    }

    CfOut(cf_verbose, "", "[%s] has size %ld and full mode %o\n", nodename, (unsigned long) (statbuf.st_size),
          (unsigned int) (statbuf.st_mode));
    return true;
}
Пример #16
0
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);
}
Пример #17
0
void CheckAutoBootstrap()
{
    struct stat sb;
    char name[CF_BUFSIZE];
    int repaired = false, have_policy = false, am_appliance = false;

    CfOut(cf_cmdout, "", "** CFEngine BOOTSTRAP probe initiated");

    PrintVersionBanner("CFEngine");
    printf("\n");

    printf(" -> This host is: %s\n", VSYSNAME.nodename);
    printf(" -> Operating System Type is %s\n", VSYSNAME.sysname);
    printf(" -> Operating System Release is %s\n", VSYSNAME.release);
    printf(" -> Architecture = %s\n", VSYSNAME.machine);
    printf(" -> Internal soft-class is %s\n", CLASSTEXT[VSYSTEMHARDCLASS]);

    if (!BootstrapAllowed())
    {
        FatalError(" !! Not enough privileges to bootstrap CFEngine");
    }

    snprintf(name, CF_BUFSIZE - 1, "%s/inputs/failsafe.cf", CFWORKDIR);
    MapName(name);

    if (cfstat(name, &sb) == -1)
    {
        CreateFailSafe(name);
        repaired = true;
    }

    snprintf(name, CF_BUFSIZE - 1, "%s/inputs/promises.cf", CFWORKDIR);
    MapName(name);

    if (cfstat(name, &sb) == -1)
    {
        CfOut(cf_cmdout, "", " -> No previous policy has been cached on this host");
    }
    else
    {
        CfOut(cf_cmdout, "", " -> An existing policy was cached on this host in %s/inputs", CFWORKDIR);
        have_policy = true;
    }

    if (strlen(POLICY_SERVER) > 0)
    {
        CfOut(cf_cmdout, "", " -> Assuming the policy distribution point at: %s:/var/cfengine/masterfiles\n",
              POLICY_SERVER);
    }
    else
    {
        if (have_policy)
        {
            CfOut(cf_cmdout, "",
                  " -> No policy distribution host was discovered - it might be contained in the existing policy, otherwise this will function autonomously\n");
        }
        else if (repaired)
        {
            CfOut(cf_cmdout, "", " -> No policy distribution host was defined - use --policy-server to set one\n");
        }
    }

    printf(" -> Attempting to initiate promised autonomous services...\n\n");

    am_appliance = IsDefinedClass(CanonifyName(POLICY_SERVER), NULL);
    snprintf(name, CF_MAXVARSIZE, "ipv4_%s", CanonifyName(POLICY_SERVER));
    am_appliance |= IsDefinedClass(name, NULL);

    if (strlen(POLICY_SERVER) == 0)
    {
        am_appliance = false;
    }

    snprintf(name, sizeof(name), "%s/state/am_policy_hub", CFWORKDIR);
    MapName(name);

    if (am_appliance)
    {
        HardClass("am_policy_hub");
        printf
        (" ** This host recognizes itself as a CFEngine Policy Hub, with policy distribution and knowledge base.\n");
        printf
        (" -> The system is now converging. Full initialisation and self-analysis could take up to 30 minutes\n\n");
        creat(name, 0600);
    }
    else
    {
        unlink(name);
    }
}
Пример #18
0
void LocateFilePromiserGroup(EvalContext *ctx, char *wildpath, Promise *pp, void (*fnptr) (EvalContext *ctx, char *path, Promise *ptr))
{
    Item *path, *ip, *remainder = NULL;
    char pbuffer[CF_BUFSIZE];
    struct stat statbuf;
    int count = 0, lastnode = false, expandregex = false;
    uid_t agentuid = getuid();
    int create = PromiseGetConstraintAsBoolean(ctx, "create", pp);
    char *pathtype = ConstraintGetRvalValue(ctx, "pathtype", pp, RVAL_TYPE_SCALAR);

    CfDebug("LocateFilePromiserGroup(%s)\n", wildpath);

/* Do a search for promiser objects matching wildpath */

    if ((!IsPathRegex(wildpath)) || (pathtype && (strcmp(pathtype, "literal") == 0)))
    {
        CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Using literal pathtype for %s\n", wildpath);
        (*fnptr) (ctx, wildpath, pp);
        return;
    }
    else
    {
        CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Using regex pathtype for %s (see pathtype)\n", wildpath);
    }

    pbuffer[0] = '\0';
    path = SplitString(wildpath, '/');  // require forward slash in regex on all platforms

    for (ip = path; ip != NULL; ip = ip->next)
    {
        if ((ip->name == NULL) || (strlen(ip->name) == 0))
        {
            continue;
        }

        if (ip->next == NULL)
        {
            lastnode = true;
        }

        /* No need to chdir as in recursive descent, since we know about the path here */

        if (IsRegex(ip->name))
        {
            remainder = ip->next;
            expandregex = true;
            break;
        }
        else
        {
            expandregex = false;
        }

        if (!JoinPath(pbuffer, ip->name))
        {
            CfOut(OUTPUT_LEVEL_ERROR, "", "Buffer has limited size in LocateFilePromiserGroup\n");
            return;
        }

        if (cfstat(pbuffer, &statbuf) != -1)
        {
            if ((S_ISDIR(statbuf.st_mode)) && ((statbuf.st_uid) != agentuid) && ((statbuf.st_uid) != 0))
            {
                CfOut(OUTPUT_LEVEL_INFORM, "",
                      "Directory %s in search path %s is controlled by another user (uid %ju) - trusting its content is potentially risky (possible race)\n",
                      pbuffer, wildpath, (uintmax_t)statbuf.st_uid);
                PromiseRef(OUTPUT_LEVEL_INFORM, pp);
            }
        }
    }

    if (expandregex)            /* Expand one regex link and hand down */
    {
        char nextbuffer[CF_BUFSIZE], nextbufferOrig[CF_BUFSIZE], regex[CF_BUFSIZE];
        const struct dirent *dirp;
        Dir *dirh;

        memset(regex, 0, CF_BUFSIZE);

        strncpy(regex, ip->name, CF_BUFSIZE - 1);

        if ((dirh = DirOpen(pbuffer)) == NULL)
        {
            // Could be a dummy directory to be created so this is not an error.
            CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Using best-effort expanded (but non-existent) file base path %s\n", wildpath);
            (*fnptr) (ctx, wildpath, pp);
            DeleteItemList(path);
            return;
        }
        else
        {
            count = 0;

            for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh))
            {
                if (!ConsiderLocalFile(dirp->d_name, pbuffer))
                {
                    continue;
                }

                if ((!lastnode) && (!S_ISDIR(statbuf.st_mode)))
                {
                    CfDebug("Skipping non-directory %s\n", dirp->d_name);
                    continue;
                }

                if (FullTextMatch(regex, dirp->d_name))
                {
                    CfDebug("Link %s matched regex %s\n", dirp->d_name, regex);
                }
                else
                {
                    continue;
                }

                count++;

                strncpy(nextbuffer, pbuffer, CF_BUFSIZE - 1);
                AddSlash(nextbuffer);
                strcat(nextbuffer, dirp->d_name);

                for (ip = remainder; ip != NULL; ip = ip->next)
                {
                    AddSlash(nextbuffer);
                    strcat(nextbuffer, ip->name);
                }

                /* The next level might still contain regexs, so go again as long as expansion is not nullpotent */

                if ((!lastnode) && (strcmp(nextbuffer, wildpath) != 0))
                {
                    LocateFilePromiserGroup(ctx, nextbuffer, pp, fnptr);
                }
                else
                {
                    Promise *pcopy;

                    CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Using expanded file base path %s\n", nextbuffer);

                    /* Now need to recompute any back references to get the complete path */

                    snprintf(nextbufferOrig, sizeof(nextbufferOrig), "%s", nextbuffer);
                    MapNameForward(nextbuffer);

                    if (!FullTextMatch(pp->promiser, nextbuffer))
                    {
                        CfDebug("Error recomputing references for \"%s\" in: %s", pp->promiser, nextbuffer);
                    }

                    /* If there were back references there could still be match.x vars to expand */

                    pcopy = ExpandDeRefPromise(ctx, ScopeGetCurrent()->scope, pp);
                    (*fnptr) (ctx, nextbufferOrig, pcopy);
                    PromiseDestroy(pcopy);
                }
            }

            DirClose(dirh);
        }
    }
    else
    {
        CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Using file base path %s\n", pbuffer);
        (*fnptr) (ctx, pbuffer, pp);
    }

    if (count == 0)
    {
        CfOut(OUTPUT_LEVEL_VERBOSE, "", "No promiser file objects matched as regular expression %s\n", wildpath);

        if (create)
        {
            (*fnptr)(ctx, pp->promiser, pp);
        }
    }

    DeleteItemList(path);
}
void MonNetworkSnifferGatherData(double *cf_this)
{
    int i;
    char vbuff[CF_BUFSIZE];

    for (i = 0; i < CF_NETATTR; i++)
    {
        struct stat statbuf;
        double entropy;
        time_t now = time(NULL);

        CfDebug("save incoming %s\n", TCPNAMES[i]);
        snprintf(vbuff, CF_MAXVARSIZE, "%s/state/cf_incoming.%s", CFWORKDIR, TCPNAMES[i]);

        if (cfstat(vbuff, &statbuf) != -1)
        {
            if ((ByteSizeList(NETIN_DIST[i]) < statbuf.st_size) && (now < statbuf.st_mtime + 40 * 60))
            {
                CfOut(cf_verbose, "", "New state %s is smaller, retaining old for 40 mins longer\n", TCPNAMES[i]);
                DeleteItemList(NETIN_DIST[i]);
                NETIN_DIST[i] = NULL;
                continue;
            }
        }

        SaveTCPEntropyData(NETIN_DIST[i], i, "in");

        entropy = MonEntropyCalculate(NETIN_DIST[i]);
        MonEntropyClassesSet(TCPNAMES[i], "in", entropy);
        DeleteItemList(NETIN_DIST[i]);
        NETIN_DIST[i] = NULL;
    }

    for (i = 0; i < CF_NETATTR; i++)
    {
        struct stat statbuf;
        double entropy;
        time_t now = time(NULL);

        CfDebug("save outgoing %s\n", TCPNAMES[i]);
        snprintf(vbuff, CF_MAXVARSIZE, "%s/state/cf_outgoing.%s", CFWORKDIR, TCPNAMES[i]);

        if (cfstat(vbuff, &statbuf) != -1)
        {
            if ((ByteSizeList(NETOUT_DIST[i]) < statbuf.st_size) && (now < statbuf.st_mtime + 40 * 60))
            {
                CfOut(cf_verbose, "", "New state %s is smaller, retaining old for 40 mins longer\n", TCPNAMES[i]);
                DeleteItemList(NETOUT_DIST[i]);
                NETOUT_DIST[i] = NULL;
                continue;
            }
        }

        SaveTCPEntropyData(NETOUT_DIST[i], i, "out");

        entropy = MonEntropyCalculate(NETOUT_DIST[i]);
        MonEntropyClassesSet(TCPNAMES[i], "out", entropy);
        DeleteItemList(NETOUT_DIST[i]);
        NETOUT_DIST[i] = NULL;
    }
}
Пример #20
0
RSA *HavePublicKey(char *username, char *ipaddress, char *digest)
{
    char keyname[CF_MAXVARSIZE], newname[CF_BUFSIZE], oldname[CF_BUFSIZE];
    struct stat statbuf;
    static char *passphrase = "public";
    unsigned long err;
    FILE *fp;
    RSA *newkey = NULL;

    snprintf(keyname, CF_MAXVARSIZE, "%s-%s", username, digest);

    CfDebug("HavePublickey(%s)\n", keyname);

    snprintf(newname, CF_BUFSIZE, "%s/ppkeys/%s.pub", CFWORKDIR, keyname);
    MapName(newname);

    if (cfstat(newname, &statbuf) == -1)
    {
        CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Did not find new key format %s", newname);
        snprintf(oldname, CF_BUFSIZE, "%s/ppkeys/%s-%s.pub", CFWORKDIR, username, ipaddress);
        MapName(oldname);

        CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Trying old style %s", oldname);

        if (cfstat(oldname, &statbuf) == -1)
        {
            CfDebug("Did not have old-style key %s\n", oldname);
            return NULL;
        }

        if (strlen(digest) > 0)
        {
            CfOut(OUTPUT_LEVEL_INFORM, "", " -> Renaming old key from %s to %s", oldname, newname);

            if (rename(oldname, newname) != 0)
            {
                CfOut(OUTPUT_LEVEL_ERROR, "rename", "!! Could not rename from old key format (%s) to new (%s)", oldname, newname);
            }
        }
        else                    // we don't know the digest (e.g. because we are a client and
            // have no lastseen-map and/or root-SHA...pub of the server's key
            // yet) Just using old file format (root-IP.pub) without renaming for now.
        {
            CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Could not map key file to new format - we have no digest yet (using %s)",
                  oldname);
            snprintf(newname, sizeof(newname), "%s", oldname);
        }
    }

    if ((fp = fopen(newname, "r")) == NULL)
    {
        CfOut(OUTPUT_LEVEL_ERROR, "fopen", "Couldn't find a public key (%s)", newname);
        return NULL;
    }

    if ((newkey = 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));
        fclose(fp);
        return NULL;
    }

    fclose(fp);

    if ((BN_num_bits(newkey->e) < 2) || (!BN_is_odd(newkey->e)))
    {
        FatalError("RSA Exponent too small or not odd");
    }

    return newkey;
}
Пример #21
0
void MonNetworkGatherData(double *cf_this)
{
    FILE *pp;
    char local[CF_BUFSIZE], remote[CF_BUFSIZE], comm[CF_BUFSIZE];
    Item *in[ATTR], *out[ATTR];
    char *sp;
    int i;
    char vbuff[CF_BUFSIZE];
    enum cf_netstat_type { cfn_new, cfn_old } type = cfn_new;
    enum cf_packet_type { cfn_tcp4, cfn_tcp6 } packet = cfn_tcp4;

    CfDebug("GatherSocketData()\n");

    for (i = 0; i < ATTR; i++)
    {
        in[i] = out[i] = NULL;
    }

    DeleteItemList(ALL_INCOMING);
    ALL_INCOMING = NULL;

    sscanf(VNETSTAT[VSYSTEMHARDCLASS], "%s", comm);

    strcat(comm, " -an");

    if ((pp = cf_popen(comm, "r")) == NULL)
    {
        return;
    }

    while (!feof(pp))
    {
        memset(local, 0, CF_BUFSIZE);
        memset(remote, 0, CF_BUFSIZE);

        CfReadLine(vbuff, CF_BUFSIZE, pp);

        if (strstr(vbuff, "UNIX"))
        {
            break;
        }

        if (!(strstr(vbuff, ":") || strstr(vbuff, ".")))
        {
            continue;
        }

        /* Different formats here ... ugh.. pick a model */

        // If this is old style, we look for chapter headings, e.g. "TCP: IPv4"

        if (strncmp(vbuff,"TCP:",4) == 0 && strstr(vbuff+4,"6"))
        {
            packet = cfn_tcp6;
            type = cfn_old;
            continue;
        }
        else if (strncmp(vbuff,"TCP:",4) == 0 && strstr(vbuff+4,"4"))
        {
            packet = cfn_tcp4;
            type = cfn_old;
            continue;
        }

        // Line by line state in modern/linux output

        if (strncmp(vbuff,"tcp6",4) == 0)
        {
            packet = cfn_tcp6;
            type = cfn_new;
        }
        else if (strncmp(vbuff,"tcp",3) == 0)
        {
            packet = cfn_tcp4;
            type = cfn_new;
        }

        // End extract type
        
        switch (type)
        {
        case cfn_new:  sscanf(vbuff, "%*s %*s %*s %s %s", local, remote);  /* linux-like */
            break;
            
        case cfn_old:
            sscanf(vbuff, "%s %s", local, remote);
            break;
        }

        if (strlen(local) == 0)
        {
            continue;
        }

        // Extract the port number from the end of the string
        
        for (sp = local + strlen(local); (*sp != '.') && (*sp != ':')  && (sp > local); sp--)
        {
        }

        *sp = '\0'; // Separate address from port number
        sp++;

        if (strstr(vbuff, "LISTEN"))
        {
            // General bucket

            IdempPrependItem(&ALL_INCOMING, sp, NULL);

            // Categories the incoming ports by packet types

            switch (packet)
            {
            case cfn_tcp4:
                IdempPrependItem(&MON_TCP4, sp, local);
                break;
            case cfn_tcp6:
                IdempPrependItem(&MON_TCP6, sp, local);
                break;
            default:
                break;
            }
        }


        // Now look at outgoing
        
        for (sp = remote + strlen(remote); (sp >= remote) && !isdigit((int) *sp); sp--)
        {
        }

        sp++;

        // Now look for the specific vital signs to count frequencies
        
        for (i = 0; i < ATTR; i++)
        {
            char *spend;

            for (spend = local + strlen(local) - 1; isdigit((int) *spend); spend--)
            {
            }

            spend++;

            if (strcmp(spend, ECGSOCKS[i].portnr) == 0)
            {
                cf_this[ECGSOCKS[i].in]++;
                AppendItem(&in[i], vbuff, "");
            }

            for (spend = remote + strlen(remote) - 1; (sp >= remote) && isdigit((int) *spend); spend--)
            {
            }

            spend++;

            if (strcmp(spend, ECGSOCKS[i].portnr) == 0)
            {
                cf_this[ECGSOCKS[i].out]++;
                AppendItem(&out[i], vbuff, "");
            }
        }
    }

    cf_pclose(pp);

/* Now save the state for ShowState() 
   the state is not smaller than the last or at least 40 minutes
   older. This mirrors the persistence of the maxima classes */

    for (i = 0; i < ATTR; i++)
    {
        struct stat statbuf;
        time_t now = time(NULL);

        CfDebug("save incoming %s\n", ECGSOCKS[i].name);
        snprintf(vbuff, CF_MAXVARSIZE, "%s/state/cf_incoming.%s", CFWORKDIR, ECGSOCKS[i].name);
        if (cfstat(vbuff, &statbuf) != -1)
        {
            if ((ByteSizeList(in[i]) < statbuf.st_size) && (now < statbuf.st_mtime + 40 * 60))
            {
                CfOut(cf_verbose, "", "New state %s is smaller, retaining old for 40 mins longer\n", ECGSOCKS[i].name);
                DeleteItemList(in[i]);
                continue;
            }
        }

        SetNetworkEntropyClasses(ECGSOCKS[i].name, "in", in[i]);
        RawSaveItemList(in[i], vbuff);
        DeleteItemList(in[i]);
        CfDebug("Saved in netstat data in %s\n", vbuff);
    }

    for (i = 0; i < ATTR; i++)
    {
        struct stat statbuf;
        time_t now = time(NULL);

        CfDebug("save outgoing %s\n", ECGSOCKS[i].name);
        snprintf(vbuff, CF_MAXVARSIZE, "%s/state/cf_outgoing.%s", CFWORKDIR, ECGSOCKS[i].name);

        if (cfstat(vbuff, &statbuf) != -1)
        {
            if ((ByteSizeList(out[i]) < statbuf.st_size) && (now < statbuf.st_mtime + 40 * 60))
            {
                CfOut(cf_verbose, "", "New state %s is smaller, retaining old for 40 mins longer\n", ECGSOCKS[i].name);
                DeleteItemList(out[i]);
                continue;
            }
        }

        SetNetworkEntropyClasses(ECGSOCKS[i].name, "out", out[i]);
        RawSaveItemList(out[i], vbuff);
        CfDebug("Saved out netstat data in %s\n", vbuff);
        DeleteItemList(out[i]);
    }
}
Пример #22
0
static void KeepKeyPromises(void)
{
    unsigned long err;
    RSA *pair;
    FILE *fp;
    struct stat statbuf;
    int fd;
    static char *passphrase = "Cfengine passphrase";
    const EVP_CIPHER *cipher;
    char vbuff[CF_BUFSIZE];

    NewScope("common");

    cipher = EVP_des_ede3_cbc();

    if (cfstat(CFPUBKEYFILE, &statbuf) != -1)
    {
        CfOut(cf_cmdout, "", "A key file already exists at %s\n", CFPUBKEYFILE);
        return;
    }

    if (cfstat(CFPRIVKEYFILE, &statbuf) != -1)
    {
        CfOut(cf_cmdout, "", "A key file already exists at %s\n", CFPRIVKEYFILE);
        return;
    }

    printf("Making a key pair for cfengine, please wait, this could take a minute...\n");

    pair = RSA_generate_key(2048, 35, NULL, NULL);

    if (pair == NULL)
    {
        err = ERR_get_error();
        CfOut(cf_error, "", "Unable to generate key: %s\n", ERR_reason_error_string(err));
        return;
    }

    if (DEBUG)
    {
        RSA_print_fp(stdout, pair, 0);
    }

    fd = open(CFPRIVKEYFILE, O_WRONLY | O_CREAT | O_TRUNC, 0600);

    if (fd < 0)
    {
        CfOut(cf_error, "open", "Open %s failed: %s.", CFPRIVKEYFILE, strerror(errno));
        return;
    }

    if ((fp = fdopen(fd, "w")) == NULL)
    {
        CfOut(cf_error, "fdopen", "Couldn't open private key %s.", CFPRIVKEYFILE);
        close(fd);
        return;
    }

    CfOut(cf_verbose, "", "Writing private key to %s\n", CFPRIVKEYFILE);

    if (!PEM_write_RSAPrivateKey(fp, pair, cipher, passphrase, strlen(passphrase), NULL, NULL))
    {
        err = ERR_get_error();
        CfOut(cf_error, "", "Couldn't write private key: %s\n", ERR_reason_error_string(err));
        return;
    }

    fclose(fp);

    fd = open(CFPUBKEYFILE, O_WRONLY | O_CREAT | O_TRUNC, 0600);

    if (fd < 0)
    {
        CfOut(cf_error, "open", "Unable to open public key %s.", CFPUBKEYFILE);
        return;
    }

    if ((fp = fdopen(fd, "w")) == NULL)
    {
        CfOut(cf_error, "fdopen", "Open %s failed.", CFPUBKEYFILE);
        close(fd);
        return;
    }

    CfOut(cf_verbose, "", "Writing public key to %s\n", CFPUBKEYFILE);

    if (!PEM_write_RSAPublicKey(fp, pair))
    {
        err = ERR_get_error();
        CfOut(cf_error, "", "Unable to write public key: %s\n", ERR_reason_error_string(err));
        return;
    }

    fclose(fp);

    snprintf(vbuff, CF_BUFSIZE, "%s/randseed", CFWORKDIR);
    RAND_write_file(vbuff);
    cf_chmod(vbuff, 0644);
}
Пример #23
0
static void MailResult(const ExecConfig *config, char *file)
{
    int sd, count = 0, anomaly = false;
    char prev_file[CF_BUFSIZE], vbuff[CF_BUFSIZE];
    struct hostent *hp;
    struct sockaddr_in raddr;
    struct servent *server;
    struct stat statbuf;
#if defined __linux__ || defined __NetBSD__ || defined __FreeBSD__ || defined __OpenBSD__
    time_t now = time(NULL);
#endif
    FILE *fp;

    CfOut(cf_verbose, "", "Mail result...\n");

    if (cfstat(file, &statbuf) == -1)
    {
        return;
    }

    snprintf(prev_file, CF_BUFSIZE - 1, "%s/outputs/previous", CFWORKDIR);
    MapName(prev_file);

    if (statbuf.st_size == 0)
    {
        unlink(file);
        CfDebug("Nothing to report in %s\n", file);
        return;
    }

    if (CompareResult(file, prev_file) == 0)
    {
        CfOut(cf_verbose, "", "Previous output is the same as current so do not mail it\n");
        return;
    }

    if ((strlen(config->mail_server) == 0) || (strlen(config->mail_to_address) == 0))
    {
        /* Syslog should have done this */
        CfOut(cf_verbose, "", "Empty mail server or address - skipping");
        return;
    }

    if (config->mail_max_lines == 0)
    {
        CfDebug("Not mailing: EmailMaxLines was zero\n");
        return;
    }

    CfDebug("Mailing results of (%s) to (%s)\n", file, config->mail_to_address);

/* Check first for anomalies - for subject header */

    if ((fp = fopen(file, "r")) == NULL)
    {
        CfOut(cf_inform, "fopen", "!! Couldn't open file %s", file);
        return;
    }

    while (!feof(fp))
    {
        vbuff[0] = '\0';
        if (fgets(vbuff, CF_BUFSIZE, fp) == NULL)
        {
            break;
        }

        if (strstr(vbuff, "entropy"))
        {
            anomaly = true;
            break;
        }
    }

    fclose(fp);

    if ((fp = fopen(file, "r")) == NULL)
    {
        CfOut(cf_inform, "fopen", "Couldn't open file %s", file);
        return;
    }

    CfDebug("Looking up hostname %s\n\n", config->mail_server);

    if ((hp = gethostbyname(config->mail_server)) == NULL)
    {
        printf("Unknown host: %s\n", config->mail_server);
        printf("Make sure that fully qualified names can be looked up at your site.\n");
        fclose(fp);
        return;
    }

    if ((server = getservbyname("smtp", "tcp")) == NULL)
    {
        CfOut(cf_inform, "getservbyname", "Unable to lookup smtp service");
        fclose(fp);
        return;
    }

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

    raddr.sin_port = (unsigned int) server->s_port;
    raddr.sin_addr.s_addr = ((struct in_addr *) (hp->h_addr))->s_addr;
    raddr.sin_family = AF_INET;

    CfDebug("Connecting...\n");

    if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        CfOut(cf_inform, "socket", "Couldn't open a socket");
        fclose(fp);
        return;
    }

    if (connect(sd, (void *) &raddr, sizeof(raddr)) == -1)
    {
        CfOut(cf_inform, "connect", "Couldn't connect to host %s\n", config->mail_server);
        fclose(fp);
        cf_closesocket(sd);
        return;
    }

/* read greeting */

    if (!Dialogue(sd, NULL))
    {
        goto mail_err;
    }

    sprintf(vbuff, "HELO %s\r\n", config->fq_name);
    CfDebug("%s", vbuff);

    if (!Dialogue(sd, vbuff))
    {
        goto mail_err;
    }

    if (strlen(config->mail_from_address) == 0)
    {
        sprintf(vbuff, "MAIL FROM: <cfengine@%s>\r\n", config->fq_name);
        CfDebug("%s", vbuff);
    }
    else
    {
        sprintf(vbuff, "MAIL FROM: <%s>\r\n", config->mail_from_address);
        CfDebug("%s", vbuff);
    }

    if (!Dialogue(sd, vbuff))
    {
        goto mail_err;
    }

    sprintf(vbuff, "RCPT TO: <%s>\r\n", config->mail_to_address);
    CfDebug("%s", vbuff);

    if (!Dialogue(sd, vbuff))
    {
        goto mail_err;
    }

    if (!Dialogue(sd, "DATA\r\n"))
    {
        goto mail_err;
    }

    if (anomaly)
    {
        sprintf(vbuff, "Subject: %s **!! [%s/%s]\r\n", MailSubject(), config->fq_name, config->ip_address);
        CfDebug("%s", vbuff);
    }
    else
    {
        sprintf(vbuff, "Subject: %s [%s/%s]\r\n", MailSubject(), config->fq_name, config->ip_address);
        CfDebug("%s", vbuff);
    }

    send(sd, vbuff, strlen(vbuff), 0);

#if defined __linux__ || defined __NetBSD__ || defined __FreeBSD__ || defined __OpenBSD__
    strftime(vbuff, CF_BUFSIZE, "Date: %a, %d %b %Y %H:%M:%S %z\r\n", localtime(&now));
    send(sd, vbuff, strlen(vbuff), 0);
#endif

    if (strlen(config->mail_from_address) == 0)
    {
        sprintf(vbuff, "From: cfengine@%s\r\n", config->fq_name);
        CfDebug("%s", vbuff);
    }
    else
    {
        sprintf(vbuff, "From: %s\r\n", config->mail_from_address);
        CfDebug("%s", vbuff);
    }

    send(sd, vbuff, strlen(vbuff), 0);

    sprintf(vbuff, "To: %s\r\n\r\n", config->mail_to_address);
    CfDebug("%s", vbuff);
    send(sd, vbuff, strlen(vbuff), 0);

    while (!feof(fp))
    {
        vbuff[0] = '\0';
        if (fgets(vbuff, CF_BUFSIZE, fp) == NULL)
        {
            break;
        }

        CfDebug("%s", vbuff);

        if (strlen(vbuff) > 0)
        {
            vbuff[strlen(vbuff) - 1] = '\r';
            strcat(vbuff, "\n");
            count++;
            send(sd, vbuff, strlen(vbuff), 0);
        }

        if ((config->mail_max_lines != INF_LINES) && (count > config->mail_max_lines))
        {
            sprintf(vbuff, "\r\n[Mail truncated by cfengine. File is at %s on %s]\r\n", file, config->fq_name);
            send(sd, vbuff, strlen(vbuff), 0);
            break;
        }
    }

    if (!Dialogue(sd, ".\r\n"))
    {
        CfDebug("mail_err\n");
        goto mail_err;
    }

    Dialogue(sd, "QUIT\r\n");
    CfDebug("Done sending mail\n");
    fclose(fp);
    cf_closesocket(sd);
    return;

  mail_err:

    fclose(fp);
    cf_closesocket(sd);
    CfOut(cf_log, "", "Cannot mail to %s.", config->mail_to_address);
}
Пример #24
0
bool CopyRegularFileDisk(const char *source, const char *destination, bool make_holes)
{
    int sd, dd, buf_size;
    char *buf, *cp;
    int n_read, *intp;
    long n_read_total = 0;
    int last_write_made_hole = 0;

    if ((sd = open(source, O_RDONLY | O_BINARY)) == -1)
    {
        CfOut(OUTPUT_LEVEL_INFORM, "open", "Can't copy %s!\n", source);
        unlink(destination);
        return false;
    }
    /*
     * We need to stat the file in order to get the right source permissions.
     */
    struct stat statbuf;

    if (cfstat(source, &statbuf) == -1)
    {
        CfOut(OUTPUT_LEVEL_INFORM, "stat", "Can't copy %s!\n", source);
        unlink(destination);
        return false;
    }

    unlink(destination);                /* To avoid link attacks */

    if ((dd = open(destination, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY, statbuf.st_mode)) == -1)
    {
        close(sd);
        unlink(destination);
        return false;
    }

    buf_size = ST_BLKSIZE(dstat);
    buf = xmalloc(buf_size + sizeof(int));

    while (true)
    {
        if ((n_read = read(sd, buf, buf_size)) == -1)
        {
            if (errno == EINTR)
            {
                continue;
            }

            close(sd);
            close(dd);
            free(buf);
            return false;
        }

        if (n_read == 0)
        {
            break;
        }

        n_read_total += n_read;

        intp = 0;

        if (make_holes)
        {
            buf[n_read] = 1;    /* Sentinel to stop loop.  */

            /* Find first non-zero *word*, or the word with the sentinel.  */

            intp = (int *) buf;

            while (*intp++ == 0)
            {
            }

            /* Find the first non-zero *byte*, or the sentinel.  */

            cp = (char *) (intp - 1);

            while (*cp++ == 0)
            {
            }

            /* If we found the sentinel, the whole input block was zero,
               and we can make a hole.  */

            if (cp > buf + n_read)
            {
                /* Make a hole.  */
                if (lseek(dd, (off_t) n_read, SEEK_CUR) < 0L)
                {
                    CfOut(OUTPUT_LEVEL_ERROR, "lseek", "Copy failed (no space?) while doing %s to %s\n", source, destination);
                    free(buf);
                    unlink(destination);
                    close(dd);
                    close(sd);
                    return false;
                }
                last_write_made_hole = 1;
            }
            else
            {
                /* Clear to indicate that a normal write is needed. */
                intp = 0;
            }
        }

        if (intp == 0)
        {
            if (FullWrite(dd, buf, n_read) < 0)
            {
                CfOut(OUTPUT_LEVEL_ERROR, "", "Copy failed (no space?) while doing %s to %s\n", source, destination);
                close(sd);
                close(dd);
                free(buf);
                unlink(destination);
                return false;
            }
            last_write_made_hole = 0;
        }
    }

    /* If the file ends with a `hole', something needs to be written at
       the end.  Otherwise the kernel would truncate the file at the end
       of the last write operation.  */

    if (last_write_made_hole)
    {
        /* Write a null character and truncate it again.  */

        if ((FullWrite(dd, "", 1) < 0) || (ftruncate(dd, n_read_total) < 0))
        {
            CfOut(OUTPUT_LEVEL_ERROR, "write", "cfengine: full_write or ftruncate error in CopyReg\n");
            free(buf);
            unlink(destination);
            close(sd);
            close(dd);
            return false;
        }
    }

    close(sd);
    close(dd);

    free(buf);
    return true;
}
Пример #25
0
void PurgeHashes(char *path, Attributes attr, Promise *pp)
/* Go through the database and purge records about non-existent files */
{
    CF_DB *dbp;
    CF_DBC *dbcp;
    struct stat statbuf;
    int ksize, vsize;
    char *key;
    void *value;

    if (!OpenDB(&dbp,dbid_checksums))
    {
        return;
    }

    if (path)
    {
        if (cfstat(path, &statbuf) == -1)
        {
            DeleteDB(dbp, path);
        }
        CloseDB(dbp);
        return;
    }

/* Acquire a cursor for the database. */

    if (!NewDBCursor(dbp, &dbcp))
    {
        CfOut(OUTPUT_LEVEL_INFORM, "", " !! Unable to scan hash database");
        CloseDB(dbp);
        return;
    }

    /* Walk through the database and print out the key/data pairs. */

    while (NextDB(dbp, dbcp, &key, &ksize, &value, &vsize))
    {
        char *obj = (char *) key + CF_INDEX_OFFSET;

        if (cfstat(obj, &statbuf) == -1)
        {
            if (attr.change.update)
            {
                DBCursorDeleteEntry(dbcp);
            }
            else
            {
                cfPS(OUTPUT_LEVEL_ERROR, CF_WARN, "", pp, attr, "ALERT: File %s no longer exists!", obj);
            }

            LogHashChange(obj, cf_file_removed, "File removed", pp);
        }

        memset(&key, 0, sizeof(key));
        memset(&value, 0, sizeof(value));
    }

    DeleteDBCursor(dbp, dbcp);
    CloseDB(dbp);
}
Пример #26
0
int ArchiveToRepository(char *file, Attributes attr, Promise *pp, const ReportContext *report_context)
 /* Returns true if the file was backup up and false if not */
{
    char destination[CF_BUFSIZE];
    struct stat sb, dsb;

    if (!GetRepositoryPath(file, attr, destination))
    {
        return false;
    }

    if (attr.copy.backup == cfa_nobackup)
    {
        return true;
    }

    if (IsItemIn(VREPOSLIST, file))
    {
        CfOut(cf_inform, "",
              "The file %s has already been moved to the repository once. Multiple update will cause loss of backup.",
              file);
        return true;
    }

    ThreadLock(cft_getaddr);
    PrependItemList(&VREPOSLIST, file);
    ThreadUnlock(cft_getaddr);

    CfDebug("Repository(%s)\n", file);
    
    JoinPath(destination, CanonifyName(file));

    if (!MakeParentDirectory(destination, attr.move_obstructions, report_context))
    {
    }

    if (cfstat(file, &sb) == -1)
    {
        CfDebug("File %s promised to archive to the repository but it disappeared!\n", file);
        return true;
    }

    cfstat(destination, &dsb);

    attr.copy.servers = NULL;
    attr.copy.backup = cfa_repos_store; // cfa_nobackup;
    attr.copy.stealth = false;
    attr.copy.verify = false;
    attr.copy.preserve = false;

    CheckForFileHoles(&sb, pp);

    if (CopyRegularFileDisk(file, destination, attr, pp))
    {
        CfOut(cf_inform, "", "Moved %s to repository location %s\n", file, destination);
        return true;
    }
    else
    {
        CfOut(cf_inform, "", "Failed to move %s to repository location %s\n", file, destination);
        return false;
    }
}
Пример #27
0
int DepthSearch(char *name, struct stat *sb, int rlevel, Attributes attr, Promise *pp)
{
    Dir *dirh;
    int goback;
    const struct dirent *dirp;
    char path[CF_BUFSIZE];
    struct stat lsb;

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

        CfDebug(" -> Direct file reference %s, no search implied\n", name);
        snprintf(basedir, sizeof(basedir), "%s", name);
        ChopLastNode(basedir);
        chdir(basedir);
        return VerifyFileLeaf(name, sb, attr, pp);
    }

    if (rlevel > CF_RECURSION_LIMIT)
    {
        CfOut(cf_error, "", "WARNING: Very deep nesting of directories (>%d deep): %s (Aborting files)", rlevel, name);
        return false;
    }

    if (rlevel > CF_RECURSION_LIMIT)
    {
        CfOut(cf_error, "", "WARNING: Very deep nesting of directories (>%d deep): %s (Aborting files)", rlevel, name);
        return false;
    }

    memset(path, 0, CF_BUFSIZE);

    CfDebug("To iterate is Human, to recurse is Divine...(%s)\n", name);

    if (!PushDirState(name, sb))
    {
        return false;
    }

    if ((dirh = OpenDirLocal(".")) == NULL)
    {
        CfOut(cf_inform, "opendir", "Could not open existing directory %s\n", name);
        return false;
    }

    for (dirp = ReadDir(dirh); dirp != NULL; dirp = ReadDir(dirh))
    {
        if (!ConsiderFile(dirp->d_name, name, attr, pp))
        {
            continue;
        }

        strcpy(path, name);
        AddSlash(path);

        if (!JoinPath(path, dirp->d_name))
        {
            CloseDir(dirh);
            return true;
        }

        if (lstat(dirp->d_name, &lsb) == -1)
        {
            CfOut(cf_verbose, "lstat", "Recurse was looking at %s when an error occurred:\n", path);
            continue;
        }

        if (S_ISLNK(lsb.st_mode))       /* should we ignore links? */
        {
            if (!KillGhostLink(path, attr, pp))
            {
                VerifyFileLeaf(path, &lsb, attr, pp);
            }
            else
            {
                continue;
            }
        }

        /* See if we are supposed to treat links to dirs as dirs and descend */

        if (attr.recursion.travlinks && S_ISLNK(lsb.st_mode))
        {
            if (lsb.st_uid != 0 && lsb.st_uid != getuid())
            {
                CfOut(cf_inform, "",
                      "File %s is an untrusted link: cfengine will not follow it with a destructive operation", path);
                continue;
            }

            /* if so, hide the difference by replacing with actual object */

            if (cfstat(dirp->d_name, &lsb) == -1)
            {
                CfOut(cf_error, "stat", "Recurse was working on %s when this failed:\n", path);
                continue;
            }
        }

        if (attr.recursion.xdev && DeviceBoundary(&lsb, pp))
        {
            CfOut(cf_verbose, "", "Skipping %s on different device - use xdev option to change this\n", path);
            continue;
        }

        if (S_ISDIR(lsb.st_mode))
        {
            if (SkipDirLinks(path, dirp->d_name, attr.recursion))
            {
                continue;
            }

            if (attr.recursion.depth > 1 && rlevel <= attr.recursion.depth)
            {
                CfOut(cf_verbose, "", " ->>  Entering %s (%d)\n", path, rlevel);
                goback = DepthSearch(path, &lsb, rlevel + 1, attr, pp);
                PopDirState(goback, name, sb, attr.recursion);
                VerifyFileLeaf(path, &lsb, attr, pp);
            }
            else
            {
                VerifyFileLeaf(path, &lsb, attr, pp);
            }
        }
        else
        {
            VerifyFileLeaf(path, &lsb, attr, pp);
        }
    }

    CloseDir(dirh);
    return true;
}
Пример #28
0
void MonNetworkGatherData(double *cf_this)
{
FILE *pp;
char local[CF_BUFSIZE],remote[CF_BUFSIZE],comm[CF_BUFSIZE];
struct Item *in[ATTR],*out[ATTR];
char *sp;
int i;
char vbuff[CF_BUFSIZE];

Debug("GatherSocketData()\n");

for (i = 0; i < ATTR; i++)
   {
   in[i] = out[i] = NULL;
   }

if (ALL_INCOMING != NULL)
   {
   DeleteItemList(ALL_INCOMING);
   ALL_INCOMING = NULL;
   }

if (ALL_OUTGOING != NULL)
   {
   DeleteItemList(ALL_OUTGOING);
   ALL_OUTGOING = NULL;
   }

sscanf(VNETSTAT[VSYSTEMHARDCLASS],"%s",comm);

strcat(comm," -n");

if ((pp = cf_popen(comm,"r")) == NULL)
   {
   return;
   }

while (!feof(pp))
   {
   memset(local,0,CF_BUFSIZE);
   memset(remote,0,CF_BUFSIZE);

   CfReadLine(vbuff,CF_BUFSIZE,pp);

   if (strstr(vbuff,"UNIX"))
      {
      break;
      }

   if (!strstr(vbuff,"."))
      {
      continue;
      }

   /* Different formats here ... ugh.. */

   if (strncmp(vbuff,"tcp",3) == 0)
      {
      sscanf(vbuff,"%*s %*s %*s %s %s",local,remote); /* linux-like */
      }
   else
      {
      sscanf(vbuff,"%s %s",local,remote);             /* solaris-like */
      }

   if (strlen(local) == 0)
      {
      continue;
      }

   for (sp = local+strlen(local); (*sp != '.') && (sp > local); sp--)
      {
      }

   sp++;

   if ((strlen(sp) < 5) &&!IsItemIn(ALL_INCOMING,sp))
      {
      PrependItem(&ALL_INCOMING,sp,NULL);
      }

   for (sp = remote+strlen(remote); (sp >= remote) && !isdigit((int)*sp); sp--)
      {
      }

   sp++;

   if ((strlen(sp) < 5) && !IsItemIn(ALL_OUTGOING,sp))
      {
      PrependItem(&ALL_OUTGOING,sp,NULL);
      }

   for (i = 0; i < ATTR; i++)
      {
      char *spend;

      for (spend = local+strlen(local)-1; isdigit((int)*spend); spend--)
         {
         }

      spend++;

      if (strcmp(spend,ECGSOCKS[i].portnr) == 0)
         {
         cf_this[ECGSOCKS[i].in]++;
         AppendItem(&in[i],vbuff,"");
         }

      for (spend = remote+strlen(remote)-1; (sp >= remote) && isdigit((int)*spend); spend--)
         {
         }

      spend++;

      if (strcmp(spend,ECGSOCKS[i].portnr) == 0)
         {
         cf_this[ECGSOCKS[i].out]++;
         AppendItem(&out[i],vbuff,"");
         }
      }
   }

cf_pclose(pp);

/* Now save the state for ShowState() cf2 version alert function IFF
   the state is not smaller than the last or at least 40 minutes
   older. This mirrors the persistence of the maxima classes */


for (i = 0; i < ATTR; i++)
   {
   struct stat statbuf;
   time_t now = time(NULL);

   Debug("save incoming %s\n",ECGSOCKS[i].name);
   snprintf(vbuff,CF_MAXVARSIZE,"%s/state/cf_incoming.%s",CFWORKDIR,ECGSOCKS[i].name);
   if (cfstat(vbuff,&statbuf) != -1)
      {
      if ((ByteSizeList(in[i]) < statbuf.st_size) && (now < statbuf.st_mtime+40*60))
         {
         CfOut(cf_verbose,"","New state %s is smaller, retaining old for 40 mins longer\n",ECGSOCKS[i].name);
         DeleteItemList(in[i]);
         continue;
         }
      }

   SetNetworkEntropyClasses(ECGSOCKS[i].name,"in",in[i]);
   RawSaveItemList(in[i],vbuff);
   DeleteItemList(in[i]);
   Debug("Saved in netstat data in %s\n",vbuff);
   }

for (i = 0; i < ATTR; i++)
   {
   struct stat statbuf;
   time_t now = time(NULL);

   Debug("save outgoing %s\n",ECGSOCKS[i].name);
   snprintf(vbuff,CF_MAXVARSIZE,"%s/state/cf_outgoing.%s",CFWORKDIR,ECGSOCKS[i].name);

   if (cfstat(vbuff,&statbuf) != -1)
      {
      if ((ByteSizeList(out[i]) < statbuf.st_size) && (now < statbuf.st_mtime+40*60))
         {
         CfOut(cf_verbose,"","New state %s is smaller, retaining old for 40 mins longer\n",ECGSOCKS[i].name);
         DeleteItemList(out[i]);
         continue;
         }
      }

   SetNetworkEntropyClasses(ECGSOCKS[i].name,"out",out[i]);
   RawSaveItemList(out[i],vbuff);
   Debug("Saved out netstat data in %s\n",vbuff);
   DeleteItemList(out[i]);
   }
}