# HG changeset patch # User Thomas Klausner # Date 1558090759 -7200 # Node ID 0dff6a604b0a5f1ca86b73ccb8bc744b8f5dda9a # Parent 0f226d35501e6c8ce6a85f3fa203749a53418117 acl_wl: add reload support using SIGUSR1 diff -r 0f226d35501e -r 0dff6a604b0a doc/acl_wl.conf.sample --- a/doc/acl_wl.conf.sample Sun May 12 23:16:22 2019 +0800 +++ b/doc/acl_wl.conf.sample Fri May 17 12:59:19 2019 +0200 @@ -3,6 +3,11 @@ # This extension is meant to allow connection from remote peers, without actively # maintaining this connection ourselves (as it would be the case by declaring the # peer in a ConnectPeer directive). +# +# This extension supports configuration reload at runtime. Send +# signal SIGUSR1 to the process to cause the process to reload its +# config. +# # The format of this file is very simple. It contains a list of peer names # separated by spaces or newlines. # diff -r 0f226d35501e -r 0dff6a604b0a extensions/acl_wl/acl_wl.c --- a/extensions/acl_wl/acl_wl.c Sun May 12 23:16:22 2019 +0800 +++ b/extensions/acl_wl/acl_wl.c Fri May 17 12:59:19 2019 +0200 @@ -37,8 +37,17 @@ * Whitelist extension for freeDiameter. */ +#include +#include + #include "acl_wl.h" +static pthread_rwlock_t acl_wl_lock; + +#define MODULE_NAME "acl_wl" + +static char *acl_wl_config_file; + /* The validator function */ static int aw_validate(struct peer_info * info, int * auth, int (**cb2)(struct peer_info *)) { @@ -53,9 +62,20 @@ /* Default to unknown result */ *auth = 0; - + + if (pthread_rwlock_rdlock(&acl_wl_lock) != 0) { + fd_log_notice("%s: read-lock failed, skipping handler", MODULE_NAME); + return 0; + } + /* Now search the peer in our tree */ CHECK_FCT( aw_tree_lookup(info->pi_diamid, &res) ); + + if (pthread_rwlock_unlock(&acl_wl_lock) != 0) { + fd_log_notice("%s: read-unlock failed after aw_tree_lookup, exiting", MODULE_NAME); + exit(1); + } + if (res < 0) { /* The peer is not whitelisted */ return 0; @@ -87,20 +107,82 @@ return 0; } +static volatile int in_signal_handler = 0; + +/* signal handler */ +static void sig_hdlr(void) +{ + struct fd_list old_tree; + + if (in_signal_handler) { + fd_log_error("%s: already handling a signal, ignoring new one", MODULE_NAME); + return; + } + in_signal_handler = 1; + + if (pthread_rwlock_wrlock(&acl_wl_lock) != 0) { + fd_log_error("%s: locking failed, aborting config reload", MODULE_NAME); + return; + } + + /* save old config in case reload goes wrong */ + old_tree = tree_root; + fd_list_init(&tree_root, NULL); + + if (aw_conf_handle(acl_wl_config_file) != 0) { + fd_log_error("%s: error reloading configuration, restoring previous configuration", MODULE_NAME); + aw_tree_destroy(); + tree_root = old_tree; + } else { + struct fd_list new_tree; + new_tree = tree_root; + tree_root = old_tree; + aw_tree_destroy(); + tree_root = new_tree; + } + + if (pthread_rwlock_unlock(&acl_wl_lock) != 0) { + fd_log_error("%s: unlocking failed after config reload, exiting", MODULE_NAME); + exit(1); + } + + fd_log_notice("%s: reloaded configuration", MODULE_NAME); + + in_signal_handler = 0; +} + + /* entry point */ static int aw_entry(char * conffile) { TRACE_ENTRY("%p", conffile); CHECK_PARAMS(conffile); - + + acl_wl_config_file = conffile; + + pthread_rwlock_init(&acl_wl_lock, NULL); + + if (pthread_rwlock_wrlock(&acl_wl_lock) != 0) { + fd_log_notice("%s: write-lock failed, aborting", MODULE_NAME); + return EDEADLK; + } + /* Parse configuration file */ CHECK_FCT( aw_conf_handle(conffile) ); - + TRACE_DEBUG(INFO, "Extension ACL_wl initialized with configuration: '%s'", conffile); if (TRACE_BOOL(ANNOYING)) { aw_tree_dump(); } - + + if (pthread_rwlock_unlock(&acl_wl_lock) != 0) { + fd_log_notice("%s: write-unlock failed, aborting", MODULE_NAME); + return EDEADLK; + } + + /* Register reload callback */ + CHECK_FCT(fd_event_trig_regcb(SIGUSR1, MODULE_NAME, sig_hdlr)); + /* Register the validator function */ CHECK_FCT( fd_peer_validate_register ( aw_validate ) ); @@ -114,4 +196,4 @@ aw_tree_destroy(); } -EXTENSION_ENTRY("acl_wl", aw_entry); +EXTENSION_ENTRY(MODULE_NAME, aw_entry); diff -r 0f226d35501e -r 0dff6a604b0a extensions/acl_wl/acl_wl.h --- a/extensions/acl_wl/acl_wl.h Sun May 12 23:16:22 2019 +0800 +++ b/extensions/acl_wl/acl_wl.h Fri May 17 12:59:19 2019 +0200 @@ -43,6 +43,8 @@ #include +extern struct fd_list tree_root; + /* Parse the configuration file */ int aw_conf_handle(char * conffile); diff -r 0f226d35501e -r 0dff6a604b0a extensions/acl_wl/aw_conf.l --- a/extensions/acl_wl/aw_conf.l Sun May 12 23:16:22 2019 +0800 +++ b/extensions/acl_wl/aw_conf.l Fri May 17 12:59:19 2019 +0200 @@ -35,7 +35,7 @@ /* Lex extension's configuration parser. * - * The configuration file contains a default priority, and a list of peers with optional overwite priority. + * The configuration file contains a default priority, and a list of peers with optional overwrite priority. * -- see the app_test.conf.sample file for more detail. */ diff -r 0f226d35501e -r 0dff6a604b0a extensions/acl_wl/aw_conf.y --- a/extensions/acl_wl/aw_conf.y Sun May 12 23:16:22 2019 +0800 +++ b/extensions/acl_wl/aw_conf.y Fri May 17 12:59:19 2019 +0200 @@ -57,6 +57,7 @@ /* Forward declaration */ int yyparse(char * conffile); +void aw_confrestart(FILE *input_file); static int fqdn_added = 0; @@ -74,19 +75,20 @@ if (aw_confin == NULL) { ret = errno; fd_log_debug("Unable to open extension configuration file %s for reading: %s", conffile, strerror(ret)); - TRACE_DEBUG (INFO, "Error occurred, message logged -- configuration file."); + TRACE_DEBUG (INFO, "acl_wl: Error occurred, message logged -- configuration file."); return ret; } + aw_confrestart(aw_confin); ret = yyparse(conffile); fclose(aw_confin); if (ret != 0) { - TRACE_DEBUG (INFO, "Unable to parse the configuration file."); + TRACE_DEBUG (INFO, "acl_wl: Unable to parse the configuration file."); return EINVAL; } else { - TRACE_DEBUG(FULL, "Read %d FQDN entries successfully.", fqdn_added); + TRACE_DEBUG(FULL, "acl_wl: Read %d FQDN entries successfully.", fqdn_added); } return 0; @@ -98,7 +100,7 @@ /* Function to report the errors */ void yyerror (YYLTYPE *ploc, char * conffile, char const *s) { - TRACE_DEBUG(INFO, "Error in configuration parsing"); + TRACE_DEBUG(INFO, "acl_wl: Error in configuration parsing"); if (ploc->first_line != ploc->last_line) fd_log_debug("%s:%d.%d-%d.%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s); @@ -130,11 +132,11 @@ | conffile FQDN { fqdn_added++; - TRACE_DEBUG(FULL, "Added FQDN: %s", $2); + TRACE_DEBUG(FULL, "acl_wl: Added FQDN: %s", $2); } | conffile LEX_ERROR { - yyerror(&yylloc, conffile, "An error occurred while parsing the configuration file"); + yyerror(&yylloc, conffile, "acl_wl: An error occurred while parsing the configuration file"); return EINVAL; } ; diff -r 0f226d35501e -r 0dff6a604b0a extensions/acl_wl/aw_tree.c --- a/extensions/acl_wl/aw_tree.c Sun May 12 23:16:22 2019 +0800 +++ b/extensions/acl_wl/aw_tree.c Fri May 17 12:59:19 2019 +0200 @@ -69,9 +69,9 @@ }; /* The root of the tree */ -static struct fd_list tree_root = FD_LIST_INITIALIZER(tree_root); +struct fd_list tree_root = FD_LIST_INITIALIZER(tree_root); -/* Note: we don't need to lock, since we add only when parsing the conf, and then read only */ +/* Note: we lock accesses to the tree with acl_wl_lock because of config reload */ /* The parsed name */