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