1
0
mirror of https://github.com/rd235/cado synced 2025-06-05 21:59:29 +02:00

new feature: conditioned rules in cado.conf

This commit is contained in:
Renzo Davoli
2016-08-04 12:59:42 +02:00
parent 6aaa8cee2f
commit 32c1eb2ab3
5 changed files with 73 additions and 24 deletions

13
cado.c
View File

@@ -67,7 +67,7 @@ int main(int argc, char*argv[])
{ {
char *progname=basename(argv[0]); char *progname=basename(argv[0]);
char **user_groups=get_user_groups(); char **user_groups=get_user_groups();
uint64_t okcaps=get_authorized_caps(user_groups); uint64_t okcaps;
uint64_t reqcaps=0; uint64_t reqcaps=0;
uint64_t grantcap=0; uint64_t grantcap=0;
int verbose=0; int verbose=0;
@@ -95,7 +95,7 @@ int main(int argc, char*argv[])
fprintf(stderr, "setcap requires root access\n"); fprintf(stderr, "setcap requires root access\n");
exit(2); exit(2);
} }
okcaps = get_authorized_caps(NULL); okcaps = get_authorized_caps(NULL, -1LL);
okcaps |= 1ULL << CAP_DAC_READ_SEARCH; okcaps |= 1ULL << CAP_DAC_READ_SEARCH;
if (verbose) { if (verbose) {
printf("Capability needed by %s:\n", progname); printf("Capability needed by %s:\n", progname);
@@ -108,13 +108,12 @@ int main(int argc, char*argv[])
exit(0); exit(0);
} }
if (verbose) { if (verbose && (argc == optind)) {
okcaps=get_authorized_caps(user_groups, -1LL);
printf("Allowed ambient capabilities:\n"); printf("Allowed ambient capabilities:\n");
printcapset(okcaps, " "); printcapset(okcaps, " ");
}
if (verbose && (argc == optind))
exit(0); exit(0);
}
if (argc - optind < 2) if (argc - optind < 2)
usage(progname); usage(progname);
@@ -127,6 +126,8 @@ int main(int argc, char*argv[])
printcapset(reqcaps, " "); printcapset(reqcaps, " ");
} }
okcaps=get_authorized_caps(user_groups, reqcaps);
if (reqcaps & ~okcaps) { if (reqcaps & ~okcaps) {
if (verbose) { if (verbose) {
printf("Unavailable ambient capabilities:\n"); printf("Unavailable ambient capabilities:\n");

View File

@@ -13,6 +13,10 @@ Non-comment lines have the following syntax
.nf .nf
\fIlist_of_capabilities\fB:\fI list_of_users_and_groups\fR \fIlist_of_capabilities\fB:\fI list_of_users_and_groups\fR
.fi .fi
or
.nf
\fIlist_of_capabilities\fB:\fI list_of_users_and_groups\fB:\fR \fIlist_of_auth_commands\fR
.fi
Both \fIlist_of_capabilities\fR and \fIlist_of_users_and_groups\fR are comma separated lists of identifiers. Both \fIlist_of_capabilities\fR and \fIlist_of_users_and_groups\fR are comma separated lists of identifiers.
@@ -22,13 +26,18 @@ have the same meaning).
Items of \fIlist_of_users_and_groups\fR are usernames or groupnames (groupnames must be prefexed by '@'). Items of \fIlist_of_users_and_groups\fR are usernames or groupnames (groupnames must be prefexed by '@').
\fIlist_of_auth_commands\fR is a command or a list of commands separated by semicolon (;). If present, cado runs
all the sequence of commands it grants the capabilities as defined in the current line only if all return zero as
their exit status.
Example of \fBcado.conf\fR file: Example of \fBcado.conf\fR file:
.ni .nf
# Capability Ambient DO configuration file # Capability Ambient DO configuration file
# cado.conf # cado.conf
net_admin: @netadmin,renzo net_admin: @netadmin,renzo: /usr/bin/logger cado net_admin $USER; /bin/echo OK
net_admin: @privatenet: /usr/local/lib/cado_autorize_privatenet
net_admin,net_bind_service,net_raw,net_broadcast: @vxvdex net_admin,net_bind_service,net_raw,net_broadcast: @vxvdex
cap_kill: renzo cap_kill: renzo
.fi .fi

View File

@@ -13,6 +13,10 @@ AC_PROG_CC
AC_PROG_INSTALL AC_PROG_INSTALL
# Checks for libraries. # Checks for libraries.
AC_CHECK_LIB([s2argv], [s2argv], [],
[
AC_MSG_ERROR([Could not find S2ARGV library])
])
# Checks for header files. # Checks for header files.
AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h unistd.h]) AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h unistd.h])
@@ -22,6 +26,9 @@ AC_CHECK_HEADERS([sys/capability.h],
AC_CHECK_HEADERS([security/pam_appl.h security/pam_misc.h], AC_CHECK_HEADERS([security/pam_appl.h security/pam_misc.h],
[], [],
[AC_MSG_ERROR([missing PAM headers])]) [AC_MSG_ERROR([missing PAM headers])])
AC_CHECK_HEADERS([s2argv.h],
[],
[AC_MSG_ERROR([missing S2ARGV headers])])
# Checks for typedefs, structures, and compiler characteristics. # Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_UID_T AC_TYPE_UID_T

View File

@@ -25,9 +25,11 @@
#include <unistd.h> #include <unistd.h>
#include <ctype.h> #include <ctype.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/prctl.h>
#include <read_conf.h> #include <read_conf.h>
#include <set_ambient_cap.h> #include <set_ambient_cap.h>
#include <capset_from_namelist.h> #include <capset_from_namelist.h>
#include <s2argv.h>
#ifndef CONFDIR #ifndef CONFDIR
#define CONFDIR "/etc" #define CONFDIR "/etc"
@@ -35,6 +37,7 @@
#define CADO_CONF CONFDIR "/cado.conf" #define CADO_CONF CONFDIR "/cado.conf"
/* groupmatch returns 1 if group belongs to grouplist */
static int groupmatch (char *group, char **grouplist) { static int groupmatch (char *group, char **grouplist) {
for (;*grouplist; grouplist++) { for (;*grouplist; grouplist++) {
//printf("%s %s\n",group, *grouplist); //printf("%s %s\n",group, *grouplist);
@@ -44,62 +47,91 @@ static int groupmatch (char *group, char **grouplist) {
return 0; return 0;
} }
uint64_t get_authorized_caps(char **user_groups) { /* s2argv security, children must drop their capabilities */
static int drop_capabilities(void *useless) {
return prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
}
/* get_authorized_caps returns the set of authorized capabilities
for the user user_groups[0] belonging to the groups user_groups[1:] */
/* if user_groups==NULL, get_authorized_caps computes the maximum set
of capabilities that cado itself must own to be able to assign */
uint64_t get_authorized_caps(char **user_groups, uint64_t reqset) {
uint64_t ok_caps=0; uint64_t ok_caps=0;
FILE *f; FILE *f;
/* cado.conf is not readble by users. Add the capability to do it */
if (user_groups) raise_cap_dac_read_search(); if (user_groups) raise_cap_dac_read_search();
f=fopen(CADO_CONF, "r"); f=fopen(CADO_CONF, "r");
if (f) { if (f) {
char *line=NULL; char *line=NULL;
ssize_t len,n=0; ssize_t len,n=0;
while ((len=getline(&line, &n, f)) > 0) { /* set s2argv security, children must drop their capabilities */
s2_fork_security=drop_capabilities;
while ((len=getline(&line, &n, f)) > 0 && (reqset & ~ok_caps)) {
//printf("%s",line); //printf("%s",line);
char *scan=line; char *scan=line;
char *tokencap;
char *tokenusergroup;
char *tokencondition;
char *tok; char *tok;
uint64_t capset; uint64_t capset;
char *tmptok; char *tmptok;
int usermatch=0;
/* skip leading spaces */
while (isspace(*scan)) scan++; while (isspace(*scan)) scan++;
if (*scan == 0 || *scan == '#') //comment if (*scan == 0 || *scan == '#') //comment
continue; continue;
tok=strtok_r(scan, ":", &tmptok); tokencap=strtok_r(scan, ":", &tmptok);
//printf("%s\n",tok); //printf("CAP %s\n",tokencap);
tokenusergroup=strtok_r(NULL, ":\n", &tmptok);
//printf("UG %s\n",tokenusergroup);
tokencondition=strtok_r(NULL, ":\n", &tmptok);
//printf("COND %s\n",tokencondition);
capset=0; capset=0;
if (capset_from_namelist(tok, &capset) < 0) if (capset_from_namelist(tokencap, &capset) < 0)
continue; continue;
if (user_groups == NULL) { if (user_groups == NULL) {
ok_caps |= capset; ok_caps |= capset;
continue; continue;
} }
//printf("CAP %s %d\n",tok,thiscap); //printf("CAP %s %d\n",tok,thiscap);
while ((tok=strtok_r(NULL, ",\n ",&tmptok)) != NULL) { while ((tok=strtok_r(tokenusergroup, ",\n ",&tmptok)) != NULL) {
//printf("XX %s\n",tok); //printf("XX %s\n",tok);
if (*tok=='@') { if (*tok=='@') {
if (groupmatch(tok+1, user_groups+1)) { if (groupmatch(tok+1, user_groups+1)) {
ok_caps |= capset; usermatch = 1;
break; break;
} }
} else if (strcmp(tok, user_groups[0]) == 0) { } else if (strcmp(tok, user_groups[0]) == 0) {
ok_caps |= capset; usermatch = 1;
break; break;
} }
tokenusergroup=NULL;
}
if (usermatch) {
if (tokencondition) {
if (system_execsa(tokencondition) == 0)
ok_caps |= capset;
} else
ok_caps |= capset;
} }
} }
fclose(f); fclose(f);
if (line) if (line)
free(line); free(line);
} }
/* the capability to read cado.conf is no longer needed */
if (user_groups) lower_cap_dac_read_search(); if (user_groups) lower_cap_dac_read_search();
return ok_caps; return ok_caps;
} }
/* set_self_capability sets the capability set needed by cado itself */
int set_self_capability(uint64_t capset) { int set_self_capability(uint64_t capset) {
cap_value_t cap; cap_value_t cap;
cap_t caps=cap_init(); cap_t caps=cap_init();
int f,rv=-1; int f,rv=-1;
for (cap = 0; cap <= CAP_LAST_CAP; cap++) { for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
if (capset & (1ULL << cap)) { if (capset & (1ULL << cap)) {
/*if (cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_SET) ||
cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET)) {*/
if (cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_SET)) { if (cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_SET)) {
fprintf(stderr, "Cannot set permitted cap %s\n",cap_to_name(cap)); fprintf(stderr, "Cannot set permitted cap %s\n",cap_to_name(cap));
exit(2); exit(2);

View File

@@ -2,7 +2,7 @@
#define READ_CONF_H #define READ_CONF_H
#include <stdint.h> #include <stdint.h>
uint64_t get_authorized_caps(char **user_groups); uint64_t get_authorized_caps(char **user_groups, uint64_t reqset);
int set_self_capability(uint64_t capset); int set_self_capability(uint64_t capset);