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