diff --git a/Makefile.am b/Makefile.am
index 47f4a41..6778763 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,10 +1,14 @@
-bin_PROGRAMS = cado scado caprint
+bin_PROGRAMS = cado cadrop scado caprint
cado_SOURCES = cado.c pam_check.c get_user_groups.c capset_from_namelist.c read_conf.c set_ambient_cap.c \
compute_digest.c file_utils.c scado_parse.c cado_scado_check.c
cado_LDADD = -lpam -lpam_misc -lcap -lmhash
+cadrop_SOURCES = cadrop.c capset_from_namelist.c set_ambient_cap.c
+
+cadrop_LDADD = -lcap
+
caprint_LDADD = -lcap
scado_SOURCES = scado.c pam_check.c file_utils.c compute_digest.c capset_from_namelist.c scado_parse.c
@@ -14,7 +18,7 @@ scado_LDADD = -lpam -lpam_misc -lcap -lmhash
common_nodist = cado_paths.h
BUILT_SOURCES = $(common_nodist)
-man_MANS = cado.1 caprint.1 scado.1 cado.conf.5
+man_MANS = cado.1 cadrop.1 caprint.1 scado.1 cado.conf.5
install-exec-hook:
(useradd -r -s /bin/nologin -g `getent passwd | grep cado | cut -f 3 -d ':'` cado ||\
diff --git a/cadrop.1 b/cadrop.1
new file mode 100644
index 0000000..ec9d360
--- /dev/null
+++ b/cadrop.1
@@ -0,0 +1,30 @@
+.TH CADROP 1 "November 26, 2016" "VirtualSquare Labs"
+.SH NAME
+cadrop \- Capability Ambient Drop
+.SH SYNOPSIS
+.B cadrop
+[
+.I capability_list
+[
+.I command
+[
+.I args
+]
+]
+]
+
+.SH DESCRIPTION
+Cadrop permits to drop (ambient) capabilities.
+
+Cadrop launches the command indicated as a parameter ($SHELL if omitted) dropping all the capabilities
+listed in the capability_list.
+
+If the capability_list is also omitted or it matches one of the string "all" or "-", cadrop drops all the capabilities.
+
+.SH SEE ALSO
+\fBcado\fR(1),
+\fBcaprint\fR(1),
+\fBscado\fR(1),
+\fBcado.conf\fR(5),
+\fBcapabilities\fR(7)
+
diff --git a/cadrop.c b/cadrop.c
new file mode 100644
index 0000000..e371794
--- /dev/null
+++ b/cadrop.c
@@ -0,0 +1,66 @@
+/*
+ * cado: execute a command in a capability ambient
+ * Copyright (C) 2016 Renzo Davoli, Davide Berardi, University of Bologna
+ *
+ * This file is part of cado.
+ *
+ * Cado is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, 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; If not, see .
+ *
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+static int argv1_all(char *s) {
+ if (s == NULL)
+ return 1;
+ if (strcmp(s,"") == 0)
+ return 1;
+ if (strcmp(s,"-") == 0)
+ return 1;
+ if (strcmp(s,"all") == 0)
+ return 1;
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ uint64_t capset = -1;
+ char *argvsh[]={getenv("SHELL"),NULL};
+ switch (argc) {
+ case 1:
+ capset = -1;
+ argv += 1;
+ break;
+ default:
+ if (argv1_all(argv[1]))
+ capset = -1;
+ else if (capset_from_namelist(argv[1], &capset) < 0) {
+ fprintf(stderr, "error parsing capabilities\n");
+ exit(2);
+ }
+ argv+=2;
+ break;
+ }
+ if (*argv == NULL) argv = argvsh;
+ drop_ambient_cap(capset);
+ execvp(argv[0],argv);
+ perror("exec");
+ return 2;
+}
+
diff --git a/set_ambient_cap.c b/set_ambient_cap.c
index b5fc57f..8f71786 100644
--- a/set_ambient_cap.c
+++ b/set_ambient_cap.c
@@ -62,6 +62,32 @@ void set_ambient_cap(uint64_t capset)
}
}
+/* drop the capabilities of the capset */
+
+void drop_ambient_cap(uint64_t capset) {
+ cap_value_t cap;
+ cap_t caps=cap_get_proc();
+ for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
+ if (capset & (1ULL << cap)) {
+ if (cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_CLEAR)) {
+ fprintf(stderr, "Cannot clear inheritable cap %s\n",cap_to_name(cap));
+ exit(2);
+ }
+ }
+ }
+ cap_set_proc(caps);
+ cap_free(caps);
+
+ for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
+ if ((capset & (1ULL << cap))) {
+ if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, cap, 0, 0)) {
+ perror("Cannot set cap");
+ exit(1);
+ }
+ }
+ }
+}
+
/* turn cap_dac_read_search on and off to have "extra" powers only when needed */
void raise_cap_dac_read_search(void) {
cap_value_t cap=CAP_DAC_READ_SEARCH;
diff --git a/set_ambient_cap.h b/set_ambient_cap.h
index 55e1f06..d696c5f 100644
--- a/set_ambient_cap.h
+++ b/set_ambient_cap.h
@@ -1,8 +1,11 @@
#ifndef SET_AMBIENT_CAP_H
#define SET_AMBIENT_CAP_H
+#include
void set_ambient_cap(uint64_t capset);
+void drop_ambient_cap(uint64_t capset);
+
void raise_cap_dac_read_search(void);
void lower_cap_dac_read_search(void);