1/* 2 * pscap.c - A program that lists running processes with capabilities 3 * Copyright (c) 2009,2012 Red Hat Inc., Durham, North Carolina. 4 * All Rights Reserved. 5 * 6 * This software may be freely redistributed and/or modified under the 7 * terms of the GNU General Public License as published by the Free 8 * Software Foundation; either version 2, or (at your option) any 9 * later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; see the file COPYING. If not, write to the 18 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 * 20 * Authors: 21 * Steve Grubb <sgrubb@redhat.com> 22 */ 23 24#include "config.h" 25#include <stdio.h> 26#if !defined(ANDROID) 27#include <stdio_ext.h> 28#endif 29#include <unistd.h> 30#include <stdlib.h> 31#include <errno.h> 32#include <string.h> 33#include <dirent.h> 34#include <fcntl.h> 35#include <pwd.h> 36#include "cap-ng.h" 37 38 39static void usage(void) 40{ 41 fprintf(stderr, "usage: pscap [-a]\n"); 42 exit(1); 43} 44 45int main(int argc, char *argv[]) 46{ 47 DIR *d; 48 struct dirent *ent; 49 int header = 0, show_all = 0, caps; 50 pid_t our_pid = getpid(); 51 52 if (argc > 2) { 53 fputs("Too many arguments\n", stderr); 54 usage(); 55 } 56 if (argc == 2) { 57 if (strcmp(argv[1], "-a") == 0) 58 show_all = 1; 59 else 60 usage(); 61 } 62 63 d = opendir("/proc"); 64 if (d == NULL) { 65 printf("Can't open /proc: %s\n", strerror(errno)); 66 return 1; 67 } 68 while (( ent = readdir(d) )) { 69 int pid, ppid, uid = -1, euid = -1; 70 char buf[100]; 71 char *tmp, cmd[16], state, *name = NULL; 72 int fd, len; 73 struct passwd *p; 74 75 // Skip non-process dir entries 76 if(*ent->d_name<'0' || *ent->d_name>'9') 77 continue; 78 errno = 0; 79 pid = strtol(ent->d_name, NULL, 10); 80 if (errno) 81 continue; 82 83 /* Skip our pid so we aren't listed */ 84 if (pid == our_pid) 85 continue; 86 87 // Parse up the stat file for the proc 88 snprintf(buf, 32, "/proc/%d/stat", pid); 89 fd = open(buf, O_RDONLY|O_CLOEXEC, 0); 90 if (fd < 0) 91 continue; 92 len = read(fd, buf, sizeof buf - 1); 93 close(fd); 94 if (len < 40) 95 continue; 96 buf[len] = 0; 97 tmp = strrchr(buf, ')'); 98 if (tmp) 99 *tmp = 0; 100 else 101 continue; 102 memset(cmd, 0, sizeof(cmd)); 103 sscanf(buf, "%d (%15c", &ppid, cmd); 104 sscanf(tmp+2, "%c %d", &state, &ppid); 105 106 // Skip kthreads 107 if (pid == 2 || ppid == 2) 108 continue; 109 110 if (!show_all && pid == 1) 111 continue; 112 113 // now get the capabilities 114 capng_clear(CAPNG_SELECT_BOTH); 115 capng_setpid(pid); 116 if (capng_get_caps_process()) 117 continue; 118 119 // And print out anything with capabilities 120 caps = capng_have_capabilities(CAPNG_SELECT_CAPS); 121 if (caps > CAPNG_NONE) { 122 // Get the effective uid 123 FILE *f; 124 int line; 125 snprintf(buf, 32, "/proc/%d/status", pid); 126 f = fopen(buf, "rte"); 127 if (f == NULL) 128 euid = 0; 129 else { 130 line = 0; 131#if !defined(ANDROID) 132 __fsetlocking(f, FSETLOCKING_BYCALLER); 133#endif 134 while (fgets(buf, sizeof(buf), f)) { 135 if (line == 0) { 136 line++; 137 continue; 138 } 139 if (memcmp(buf, "Uid:", 4) == 0) { 140 int id; 141 sscanf(buf, "Uid: %d %d", 142 &id, &euid); 143 break; 144 } 145 } 146 fclose(f); 147 } 148 149 len = read(fd, buf, sizeof buf - 1); 150 close(fd); 151 if (header == 0) { 152 printf("%-5s %-5s %-10s %-16s %s\n", 153 "ppid", "pid", "name", "command", 154 "capabilities"); 155 header = 1; 156 } 157 if (euid == 0) { 158 // Take short cut for this one 159 name = "root"; 160 uid = 0; 161 } else if (euid != uid) { 162 // Only look up if name changed 163 p = getpwuid(euid); 164 uid = euid; 165 if (p) 166 name = p->pw_name; 167 // If not taking this branch, use last val 168 } 169 if (name) { 170 printf("%-5d %-5d %-10s %-16s ", ppid, pid, 171 name, cmd); 172 } else 173 printf("%-5d %-5d %-10d %-16s ", ppid, pid, 174 uid, cmd); 175 if (caps == CAPNG_PARTIAL) { 176 capng_print_caps_text(CAPNG_PRINT_STDOUT, 177 CAPNG_PERMITTED); 178 if (capng_have_capabilities(CAPNG_SELECT_BOUNDS) 179 == CAPNG_FULL) 180 printf(" +"); 181 printf("\n"); 182 } else 183 printf("full\n"); 184 } 185 } 186 closedir(d); 187 return 0; 188} 189 190