コード例 #1
0
ファイル: djconfig_mac.c プロジェクト: Brainiarc7/pbis
DWORD
DJIsAppleADPluginInUse(BOOLEAN* pExists)
{
    DWORD ceError = ERROR_SUCCESS;
    PSTR value = NULL;
    PSTR valueStart = NULL;
    BOOLEAN bInUse = FALSE;

    DJ_LOG_INFO("Testing to see if Apple AD plugin is already in use");

    ceError = CTCaptureOutput("/usr/bin/dscl localhost -list / | grep \"^Active Directory\"", &value);
    if (ceError)
    {
        ceError = ERROR_SUCCESS;
        goto error;
    }

    CTStripWhitespace(value);
    valueStart = strstr(value, "Active Directory");
    if (valueStart != NULL)
    {
        bInUse = TRUE;
    }

error:

    CT_SAFE_FREE_STRING(value);

    *pExists = bInUse;

    return ceError;
}
コード例 #2
0
ファイル: ctprocutils.c プロジェクト: Brainiarc7/pbis
DWORD
CTMatchProgramToPID(
    PCSTR pszProgramName,
    pid_t    pid
    )
{
    DWORD ceError = ERROR_SUCCESS;
    CHAR szBuf[PATH_MAX+1];
    FILE* pFile = NULL;

#if defined(__LWI_DARWIN__) || defined(__LWI_FREEBSD__)
    sprintf(szBuf, "ps -p %d -o command= | grep %s", pid, pszProgramName);
#elif defined(__LWI_SOLARIS__) || defined(__LWI_HP_UX__) || defined(__LWI_AIX__)
    sprintf(szBuf, "PS=ps; [ -x /bin/ps ] && PS=/bin/ps; UNIX95=1 $PS -p %ld -o comm= | grep %s", (long)pid, pszProgramName);
#else
    sprintf(szBuf, "UNIX95=1 ps -p %ld -o cmd= | grep %s", (long)pid, pszProgramName);
#endif

    pFile = popen(szBuf, "r");
    if (pFile == NULL) {
        ceError = LwMapErrnoToLwError(errno);
        BAIL_ON_CENTERIS_ERROR(ceError);
    }

    /* Assume that we won't find the process we are looking for */
    ceError = ERROR_PROC_NOT_FOUND;

    while (TRUE) {

        if (NULL == fgets(szBuf, PATH_MAX, pFile)) {
            if (feof(pFile)) {
                break;
            } else {
                ceError = LwMapErrnoToLwError(errno);
                BAIL_ON_CENTERIS_ERROR(ceError);
            }
        }

        CTStripWhitespace(szBuf);
        if (!IsNullOrEmptyString(szBuf)) {
            /* Well what do you know, it was found! */
            ceError = ERROR_SUCCESS;
            break;
        }

    }

error:

    if (pFile)
        pclose(pFile);

    return ceError;
}
コード例 #3
0
ファイル: djaixparser.c プロジェクト: Brainiarc7/pbis
DWORD DJGetOptionValue(const DynamicArray *lines, PCSTR stanza, PCSTR name, PSTR *value)
{
    DWORD ceError = ERROR_SUCCESS;
    ssize_t i = DJFindLine(lines, stanza, name);
    PCSTR line;
    PSTR _value = NULL;

    *value = NULL;
    
    if(i == -1)
        GCE(ceError = ERROR_NOT_FOUND);

    line = *(PCSTR *)CTArrayGetItem((DynamicArray*)lines, i,
            sizeof(PCSTR));

    while (*line != '\0' && isspace((int)*line))
        line++;

    line += strlen(name);
   
    while (*line != '\0' && isspace((int)*line))
        line++;

    if(*line != '=')
    {
        GCE(ceError = ERROR_BAD_FORMAT);
    }
    line++;

    GCE(ceError = CTStrdup(line, &_value));
    CTStripWhitespace(_value);
    /* Remove the quotes around the value, if they exist */
    if(CTStrStartsWith(_value, "\"") && CTStrEndsWith(_value, "\""))
    {
        size_t len = strlen(_value);
        memmove(_value, _value + 1, len - 2 );
        _value[len - 2 ] = '\0';
    }

    *value = _value;
    _value = NULL;

cleanup:
    CT_SAFE_FREE_STRING(_value);
    return ceError;
}
コード例 #4
0
static DWORD UnsupportedSeLinuxEnabled(BOOLEAN *hasBadSeLinux)
{
    BOOLEAN hasSeLinux;
    DWORD ceError = ERROR_SUCCESS;
    PSTR output = NULL;
    DistroInfo distro;

    *hasBadSeLinux = FALSE;
    memset(&distro, 0, sizeof(distro));

    GCE(ceError = CTCheckFileOrLinkExists("/usr/sbin/selinuxenabled", &hasSeLinux));
    if(!hasSeLinux)
        goto cleanup;

    GCE(ceError = CTCheckFileOrLinkExists("/usr/sbin/getenforce", &hasSeLinux));
    if(!hasSeLinux)
        goto cleanup;

    ceError = CTRunCommand("/usr/sbin/selinuxenabled >/dev/null 2>&1");
    if(ceError == ERROR_BAD_COMMAND)
    {
        //selinux is not enabled
        ceError = ERROR_SUCCESS;
        goto cleanup;
    }
    GCE(ceError);

    GCE(ceError = CTCaptureOutput("/usr/sbin/getenforce", &output));
    CTStripWhitespace(output);
    if(!strcmp(output, "Permissive"))
    {
        goto cleanup;
    }

    DJ_LOG_INFO("Selinux found to be present, enabled, and enforcing.");

    GCE(ceError = DJGetDistroInfo("", &distro));

    switch(distro.distro)
    {
        case DISTRO_CENTOS:
        case DISTRO_RHEL:
            if(distro.version[0] < '5')
            {
                DJ_LOG_INFO("Safe version of RHEL");
                goto cleanup;
            }
            break;
        case DISTRO_FEDORA:
            if(atol(distro.version) < 6)
            {
                DJ_LOG_INFO("Safe version of Fedora");
                goto cleanup;
            }
            break;
        default:
            goto cleanup;
    }
    *hasBadSeLinux = TRUE;

cleanup:
    if(ceError)
        *hasBadSeLinux = TRUE;

    CT_SAFE_FREE_STRING(output);
    DJFreeDistroInfo(&distro);

    return ceError;
}
コード例 #5
0
ファイル: djparsehosts.c プロジェクト: aleksey-novikov/pbis
// newFdqnHostname = <shortHostname>.<dnsDomainName>
DWORD
DJReplaceHostnameInMemory(
    PHOSTSFILELINE pHostsFileLineList,
    PCSTR oldShortHostname,
    PCSTR oldFqdnHostname,
    PCSTR shortHostname,
    PCSTR dnsDomainName
    )
{
    DWORD ceError = ERROR_SUCCESS;
    PSTR pszDomainName = NULL;
    PSTR pszHostName = NULL;
    PSTR pszCanonicalName = NULL;
    PHOSTSFILELINE pLine = NULL;
    PHOSTSFILELINE pCreatedLine = NULL;
    BOOLEAN bFound = FALSE;
    BOOLEAN bModified = FALSE;
    PHOSTFILEALIAS pAlias = NULL;

    //
    // Ideal algorithm:
    //
    // 1) Find any lines with hostname.
    // 2) Make sure the the FQDN is present as the first
    //    name in each of those lines.
    // 3) If no lines were found, then add hostname to 127.0.0.1
    //    and put FQDN first.
    // 4) If 127.0.0.2 line is present, edit that to just have our info.
    //

    if (IsNullOrEmptyString(shortHostname)) {
        ceError = ERROR_INVALID_PARAMETER;
        BAIL_ON_CENTERIS_ERROR(ceError);
    }

    if (strchr(shortHostname, '.')) {
        ceError = ERROR_INVALID_COMPUTERNAME;
        BAIL_ON_CENTERIS_ERROR(ceError);
    }

    ceError = CTAllocateString(shortHostname, &pszHostName);
    BAIL_ON_CENTERIS_ERROR(ceError);

    CTStripWhitespace(pszHostName);

    CTStrToLower(pszHostName);

    if (dnsDomainName != NULL)
    {
        ceError = CTAllocateString(dnsDomainName, &pszDomainName);
        BAIL_ON_CENTERIS_ERROR(ceError);
        CTStripWhitespace(pszDomainName);
        CTStrToLower(pszDomainName);
        ceError = CTAllocateMemory(strlen(pszHostName)+strlen(pszDomainName)+2,
                                   (PVOID*)(PVOID)&pszCanonicalName);
        BAIL_ON_CENTERIS_ERROR(ceError);

        sprintf(pszCanonicalName, "%s.%s", pszHostName, pszDomainName);
    }
    else
    {
        ceError = CTAllocateString(pszHostName, &pszCanonicalName);
        BAIL_ON_CENTERIS_ERROR(ceError);
    }

    for (pLine = pHostsFileLineList; pLine; pLine = pLine->pNext) {

        if (pLine->pEntry != NULL) {
            if (pLine->pEntry->pszCanonicalName != NULL &&
                (!strcasecmp(pLine->pEntry->pszCanonicalName, pszHostName) ||
                 !strcasecmp(pLine->pEntry->pszCanonicalName, oldShortHostname ? oldShortHostname : "") ||
                 !strcasecmp(pLine->pEntry->pszCanonicalName, oldFqdnHostname ? oldFqdnHostname : "") ||
                 !strcasecmp(pLine->pEntry->pszCanonicalName, pszCanonicalName))) {

                ceError = DJUpdateHostEntry( pLine, pszHostName, pszCanonicalName, oldShortHostname, oldFqdnHostname);
                BAIL_ON_CENTERIS_ERROR(ceError);
                bFound = TRUE;
            }
            else if (DJEntryHasAlias(pLine->pEntry->pAliasList, pszHostName)) {

                bFound = TRUE;
                ceError = DJUpdateHostEntry( pLine, pszHostName, pszCanonicalName, oldShortHostname, oldFqdnHostname);
                BAIL_ON_CENTERIS_ERROR(ceError);
            }
        }
    }

    if (!bFound) {
        //First try to setup ip address on the loop back device which are not
        //127.0.0.1
        for (pLine = pHostsFileLineList; pLine; pLine = pLine->pNext) {
            if (pLine->pEntry != NULL &&
                !strncmp(pLine->pEntry->pszIpAddress, "127.0.", strlen("127.0.")) &&
                strcmp(pLine->pEntry->pszIpAddress, "127.0.0.1"))
            {
                ceError = DJUpdateHostEntry( pLine, pszHostName, pszCanonicalName, oldShortHostname, oldFqdnHostname);
                BAIL_ON_CENTERIS_ERROR(ceError);
                bFound = TRUE;
            }
        }
        if (!bFound)
        {
            //Have to add it to the 127.0.0.1 address
            pLine = DJFindLineByIPAddress(pHostsFileLineList, "127.0.0.1");
            if(pLine == NULL)
            {
                //We have to create the 127.0.0.1 address
                ceError = CTAllocateMemory(sizeof(HOSTSFILELINE), (PVOID*)(PVOID)&pCreatedLine);
                BAIL_ON_CENTERIS_ERROR(ceError);

                ceError = CTAllocateMemory(sizeof(HOSTSFILEENTRY),
                                           (PVOID*)(PVOID)&pCreatedLine->pEntry);

                ceError = CTAllocateString("127.0.0.1",
                                           &pCreatedLine->pEntry->pszIpAddress);
                BAIL_ON_CENTERIS_ERROR(ceError);

                ceError = DJAddAlias(pCreatedLine, "localhost", FALSE, &bModified);
                BAIL_ON_CENTERIS_ERROR(ceError);

                *DJGetLastHostsLine(&pHostsFileLineList) = pCreatedLine;
                pLine = pCreatedLine;
                pCreatedLine = NULL;
            }
            ceError = DJUpdateHostEntry( pLine, pszHostName, pszCanonicalName, oldShortHostname, oldFqdnHostname);
            BAIL_ON_CENTERIS_ERROR(ceError);
        }
    }

error:

    if (pAlias)
        DJFreeAlias(pAlias);

    if (pszHostName)
        CTFreeString(pszHostName);

    if (pszDomainName)
        CTFreeString(pszDomainName);

    if (pszCanonicalName)
        CTFreeMemory(pszCanonicalName);

    if(pCreatedLine)
        DJFreeHostsLine(pCreatedLine);

    return ceError;
}
コード例 #6
0
ファイル: djparsehosts.c プロジェクト: aleksey-novikov/pbis
DWORD
DJParseHostsFile(
    const char *filename,
    PHOSTSFILELINE* ppHostsFileLineList
    )
{
    DWORD ceError = ERROR_SUCCESS;
    PHOSTSFILELINE pLineHead = NULL;
    PHOSTSFILELINE pHostsLine = NULL;
    PHOSTFILEALIAS pAlias = NULL;
    FILE* fp = NULL;
    CHAR szBuf[1024+1];
    PSTR pszTmp = NULL;
    DWORD iToken = 0;
    PHOSTSFILELINE pLineTail = NULL;
    BOOLEAN exists;

    BAIL_ON_CENTERIS_ERROR(ceError = CTCheckFileOrLinkExists(filename, &exists));
    if(!exists)
        BAIL_ON_CENTERIS_ERROR(ceError = ERROR_FILE_NOT_FOUND);

    fp = fopen(filename, "r");
    if (fp == NULL) {
        ceError = LwMapErrnoToLwError(errno);
        BAIL_ON_CENTERIS_ERROR(ceError);
    }

    while (1) {

        if (fgets(szBuf, 1024, fp) == NULL) {

            if (!feof(fp)) {

                ceError = LwMapErrnoToLwError(errno);
                BAIL_ON_CENTERIS_ERROR(ceError);

            } else {

                break;

            }
        }

        CTStripWhitespace(szBuf);

        ceError = CTAllocateMemory(sizeof(HOSTSFILELINE),
                                   (PVOID*)(PVOID)&pHostsLine);
        BAIL_ON_CENTERIS_ERROR(ceError);

        pHostsLine->pEntry = NULL;
        pHostsLine->pszComment = NULL;
        pszTmp = strchr(szBuf, '#');
        if (pszTmp != NULL) {
            ceError = CTAllocateString(pszTmp,
                                       &pHostsLine->pszComment);
            BAIL_ON_CENTERIS_ERROR(ceError);

            *pszTmp = '\0';
        }

        if(szBuf[0] != '\0')
        {
            ceError = CTAllocateMemory(sizeof(HOSTSFILEENTRY),
                                       (PVOID*)(PVOID)&pHostsLine->pEntry);
            BAIL_ON_CENTERIS_ERROR(ceError);


            iToken = 0;
            pszTmp = strtok(szBuf, " \t");
            while (pszTmp != NULL) {

                if (iToken == 0) {

                    ceError = CTAllocateString(pszTmp,
                                               &pHostsLine->pEntry->pszIpAddress);
                    BAIL_ON_CENTERIS_ERROR(ceError);

                } else if (iToken == 1) {

                    ceError = CTAllocateString(pszTmp,
                                               &pHostsLine->pEntry->pszCanonicalName);
                    BAIL_ON_CENTERIS_ERROR(ceError);

                } else {

                    ceError = CTAllocateMemory(sizeof(HOSTFILEALIAS),
                                               (PVOID*)(PVOID)&pAlias);
                    BAIL_ON_CENTERIS_ERROR(ceError);

                    ceError = CTAllocateString(pszTmp, &pAlias->pszAlias);
                    BAIL_ON_CENTERIS_ERROR(ceError);

                    //The alias list is first built in reverse
                    pAlias->pNext = pHostsLine->pEntry->pAliasList;
                    pHostsLine->pEntry->pAliasList = pAlias;
                    pAlias = NULL;
                }

                iToken++;

                pszTmp = strtok(NULL, " \t");
            }

            if (pHostsLine->pEntry->pAliasList) {
                pHostsLine->pEntry->pAliasList =
                    DJReverseAliasList(pHostsLine->pEntry->pAliasList);
            }
        }

        if(pLineTail != NULL)
            pLineTail->pNext = pHostsLine;
        else
            pLineHead = pHostsLine;
        pLineTail = pHostsLine;

        pHostsLine = NULL;
    }

    *ppHostsFileLineList = pLineHead;
    pLineHead = NULL;

error:

    if (pAlias)
        DJFreeAlias(pAlias);

    if (pHostsLine)
        DJFreeHostsLine(pHostsLine);

    if (pLineHead)
        DJFreeHostsFileLineList(pLineHead);

    if (fp)
        fclose(fp);

    return ceError;
}
コード例 #7
0
static QueryResult QueryDSPlugin(const JoinProcessOptions *options, LWException **exc)
{
    BOOLEAN exists = FALSE;
    QueryResult result = NotConfigured;
    PSTR value = NULL;
    PSTR valueStart = NULL;
    BOOLEAN bLikewisePresent = FALSE;

    if (options->enableMultipleJoins)
    {
        result = NotApplicable;
        goto cleanup;
    }

    LW_CLEANUP_CTERR(exc, CTCheckFileOrLinkExists("/usr/bin/dscl", &exists));
    if(!exists)
    {
        result = NotApplicable;
        goto cleanup;
    }

    LW_CLEANUP_CTERR(exc, DJIsAppleADPluginInUse(&exists));
    if(exists)
    {
        result = ApplePluginInUse;
        goto cleanup;
    }

    LW_CLEANUP_CTERR(exc, CTCaptureOutput("/usr/bin/dscl /Search -read / dsAttrTypeStandard:SearchPolicy", &value));
    CTStripWhitespace(value);
    valueStart = value;
    if(CTStrStartsWith(valueStart, "SearchPolicy:"))
        valueStart += strlen("SearchPolicy:");
    CTStripWhitespace(valueStart);
    if(CTStrStartsWith(valueStart, "dsAttrTypeStandard:"))
      valueStart += strlen("dsAttrTypeStandard:");
    CTStripWhitespace(valueStart);
    if(options->joiningDomain)
    {
        if(strcmp(valueStart, "CSPSearchPath"))
            goto cleanup;
    }
    else
    {
        if(strcmp(valueStart, "NSPSearchPath"))
            goto cleanup;
    }
    CT_SAFE_FREE_STRING(value);

    LW_CLEANUP_CTERR(exc, CTCaptureOutput("/usr/bin/dscl /Search -read / dsAttrTypeStandard:CSPSearchPath", &value));
    CTStripWhitespace(value);
    valueStart = strstr(value, LWDSPLUGIN_NAME);
    if (valueStart == NULL)
    {
        bLikewisePresent = FALSE;
    }
    else
    {
        switch (valueStart[strlen(LWDSPLUGIN_NAME)])
        {
            case 0:
            case '\r':
            case '\n':
                bLikewisePresent = TRUE;
                break;
            default:
                bLikewisePresent = FALSE;
        }
    }

    if( (bLikewisePresent != 0) != (options->joiningDomain != 0) )
        goto cleanup;
    CT_SAFE_FREE_STRING(value);

    result = FullyConfigured;

cleanup:
    CT_SAFE_FREE_STRING(value);
    return result;
}
コード例 #8
0
ファイル: ctdistroinfo.c プロジェクト: josephholsten/pbis
DWORD
CTGetLikewiseVersion(
    PSTR *product,
    PSTR *version,
    PSTR *build,
    PSTR *revision
    )
{
    FILE *versionFile = NULL;
    PSTR line = NULL; 
    BOOLEAN isEndOfFile = FALSE;
    DWORD ceError = ERROR_SUCCESS;
    BOOLEAN bIsEnterprise = FALSE;

    PSTR _product = NULL;
    PSTR _version = NULL;
    PSTR _build = NULL;
    PSTR _revision = NULL;

    *version = NULL;
    *build = NULL;
    *revision = NULL;

#ifdef MINIMAL_JOIN
    GCE(ceError = CTOpenFile(LOCALSTATEDIR "/VERSION", "r", &versionFile));
#else
    ceError = CTOpenFile(PREFIXDIR "/data/ENTERPRISE_VERSION", "r", &versionFile);
    if (ceError == 0)
    {
        bIsEnterprise = TRUE;
    }
    else
    {
        GCE(ceError = CTOpenFile(PREFIXDIR "/data/VERSION", "r", &versionFile));
    }
#endif

    while (TRUE)
    {
		CT_SAFE_FREE_STRING(line);
        GCE(ceError = CTReadNextLine(versionFile, &line, &isEndOfFile));
        if (isEndOfFile)
            break;
        CTStripWhitespace(line);
        if (!strncmp(line, "VERSION=", sizeof("VERSION=") - 1))
        {
            GCE(ceError = CTStrdup(line + sizeof("VERSION=") - 1,
                        &_version));
        }
        else if (!strncmp(line, "BUILD=", sizeof("BUILD=") - 1))
        {
            GCE(ceError = CTStrdup(line + sizeof("BUILD=") - 1,
                    &_build));
        }
        else if (!strncmp(line, "REVISION=", sizeof("REVISION=") - 1))
        {
            GCE(ceError = CTStrdup(line + sizeof("REVISION=") - 1,
                    &_revision));
        }
    }

    if (bIsEnterprise)
    {
        GCE(ceError = CTStrdup("Enterprise", &_product));
    }
    else
    {
        GCE(ceError = CTStrdup("Open", &_product));
    }
    if (_version == NULL)
    {
        GCE(ceError = CTStrdup("unknown", &_version));
    }
    if (_build == NULL)
    {
        GCE(ceError = CTStrdup("unknown", &_build));
    }
    if (_revision == NULL)
    {
        GCE(ceError = CTStrdup("unknown", &_revision));
    }

    GCE(ceError = CTSafeCloseFile(&versionFile));

    *product = _product;
    *version = _version;
    *build = _build;
    *revision = _revision;
    _product = NULL;
    _version = NULL;
    _build = NULL;
    _revision = NULL;
    
cleanup:

    CTSafeCloseFile(&versionFile);
    CT_SAFE_FREE_STRING(line);
    CT_SAFE_FREE_STRING(_version);
    CT_SAFE_FREE_STRING(_build);
    CT_SAFE_FREE_STRING(_revision);

    return ceError;
}
コード例 #9
0
ファイル: ctdistroinfo.c プロジェクト: josephholsten/pbis
DWORD CTGetDistroInfo(const char *testPrefix, CtDistroInfo *info)
{
    BOOLEAN exists;
    DWORD ceError = ERROR_SUCCESS;
    struct utsname unameStruct;
    char *path = NULL;
    PSTR fileContents = NULL;
    PSTR distroString = NULL;
    BOOLEAN rxAlloced = FALSE;
    regex_t rx;
    memset(info, 0, sizeof(*info));
#if defined(HAVE_SYSINFO) && defined(SI_ARCHITECTURE)
    char archBuffer[100];
#endif

    //According to the Solaris man page, any non-negative return value
    //indicates success. In fact, Solaris 8 returns 1, while Linux returns
    //0.
    if(uname(&unameStruct) < 0)
        return LwMapErrnoToLwError(errno);

    //Check for os override file
    if(testPrefix == NULL)
        testPrefix = "";
    GCE(ceError = CTAllocateStringPrintf(
            &path, "%s/ostype", testPrefix));
    GCE(ceError = CTCheckFileOrLinkExists(
            path, &exists));
    if(exists)
    {
        GCE(ceError = CTReadFile(
                path, SIZE_MAX, &fileContents, NULL));
    }
    if(fileContents != NULL)
    {
        CTStripWhitespace(fileContents);
        info->os = CTGetOSFromString(fileContents);
    }
    else
        info->os = CTGetOSFromString(unameStruct.sysname);
    CT_SAFE_FREE_STRING(fileContents);
    CT_SAFE_FREE_STRING(path);

    //Check for distro override file
    GCE(ceError = CTAllocateStringPrintf(
            &path, "%s/osdistro", testPrefix));
    GCE(ceError = CTCheckFileOrLinkExists(
            path, &exists));
    if(exists)
    {
        GCE(ceError = CTReadFile(
                path, SIZE_MAX, &distroString, NULL));
    }
    CT_SAFE_FREE_STRING(path);

    if(distroString != NULL)
    {
        CTStripWhitespace(distroString);
        info->distro = CTGetDistroFromString(distroString);
        CT_SAFE_FREE_STRING(distroString);
        GCE(ceError = CTStrdup("unknown", &info->version));
    }
    else if(info->os == OS_LINUX)
    {
        struct
        {
            CtDistroType matchDistro;
            const char *searchFile;
            const char *matchRegex;
            int versionMatchNum;
            int updateMatchNum;
            BOOLEAN compareCase;
        } const distroSearch[] = {
            {
                DISTRO_ESX,
                "/etc/vmware-release",
                /*
                # The format of the line is something like:
                #   VMware ESX 4.0 (Kandinsky)
                */
                "^[[:space:]]*VMware ESX ([[:digit:]]+(\\.[[:digit:]]+)?)"
                "( \\(\\S+\\))?",
                1,
                -1,
                1
            },
            {
                DISTRO_RHEL,
                "/etc/redhat-release",
                /*
                # The format of the line is something like:
                #   Red Hat Enterprise Linux ES release 4 (Nahant Update 1)
                #   Red Hat Linux Advanced Server release 2.1AS (Pensacola)
                #   Red Hat Enterprise Linux Client release 5 (Tikanga)
                #   Red Hat Enterprise Linux Server release 5.3 (Tikanga)
                #   Red Hat Enterprise Linux ES release 4 (Nahant Update 8)
                #   Red Hat Enterprise Linux Workstation release 6.0 (Santiago)
                # In addition, Oracle Linux reports itself as:
                #   Enterprise Linux Enterprise Linux AS release 4 (October Update 5)
                */
                //Find a matching distro name
                "^[[:space:]]*((Red Hat)|(Enterprise Linux)) ((Enterprise Linux)|(Linux (Advanced|Enterprise) Server))[[:space:]]+(AS |ES |Client |Server |Workstation )?"
                "release ([[:digit:]]+(\\.[[:digit:]]+)?(AS|ES)?) (\\(\\S+ Update ([[:digit:]]+)\\))?",
                9,
                13,
                1
            },
            {
                DISTRO_REDHAT,
                "/etc/redhat-release",
                /*
                # The format of the line is something like:
                #   Red Hat Linux release 7.3 (Valhala)
                */
                "^[[:space:]]*Red Hat Linux release ([[:digit:]]+(\\.[[:digit:]]+)?)",
                1,
                -1,
                1
            },
            {
                DISTRO_FEDORA,
                "/etc/redhat-release",
                /*
                # The format of the line is something like:
                #   Fedora Core release 4 (Stentz)
                */
                "^[[:space:]]*Fedora (Core )?release (\\S+)",
                2,
                -1,
                1
            },
            {
                DISTRO_CENTOS,
                "/etc/redhat-release",
                /*
                # The format of the line is something like:
                #   CentOS release 4.x (Final)
                */
                "^[[:space:]]*(CentOS|CentOS Linux) release ([[:digit:]]+(\\.[[:digit:]]+)?)",
                2,
                -1,
                1
            },
            {
                DISTRO_SCIENTIFIC,
                "/etc/redhat-release",
                /*
                # The format of the line is something like:
                #   Scientific Linux release 6.1 (Carbon)
                */
                "^[[:space:]]*(Scientific|Scientific Linux) release ([[:digit:]]+(\\.[[:digit:]]+)?)",
                2,
                -1,
                1
            },
            {
                DISTRO_SUSE,
                "/etc/SuSE-release",
                "^[[:space:]]*SUSE LINUX ([[:digit:]]+\\.[[:digit:]]+)[[:space:]]+",
                1,
                -1,
                0
            },
            {
                DISTRO_OPENSUSE,
                "/etc/SuSE-release",
                "^[[:space:]]*openSUSE ([[:digit:]]+\\.[[:digit:]]+)[[:space:]]+",
                1,
                -1,
                0
            },
            {
                DISTRO_SLES,
                "/etc/SuSE-release",
                "^[[:space:]]*SUSE LINUX Enterprise Server ([[:digit:]]+( SP[[:digit:]]+)?)",
                1,
                -1,
                0
            },
            {
                DISTRO_SLED,
                "/etc/SuSE-release",
                "^[[:space:]]*SUSE LINUX Enterprise Desktop ([[:digit:]]+( SP[[:digit:]]+)?)",
                1,
                -1,
                0
            },
            {
                DISTRO_UBUNTU,
                "/etc/lsb-release",
                /*
                # The file will have lines that include:
                #   DISTRIB_ID=Ubuntu
                #   DISTRIB_RELEASE=6.06
                */
                "^[[:space:]]*DISTRIB_ID[[:space:]]*=[[:space:]]*Ubuntu[[:space:]]*\n"
                "(.*\n)?DISTRIB_RELEASE[[:space:]]*=[[:space:]]*(\\S+)[[:space:]]*(\n.*)?$",
                2,
                -1,
                1
            },
            {
                DISTRO_DEBIAN,
                "/etc/debian_version",
                /*
                # The format of the entire file is a single line like:
                # 3.1
                # and nothing else, so that is the version
                */
                "^[[:space:]]*(\\S+)[[:space:]]*$",
                1,
                -1,
                1
            },
        };
        int i;
        regmatch_t matches[20];
        info->distro = DISTRO_UNKNOWN;
        for(i = 0; info->distro == DISTRO_UNKNOWN; i++)
        {
            if(i == sizeof(distroSearch)/sizeof(distroSearch[0]))
            {
                //We past the last item in DistroSearch
                break;
            }
            GCE(ceError = CTAllocateStringPrintf(
                    &path, "%s%s", testPrefix, distroSearch[i].searchFile));
            GCE(ceError = CTCheckFileOrLinkExists(path, &exists));
            if(exists)
            {
                int flags = REG_EXTENDED;
                if(!distroSearch[i].compareCase)
                    flags |= REG_ICASE;

                GCE(ceError = CTReadFile(path, SIZE_MAX, &fileContents, NULL));
                if(regcomp(&rx, distroSearch[i].matchRegex, flags) != 0)
                {
                    GCE(ceError = LW_ERROR_REGEX_COMPILE_FAILED);
                }
                rxAlloced = TRUE;
                if(regexec(&rx, fileContents,
                        sizeof(matches)/sizeof(matches[0]), matches, 0) == 0 &&
                        matches[distroSearch[i].versionMatchNum].rm_so != -1)
                {
                    //This is the correct distro
                    regmatch_t *ver = &matches[distroSearch[i].versionMatchNum];
                    regmatch_t *update = &matches[distroSearch[i].updateMatchNum];
                    info->distro = distroSearch[i].matchDistro;
                    if (distroSearch[i].updateMatchNum == -1 ||
                            update->rm_so == -1)
                    {
                        GCE(ceError = CTStrndup(fileContents + ver->rm_so,
                                    ver->rm_eo - ver->rm_so,
                                    &info->version));
                    }
                    else
                    {
                        GCE(ceError = CTAllocateStringPrintf(
                                &info->version,
                                "%.*s.%.*s",
                                ver->rm_eo - ver->rm_so,
                                fileContents + ver->rm_so,
                                update->rm_eo - update->rm_so,
                                fileContents + update->rm_so));
                    }
                }
                regfree(&rx);
                rxAlloced = FALSE;
                CT_SAFE_FREE_STRING(fileContents);
            }
            CT_SAFE_FREE_STRING(path);
        }
        if(info->distro == DISTRO_DEBIAN)
        {
            /*
            #
            # Debian and Ubuntu both have /etc/debian_version,
            # but only Ubuntu has an /etc/lsb-release
            #
            */
            GCE(ceError = CTAllocateStringPrintf(
                    &path, "%s/etc/lsb-release", testPrefix));
            GCE(ceError = CTCheckFileOrLinkExists(path, &exists));
            if(exists)
            {
                // CT_LOG_ERROR("Unexpected file: %s", path);
                info->distro = DISTRO_UNKNOWN;
            }
            CT_SAFE_FREE_STRING(path);
        }
    }
    else
    {
        //It's a UNIX system
        switch(info->os)
        {
        case OS_AIX:
            info->distro = DISTRO_AIX;
            /*Uname output from AIX 5.3:
            $ uname -v
            5
            $ uname -r
            3
            */
            GCE(ceError = CTAllocateStringPrintf(&info->version,
                        "%s.%s", unameStruct.version, unameStruct.release));
            break;
        case OS_SUNOS:
            info->distro = DISTRO_SUNOS;
            /*Uname output from Solaris 8:
            $ uname -r
            5.8
            */
            GCE(ceError = CTAllocateStringPrintf(&info->version,
                        "%s", unameStruct.release));
            break;
        case OS_DARWIN:
            info->distro = DISTRO_DARWIN;
            ceError = CTGetPListVersion(&info->version);
            GCE(ceError);
            CTStripWhitespace(info->version);
            break;
        case OS_HPUX:
            info->distro = DISTRO_HPUX;
            {
                const char *temp = unameStruct.release;
                while(!isdigit((int)*temp)) temp++;
                GCE(ceError = CTStrdup(temp, &info->version));
            }
            break;
        case OS_FREEBSD:
            info->distro = DISTRO_FREEBSD;
            GCE(ceError = CTAllocateStringPrintf(&info->version,
                        "%s", unameStruct.release));
            break;
        default:
            info->distro = DISTRO_UNKNOWN;
        }
    }

    if(info->distro == DISTRO_UNKNOWN)
    {
        CT_SAFE_FREE_STRING(info->version);
        GCE(ceError = CTStrdup("unknown", &info->version));
    }

    //Check for version override file
    GCE(ceError = CTAllocateStringPrintf(
            &path, "%s/osver", testPrefix));
    GCE(ceError = CTCheckFileOrLinkExists(
            path, &exists));
    if(exists)
    {
        GCE(ceError = CTReadFile(
                path, SIZE_MAX, &fileContents, NULL));
    }
    if(fileContents != NULL)
    {
        CTStripWhitespace(fileContents);
        CT_SAFE_FREE_STRING(info->version);
        info->version = fileContents;
        fileContents = NULL;
    }
    CT_SAFE_FREE_STRING(path);

    /*
    uname -m output:
    Linux: x86_64
    Linux: i386
    Linux: i686
    AIX: 00CBE1DD4C00
    Solaris: sun4u
    Solaris: i86pc
    Darwin: i386
    Darwin: Power Macintosh
    HPUX: 9000/785

    uname -i output:
    Linux: x86_64
    Linux: i386
    RHEL21: not recogn
    AIX: not recogn
    Darwin: not recogn
    Solaris: SUNW,Ultra-4
    Solaris: i86pc
    HPUX: 2000365584

    uname -p output:
    Linux reads /proc/cpuinfo
    Linux: x86_64
    Linux: i686
    Linux: athlon
    Darwin: i386
    Darwin: powerpc
    AIX has the value hard coded in uname
    AIX: powerpc
    Solaris uses sysinfo(SI_ARCHITECTURE, buff, sizeof(buff)
    Solaris: sparc
    Solaris: i386
    HPUX: not recogn
    */
    info->arch = ARCH_UNKNOWN;
#if defined(HAVE_SYSINFO) && defined(SI_ARCHITECTURE)
    //Solaris has this
    if(info->arch == ARCH_UNKNOWN &&
            sysinfo(SI_ARCHITECTURE, archBuffer, sizeof(archBuffer)) != -1)
    {
        info->arch = CTGetArchFromString(archBuffer);
    }
#endif
#if defined(HAVE_SYSCONF) && defined(_SC_CPU_VERSION)
    //HPUX uses this
    if(info->arch == ARCH_UNKNOWN)
    {
        switch(sysconf(_SC_CPU_VERSION))
        {
            case CPU_PA_RISC1_0:
            case CPU_PA_RISC1_1:
            case CPU_PA_RISC1_2:
            case CPU_PA_RISC2_0:
            case CPU_PA_RISC_MAX:
                info->arch = ARCH_HPPA;
                break;
#ifdef CPU_HP_INTEL_EM_1_0
            case CPU_HP_INTEL_EM_1_0:
#endif
#ifdef CPU_IA64_ARCHREV_0
            case CPU_IA64_ARCHREV_0:
#endif
                info->arch = ARCH_IA64;
                break;
            //If it's not any of the previous values, let another test figure
            //it out.
        }
    }
#endif
    if(info->arch == ARCH_UNKNOWN)
    {
        //Linux uses this, and sometimes Darwin does too. If 'uname -m' doesn't
        //return something meaningful on this platform, then the arch will stay
        //as unknown.
        info->arch = CTGetArchFromString(unameStruct.machine);
    }
    if(info->arch == ARCH_UNKNOWN)
    {
        //AIX and sometimes Darwin use this
        GCE(ceError = CTCaptureOutput("uname -p", &distroString));
        CTStripWhitespace(distroString);
        info->arch = CTGetArchFromString(distroString);
        CT_SAFE_FREE_STRING(distroString);
    }

    //Check for arch override file
    GCE(ceError = CTAllocateStringPrintf(
            &path, "%s/osarch", testPrefix));
    GCE(ceError = CTCheckFileOrLinkExists(
            path, &exists));
    if(exists)
    {
        GCE(ceError = CTReadFile(
                path, SIZE_MAX, &fileContents, NULL));
        info->arch = CTGetArchFromString(fileContents);
        CT_SAFE_FREE_STRING(fileContents);
    }
    CT_SAFE_FREE_STRING(path);

cleanup:
    CT_SAFE_FREE_STRING(path);
    CT_SAFE_FREE_STRING(fileContents);
    CT_SAFE_FREE_STRING(distroString);
    if(rxAlloced)
        regfree(&rx);
    if(ceError)
    {
        CTFreeDistroInfo(info);
    }
    return ceError;
}