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