1 /*
2 * filecap.c - A program that lists running processes with capabilities
3 * Copyright (c) 2009-10,2012,2017,2020 Red Hat Inc.
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., 51 Franklin Street, Fifth Floor
19 * Boston, MA 02110-1335, USA.
20 *
21 * Authors:
22 * Steve Grubb <[email protected]>
23 */
24
25 #include "config.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #include "cap-ng.h"
31 #include <fcntl.h>
32 #include <ftw.h>
33
34 #ifndef FTW_CONTINUE
35 #define FTW_CONTINUE 0
36 #endif
37
38
39 static int show_all = 0, header = 0, capabilities = 0, cremove = 0;
40 static int single_file = 0;
41
usage(void)42 static void usage(void)
43 {
44 fprintf(stderr,
45 "usage: filecap [-a | -d | /dir | /dir/file [cap1 cap2 ...] ]\n");
46 exit(1);
47 }
48
49 // Returns 1 on error and 0 otherwise
check_file(const char * fpath,const struct stat * sb,int typeflag_unused,struct FTW * s_unused)50 static int check_file(const char *fpath,
51 const struct stat *sb,
52 int typeflag_unused __attribute__ ((unused)),
53 struct FTW *s_unused __attribute__ ((unused)))
54 {
55 int ret = FTW_CONTINUE;
56
57 if (S_ISREG(sb->st_mode) == 0)
58 return ret;
59
60 int fd = open(fpath, O_RDONLY|O_CLOEXEC);
61 if (fd >= 0) {
62 capng_results_t rc;
63 int permitted = 0;
64
65 capng_clear(CAPNG_SELECT_BOTH);
66 if (capng_get_caps_fd(fd) < 0 && errno != ENODATA) {
67 fprintf(stderr,
68 "Unable to get capabilities of %s: %s\n",
69 fpath, strerror(errno));
70 if (single_file)
71 ret = 1;
72 }
73 rc = capng_have_capabilities(CAPNG_SELECT_CAPS);
74 if (rc == CAPNG_NONE) {
75 permitted = 1;
76 rc = capng_have_permitted_capabilities();
77 }
78 if (rc > CAPNG_NONE) {
79 if (header == 0) {
80 header = 1;
81 printf("%-9s %-20s capabilities rootid\n",
82 "set", "file");
83 }
84
85 int rootid = capng_get_rootid();
86 printf("%s %s ",
87 permitted ? "permitted" : "effective", fpath);
88
89 if (rc == CAPNG_FULL)
90 printf("full");
91 else
92 capng_print_caps_text(CAPNG_PRINT_STDOUT,
93 CAPNG_PERMITTED);
94
95 if (rootid != CAPNG_UNSET_ROOTID)
96 printf(" %d", rootid);
97 printf("\n");
98 }
99 close(fd);
100 }
101 return ret;
102 }
103
104
105 // Use cases:
106 // filecap
107 // filecap -a
108 // filecap /path/dir
109 // filecap /path/file
110 // filecap /path/file capability1 capability2 capability 3 ...
111 //
main(int argc,char * argv[])112 int main(int argc, char *argv[])
113 {
114 #if CAP_LAST_CAP < 31 || !defined (VFS_CAP_U32) || \
115 (!defined (HAVE_ATTR_XATTR_H) && !defined(HAVE_SYS_XATTR_H))
116 fprintf(stderr, "File based capabilities are not supported\n");
117 #else
118 char *path_env, *path = NULL, *dir = NULL;
119 struct stat sbuf;
120 int nftw_flags = FTW_PHYS;
121 int i, rc = 0;
122
123 if (argc >1) {
124 for (i=1; i<argc; i++) {
125 if (strcmp(argv[i], "-a") == 0) {
126 show_all = 1;
127 if (argc != 2)
128 usage();
129 } else if (strcmp(argv[i], "-d") == 0) {
130 int j;
131 for (j=0; j<=CAP_LAST_CAP; j++) {
132 const char *n =
133 capng_capability_to_name(j);
134 if (n == NULL)
135 n = "unknown";
136 printf("%s\n", n);
137 }
138 return 0;
139 } else if (argv[i][0] == '/') {
140 if (lstat(argv[i], &sbuf) != 0) {
141 fprintf(stderr,
142 "Error checking path %s (%s)\n",
143 argv[i], strerror(errno));
144 exit(1);
145 }
146 // Clear all capabilities in case cap strings
147 // follow. If we get a second file we err out
148 // so this is safe
149 if (S_ISREG(sbuf.st_mode) && path == NULL &&
150 dir == NULL) {
151 path = argv[i];
152 capng_clear(CAPNG_SELECT_BOTH);
153 } else if (S_ISDIR(sbuf.st_mode) && path == NULL
154 && dir == NULL)
155 dir = argv[i];
156 else {
157 fprintf(stderr,
158 "Must be one regular file or "
159 "directory\n");
160 exit(1);
161 }
162 } else {
163 int cap = capng_name_to_capability(argv[i]);
164 if (cap >= 0) {
165 if (path == NULL)
166 usage();
167 capng_update(CAPNG_ADD,
168 CAPNG_PERMITTED|CAPNG_EFFECTIVE,
169 cap);
170 capabilities = 1;
171 } else if (strcmp("none", argv[i]) == 0) {
172 capng_clear(CAPNG_SELECT_BOTH);
173 capabilities = 1;
174 cremove = 1;
175 } else {
176 fprintf(stderr,
177 "Unrecognized capability.\n");
178 usage();
179 }
180 }
181 }
182 }
183 if (path == NULL && dir == NULL && show_all == 0) {
184 path_env = getenv("PATH");
185 if (path_env != NULL) {
186 path = strdup(path_env);
187 if (!path)
188 return 1;
189 for (dir=strtok(path,":"); dir!=NULL;
190 dir=strtok(NULL,":")) {
191 nftw(dir, check_file, 1024, nftw_flags);
192 }
193 free(path);
194 }
195 } else if (path == NULL && dir == NULL && show_all == 1) {
196 // Find files
197 nftw("/", check_file, 1024, nftw_flags);
198 } else if (dir) {
199 // Print out the dir
200 nftw(dir, check_file, 1024, nftw_flags);
201 }else if (path && capabilities == 0) {
202 // Print out specific file
203 single_file = 1;
204 rc = check_file(path, &sbuf, 0, NULL);
205 } else if (path && capabilities == 1) {
206 // Write capabilities to file
207 int fd = open(path, O_WRONLY|O_NOFOLLOW|O_CLOEXEC);
208 if (fd < 0) {
209 fprintf(stderr,
210 "Could not open %s for writing (%s)\n", path,
211 strerror(errno));
212 return 1;
213 }
214 if (capng_apply_caps_fd(fd) < 0) {
215 fprintf(stderr,
216 "Could not set capabilities on %s: %s\n",
217 path, strerror(errno));
218 rc = 1;
219 }
220 close(fd);
221 }
222 #endif
223 return rc;
224 }
225
226