* 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:
parent
c3e26b004c
commit
c20c672d83
32 changed files with 410 additions and 221 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue