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#include <stdio_ext.h>
271d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <unistd.h>
281d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <stdlib.h>
291d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <errno.h>
301d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <string.h>
311d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <dirent.h>
321d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <fcntl.h>
331d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include <pwd.h>
341d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich#include "cap-ng.h"
351d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
361d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
371d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevichstatic void usage(void)
381d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich{
391d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	fprintf(stderr, "usage: pscap [-a]\n");
401d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	exit(1);
411d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich}
421d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
431d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevichint main(int argc, char *argv[])
441d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich{
451d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	DIR *d;
461d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	struct dirent *ent;
471d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	int header = 0, show_all = 0, caps;
481d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	pid_t our_pid = getpid();
491d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
501d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	if (argc > 2) {
511d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		fputs("Too many arguments\n", stderr);
521d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		usage();
531d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	}
541d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	if (argc == 2) {
551d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (strcmp(argv[1], "-a") == 0)
561d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			show_all = 1;
571d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		else
581d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			usage();
591d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	}
601d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
611d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	d = opendir("/proc");
621d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	if (d == NULL) {
631d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		printf("Can't open /proc: %s\n", strerror(errno));
641d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		return 1;
651d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	}
661d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	while (( ent = readdir(d) )) {
671d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		int pid, ppid, uid = -1, euid = -1;
681d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		char buf[100];
691d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		char *tmp, cmd[16], state, *name = NULL;
701d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		int fd, len;
711d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		struct passwd *p;
721d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
731d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		// Skip non-process dir entries
741d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if(*ent->d_name<'0' || *ent->d_name>'9')
751d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
761d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		errno = 0;
771d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		pid = strtol(ent->d_name, NULL, 10);
781d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (errno)
791d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
801d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
811d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		/* Skip our pid so we aren't listed */
821d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (pid == our_pid)
831d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
841d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
851d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		// Parse up the stat file for the proc
861d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		snprintf(buf, 32, "/proc/%d/stat", pid);
871d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		fd = open(buf, O_RDONLY|O_CLOEXEC, 0);
881d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (fd < 0)
891d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
901d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		len = read(fd, buf, sizeof buf - 1);
911d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		close(fd);
921d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (len < 40)
931d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
941d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		buf[len] = 0;
951d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		tmp = strrchr(buf, ')');
961d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (tmp)
971d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			*tmp = 0;
981d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		else
991d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
1001d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		memset(cmd, 0, sizeof(cmd));
1011d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		sscanf(buf, "%d (%15c", &ppid, cmd);
1021d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		sscanf(tmp+2, "%c %d", &state, &ppid);
1031d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
1041d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		// Skip kthreads
1051d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (pid == 2 || ppid == 2)
1061d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
1071d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
1081d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (!show_all && pid == 1)
1091d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
1101d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
1111d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		// now get the capabilities
1121d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		capng_clear(CAPNG_SELECT_BOTH);
1131d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		capng_setpid(pid);
1141d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (capng_get_caps_process())
1151d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			continue;
1161d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
1171d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		// And print out anything with capabilities
1181d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		caps = capng_have_capabilities(CAPNG_SELECT_CAPS);
1191d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		if (caps > CAPNG_NONE) {
1201d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			// Get the effective uid
1211d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			FILE *f;
1221d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			int line;
1231d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			snprintf(buf, 32, "/proc/%d/status", pid);
1241d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			f = fopen(buf, "rte");
1251d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			if (f == NULL)
1261d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				euid = 0;
1271d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			else {
1281d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				line = 0;
1291d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				__fsetlocking(f, FSETLOCKING_BYCALLER);
1301d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				while (fgets(buf, sizeof(buf), f)) {
1311d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					if (line == 0) {
1321d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich						line++;
1331d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich						continue;
1341d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					}
1351d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					if (memcmp(buf, "Uid:", 4) == 0) {
1361d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich						int id;
1371d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich						sscanf(buf, "Uid: %d %d",
1381d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich							&id, &euid);
1391d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich						break;
1401d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					}
1411d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				}
1421d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				fclose(f);
1431d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			}
1441d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
1451d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			len = read(fd, buf, sizeof buf - 1);
1461d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			close(fd);
1471d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			if (header == 0) {
1481d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				printf("%-5s %-5s %-10s  %-16s  %s\n",
1491d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				    "ppid", "pid", "name", "command",
1501d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				    "capabilities");
1511d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				header = 1;
1521d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			}
1531d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			if (euid == 0) {
1541d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				// Take short cut for this one
1551d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				name = "root";
1561d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				uid = 0;
1571d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			} else if (euid != uid) {
1581d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				// Only look up if name changed
1591d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				p = getpwuid(euid);
1601d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				uid = euid;
1611d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				if (p)
1621d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					name = p->pw_name;
1631d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				// If not taking this branch, use last val
1641d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			}
1651d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			if (name) {
1661d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				printf("%-5d %-5d %-10s  %-16s  ", ppid, pid,
1671d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					name, cmd);
1681d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			} else
1691d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				printf("%-5d %-5d %-10d  %-16s  ", ppid, pid,
1701d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					uid, cmd);
1711d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			if (caps == CAPNG_PARTIAL) {
1721d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				capng_print_caps_text(CAPNG_PRINT_STDOUT,
1731d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich							CAPNG_PERMITTED);
1741d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				if (capng_have_capabilities(CAPNG_SELECT_BOUNDS)
1751d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich							 == CAPNG_FULL)
1761d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich					printf(" +");
1771d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				printf("\n");
1781d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich			} else
1791d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich				printf("full\n");
1801d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich		}
1811d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	}
1821d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	closedir(d);
1831d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich	return 0;
1841d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich}
1851d1011a3c5049a7f9eef99d22f3704e4367579ccNick Kralevich
186