/* * Routine to provide information about the other side of a FD. * * Copyright (C) 2015 Peter Wu * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #define _GNU_SOURCE /* for struct ucred on Linux */ #include "scope.h" #include #include #include /* for pid_t */ #ifdef HAVE_GETPEERUCRED /* Solaris-derived systems */ #include #endif #ifdef __sun #include #endif static pid_t GetPidFromFd(FD fd) { #ifdef SO_PEERCRED #ifndef __OpenBSD__ struct ucred cred; #else struct sockpeercred cred; #endif socklen_t cred_len = sizeof(cred); if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) == 0 && cred_len == sizeof(cred)) { return cred.pid; } #elif defined(HAVE_GETPEERUCRED) ucred_t *peercred = NULL; if (getpeerucred(fd, &peercred) == 0) { pid_t peerpid = ucred_getpid(peercred); ucred_free(peercred); if (peerpid != -1) { return peerpid; } } #endif return 0; } static const char * GetProcnameForPid(pid_t pid) { #ifdef __sun /* Solaris-derived /proc */ static char comm[PRARGSZ]; char path[32]; int totsize = 0; int fd = 0; psinfo_t psinfo = { 0 }; char *sp; if (snprintf(path, sizeof(path), "/proc/%d/psinfo", pid) < 0) return NULL; fd = open(path, O_RDONLY); if (fd < 0) return NULL; totsize = read(fd, &psinfo, sizeof(psinfo_t)); close(fd); if (totsize <= 0) return NULL; /* pr_psargs is the first PRARGSZ (80) characters of the command * line string - assume up to the first space is the command name, * since it's not delimited. While there is also pr_fname, that's * more limited, giving only the first 16 chars of the basename of * the file that was exec'ed, thus cutting off many long gnome * command names, or returning "isapython2.6" for all python scripts. */ psinfo.pr_psargs[PRARGSZ - 1] = '\0'; sp = strchr(psinfo.pr_psargs, ' '); if (sp) *sp = '\0'; strlcpy(comm, psinfo.pr_psargs, sizeof(comm)); return comm; #else /* Linux-style /proc */ /* comm is no longer than TASK_COMM_LEN (16) */ static char comm[17]; char comm_path[32]; char comm_fd; unsigned comm_len = 0; snprintf(comm_path, sizeof(comm_path), "/proc/%d/comm", pid); comm_fd = open(comm_path, O_RDONLY); if (comm_fd != -1) { comm_len = read(comm_fd, comm, sizeof(comm) - 1); if (comm_len < 0) comm_len = 0; close(comm_fd); } if (comm_len > 0 && comm[comm_len - 1] == '\n') comm_len--; comm[comm_len] = '\0'; return comm; #endif } /* Retrieves additional information about the other side of the fd. For Unix domain sockets, this results in the process ID and name. */ char * ReadPeerInfo(FD fd) { /* should hold enough for "PID " */ char peer_info[40]; unsigned pos; pid_t pid; const char *comm; pid = GetPidFromFd(fd); /* Use the fact that pid_t is the first field of struct ucred. */ if (pid) { pos = snprintf(peer_info, sizeof(peer_info), "pid %d", pid); comm = GetProcnameForPid(pid); if (comm) pos += snprintf(peer_info + pos, sizeof(peer_info) - pos, " %s", comm); return strdup(peer_info); } /* (Could add port number here for AF_INET if it helps.) */ return NULL; }