diff --git a/CHANGELOG.md b/CHANGELOG.md index 47611218..5672d37a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,23 @@ ## 4.9.0 Expected: 15 Dec 2020 +### New features + +* Restconf configuration has a new configure model: `clixon-restconf.yang` enabling restconf daemon configuration from datastore instead of from config file. + * Restconf config data, such as addresses, authentication type, etc, is read from the backend datastore instead of the clixon-config file on startup. + * This is enabled by setting `CLIXON_RESTCONF_CONFIG` to true (or start clixon-restconf with `-b`), in which case restconf data can be set in the datastore. + * This only applies to the evhtp restconf daemon, not fcgi/nginx. + * If enabled, most RESTCONF clixon-config options are obsolete + * Thanks to Dave Cornejo for the idea + * Example: instead of setting `file` in clixon.xml, set: `arestconf>file` in the running datastore before starting restconf. + +### API changes on existing protocol/config features + +Users may have to change how they access the system + +* New clixon-config@2020-11-03.yang revision + * Added option: `CLICON_RESTCONF_CONFIG` for reading restconf daemon config frm datastore + ### Minor changes * Added new backend plugin: ca_pre-demon called if backend is daemonized just prior to forking. diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index 0c56c84b..558e35db 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -262,7 +262,7 @@ autocli_tree(clicon_handle h, enum genmodel_type gt, int state, int printgen, - int show_tree) + int show_tree) { int retval = -1; parse_tree *pt = NULL; /* cli parse tree */ diff --git a/apps/restconf/restconf_main_evhtp.c b/apps/restconf/restconf_main_evhtp.c index 73494c85..fc8316f8 100644 --- a/apps/restconf/restconf_main_evhtp.c +++ b/apps/restconf/restconf_main_evhtp.c @@ -79,26 +79,35 @@ #include "restconf_err.h" #include "restconf_root.h" + /* Command line options to be passed to getopt(3) */ -#define RESTCONF_OPTS "hD:f:E:l:p:d:y:a:u:ro:scP:" +#define RESTCONF_OPTS "hD:f:E:l:p:d:y:a:u:ro:bscP:" /* See see listen(5) */ #define SOCKET_LISTEN_BACKLOG 16 -/* Need global variable to for signal handler XXX */ -static clicon_handle _CLICON_HANDLE = NULL; - -static struct evhtp_handle{ +/* clixon evhtp handle */ +typedef struct { evhtp_t *eh_htp; struct event_base *eh_evbase; evhtp_ssl_cfg_t *eh_ssl_config; -} _EVHTP_HANDLE = {0,}; +} cx_evhtp_handle; + +/* Need this global to pass to signal handler + * XXX Try to get rid of code in signal handler + */ +static cx_evhtp_handle *_EVHTP_HANDLE = NULL; + +/* Need global variable to for signal handler XXX */ +static clicon_handle _CLICON_HANDLE = NULL; static void -evhtp_terminate(struct evhtp_handle *eh) +evhtp_terminate(cx_evhtp_handle *eh) { evhtp_ssl_cfg_t *sc; + if (eh == NULL) + return; if (eh->eh_htp){ evhtp_unbind_socket(eh->eh_htp); evhtp_free(eh->eh_htp); @@ -114,9 +123,11 @@ evhtp_terminate(struct evhtp_handle *eh) free(sc->privfile); free(sc); } + free(eh); } /*! Signall terminates process + * XXX Try to get rid of code in signal handler -> so we can get rid of global variables */ static void restconf_sig_term(int arg) @@ -128,7 +139,8 @@ restconf_sig_term(int arg) __PROGRAM__, __FUNCTION__, getpid(), arg); else exit(-1); - evhtp_terminate(&_EVHTP_HANDLE); + if (_EVHTP_HANDLE) /* global */ + evhtp_terminate(_EVHTP_HANDLE); if (_CLICON_HANDLE){ // stream_child_freeall(_CLICON_HANDLE); restconf_terminate(_CLICON_HANDLE); @@ -492,9 +504,84 @@ cx_path_restconf(evhtp_request_t *req, return; /* void */ } +/*! Get Server cert ssl info + * @param[in] h Clicon handle + * @param[in] server_cert_path Path to server ssl cert file + * @param[in] server_key_path Path to server ssl key file + * @param[in,out] ssl_config evhtp ssl config struct + * @retval 0 OK + * @retval -1 Error + */ +static int +cx_get_ssl_server_certs(clicon_handle h, + const char *server_cert_path, + const char *server_key_path, + evhtp_ssl_cfg_t *ssl_config) +{ + int retval = -1; + struct stat f_stat; + + if (ssl_config == NULL || server_cert_path == NULL){ + clicon_err(OE_CFG, EINVAL, "Input parameter is NULL"); + goto done; + } + if ((ssl_config->pemfile = strdup(server_cert_path)) == NULL){ + clicon_err(OE_CFG, errno, "strdup"); + goto done; + } + if (stat(ssl_config->pemfile, &f_stat) != 0) { + clicon_err(OE_FATAL, errno, "Cannot load SSL cert '%s'", ssl_config->pemfile); + goto done; + } + if ((ssl_config->privfile = strdup(server_key_path)) == NULL){ + clicon_err(OE_CFG, errno, "strdup"); + goto done; + } + if (stat(ssl_config->privfile, &f_stat) != 0) { + clicon_err(OE_FATAL, errno, "Cannot load SSL key '%s'", ssl_config->privfile); + goto done; + } + retval = 0; + done: + return retval; +} + +/*! Get client ssl cert info + * @param[in] h Clicon handle + * @param[in] server_ca_cert_path Path to server ssl CA file for client certs + * @param[in,out] ssl_config evhtp ssl config struct + * @retval 0 OK + * @retval -1 Error + */ +static int +cx_get_ssl_client_certs(clicon_handle h, + const char *server_ca_cert_path, + evhtp_ssl_cfg_t *ssl_config) +{ + int retval = -1; + struct stat f_stat; + + if (ssl_config == NULL || server_ca_cert_path == NULL){ + clicon_err(OE_CFG, EINVAL, "Input parameter is NULL"); + goto done; + } + if ((ssl_config->cafile = strdup(server_ca_cert_path)) == NULL){ + clicon_err(OE_CFG, errno, "strdup"); + goto done; + } + if (stat(ssl_config->cafile, &f_stat) != 0) { + clicon_err(OE_FATAL, errno, "Cannot load SSL key '%s'", ssl_config->privfile); + goto done; + } + retval = 0; + done: + return retval; +} + /*! Get Server cert info - * @param[in] h Clicon handle - * @param[out] ssl_config evhtp ssl config struct + * @param[in] h Clicon handle + * @param[in] ssl_verify_clients If true, verify client certs + * @param[out] ssl_config evhtp ssl config struct */ static int cx_get_certs(clicon_handle h, @@ -602,10 +689,11 @@ usage(clicon_handle h, "\t-a UNIX|IPv4|IPv6 Internal backend socket family\n" "\t-u \t Internal socket domain path or IP addr (see -a)\n" "\t-r \t\t Do not drop privileges if run as root\n" + "\t-b \t\t Read config from backend - not local (same as CLICON_RESTCONF_CONF=true) \n" "\t-o