Home | History | Annotate | Download | only in utils
      1 /*
      2  * filecap.c - A program that lists running processes with capabilities
      3  * Copyright (c) 2009-10 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 (at) redhat.com>
     22  */
     23 
     24 #include "config.h"
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <errno.h>
     29 #include "cap-ng.h"
     30 #define __USE_GNU 1
     31 #include <fcntl.h>
     32 #define __USE_XOPEN_EXTENDED 1
     33 #include <ftw.h>
     34 
     35 static int show_all = 0, header = 0, capabilities = 0, cremove = 0;
     36 
     37 static void usage(void)
     38 {
     39 	fprintf(stderr,
     40 	    "usage: filecap [-a | -d | /dir | /dir/file [cap1 cap2 ...] ]\n");
     41 	exit(1);
     42 }
     43 
     44 static int check_file(const char *fpath,
     45 		const struct stat *sb,
     46 		int typeflag_unused __attribute__ ((unused)),
     47 		struct FTW *s_unused __attribute__ ((unused)))
     48 {
     49 	if (S_ISREG(sb->st_mode) == 0)
     50 		return FTW_CONTINUE;
     51 
     52 	int fd = open(fpath, O_RDONLY|O_CLOEXEC);
     53 	if (fd >= 0) {
     54 		capng_results_t rc;
     55 
     56 		capng_clear(CAPNG_SELECT_BOTH);
     57 		capng_get_caps_fd(fd);
     58 		rc = capng_have_capabilities(CAPNG_SELECT_CAPS);
     59 		if (rc > CAPNG_NONE) {
     60 			if (header == 0) {
     61 				header = 1;
     62 				printf("%-20s capabilities\n", "file");
     63 			}
     64 			printf("%s     ", fpath);
     65 			if (rc == CAPNG_FULL)
     66 				printf("full");
     67 			else
     68 				capng_print_caps_text(CAPNG_PRINT_STDOUT,
     69 						CAPNG_PERMITTED);
     70 			printf("\n");
     71 		}
     72 		close(fd);
     73 	}
     74 	return FTW_CONTINUE;
     75 }
     76 
     77 
     78 // Use cases:
     79 //  filecap
     80 //  filecap -a
     81 //  filecap /path/dir
     82 //  filecap /path/file
     83 //  filecap /path/file capability1 capability2 capability 3 ...
     84 //
     85 int main(int argc, char *argv[])
     86 {
     87 #if CAP_LAST_CAP < 31 || !defined (VFS_CAP_U32) || !defined (HAVE_ATTR_XATTR_H)
     88 	printf("File based capabilities are not supported\n");
     89 #else
     90 	char *path_env, *path = NULL, *dir = NULL;
     91 	struct stat sbuf;
     92 	int nftw_flags = FTW_PHYS;
     93 	int i;
     94 
     95 	if (argc >1) {
     96 		for (i=1; i<argc; i++) {
     97 			if (strcmp(argv[i], "-a") == 0) {
     98 				show_all = 1;
     99 				if (argc != 2)
    100 					usage();
    101 			} else if (strcmp(argv[i], "-d") == 0) {
    102 				for (i=0; i<=CAP_LAST_CAP; i++) {
    103 					const char *n =
    104 						capng_capability_to_name(i);
    105 					if (n == NULL)
    106 						n = "unknown";
    107 					printf("%s\n", n);
    108 				}
    109 				return 0;
    110 			} else if (argv[i][0] == '/') {
    111 				if (lstat(argv[i], &sbuf) != 0) {
    112 					printf("Error checking path %s (%s)\n",
    113 						argv[i], strerror(errno));
    114 					exit(1);
    115 				}
    116 				// Clear all capabilities in case cap strings
    117 				// follow. If we get a second file we err out
    118 				// so this is safe
    119 				if (S_ISREG(sbuf.st_mode) && path == NULL &&
    120 								 dir == NULL) {
    121 					path = argv[i];
    122 					capng_clear(CAPNG_SELECT_BOTH);
    123 				} else if (S_ISDIR(sbuf.st_mode) && path == NULL
    124 								&& dir == NULL)
    125 					dir = argv[i];
    126 				else {
    127 					printf("Must be one regular file or "
    128 						"directory\n");
    129 					exit(1);
    130 				}
    131 			} else {
    132 				int cap = capng_name_to_capability(argv[i]);
    133 				if (cap >= 0) {
    134 					if (path == NULL)
    135 						usage();
    136 					capng_update(CAPNG_ADD,
    137 						CAPNG_PERMITTED|CAPNG_EFFECTIVE,
    138 						cap);
    139 					capabilities = 1;
    140 				} else if (strcmp("none", argv[i]) == 0) {
    141 					capng_clear(CAPNG_SELECT_BOTH);
    142 					capabilities = 1;
    143 					cremove = 1;
    144 				} else {
    145 					printf("Unrecognized capability.\n");
    146 					usage();
    147 				}
    148 			}
    149 		}
    150 	}
    151 	if (path == NULL && dir == NULL && show_all == 0) {
    152 		path_env = getenv("PATH");
    153 		if (path_env != NULL) {
    154 			path = strdup(path_env);
    155 			for (dir=strtok(path,":"); dir!=NULL;
    156 						dir=strtok(NULL,":")) {
    157 				nftw(dir, check_file, 1024, nftw_flags);
    158 			}
    159 			free(path);
    160 		}
    161 	} else if (path == NULL && dir == NULL && show_all == 1) {
    162 		// Find files
    163 		nftw("/", check_file, 1024, nftw_flags);
    164 	} else if (dir) {
    165 		// Print out the dir
    166 		nftw(dir, check_file, 1024, nftw_flags);
    167 	}else if (path && capabilities == 0) {
    168 		// Print out specific file
    169 		check_file(path, &sbuf, 0, NULL);
    170 	} else if (path && capabilities == 1) {
    171 		// Write capabilities to file
    172 		int fd = open(path, O_WRONLY|O_NOFOLLOW|O_CLOEXEC);
    173 		if (fd < 0) {
    174 			printf("Could not open %s for writing (%s)\n", path,
    175 				strerror(errno));
    176 			return 1;
    177 		}
    178 		capng_apply_caps_fd(fd);
    179 		close(fd);
    180 	}
    181 #endif
    182 	return 0;
    183 }
    184 
    185