• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
usage(void)39 static void usage(void)
40 {
41 	fprintf(stderr, "usage: pscap [-a]\n");
42 	exit(1);
43 }
44 
main(int argc,char * argv[])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