diff --git a/CHANGELOG.md b/CHANGELOG.md
index ef465001..6a1853a3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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=
` 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=` 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.
diff --git a/apps/backend/Makefile.in b/apps/backend/Makefile.in
index 66c70d10..bd8bc619 100644
--- a/apps/backend/Makefile.in
+++ b/apps/backend/Makefile.in
@@ -43,6 +43,7 @@ CPPFLAGS = @CPPFLAGS@
ifeq ($(LINKAGE),dynamic)
CPPFLAGS += -fPIC
endif
+
SH_SUFFIX = @SH_SUFFIX@
INSTALLFLAGS = @INSTALLFLAGS@
LDFLAGS = @LDFLAGS@
diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c
index 7d0a1c91..c4ffbe4a 100644
--- a/apps/backend/backend_client.c
+++ b/apps/backend/backend_client.c
@@ -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;
diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c
index fd4e6170..03529fbd 100644
--- a/apps/backend/backend_main.c
+++ b/apps/backend/backend_main.c
@@ -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)
diff --git a/apps/backend/backend_plugin_restconf.c b/apps/backend/backend_plugin_restconf.c
index d796b8c6..f808e4ca 100644
--- a/apps/backend/backend_plugin_restconf.c
+++ b/apps/backend/backend_plugin_restconf.c
@@ -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;
+ 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 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)){
diff --git a/apps/restconf/Makefile.in b/apps/restconf/Makefile.in
index b67e67c8..98527f92 100644
--- a/apps/restconf/Makefile.in
+++ b/apps/restconf/Makefile.in
@@ -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:
diff --git a/apps/restconf/README.md b/apps/restconf/README.md
index 308b20a0..aee444c1 100644
--- a/apps/restconf/README.md
+++ b/apps/restconf/README.md
@@ -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)
diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c
index 14358a2e..40e237f6 100644
--- a/apps/restconf/restconf_lib.c
+++ b/apps/restconf/restconf_lib.c
@@ -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);
diff --git a/apps/restconf/restconf_lib.h b/apps/restconf/restconf_lib.h
index 966da104..89bef5c6 100644
--- a/apps/restconf/restconf_lib.h
+++ b/apps/restconf/restconf_lib.h
@@ -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);
diff --git a/apps/restconf/restconf_main_fcgi.c b/apps/restconf/restconf_main_fcgi.c
index f10c55e5..6e1d93bf 100644
--- a/apps/restconf/restconf_main_fcgi.c
+++ b/apps/restconf/restconf_main_fcgi.c
@@ -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 \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 \tRun restconf daemon as this user, drop according to CLICON_RESTCONF_PRIVILEGES\n"
"\t-o \"