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 (at) redhat.com> 22 */ 23 24 #include "config.h" 25 #include <stdio.h> 26 #include <stdio_ext.h> 27 #include <unistd.h> 28 #include <stdlib.h> 29 #include <errno.h> 30 #include <string.h> 31 #include <dirent.h> 32 #include <fcntl.h> 33 #include <pwd.h> 34 #include "cap-ng.h" 35 36 37 static void usage(void) 38 { 39 fprintf(stderr, "usage: pscap [-a]\n"); 40 exit(1); 41 } 42 43 int main(int argc, char *argv[]) 44 { 45 DIR *d; 46 struct dirent *ent; 47 int header = 0, show_all = 0, caps; 48 pid_t our_pid = getpid(); 49 50 if (argc > 2) { 51 fputs("Too many arguments\n", stderr); 52 usage(); 53 } 54 if (argc == 2) { 55 if (strcmp(argv[1], "-a") == 0) 56 show_all = 1; 57 else 58 usage(); 59 } 60 61 d = opendir("/proc"); 62 if (d == NULL) { 63 printf("Can't open /proc: %s\n", strerror(errno)); 64 return 1; 65 } 66 while (( ent = readdir(d) )) { 67 int pid, ppid, uid = -1, euid = -1; 68 char buf[100]; 69 char *tmp, cmd[16], state, *name = NULL; 70 int fd, len; 71 struct passwd *p; 72 73 // Skip non-process dir entries 74 if(*ent->d_name<'0' || *ent->d_name>'9') 75 continue; 76 errno = 0; 77 pid = strtol(ent->d_name, NULL, 10); 78 if (errno) 79 continue; 80 81 /* Skip our pid so we aren't listed */ 82 if (pid == our_pid) 83 continue; 84 85 // Parse up the stat file for the proc 86 snprintf(buf, 32, "/proc/%d/stat", pid); 87 fd = open(buf, O_RDONLY|O_CLOEXEC, 0); 88 if (fd < 0) 89 continue; 90 len = read(fd, buf, sizeof buf - 1); 91 close(fd); 92 if (len < 40) 93 continue; 94 buf[len] = 0; 95 tmp = strrchr(buf, ')'); 96 if (tmp) 97 *tmp = 0; 98 else 99 continue; 100 memset(cmd, 0, sizeof(cmd)); 101 sscanf(buf, "%d (%15c", &ppid, cmd); 102 sscanf(tmp+2, "%c %d", &state, &ppid); 103 104 // Skip kthreads 105 if (pid == 2 || ppid == 2) 106 continue; 107 108 if (!show_all && pid == 1) 109 continue; 110 111 // now get the capabilities 112 capng_clear(CAPNG_SELECT_BOTH); 113 capng_setpid(pid); 114 if (capng_get_caps_process()) 115 continue; 116 117 // And print out anything with capabilities 118 caps = capng_have_capabilities(CAPNG_SELECT_CAPS); 119 if (caps > CAPNG_NONE) { 120 // Get the effective uid 121 FILE *f; 122 int line; 123 snprintf(buf, 32, "/proc/%d/status", pid); 124 f = fopen(buf, "rte"); 125 if (f == NULL) 126 euid = 0; 127 else { 128 line = 0; 129 __fsetlocking(f, FSETLOCKING_BYCALLER); 130 while (fgets(buf, sizeof(buf), f)) { 131 if (line == 0) { 132 line++; 133 continue; 134 } 135 if (memcmp(buf, "Uid:", 4) == 0) { 136 int id; 137 sscanf(buf, "Uid: %d %d", 138 &id, &euid); 139 break; 140 } 141 } 142 fclose(f); 143 } 144 145 len = read(fd, buf, sizeof buf - 1); 146 close(fd); 147 if (header == 0) { 148 printf("%-5s %-5s %-10s %-16s %s\n", 149 "ppid", "pid", "name", "command", 150 "capabilities"); 151 header = 1; 152 } 153 if (euid == 0) { 154 // Take short cut for this one 155 name = "root"; 156 uid = 0; 157 } else if (euid != uid) { 158 // Only look up if name changed 159 p = getpwuid(euid); 160 uid = euid; 161 if (p) 162 name = p->pw_name; 163 // If not taking this branch, use last val 164 } 165 if (name) { 166 printf("%-5d %-5d %-10s %-16s ", ppid, pid, 167 name, cmd); 168 } else 169 printf("%-5d %-5d %-10d %-16s ", ppid, pid, 170 uid, cmd); 171 if (caps == CAPNG_PARTIAL) { 172 capng_print_caps_text(CAPNG_PRINT_STDOUT, 173 CAPNG_PERMITTED); 174 if (capng_have_capabilities(CAPNG_SELECT_BOUNDS) 175 == CAPNG_FULL) 176 printf(" +"); 177 printf("\n"); 178 } else 179 printf("full\n"); 180 } 181 } 182 closedir(d); 183 return 0; 184 } 185 186