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; }
static void GetSshVersion(PCSTR rootPrefix, SshdVersion *version, PCSTR binaryPath, LWException **exc) { DWORD ceError = ERROR_SUCCESS; PSTR command = NULL; PSTR commandOutput = NULL; PCSTR versionStart; PSTR intEnd; version->isOpenSsh = FALSE; version->major = -1; version->minor = -1; version->secondMinor = -1; version->patch = -1; if(rootPrefix == NULL) rootPrefix = ""; LW_CLEANUP_CTERR(exc, CTAllocateStringPrintf( &command, "%s%s -v 2>&1", rootPrefix, binaryPath)); ceError = CTCaptureOutput(command, &commandOutput); if(ceError == ERROR_BAD_COMMAND) ceError = ERROR_SUCCESS; LW_CLEANUP_CTERR(exc, ceError); // The version string is in the form OpenSSH_4.6p1 // or OpenSSH_3.6.1p1 versionStart = strstr(commandOutput, "OpenSSH_"); if(versionStart == NULL) { goto cleanup; } version->isOpenSsh = TRUE; versionStart += strlen("OpenSSH_"); version->major = strtoul(versionStart, &intEnd, 10); if(intEnd == versionStart) version->major = -1; if(intEnd == NULL || *intEnd != '.') goto cleanup; versionStart = intEnd + 1; version->minor = strtoul(versionStart, &intEnd, 10); if(intEnd == versionStart) version->minor = -1; if(intEnd == NULL || (*intEnd != '.' && *intEnd != 'p')) goto cleanup; versionStart = intEnd + 1; if(*intEnd == '.') { version->secondMinor = strtoul(versionStart, &intEnd, 10); if(intEnd == versionStart) version->secondMinor = -1; if(intEnd == NULL || *intEnd != 'p') goto cleanup; versionStart = intEnd + 1; } version->patch = strtoul(versionStart, &intEnd, 10); if(intEnd == versionStart) version->patch = -1; cleanup: if(version->isOpenSsh) { DJ_LOG_INFO("Found open sshd version %d.%d.%dp%d", version->major, version->minor, version->secondMinor, version->patch); } else { DJ_LOG_INFO("Found non-openssh version of ssh"); } CT_SAFE_FREE_STRING(command); CT_SAFE_FREE_STRING(commandOutput); }
static BOOLEAN TestOption(PCSTR rootPrefix, struct SshConf *conf, PCSTR binary, PCSTR testFlag, PCSTR optionName, LWException **exc) { DWORD ceError = ERROR_SUCCESS; BOOLEAN result = FALSE; PSTR command = NULL; PSTR commandOutput = NULL; int existingLine; if(rootPrefix == NULL) rootPrefix = ""; DJ_LOG_INFO("Testing option %s", optionName); existingLine = FindOption(conf, 0, optionName); if(existingLine != -1) { if(!strcmp(conf->lines[existingLine].value.value, "yes")) { //The option is already enabled, so it must be supported result = TRUE; goto cleanup; } } /* Most versions of sshd support the -t option which runs it in test mode. Test mode is used to verify that a config file is correct, or in our case that the passed options are valid. The only version of sshd known to not support -t is the version that comes with Solaris 9. However, this version does not support the -o option, and it will error out if the -o option is used. The Solaris 9 version of sshd does not support any of the options we'd like to enable, so it will correctly fail all of the option tests. Sshd will either complain about the first invalid option that is passed with -o, or it will complain about all invalid options. -o BadOption=yes is passed to verify that sshd understands -o, and to make doubly sure that it will not start listening on a port. The -v option can be used to test whether ssh (the client) supports given options. Passing -v to ssh will cause it to print out its version number and not attempt to connect to a machine. All versions of ssh seem to parse the options passed with -o even when -v is passed. Ssh will either complain about the first invalid option that is passed with -o, or it will complain about all invalid options. -o BadOption=yes is passed to verify that ssh understands -o. */ LW_CLEANUP_CTERR(exc, CTAllocateStringPrintf( &command, "%s%s %s -o %s=yes -o BadOption=yes 2>&1", rootPrefix, binary, testFlag, optionName)); ceError = CTCaptureOutput(command, &commandOutput); /* Some versions of sshd will return an error code because an invalid option was passed, but not all will. */ if(ceError == ERROR_BAD_COMMAND) ceError = ERROR_SUCCESS; LW_CLEANUP_CTERR(exc, ceError); if(strstr(commandOutput, optionName) != NULL) { DJ_LOG_INFO("Option %s not supported", optionName); goto cleanup; } if(strstr(commandOutput, "BadOption") == NULL) { DJ_LOG_INFO("Sshd does not support -o"); goto cleanup; } DJ_LOG_INFO("Option %s supported", optionName); result = TRUE; cleanup: CT_SAFE_FREE_STRING(command); CT_SAFE_FREE_STRING(commandOutput); return result; }
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; }
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; }
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; }