xref: /aosp_15_r20/external/libcap-ng/utils/filecap.c (revision 8dd5e09d5faf27a871e8654ddaa2d2af7c696578)
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