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:
13
cado.c
13
cado.c
@@ -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");
|
||||||
|
13
cado.conf.5
13
cado.conf.5
@@ -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
|
||||||
|
@@ -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
|
||||||
|
52
read_conf.c
52
read_conf.c
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user