blob: 59075130f1536052e8317d3e6cc85bc94ecd9441 [file] [log] [blame]
Nick Kralevich1d1011a2012-09-06 10:14:03 -07001/*
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