From 04d67b3bab42437a83f27f18bc7d1951395142d4 Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 1 Jun 2012 14:48:34 +0100 Subject: [PATCH] acls: Add a default-deny option, which allows you to specify what an empty ACL means. When this option is specified, an empty ACL means "reject all clients". Without it, an empty ACL means "accept all clients" --- src/flexnbd.c | 20 ++++++++++++++++---- src/options.h | 9 +++++++-- src/params.h | 2 ++ src/serve.c | 21 ++++++++++++++++----- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/flexnbd.c b/src/flexnbd.c index 1acb911..996cd37 100644 --- a/src/flexnbd.c +++ b/src/flexnbd.c @@ -48,6 +48,7 @@ void params_serve( char* s_port, char* s_file, char *s_ctrl_sock, + int default_deny, int acl_entries, char** s_acl_entries /* first may actually be path to control socket */ ) @@ -71,6 +72,10 @@ void params_serve( * we pass NULL. */ out->control_socket_name = s_ctrl_sock; + /* If this is true then an empty ACL means "nobody is allowed to connect", + * rather than "anybody is allowed to connect" */ + out->default_deny = default_deny; + out->acl_entries = acl_entries; parsed = parse_acl(&out->acl, acl_entries, s_acl_entries); if (parsed != acl_entries) @@ -161,7 +166,8 @@ void do_read(struct mode_readwrite_params* params); void do_write(struct mode_readwrite_params* params); void do_remote_command(char* command, char* mode, int argc, char** argv); -void read_serve_param( int c, char **ip_addr, char **ip_port, char **file, char **sock ) +void read_serve_param( int c, char **ip_addr, char **ip_port, char **file, char **sock, int *default_deny ) + { switch(c){ case 'h': @@ -180,6 +186,9 @@ void read_serve_param( int c, char **ip_addr, char **ip_port, char **file, char case 's': *sock = optarg; break; + case 'D': + *default_deny = 1; + break; default: exit_err( serve_help_text ); break; @@ -267,14 +276,17 @@ int mode_serve( int argc, char *argv[] ) char *ip_port = NULL; char *file = NULL; char *sock = NULL; + int default_deny = 0; // not on by default int err = 0; struct mode_serve_params serve; while (1) { c = getopt_long(argc, argv, serve_short_options, serve_options, NULL); - if ( c == -1 ) break; - read_serve_param( c, &ip_addr, &ip_port, &file, &sock ); + if ( c == -1 ) + break; + + read_serve_param( c, &ip_addr, &ip_port, &file, &sock, &default_deny ); } if ( NULL == ip_addr || NULL == ip_port ) { @@ -288,7 +300,7 @@ int mode_serve( int argc, char *argv[] ) if ( err ) { exit_err( serve_help_text ); } memset( &serve, 0, sizeof( serve ) ); - params_serve( &serve, ip_addr, ip_port, file, sock, argc - optind, argv + optind ); + params_serve( &serve, ip_addr, ip_port, file, sock, default_deny, argc - optind, argv + optind ); do_serve( &serve ); return 0; diff --git a/src/options.h b/src/options.h index 6dee399..85c676c 100644 --- a/src/options.h +++ b/src/options.h @@ -8,6 +8,7 @@ #define OPT_SOCK "sock" #define OPT_FROM "from" #define OPT_SIZE "size" +#define OPT_DENY "default-deny" #define CMD_SERVE "serve" #define CMD_READ "read" @@ -16,7 +17,7 @@ #define CMD_MIRROR "mirror" #define CMD_STATUS "status" #define CMD_HELP "help" -#define LEN_CMD_MAX 6 +#define LEN_CMD_MAX 7 #define PATH_LEN_MAX 1024 #define ADDR_LEN_MAX 64 @@ -25,6 +26,8 @@ #define IS_CMD(x,c) (strncmp((x),(c),(LEN_CMD_MAX)) == 0) #define GETOPT_HELP GETOPT_FLAG( OPT_HELP, 'h' ) +#define GETOPT_DENY GETOPT_FLAG( OPT_DENY, 'D' ) + #define GETOPT_ADDR GETOPT_ARG( OPT_ADDR, 'l' ) #define GETOPT_PORT GETOPT_ARG( OPT_PORT, 'p' ) #define GETOPT_FILE GETOPT_ARG( OPT_FILE, 'f' ) @@ -38,9 +41,10 @@ static struct option serve_options[] = { GETOPT_PORT, GETOPT_FILE, GETOPT_SOCK, + GETOPT_DENY, {0} }; -static char serve_short_options[] = "hl:p:f:s:"; +static char serve_short_options[] = "Dhl:p:f:s:"; static char serve_help_text[] = "Usage: flexnbd " CMD_SERVE " [*]\n\n" "Serve FILE from ADDR:PORT, with an optional control socket at SOCK.\n\n" @@ -48,6 +52,7 @@ static char serve_help_text[] = "\t--" OPT_ADDR ",-l \tThe address to serve on.\n" "\t--" OPT_PORT ",-p \tThe port to serve on.\n" "\t--" OPT_FILE ",-f \tThe file to serve.\n" + "\t--" OPT_DENY ",-D\tDeny connections by default unless in ACL\n" "\t--" OPT_SOCK ",-s \tPath to the control socket to open.\n"; static struct option read_options[] = { diff --git a/src/params.h b/src/params.h index 98d9325..db7dc94 100644 --- a/src/params.h +++ b/src/params.h @@ -34,6 +34,8 @@ struct control_params { struct mode_serve_params { /** address/port to bind to */ union mysockaddr bind_to; + /** does an empty ACL mean "deny all"? */ + int default_deny; /** number of entries in current access control list*/ int acl_entries; /** pointer to access control list entries*/ diff --git a/src/serve.c b/src/serve.c index a83d53f..1dbe628 100644 --- a/src/serve.c +++ b/src/serve.c @@ -452,6 +452,8 @@ void accept_nbd_client(struct mode_serve_params* params, int client_fd, union my struct client_params* client_params; int slot = cleanup_and_find_client_slot(params); char s_client_address[64]; + int acl_passed = 0; + if (inet_ntop(client_address->generic.sa_family, sockaddr_address_data(&client_address->generic), s_client_address, 64) == NULL) { write(client_fd, "Bad client_address", 18); @@ -459,12 +461,21 @@ void accept_nbd_client(struct mode_serve_params* params, int client_fd, union my return; } - if (params->acl && - !is_included_in_acl(params->acl_entries, params->acl, client_address)) { - write(client_fd, "Access control error", 20); - close(client_fd); - return; + + if (params->acl) { + if (is_included_in_acl(params->acl_entries, params->acl, client_address)) + acl_passed = 1; + } else { + if (!params->default_deny) + acl_passed = 1; } + + if (!acl_passed) { + write(client_fd, "Access control error", 20); + close(client_fd); + return; + } + if (slot < 0) { write(client_fd, "Too many clients", 16);