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@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
usage(void)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
check_file(const char * fpath,const struct stat * sb,int typeflag_unused,struct FTW * s_unused)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 //
main(int argc,char * argv[])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