static DWORD ReadNsswitchFile(NsswitchConf *conf, const char *rootPrefix, const char *filename) { DWORD ceError = ERROR_SUCCESS; FILE *file = NULL; PSTR buffer = NULL; char *fullPath = NULL; BOOLEAN endOfFile = FALSE; BOOLEAN exists; if(rootPrefix == NULL) rootPrefix = ""; GCE(ceError = CTAllocateStringPrintf( &fullPath, "%s%s", rootPrefix, filename)); DJ_LOG_INFO("Reading nsswitch file %s", fullPath); GCE(ceError = CTCheckFileOrLinkExists(fullPath, &exists)); if(!exists) { DJ_LOG_INFO("File %s does not exist", fullPath); ceError = ERROR_FILE_NOT_FOUND; goto cleanup; } GCE(ceError = CTStrdup(filename, &conf->filename)); GCE(ceError = CTOpenFile(fullPath, "r", &file)); CT_SAFE_FREE_STRING(fullPath); while(TRUE) { CT_SAFE_FREE_STRING(buffer); GCE(ceError = CTReadNextLine(file, &buffer, &endOfFile)); if(endOfFile) break; GCE(ceError = AddFormattedLine(conf, filename, buffer, NULL)); } conf->modified = FALSE; cleanup: CT_SAFE_FREE_STRING(buffer); if(file != NULL) CTCloseFile(file); CT_SAFE_FREE_STRING(fullPath); if(ceError) FreeNsswitchConfContents(conf); return ceError; }
static DWORD ReadSshFile(struct SshConf *conf, const char *rootPrefix, const char *filename) { DWORD ceError = ERROR_SUCCESS; FILE *file = NULL; PSTR buffer = NULL; char *fullPath = NULL; BOOLEAN endOfFile = FALSE; BOOLEAN exists; BAIL_ON_CENTERIS_ERROR(ceError = CTAllocateStringPrintf( &fullPath, "%s%s", rootPrefix, filename)); DJ_LOG_INFO("Reading ssh file %s", fullPath); BAIL_ON_CENTERIS_ERROR(ceError = CTCheckFileOrLinkExists(fullPath, &exists)); if(!exists) { DJ_LOG_INFO("File %s does not exist", fullPath); ceError = ERROR_FILE_NOT_FOUND; goto error; } BAIL_ON_CENTERIS_ERROR(ceError = CTStrdup(filename, &conf->filename)); BAIL_ON_CENTERIS_ERROR(ceError = CTOpenFile(fullPath, "r", &file)); CT_SAFE_FREE_STRING(fullPath); while(TRUE) { CT_SAFE_FREE_STRING(buffer); BAIL_ON_CENTERIS_ERROR(ceError = CTReadNextLine(file, &buffer, &endOfFile)); if(endOfFile) break; BAIL_ON_CENTERIS_ERROR(ceError = AddFormattedLine(conf, filename, buffer, NULL)); } CT_SAFE_FREE_STRING(buffer); BAIL_ON_CENTERIS_ERROR(ceError = CTCloseFile(file)); file = NULL; return ceError; error: if(file != NULL) CTCloseFile(file); CT_SAFE_FREE_STRING(fullPath); FreeSshConfContents(conf); CT_SAFE_FREE_STRING(buffer); return ceError; }
static void ConfigureApparmor(BOOLEAN enable, LWException **exc) { DWORD ceError = ERROR_SUCCESS; BOOLEAN hasApparmor; BOOLEAN configured; BOOLEAN usingMr; FILE *file = NULL; PCSTR addString; PSTR restartPath = NULL; PSTR restartCommand = NULL; char *tempName = NULL; char *finalName = NULL; LW_CLEANUP_CTERR(exc, IsApparmorConfigured(&configured)); if(configured == enable) goto cleanup; LW_CLEANUP_CTERR(exc, CTCheckFileOrLinkExists(APPARMOR_NSSWITCH, &hasApparmor)); if(!hasApparmor) goto cleanup; GCE(ceError = CTGetFileTempPath( APPARMOR_NSSWITCH, &finalName, &tempName)); LW_CLEANUP_CTERR(exc, CTCheckFileHoldsPattern(finalName, "mr,", &usingMr)); if(usingMr) addString = PREFIXDIR "/lib/*.so* mr,\n" PREFIXDIR "/lib64/*.so* mr,\n" "/tmp/.lwidentity/pipe rw,\n" LOCALSTATEDIR "/lib/likewise/.lsassd rw,\n" LOCALSTATEDIR "/tmp/.lsaclient_* rw,\n"; else addString = PREFIXDIR "/lib/*.so* r,\n" PREFIXDIR "/lib64/*.so* r,\n" "/tmp/.lwidentity/pipe rw,\n" LOCALSTATEDIR "/lib/likewise/.lsassd rw,\n" LOCALSTATEDIR "/tmp/.lsaclient_* rw,\n"; if(enable) { LW_CLEANUP_CTERR(exc, CTCopyFileWithOriginalPerms(finalName, tempName)); LW_CLEANUP_CTERR(exc, CTOpenFile(tempName, "a", &file)); LW_CLEANUP_CTERR(exc, CTFilePrintf(file, "# likewise\n%s# end likewise\n", addString)); CTSafeCloseFile(&file); LW_CLEANUP_CTERR(exc, CTSafeReplaceFile(finalName, tempName)); } else { LW_CLEANUP_CTERR(exc, CTRunSedOnFile(finalName, finalName, FALSE, "/^[ \t]*#[ \t]*likewise[ \t]*$/,/^[ \t]*#[ \t]*end likewise[ \t]*$/d")); LW_CLEANUP_CTERR(exc, CTRunSedOnFile(finalName, finalName, FALSE, "/^[ \t]*#[ \t]*centeris[ \t]*$/,/^[ \t]*#[ \t]*end centeris[ \t]*$/d")); } ceError = CTFindFileInPath("rcapparmor", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", &restartPath); if(ceError == ERROR_FILE_NOT_FOUND) { ceError = CTFindFileInPath("apparmor", "/etc/init.d/apparmor", &restartPath); } if(ceError == ERROR_FILE_NOT_FOUND) { ceError = ERROR_SUCCESS; } else if(!ceError) { LW_CLEANUP_CTERR(exc, CTAllocateStringPrintf(&restartCommand, "%s restart", restartPath)); LW_TRY(exc, CTCaptureOutputToExc(restartCommand, &LW_EXC)); } LW_CLEANUP_CTERR(exc, ceError); cleanup: if(file != NULL) { CTCloseFile(file); CTRemoveFile(tempName); } CT_SAFE_FREE_STRING(restartPath); CT_SAFE_FREE_STRING(restartCommand); CT_SAFE_FREE_STRING(tempName); CT_SAFE_FREE_STRING(finalName); }
static DWORD HasApparmor(BOOLEAN *hasApparmor) { return CTCheckFileOrLinkExists(APPARMOR_NSSWITCH, hasApparmor); }
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; }
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; }
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; }
//Solaris and AIX should have this DWORD CTGetPidOfCmdLine( PCSTR programName, PCSTR programFilename, PCSTR cmdLine, uid_t owner, pid_t *pid, size_t *count ) { DWORD ceError = ERROR_NOT_SUPPORTED; size_t fillCount = 0; size_t foundCount = 0; struct stat findStat; DIR *dir = NULL; struct dirent *dirEntry = NULL; PSTR filePath = NULL; struct psinfo infoStruct; FILE *infoFile = NULL; struct stat compareStat; BOOLEAN bFileExists; #if defined(__LWI_SOLARIS__) int (*getzoneid)() = NULL; int zoneid = -1; #endif if(count) { fillCount = *count; *count = 0; } else if(pid != NULL) fillCount = 1; if(programFilename != NULL) { while(stat(programFilename, &findStat) < 0) { if(errno == EINTR) continue; GCE(ceError = LwMapErrnoToLwError(errno)); } } if ((dir = opendir("/proc")) == NULL) { GCE(ceError = LwMapErrnoToLwError(errno)); } #if defined(__LWI_SOLARIS__) getzoneid = dlsym(RTLD_DEFAULT, "getzoneid"); if (getzoneid) { zoneid = getzoneid(); } #endif while(1) { errno = 0; dirEntry = readdir(dir); if(dirEntry == NULL) { if(errno != 0) GCE(ceError = LwMapErrnoToLwError(errno)); else { //No error here. We simply read the last entry break; } } if(dirEntry->d_name[0] == '.') continue; // On AIX, there is a /proc/sys which does not contain a psinfo if(!isdigit((int)dirEntry->d_name[0])) continue; CT_SAFE_FREE_STRING(filePath); GCE(ceError = CTAllocateStringPrintf(&filePath, "/proc/%s/psinfo", dirEntry->d_name)); GCE(ceError = CTCheckFileOrLinkExists(filePath, &bFileExists)); if(!bFileExists) { // On AIX 6.1, a defunct process can lack a psinfo file. continue; } GCE(ceError = CTSafeCloseFile(&infoFile)); GCE(ceError = CTOpenFile(filePath, "r", &infoFile)); if(fread(&infoStruct, sizeof(infoStruct), 1, infoFile) != 1) { GCE(ceError = LwMapErrnoToLwError(errno)); } #if defined(__LWI_SOLARIS__) if (zoneid != -1) { int processzoneid = -1; #ifdef HAVE_STRUCT_PSINFO_PR_ZONEID processzoneid = (int) infoStruct.pr_zoneid; #else processzoneid = (int) *(infoStruct.pr_filler + sizeof(infoStruct.pr_filler)/sizeof(infoStruct.pr_filler[0]) - 3); #endif if (zoneid != processzoneid) { continue; } } #endif if (owner != (uid_t)-1 && owner != infoStruct.pr_euid) { continue; } if (programName != NULL && strcmp(infoStruct.pr_fname, programName)) { continue; } if (cmdLine != NULL && strcmp(infoStruct.pr_psargs, cmdLine)) { continue; } if(programFilename != NULL) { CT_SAFE_FREE_STRING(filePath); GCE(ceError = CTAllocateStringPrintf(&filePath, "/proc/%s/object/a.out", dirEntry->d_name)); while(stat(filePath, &compareStat) < 0) { if(errno == EINTR) continue; if(errno == ENOENT || errno == ENOTDIR) { //This process wasn't executed from a file? goto not_match; } GCE(ceError = LwMapErrnoToLwError(errno)); } if(findStat.st_ino != compareStat.st_ino) continue; if(findStat.st_dev != compareStat.st_dev) continue; if(findStat.st_rdev != compareStat.st_rdev) continue; } //This is a match if(foundCount < fillCount) pid[foundCount] = infoStruct.pr_pid; foundCount++; not_match: ; } if(count) *count = foundCount; else if(!ceError && foundCount == 0) ceError = ERROR_PROC_NOT_FOUND; cleanup: if(dir != NULL) closedir(dir); CT_SAFE_FREE_STRING(filePath); CTSafeCloseFile(&infoFile); return ceError; }
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; }
DWORD CTGetPidOfCmdLine( PCSTR programName, PCSTR programFilename, PCSTR cmdLine, uid_t owner, pid_t *pid, size_t *count ) { DWORD ceError = ERROR_NOT_SUPPORTED; size_t fillCount = 0; size_t foundCount = 0; struct stat findStat; #if HAVE_DECL_PSTAT_GETPROC //HPUX should have this struct pst_status mystatus; struct pst_status status[10]; int inBuffer; int i; #endif #ifdef HAVE_STRUCT_PSINFO //Solaris and AIX should have this DIR *dir = NULL; struct dirent *dirEntry = NULL; PSTR filePath = NULL; struct psinfo infoStruct; FILE *infoFile = NULL; struct stat compareStat; BOOLEAN bFileExists; #endif #if defined(HAVE_KVM_GETPROCS) && HAVE_DECL_KERN_PROC_PATHNAME //FreeBSD has this char pathBuffer[MAXPATHLEN]; size_t len; int unfilteredCount; kvm_t *kd = NULL; struct kinfo_proc *procs; int i; struct kinfo_proc *pos; int sysctlName[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, 0 }; #endif if(count) { fillCount = *count; *count = 0; } else if(pid != NULL) fillCount = 1; if(programFilename != NULL) { while(stat(programFilename, &findStat) < 0) { if(errno == EINTR) continue; GCE(ceError = LwMapErrnoToLwError(errno)); } } #if HAVE_DECL_PSTAT_GETPROC //First get the process info for this process inBuffer = pstat_getproc(&mystatus, sizeof(mystatus), 0, getpid()); if(inBuffer != 1) GCE(ceError = LwMapErrnoToLwError(errno)); //Now look at all processes inBuffer = pstat_getproc(status, sizeof(status[0]), sizeof(status)/sizeof(status[0]), 0); if(inBuffer < 0) GCE(ceError = LwMapErrnoToLwError(errno)); while(inBuffer > 0) { for(i = 0; i < inBuffer; i++) { if(memcmp(&mystatus.pst_rdir, &status[i].pst_rdir, sizeof(mystatus.pst_rdir))) { /* This process has a different root directory (it is being run via a chroot). Let's not count this process as a match. */ continue; } if (owner != (uid_t)-1 && owner != status[i].pst_euid) { continue; } if (programName != NULL && strcmp(status[i].pst_ucomm, programName)) { continue; } if (cmdLine != NULL && strcmp(status[i].pst_cmd, cmdLine)) { continue; } if(programFilename != NULL && ( status[i].pst_text.psf_fileid != findStat.st_ino || status[i].pst_text.psf_fsid.psfs_id != findStat.st_dev || status[i].pst_text.psf_fsid.psfs_type != findStat.st_fstype )) { continue; } //This is a match if(foundCount < fillCount) pid[foundCount] = status[i].pst_pid; foundCount++; } //Continue looking at the process list where we left off inBuffer = pstat_getproc(status, sizeof(status[0]), sizeof(status)/sizeof(status[0]), status[inBuffer - 1].pst_idx + 1); if(inBuffer < 0) GCE(ceError = LwMapErrnoToLwError(errno)); } ceError = ERROR_SUCCESS; #endif #ifdef HAVE_STRUCT_PSINFO if ((dir = opendir("/proc")) == NULL) { GCE(ceError = LwMapErrnoToLwError(errno)); } while(1) { errno = 0; dirEntry = readdir(dir); if(dirEntry == NULL) { if(errno != 0) GCE(ceError = LwMapErrnoToLwError(errno)); else { //No error here. We simply read the last entry break; } } if(dirEntry->d_name[0] == '.') continue; // On AIX, there is a /proc/sys which does not contain a psinfo if(!isdigit((int)dirEntry->d_name[0])) continue; CT_SAFE_FREE_STRING(filePath); GCE(ceError = CTAllocateStringPrintf(&filePath, "/proc/%s/psinfo", dirEntry->d_name)); GCE(ceError = CTCheckFileOrLinkExists(filePath, &bFileExists)); if(!bFileExists) { // On AIX 6.1, a defunct process can lack a psinfo file. continue; } GCE(ceError = CTSafeCloseFile(&infoFile)); GCE(ceError = CTOpenFile(filePath, "r", &infoFile)); if(fread(&infoStruct, sizeof(infoStruct), 1, infoFile) != 1) { GCE(ceError = LwMapErrnoToLwError(errno)); } if (owner != (uid_t)-1 && owner != infoStruct.pr_euid) { continue; } if (programName != NULL && strcmp(infoStruct.pr_fname, programName)) { continue; } if (cmdLine != NULL && strcmp(infoStruct.pr_psargs, cmdLine)) { continue; } if(programFilename != NULL) { CT_SAFE_FREE_STRING(filePath); GCE(ceError = CTAllocateStringPrintf(&filePath, "/proc/%s/object/a.out", dirEntry->d_name)); while(stat(filePath, &compareStat) < 0) { if(errno == EINTR) continue; if(errno == ENOENT || errno == ENOTDIR) { //This process wasn't executed from a file? goto not_match; } GCE(ceError = LwMapErrnoToLwError(errno)); } if(findStat.st_ino != compareStat.st_ino) continue; if(findStat.st_dev != compareStat.st_dev) continue; if(findStat.st_rdev != compareStat.st_rdev) continue; } //This is a match if(foundCount < fillCount) pid[foundCount] = infoStruct.pr_pid; foundCount++; not_match: ; } #endif #if defined(HAVE_KVM_GETPROCS) && HAVE_DECL_KERN_PROC_PATHNAME kd = kvm_open(NULL, "/dev/null", NULL, O_RDONLY, NULL); if (kd == NULL) GCE(ceError = DWORD_ACCESS_DENIED); procs = kvm_getprocs(kd, KERN_PROC_PROC, 0, &unfilteredCount); if (procs == NULL) GCE(ceError = DWORD_ACCESS_DENIED); pos = procs; for(i = 0; i < unfilteredCount; i++, pos = (struct kinfo_proc *)((char *)pos + pos->ki_structsize)) { if (owner != (uid_t)-1 && owner != pos->ki_uid) { continue; } if (programName != NULL && strcmp(pos->ki_comm, programName)) { continue; } if (cmdLine != NULL) { char **args = kvm_getargv(kd, pos, 0); char **argPos = args; PCSTR cmdLinePos = cmdLine; while (*cmdLinePos != '\0') { if (argPos == NULL || *argPos == NULL) break; if (strncmp(cmdLinePos, *argPos, strlen(*argPos))) break; cmdLinePos += strlen(*argPos); argPos++; if(cmdLinePos[0] == ' ') cmdLinePos++; } if(*cmdLinePos != '\0' || (argPos != NULL && *argPos != NULL)) { //not a match continue; } } if (programFilename != NULL) { pathBuffer[0] = '\0'; if (pos->ki_textvp != NULL) { sysctlName[3] = pos->ki_pid; len = sizeof(pathBuffer); if( sysctl(sysctlName, 4, pathBuffer, &len, NULL, 0) < 0) { /* If the executable path does not exist (e.g. because the file was deleted after the program started), move on */ if (errno == ENOENT) continue; GCE(ceError = LwMapErrnoToLwError(errno)); } } if(strcmp(programFilename, pathBuffer)) continue; } //This is a match if(foundCount < fillCount) pid[foundCount] = pos->ki_pid; foundCount++; } ceError = ERROR_SUCCESS; #endif if(count) *count = foundCount; else if(!ceError && foundCount == 0) ceError = ERROR_PROC_NOT_FOUND; cleanup: #ifdef HAVE_STRUCT_PSINFO if(dir != NULL) closedir(dir); CT_SAFE_FREE_STRING(filePath); CTSafeCloseFile(&infoFile); #endif #if defined(HAVE_KVM_GETPROCS) && HAVE_DECL_KERN_PROC_PATHNAME if(kd != NULL) { kvm_close(kd); } #endif return ceError; }