static DWORD IsApparmorConfigured(BOOLEAN *configured) { DWORD ceError = ERROR_SUCCESS; BOOLEAN hasApparmor; *configured = FALSE; GCE(ceError = HasApparmor(&hasApparmor)); if(hasApparmor) { GCE(ceError = CTCheckFileHoldsPattern(APPARMOR_NSSWITCH, "centeris", configured)); if(!*configured) { GCE(ceError = CTCheckFileHoldsPattern(APPARMOR_NSSWITCH, "likewise", configured)); } } else { *configured = TRUE; } cleanup: return ceError; }
DWORD DJGetFinalFqdn( const JoinProcessOptions *options, PSTR *fqdn ) { DWORD ceError = ERROR_SUCCESS; const ModuleState *state = DJGetModuleStateByName((JoinProcessOptions *)options, "hostname"); *fqdn = NULL; if(state != NULL && state->disposition == EnableModule) { //The fqdn will be set ceError = CTAllocateStringPrintf(fqdn, "%s.%s", options->computerName, options->domainName); GCE(ceError); } else { //The fqdn will not be set GCE(ceError = DJGetFQDN(NULL, fqdn)); } cleanup: return ceError; }
DWORD LWPrintException(FILE *dest, const LWException *print, BOOLEAN showTrace) { DWORD ceError = ERROR_SUCCESS; PSTR string = NULL; PSTR wrapped = NULL; int columns; ceError = LWExceptionToString(print, "Error: ", FALSE, showTrace, &string); GCE(ceError); //Don't word wrap if the terminal width can't be determined if (CTGetTerminalWidth(fileno(dest), &columns)) columns = -1; ceError = CTWordWrap(string, &wrapped, 4, columns); GCE(ceError); fprintf(dest, "%s\n", wrapped); cleanup: if(ceError) { fprintf(dest, "Error %x occurred while trying to print exception\n", ceError); } CT_SAFE_FREE_STRING(string); CT_SAFE_FREE_STRING(wrapped); return ceError; }
DWORD LWExceptionToString(const LWException *conv, PCSTR titlePrefix, BOOLEAN showSymbolicCode, BOOLEAN showTrace, PSTR *result) { DWORD ceError; PSTR ret = NULL; PSTR temp = NULL; PCSTR codeName = NULL; if(titlePrefix == NULL) titlePrefix = ""; if(showSymbolicCode) codeName = LwWin32ExtErrorToName(conv->code); if(codeName != NULL) { GCE(ceError = CTAllocateStringPrintf( &ret, "%s%s [%s]\n\n%s", titlePrefix, conv->shortMsg, codeName, conv->longMsg)); } else { GCE(ceError = CTAllocateStringPrintf( &ret, "%s%s [code 0x%.8x]\n\n%s", titlePrefix, conv->shortMsg, conv->code, conv->longMsg)); } if(showTrace) { const LWStackFrame *frame = &conv->stack; temp = ret; GCE(ceError = CTAllocateStringPrintf( &ret, "%s\n\nStack Trace:", temp)); CT_SAFE_FREE_STRING(temp); while(frame != NULL) { temp = ret; GCE(ceError = CTAllocateStringPrintf( &ret, "%s\n%s:%d", temp, frame->file, frame->line)); CT_SAFE_FREE_STRING(temp); frame = frame->down; } } *result = ret; ret = NULL; cleanup: CT_SAFE_FREE_STRING(temp); CT_SAFE_FREE_STRING(ret); return ceError; }
static DWORD RemoveModule(NsswitchConf *conf, int line, int moduleIndex) { DWORD ceError = ERROR_SUCCESS; NsswitchEntry *lineObj = (NsswitchEntry *)GetEntry(conf, line); CTParseToken *beforeModule = NULL, *afterModule = NULL; CTParseToken *removeModule; removeModule = (CTParseToken *)lineObj->modules.data + moduleIndex; if(moduleIndex - 1 >= 0) beforeModule = (CTParseToken *)lineObj->modules.data + moduleIndex - 1; if(moduleIndex + 1 < lineObj->modules.size) afterModule = (CTParseToken *)lineObj->modules.data + moduleIndex + 1; if(afterModule == NULL && beforeModule != NULL) { /* Since the last module is being removed, move the trailingSeparator * to the previous module */ CT_SAFE_FREE_STRING(beforeModule->trailingSeparator); beforeModule->trailingSeparator = removeModule->trailingSeparator; removeModule->trailingSeparator = NULL; } CTFreeParseTokenContents(removeModule); GCE(ceError = CTArrayRemove(&lineObj->modules, moduleIndex, sizeof(CTParseToken), 1)); conf->modified = 1; cleanup: return ceError; }
DWORD DJConfigureNameServiceSwitch(const char *testPrefix, BOOLEAN enable) { DWORD ceError = ERROR_SUCCESS; NsswitchConf conf; if(testPrefix == NULL) testPrefix = ""; ceError = ReadNsswitchConf(&conf, testPrefix, TRUE); if(ceError == ERROR_FILE_NOT_FOUND) { ceError = ERROR_SUCCESS; DJ_LOG_WARNING("Warning: Could not find nsswitch file"); goto cleanup; } GCE(ceError); ceError = UpdateNsswitchConf(&conf, enable); if(conf.modified) WriteNsswitchConfiguration(testPrefix, &conf); else DJ_LOG_INFO("nsswitch not modified"); cleanup: FreeNsswitchConfContents(&conf); return ceError; }
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; }
static DWORD RemoveLine(NsswitchConf *conf, int line) { DWORD ceError = ERROR_SUCCESS; NsswitchEntry *lineObj = (NsswitchEntry *)GetEntry(conf, line); if(lineObj == NULL) { GCE(ceError = ERROR_INVALID_PARAMETER); } FreeNsswitchEntryContents(lineObj); GCE(ceError = CTArrayRemove(&conf->lines, line, sizeof(NsswitchEntry), 1)); conf->modified = 1; cleanup: return ceError; }
static DWORD AddEntry(NsswitchConf *conf, const DistroInfo *distro, int *addedIndex, const char *name) { DWORD ceError = ERROR_SUCCESS; int line = -1; NsswitchEntry lineObj; const NsswitchEntry *copy; memset(&lineObj, 0, sizeof(lineObj)); GCE(ceError = CTStrdup(name, &lineObj.name.value)); for(line = 0; line < conf->lines.size; line++) { copy = GetEntry(conf, line); if(copy->name.value != NULL) { GCE(ceError = CTStrdup(copy->name.trailingSeparator, &lineObj.name.trailingSeparator)); break; } } if(lineObj.name.trailingSeparator == NULL) { //Couldn't find an existing line to copy the separator from. We'll //have to guess based on the OS if(distro->os == OS_AIX) GCE(ceError = CTStrdup(" = ", &lineObj.name.trailingSeparator)); else GCE(ceError = CTStrdup(": ", &lineObj.name.trailingSeparator)); } GCE(ceError = CTArrayAppend(&conf->lines, sizeof(NsswitchEntry), &lineObj, 1)); memset(&lineObj, 0, sizeof(lineObj)); conf->modified = 1; if(addedIndex != NULL) *addedIndex = conf->lines.size - 1; cleanup: FreeNsswitchEntryContents(&lineObj); return ceError; }
//Does the platform-specific equivalent of this in nsswitch.conf: // hosts: files dns DWORD DJConfigureHostsEntry(const char *testPrefix) { DWORD ceError = ERROR_SUCCESS; NsswitchConf conf; DistroInfo distro; int line; const char *hostsByFile; const char *hostsByDns; int moduleIndex; if(testPrefix == NULL) testPrefix = ""; memset(&distro, 0, sizeof(distro)); memset(&conf, 0, sizeof(conf)); GCE(ceError = DJGetDistroInfo(testPrefix, &distro)); ceError = ReadNsswitchConf(&conf, testPrefix, TRUE); GCE(ceError); hostsByFile = GetNameOfHostsByFile(&conf, &distro); hostsByDns = GetNameOfHostsByDns(&conf, &distro); line = FindEntry(&conf, 0, "hosts"); if(line == -1) { DJ_LOG_INFO("Adding hosts line"); GCE(ceError = AddEntry(&conf, &distro, &line, "hosts")); GCE(ceError = InsertModule(&conf, &distro, line, 0, hostsByDns)); GCE(ceError = InsertModule(&conf, &distro, line, 0, hostsByFile)); } moduleIndex = FindModuleOnLine(&conf, line, hostsByFile); if(moduleIndex > 0) { /* The local module exists on the line, but it is not the first * entry. */ GCE(ceError = RemoveModule(&conf, line, moduleIndex)); } if(moduleIndex != 0) { GCE(ceError = InsertModule(&conf, &distro, line, 0, hostsByFile)); } if(conf.modified) WriteNsswitchConfiguration(testPrefix, &conf); else DJ_LOG_INFO("nsswitch not modified"); cleanup: FreeNsswitchConfContents(&conf); DJFreeDistroInfo(&distro); return ceError; }
static DWORD GetPstrFromStringRef( CFStringRef pIn, PSTR *ppOut ) { size_t len = 0; PSTR pOut = NULL; DWORD error = 0; len = CFStringGetMaximumSizeForEncoding( CFStringGetLength(pIn), CFStringGetSystemEncoding()); error = LwAllocateMemory( len + 1, (PVOID*)&pOut); GCE(error); if (!CFStringGetCString( pIn, pOut, len + 1, CFStringGetSystemEncoding())) { error = ERROR_ILLEGAL_CHARACTER; GCE(error); } *ppOut = pOut; cleanup: if (error) { LW_SAFE_FREE_STRING(pOut); } return error; }
DWORD DJSetOptionValue(DynamicArray *lines, PCSTR stanza, PCSTR name, PCSTR value) { ssize_t index; PSTR newLine = NULL; DWORD ceError = ERROR_SUCCESS; if(strchr(value, ' ')) { /* Fixes bug 5564 */ GCE(ceError = CTAllocateStringPrintf(&newLine, "\t%s = \"%s\"\n", name, value)); } else GCE(ceError = CTAllocateStringPrintf(&newLine, "\t%s = %s\n", name, value)); index = DJFindLine(lines, stanza, name); if(index == -1) { index = DJFindStanza(lines, stanza); if(index == -1) GCE(ceError = ERROR_INVALID_OPERATION); index++; } else { CT_SAFE_FREE_STRING(*(PSTR *)CTArrayGetItem((DynamicArray*)lines, index, sizeof(PSTR))); GCE(ceError = CTArrayRemove((DynamicArray *)lines, index, sizeof(PSTR), 1)); } GCE(ceError = CTArrayInsert((DynamicArray *)lines, index, sizeof(PSTR), &newLine, 1)); cleanup: return ceError; }
static DWORD WriteNsswitchConfiguration(const char *rootPrefix, NsswitchConf *conf) { DWORD ceError = ERROR_SUCCESS; DynamicArray printedLine; int i; char *tempName = NULL; char *finalName = NULL; char *prefixedPath = NULL; FILE *file = NULL; memset(&printedLine, 0, sizeof(printedLine)); GCE(ceError = CTAllocateStringPrintf(&prefixedPath, "%s%s", rootPrefix, conf->filename)); GCE(ceError = CTGetFileTempPath( prefixedPath, &finalName, &tempName)); DJ_LOG_INFO("Writing nsswitch configuration for %s", finalName); ceError = CTOpenFile(tempName, "w", &file); if(ceError) { DJ_LOG_ERROR("Unable to open '%s' for writing", tempName); GCE(ceError); } for(i = 0; i < conf->lines.size; i++) { GCE(ceError = GetPrintedLine(&printedLine, conf, i)); GCE(ceError = CTFilePrintf(file, "%s\n", printedLine.data)); } GCE(ceError = CTCloseFile(file)); file = NULL; GCE(ceError = CTSafeReplaceFile( finalName, tempName)); DJ_LOG_INFO("File moved into place"); cleanup: if(file != NULL) CTCloseFile(file); CTArrayFree(&printedLine); CT_SAFE_FREE_STRING(tempName); CT_SAFE_FREE_STRING(finalName); CT_SAFE_FREE_STRING(prefixedPath); return ceError; }
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 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; }
/* Get the printed form of a line from the parsed form by concatenating all of the strings together */ static DWORD GetPrintedLine(DynamicArray *dest, NsswitchConf *conf, int line) { DWORD ceError = ERROR_SUCCESS; size_t len = 0; char *pos; int i; const NsswitchEntry *lineObj = GetEntry(conf, line); len += CTGetTokenLen(&lineObj->name); for(i = 0; i < lineObj->modules.size; i++) { len += CTGetTokenLen(&((CTParseToken *)lineObj->modules.data)[i]); } if(lineObj->comment != NULL) len += strlen(lineObj->comment); //For the terminating NULL len++; if(len > dest->capacity) GCE(ceError = CTSetCapacity(dest, 1, len)); pos = dest->data; CTAppendTokenString(&pos, &lineObj->name); for(i = 0; i < lineObj->modules.size; i++) { CTAppendTokenString(&pos, &((CTParseToken *)lineObj->modules.data)[i]); } if(lineObj->comment != NULL) { memcpy(pos, lineObj->comment, strlen(lineObj->comment)); pos += strlen(lineObj->comment); } *pos = '\0'; dest->size = len; cleanup: return ceError; }
DWORD DJFixLoginConfigFile( PCSTR pszPath ) { DWORD ceError = ERROR_SUCCESS; PCSTR pszFilePath = NULL; PSTR pszTmpPath = NULL; PSTR pszFinalPath = NULL; BOOLEAN bFileExists = FALSE; FILE* fp = NULL; FILE* fp_new = NULL; DynamicArray lines; PSTR currentSystem = NULL; memset(&lines, 0, sizeof(lines)); if (IsNullOrEmptyString(pszPath)) pszFilePath = LOGIN_CONFIG_PATH; else pszFilePath = pszPath; GCE(ceError = CTGetFileTempPath( pszFilePath, &pszFinalPath, &pszTmpPath)); GCE(ceError = CTCheckFileExists(pszFinalPath, &bFileExists)); if (!bFileExists) goto cleanup; GCE(ceError = CTOpenFile(pszFinalPath, "r", &fp)); GCE(ceError = CTReadLines(fp, &lines)); GCE(ceError = CTSafeCloseFile(&fp)); GCE(ceError = GetAuthType(&lines, ¤tSystem)); if(!strcmp(currentSystem, "PAM_AUTH")) goto cleanup; GCE(ceError = SetAuthType(&lines, "PAM_AUTH")); GCE(ceError = CTOpenFile(pszTmpPath, "w", &fp_new)); GCE(ceError = CTWriteLines(fp_new, &lines)); GCE(ceError = CTSafeCloseFile(&fp_new)); GCE(ceError = CTSafeReplaceFile(pszFilePath, pszTmpPath)); cleanup: CTSafeCloseFile(&fp); CTSafeCloseFile(&fp_new); CT_SAFE_FREE_STRING(currentSystem); CT_SAFE_FREE_STRING(pszTmpPath); CT_SAFE_FREE_STRING(pszFinalPath); CTFreeLines(&lines); 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; }
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 CTGetPListVersion( PSTR* ppVersion ) { DWORD error = 0; CFURLRef pURL = NULL; CFDataRef pContents = NULL; // SInt32 urlError = 0; // Do not free. This is returned by a mac function following the "get" // rule. CFStringRef pVers = NULL; CFErrorRef pError = NULL; PSTR pVersionString = NULL; CFPropertyListRef pPList = NULL; PSTR pErrorString = NULL; pURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, CFSTR("/System/Library/CoreServices/SystemVersion.plist"), kCFURLPOSIXPathStyle, false); if (!pURL) { error = ERROR_NOT_ENOUGH_MEMORY; GCE(error); } //// CFMutableDataRef fileContent = CFDataCreateMutable(kCFAllocatorDefault, 0); CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, pURL); if(stream) { if(CFReadStreamOpen(stream)) { UInt8 buffer[BUFFERSIZE]; CFIndex bytesRead; do { bytesRead = CFReadStreamRead(stream, buffer, sizeof(buffer)); if(bytesRead > 0) { CFDataAppendBytes(fileContent, buffer, bytesRead); } } while (bytesRead > 0); CFReadStreamClose(stream); } CFRelease(stream); } //// /* if (!CFURLCreateDataAndPropertiesFromResource( kCFAllocatorDefault, pURL, &pContents, NULL, NULL, &urlError)) { error = UrlErrorToLwError(urlError); GCE(error); } */ pPList = CFPropertyListCreateWithData( kCFAllocatorDefault, pContents, kCFPropertyListImmutable, NULL, &pError); if (!pPList) { CFStringRef pErrorDesc = CFErrorCopyDescription(pError); GetPstrFromStringRef(pErrorDesc, &pErrorString); // CT_LOG_ERROR("Error '%s' parsing OS X version file", // LW_SAFE_LOG_STRING(pErrorString)); error = ERROR_PRODUCT_VERSION; CFRelease(pErrorDesc); GCE(error); } pVers = (CFStringRef)CFDictionaryGetValue( (CFDictionaryRef)pPList, CFSTR("ProductVersion")); if (!pVers) { error = ERROR_PRODUCT_VERSION; GCE(error); } error = GetPstrFromStringRef( pVers, &pVersionString); GCE(error); *ppVersion = pVersionString; cleanup: if (error) { LW_SAFE_FREE_STRING(pVersionString); } if (pError) { CFRelease(pError); } LW_SAFE_FREE_STRING(pErrorString); if (pURL) { CFRelease(pURL); } if (pContents) { CFRelease(pContents); } if (pPList) { CFRelease(pPList); } return error; }
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 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; }
DWORD UpdateNsswitchConf(NsswitchConf *conf, BOOLEAN enable) { DWORD ceError = ERROR_SUCCESS; DistroInfo distro; int line; int lwiIndex; static const char* moduleName = "lsass"; static const char* oldModule = "lwidentity"; GCE(ceError = DJGetDistroInfo(NULL, &distro)); line = FindEntry(conf, 0, "passwd"); if(enable && line == -1) { DJ_LOG_INFO("Adding passwd line"); GCE(ceError = AddEntry(conf, &distro, &line, "passwd")); GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } lwiIndex = FindModuleOnLine(conf, line, moduleName); if(enable && lwiIndex == -1) { GCE(ceError = InsertModule(conf, &distro, line, -1, moduleName)); } if(!enable && lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } lwiIndex = FindModuleOnLine(conf, line, oldModule); if(lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } // If lwidentity was the only entry // and we removed that now, don't write // an empty entry into the file if(!enable && line != -1 && GetEntry(conf, line)->modules.size == 0) { GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } line = FindEntry(conf, 0, "group"); if(line == -1) { line = FindEntry(conf, 0, "groups"); } if(enable && line == -1) { /* The nsswitch file doesn't have an existing groups line. We have to * guess based on platform whether it uses 'group' or 'groups'. */ const char *groupName = "group"; if(distro.os == OS_AIX || distro.os == OS_DARWIN) { groupName = "groups"; } DJ_LOG_INFO("Adding %s line", groupName); GCE(ceError = AddEntry(conf, &distro, &line, groupName)); GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } lwiIndex = FindModuleOnLine(conf, line, moduleName); if(enable && lwiIndex == -1) { GCE(ceError = InsertModule(conf, &distro, line, -1, moduleName)); } if(!enable && lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } lwiIndex = FindModuleOnLine(conf, line, oldModule); if(lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } // If lwidentity was the only entry // and we removed that now, don't write // an empty entry into the file if(!enable && line != -1 && GetEntry(conf, line)->modules.size == 0) { GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } cleanup: DJFreeDistroInfo(&distro); return ceError; }
DWORD ReadNsswitchConf(NsswitchConf *conf, const char *testPrefix, BOOLEAN allowFileCreate) { PSTR copyDestPath = NULL; PSTR defaultFilePath = NULL; DWORD ceError = ERROR_SUCCESS; BOOLEAN bFileExists = FALSE; memset(conf, 0, sizeof(*conf)); //Keep trying to read different filenames until one of them is found if(!bFileExists) { bFileExists = TRUE; ceError = ReadNsswitchFile(conf, testPrefix, "/etc/nsswitch.conf"); if(ceError == ERROR_FILE_NOT_FOUND) { bFileExists = FALSE; ceError = ERROR_SUCCESS; } GCE(ceError); } if(!bFileExists) { bFileExists = TRUE; ceError = ReadNsswitchFile(conf, testPrefix, "/etc/netsvc.conf"); if(ceError == ERROR_FILE_NOT_FOUND) { bFileExists = FALSE; ceError = ERROR_SUCCESS; } GCE(ceError); } /* HP-UX 11.xx does not appear to have an nsswitch file in place by default. If we don't find on already installed, use our own */ if(!bFileExists) { GCE(ceError = CTAllocateStringPrintf( &defaultFilePath, "%s%s", testPrefix, NSSWITCH_LWIDEFAULTS)); GCE(ceError = CTCheckFileExists(defaultFilePath, &bFileExists)); if (bFileExists) { ceError = ReadNsswitchFile(conf, testPrefix, NSSWITCH_LWIDEFAULTS); GCE(ceError); CT_SAFE_FREE_STRING(conf->filename); conf->modified = TRUE; if(allowFileCreate) { GCE(ceError = CTStrdup(NSSWITCH_CONF_PATH, &conf->filename)); /* Copy over the original file. This way the user can more * clearly see what we changed by comparing nsswitch.conf with * nsswitch.conf.lwidentity.orig. Also, the permissions will be * correct this way when the file is written out. */ DJ_LOG_INFO("Copying default nsswitch file"); GCE(ceError = CTAllocateStringPrintf( ©DestPath, "%s%s", testPrefix, NSSWITCH_CONF_PATH)); ceError = CTCopyFileWithOriginalPerms(defaultFilePath, copyDestPath); GCE(ceError); } else { GCE(ceError = CTStrdup(NSSWITCH_LWIDEFAULTS, &conf->filename)); } } } if(!bFileExists) { GCE(ceError = ERROR_FILE_NOT_FOUND); } cleanup: CT_SAFE_FREE_STRING(copyDestPath); CT_SAFE_FREE_STRING(defaultFilePath); return ceError; }
// HPUX 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; struct pst_status mystatus; struct pst_status status[10]; int inBuffer; int i; 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)); } } //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; if(count) *count = foundCount; else if(!ceError && foundCount == 0) ceError = ERROR_PROC_NOT_FOUND; cleanup: return ceError; }
//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; }
static DWORD InsertModule(NsswitchConf *conf, const DistroInfo *distro, int line, int insertIndex, const char *name) { DWORD ceError = ERROR_SUCCESS; NsswitchEntry *lineObj = (NsswitchEntry *)GetEntry(conf, line); CTParseToken *beforeModule = NULL, *afterModule = NULL; CTParseToken addModule; memset(&addModule, 0, sizeof(addModule)); if(insertIndex == -1) insertIndex = lineObj->modules.size; GCE(ceError = CTStrdup(name, &addModule.value)); if(insertIndex - 1 >= 0) beforeModule = (CTParseToken *)lineObj->modules.data + insertIndex - 1; if(insertIndex < lineObj->modules.size) afterModule = (CTParseToken *)lineObj->modules.data + insertIndex; if(beforeModule != NULL) { /* Copy the separator from the previous module */ GCE(ceError = CTDupOrNullStr(beforeModule->trailingSeparator, &addModule.trailingSeparator)); if(afterModule == NULL) { /*This is the last module. Put in the correct separator after the * previous module */ CT_SAFE_FREE_STRING(beforeModule->trailingSeparator); GCE(ceError = CTStrdup(GetModuleSeparator(conf, distro), &beforeModule->trailingSeparator)); } } else { if(afterModule == NULL) { //This is the last module if(lineObj->comment == NULL) { //Leave the trailingSeparator as NULL } else { GCE(ceError = CTStrdup(" ", &addModule.trailingSeparator)); } } else { //This is the first module. Add the appropriate separator to //distinguish it from the next module. GCE(ceError = CTStrdup(GetModuleSeparator(conf, distro), &addModule.trailingSeparator)); } } GCE(ceError = CTArrayInsert(&lineObj->modules, insertIndex, sizeof(addModule), &addModule, 1)); memset(&addModule, 0, sizeof(addModule)); conf->modified = 1; cleanup: CTFreeParseTokenContents(&addModule); return ceError; }
//FreeBSD has 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; //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 }; 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)); } } 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; if(count) *count = foundCount; else if(!ceError && foundCount == 0) ceError = ERROR_PROC_NOT_FOUND; cleanup: if(kd != NULL) { kvm_close(kd); } return ceError; }
DWORD UpdateNsswitchConf(NsswitchConf *conf, BOOLEAN enable) { DWORD ceError = ERROR_SUCCESS; LwDistroInfo distro; int line; int lwiIndex; static const char* moduleName = "lsass"; static const char* oldModule = "lwidentity"; const char* pszModule = NULL; CHAR szCommand[2 * PATH_MAX + 1] = {}; GCE(ceError = DJGetDistroInfo(NULL, &distro)); line = FindEntry(conf, 0, "passwd"); if(enable && line == -1) { DJ_LOG_INFO("Adding passwd line"); GCE(ceError = AddEntry(conf, &distro, &line, "passwd")); GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } lwiIndex = FindModuleOnLine(conf, line, moduleName); if(enable && lwiIndex == -1) { GCE(ceError = InsertModule(conf, &distro, line, -1, moduleName)); } if(!enable && lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } lwiIndex = FindModuleOnLine(conf, line, oldModule); if(lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } // If lwidentity was the only entry // and we removed that now, don't write // an empty entry into the file if(!enable && line != -1 && GetEntry(conf, line)->modules.size == 0) { GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } line = FindEntry(conf, 0, "group"); if(line == -1) { line = FindEntry(conf, 0, "groups"); } if(enable && line == -1) { /* The nsswitch file doesn't have an existing groups line. We have to * guess based on platform whether it uses 'group' or 'groups'. */ const char *groupName = "group"; if(distro.os == OS_AIX || distro.os == OS_DARWIN) { groupName = "groups"; } DJ_LOG_INFO("Adding %s line", groupName); GCE(ceError = AddEntry(conf, &distro, &line, groupName)); GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } lwiIndex = FindModuleOnLine(conf, line, moduleName); if(enable && lwiIndex == -1) { GCE(ceError = InsertModule(conf, &distro, line, -1, moduleName)); } if(!enable && lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } lwiIndex = FindModuleOnLine(conf, line, oldModule); if(lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } // If lwidentity was the only entry // and we removed that now, don't write // an empty entry into the file if(!enable && line != -1 && GetEntry(conf, line)->modules.size == 0) { GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } // If initgroups is present, it overrides the groups line // and has different semantics. // As soon as a module reports success, processing stops. We don't want // that so we need to add '[SUCCESS=continue]' // We are not adding initgroups if it is not present. line = FindEntry(conf, 0, "initgroups"); lwiIndex = FindModuleOnLine(conf, line, moduleName); if(enable && line != -1 && lwiIndex == -1) { GCE(ceError = InsertModule(conf, &distro, line, -1, moduleName)); lwiIndex = FindModuleOnLine(conf, line, moduleName); if (lwiIndex > 0) { ceError = InsertModule(conf, &distro, line, lwiIndex, "[SUCCESS=continue]"); if (ceError) { RemoveModule(conf, line, lwiIndex - 1); GCE(ceError); } } } if (!enable && line != -1 && lwiIndex != -1) { if (lwiIndex > 0) { pszModule = GetModule(conf, line, lwiIndex - 1); if (pszModule && *pszModule == '[') { GCE(ceError = RemoveModule(conf, line, lwiIndex - 1)); lwiIndex = lwiIndex - 1; } } GCE(ceError = RemoveModule(conf, line, lwiIndex)); } if(!enable && line != -1 && GetEntry(conf, line)->modules.size == 0) { GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } if(distro.os == OS_SUNOS) { if(strcmp("5.11", distro.version) == 0) { if(enable) { sprintf(szCommand, "svccfg -s name-service/switch setprop config/password=\\\"files %s\\\"", moduleName); if(system(szCommand) < 0) { goto cleanup; } memset(szCommand, 0, sizeof(szCommand)); sprintf(szCommand, "svccfg -s name-service/switch setprop config/group=\\\"files %s\\\"", moduleName); if(system(szCommand) < 0) { goto cleanup; } memset(szCommand, 0, sizeof(szCommand)); sprintf(szCommand, "svcadm refresh name-service/switch"); if(system(szCommand) < 0) { goto cleanup; } } else { memset(szCommand, 0, sizeof(szCommand)); sprintf(szCommand, "svccfg -s name-service/switch setprop config/password=files"); if(system(szCommand) < 0) { goto cleanup; } memset(szCommand, 0, sizeof(szCommand)); sprintf(szCommand, "svccfg -s name-service/switch setprop config/group=files"); if(system(szCommand) < 0) { goto cleanup; } memset(szCommand, 0, sizeof(szCommand)); sprintf(szCommand, "svcadm refresh name-service/switch"); if(system(szCommand) < 0) { goto cleanup; } } } else { goto cleanup; } } cleanup: DJFreeDistroInfo(&distro); return ceError; }
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; }