summaryrefslogtreecommitdiff
path: root/progs/setcap.c
diff options
context:
space:
mode:
Diffstat (limited to 'progs/setcap.c')
-rw-r--r--progs/setcap.c185
1 files changed, 185 insertions, 0 deletions
diff --git a/progs/setcap.c b/progs/setcap.c
new file mode 100644
index 0000000..0215fc4
--- /dev/null
+++ b/progs/setcap.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 1997,2007-8 Andrew G. Morgan <morgan@kernel.org>
+ *
+ * This sets/verifies the capabilities of a given file.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/capability.h>
+#include <unistd.h>
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "usage: setcap [-q] [-v] (-r|-|<caps>) <filename> "
+ "[ ... (-r|-|<capsN>) <filenameN> ]\n"
+ "\n"
+ " Note <filename> must be a regular (non-symlink) file.\n"
+ );
+ exit(1);
+}
+
+#define MAXCAP 2048
+
+static int read_caps(int quiet, const char *filename, char *buffer)
+{
+ int i=MAXCAP;
+
+ if (!quiet) {
+ fprintf(stderr, "Please enter caps for file [empty line to end]:\n");
+ }
+ while (i > 0) {
+ int j = read(STDIN_FILENO, buffer, i);
+
+ if (j < 0) {
+ fprintf(stderr, "\n[Error - aborting]\n");
+ exit(1);
+ }
+
+ if (j==0 || buffer[0] == '\n') {
+ /* we're done */
+ break;
+ }
+
+ /* move on... */
+
+ i -= j;
+ buffer += j;
+ }
+
+ /* <NUL> terminate */
+ buffer[0] = '\0';
+
+ return (i < MAXCAP ? 0:-1);
+}
+
+int main(int argc, char **argv)
+{
+ int tried_to_cap_setfcap = 0;
+ char buffer[MAXCAP+1];
+ int retval, quiet=0, verify=0;
+ cap_t mycaps;
+ cap_value_t capflag;
+
+ if (argc < 3) {
+ usage();
+ }
+
+ mycaps = cap_get_proc();
+ if (mycaps == NULL) {
+ fprintf(stderr, "warning - unable to get process capabilities"
+ " (old libcap?)\n");
+ }
+
+ while (--argc > 0) {
+ const char *text;
+ cap_t cap_d;
+
+ if (!strcmp(*++argv, "-q")) {
+ quiet = 1;
+ continue;
+ }
+ if (!strcmp(*argv, "-v")) {
+ verify = 1;
+ continue;
+ }
+
+ if (!strcmp(*argv, "-r")) {
+ cap_d = NULL;
+ } else {
+ if (!strcmp(*argv,"-")) {
+ retval = read_caps(quiet, *argv, buffer);
+ if (retval)
+ usage();
+ text = buffer;
+ } else {
+ text = *argv;
+ }
+
+ cap_d = cap_from_text(text);
+ if (cap_d == NULL) {
+ perror("fatal error");
+ usage();
+ }
+#ifdef DEBUG
+ {
+ ssize_t length;
+ const char *result;
+
+ result = cap_to_text(cap_d, &length);
+ fprintf(stderr, "caps set to: [%s]\n", result);
+ }
+#endif
+ }
+
+ if (--argc <= 0)
+ usage();
+ /*
+ * Set the filesystem capability for this file.
+ */
+ if (verify) {
+ cap_t cap_on_file;
+ int cmp;
+
+ if (cap_d == NULL) {
+ cap_d = cap_from_text("=");
+ }
+
+ cap_on_file = cap_get_file(*++argv);
+
+ if (cap_on_file == NULL) {
+ cap_on_file = cap_from_text("=");
+ }
+
+ cmp = cap_compare(cap_on_file, cap_d);
+ cap_free(cap_on_file);
+
+ if (cmp != 0) {
+ if (!quiet) {
+ printf("%s differs in [%s%s%s]\n", *argv,
+ CAP_DIFFERS(cmp, CAP_PERMITTED) ? "p" : "",
+ CAP_DIFFERS(cmp, CAP_INHERITABLE) ? "i" : "",
+ CAP_DIFFERS(cmp, CAP_EFFECTIVE) ? "e" : "");
+ }
+ exit(1);
+ }
+ if (!quiet) {
+ printf("%s: OK\n", *argv);
+ }
+ } else {
+ if (!tried_to_cap_setfcap) {
+ capflag = CAP_SETFCAP;
+
+ /*
+ * Raise the effective CAP_SETFCAP.
+ */
+ if (cap_set_flag(mycaps, CAP_EFFECTIVE, 1, &capflag, CAP_SET)
+ != 0) {
+ perror("unable to manipulate CAP_SETFCAP - "
+ "try a newer libcap?");
+ exit(1);
+ }
+ if (cap_set_proc(mycaps) != 0) {
+ perror("unable to set CAP_SETFCAP effective capability");
+ exit(1);
+ }
+ tried_to_cap_setfcap = 1;
+ }
+ retval = cap_set_file(*++argv, cap_d);
+ if (retval != 0) {
+ fprintf(stderr,
+ "Failed to set capabilities on file `%s' (%s)\n",
+ argv[0], strerror(errno));
+ usage();
+ }
+ }
+ if (cap_d) {
+ cap_free(cap_d);
+ }
+ }
+
+ exit(0);
+}