/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: * * -*- mode: c, c-basic-offset: 4 -*- */ /* * Copyright Likewise Software 2004-2008 * All rights reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Copyright Likewise Software 2004-2008 * All rights reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ #include "config.h" #include "ctbase.h" #include "ctprocutils.h" #if HAVE_SYS_PARAM_H #include #endif #if HAVE_SYS_PSTAT_H #include #endif #if HAVE_PROCFS_H #include #elif HAVE_SYS_PROCFS_H #include #endif #if HAVE_FCNTL_H #include #endif #if HAVE_KVM_H #include #endif #if HAVE_SYS_TYPES_H #include #endif #if HAVE_SYS_SYSCTL_H #include #endif #if HAVE_SYS_USER_H #include #endif #define GCE(x) GOTO_CLEANUP_ON_CENTERROR((x)) CENTERROR CTMatchProgramToPID( PCSTR pszProgramName, pid_t pid ) { CENTERROR ceError = CENTERROR_SUCCESS; CHAR szBuf[PATH_MAX+1]; FILE* pFile = NULL; #if defined(__LWI_DARWIN__) || defined(__LWI_FREEBSD__) sprintf(szBuf, "ps -p %d -o command= | grep %s", pid, pszProgramName); #elif defined(__LWI_SOLARIS__) || defined(__LWI_HP_UX__) || defined(__LWI_AIX__) sprintf(szBuf, "UNIX95=1 ps -p %ld -o comm= | grep %s", (long)pid, pszProgramName); #else sprintf(szBuf, "UNIX95=1 ps -p %ld -o cmd= | grep %s", (long)pid, pszProgramName); #endif pFile = popen(szBuf, "r"); if (pFile == NULL) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } /* Assume that we won't find the process we are looking for */ ceError = CENTERROR_NO_SUCH_PROCESS; while (TRUE) { if (NULL == fgets(szBuf, PATH_MAX, pFile)) { if (feof(pFile)) { break; } else { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } } CTStripWhitespace(szBuf); if (!IsNullOrEmptyString(szBuf)) { /* Well what do you know, it was found! */ ceError = CENTERROR_SUCCESS; break; } } error: if (pFile) pclose(pFile); return ceError; } CENTERROR CTIsProgramRunning( PCSTR pszPidFile, PCSTR pszProgramName, pid_t *pPid, PBOOLEAN pbRunning ) { CENTERROR ceError = CENTERROR_SUCCESS; pid_t pid = 0; int fd = -1; int result; char contents[20]; BOOLEAN bFileExists = FALSE; if(pbRunning != NULL) *pbRunning = FALSE; if(pPid != NULL) *pPid = -1; ceError = CTCheckFileExists(pszPidFile, &bFileExists); BAIL_ON_CENTERIS_ERROR(ceError); if (bFileExists) { fd = open(pszPidFile, O_RDONLY, 0644); if (fd < 0) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } result = read(fd, contents, sizeof(contents)-1); if (result < 0) { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } else if (result > 0) { contents[result-1] = 0; result = atoi(contents); } if (result <= 0) { ceError = CENTERROR_NO_SUCH_PROCESS; BAIL_ON_CENTERIS_ERROR(ceError); } pid = (pid_t) result; result = kill(pid, 0); if (!result) { // Verify that the peer process is the auth daemon ceError = CTMatchProgramToPID(pszProgramName, pid); BAIL_ON_CENTERIS_ERROR(ceError); if(pbRunning != NULL) { *pbRunning = TRUE; } if ( pPid ) { *pPid = pid; } } else if (errno == ESRCH) { ceError = CENTERROR_NO_SUCH_PROCESS; BAIL_ON_CENTERIS_ERROR(ceError); } else { ceError = CTMapSystemError(errno); BAIL_ON_CENTERIS_ERROR(ceError); } } error: if (fd != -1) { close(fd); } return (ceError == CENTERROR_NO_SUCH_PROCESS ? CENTERROR_SUCCESS : ceError); } CENTERROR CTSendSignal( pid_t pid, int sig ) { int ret = 0; ret = kill(pid, sig); if (ret < 0) { return CTMapSystemError(errno); } return CENTERROR_SUCCESS; } CENTERROR CTGetPidOf( PCSTR programName, uid_t owner, pid_t *pid, size_t *count ) { return CTGetPidOfCmdLine(programName, NULL, NULL, owner, pid, count); } CENTERROR CTGetPidOfCmdLine( PCSTR programName, PCSTR programFilename, PCSTR cmdLine, uid_t owner, pid_t *pid, size_t *count ) { CENTERROR ceError = CENTERROR_NOT_IMPLEMENTED; 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 = CTMapSystemError(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 = CTMapSystemError(errno)); //Now look at all processes inBuffer = pstat_getproc(status, sizeof(status[0]), sizeof(status)/sizeof(status[0]), 0); if(inBuffer < 0) GCE(ceError = CTMapSystemError(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 = CTMapSystemError(errno)); } ceError = CENTERROR_SUCCESS; #endif #ifdef HAVE_STRUCT_PSINFO if ((dir = opendir("/proc")) == NULL) { GCE(ceError = CTMapSystemError(errno)); } while(1) { errno = 0; dirEntry = readdir(dir); if(dirEntry == NULL) { if(errno != 0) GCE(ceError = CTMapSystemError(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 = CTMapSystemError(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 = CTMapSystemError(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 = CENTERROR_ACCESS_DENIED); procs = kvm_getprocs(kd, KERN_PROC_PROC, 0, &unfilteredCount); if (procs == NULL) GCE(ceError = CENTERROR_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 = CTMapSystemError(errno)); } } if(strcmp(programFilename, pathBuffer)) continue; } //This is a match if(foundCount < fillCount) pid[foundCount] = pos->ki_pid; foundCount++; } ceError = CENTERROR_SUCCESS; #endif if(count) *count = foundCount; else if(CENTERROR_IS_OK(ceError) && foundCount == 0) ceError = CENTERROR_NO_SUCH_PROCESS; 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; }