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 #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
usage(void)37 static void usage(void)
38 {
39 fprintf(stderr, "usage: pscap [-a]\n");
40 exit(1);
41 }
42
main(int argc,char * argv[])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