You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
4.7 KiB
185 lines
4.7 KiB
/*
|
|
* filecap.c - A program that lists running processes with capabilities
|
|
* Copyright (c) 2009-10 Red Hat Inc., Durham, North Carolina.
|
|
* All Rights Reserved.
|
|
*
|
|
* This software may be freely redistributed and/or modified under the
|
|
* terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2, or (at your option) any
|
|
* later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to the
|
|
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* Authors:
|
|
* Steve Grubb <sgrubb@redhat.com>
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include "cap-ng.h"
|
|
#define __USE_GNU 1
|
|
#include <fcntl.h>
|
|
#define __USE_XOPEN_EXTENDED 1
|
|
#include <ftw.h>
|
|
|
|
static int show_all = 0, header = 0, capabilities = 0, cremove = 0;
|
|
|
|
static void usage(void)
|
|
{
|
|
fprintf(stderr,
|
|
"usage: filecap [-a | -d | /dir | /dir/file [cap1 cap2 ...] ]\n");
|
|
exit(1);
|
|
}
|
|
|
|
static int check_file(const char *fpath,
|
|
const struct stat *sb,
|
|
int typeflag_unused __attribute__ ((unused)),
|
|
struct FTW *s_unused __attribute__ ((unused)))
|
|
{
|
|
if (S_ISREG(sb->st_mode) == 0)
|
|
return FTW_CONTINUE;
|
|
|
|
int fd = open(fpath, O_RDONLY|O_CLOEXEC);
|
|
if (fd >= 0) {
|
|
capng_results_t rc;
|
|
|
|
capng_clear(CAPNG_SELECT_BOTH);
|
|
capng_get_caps_fd(fd);
|
|
rc = capng_have_capabilities(CAPNG_SELECT_CAPS);
|
|
if (rc > CAPNG_NONE) {
|
|
if (header == 0) {
|
|
header = 1;
|
|
printf("%-20s capabilities\n", "file");
|
|
}
|
|
printf("%s ", fpath);
|
|
if (rc == CAPNG_FULL)
|
|
printf("full");
|
|
else
|
|
capng_print_caps_text(CAPNG_PRINT_STDOUT,
|
|
CAPNG_PERMITTED);
|
|
printf("\n");
|
|
}
|
|
close(fd);
|
|
}
|
|
return FTW_CONTINUE;
|
|
}
|
|
|
|
|
|
// Use cases:
|
|
// filecap
|
|
// filecap -a
|
|
// filecap /path/dir
|
|
// filecap /path/file
|
|
// filecap /path/file capability1 capability2 capability 3 ...
|
|
//
|
|
int main(int argc, char *argv[])
|
|
{
|
|
#if CAP_LAST_CAP < 31 || !defined (VFS_CAP_U32) || !defined (HAVE_ATTR_XATTR_H)
|
|
printf("File based capabilities are not supported\n");
|
|
#else
|
|
char *path_env, *path = NULL, *dir = NULL;
|
|
struct stat sbuf;
|
|
int nftw_flags = FTW_PHYS;
|
|
int i;
|
|
|
|
if (argc >1) {
|
|
for (i=1; i<argc; i++) {
|
|
if (strcmp(argv[i], "-a") == 0) {
|
|
show_all = 1;
|
|
if (argc != 2)
|
|
usage();
|
|
} else if (strcmp(argv[i], "-d") == 0) {
|
|
for (i=0; i<=CAP_LAST_CAP; i++) {
|
|
const char *n =
|
|
capng_capability_to_name(i);
|
|
if (n == NULL)
|
|
n = "unknown";
|
|
printf("%s\n", n);
|
|
}
|
|
return 0;
|
|
} else if (argv[i][0] == '/') {
|
|
if (lstat(argv[i], &sbuf) != 0) {
|
|
printf("Error checking path %s (%s)\n",
|
|
argv[i], strerror(errno));
|
|
exit(1);
|
|
}
|
|
// Clear all capabilities in case cap strings
|
|
// follow. If we get a second file we err out
|
|
// so this is safe
|
|
if (S_ISREG(sbuf.st_mode) && path == NULL &&
|
|
dir == NULL) {
|
|
path = argv[i];
|
|
capng_clear(CAPNG_SELECT_BOTH);
|
|
} else if (S_ISDIR(sbuf.st_mode) && path == NULL
|
|
&& dir == NULL)
|
|
dir = argv[i];
|
|
else {
|
|
printf("Must be one regular file or "
|
|
"directory\n");
|
|
exit(1);
|
|
}
|
|
} else {
|
|
int cap = capng_name_to_capability(argv[i]);
|
|
if (cap >= 0) {
|
|
if (path == NULL)
|
|
usage();
|
|
capng_update(CAPNG_ADD,
|
|
CAPNG_PERMITTED|CAPNG_EFFECTIVE,
|
|
cap);
|
|
capabilities = 1;
|
|
} else if (strcmp("none", argv[i]) == 0) {
|
|
capng_clear(CAPNG_SELECT_BOTH);
|
|
capabilities = 1;
|
|
cremove = 1;
|
|
} else {
|
|
printf("Unrecognized capability.\n");
|
|
usage();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (path == NULL && dir == NULL && show_all == 0) {
|
|
path_env = getenv("PATH");
|
|
if (path_env != NULL) {
|
|
path = strdup(path_env);
|
|
for (dir=strtok(path,":"); dir!=NULL;
|
|
dir=strtok(NULL,":")) {
|
|
nftw(dir, check_file, 1024, nftw_flags);
|
|
}
|
|
free(path);
|
|
}
|
|
} else if (path == NULL && dir == NULL && show_all == 1) {
|
|
// Find files
|
|
nftw("/", check_file, 1024, nftw_flags);
|
|
} else if (dir) {
|
|
// Print out the dir
|
|
nftw(dir, check_file, 1024, nftw_flags);
|
|
}else if (path && capabilities == 0) {
|
|
// Print out specific file
|
|
check_file(path, &sbuf, 0, NULL);
|
|
} else if (path && capabilities == 1) {
|
|
// Write capabilities to file
|
|
int fd = open(path, O_WRONLY|O_NOFOLLOW|O_CLOEXEC);
|
|
if (fd < 0) {
|
|
printf("Could not open %s for writing (%s)\n", path,
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
capng_apply_caps_fd(fd);
|
|
close(fd);
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|