static DWORD AddFormattedLine(struct SshConf *conf, const char *filename, const char *linestr, const char **endptr) { DWORD ceError = ERROR_SUCCESS; struct SshLine lineObj; const char *pos = linestr; const char *token_start = NULL; memset(&lineObj, 0, sizeof(lineObj)); /* Find the leading whitespace in the line */ token_start = pos; while(isblank(*pos)) pos++; BAIL_ON_CENTERIS_ERROR(ceError = CTStrndup(token_start, pos - token_start, &lineObj.leadingWhiteSpace)); /* Find the option name in the line */ token_start = pos; while(!isspace((int)*pos) && *pos != '\0' && *pos != '#') { pos++; } BAIL_ON_CENTERIS_ERROR(ceError = CTStrndup(token_start, pos - token_start, &lineObj.name.value)); /* Find the blank space separating the option name and option value */ token_start = pos; while(isblank(*pos)) pos++; BAIL_ON_CENTERIS_ERROR(ceError = CTStrndup(token_start, pos - token_start, &lineObj.name.trailingSeparator)); /* Find the option value */ token_start = pos; //This token can contain spaces and tabs while(*pos != '\0' && *pos != '#' && *pos != '\n' && *pos != '\r') pos++; //But not at the end, so trim off the trailing white space while(pos > token_start && isblank(pos[-1])) pos--; BAIL_ON_CENTERIS_ERROR(ceError = CTStrndup(token_start, pos - token_start, &lineObj.value.value)); /* Find the line's trailing whitespace and comment */ token_start = pos; while(*pos != '\0' && *pos != '\n' && *pos != '\r') pos++; BAIL_ON_CENTERIS_ERROR(ceError = CTStrndup(token_start, pos - token_start, &lineObj.value.trailingSeparator)); BAIL_ON_CENTERIS_ERROR(ceError = CTArrayAppend(&conf->private_data, sizeof(lineObj), &lineObj, 1)); memset(&lineObj, 0, sizeof(lineObj)); UpdatePublicLines(conf); if(endptr != NULL) *endptr = pos; conf->modified = 1; error: FreeSshLineContents(&lineObj); return ceError; }
static DWORD AddFormattedLine(NsswitchConf *conf, const char *filename, const char *linestr, const char **endptr) { DWORD ceError = ERROR_SUCCESS; NsswitchEntry lineObj; const char *pos = linestr; const char *token_start = NULL; CTParseToken token; memset(&lineObj, 0, sizeof(lineObj)); memset(&token, 0, sizeof(token)); /* Find the leading whitespace in the line */ token_start = pos; while(isblank(*pos)) pos++; GCE(ceError = CTStrndup(token_start, pos - token_start, &lineObj.leadingWhiteSpace)); /* Read the name of the entry and attach its trailing : or = */ GCE(ceError = CTReadToken(&pos, &lineObj.name, "=: \t", ";#\r\n", "")); /* Create an array of the modules for this entry */ while(strchr("\r\n;#", *pos) == NULL) { GCE(ceError = CTReadToken(&pos, &token, ", \t", ";#\r\n", "")); GCE(ceError = CTArrayAppend(&lineObj.modules, sizeof(CTParseToken), &token, 1)); memset(&token, 0, sizeof(token)); } /*Read the comment, if there is one*/ token_start = pos; while(strchr("\r\n", *pos) == NULL) pos++; if(pos != token_start) GCE(ceError = CTStrndup(token_start, pos - token_start, &lineObj.comment)); GCE(ceError = CTArrayAppend(&conf->lines, sizeof(lineObj), &lineObj, 1)); memset(&lineObj, 0, sizeof(lineObj)); if(endptr != NULL) *endptr = pos; cleanup: FreeNsswitchEntryContents(&lineObj); CTFreeParseTokenContents(&token); return ceError; }
DWORD CTReadToken(const char **pos, CTParseToken *store, const char *includeSeparators, const char *excludeSeparators, const char *trimBack) { DWORD ceError = ERROR_SUCCESS; char const * token_start = *pos; char const * white_start, * white_end; memset(store, 0, sizeof(*store)); while(**pos != '\0' && strchr(includeSeparators, **pos) == NULL && strchr(excludeSeparators, **pos) == NULL) { (*pos)++; } white_start = *pos; while (**pos != '\0' && strchr(includeSeparators, **pos) != NULL) { (*pos)++; } white_end = *pos; while (white_start > token_start && white_start[-1] != '\0' && strchr(trimBack, white_start[-1]) != NULL) { white_start--; } if(token_start != white_start) { ceError = CTStrndup(token_start, white_start - token_start, &store->value); BAIL_ON_CENTERIS_ERROR(ceError); } if(white_start != white_end) { ceError = CTStrndup(white_start, white_end - white_start, &store->trailingSeparator); BAIL_ON_CENTERIS_ERROR(ceError); } error: if (ceError) CTFreeParseTokenContents(store); 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; }