pscap.c revision 1d1011a3c5049a7f9eef99d22f3704e4367579cc
11d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich/*
21d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * pscap.c - A program that lists running processes with capabilities
31d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * Copyright (c) 2009,2012 Red Hat Inc., Durham, North Carolina.
41d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * All Rights Reserved.
51d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich *
61d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * This software may be freely redistributed and/or modified under the
71d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * terms of the GNU General Public License as published by the Free
81d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * Software Foundation; either version 2, or (at your option) any
91d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * later version.
101d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich *
111d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * This program is distributed in the hope that it will be useful,
121d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * but WITHOUT ANY WARRANTY; without even the implied warranty of
131d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * GNU General Public License for more details.
151d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich *
161d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * You should have received a copy of the GNU General Public License
171d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * along with this program; see the file COPYING. If not, write to the
181d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
191d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich *
201d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich * Authors:
211d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich *   Steve Grubb <sgrubb@redhat.com>
221d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich */
231d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
241d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include "config.h"
251d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <stdio.h>
261d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#if !defined(ANDROID)
271d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <stdio_ext.h>
281d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#endif
291d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <unistd.h>
301d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <stdlib.h>
311d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <errno.h>
321d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <string.h>
331d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <dirent.h>
341d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <fcntl.h>
351d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <pwd.h>
361d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include "cap-ng.h"
371d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
381d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
391d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevichstatic void usage(void)
401d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich{
411d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	fprintf(stderr, "usage: pscap [-a]\n");
421d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	exit(1);
431d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich}
441d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
451d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevichint main(int argc, char *argv[])
461d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich{
471d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	DIR *d;
481d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	struct dirent *ent;
491d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	int header = 0, show_all = 0, caps;
501d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	pid_t our_pid = getpid();
511d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
521d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	if (argc > 2) {
531d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		fputs("Too many arguments\n", stderr);
541d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		usage();
551d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	}
561d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	if (argc == 2) {
571d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (strcmp(argv[1], "-a") == 0)
581d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			show_all = 1;
591d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		else
601d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			usage();
611d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	}
621d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
631d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	d = opendir("/proc");
641d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	if (d == NULL) {
651d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		printf("Can't open /proc: %s\n", strerror(errno));
661d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		return 1;
671d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	}
681d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	while (( ent = readdir(d) )) {
691d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		int pid, ppid, uid = -1, euid = -1;
701d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		char buf[100];
711d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		char *tmp, cmd[16], state, *name = NULL;
721d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		int fd, len;
731d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		struct passwd *p;
741d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
751d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		// Skip non-process dir entries
761d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if(*ent->d_name<'0' || *ent->d_name>'9')
771d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
781d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		errno = 0;
791d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		pid = strtol(ent->d_name, NULL, 10);
801d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (errno)
811d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
821d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
831d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		/* Skip our pid so we aren't listed */
841d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (pid == our_pid)
851d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
861d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
871d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		// Parse up the stat file for the proc
881d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		snprintf(buf, 32, "/proc/%d/stat", pid);
891d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		fd = open(buf, O_RDONLY|O_CLOEXEC, 0);
901d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (fd < 0)
911d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
921d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		len = read(fd, buf, sizeof buf - 1);
931d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		close(fd);
941d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (len < 40)
951d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
961d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		buf[len] = 0;
971d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		tmp = strrchr(buf, ')');
981d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (tmp)
991d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			*tmp = 0;
1001d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		else
1011d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
1021d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		memset(cmd, 0, sizeof(cmd));
1031d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		sscanf(buf, "%d (%15c", &ppid, cmd);
1041d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		sscanf(tmp+2, "%c %d", &state, &ppid);
1051d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
1061d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		// Skip kthreads
1071d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (pid == 2 || ppid == 2)
1081d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
1091d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
1101d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (!show_all && pid == 1)
1111d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
1121d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
1131d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		// now get the capabilities
1141d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		capng_clear(CAPNG_SELECT_BOTH);
1151d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		capng_setpid(pid);
1161d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (capng_get_caps_process())
1171d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
1181d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
1191d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		// And print out anything with capabilities
1201d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		caps = capng_have_capabilities(CAPNG_SELECT_CAPS);
1211d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (caps > CAPNG_NONE) {
1221d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			// Get the effective uid
1231d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			FILE *f;
1241d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			int line;
1251d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			snprintf(buf, 32, "/proc/%d/status", pid);
1261d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			f = fopen(buf, "rte");
1271d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			if (f == NULL)
1281d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				euid = 0;
1291d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			else {
1301d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				line = 0;
1311d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#if !defined(ANDROID)
1321d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				__fsetlocking(f, FSETLOCKING_BYCALLER);
1331d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#endif
1341d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				while (fgets(buf, sizeof(buf), f)) {
1351d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					if (line == 0) {
1361d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich						line++;
1371d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich						continue;
1381d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					}
1391d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					if (memcmp(buf, "Uid:", 4) == 0) {
1401d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich						int id;
1411d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich						sscanf(buf, "Uid: %d %d",
1421d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich							&id, &euid);
1431d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich						break;
1441d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					}
1451d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				}
1461d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				fclose(f);
1471d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			}
1481d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
1491d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			len = read(fd, buf, sizeof buf - 1);
1501d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			close(fd);
1511d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			if (header == 0) {
1521d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				printf("%-5s %-5s %-10s  %-16s  %s\n",
1531d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				    "ppid", "pid", "name", "command",
1541d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				    "capabilities");
1551d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				header = 1;
1561d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			}
1571d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			if (euid == 0) {
1581d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				// Take short cut for this one
1591d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				name = "root";
1601d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				uid = 0;
1611d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			} else if (euid != uid) {
1621d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				// Only look up if name changed
1631d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				p = getpwuid(euid);
1641d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				uid = euid;
1651d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				if (p)
1661d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					name = p->pw_name;
1671d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				// If not taking this branch, use last val
1681d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			}
1691d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			if (name) {
1701d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				printf("%-5d %-5d %-10s  %-16s  ", ppid, pid,
1711d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					name, cmd);
1721d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			} else
1731d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				printf("%-5d %-5d %-10d  %-16s  ", ppid, pid,
1741d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					uid, cmd);
1751d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			if (caps == CAPNG_PARTIAL) {
1761d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				capng_print_caps_text(CAPNG_PRINT_STDOUT,
1771d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich							CAPNG_PERMITTED);
1781d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				if (capng_have_capabilities(CAPNG_SELECT_BOUNDS)
1791d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich							 == CAPNG_FULL)
1801d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					printf(" +");
1811d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				printf("\n");
1821d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			} else
1831d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				printf("full\n");
1841d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		}
1851d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	}
1861d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	closedir(d);
1871d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	return 0;
1881d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich}
1891d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
190