Home | History | Annotate | Download | only in utils
      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 #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 
     39 static void usage(void)
     40 {
     41 	fprintf(stderr, "usage: pscap [-a]\n");
     42 	exit(1);
     43 }
     44 
     45 int 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