* 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
* 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
* 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.

View file

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

View file

@ -1796,7 +1796,7 @@ from_client_msg(clicon_handle h,
goto done;
if (ret == 0){ /* Do NACM RPC validation */
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;
if (ret == 0) /* credentials fail */
goto reply;

View file

@ -287,9 +287,9 @@ check_drop_priv(clicon_handle h,
enum priv_mode_t priv_mode = PM_NONE;
char *backend_user = NULL;
/* Get privileges mode (for dropping privileges) */
priv_mode = clicon_backend_privileges_mode(h);
if (priv_mode == PM_NONE)
if ((priv_mode = clicon_backend_privileges_mode(h)) == PM_NONE)
goto ok;
/* From here, drop privileges */
@ -575,9 +575,6 @@ main(int argc,
usage(h, argv[0]);
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 */
if (clixon_plugin_module_init(h) < 0)

View file

@ -65,32 +65,62 @@
*
* 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.
* @param[in] h Clixon backend
* @param[in] dbg Debug string , eg "0" or "1"
* @param[in] h Clixon backend
* @param[in] xt XML target
*/
static int
restconf_pseudo_set_debug(clicon_handle h,
char *dbg)
restconf_pseudo_set_log(clicon_handle h,
cxobj *xt)
{
int retval = -1;
char **argv;
int argc;
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;
if (clixon_process_argv_get(h, RESTCONF_PROCESS, &argv, &argc) < 0)
goto done;
for (i=0; i<argc; i++){
if (argv[i] == NULL)
break;
if (strcmp(argv[i], "-D") == 0 && argc > i+1 && argv[i+1]){
free(argv[i+1]);
if ((argv[i+1] = strdup(dbg)) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
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;
}
}
}
break;
i++;
}
if (strcmp(argv[i], "-D") == 0 && argc > i+1 && argv[i+1]){
if (dbg){
free(argv[i+1]);
if ((argv[i+1] = strdup(dbg)) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
}
i++;
}
}
ok:
@ -111,7 +141,6 @@ restconf_rpc_wrapper(clicon_handle h,
{
int retval = -1;
cxobj *xt = NULL;
cxobj *xb;
clicon_debug(1, "%s", __FUNCTION__);
switch (*operation){
@ -133,10 +162,8 @@ restconf_rpc_wrapper(clicon_handle h,
* but in this way it is set directly in its input args.
* Its a trick.
*/
if ((xb = xpath_first(xt, NULL, "/restconf/debug")) != NULL){
if (restconf_pseudo_set_debug(h, xml_body(xb)) < 0)
goto done;
}
if (restconf_pseudo_set_log(h, xt) < 0)
goto done;
}
break;
default:
@ -165,7 +192,7 @@ restconf_pseudo_process_control(clicon_handle h)
int nr;
cbuf *cb = NULL;
nr = 6;
nr = 8;
if ((argv = calloc(nr, sizeof(char *))) == NULL){
clicon_err(OE_UNIX, errno, "calloc");
goto done;
@ -175,15 +202,23 @@ restconf_pseudo_process_control(clicon_handle h)
clicon_err(OE_UNIX, errno, "cbuf_new");
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++] = "-f";
argv[i++] = clicon_option_str(h, "CLICON_CONFIGFILE");
/* Add debug if backend has debug.
* 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++] = "0";
argv[i++] = "-l";
argv[i++] = "s"; /* There is also log-destination in clixon-restconf.yang */
argv[i++] = NULL;
assert(i==nr);
if (clixon_process_register(h, RESTCONF_PROCESS,
@ -201,7 +236,7 @@ restconf_pseudo_process_control(clicon_handle h)
return retval;
}
/*! Restconf pseduo-plugin process validate
/*! Restconf pseudo-plugin process validate
*/
static int
restconf_pseudo_process_validate(clicon_handle h,
@ -241,7 +276,6 @@ restconf_pseudo_process_commit(clicon_handle h,
cxobj *xsource;
cxobj *cx;
int enabled = 0;
cxobj *xb;
clicon_debug(1, "%s", __FUNCTION__);
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.
* Its a trick.
*/
if ((xb = xpath_first(xtarget, NULL, "/restconf/debug")) != NULL){
if (restconf_pseudo_set_debug(h, xml_body(xb)) < 0)
goto done;
}
if (restconf_pseudo_set_log(h, xtarget) < 0)
goto done;
/* Toggle start/stop if enable flag changed */
if ((cx = xpath_first(xtarget, NULL, "/restconf/enable")) != NULL &&
xml_flag(cx, XML_FLAG_CHANGE|XML_FLAG_ADD)){

View file

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

View file

@ -82,11 +82,11 @@ Start clixon backend daemon (if not already started)
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:
```
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:
@ -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:
```
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:
```
@ -240,7 +240,7 @@ curl -G http://127.0.0.1/restconf/data/*
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
```
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();
restconf_handle_exit(h);
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 */
return 0;
}
@ -495,18 +495,18 @@ restconf_uripath(clicon_handle h)
/*! Drop privileges from root to user (or already at user)
* @param[in] h Clicon handle
* @param[in] user Drop to this level
* Group set to clicon to communicate with backend
*/
int
restconf_drop_privileges(clicon_handle h,
char *user)
restconf_drop_privileges(clicon_handle h)
{
int retval = -1;
uid_t newuid = -1;
uid_t uid;
char *group;
gid_t gid = -1;
char *user;
enum priv_mode_t priv_mode = PM_NONE;
clicon_debug(1, "%s", __FUNCTION__);
/* Sanity check: backend group exists */
@ -523,12 +523,19 @@ restconf_drop_privileges(clicon_handle h,
clicon_configfile(h));
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 */
if (name2uid(user, &newuid) < 0){
clicon_err(OE_DAEMON, errno, "'%s' is not a valid user .\n", user);
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)
goto ok;
if (uid != 0){
@ -539,12 +546,22 @@ restconf_drop_privileges(clicon_handle h,
clicon_err(OE_DAEMON, errno, "setgid %d", gid);
goto done;
}
if (drop_priv_perm(newuid) < 0)
goto done;
/* Verify you cannot regain root privileges */
if (setuid(0) != -1){
clicon_err(OE_DAEMON, EPERM, "Could regain root privilieges");
goto done;
switch (priv_mode){
case PM_DROP_PERM:
if (drop_priv_perm(newuid) < 0)
goto done;
/* Verify you cannot regain root privileges */
if (setuid(0) != -1){
clicon_err(OE_DAEMON, EPERM, "Could regain root privilieges");
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)",
__FUNCTION__, user, newuid);

View file

@ -81,7 +81,7 @@ int restconf_terminate(clicon_handle h);
int restconf_insert_attributes(cxobj *xdata, cvec *qvec);
int restconf_main_extension_cb(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
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_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);

View file

@ -88,7 +88,7 @@
#include "restconf_stream.h"
/* 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
* @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-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",
argv0
);
@ -225,7 +226,6 @@ main(int argc,
size_t cligen_buflen;
size_t cligen_bufthreshold;
int dbg = 0;
int drop_privileges = 1;
int ret;
cxobj *xrestconf1 = NULL; /* Local config file */
cxobj *xconfig2 = NULL;
@ -234,6 +234,7 @@ main(int argc,
cvec *nsc = NULL;
cxobj *xerr = NULL;
struct passwd *pw;
char *wwwuser;
/* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
@ -272,6 +273,7 @@ main(int argc,
goto done;
break;
} /* switch getopt */
dbg=1;
/*
* 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);
break;
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 'o':{ /* Configuration option */
@ -507,11 +510,12 @@ main(int argc,
goto done;
}
_MYSOCK = sock;
/* Change group of fcgi sock fronting reverse proxy to WWWUSER, the effective group is clicon
* which is backend. */
/* Change group of fcgi sock fronting reverse proxy to CLICON_RESTCONF_USER,
* the effective group is clicon which is backend. */
gid_t wgid = -1;
if (group_name2gid(WWWUSER, &wgid) < 0){
clicon_log(LOG_ERR, "'%s' does not seem to be a valid user group.", WWWUSER);
wwwuser = clicon_option_str(h, "CLICON_RESTCONF_USER");
if (group_name2gid(wwwuser, &wgid) < 0){
clicon_log(LOG_ERR, "'%s' does not seem to be a valid user group.", wwwuser);
goto done;
}
if (chown(sockpath, -1, wgid) < 0){
@ -525,11 +529,11 @@ main(int argc,
clicon_err(OE_UNIX, errno, "chmod");
goto done;
}
if (drop_privileges){
/* Drop privileges to WWWUSER if started as root */
if (restconf_drop_privileges(h, WWWUSER) < 0)
goto done;
}
/* Drop privileges if started as root to CLICON_RESTCONF_USER
* and use drop mode: CLICON_RESTCONF_PRIVILEGES
*/
if (restconf_drop_privileges(h) < 0)
goto done;
if (FCGX_InitRequest(req, sock, 0) != 0){
clicon_err(OE_CFG, errno, "FCGX_InitRequest");
goto done;

View file

@ -168,7 +168,7 @@
#include "restconf_native.h" /* Restconf-openssl mode specific headers*/
/* 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
* Should work both ways, but in the ninblocking case,
@ -1093,7 +1093,7 @@ restconf_connection(int s,
if (conn->bev != NULL){
struct evbuffer *ev;
size_t buflen0;
size_t buflen;
size_t buflen1;
char *buf = NULL;
if ((rc = conn->arg) == NULL){
@ -1102,31 +1102,34 @@ restconf_connection(int s,
}
if ((ev = bufferevent_get_output(conn->bev)) != NULL){
buflen0 = evbuffer_get_length(ev);
buflen = buflen0 - rc->rc_bufferevent_output_offset;
if (buflen == 0)
readmore = 1;
else if (buflen > 0){
buflen1 = buflen0 - rc->rc_bufferevent_output_offset;
if (buflen1 > 0){
buf = (char*)evbuffer_pullup(ev, -1);
/* If evhtp has print an output buffer, clixon whould not have done it
* Shouldnt happen
*/
clicon_debug(1, "%s Warning: evhtp printed output buffer, but clixon output buffer is non-empty %s",
__FUNCTION__, cbuf_get(rc->rc_outp_buf));
cbuf_reset(rc->rc_outp_buf);
if (cbuf_append_buf(rc->rc_outp_buf, buf, buflen) < 0){
if (cbuf_len(rc->rc_outp_buf)){
clicon_debug(1, "%s Warning: evhtp printed output buffer, but clixon output buffer is non-empty %s",
__FUNCTION__, cbuf_get(rc->rc_outp_buf));
cbuf_reset(rc->rc_outp_buf);
}
if (cbuf_append_buf(rc->rc_outp_buf, buf, buflen1) < 0){
clicon_err(OE_UNIX, errno, "cbuf_append_buf");
goto done;
}
/* XXX Cant get drain to work, need to keep an offset */
evbuffer_drain(ev, -1);
rc->rc_bufferevent_output_offset += buflen;
rc->rc_bufferevent_output_offset += buflen1;
}
}
if (cbuf_len(rc->rc_outp_buf) &&
buf_write(cbuf_get(rc->rc_outp_buf), cbuf_len(rc->rc_outp_buf), conn->sock, conn->ssl) < 0)
if (cbuf_len(rc->rc_outp_buf) == 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;
cvec_reset(rc->rc_outp_hdrs); /* Can be done in native_send_reply */
cbuf_reset(rc->rc_outp_buf);
cvec_reset(rc->rc_outp_hdrs); /* Can be done in native_send_reply */
cbuf_reset(rc->rc_outp_buf);
}
}
else{
if (send_badrequest(h, s, conn->ssl, "application/yang-data+xml",
@ -1896,6 +1899,7 @@ usage(clicon_handle h,
"\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-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"
,
argv0
@ -1913,7 +1917,6 @@ main(int argc,
clicon_handle h;
int dbg = 0;
int logdst = CLICON_LOG_SYSLOG;
int drop_privileges = 1;
restconf_native_handle *rh = NULL;
int ret;
cxobj *xrestconf = NULL;
@ -2012,10 +2015,14 @@ main(int argc,
usage(h, argv0);
clicon_option_str_set(h, "CLICON_SOCK", optarg);
break;
case 'r':{ /* Do not drop privileges if run as root */
drop_privileges = 0;
case 'r': /* Do not drop privileges if run as root */
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;
}
case 'o':{ /* Configuration option */
char *val;
if ((val = index(optarg, '=')) == NULL)
@ -2068,12 +2075,12 @@ main(int argc,
/* Openssl inits */
if (restconf_openssl_init(h, dbg, xrestconf) < 0)
goto done;
/* Drop privileges after clixon and openssl init */
if (drop_privileges){
/* Drop privileges to WWWUSER if started as root */
if (restconf_drop_privileges(h, WWWUSER) < 0)
goto done;
}
/* Drop privileges if started as root to CLICON_RESTCONF_USER
* and use drop mode: CLICON_RESTCONF_PRIVILEGES
*/
if (restconf_drop_privileges(h) < 0)
goto done;
/* Main event loop */
if (clixon_event_loop(h) < 0)
goto done;

29
configure vendored
View file

@ -635,7 +635,6 @@ CXXFLAGS
CXX
CPP
wwwdir
wwwuser
enable_optyangs
with_libxml2
with_restconf
@ -719,7 +718,6 @@ with_cligen
enable_optyangs
enable_publish
with_restconf
with_wwwuser
with_configfile
with_libxml2
with_yang_installdir
@ -1376,7 +1374,6 @@ Optional Packages:
nginx (default)
--with-restconf=native Integrate restconf with embedded http server
--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-libxml2 Use gnome/libxml2 regex engine
--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
# Web user default (ie what RESTCONF daemon runs as).
wwwuser=www-data
# Home dir for web user
wwwdir=/www-data
@ -5298,24 +5292,6 @@ fi
# 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?
# 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
#define WWWDIR "$wwwdir"
@ -5323,11 +5299,6 @@ _ACEOF
else
cat >>confdefs.h <<_ACEOF
#define WWWUSER ""
_ACEOF
cat >>confdefs.h <<_ACEOF
#define WWWDIR ""
_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_libxml2)
AC_SUBST(enable_optyangs)
# Web user default (ie what RESTCONF daemon runs as).
AC_SUBST(wwwuser,www-data)
# Home dir for web user
# Home dir for web user, such as nginx fcgi sockets
AC_SUBST(wwwdir,/www-data)
#
@ -216,6 +214,7 @@ if test "x${with_restconf}" == xfcgi; then
# Lives in libfcgi-dev
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_UNQUOTED(WWWDIR, "$wwwdir", [WWW dir for fcgi stuff / nginx])
elif test "x${with_restconf}" == xnative; then
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]))
@ -248,23 +247,6 @@ AC_ARG_WITH([restconf],
AC_ARG_WITH([restconf],
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
CLIXON_DEFAULT_CONFIG=/usr/local/etc/clixon.xml
AC_ARG_WITH([configfile],

View file

@ -63,7 +63,7 @@ RUN adduser -D -H www-data
RUN apk add --update nginx
# 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 install
@ -114,9 +114,9 @@ RUN adduser nginx clicon
RUN adduser www-data clicon
COPY --from=0 /clixon/build/ /usr/local/
COPY --from=0 /www-data /www-data
# Manually created
RUN mkdir /www-data
RUN chown www-data /www-data
RUN chgrp www-data /www-data

View file

@ -77,7 +77,7 @@ COPY clixon .
RUN adduser -D -H www-data
# 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 install
@ -129,10 +129,10 @@ RUN adduser -D -H clicon
RUN adduser www-data clicon
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/
# Manually created
RUN mkdir /www-data
RUN chown 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}
WWWUSER=${WWWUSER:-www-data}
# Initiate clixon configuration (env variable)
echo "$CONFIG" > /usr/local/etc/clixon.xml
@ -96,7 +94,6 @@ EOF
# sudo: setrlimit(RLIMIT_CORE): Operation not permitted
echo "Set disable_coredump false" > /etc/sudo.conf
chmod 775 /usr/local/bin/test/site.sh
if [ ! -d /run/nginx ]; then
@ -109,7 +106,7 @@ fi
>&2 echo "nginx started"
# 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"
# 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)
: ${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)
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
# -s https
# 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"
# Start clixon backend (tests will kill this)

View file

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

View file

@ -63,6 +63,6 @@ int nacm_datanode_write(clicon_handle h, cxobj *xr, cxobj *xt,
enum nacm_access access,
char *username, cxobj *xnacm, cbuf *cbret);
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 */

View file

@ -219,6 +219,7 @@ int clicon_sock_port(clicon_handle h);
int clicon_autocommit(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_restconf_privileges_mode(clicon_handle h);
enum nacm_credentials_t clicon_nacm_credentials(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;
cvec *nsc = NULL;
char *recovery_user;
#ifdef WITH_RESTCONF
char *wwwuser;
#endif
clicon_debug(1, "%s", __FUNCTION__);
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
@ -1148,9 +1151,10 @@ nacm_access_check(clicon_handle h,
strcmp(peername, "root") == 0)
goto permit;
#ifdef WITH_RESTCONF
wwwuser=clicon_option_str(h,"CLICON_RESTCONF_USER");
if (strcmp(username, recovery_user) == 0 &&
strcmp(peername, WWWUSER) == 0)
goto permit;
wwwuser && strcmp(peername, wwwuser) == 0)
goto permit;
#endif
break;
}
@ -1252,6 +1256,8 @@ nacm_access_pre(clicon_handle h,
}
/*! Verify nacm user with peer uid credentials
*
* @param[in] h Clixon handle
* @param[in] mode Peer credential mode: none, exact or except
* @param[in] peername Peer username if any
* @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)
*/
int
verify_nacm_user(enum nacm_credentials_t cred,
verify_nacm_user(clicon_handle h,
enum nacm_credentials_t cred,
char *peername,
char *nacmname,
cbuf *cbret)
{
int retval = -1;
cbuf *cbmsg = NULL;
#ifdef WITH_RESTCONF
char *wwwuser;
#endif
if (cred == NC_NONE)
return 1;
@ -1294,7 +1304,8 @@ verify_nacm_user(enum nacm_credentials_t cred,
if (strcmp(peername, "root") == 0)
goto ok;
#ifdef WITH_RESTCONF
if (strcmp(peername, WWWUSER) == 0)
wwwuser=clicon_option_str(h,"CLICON_RESTCONF_USER");
if (wwwuser && strcmp(peername, wwwuser) == 0)
goto ok;
#endif
}

View file

@ -871,7 +871,7 @@ clicon_startup_mode(clicon_handle h)
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
* @retval mode Privileges mode
*/
@ -885,6 +885,20 @@ clicon_backend_privileges_mode(clicon_handle h)
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
* @param[in] h Clicon handle
* @retval mode Privileges mode

View file

@ -277,11 +277,17 @@ clixon_proc_background(char **argv,
clicon_err(OE_UNIX, EINVAL, "argv is NULL");
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 */
sigprocmask(0, NULL, &oset);
set_signal(SIGINT, clixon_proc_sigint, &oldhandler);
/* Now call done on error */
if ((child = fork()) < 0) {
clicon_err(OE_UNIX, errno, "fork");
goto done;
@ -327,7 +333,7 @@ clixon_proc_background(char **argv,
}
#endif /* HAVE_SETNS */
if (execvp(argv[0], argv) < 0) {
clicon_err(OE_UNIX, errno, "execv");
clicon_err(OE_UNIX, errno, "execv(%s)", argv[0]);
exit(1);
}
/* Not reached */

View file

@ -10,7 +10,7 @@ fi
restconf=$1
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
./configure --enable-optyangs --with-restconf=$restconf
fi

View file

@ -50,12 +50,6 @@ CXX=@CXX@
# C compiler
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_SRCDIR=@top_srcdir@
@ -68,8 +62,8 @@ DATASTORE_TOP="config"
# clixon yang revisions occuring in tests
CLIXON_LIB_REV="2021-03-08"
CLIXON_CONFIG_REV="2021-03-08"
CLIXON_RESTCONF_REV="2021-03-15"
CLIXON_CONFIG_REV="2021-05-20"
CLIXON_RESTCONF_REV="2021-05-20"
CLIXON_EXAMPLE_REV="2020-12-01"
# Length of TSL RSA key
@ -80,3 +74,4 @@ CERTKEYLEN=2048
# Linking: static or dynamic
LINKAGE=@LINKAGE@
SH_SUFFIX=@SH_SUFFIX@

View file

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

View file

@ -26,10 +26,6 @@ new "Check installed files /usr"
if [ ! -d $dir/usr ]; then
err $dir/usr
fi
new "Check installed files /www-data"
if [ ! -d $dir/www-data ]; then
err $dir/www-data
fi
new "Check installed files clixon-config"
if [ ! -f $dir/usr/local/share/clixon/clixon-config* ]; then
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
new "Make DESTDIR install include"
(cd ..; $make DESTDIR=$dir install-include)
if [ $? -ne 0 ]; then

View file

@ -9,6 +9,7 @@
# See test_restconf_netns for network namespaces
# 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
# 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)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
@ -22,6 +23,17 @@ startupdb=$dir/startup_db
RESTCONFDBG=$DBG
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
EXTRACONF="<CLICON_FEATURE>clixon-restconf:fcgi</CLICON_FEATURE>"
else
@ -100,10 +112,10 @@ EOF
err "No pid return value" "$retx"
fi
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
# 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
match=$(echo "$retx" | grep --null -Go "$expect")
if [ -z "$match" ]; then
@ -140,6 +152,7 @@ cat<<EOF > $startupdb
<auth-type>none</auth-type>
<pretty>false</pretty>
<debug>$RESTCONFDBG</debug>
<log-destination>$LOGDST</log-destination>
<socket>
<namespace>default</namespace>
<address>0.0.0.0</address>
@ -169,14 +182,19 @@ new "wait backend"
wait_backend
# 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
new "1. Get rpc status"
rpcstatus true running
pid0=$pid # Save pid0
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"
ps=$(ps -hp $pid0)
@ -219,6 +237,11 @@ if [ "$pid0" -eq "$pid1" ]; then
err1 "not $pid0" "$pid1"
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"
rpcoperation stop
if [ $? -ne 0 ]; then exit -1; fi
@ -335,6 +358,7 @@ cat<<EOF > $startupdb
<auth-type>none</auth-type>
<pretty>false</pretty>
<debug>$RESTCONFDBG</debug>
<log-destination>$LOGDST</log-destination>
<socket>
<namespace>default</namespace>
<address>0.0.0.0</address>
@ -375,7 +399,7 @@ rpcstatus false stopped
if [ $pid -ne 0 ]; then err "Pid" "$pid"; fi
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"
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
@ -457,6 +481,8 @@ new "endtest"
endtest
# Set by restconf_config
unset LOGDST
unset LOGDST_CMD
unset pid
unset RESTCONFIG
unset RESTCONFDBG

View file

@ -34,6 +34,10 @@ RESTCONFDBG=$DBG
RCPROTO=http # no ssl here
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
EXTRACONF="<CLICON_FEATURE>clixon-restconf:fcgi</CLICON_FEATURE>"
else
@ -114,10 +118,10 @@ EOF
err "No pid return value" "$retx"
fi
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
# 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
match=$(echo "$retx" | grep --null -Go "$expect")
if [ -z "$match" ]; then
@ -158,6 +162,8 @@ new "1. get status"
rpcstatus false stopped
if [ $pid -ne 0 ]; then err "Pid" "$pid"; fi
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>]]>]]>$"
@ -235,6 +241,7 @@ RESTCONFIG1=$(cat <<EOF
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<debug>$RESTCONFDBG</debug>
<log-destination>$LOGDST</log-destination>
<auth-type>none</auth-type>
<pretty>false</pretty>
<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">
<enable>true</enable>
<debug>$RESTCONFDBG</debug>
<log-destination>$LOGDST</log-destination>
<auth-type>none</auth-type>
<pretty>false</pretty>
<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
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
new "Delete server"
@ -398,6 +406,7 @@ RESTCONFIG1=$(cat <<EOF
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<debug>$RESTCONFDBG</debug>
<log-destination>$LOGDST</log-destination>
<auth-type>none</auth-type>
<pretty>false</pretty>
<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
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
new "Kill backend"
@ -445,6 +454,8 @@ new "endtest"
endtest
# Set by restconf_config
unset LOGDST
unset LOGDST_CMD
unset RESTCONFIG1
unset RESTCONFIG2
unset RESTCONFDBG

View file

@ -41,11 +41,11 @@ datarootdir = @datarootdir@
# See also OPT_YANG_INSTALLDIR for the standard yang files
YANG_INSTALLDIR = @YANG_INSTALLDIR@
YANGSPECS = clixon-config@2021-03-08.yang
YANGSPECS += clixon-lib@2021-03-08.yang
YANGSPECS = clixon-config@2021-05-20.yang # 5.2
YANGSPECS += clixon-lib@2021-03-08.yang # 5.1
YANGSPECS += clixon-rfc5277@2008-07-01.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

View file

@ -43,6 +43,22 @@ module clixon-config {
***** 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 {
description
"Added option:
@ -197,7 +213,7 @@ module clixon-config {
}
typedef cli_genmodel_type{
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;}}";
type enumeration{
enum NONE{
@ -430,6 +446,20 @@ module clixon-config {
type string;
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 {
type string;
description
@ -445,10 +475,20 @@ module clixon-config {
description
"FastCGI unix socket. Should be specified in webserver
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";
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 {
type boolean;
@ -465,6 +505,22 @@ module clixon-config {
Note: Obsolete, use pretty in clixon-restconf.yang instead";
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 {
type string;
description
@ -506,7 +562,7 @@ module clixon-config {
type string;
default "datamodel";
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.
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)
@ -526,7 +582,16 @@ module clixon-config {
leaf CLICON_CLI_GENMODEL_TYPE {
type cli_genmodel_type;
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 {
type int32;
@ -676,7 +741,7 @@ module clixon-config {
user (eg datastores).
It also sets the backend unix socket owner to this user, but its group
is set by CLICON_SOCK_GROUP.
See also CLICON_PRIVILEGES setting";
See also CLICON_BACKEND_PRIVILEGES setting";
}
leaf CLICON_BACKEND_PRIVILEGES {
type priv_mode;
@ -697,6 +762,8 @@ module clixon-config {
description
"If set, enable process-control of restconf daemon, ie start/stop restconf
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
Process control of restconf daemon is as follows:
- 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.
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 {
type boolean;
default false;

View file

@ -43,6 +43,17 @@ module clixon-restconf {
***** 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 {
description
"Added: debug field
@ -53,6 +64,7 @@ module clixon-restconf {
description
"Initial release";
}
feature fcgi {
description
"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.";
}
feature allow-auth-none {
description
"This feature allows the use of authentication-type none.";
}
typedef http-auth-type {
type enumeration {
enum none {
if-feature "allow-auth-none";
description
"Incoming message are set to authenticated by default. No ca-auth callback is called,
Authenticated user is set to special user 'none'.
@ -85,6 +103,20 @@ module clixon-restconf {
description
"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{
description
"HTTP RESTCONF configuration.";
@ -103,19 +135,30 @@ module clixon-restconf {
description
"The authentication type.
Note client-certificate applies only if ssl-enable is true and socket has ssl";
default none;
default user;
}
leaf debug {
description
"Set debug level of restconf daemon.
0 is no debug, 1 is debugging, more is detailed debug.
Debug logs will be directed to syslog with
ident: clixon_restconf and PID
facility: LOG_USER
level: LOG_DEBUG";
Debug logs will be directed to log-destination with LOG_DEBUG level (for syslog)";
type uint32;
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 {
type boolean;
default true;
@ -170,7 +213,8 @@ module clixon-restconf {
type string;
description
"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 {
type inet:ip-address;