* Changed config and install options for Restconf

* clixon_restconf daemon is installed in /usr/local/sbin (as clixon_backend), instead of /www-data
    * `configure --with-wwwdir=<dir>` remains but only applies to fcgi socket and log
    * New option `CLICON_RESTCONF_INSTALL_DIR` is set to where clixon_restconf is installed, with default `/usr/local/sbin/`
  * Restconf drop privileges user is defined by `CLICON_RESTCONF_USER`
    * `configure --with-wwwuser=<user>` is removed
  * clixon_restconf drop of privileges is defined by `CLICON_RESTCONF_PRIVILEGES` option
* New clixon-restconf@2020-05-20.yang revision
  * Added: restconf `log-destination`
This commit is contained in:
Olof hagsand 2021-05-21 15:12:06 +02:00
parent c3e26b004c
commit c20c672d83
32 changed files with 410 additions and 221 deletions

View file

@ -47,6 +47,19 @@ Expected: June 2021
Users may have to change how they access the system Users may have to change how they access the system
* Changed config and install options for Restconf
* clixon_restconf daemon is installed in /usr/local/sbin (as clixon_backend), instead of /www-data
* `configure --with-wwwdir=<dir>` remains but only applies to fcgi socket and log
* New option `CLICON_RESTCONF_INSTALL_DIR` is set to where clixon_restconf is installed, with default `/usr/local/sbin/`
* Restconf drop privileges user is defined by `CLICON_RESTCONF_USER`
* `configure --with-wwwuser=<user>` is removed
* clixon_restconf drop of privileges is defined by `CLICON_RESTCONF_PRIVILEGES` option
* New clixon-config@2020-05-20.yang revision
* Added: `CLICON_RESTCONF_USER`
* Added: `CLICON_RESTCONF_PRIVILEGES`
* Added: `CLICON_RESTCONF_INSTALL_DIR`
* New clixon-restconf@2020-05-20.yang revision
* Added: restconf `log-destination`
* RESTCONF error replies have changed * RESTCONF error replies have changed
* Added Restconf-style xml/json message bodies everywhere * Added Restconf-style xml/json message bodies everywhere
* Clixon removed the message body from many errors in the 4.6 version since they used html encoding. * Clixon removed the message body from many errors in the 4.6 version since they used html encoding.

View file

@ -43,6 +43,7 @@ CPPFLAGS = @CPPFLAGS@
ifeq ($(LINKAGE),dynamic) ifeq ($(LINKAGE),dynamic)
CPPFLAGS += -fPIC CPPFLAGS += -fPIC
endif endif
SH_SUFFIX = @SH_SUFFIX@ SH_SUFFIX = @SH_SUFFIX@
INSTALLFLAGS = @INSTALLFLAGS@ INSTALLFLAGS = @INSTALLFLAGS@
LDFLAGS = @LDFLAGS@ LDFLAGS = @LDFLAGS@

View file

@ -1796,7 +1796,7 @@ from_client_msg(clicon_handle h,
goto done; goto done;
if (ret == 0){ /* Do NACM RPC validation */ if (ret == 0){ /* Do NACM RPC validation */
creds = clicon_nacm_credentials(h); creds = clicon_nacm_credentials(h);
if ((ret = verify_nacm_user(creds, ce->ce_username, username, cbret)) < 0) if ((ret = verify_nacm_user(h, creds, ce->ce_username, username, cbret)) < 0)
goto done; goto done;
if (ret == 0) /* credentials fail */ if (ret == 0) /* credentials fail */
goto reply; goto reply;

View file

@ -287,9 +287,9 @@ check_drop_priv(clicon_handle h,
enum priv_mode_t priv_mode = PM_NONE; enum priv_mode_t priv_mode = PM_NONE;
char *backend_user = NULL; char *backend_user = NULL;
/* Get privileges mode (for dropping privileges) */ /* Get privileges mode (for dropping privileges) */
priv_mode = clicon_backend_privileges_mode(h); if ((priv_mode = clicon_backend_privileges_mode(h)) == PM_NONE)
if (priv_mode == PM_NONE)
goto ok; goto ok;
/* From here, drop privileges */ /* From here, drop privileges */
@ -575,9 +575,6 @@ main(int argc,
usage(h, argv[0]); usage(h, argv[0]);
goto done; goto done;
} }
/* Add some specific options from autotools configure NOT config file */
clicon_option_str_set(h, "CLICON_WWWUSER", WWWUSER);
clicon_option_str_set(h, "CLICON_WWWDIR", WWWDIR);
/* Initialize plugin module by creating a handle holding plugin and callback lists */ /* Initialize plugin module by creating a handle holding plugin and callback lists */
if (clixon_plugin_module_init(h) < 0) if (clixon_plugin_module_init(h) < 0)

View file

@ -66,31 +66,61 @@
* process argv list including -D is set on start. But the debug flags may change and this is a way * process argv list including -D is set on start. But the debug flags may change and this is a way
* to set it dynamically, ie at the time the process is started, not when the backend is started. * to set it dynamically, ie at the time the process is started, not when the backend is started.
* @param[in] h Clixon backend * @param[in] h Clixon backend
* @param[in] dbg Debug string , eg "0" or "1" * @param[in] xt XML target
*/ */
static int static int
restconf_pseudo_set_debug(clicon_handle h, restconf_pseudo_set_log(clicon_handle h,
char *dbg) cxobj *xt)
{ {
int retval = -1; int retval = -1;
char **argv; char **argv;
int argc; int argc;
int i; int i;
char *log = NULL;
char *dbg = NULL;
cxobj *xb;
if (dbg == NULL) if ((xb = xpath_first(xt, NULL, "/restconf/log-destination")) != NULL)
log = xml_body(xb);
if ((xb = xpath_first(xt, NULL, "/restconf/debug")) != NULL)
dbg = xml_body(xb);
if (dbg == NULL && log == NULL)
goto ok; goto ok;
if (clixon_process_argv_get(h, RESTCONF_PROCESS, &argv, &argc) < 0) if (clixon_process_argv_get(h, RESTCONF_PROCESS, &argv, &argc) < 0)
goto done; goto done;
for (i=0; i<argc; i++){ for (i=0; i<argc; i++){
if (argv[i] == NULL) if (argv[i] == NULL)
break; break;
if (strcmp(argv[i], "-l") == 0 && argc > i+1 && argv[i+1]){
if (log){
if (strcmp(log, "syslog") == 0){
if (argv[i+1])
free(argv[i+1]);
if ((argv[i+1] = strdup("s")) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
}
else if (strcmp(log, "file") == 0){
if (argv[i+1])
free(argv[i+1]);
if ((argv[i+1] = strdup("f/var/log/clixon_restconf.log")) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
}
}
i++;
}
if (strcmp(argv[i], "-D") == 0 && argc > i+1 && argv[i+1]){ if (strcmp(argv[i], "-D") == 0 && argc > i+1 && argv[i+1]){
if (dbg){
free(argv[i+1]); free(argv[i+1]);
if ((argv[i+1] = strdup(dbg)) == NULL){ if ((argv[i+1] = strdup(dbg)) == NULL){
clicon_err(OE_UNIX, errno, "strdup"); clicon_err(OE_UNIX, errno, "strdup");
goto done; goto done;
} }
break; }
i++;
} }
} }
ok: ok:
@ -111,7 +141,6 @@ restconf_rpc_wrapper(clicon_handle h,
{ {
int retval = -1; int retval = -1;
cxobj *xt = NULL; cxobj *xt = NULL;
cxobj *xb;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
switch (*operation){ switch (*operation){
@ -133,11 +162,9 @@ restconf_rpc_wrapper(clicon_handle h,
* but in this way it is set directly in its input args. * but in this way it is set directly in its input args.
* Its a trick. * Its a trick.
*/ */
if ((xb = xpath_first(xt, NULL, "/restconf/debug")) != NULL){ if (restconf_pseudo_set_log(h, xt) < 0)
if (restconf_pseudo_set_debug(h, xml_body(xb)) < 0)
goto done; goto done;
} }
}
break; break;
default: default:
break; break;
@ -165,7 +192,7 @@ restconf_pseudo_process_control(clicon_handle h)
int nr; int nr;
cbuf *cb = NULL; cbuf *cb = NULL;
nr = 6; nr = 8;
if ((argv = calloc(nr, sizeof(char *))) == NULL){ if ((argv = calloc(nr, sizeof(char *))) == NULL){
clicon_err(OE_UNIX, errno, "calloc"); clicon_err(OE_UNIX, errno, "calloc");
goto done; goto done;
@ -175,15 +202,23 @@ restconf_pseudo_process_control(clicon_handle h)
clicon_err(OE_UNIX, errno, "cbuf_new"); clicon_err(OE_UNIX, errno, "cbuf_new");
goto done; goto done;
} }
cprintf(cb, "%s/clixon_restconf", clicon_option_str(h, "CLICON_WWWDIR")); /* CLICON_RESTCONF_INSTALL_DIR is where we think clixon_restconf is installed
* Problem is where to define it? Now in config file, but maybe it should be in configure?
* Tried Makefile but didnt work on Docker since it was moved around.
* Use PATH?
*/
cprintf(cb, "%s/clixon_restconf", clicon_option_str(h, "CLICON_RESTCONF_INSTALL_DIR"));
argv[i++] = cbuf_get(cb); argv[i++] = cbuf_get(cb);
argv[i++] = "-f"; argv[i++] = "-f";
argv[i++] = clicon_option_str(h, "CLICON_CONFIGFILE"); argv[i++] = clicon_option_str(h, "CLICON_CONFIGFILE");
/* Add debug if backend has debug. /* Add debug if backend has debug.
* There is also a debug flag in clixon-restconf.yang but it kicks in after it starts * There is also a debug flag in clixon-restconf.yang but it kicks in after it starts
* see restconf_pseudo_set_log which sets flag when process starts
*/ */
argv[i++] = "-D"; argv[i++] = "-D";
argv[i++] = "0"; argv[i++] = "0";
argv[i++] = "-l";
argv[i++] = "s"; /* There is also log-destination in clixon-restconf.yang */
argv[i++] = NULL; argv[i++] = NULL;
assert(i==nr); assert(i==nr);
if (clixon_process_register(h, RESTCONF_PROCESS, if (clixon_process_register(h, RESTCONF_PROCESS,
@ -201,7 +236,7 @@ restconf_pseudo_process_control(clicon_handle h)
return retval; return retval;
} }
/*! Restconf pseduo-plugin process validate /*! Restconf pseudo-plugin process validate
*/ */
static int static int
restconf_pseudo_process_validate(clicon_handle h, restconf_pseudo_process_validate(clicon_handle h,
@ -241,7 +276,6 @@ restconf_pseudo_process_commit(clicon_handle h,
cxobj *xsource; cxobj *xsource;
cxobj *cx; cxobj *cx;
int enabled = 0; int enabled = 0;
cxobj *xb;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
xtarget = transaction_target(td); xtarget = transaction_target(td);
@ -253,10 +287,8 @@ restconf_pseudo_process_commit(clicon_handle h,
* but in this way it is set directly in its input args. * but in this way it is set directly in its input args.
* Its a trick. * Its a trick.
*/ */
if ((xb = xpath_first(xtarget, NULL, "/restconf/debug")) != NULL){ if (restconf_pseudo_set_log(h, xtarget) < 0)
if (restconf_pseudo_set_debug(h, xml_body(xb)) < 0)
goto done; goto done;
}
/* Toggle start/stop if enable flag changed */ /* Toggle start/stop if enable flag changed */
if ((cx = xpath_first(xtarget, NULL, "/restconf/enable")) != NULL && if ((cx = xpath_first(xtarget, NULL, "/restconf/enable")) != NULL &&
xml_flag(cx, XML_FLAG_CHANGE|XML_FLAG_ADD)){ xml_flag(cx, XML_FLAG_CHANGE|XML_FLAG_ADD)){

View file

@ -49,6 +49,7 @@ datarootdir = @datarootdir@
exec_prefix = @exec_prefix@ exec_prefix = @exec_prefix@
bindir = @bindir@ bindir = @bindir@
libdir = @libdir@ libdir = @libdir@
sbindir = @sbindir@
mandir = @mandir@ mandir = @mandir@
libexecdir = @libexecdir@ libexecdir = @libexecdir@
localstatedir = @localstatedir@ localstatedir = @localstatedir@
@ -56,9 +57,6 @@ sysconfdir = @sysconfdir@
includedir = @includedir@ includedir = @includedir@
HOST_VENDOR = @host_vendor@ HOST_VENDOR = @host_vendor@
# XXX why is not wwwdir under prefix?
wwwdir = @wwwdir@
wwwuser = @wwwuser@
# one of fcgi or native: # one of fcgi or native:
with_restconf = @with_restconf@ with_restconf = @with_restconf@
@ -79,6 +77,8 @@ LIBDEPS = $(top_srcdir)/lib/src/$(CLIXON_LIB)
LIBS = -L$(top_srcdir)/lib/src $(top_srcdir)/lib/src/$(CLIXON_LIB) @LIBS@ LIBS = -L$(top_srcdir)/lib/src $(top_srcdir)/lib/src/$(CLIXON_LIB) @LIBS@
CPPFLAGS = @CPPFLAGS@ CPPFLAGS = @CPPFLAGS@
ifeq ($(LINKAGE),dynamic) ifeq ($(LINKAGE),dynamic)
CPPFLAGS += -fPIC CPPFLAGS += -fPIC
endif endif
@ -149,12 +149,8 @@ distclean: clean
# Put config file in etc/ # Put config file in etc/
# Also a rule for letting www-dir be owned by www-data, which only works for sudo # Also a rule for letting www-dir be owned by www-data, which only works for sudo
install: install-lib $(APPL) install: install-lib $(APPL)
ifeq ($(shell whoami),root) install -d -m 0755 $(DESTDIR)$(sbindir)
install -d -m 0755 -o $(wwwuser) -g $(wwwuser) $(DESTDIR)$(wwwdir) install -m 0755 $(INSTALLFLAGS) $(APPL) $(DESTDIR)$(sbindir)
else
install -d -m 0755 $(DESTDIR)$(wwwdir)
endif
install -m 0755 $(INSTALLFLAGS) $(APPL) $(DESTDIR)$(wwwdir)
install-lib: $(MYLIB) install-lib: $(MYLIB)
install -d -m 0755 $(DESTDIR)$(libdir) install -d -m 0755 $(DESTDIR)$(libdir)
@ -169,7 +165,7 @@ install-include: clixon_restconf.h
install -m 0644 $^ $(DESTDIR)$(includedir)/clixon install -m 0644 $^ $(DESTDIR)$(includedir)/clixon
uninstall: uninstall:
rm -f $(DESTDIR)$(wwwdir)/$(APPL) rm -f $(DESTDIR)$(sbindir)/$(APPL)
rm -f $(DESTDIR)$(libdir)/$(MYLIBLINK)* rm -f $(DESTDIR)$(libdir)/$(MYLIBLINK)*
.SUFFIXES: .SUFFIXES:

View file

@ -82,11 +82,11 @@ Start clixon backend daemon (if not already started)
Start clixon restconf daemon Start clixon restconf daemon
``` ```
sudo -u www-data -s /www-data/clixon_restconf -f /usr/local/etc/example.xml sudo clixon_restconf -f /usr/local/etc/example.xml
``` ```
On FreeBSD: On FreeBSD:
``` ```
sudo -u www -s /www/clixon_restconf -f /usr/local/etc/example.xml sudo clixon_restconf -f /usr/local/etc/example.xml
``` ```
Make restconf calls with curl (or other http client). Example of writing a new interface specification: Make restconf calls with curl (or other http client). Example of writing a new interface specification:
@ -226,7 +226,7 @@ See (https://nchan.io/#eventsource) on more info on how to access an SSE sub end
Start the restconf fastcgi program with debug flag: Start the restconf fastcgi program with debug flag:
``` ```
sudo su -c "/www-data/clixon_restconf -D 1 -f /usr/local/etc/example.xml" -s /bin/sh www-data sudo clixon_restconf -D 1 -f /usr/local/etc/example.xml
``` ```
Look at syslog: Look at syslog:
``` ```
@ -240,7 +240,7 @@ curl -G http://127.0.0.1/restconf/data/*
You can also run restconf in a debugger. You can also run restconf in a debugger.
``` ```
sudo gdb /www-data/clixon_restconf sudo gdb clixon_restconf
(gdb) run -D 1 -f /usr/local/etc/example.xml (gdb) run -D 1 -f /usr/local/etc/example.xml
``` ```
but you need to ensure /www-data/fastcgi_restconf.sock has the following access (may need to be done after restconf has started) but you need to ensure /www-data/fastcgi_restconf.sock has the following access (may need to be done after restconf has started)

View file

@ -312,7 +312,7 @@ restconf_terminate(clicon_handle h)
xpath_optimize_exit(); xpath_optimize_exit();
restconf_handle_exit(h); restconf_handle_exit(h);
clixon_err_exit(); clixon_err_exit();
clicon_debug(1, "%s done", __FUNCTION__); clicon_debug(1, "%s pid:%u done", __FUNCTION__, getpid());
clicon_log_exit(); /* Must be after last clicon_debug */ clicon_log_exit(); /* Must be after last clicon_debug */
return 0; return 0;
} }
@ -495,18 +495,18 @@ restconf_uripath(clicon_handle h)
/*! Drop privileges from root to user (or already at user) /*! Drop privileges from root to user (or already at user)
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @param[in] user Drop to this level
* Group set to clicon to communicate with backend * Group set to clicon to communicate with backend
*/ */
int int
restconf_drop_privileges(clicon_handle h, restconf_drop_privileges(clicon_handle h)
char *user)
{ {
int retval = -1; int retval = -1;
uid_t newuid = -1; uid_t newuid = -1;
uid_t uid; uid_t uid;
char *group; char *group;
gid_t gid = -1; gid_t gid = -1;
char *user;
enum priv_mode_t priv_mode = PM_NONE;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
/* Sanity check: backend group exists */ /* Sanity check: backend group exists */
@ -523,12 +523,19 @@ restconf_drop_privileges(clicon_handle h,
clicon_configfile(h)); clicon_configfile(h));
goto done; goto done;
} }
/* Get privileges mode (for dropping privileges) */
if ((priv_mode = clicon_restconf_privileges_mode(h)) == PM_NONE)
goto ok;
if ((user = clicon_option_str(h, "CLICON_RESTCONF_USER")) == NULL)
goto ok;
/* Get (wanted) new www user id */ /* Get (wanted) new www user id */
if (name2uid(user, &newuid) < 0){ if (name2uid(user, &newuid) < 0){
clicon_err(OE_DAEMON, errno, "'%s' is not a valid user .\n", user); clicon_err(OE_DAEMON, errno, "'%s' is not a valid user .\n", user);
goto done; goto done;
} }
/* get current backend userid, if already at this level OK */ /* get current userid, if already at this level OK */
if ((uid = getuid()) == newuid) if ((uid = getuid()) == newuid)
goto ok; goto ok;
if (uid != 0){ if (uid != 0){
@ -539,6 +546,8 @@ restconf_drop_privileges(clicon_handle h,
clicon_err(OE_DAEMON, errno, "setgid %d", gid); clicon_err(OE_DAEMON, errno, "setgid %d", gid);
goto done; goto done;
} }
switch (priv_mode){
case PM_DROP_PERM:
if (drop_priv_perm(newuid) < 0) if (drop_priv_perm(newuid) < 0)
goto done; goto done;
/* Verify you cannot regain root privileges */ /* Verify you cannot regain root privileges */
@ -546,6 +555,14 @@ restconf_drop_privileges(clicon_handle h,
clicon_err(OE_DAEMON, EPERM, "Could regain root privilieges"); clicon_err(OE_DAEMON, EPERM, "Could regain root privilieges");
goto done; goto done;
} }
break;
case PM_DROP_TEMP:
if (drop_priv_temp(newuid) < 0)
goto done;
break;
case PM_NONE:
break; /* catched above */
}
clicon_debug(1, "%s dropped privileges from root to %s(%d)", clicon_debug(1, "%s dropped privileges from root to %s(%d)",
__FUNCTION__, user, newuid); __FUNCTION__, user, newuid);
ok: ok:

View file

@ -81,7 +81,7 @@ int restconf_terminate(clicon_handle h);
int restconf_insert_attributes(cxobj *xdata, cvec *qvec); int restconf_insert_attributes(cxobj *xdata, cvec *qvec);
int restconf_main_extension_cb(clicon_handle h, yang_stmt *yext, yang_stmt *ys); int restconf_main_extension_cb(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
char *restconf_uripath(clicon_handle h); char *restconf_uripath(clicon_handle h);
int restconf_drop_privileges(clicon_handle h, char *user); int restconf_drop_privileges(clicon_handle h);
int restconf_authentication_cb(clicon_handle h, void *req, int pretty, restconf_media media_out); int restconf_authentication_cb(clicon_handle h, void *req, int pretty, restconf_media media_out);
int restconf_config_init(clicon_handle h, cxobj *xrestconf); int restconf_config_init(clicon_handle h, cxobj *xrestconf);
int restconf_socket_init(const char *netns0, const char *addrstr, const char *addrtype, uint16_t port, int backlog, int flags, int *ss); int restconf_socket_init(const char *netns0, const char *addrstr, const char *addrtype, uint16_t port, int backlog, int flags, int *ss);

View file

@ -88,7 +88,7 @@
#include "restconf_stream.h" #include "restconf_stream.h"
/* Command line options to be passed to getopt(3) */ /* Command line options to be passed to getopt(3) */
#define RESTCONF_OPTS "hD:f:E:l:p:d:y:a:u:ro:" #define RESTCONF_OPTS "hD:f:E:l:p:d:y:a:u:rW:o:"
/*! Convert FCGI parameters to clixon runtime data /*! Convert FCGI parameters to clixon runtime data
* @param[in] h Clixon handle * @param[in] h Clixon handle
@ -192,6 +192,7 @@ usage(clicon_handle h,
"\t-u <path|addr>\t Internal socket domain path or IP addr (see -a)\n" "\t-u <path|addr>\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-r \t\t Do not drop privileges if run as root\n"
"\t-W <user>\tRun restconf daemon as this user, drop according to CLICON_RESTCONF_PRIVILEGES\n"
"\t-o \"<option>=<value>\" Give configuration option overriding config file (see clixon-config.yang)\n", "\t-o \"<option>=<value>\" Give configuration option overriding config file (see clixon-config.yang)\n",
argv0 argv0
); );
@ -225,7 +226,6 @@ main(int argc,
size_t cligen_buflen; size_t cligen_buflen;
size_t cligen_bufthreshold; size_t cligen_bufthreshold;
int dbg = 0; int dbg = 0;
int drop_privileges = 1;
int ret; int ret;
cxobj *xrestconf1 = NULL; /* Local config file */ cxobj *xrestconf1 = NULL; /* Local config file */
cxobj *xconfig2 = NULL; cxobj *xconfig2 = NULL;
@ -234,6 +234,7 @@ main(int argc,
cvec *nsc = NULL; cvec *nsc = NULL;
cxobj *xerr = NULL; cxobj *xerr = NULL;
struct passwd *pw; struct passwd *pw;
char *wwwuser;
/* In the startup, logs to stderr & debug flag set later */ /* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst); clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
@ -272,6 +273,7 @@ main(int argc,
goto done; goto done;
break; break;
} /* switch getopt */ } /* switch getopt */
dbg=1;
/* /*
* Logs, error and debug to stderr or syslog, set debug level * Logs, error and debug to stderr or syslog, set debug level
*/ */
@ -324,7 +326,8 @@ main(int argc,
clicon_option_str_set(h, "CLICON_SOCK", optarg); clicon_option_str_set(h, "CLICON_SOCK", optarg);
break; break;
case 'r':{ /* Do not drop privileges if run as root */ case 'r':{ /* Do not drop privileges if run as root */
drop_privileges = 0; if (clicon_option_add(h, "CLICON_RESTCONF_PRIVILEGES", "none") < 0)
goto done;
break; break;
} }
case 'o':{ /* Configuration option */ case 'o':{ /* Configuration option */
@ -507,11 +510,12 @@ main(int argc,
goto done; goto done;
} }
_MYSOCK = sock; _MYSOCK = sock;
/* Change group of fcgi sock fronting reverse proxy to WWWUSER, the effective group is clicon /* Change group of fcgi sock fronting reverse proxy to CLICON_RESTCONF_USER,
* which is backend. */ * the effective group is clicon which is backend. */
gid_t wgid = -1; gid_t wgid = -1;
if (group_name2gid(WWWUSER, &wgid) < 0){ wwwuser = clicon_option_str(h, "CLICON_RESTCONF_USER");
clicon_log(LOG_ERR, "'%s' does not seem to be a valid user group.", WWWUSER); if (group_name2gid(wwwuser, &wgid) < 0){
clicon_log(LOG_ERR, "'%s' does not seem to be a valid user group.", wwwuser);
goto done; goto done;
} }
if (chown(sockpath, -1, wgid) < 0){ if (chown(sockpath, -1, wgid) < 0){
@ -525,11 +529,11 @@ main(int argc,
clicon_err(OE_UNIX, errno, "chmod"); clicon_err(OE_UNIX, errno, "chmod");
goto done; goto done;
} }
if (drop_privileges){ /* Drop privileges if started as root to CLICON_RESTCONF_USER
/* Drop privileges to WWWUSER if started as root */ * and use drop mode: CLICON_RESTCONF_PRIVILEGES
if (restconf_drop_privileges(h, WWWUSER) < 0) */
if (restconf_drop_privileges(h) < 0)
goto done; goto done;
}
if (FCGX_InitRequest(req, sock, 0) != 0){ if (FCGX_InitRequest(req, sock, 0) != 0){
clicon_err(OE_CFG, errno, "FCGX_InitRequest"); clicon_err(OE_CFG, errno, "FCGX_InitRequest");
goto done; goto done;

View file

@ -168,7 +168,7 @@
#include "restconf_native.h" /* Restconf-openssl mode specific headers*/ #include "restconf_native.h" /* Restconf-openssl mode specific headers*/
/* Command line options to be passed to getopt(3) */ /* Command line options to be passed to getopt(3) */
#define RESTCONF_OPTS "hD:f:E:l:p:y:a:u:ro:" #define RESTCONF_OPTS "hD:f:E:l:p:y:a:u:rW:o:"
/* If set, open outwards socket non-blocking, as opposed to blocking /* If set, open outwards socket non-blocking, as opposed to blocking
* Should work both ways, but in the ninblocking case, * Should work both ways, but in the ninblocking case,
@ -1093,7 +1093,7 @@ restconf_connection(int s,
if (conn->bev != NULL){ if (conn->bev != NULL){
struct evbuffer *ev; struct evbuffer *ev;
size_t buflen0; size_t buflen0;
size_t buflen; size_t buflen1;
char *buf = NULL; char *buf = NULL;
if ((rc = conn->arg) == NULL){ if ((rc = conn->arg) == NULL){
@ -1102,32 +1102,35 @@ restconf_connection(int s,
} }
if ((ev = bufferevent_get_output(conn->bev)) != NULL){ if ((ev = bufferevent_get_output(conn->bev)) != NULL){
buflen0 = evbuffer_get_length(ev); buflen0 = evbuffer_get_length(ev);
buflen = buflen0 - rc->rc_bufferevent_output_offset; buflen1 = buflen0 - rc->rc_bufferevent_output_offset;
if (buflen == 0) if (buflen1 > 0){
readmore = 1;
else if (buflen > 0){
buf = (char*)evbuffer_pullup(ev, -1); buf = (char*)evbuffer_pullup(ev, -1);
/* If evhtp has print an output buffer, clixon whould not have done it /* If evhtp has print an output buffer, clixon whould not have done it
* Shouldnt happen * Shouldnt happen
*/ */
if (cbuf_len(rc->rc_outp_buf)){
clicon_debug(1, "%s Warning: evhtp printed output buffer, but clixon output buffer is non-empty %s", clicon_debug(1, "%s Warning: evhtp printed output buffer, but clixon output buffer is non-empty %s",
__FUNCTION__, cbuf_get(rc->rc_outp_buf)); __FUNCTION__, cbuf_get(rc->rc_outp_buf));
cbuf_reset(rc->rc_outp_buf); cbuf_reset(rc->rc_outp_buf);
if (cbuf_append_buf(rc->rc_outp_buf, buf, buflen) < 0){ }
if (cbuf_append_buf(rc->rc_outp_buf, buf, buflen1) < 0){
clicon_err(OE_UNIX, errno, "cbuf_append_buf"); clicon_err(OE_UNIX, errno, "cbuf_append_buf");
goto done; goto done;
} }
/* XXX Cant get drain to work, need to keep an offset */ /* XXX Cant get drain to work, need to keep an offset */
evbuffer_drain(ev, -1); evbuffer_drain(ev, -1);
rc->rc_bufferevent_output_offset += buflen; rc->rc_bufferevent_output_offset += buflen1;
} }
} }
if (cbuf_len(rc->rc_outp_buf) && if (cbuf_len(rc->rc_outp_buf) == 0)
buf_write(cbuf_get(rc->rc_outp_buf), cbuf_len(rc->rc_outp_buf), conn->sock, conn->ssl) < 0) readmore = 1;
else {
if (buf_write(cbuf_get(rc->rc_outp_buf), cbuf_len(rc->rc_outp_buf), conn->sock, conn->ssl) < 0)
goto done; goto done;
cvec_reset(rc->rc_outp_hdrs); /* Can be done in native_send_reply */ cvec_reset(rc->rc_outp_hdrs); /* Can be done in native_send_reply */
cbuf_reset(rc->rc_outp_buf); cbuf_reset(rc->rc_outp_buf);
} }
}
else{ else{
if (send_badrequest(h, s, conn->ssl, "application/yang-data+xml", if (send_badrequest(h, s, conn->ssl, "application/yang-data+xml",
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>No evhtp output</error-message></error></errors>") < 0) "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>No evhtp output</error-message></error></errors>") < 0)
@ -1896,6 +1899,7 @@ usage(clicon_handle h,
"\t-a UNIX|IPv4|IPv6 Internal backend socket family\n" "\t-a UNIX|IPv4|IPv6 Internal backend socket family\n"
"\t-u <path|addr>\t Internal socket domain path or IP addr (see -a)\n" "\t-u <path|addr>\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-r \t\t Do not drop privileges if run as root\n"
"\t-W <user>\tRun restconf daemon as this user, drop according to CLICON_RESTCONF_PRIVILEGES\n"
"\t-o <option>=<value> Set configuration option overriding config file (see clixon-config.yang)\n" "\t-o <option>=<value> Set configuration option overriding config file (see clixon-config.yang)\n"
, ,
argv0 argv0
@ -1913,7 +1917,6 @@ main(int argc,
clicon_handle h; clicon_handle h;
int dbg = 0; int dbg = 0;
int logdst = CLICON_LOG_SYSLOG; int logdst = CLICON_LOG_SYSLOG;
int drop_privileges = 1;
restconf_native_handle *rh = NULL; restconf_native_handle *rh = NULL;
int ret; int ret;
cxobj *xrestconf = NULL; cxobj *xrestconf = NULL;
@ -2012,10 +2015,14 @@ main(int argc,
usage(h, argv0); usage(h, argv0);
clicon_option_str_set(h, "CLICON_SOCK", optarg); clicon_option_str_set(h, "CLICON_SOCK", optarg);
break; break;
case 'r':{ /* Do not drop privileges if run as root */ case 'r': /* Do not drop privileges if run as root */
drop_privileges = 0; if (clicon_option_add(h, "CLICON_RESTCONF_PRIVILEGES", "none") < 0)
goto done;
break;
case 'W': /* Run restconf daemon as this user (afetr drop) */
if (clicon_option_add(h, "CLICON_RESTCONF_USER", optarg) < 0)
goto done;
break; break;
}
case 'o':{ /* Configuration option */ case 'o':{ /* Configuration option */
char *val; char *val;
if ((val = index(optarg, '=')) == NULL) if ((val = index(optarg, '=')) == NULL)
@ -2068,12 +2075,12 @@ main(int argc,
/* Openssl inits */ /* Openssl inits */
if (restconf_openssl_init(h, dbg, xrestconf) < 0) if (restconf_openssl_init(h, dbg, xrestconf) < 0)
goto done; goto done;
/* Drop privileges after clixon and openssl init */ /* Drop privileges if started as root to CLICON_RESTCONF_USER
if (drop_privileges){ * and use drop mode: CLICON_RESTCONF_PRIVILEGES
/* Drop privileges to WWWUSER if started as root */ */
if (restconf_drop_privileges(h, WWWUSER) < 0) if (restconf_drop_privileges(h) < 0)
goto done; goto done;
}
/* Main event loop */ /* Main event loop */
if (clixon_event_loop(h) < 0) if (clixon_event_loop(h) < 0)
goto done; goto done;

29
configure vendored
View file

@ -635,7 +635,6 @@ CXXFLAGS
CXX CXX
CPP CPP
wwwdir wwwdir
wwwuser
enable_optyangs enable_optyangs
with_libxml2 with_libxml2
with_restconf with_restconf
@ -719,7 +718,6 @@ with_cligen
enable_optyangs enable_optyangs
enable_publish enable_publish
with_restconf with_restconf
with_wwwuser
with_configfile with_configfile
with_libxml2 with_libxml2
with_yang_installdir with_yang_installdir
@ -1376,7 +1374,6 @@ Optional Packages:
nginx (default) nginx (default)
--with-restconf=native Integrate restconf with embedded http server --with-restconf=native Integrate restconf with embedded http server
--without-restconf Disable restconf altogether --without-restconf Disable restconf altogether
--with-wwwuser=<user> Set www user different from www-data
--with-configfile=FILE Set default path to config file --with-configfile=FILE Set default path to config file
--with-libxml2 Use gnome/libxml2 regex engine --with-libxml2 Use gnome/libxml2 regex engine
--with-yang-installdir=DIR --with-yang-installdir=DIR
@ -3355,9 +3352,6 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
# Set to native or fcgi -> compile apps/restconf # Set to native or fcgi -> compile apps/restconf
# Web user default (ie what RESTCONF daemon runs as).
wwwuser=www-data
# Home dir for web user # Home dir for web user
wwwdir=/www-data wwwdir=/www-data
@ -5298,24 +5292,6 @@ fi
# Common actions for all restconf packages # Common actions for all restconf packages
if test "x${with_restconf}" != "x"; then if test "x${with_restconf}" != "x"; then
# Web user default (ie what RESTCONF daemon runs as). Default: www-data
# Should this be a runtime option?
# Check whether --with-wwwuser was given.
if test "${with_wwwuser+set}" = set; then :
withval=$with_wwwuser;
fi
if test "${with_wwwuser}"; then
wwwuser=${with_wwwuser}
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: www user is $wwwuser" >&5
$as_echo "www user is $wwwuser" >&6; }
cat >>confdefs.h <<_ACEOF
#define WWWUSER "$wwwuser"
_ACEOF
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
#define WWWDIR "$wwwdir" #define WWWDIR "$wwwdir"
@ -5323,11 +5299,6 @@ _ACEOF
else else
cat >>confdefs.h <<_ACEOF
#define WWWUSER ""
_ACEOF
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
#define WWWDIR "" #define WWWDIR ""
_ACEOF _ACEOF

View file

@ -98,9 +98,7 @@ AC_SUBST(LINKAGE)
AC_SUBST(with_restconf) # Set to native or fcgi -> compile apps/restconf AC_SUBST(with_restconf) # Set to native or fcgi -> compile apps/restconf
AC_SUBST(with_libxml2) AC_SUBST(with_libxml2)
AC_SUBST(enable_optyangs) AC_SUBST(enable_optyangs)
# Web user default (ie what RESTCONF daemon runs as). # Home dir for web user, such as nginx fcgi sockets
AC_SUBST(wwwuser,www-data)
# Home dir for web user
AC_SUBST(wwwdir,/www-data) AC_SUBST(wwwdir,/www-data)
# #
@ -216,6 +214,7 @@ if test "x${with_restconf}" == xfcgi; then
# Lives in libfcgi-dev # Lives in libfcgi-dev
AC_CHECK_LIB(fcgi, FCGX_Init,, AC_MSG_ERROR([libfcgi-dev missing])) AC_CHECK_LIB(fcgi, FCGX_Init,, AC_MSG_ERROR([libfcgi-dev missing]))
AC_DEFINE(WITH_RESTCONF_FCGI, 1, [Use fcgi restconf mode]) # For c-code that cant use strings AC_DEFINE(WITH_RESTCONF_FCGI, 1, [Use fcgi restconf mode]) # For c-code that cant use strings
AC_DEFINE_UNQUOTED(WWWDIR, "$wwwdir", [WWW dir for fcgi stuff / nginx])
elif test "x${with_restconf}" == xnative; then elif test "x${with_restconf}" == xnative; then
AC_CHECK_LIB(ssl, OPENSSL_init_ssl ,, AC_MSG_ERROR([libssl missing])) AC_CHECK_LIB(ssl, OPENSSL_init_ssl ,, AC_MSG_ERROR([libssl missing]))
AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, , AC_MSG_ERROR([libcrypto missing])) AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, , AC_MSG_ERROR([libcrypto missing]))
@ -248,23 +247,6 @@ AC_ARG_WITH([restconf],
AC_ARG_WITH([restconf], AC_ARG_WITH([restconf],
AS_HELP_STRING([--without-restconf],[Disable restconf altogether])) AS_HELP_STRING([--without-restconf],[Disable restconf altogether]))
# Common actions for all restconf packages
if test "x${with_restconf}" != "x"; then
# Web user default (ie what RESTCONF daemon runs as). Default: www-data
# Should this be a runtime option?
AC_ARG_WITH([wwwuser],
[AS_HELP_STRING([--with-wwwuser=<user>],[Set www user different from www-data])])
if test "${with_wwwuser}"; then
wwwuser=${with_wwwuser}
fi
AC_MSG_RESULT(www user is $wwwuser)
AC_DEFINE_UNQUOTED(WWWUSER, "$wwwuser", [WWW user for restconf daemon])
AC_DEFINE_UNQUOTED(WWWDIR, "$wwwdir", [WWW dir for restconf daemon])
else
AC_DEFINE_UNQUOTED(WWWUSER, "", [WWW user for restconf daemon])
AC_DEFINE_UNQUOTED(WWWDIR, "", [WWW dir for restconf daemon])
fi
# Set default config file location # Set default config file location
CLIXON_DEFAULT_CONFIG=/usr/local/etc/clixon.xml CLIXON_DEFAULT_CONFIG=/usr/local/etc/clixon.xml
AC_ARG_WITH([configfile], AC_ARG_WITH([configfile],

View file

@ -63,7 +63,7 @@ RUN adduser -D -H www-data
RUN apk add --update nginx RUN apk add --update nginx
# Configure, build and install clixon # Configure, build and install clixon
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-wwwuser=www-data --enable-optyangs --with-restconf=fcgi RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --enable-optyangs --with-restconf=fcgi
RUN make RUN make
RUN make install RUN make install
@ -114,9 +114,9 @@ RUN adduser nginx clicon
RUN adduser www-data clicon RUN adduser www-data clicon
COPY --from=0 /clixon/build/ /usr/local/ COPY --from=0 /clixon/build/ /usr/local/
COPY --from=0 /www-data /www-data
# Manually created # Manually created
RUN mkdir /www-data
RUN chown www-data /www-data RUN chown www-data /www-data
RUN chgrp www-data /www-data RUN chgrp www-data /www-data

View file

@ -77,7 +77,7 @@ COPY clixon .
RUN adduser -D -H www-data RUN adduser -D -H www-data
# Configure, build and install clixon # Configure, build and install clixon
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-wwwuser=www-data --enable-optyangs --with-restconf=native RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --enable-optyangs --with-restconf=native
RUN make RUN make
RUN make install RUN make install
@ -129,10 +129,10 @@ RUN adduser -D -H clicon
RUN adduser www-data clicon RUN adduser www-data clicon
COPY --from=0 /clixon/build/ /usr/local/ COPY --from=0 /clixon/build/ /usr/local/
COPY --from=0 /www-data /www-data
COPY --from=0 /usr/local/lib/libevhtp.so* /usr/local/lib/ COPY --from=0 /usr/local/lib/libevhtp.so* /usr/local/lib/
# Manually created # Manually created
RUN mkdir /www-data
RUN chown www-data /www-data RUN chown www-data /www-data
RUN chgrp www-data /www-data RUN chgrp www-data /www-data

View file

@ -46,8 +46,6 @@ set -ux # e but clixon_backend may fail if test is run in parallell
DBG=${DBG:-0} DBG=${DBG:-0}
WWWUSER=${WWWUSER:-www-data}
# Initiate clixon configuration (env variable) # Initiate clixon configuration (env variable)
echo "$CONFIG" > /usr/local/etc/clixon.xml echo "$CONFIG" > /usr/local/etc/clixon.xml
@ -96,7 +94,6 @@ EOF
# sudo: setrlimit(RLIMIT_CORE): Operation not permitted # sudo: setrlimit(RLIMIT_CORE): Operation not permitted
echo "Set disable_coredump false" > /etc/sudo.conf echo "Set disable_coredump false" > /etc/sudo.conf
chmod 775 /usr/local/bin/test/site.sh chmod 775 /usr/local/bin/test/site.sh
if [ ! -d /run/nginx ]; then if [ ! -d /run/nginx ]; then
@ -109,7 +106,7 @@ fi
>&2 echo "nginx started" >&2 echo "nginx started"
# Start clixon_restconf (tests will kill this) # Start clixon_restconf (tests will kill this)
su -c "/www-data/clixon_restconf -l f/www-data/restconf.log -D $DBG" -s /bin/sh $WWWUSER & /usr/local/sbin/clixon_restconf -l f/var/log/restconf.log -D $DBG &
>&2 echo "clixon_restconf started" >&2 echo "clixon_restconf started"
# Set grp write XXX do this when creating # Set grp write XXX do this when creating

View file

@ -46,12 +46,6 @@ set -ux # e but clixon_backend may fail if test is run in parallell
# If set, enable debugging (of backend and restconf daemons) # If set, enable debugging (of backend and restconf daemons)
: ${DBG:=0} : ${DBG:=0}
# Web user default (ie what RESTCONF daemon runs as)
: ${WWWUSER:=www-data}
# Home dir for web user
: ${WWWDIR:=/www-data}
# Initiate clixon configuration (env variable) # Initiate clixon configuration (env variable)
echo "$CONFIG" > /usr/local/etc/clixon.xml echo "$CONFIG" > /usr/local/etc/clixon.xml
@ -115,7 +109,7 @@ openssl req -x509 -config ./ca.cnf -nodes -newkey rsa:4096 -keyout /etc/ssl/priv
# Start clixon_restconf # Start clixon_restconf
# -s https # -s https
# But dont use -s exposing local ports since there is problem with self-signed certs? # But dont use -s exposing local ports since there is problem with self-signed certs?
${WWWDIR}/clixon_restconf -l f${WWWDIR}/restconf.log -D $DBG & /usr/local/bin/clixon_restconf -l f/var/log/restconf.log -D $DBG &
>&2 echo "clixon_restconf started" >&2 echo "clixon_restconf started"
# Start clixon backend (tests will kill this) # Start clixon backend (tests will kill this)

View file

@ -150,9 +150,6 @@
/* WWW dir for restconf daemon */ /* WWW dir for restconf daemon */
#undef WWWDIR #undef WWWDIR
/* WWW user for restconf daemon */
#undef WWWUSER
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
`char[]'. */ `char[]'. */
#undef YYTEXT_POINTER #undef YYTEXT_POINTER

View file

@ -63,6 +63,6 @@ int nacm_datanode_write(clicon_handle h, cxobj *xr, cxobj *xt,
enum nacm_access access, enum nacm_access access,
char *username, cxobj *xnacm, cbuf *cbret); char *username, cxobj *xnacm, cbuf *cbret);
int nacm_access_pre(clicon_handle h, char *peername, char *username, cxobj **xnacmp); int nacm_access_pre(clicon_handle h, char *peername, char *username, cxobj **xnacmp);
int verify_nacm_user(enum nacm_credentials_t cred, char *peername, char *nacmname, cbuf *cbret); int verify_nacm_user(clicon_handle h, enum nacm_credentials_t cred, char *peername, char *nacmname, cbuf *cbret);
#endif /* _CLIXON_NACM_H */ #endif /* _CLIXON_NACM_H */

View file

@ -219,6 +219,7 @@ int clicon_sock_port(clicon_handle h);
int clicon_autocommit(clicon_handle h); int clicon_autocommit(clicon_handle h);
int clicon_startup_mode(clicon_handle h); int clicon_startup_mode(clicon_handle h);
enum priv_mode_t clicon_backend_privileges_mode(clicon_handle h); enum priv_mode_t clicon_backend_privileges_mode(clicon_handle h);
enum priv_mode_t clicon_restconf_privileges_mode(clicon_handle h);
enum nacm_credentials_t clicon_nacm_credentials(clicon_handle h); enum nacm_credentials_t clicon_nacm_credentials(clicon_handle h);
enum datastore_cache clicon_datastore_cache(clicon_handle h); enum datastore_cache clicon_datastore_cache(clicon_handle h);

View file

@ -1106,6 +1106,9 @@ nacm_access_check(clicon_handle h,
cxobj *x; cxobj *x;
cvec *nsc = NULL; cvec *nsc = NULL;
char *recovery_user; char *recovery_user;
#ifdef WITH_RESTCONF
char *wwwuser;
#endif
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL) if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
@ -1148,8 +1151,9 @@ nacm_access_check(clicon_handle h,
strcmp(peername, "root") == 0) strcmp(peername, "root") == 0)
goto permit; goto permit;
#ifdef WITH_RESTCONF #ifdef WITH_RESTCONF
wwwuser=clicon_option_str(h,"CLICON_RESTCONF_USER");
if (strcmp(username, recovery_user) == 0 && if (strcmp(username, recovery_user) == 0 &&
strcmp(peername, WWWUSER) == 0) wwwuser && strcmp(peername, wwwuser) == 0)
goto permit; goto permit;
#endif #endif
break; break;
@ -1252,6 +1256,8 @@ nacm_access_pre(clicon_handle h,
} }
/*! Verify nacm user with peer uid credentials /*! Verify nacm user with peer uid credentials
*
* @param[in] h Clixon handle
* @param[in] mode Peer credential mode: none, exact or except * @param[in] mode Peer credential mode: none, exact or except
* @param[in] peername Peer username if any * @param[in] peername Peer username if any
* @param[in] username username received in XML (eg for NACM) * @param[in] username username received in XML (eg for NACM)
@ -1270,13 +1276,17 @@ nacm_access_pre(clicon_handle h,
* - peer user is www (can be any NACM user) * - peer user is www (can be any NACM user)
*/ */
int int
verify_nacm_user(enum nacm_credentials_t cred, verify_nacm_user(clicon_handle h,
enum nacm_credentials_t cred,
char *peername, char *peername,
char *nacmname, char *nacmname,
cbuf *cbret) cbuf *cbret)
{ {
int retval = -1; int retval = -1;
cbuf *cbmsg = NULL; cbuf *cbmsg = NULL;
#ifdef WITH_RESTCONF
char *wwwuser;
#endif
if (cred == NC_NONE) if (cred == NC_NONE)
return 1; return 1;
@ -1294,7 +1304,8 @@ verify_nacm_user(enum nacm_credentials_t cred,
if (strcmp(peername, "root") == 0) if (strcmp(peername, "root") == 0)
goto ok; goto ok;
#ifdef WITH_RESTCONF #ifdef WITH_RESTCONF
if (strcmp(peername, WWWUSER) == 0) wwwuser=clicon_option_str(h,"CLICON_RESTCONF_USER");
if (wwwuser && strcmp(peername, wwwuser) == 0)
goto ok; goto ok;
#endif #endif
} }

View file

@ -871,7 +871,7 @@ clicon_startup_mode(clicon_handle h)
return clicon_str2int(startup_mode_map, mode); return clicon_str2int(startup_mode_map, mode);
} }
/*! Which privileges drop method to use /*! Which privileges drop method to use for backend
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @retval mode Privileges mode * @retval mode Privileges mode
*/ */
@ -885,6 +885,20 @@ clicon_backend_privileges_mode(clicon_handle h)
return clicon_str2int(priv_mode_map, mode); return clicon_str2int(priv_mode_map, mode);
} }
/*! Which privileges drop method to use for restconf
* @param[in] h Clicon handle
* @retval mode Privileges mode
*/
enum priv_mode_t
clicon_restconf_privileges_mode(clicon_handle h)
{
char *mode;
if ((mode = clicon_option_str(h, "CLICON_RESTCONF_PRIVILEGES")) == NULL)
return -1;
return clicon_str2int(priv_mode_map, mode);
}
/*! Which privileges drop method to use /*! Which privileges drop method to use
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @retval mode Privileges mode * @retval mode Privileges mode

View file

@ -277,11 +277,17 @@ clixon_proc_background(char **argv,
clicon_err(OE_UNIX, EINVAL, "argv is NULL"); clicon_err(OE_UNIX, EINVAL, "argv is NULL");
goto quit; goto quit;
} }
if (clicon_debug_get()){
i = 0;
while (argv[i]){
clicon_debug(1, "%s argv[%d]:%s", __FUNCTION__, i, argv[i]);
i++;
}
}
/* Before here call quit on error */ /* Before here call quit on error */
sigprocmask(0, NULL, &oset); sigprocmask(0, NULL, &oset);
set_signal(SIGINT, clixon_proc_sigint, &oldhandler); set_signal(SIGINT, clixon_proc_sigint, &oldhandler);
/* Now call done on error */ /* Now call done on error */
if ((child = fork()) < 0) { if ((child = fork()) < 0) {
clicon_err(OE_UNIX, errno, "fork"); clicon_err(OE_UNIX, errno, "fork");
goto done; goto done;
@ -327,7 +333,7 @@ clixon_proc_background(char **argv,
} }
#endif /* HAVE_SETNS */ #endif /* HAVE_SETNS */
if (execvp(argv[0], argv) < 0) { if (execvp(argv[0], argv) < 0) {
clicon_err(OE_UNIX, errno, "execv"); clicon_err(OE_UNIX, errno, "execv(%s)", argv[0]);
exit(1); exit(1);
} }
/* Not reached */ /* Not reached */

View file

@ -10,7 +10,7 @@ fi
restconf=$1 restconf=$1
if [ $(uname) = "FreeBSD" ]; then if [ $(uname) = "FreeBSD" ]; then
./configure --with-cligen=/usr/local --with-wwwuser=www --enable-optyangs --with-restconf=$restconf ./configure --with-cligen=/usr/local --enable-optyangs --with-restconf=$restconf
else else
./configure --enable-optyangs --with-restconf=$restconf ./configure --enable-optyangs --with-restconf=$restconf
fi fi

View file

@ -50,12 +50,6 @@ CXX=@CXX@
# C compiler # C compiler
CC=@CC@ CC=@CC@
# Web user default (ie what RESTCONF daemon runs as). Default: www-data
wwwuser=@wwwuser@
# Home dir for web user, by default /www-data
WWWDIR=@wwwdir@
# Top src dir # Top src dir
TOP_SRCDIR=@top_srcdir@ TOP_SRCDIR=@top_srcdir@
@ -68,8 +62,8 @@ DATASTORE_TOP="config"
# clixon yang revisions occuring in tests # clixon yang revisions occuring in tests
CLIXON_LIB_REV="2021-03-08" CLIXON_LIB_REV="2021-03-08"
CLIXON_CONFIG_REV="2021-03-08" CLIXON_CONFIG_REV="2021-05-20"
CLIXON_RESTCONF_REV="2021-03-15" CLIXON_RESTCONF_REV="2021-05-20"
CLIXON_EXAMPLE_REV="2020-12-01" CLIXON_EXAMPLE_REV="2020-12-01"
# Length of TSL RSA key # Length of TSL RSA key
@ -80,3 +74,4 @@ CERTKEYLEN=2048
# Linking: static or dynamic # Linking: static or dynamic
LINKAGE=@LINKAGE@ LINKAGE=@LINKAGE@
SH_SUFFIX=@SH_SUFFIX@ SH_SUFFIX=@SH_SUFFIX@

View file

@ -148,7 +148,7 @@ BUSER=clicon
: ${clixon_netconf:=$(which clixon_netconf)} : ${clixon_netconf:=$(which clixon_netconf)}
: ${clixon_restconf:=$WWWDIR/clixon_restconf} : ${clixon_restconf:=clixon_restconf}
: ${clixon_backend:=clixon_backend} : ${clixon_backend:=clixon_backend}
@ -357,7 +357,6 @@ function stop_restconf_pre(){
# 1) Dont use $clixon_restconf (dont work in valgrind) # 1) Dont use $clixon_restconf (dont work in valgrind)
# 2) Dont use -u $WWWUSER since clixon_restconf may drop privileges. # 2) Dont use -u $WWWUSER since clixon_restconf may drop privileges.
function stop_restconf(){ function stop_restconf(){
# sudo pkill -u $wwwuser -f clixon_restconf # Dont use $clixon_restoconf doesnt work in valgrind
sudo pkill -f clixon_restconf sudo pkill -f clixon_restconf
if [ $valgrindtest -eq 3 ]; then if [ $valgrindtest -eq 3 ]; then
sleep 1 sleep 1

View file

@ -26,10 +26,6 @@ new "Check installed files /usr"
if [ ! -d $dir/usr ]; then if [ ! -d $dir/usr ]; then
err $dir/usr err $dir/usr
fi fi
new "Check installed files /www-data"
if [ ! -d $dir/www-data ]; then
err $dir/www-data
fi
new "Check installed files clixon-config" new "Check installed files clixon-config"
if [ ! -f $dir/usr/local/share/clixon/clixon-config* ]; then if [ ! -f $dir/usr/local/share/clixon/clixon-config* ]; then
err $dir/usr/local/share/clixon/clixon-config* err $dir/usr/local/share/clixon/clixon-config*
@ -49,6 +45,7 @@ if [ ! ${LIBOPT} $dir/usr/local/lib/libclixon_backend${SH_SUFFIX} ]; then
fi fi
fi fi
new "Make DESTDIR install include" new "Make DESTDIR install include"
(cd ..; $make DESTDIR=$dir install-include) (cd ..; $make DESTDIR=$dir install-include)
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then

View file

@ -9,6 +9,7 @@
# See test_restconf_netns for network namespaces # See test_restconf_netns for network namespaces
# See test_restconf_internal_cases for some special use-cases # See test_restconf_internal_cases for some special use-cases
# XXX Lots of sleeps to remove race conditions. I am sure there are others way to fix this # XXX Lots of sleeps to remove race conditions. I am sure there are others way to fix this
# Note you cant rely on ps aux|grep <cmd> since ps delays after fork from clixon_backend->restconf
# Magic line must be first in script (see README.md) # Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
@ -22,6 +23,17 @@ startupdb=$dir/startup_db
RESTCONFDBG=$DBG RESTCONFDBG=$DBG
RCPROTO=http # no ssl here RCPROTO=http # no ssl here
# log-destination in restconf xml: syslog or file
: ${LOGDST:=syslog}
# Set daemon command-line to -f
if [ "$LOGDST" = syslog ]; then
LOGDST_CMD="s"
elif [ "$LOGDST" = file ]; then
LOGDST_CMD="f/var/log/clixon_restconf.log"
else
err1 "No such logdst: $LOGDST"
fi
if [ "${WITH_RESTCONF}" = "fcgi" ]; then if [ "${WITH_RESTCONF}" = "fcgi" ]; then
EXTRACONF="<CLICON_FEATURE>clixon-restconf:fcgi</CLICON_FEATURE>" EXTRACONF="<CLICON_FEATURE>clixon-restconf:fcgi</CLICON_FEATURE>"
else else
@ -100,10 +112,10 @@ EOF
err "No pid return value" "$retx" err "No pid return value" "$retx"
fi fi
if $active; then if $active; then
expect="^<rpc-reply $DEFAULTNS><active $LIBNS>$active</active><description $LIBNS>Clixon RESTCONF process</description><command $LIBNS>/www-data/clixon_restconf -f $cfg -D [0-9]</command><status $LIBNS>$status</status><starttime $LIBNS>20[0-9][0-9]\-[0-9][0-9]\-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]*Z</starttime><pid $LIBNS>$pid</pid></rpc-reply>]]>]]>$" expect="^<rpc-reply $DEFAULTNS><active $LIBNS>$active</active><description $LIBNS>Clixon RESTCONF process</description><command $LIBNS>/.*/clixon_restconf -f $cfg -D [0-9] -l ${LOGDST_CMD}</command><status $LIBNS>$status</status><starttime $LIBNS>20[0-9][0-9]\-[0-9][0-9]\-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]*Z</starttime><pid $LIBNS>$pid</pid></rpc-reply>]]>]]>$"
else else
# inactive, no startime or pid # inactive, no startime or pid
expect="^<rpc-reply $DEFAULTNS><active $LIBNS>$active</active><description $LIBNS>Clixon RESTCONF process</description><command $LIBNS>/www-data/clixon_restconf -f $cfg -D [0-9]</command><status $LIBNS>$status</status></rpc-reply>]]>]]>$" expect="^<rpc-reply $DEFAULTNS><active $LIBNS>$active</active><description $LIBNS>Clixon RESTCONF process</description><command $LIBNS>/.*/clixon_restconf -f $cfg -D [0-9] -l ${LOGDST_CMD}</command><status $LIBNS>$status</status></rpc-reply>]]>]]>$"
fi fi
match=$(echo "$retx" | grep --null -Go "$expect") match=$(echo "$retx" | grep --null -Go "$expect")
if [ -z "$match" ]; then if [ -z "$match" ]; then
@ -140,6 +152,7 @@ cat<<EOF > $startupdb
<auth-type>none</auth-type> <auth-type>none</auth-type>
<pretty>false</pretty> <pretty>false</pretty>
<debug>$RESTCONFDBG</debug> <debug>$RESTCONFDBG</debug>
<log-destination>$LOGDST</log-destination>
<socket> <socket>
<namespace>default</namespace> <namespace>default</namespace>
<address>0.0.0.0</address> <address>0.0.0.0</address>
@ -169,14 +182,19 @@ new "wait backend"
wait_backend wait_backend
# For debug # For debug
#>&2 echo "curl $CURLOPTS -X POST -H \"Content-Type: application/yang-data+json\" $RCPROTO://localhost/restconf/operations/clixon-lib:process-control -d '{\"clixon-lib:input\":{\"name\":\"restconf\",\"operation\":\"status\"}}'" >&2 echo "curl $CURLOPTS -X POST -H \"Content-Type: application/yang-data+json\" $RCPROTO://localhost/restconf/operations/clixon-lib:process-control -d '{\"clixon-lib:input\":{\"name\":\"restconf\",\"operation\":\"status\"}}'"
# Get pid of running process and check return xml # Get pid of running process and check return xml
new "1. Get rpc status" new "1. Get rpc status"
rpcstatus true running rpcstatus true running
pid0=$pid # Save pid0 pid0=$pid # Save pid0
if [ $pid0 -eq 0 ]; then err "Pid" 0; fi if [ $pid0 -eq 0 ]; then err "Pid" 0; fi
# pid0 is active but doesnt mean socket is open, wait for that
new "Wait for restconf to start"
wait_restconf
new "check restconf process runnng using ps pid:$pid0" new "check restconf process runnng using ps pid:$pid0"
ps=$(ps -hp $pid0) ps=$(ps -hp $pid0)
@ -219,6 +237,11 @@ if [ "$pid0" -eq "$pid1" ]; then
err1 "not $pid0" "$pid1" err1 "not $pid0" "$pid1"
fi fi
# This is to avoid a race condition: $pid1 is starting and may not have come up yet when we
# we later stop it.
new "Wait for $pid1 to start"
wait_restconf
new "4. stop restconf RPC" new "4. stop restconf RPC"
rpcoperation stop rpcoperation stop
if [ $? -ne 0 ]; then exit -1; fi if [ $? -ne 0 ]; then exit -1; fi
@ -335,6 +358,7 @@ cat<<EOF > $startupdb
<auth-type>none</auth-type> <auth-type>none</auth-type>
<pretty>false</pretty> <pretty>false</pretty>
<debug>$RESTCONFDBG</debug> <debug>$RESTCONFDBG</debug>
<log-destination>$LOGDST</log-destination>
<socket> <socket>
<namespace>default</namespace> <namespace>default</namespace>
<address>0.0.0.0</address> <address>0.0.0.0</address>
@ -375,7 +399,7 @@ rpcstatus false stopped
if [ $pid -ne 0 ]; then err "Pid" "$pid"; fi if [ $pid -ne 0 ]; then err "Pid" "$pid"; fi
new "Enable restconf" new "Enable restconf"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><default-operation>merge</default-operation><target><candidate/></target><config><restconf xmlns=\"http://clicon.org/restconf\"><enable>true</enable><debug>$RESTCONFDBG</debug></restconf></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><default-operation>merge</default-operation><target><candidate/></target><config><restconf xmlns=\"http://clicon.org/restconf\"><enable>true</enable><debug>$RESTCONFDBG</debug><log-destination>$LOGDST</log-destination></restconf></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
new "commit enable" new "commit enable"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
@ -457,6 +481,8 @@ new "endtest"
endtest endtest
# Set by restconf_config # Set by restconf_config
unset LOGDST
unset LOGDST_CMD
unset pid unset pid
unset RESTCONFIG unset RESTCONFIG
unset RESTCONFDBG unset RESTCONFDBG

View file

@ -34,6 +34,10 @@ RESTCONFDBG=$DBG
RCPROTO=http # no ssl here RCPROTO=http # no ssl here
INVALIDADDR=251.1.1.1 # used by fourth usecase as invalid INVALIDADDR=251.1.1.1 # used by fourth usecase as invalid
# log-destination in restconf xml: syslog or file
LOGDST=syslog
LOGDST_CMD="s"
if [ "${WITH_RESTCONF}" = "fcgi" ]; then if [ "${WITH_RESTCONF}" = "fcgi" ]; then
EXTRACONF="<CLICON_FEATURE>clixon-restconf:fcgi</CLICON_FEATURE>" EXTRACONF="<CLICON_FEATURE>clixon-restconf:fcgi</CLICON_FEATURE>"
else else
@ -114,10 +118,10 @@ EOF
err "No pid return value" "$retx" err "No pid return value" "$retx"
fi fi
if $active; then if $active; then
expect="^<rpc-reply $DEFAULTNS><active $LIBNS>$active</active><description $LIBNS>Clixon RESTCONF process</description><command $LIBNS>/www-data/clixon_restconf -f $cfg -D [0-9]</command><status $LIBNS>$status</status><starttime $LIBNS>20[0-9][0-9]\-[0-9][0-9]\-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]*Z</starttime><pid $LIBNS>$pid</pid></rpc-reply>]]>]]>$" expect="^<rpc-reply $DEFAULTNS><active $LIBNS>$active</active><description $LIBNS>Clixon RESTCONF process</description><command $LIBNS>/.*/clixon_restconf -f $cfg -D [0-9] -l ${LOGDST_CMD}</command><status $LIBNS>$status</status><starttime $LIBNS>20[0-9][0-9]\-[0-9][0-9]\-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]*Z</starttime><pid $LIBNS>$pid</pid></rpc-reply>]]>]]>$"
else else
# inactive, no startime or pid # inactive, no startime or pid
expect="^<rpc-reply $DEFAULTNS><active $LIBNS>$active</active><description $LIBNS>Clixon RESTCONF process</description><command $LIBNS>/www-data/clixon_restconf -f $cfg -D [0-9]</command><status $LIBNS>$status</status></rpc-reply>]]>]]>$" expect="^<rpc-reply $DEFAULTNS><active $LIBNS>$active</active><description $LIBNS>Clixon RESTCONF process</description><command $LIBNS>/.*/clixon_restconf -f $cfg -D [0-9] -l ${LOGDST_CMD}</command><status $LIBNS>$status</status></rpc-reply>]]>]]>$"
fi fi
match=$(echo "$retx" | grep --null -Go "$expect") match=$(echo "$retx" | grep --null -Go "$expect")
if [ -z "$match" ]; then if [ -z "$match" ]; then
@ -158,6 +162,8 @@ new "1. get status"
rpcstatus false stopped rpcstatus false stopped
if [ $pid -ne 0 ]; then err "Pid" "$pid"; fi if [ $pid -ne 0 ]; then err "Pid" "$pid"; fi
new "enable minimal restconf, no server" new "enable minimal restconf, no server"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config>$RESTCONFIG1</config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-config><target><candidate/></target><config>$RESTCONFIG1</config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
@ -235,6 +241,7 @@ RESTCONFIG1=$(cat <<EOF
<restconf xmlns="http://clicon.org/restconf"> <restconf xmlns="http://clicon.org/restconf">
<enable>true</enable> <enable>true</enable>
<debug>$RESTCONFDBG</debug> <debug>$RESTCONFDBG</debug>
<log-destination>$LOGDST</log-destination>
<auth-type>none</auth-type> <auth-type>none</auth-type>
<pretty>false</pretty> <pretty>false</pretty>
<socket><namespace>default</namespace><address>221.0.0.1</address><port>80</port><ssl>false</ssl></socket> <socket><namespace>default</namespace><address>221.0.0.1</address><port>80</port><ssl>false</ssl></socket>
@ -305,6 +312,7 @@ RESTCONFIG1=$(cat <<EOF
<restconf xmlns="http://clicon.org/restconf"> <restconf xmlns="http://clicon.org/restconf">
<enable>true</enable> <enable>true</enable>
<debug>$RESTCONFDBG</debug> <debug>$RESTCONFDBG</debug>
<log-destination>$LOGDST</log-destination>
<auth-type>none</auth-type> <auth-type>none</auth-type>
<pretty>false</pretty> <pretty>false</pretty>
<socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket> <socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket>
@ -329,7 +337,7 @@ if [ $pid1 -eq 0 ]; then err "Pid" 0; fi
sleep $DEMSLEEP sleep $DEMSLEEP
new "Get restconf config 1" new "Get restconf config 1"
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://localhost/restconf/data/clixon-restconf:restconf)" 0 "HTTP/1.1 200 OK" "<restconf xmlns=\"http://clicon.org/restconf\"><enable>true</enable><auth-type>none</auth-type><debug>$RESTCONFDBG</debug><enable-core-dump>false</enable-core-dump><pretty>false</pretty><socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket></restconf>" expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://localhost/restconf/data/clixon-restconf:restconf)" 0 "HTTP/1.1 200 OK" "<restconf xmlns=\"http://clicon.org/restconf\"><enable>true</enable><auth-type>none</auth-type><debug>$RESTCONFDBG</debug><log-destination>$LOGDST</log-destination><enable-core-dump>false</enable-core-dump><pretty>false</pretty><socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket></restconf>"
# remove it # remove it
new "Delete server" new "Delete server"
@ -398,6 +406,7 @@ RESTCONFIG1=$(cat <<EOF
<restconf xmlns="http://clicon.org/restconf"> <restconf xmlns="http://clicon.org/restconf">
<enable>true</enable> <enable>true</enable>
<debug>$RESTCONFDBG</debug> <debug>$RESTCONFDBG</debug>
<log-destination>$LOGDST</log-destination>
<auth-type>none</auth-type> <auth-type>none</auth-type>
<pretty>false</pretty> <pretty>false</pretty>
<socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket> <socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket>
@ -423,7 +432,7 @@ if [ $pid1 -eq 0 ]; then err "Pid" 0; fi
sleep $DEMSLEEP sleep $DEMSLEEP
new "Get restconf config" new "Get restconf config"
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://localhost/restconf/data/clixon-restconf:restconf)" 0 "HTTP/1.1 200 OK" "<restconf xmlns=\"http://clicon.org/restconf\"><enable>true</enable><auth-type>none</auth-type><debug>$RESTCONFDBG</debug><enable-core-dump>false</enable-core-dump><pretty>false</pretty><socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket><socket><namespace>default</namespace><address>$INVALIDADDR</address><port>8080</port><ssl>false</ssl></socket></restconf>" expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://localhost/restconf/data/clixon-restconf:restconf)" 0 "HTTP/1.1 200 OK" "<restconf xmlns=\"http://clicon.org/restconf\"><enable>true</enable><auth-type>none</auth-type><debug>$RESTCONFDBG</debug><log-destination>$LOGDST</log-destination><enable-core-dump>false</enable-core-dump><pretty>false</pretty><socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket><socket><namespace>default</namespace><address>$INVALIDADDR</address><port>8080</port><ssl>false</ssl></socket></restconf>"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
new "Kill backend" new "Kill backend"
@ -445,6 +454,8 @@ new "endtest"
endtest endtest
# Set by restconf_config # Set by restconf_config
unset LOGDST
unset LOGDST_CMD
unset RESTCONFIG1 unset RESTCONFIG1
unset RESTCONFIG2 unset RESTCONFIG2
unset RESTCONFDBG unset RESTCONFDBG

View file

@ -41,11 +41,11 @@ datarootdir = @datarootdir@
# See also OPT_YANG_INSTALLDIR for the standard yang files # See also OPT_YANG_INSTALLDIR for the standard yang files
YANG_INSTALLDIR = @YANG_INSTALLDIR@ YANG_INSTALLDIR = @YANG_INSTALLDIR@
YANGSPECS = clixon-config@2021-03-08.yang YANGSPECS = clixon-config@2021-05-20.yang # 5.2
YANGSPECS += clixon-lib@2021-03-08.yang YANGSPECS += clixon-lib@2021-03-08.yang # 5.1
YANGSPECS += clixon-rfc5277@2008-07-01.yang YANGSPECS += clixon-rfc5277@2008-07-01.yang
YANGSPECS += clixon-xml-changelog@2019-03-21.yang YANGSPECS += clixon-xml-changelog@2019-03-21.yang
YANGSPECS += clixon-restconf@2021-03-15.yang YANGSPECS += clixon-restconf@2021-05-20.yang # 5.2
APPNAME = clixon # subdir ehere these files are installed APPNAME = clixon # subdir ehere these files are installed

View file

@ -43,6 +43,22 @@ module clixon-config {
***** END LICENSE BLOCK *****"; ***** END LICENSE BLOCK *****";
revision 2021-05-20 {
description
"Added option:
CLICON_RESTCONF_USER
CLICON_RESTCONF_PRIVILEGES
CLICON_RESTCONF_INSTALL_DIR
Released in Clixon 5.2";
}
revision 2021-03-08 {
description
"Added option:
CLICON_NETCONF_HELLO_OPTIONAL
CLICON_CLI_AUTOCLI_EXCLUDE
CLICON_XMLDB_UPGRADE_CHECKOLD
Released in Clixon 5.1";
}
revision 2020-12-30 { revision 2020-12-30 {
description description
"Added option: "Added option:
@ -197,7 +213,7 @@ module clixon-config {
} }
typedef cli_genmodel_type{ typedef cli_genmodel_type{
description description
"How to generate CLI from YANG model, "How to generate auto CLI from YANG model,
eg {container c {list a{ key x; leaf x; leaf y;}}"; eg {container c {list a{ key x; leaf x; leaf y;}}";
type enumeration{ type enumeration{
enum NONE{ enum NONE{
@ -430,6 +446,20 @@ module clixon-config {
type string; type string;
description "Location of netconf (frontend) .so plugins"; description "Location of netconf (frontend) .so plugins";
} }
leaf CLICON_NETCONF_HELLO_OPTIONAL {
type boolean;
default false;
description
"This option relates to RFC 6241 Sec 8.1 Capabilies Exchange where it says:
When the NETCONF session is opened, each peer (both client and server) MUST
send a <hello> element...
If true, an RPC can be processed directly with no preceeding hello message.
This is legacy clixon but invalid according to the RFC.
If false, NETCONF hello messages are mandatory before any RPC can be processed.
That is, if clixon receives an rpc with no previous hello message, an error
is returned, which conforms to the RFC.
Note this applies only to external NETCONF, not the internal (IPC) netconf";
}
leaf CLICON_RESTCONF_DIR { leaf CLICON_RESTCONF_DIR {
type string; type string;
description description
@ -445,10 +475,20 @@ module clixon-config {
description description
"FastCGI unix socket. Should be specified in webserver "FastCGI unix socket. Should be specified in webserver
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock
Only if with-restconf=fcgi, NOT evhtp Only if with-restconf=fcgi, NOT native
Note: Obsolete, use fcgi-socket in clixon-restconf.yang instead"; Note: Obsolete, use fcgi-socket in clixon-restconf.yang instead";
status obsolete; status obsolete;
} }
leaf CLICON_RESTCONF_INSTALL_DIR {
type string;
default "/usr/local/sbin";
description
"Path to clixon-restconf daemon binary as used by backend if started internally
Discussion: Somewhat problematic to have it as run time option. It may think it
should be known at configure or install time, but for example the main docker
installation moves the binaries, and this may be true elsewehere too.
Maybe one could locate it via PATHs search";
}
leaf CLICON_RESTCONF_PRETTY { leaf CLICON_RESTCONF_PRETTY {
type boolean; type boolean;
@ -465,6 +505,22 @@ module clixon-config {
Note: Obsolete, use pretty in clixon-restconf.yang instead"; Note: Obsolete, use pretty in clixon-restconf.yang instead";
status obsolete; status obsolete;
} }
leaf CLICON_RESTCONF_USER {
type string;
description
"User name for restconf.
In pre-5.2 code this was configured as compile-time constant WWWUSER with
default value www-data
See also CLICON_PRIVILEGES setting";
default www-data;
}
leaf CLICON_RESTCONF_PRIVILEGES {
type priv_mode;
default drop_perm;
description
"Restconf privileges mode.
If drop_perm or drop_temp then drop privileges to CLICON_RESTCONF_USER.";
}
leaf CLICON_CLI_DIR { leaf CLICON_CLI_DIR {
type string; type string;
description description
@ -506,7 +562,7 @@ module clixon-config {
type string; type string;
default "datamodel"; default "datamodel";
description description
"If CLICON_CLI_GENMOEL is set, CLI specs can reference the "If CLICON_CLI_GENMODEL is set, CLI specs can reference the
model syntax using a model tree set by this option. model syntax using a model tree set by this option.
Three trees are generated with this name as a base, (assuming base is datamodel): Three trees are generated with this name as a base, (assuming base is datamodel):
- @datamodel - a clispec for navigating in editing a configuration (set/merge/delete) - @datamodel - a clispec for navigating in editing a configuration (set/merge/delete)
@ -526,7 +582,16 @@ module clixon-config {
leaf CLICON_CLI_GENMODEL_TYPE { leaf CLICON_CLI_GENMODEL_TYPE {
type cli_genmodel_type; type cli_genmodel_type;
default "VARS"; default "VARS";
description "How to generate and show CLI syntax: VARS|ALL"; description "How to generate and show auto CLI syntax: VARS|ALL|HIDE";
}
leaf CLICON_CLI_AUTOCLI_EXCLUDE {
type string;
description
"List of module names that should not be generated autocli from
Example:
<CLICON_CLI_AUTOCLI_EXCLUDE>clixon-restconf</CLICON_CLI_AUTOCLI_EXCLUDE>
means generate autocli for all models except clixon-restconf.yang
The value can be a list of space separated module names";
} }
leaf CLICON_CLI_VARONLY { leaf CLICON_CLI_VARONLY {
type int32; type int32;
@ -676,7 +741,7 @@ module clixon-config {
user (eg datastores). user (eg datastores).
It also sets the backend unix socket owner to this user, but its group It also sets the backend unix socket owner to this user, but its group
is set by CLICON_SOCK_GROUP. is set by CLICON_SOCK_GROUP.
See also CLICON_PRIVILEGES setting"; See also CLICON_BACKEND_PRIVILEGES setting";
} }
leaf CLICON_BACKEND_PRIVILEGES { leaf CLICON_BACKEND_PRIVILEGES {
type priv_mode; type priv_mode;
@ -697,6 +762,8 @@ module clixon-config {
description description
"If set, enable process-control of restconf daemon, ie start/stop restconf "If set, enable process-control of restconf daemon, ie start/stop restconf
daemon internally from backend daemon. daemon internally from backend daemon.
Also, if set, restconf daemon queries backend for its config
if not set, restconf daemon reads its config from main config file
It uses clixon-restconf.yang for config and clixon-lib.yang for RPC It uses clixon-restconf.yang for config and clixon-lib.yang for RPC
Process control of restconf daemon is as follows: Process control of restconf daemon is as follows:
- on RPC start, if enable is true, start the service, if false, error or ignore it - on RPC start, if enable is true, start the service, if false, error or ignore it
@ -748,6 +815,16 @@ module clixon-config {
yang modules match. yang modules match.
See also CLICON_MODULE_LIBRARY_RFC7895"; See also CLICON_MODULE_LIBRARY_RFC7895";
} }
leaf CLICON_XMLDB_UPGRADE_CHECKOLD {
type boolean;
default true;
description
"Controls behavior of check of startup in upgrade scenarios.
If set, yang bind and check datastore syntax against the old Yang.
The old yang must be accessible via YANG_DIR.
Will fail startup if old yang not found or if old config does not match.
If not set, no yang check of old config is made until it is upgraded to new yang.";
}
leaf CLICON_XML_CHANGELOG { leaf CLICON_XML_CHANGELOG {
type boolean; type boolean;
default false; default false;

View file

@ -43,6 +43,17 @@ module clixon-restconf {
***** END LICENSE BLOCK *****"; ***** END LICENSE BLOCK *****";
revision 2021-05-20 {
description
"Added log-destination for restconf
Released in Clixon 5.2";
}
revision 2021-03-15 {
description
"make authentication-type none a feature
Added flag to enable core dumps
Released in Clixon 5.1";
}
revision 2020-12-30 { revision 2020-12-30 {
description description
"Added: debug field "Added: debug field
@ -53,6 +64,7 @@ module clixon-restconf {
description description
"Initial release"; "Initial release";
} }
feature fcgi { feature fcgi {
description description
"This feature indicates that the restconf server supports the fast-cgi reverse "This feature indicates that the restconf server supports the fast-cgi reverse
@ -62,9 +74,15 @@ module clixon-restconf {
The alternative is the internal HTTP solution using evhtp."; The alternative is the internal HTTP solution using evhtp.";
} }
feature allow-auth-none {
description
"This feature allows the use of authentication-type none.";
}
typedef http-auth-type { typedef http-auth-type {
type enumeration { type enumeration {
enum none { enum none {
if-feature "allow-auth-none";
description description
"Incoming message are set to authenticated by default. No ca-auth callback is called, "Incoming message are set to authenticated by default. No ca-auth callback is called,
Authenticated user is set to special user 'none'. Authenticated user is set to special user 'none'.
@ -85,6 +103,20 @@ module clixon-restconf {
description description
"Enumeration of HTTP authorization types."; "Enumeration of HTTP authorization types.";
} }
typedef log-destination {
type enumeration {
enum syslog {
description
"Log to syslog with:
ident: clixon_restconf and PID
facility: LOG_USER";
}
enum file {
description
"Log to generated file at /var/log/clixon_restconf.log";
}
}
}
grouping clixon-restconf{ grouping clixon-restconf{
description description
"HTTP RESTCONF configuration."; "HTTP RESTCONF configuration.";
@ -103,19 +135,30 @@ module clixon-restconf {
description description
"The authentication type. "The authentication type.
Note client-certificate applies only if ssl-enable is true and socket has ssl"; Note client-certificate applies only if ssl-enable is true and socket has ssl";
default none; default user;
} }
leaf debug { leaf debug {
description description
"Set debug level of restconf daemon. "Set debug level of restconf daemon.
0 is no debug, 1 is debugging, more is detailed debug. 0 is no debug, 1 is debugging, more is detailed debug.
Debug logs will be directed to syslog with Debug logs will be directed to log-destination with LOG_DEBUG level (for syslog)";
ident: clixon_restconf and PID
facility: LOG_USER
level: LOG_DEBUG";
type uint32; type uint32;
default 0; default 0;
} }
leaf log-destination {
description
"Log destination.
If debug is not set, only notice, error and warning will be logged";
type log-destination;
default syslog;
}
leaf enable-core-dump {
description
"enable core dumps.
this is a no-op on systems that don't support it.";
type boolean;
default false;
}
leaf pretty { leaf pretty {
type boolean; type boolean;
default true; default true;
@ -170,7 +213,8 @@ module clixon-restconf {
type string; type string;
description description
"Network namespace. "Network namespace.
On platforms where namespaces are not suppported, always 'default'"; On platforms where namespaces are not suppported, 'default'
Default value can be changed by RESTCONF_NETNS_DEFAULT";
} }
leaf address { leaf address {
type inet:ip-address; type inet:ip-address;