* The backend socket has now support of credentials of peer clients
* Added: CLICON_NACM_CREDENTIALS and CLICON_NACM_RECOVERY_USER
This commit is contained in:
parent
77b491c568
commit
279614d64f
33 changed files with 951 additions and 145 deletions
17
CHANGELOG.md
17
CHANGELOG.md
|
|
@ -3,14 +3,23 @@
|
||||||
## 4.2.0 (Expected: October)
|
## 4.2.0 (Expected: October)
|
||||||
|
|
||||||
### Major New features
|
### Major New features
|
||||||
|
* Privileges and credentials features
|
||||||
* Backend daemon can drop privileges after initialization to run as non-privileged user
|
* Backend daemon can drop privileges after initialization to run as non-privileged user
|
||||||
* You can start as root and drop privileges either permanently or temporary
|
* You can start as root and drop privileges either permanently or temporary
|
||||||
* Controlled by options: CLICON_BACKEND_USER and CLICON_BACKEND_PRIVELEGES
|
* Controlled by options: CLICON_BACKEND_USER and CLICON_BACKEND_PRIVELEGES
|
||||||
* Can also be set with `-U <user>` clixon_backend command-line option
|
* Can also be set with `-U <user>` clixon_backend command-line option
|
||||||
* If dropped temporary, you can restore privileges with `restore_priv()`
|
* If dropped temporary, you can restore privileges with `restore_priv()`
|
||||||
|
* The backend socket has now support of credentials of peer clients
|
||||||
|
* NACM users are cross-checked with client credentials (cli/netconf/restconf)
|
||||||
|
* Only UNIX domain socket supports client credential checks (Not IP sockets.
|
||||||
|
* Controlled by option CLICON_NACM_CREDENTIALS
|
||||||
|
* `none` means credentials are not checked. Only option for IP sockets.
|
||||||
|
* `exact` means credentials of client user must match NACM user exactly.
|
||||||
|
* `except` means exact match is done except for root and www user.This is necessary for Restconf. This is default.
|
||||||
|
|
||||||
### API changes on existing features (you may need to change your code)
|
### API changes on existing features (you may need to change your code)
|
||||||
* In logs and debug changed "Demon error" to "Daemon error".
|
* NACM users are cross-checked with client user credentials (see new features).
|
||||||
|
* Changed "Demon error" to "Daemon error" in logs and debug.
|
||||||
* Stricter handling of multi-namespace handling
|
* Stricter handling of multi-namespace handling
|
||||||
* This occurs in cases where there are more than one XML namespaces in a config tree, such as `augment`:ed trees.
|
* This occurs in cases where there are more than one XML namespaces in a config tree, such as `augment`:ed trees.
|
||||||
* Affects all parts of the system, including datastore, backend, restconf and cli.
|
* Affects all parts of the system, including datastore, backend, restconf and cli.
|
||||||
|
|
@ -33,8 +42,10 @@
|
||||||
* Changed so that `400 Bad Request` are for invalid api-path or unknown yang elements, `404 Not Found` for valid xml when object not found.
|
* Changed so that `400 Bad Request` are for invalid api-path or unknown yang elements, `404 Not Found` for valid xml when object not found.
|
||||||
* Typical installation should now add a `clicon` user (as well as group)
|
* Typical installation should now add a `clicon` user (as well as group)
|
||||||
* New clixon-config@2019-09-11.yang revision
|
* New clixon-config@2019-09-11.yang revision
|
||||||
* Added: CLICON_BACKEND_USER: drop of privileges to user,
|
* Added: CLICON_BACKEND_USER: Drop of privileges to this user, owner of backend socket.
|
||||||
* Added: CLICON_BACKEND_PRIVELEGES: how to drop privileges
|
* Added: CLICON_BACKEND_PRIVELEGES: If and how to drop privileges
|
||||||
|
* Added: CLICON_NACM_CREDENTIALS: If and how to check backend socket priveleges with NACM
|
||||||
|
* Added: CLICON_NACM_RECOVERY_USER: Name of NACM recovery user.
|
||||||
* Restconf top-level operations GET root resource modified to comply with RFC 8040 Sec 3.1
|
* Restconf top-level operations GET root resource modified to comply with RFC 8040 Sec 3.1
|
||||||
* non-pretty print remove all spaces, eg `{"operations":{"clixon-example:client-rpc":[null]`
|
* non-pretty print remove all spaces, eg `{"operations":{"clixon-example:client-rpc":[null]`
|
||||||
* Replaced JSON `null` with `[null]` as proper empty JSON leaf/leaf-list encoding.
|
* Replaced JSON `null` with `[null]` as proper empty JSON leaf/leaf-list encoding.
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,6 @@ backend_client_rm(clicon_handle h,
|
||||||
}
|
}
|
||||||
ce_prev = &c->ce_next;
|
ce_prev = &c->ce_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return backend_client_delete(h, ce); /* actually purge it */
|
return backend_client_delete(h, ce); /* actually purge it */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1240,6 +1239,68 @@ from_client_ping(clicon_handle h,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Verify nacm user with peer uid credentials
|
||||||
|
* @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)
|
||||||
|
* @param[out] cbret Set with netconf error message if ret == 0
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 Not verified (cbret set)
|
||||||
|
* @retval 1 Verified
|
||||||
|
* Credentials OK if both NACM user and peer useri s defined AND one of the
|
||||||
|
* following is true:
|
||||||
|
* - peer user is same as NACM user
|
||||||
|
* - peer user is root (can be any NACM user)
|
||||||
|
* - peer user is www (can be any NACM user)
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
verify_nacm_user(enum nacm_credentials_t mode,
|
||||||
|
char *peername,
|
||||||
|
char *nacmname,
|
||||||
|
cbuf *cbret)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cbmsg = NULL;
|
||||||
|
|
||||||
|
if (mode == NC_NONE)
|
||||||
|
return 1;
|
||||||
|
if (peername == NULL){
|
||||||
|
if (netconf_access_denied(cbret, "application", "No peer user credentials available") < 0)
|
||||||
|
goto done;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (nacmname == NULL){
|
||||||
|
if (netconf_access_denied(cbret, "application", "No NACM available") < 0)
|
||||||
|
goto done;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (mode == NC_EXCEPT){
|
||||||
|
if (strcmp(peername, "root") == 0)
|
||||||
|
goto ok;
|
||||||
|
if (strcmp(peername, WWWUSER) == 0)
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
if (strcmp(peername, nacmname) != 0){
|
||||||
|
if ((cbmsg = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cprintf(cbmsg, "User %s credential not matching NACM user %s", peername, nacmname);
|
||||||
|
if (netconf_access_denied(cbret, "application", cbuf_get(cbmsg)) < 0)
|
||||||
|
goto done;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
ok:
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
if (cbmsg)
|
||||||
|
cbuf_free(cbmsg);
|
||||||
|
return retval;
|
||||||
|
fail:
|
||||||
|
retval = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/*! An internal clicon message has arrived from a client. Receive and dispatch.
|
/*! An internal clicon message has arrived from a client. Receive and dispatch.
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] s Socket where message arrived. read from this.
|
* @param[in] s Socket where message arrived. read from this.
|
||||||
|
|
@ -1322,6 +1383,12 @@ from_client_msg(clicon_handle h,
|
||||||
if ((ret = nacm_access_pre(h, username, NACM_RPC, &xnacm)) < 0)
|
if ((ret = nacm_access_pre(h, username, NACM_RPC, &xnacm)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){ /* Do NACM validation */
|
if (ret == 0){ /* Do NACM validation */
|
||||||
|
enum nacm_credentials_t mode;
|
||||||
|
mode = clicon_nacm_credentials(h);
|
||||||
|
if ((ret = verify_nacm_user(mode, ce->ce_username, username, cbret)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0) /* credentials fail */
|
||||||
|
goto reply;
|
||||||
/* NACM rpc operation exec validation */
|
/* NACM rpc operation exec validation */
|
||||||
if ((ret = nacm_rpc(rpc, module, username, xnacm, cbret)) < 0)
|
if ((ret = nacm_rpc(rpc, module, username, xnacm, cbret)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,8 @@ struct client_entry{
|
||||||
int ce_nr; /* Client number (for dbg/tracing) */
|
int ce_nr; /* Client number (for dbg/tracing) */
|
||||||
int ce_stat_in; /* Nr of received msgs from client */
|
int ce_stat_in; /* Nr of received msgs from client */
|
||||||
int ce_stat_out;/* Nr of sent msgs to client */
|
int ce_stat_out;/* Nr of sent msgs to client */
|
||||||
int ce_pid; /* Process id */
|
int ce_pid; /* Peer Process id */
|
||||||
int ce_uid; /* User id of calling process */
|
char *ce_username;/* Translated from peer user cred */
|
||||||
clicon_handle ce_handle; /* clicon config handle (all clients have same?) */
|
clicon_handle ce_handle; /* clicon config handle (all clients have same?) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,13 +51,12 @@
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#ifdef HAVE_SYS_UCRED_H
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/ucred.h>
|
|
||||||
#endif
|
|
||||||
#define __USE_GNU /* for ucred */
|
#define __USE_GNU /* for ucred */
|
||||||
#define _GNU_SOURCE /* for ucred */
|
#define _GNU_SOURCE /* for ucred */
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#ifdef HAVE_LOCAL_PEERCRED
|
||||||
|
#include <sys/ucred.h>
|
||||||
|
#endif
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
|
@ -226,63 +225,65 @@ backend_accept_client(int fd,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
clicon_handle h = (clicon_handle)arg;
|
clicon_handle h = (clicon_handle)arg;
|
||||||
int s;
|
int s;
|
||||||
struct sockaddr_un from;
|
struct sockaddr from = {0,};
|
||||||
socklen_t len;
|
socklen_t len;
|
||||||
struct client_entry *ce;
|
struct client_entry *ce;
|
||||||
#ifdef DONT_WORK /* XXX HAVE_SYS_UCRED_H */
|
|
||||||
struct xucred credentials; /* FreeBSD. */
|
|
||||||
socklen_t clen;
|
|
||||||
#elif defined(SO_PEERCRED)
|
|
||||||
struct ucred credentials; /* Linux. */
|
|
||||||
socklen_t clen;
|
|
||||||
#endif
|
|
||||||
char *config_group;
|
|
||||||
struct group *gr;
|
|
||||||
char *mem;
|
|
||||||
int i;
|
int i;
|
||||||
|
char *name = NULL;
|
||||||
|
#ifdef HAVE_SO_PEERCRED
|
||||||
|
socklen_t clen;
|
||||||
|
struct ucred cr = {0,}; /* Linux. */
|
||||||
|
#elif defined(HAVE_GETPEEREID)
|
||||||
|
uid_t euid;
|
||||||
|
uid_t guid;
|
||||||
|
#endif
|
||||||
|
|
||||||
clicon_debug(2, "%s", __FUNCTION__);
|
clicon_debug(2, "%s", __FUNCTION__);
|
||||||
len = sizeof(from);
|
len = sizeof(from);
|
||||||
if ((s = accept(fd, (struct sockaddr*)&from, &len)) < 0){
|
if ((s = accept(fd, &from, &len)) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "accept");
|
clicon_err(OE_UNIX, errno, "accept");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#if defined(SO_PEERCRED)
|
if ((ce = backend_client_add(h, &from)) == NULL)
|
||||||
/* fill in the user data structure */
|
goto done;
|
||||||
clen = sizeof(credentials);
|
ce->ce_handle = h;
|
||||||
if(getsockopt(s, SOL_SOCKET, SO_PEERCRED/* XXX finns ej i freebsd*/, &credentials, &clen)){
|
|
||||||
|
/*
|
||||||
|
* Get credentials of connected peer - only for unix socket
|
||||||
|
*/
|
||||||
|
switch (from.sa_family){
|
||||||
|
case AF_UNIX:
|
||||||
|
#if defined(HAVE_SO_PEERCRED)
|
||||||
|
clen = sizeof(cr);
|
||||||
|
if(getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &clen) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "getsockopt");
|
clicon_err(OE_UNIX, errno, "getsockopt");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
ce->ce_pid = cr.pid; /* XXX no use session-id */
|
||||||
if ((ce = backend_client_add(h, (struct sockaddr*)&from)) == NULL)
|
if (uid2name(cr.uid, &name) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
#if defined(SO_PEERCRED)
|
#elif defined(HAVE_GETPEEREID)
|
||||||
ce->ce_pid = credentials.pid;
|
if (getpeereid(s, &euid, &guid) < 0)
|
||||||
ce->ce_uid = credentials.uid;
|
goto done;
|
||||||
|
if (uid2name(euid, &name) < 0)
|
||||||
|
goto done;
|
||||||
|
#else
|
||||||
|
#error "Need getsockopt O_PEERCRED or getpeereid for unix socket peer cred"
|
||||||
#endif
|
#endif
|
||||||
ce->ce_handle = h;
|
if (name && (ce->ce_username = strdup(name)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
/* check credentials of caller (not properly implemented yet) */
|
|
||||||
if ((config_group = clicon_sock_group(h)) == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "clicon_sock_group option not set");
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((gr = getgrnam(config_group)) != NULL){
|
break;
|
||||||
i = 0; /* one of mem should correspond to ce->ce_uid */
|
case AF_INET: /* XXX: HACK ce->ce_pid */
|
||||||
while ((mem = gr->gr_mem[i++]) != NULL)
|
ce->ce_pid = 0;
|
||||||
;
|
for (i=0; i<len; i++)
|
||||||
|
ce->ce_pid ^= from.sa_data[i];
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
{ /* XXX */
|
|
||||||
int ii;
|
|
||||||
struct client_entry *c;
|
|
||||||
for (c = ce_list, ii=0; c; c = c->ce_next, ii++);
|
|
||||||
clicon_debug(1, "Open client socket (nr:%d pid:%d [Total: %d])",
|
|
||||||
ce->ce_nr, ce->ce_pid, ii);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ce->ce_s = s;
|
ce->ce_s = s;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ backend_client_add(clicon_handle h,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset(ce, 0, sizeof(*ce));
|
memset(ce, 0, sizeof(*ce));
|
||||||
ce->ce_nr = bh->bh_ce_nr++;
|
ce->ce_nr = bh->bh_ce_nr++; /* Session-id ? */
|
||||||
memcpy(&ce->ce_addr, addr, sizeof(*addr));
|
memcpy(&ce->ce_addr, addr, sizeof(*addr));
|
||||||
ce->ce_next = bh->bh_ce_list;
|
ce->ce_next = bh->bh_ce_list;
|
||||||
bh->bh_ce_list = ce;
|
bh->bh_ce_list = ce;
|
||||||
|
|
@ -177,6 +177,8 @@ backend_client_delete(clicon_handle h,
|
||||||
for (c = *ce_prev; c; c = c->ce_next){
|
for (c = *ce_prev; c; c = c->ce_next){
|
||||||
if (c == ce){
|
if (c == ce){
|
||||||
*ce_prev = c->ce_next;
|
*ce_prev = c->ce_next;
|
||||||
|
if (ce->ce_username)
|
||||||
|
free(ce->ce_username);
|
||||||
free(ce);
|
free(ce);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@
|
||||||
</hello>
|
</hello>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "clixon_config.h" /* generated by config & autoconf */
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -115,7 +114,10 @@ netconf_hello_dispatch(cxobj *xn)
|
||||||
* MUST send a <hello> element containing a list of that peer's capabilities
|
* MUST send a <hello> element containing a list of that peer's capabilities
|
||||||
* MUST send at least the base NETCONF capability, urn:ietf:params:netconf:base:1.1
|
* MUST send at least the base NETCONF capability, urn:ietf:params:netconf:base:1.1
|
||||||
* MAY include capabilities for previous NETCONF versions
|
* MAY include capabilities for previous NETCONF versions
|
||||||
* MUST include a <session-id>
|
* A server MUST include a <session-id>
|
||||||
|
* A client MUST NOT include a <session-id>
|
||||||
|
* A server receiving <session-id> MUST terminate the NETCONF session.
|
||||||
|
* A client not receiving <session-id> MUST terminate w/o sending<close-session>
|
||||||
* the example shows urn:ietf:params:netconf:capability:startup:1.0
|
* the example shows urn:ietf:params:netconf:capability:startup:1.0
|
||||||
|
|
||||||
* RFC5277 NETCONF Event Notifications
|
* RFC5277 NETCONF Event Notifications
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,12 @@ Download and start nginx. For example on ubuntu:
|
||||||
```
|
```
|
||||||
sudo apt install ngnix
|
sudo apt install ngnix
|
||||||
```
|
```
|
||||||
|
on FreeBSD:
|
||||||
|
```
|
||||||
|
sudo pkg install ngnix
|
||||||
|
```
|
||||||
|
|
||||||
Define nginx config file: /etc/nginx/sites-available/default
|
Edit the nginx config file. (On Ubuntu: `/etc/nginx/sites-available/default`, on FreeBSD: `/usr/local/etc/nginx/sites-available/default`)
|
||||||
```
|
```
|
||||||
server {
|
server {
|
||||||
...
|
...
|
||||||
|
|
@ -40,6 +44,10 @@ Alternatively, start it via systemd:
|
||||||
```
|
```
|
||||||
sudo systemctl start nginx.service
|
sudo systemctl start nginx.service
|
||||||
```
|
```
|
||||||
|
Or on FreeBSD:
|
||||||
|
```
|
||||||
|
sudo service nginx start
|
||||||
|
```
|
||||||
|
|
||||||
Start clixon backend daemon (if not already started)
|
Start clixon backend daemon (if not already started)
|
||||||
```
|
```
|
||||||
|
|
@ -48,8 +56,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 su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data
|
```
|
||||||
|
On FreeBSD:
|
||||||
|
```
|
||||||
|
sudo -u www -s /www/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:
|
||||||
|
|
|
||||||
70
configure
vendored
70
configure
vendored
|
|
@ -686,6 +686,7 @@ infodir
|
||||||
docdir
|
docdir
|
||||||
oldincludedir
|
oldincludedir
|
||||||
includedir
|
includedir
|
||||||
|
runstatedir
|
||||||
localstatedir
|
localstatedir
|
||||||
sharedstatedir
|
sharedstatedir
|
||||||
sysconfdir
|
sysconfdir
|
||||||
|
|
@ -768,6 +769,7 @@ datadir='${datarootdir}'
|
||||||
sysconfdir='${prefix}/etc'
|
sysconfdir='${prefix}/etc'
|
||||||
sharedstatedir='${prefix}/com'
|
sharedstatedir='${prefix}/com'
|
||||||
localstatedir='${prefix}/var'
|
localstatedir='${prefix}/var'
|
||||||
|
runstatedir='${localstatedir}/run'
|
||||||
includedir='${prefix}/include'
|
includedir='${prefix}/include'
|
||||||
oldincludedir='/usr/include'
|
oldincludedir='/usr/include'
|
||||||
docdir='${datarootdir}/doc/${PACKAGE}'
|
docdir='${datarootdir}/doc/${PACKAGE}'
|
||||||
|
|
@ -1020,6 +1022,15 @@ do
|
||||||
| -silent | --silent | --silen | --sile | --sil)
|
| -silent | --silent | --silen | --sile | --sil)
|
||||||
silent=yes ;;
|
silent=yes ;;
|
||||||
|
|
||||||
|
-runstatedir | --runstatedir | --runstatedi | --runstated \
|
||||||
|
| --runstate | --runstat | --runsta | --runst | --runs \
|
||||||
|
| --run | --ru | --r)
|
||||||
|
ac_prev=runstatedir ;;
|
||||||
|
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
|
||||||
|
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
|
||||||
|
| --run=* | --ru=* | --r=*)
|
||||||
|
runstatedir=$ac_optarg ;;
|
||||||
|
|
||||||
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
|
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
|
||||||
ac_prev=sbindir ;;
|
ac_prev=sbindir ;;
|
||||||
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
|
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
|
||||||
|
|
@ -1157,7 +1168,7 @@ fi
|
||||||
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
|
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
|
||||||
datadir sysconfdir sharedstatedir localstatedir includedir \
|
datadir sysconfdir sharedstatedir localstatedir includedir \
|
||||||
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
|
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
|
||||||
libdir localedir mandir
|
libdir localedir mandir runstatedir
|
||||||
do
|
do
|
||||||
eval ac_val=\$$ac_var
|
eval ac_val=\$$ac_var
|
||||||
# Remove trailing slashes.
|
# Remove trailing slashes.
|
||||||
|
|
@ -1310,6 +1321,7 @@ Fine tuning of the installation directories:
|
||||||
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
|
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
|
||||||
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
|
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
|
||||||
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
|
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
|
||||||
|
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
|
||||||
--libdir=DIR object code libraries [EPREFIX/lib]
|
--libdir=DIR object code libraries [EPREFIX/lib]
|
||||||
--includedir=DIR C header files [PREFIX/include]
|
--includedir=DIR C header files [PREFIX/include]
|
||||||
--oldincludedir=DIR C header files for non-gcc [/usr/include]
|
--oldincludedir=DIR C header files for non-gcc [/usr/include]
|
||||||
|
|
@ -1369,8 +1381,8 @@ Some influential environment variables:
|
||||||
you have headers in a nonstandard directory <include dir>
|
you have headers in a nonstandard directory <include dir>
|
||||||
CPP C preprocessor
|
CPP C preprocessor
|
||||||
YACC The `Yet Another Compiler Compiler' implementation to use.
|
YACC The `Yet Another Compiler Compiler' implementation to use.
|
||||||
Defaults to the first program found out of: `bison -o y.tab.c',
|
Defaults to the first program found out of: `bison -y', `byacc',
|
||||||
`byacc', `yacc'.
|
`yacc'.
|
||||||
YFLAGS The list of arguments that will be passed by default to $YACC.
|
YFLAGS The list of arguments that will be passed by default to $YACC.
|
||||||
This script will default YFLAGS to the empty string to avoid a
|
This script will default YFLAGS to the empty string to avoid a
|
||||||
default value of `-d' given by some make applications.
|
default value of `-d' given by some make applications.
|
||||||
|
|
@ -3999,7 +4011,7 @@ $as_echo "CFLAGS is $CFLAGS" >&6; }
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: INSTALLFLAGS is $INSTALLFLAGS" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: INSTALLFLAGS is $INSTALLFLAGS" >&5
|
||||||
$as_echo "INSTALLFLAGS is $INSTALLFLAGS" >&6; }
|
$as_echo "INSTALLFLAGS is $INSTALLFLAGS" >&6; }
|
||||||
|
|
||||||
for ac_prog in 'bison -o y.tab.c' byacc
|
for ac_prog in 'bison -y' byacc
|
||||||
do
|
do
|
||||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
||||||
set dummy $ac_prog; ac_word=$2
|
set dummy $ac_prog; ac_word=$2
|
||||||
|
|
@ -4715,8 +4727,15 @@ fi
|
||||||
|
|
||||||
if test "${with_wwwuser}"; then
|
if test "${with_wwwuser}"; then
|
||||||
wwwuser=${with_wwwuser}
|
wwwuser=${with_wwwuser}
|
||||||
|
|
||||||
fi
|
fi
|
||||||
echo "wwwuser:$wwwuser"
|
{ $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
|
||||||
|
|
||||||
|
|
||||||
# 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
|
||||||
|
|
@ -4727,23 +4746,6 @@ if test "${with_configfile+set}" = set; then :
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# user credentials for unix sockets
|
|
||||||
for ac_header in sys/ucred.h
|
|
||||||
do :
|
|
||||||
ac_fn_c_check_header_compile "$LINENO" "sys/ucred.h" "ac_cv_header_sys_ucred_h" "# include <sys/param.h>
|
|
||||||
|
|
||||||
"
|
|
||||||
if test "x$ac_cv_header_sys_ucred_h" = xyes; then :
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
|
||||||
#define HAVE_SYS_UCRED_H 1
|
|
||||||
_ACEOF
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5
|
||||||
$as_echo_n "checking for socket in -lsocket... " >&6; }
|
$as_echo_n "checking for socket in -lsocket... " >&6; }
|
||||||
if ${ac_cv_lib_socket_socket+:} false; then :
|
if ${ac_cv_lib_socket_socket+:} false; then :
|
||||||
|
|
@ -4896,7 +4898,7 @@ fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
for ac_func in inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort
|
for ac_func in inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort getpeereid
|
||||||
do :
|
do :
|
||||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||||
|
|
@ -4909,6 +4911,28 @@ fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
|
# Checks for getsockopt options for getting unix socket peer credentials on
|
||||||
|
# Linux
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
#include <sys/socket.h>
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
getsockopt(1, SOL_SOCKET, SO_PEERCRED, 0, 0);
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
if ac_fn_c_try_compile "$LINENO"; then :
|
||||||
|
|
||||||
|
$as_echo "#define HAVE_SO_PEERCRED 1" >>confdefs.h
|
||||||
|
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Have getsockopt peercred" >&5
|
||||||
|
$as_echo "Have getsockopt peercred" >&6; }
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||||
|
|
||||||
# YANG_INSTALLDIR is where clixon installs the Clixon yang files
|
# YANG_INSTALLDIR is where clixon installs the Clixon yang files
|
||||||
# (the files in in yang/clixon)
|
# (the files in in yang/clixon)
|
||||||
# Each application designer may need to place YANG_INSTALLDIR in their config:
|
# Each application designer may need to place YANG_INSTALLDIR in their config:
|
||||||
|
|
|
||||||
17
configure.ac
17
configure.ac
|
|
@ -198,8 +198,10 @@ AC_ARG_WITH([wwwuser],
|
||||||
[AS_HELP_STRING([--with-wwwuser=<user>],[Set www user different from www-data])])
|
[AS_HELP_STRING([--with-wwwuser=<user>],[Set www user different from www-data])])
|
||||||
if test "${with_wwwuser}"; then
|
if test "${with_wwwuser}"; then
|
||||||
wwwuser=${with_wwwuser}
|
wwwuser=${with_wwwuser}
|
||||||
|
|
||||||
fi
|
fi
|
||||||
echo "wwwuser:$wwwuser"
|
AC_MSG_RESULT(www user is $wwwuser)
|
||||||
|
AC_DEFINE_UNQUOTED(WWWUSER, "$wwwuser", [WWW user for restconf daemon])
|
||||||
|
|
||||||
# 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
|
||||||
|
|
@ -207,12 +209,6 @@ AC_ARG_WITH([configfile],
|
||||||
[AS_HELP_STRING([--with-configfile=FILE],[set default path to config file])],
|
[AS_HELP_STRING([--with-configfile=FILE],[set default path to config file])],
|
||||||
[CLIXON_DEFAULT_CONFIG="$withval"],)
|
[CLIXON_DEFAULT_CONFIG="$withval"],)
|
||||||
|
|
||||||
|
|
||||||
# user credentials for unix sockets
|
|
||||||
AC_CHECK_HEADERS([sys/ucred.h],[],[],
|
|
||||||
[[# include <sys/param.h>]]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_CHECK_LIB(socket, socket)
|
AC_CHECK_LIB(socket, socket)
|
||||||
AC_CHECK_LIB(dl, dlopen)
|
AC_CHECK_LIB(dl, dlopen)
|
||||||
|
|
||||||
|
|
@ -226,7 +222,12 @@ if test "${with_libxml2}"; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
AC_CHECK_FUNCS(inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort)
|
AC_CHECK_FUNCS(inet_aton sigaction sigvec strlcpy strsep strndup alphasort versionsort getpeereid)
|
||||||
|
|
||||||
|
# Checks for getsockopt options for getting unix socket peer credentials on
|
||||||
|
# Linux
|
||||||
|
AC_TRY_COMPILE([#include <sys/socket.h>], [getsockopt(1, SOL_SOCKET, SO_PEERCRED, 0, 0);], [AC_DEFINE(HAVE_SO_PEERCRED, 1, [Have getsockopt peercred])
|
||||||
|
AC_MSG_RESULT(Have getsockopt peercred)])
|
||||||
|
|
||||||
# YANG_INSTALLDIR is where clixon installs the Clixon yang files
|
# YANG_INSTALLDIR is where clixon installs the Clixon yang files
|
||||||
# (the files in in yang/clixon)
|
# (the files in in yang/clixon)
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@
|
||||||
/* Define to 1 if you have the <cligen/cligen.h> header file. */
|
/* Define to 1 if you have the <cligen/cligen.h> header file. */
|
||||||
#undef HAVE_CLIGEN_CLIGEN_H
|
#undef HAVE_CLIGEN_CLIGEN_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `getpeereid' function. */
|
||||||
|
#undef HAVE_GETPEEREID
|
||||||
|
|
||||||
/* Define to 1 if you have the `inet_aton' function. */
|
/* Define to 1 if you have the `inet_aton' function. */
|
||||||
#undef HAVE_INET_ATON
|
#undef HAVE_INET_ATON
|
||||||
|
|
||||||
|
|
@ -60,6 +63,9 @@
|
||||||
/* Define to 1 if you have the `sigvec' function. */
|
/* Define to 1 if you have the `sigvec' function. */
|
||||||
#undef HAVE_SIGVEC
|
#undef HAVE_SIGVEC
|
||||||
|
|
||||||
|
/* Have getsockopt peercred */
|
||||||
|
#undef HAVE_SO_PEERCRED
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdint.h> header file. */
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
#undef HAVE_STDINT_H
|
#undef HAVE_STDINT_H
|
||||||
|
|
||||||
|
|
@ -87,9 +93,6 @@
|
||||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||||
#undef HAVE_SYS_TYPES_H
|
#undef HAVE_SYS_TYPES_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/ucred.h> header file. */
|
|
||||||
#undef HAVE_SYS_UCRED_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <unistd.h> header file. */
|
/* Define to 1 if you have the <unistd.h> header file. */
|
||||||
#undef HAVE_UNISTD_H
|
#undef HAVE_UNISTD_H
|
||||||
|
|
||||||
|
|
@ -117,6 +120,9 @@
|
||||||
/* Define to 1 if you have the ANSI C header files. */
|
/* Define to 1 if you have the ANSI C header files. */
|
||||||
#undef STDC_HEADERS
|
#undef STDC_HEADERS
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,14 @@ enum startup_mode_t{
|
||||||
enum priv_mode_t{
|
enum priv_mode_t{
|
||||||
PM_NONE=0, /* Make no drop/change in privileges */
|
PM_NONE=0, /* Make no drop/change in privileges */
|
||||||
PM_DROP_PERM, /* Drop privileges permanently */
|
PM_DROP_PERM, /* Drop privileges permanently */
|
||||||
PM_DROP_TEMP, /* Drop privileges temporary */
|
PM_DROP_TEMP /* Drop privileges temporary */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! See clixon-config.yang type nacm_cred_mode (user credentials) */
|
||||||
|
enum nacm_credentials_t{
|
||||||
|
NC_NONE=0, /* "Dont match NACM user to any user credentials. */
|
||||||
|
NC_EXACT, /* Exact match between NACM user and unix socket peer user. */
|
||||||
|
NC_EXCEPT /* Exact match except for root and www user */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! Datastore cache behaviour, see clixon_datastore.[ch]
|
/*! Datastore cache behaviour, see clixon_datastore.[ch]
|
||||||
|
|
@ -183,6 +190,9 @@ static inline char *clicon_backend_pidfile(clicon_handle h){
|
||||||
static inline char *clicon_xmldb_dir(clicon_handle h){
|
static inline char *clicon_xmldb_dir(clicon_handle h){
|
||||||
return clicon_option_str(h, "CLICON_XMLDB_DIR");
|
return clicon_option_str(h, "CLICON_XMLDB_DIR");
|
||||||
}
|
}
|
||||||
|
static inline char *clicon_nacm_recovery_user(clicon_handle h){
|
||||||
|
return clicon_option_str(h, "CLICON_NACM_RECOVERY_USER");
|
||||||
|
}
|
||||||
|
|
||||||
/*-- Specific option access functions for YANG options w type conversion--*/
|
/*-- Specific option access functions for YANG options w type conversion--*/
|
||||||
int clicon_cli_genmodel(clicon_handle h);
|
int clicon_cli_genmodel(clicon_handle h);
|
||||||
|
|
@ -193,7 +203,9 @@ int clicon_sock_family(clicon_handle h);
|
||||||
int clicon_sock_port(clicon_handle h);
|
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);
|
||||||
int clicon_backend_privileges_mode(clicon_handle h);
|
enum priv_mode_t clicon_backend_privileges_mode(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);
|
||||||
enum regexp_mode clicon_yang_regexp(clicon_handle h);
|
enum regexp_mode clicon_yang_regexp(clicon_handle h);
|
||||||
/*-- Specific option access functions for non-yang options --*/
|
/*-- Specific option access functions for non-yang options --*/
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int group_name2gid(const char *name, gid_t *gid);
|
int group_name2gid(const char *name, gid_t *gid);
|
||||||
|
|
||||||
int name2uid(const char *name, uid_t *uid);
|
int name2uid(const char *name, uid_t *uid);
|
||||||
|
int uid2name(const uid_t uid, char **name);
|
||||||
int drop_priv_temp(uid_t new_uid);
|
int drop_priv_temp(uid_t new_uid);
|
||||||
int drop_priv_perm(uid_t new_uid);
|
int drop_priv_perm(uid_t new_uid);
|
||||||
int restore_priv(void);
|
int restore_priv(void);
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,9 @@ enum xp_op{
|
||||||
XO_UNION,
|
XO_UNION,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Axis specifiers according to https://www.w3.org/TR/xpath-10/#NT-AxisName */
|
/* Axis specifiers according to https://www.w3.org/TR/xpath-10/#NT-AxisName
|
||||||
|
* @see axis_type_int2str
|
||||||
|
*/
|
||||||
enum axis_type{
|
enum axis_type{
|
||||||
A_NAN = 0, /* Not set */
|
A_NAN = 0, /* Not set */
|
||||||
A_ANCESTOR,
|
A_ANCESTOR,
|
||||||
|
|
@ -69,13 +71,15 @@ enum axis_type{
|
||||||
A_FOLLOWING_SIBLING,
|
A_FOLLOWING_SIBLING,
|
||||||
A_NAMESPACE,
|
A_NAMESPACE,
|
||||||
A_PARENT,
|
A_PARENT,
|
||||||
A_PRECEEDING,
|
A_PRECEDING,
|
||||||
A_PRECEEDING_SIBLING,
|
A_PRECEDING_SIBLING,
|
||||||
A_SELF,
|
A_SELF,
|
||||||
A_ROOT /* XXX Not in https://www.w3.org/TR/xpath-10 */
|
A_ROOT /* XXX Not in https://www.w3.org/TR/xpath-10 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* used as non-terminal type in yacc rules */
|
/* used as non-terminal type in yacc rules
|
||||||
|
* @see xpath_tree_int2str
|
||||||
|
*/
|
||||||
enum xp_type{
|
enum xp_type{
|
||||||
XP_EXP,
|
XP_EXP,
|
||||||
XP_AND,
|
XP_AND,
|
||||||
|
|
@ -100,7 +104,7 @@ enum xp_type{
|
||||||
*/
|
*/
|
||||||
struct xpath_tree{
|
struct xpath_tree{
|
||||||
enum xp_type xs_type;
|
enum xp_type xs_type;
|
||||||
int xs_int;
|
int xs_int; /* step-> axis-type */
|
||||||
double xs_double;
|
double xs_double;
|
||||||
char *xs_s0;
|
char *xs_s0;
|
||||||
char *xs_s1;
|
char *xs_s1;
|
||||||
|
|
@ -112,6 +116,7 @@ typedef struct xpath_tree xpath_tree;
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
|
char* axis_type_int2str(int axis_type);
|
||||||
char* xpath_tree_int2str(int nodetype);
|
char* xpath_tree_int2str(int nodetype);
|
||||||
int xpath_tree_print_cb(cbuf *cb, xpath_tree *xs);
|
int xpath_tree_print_cb(cbuf *cb, xpath_tree *xs);
|
||||||
int xpath_tree_print(FILE *f, xpath_tree *xs);
|
int xpath_tree_print(FILE *f, xpath_tree *xs);
|
||||||
|
|
|
||||||
|
|
@ -942,6 +942,7 @@ nacm_access_pre(clicon_handle h,
|
||||||
if (xml_rootchild_node(xnacm0, xnacm) < 0)
|
if (xml_rootchild_node(xnacm0, xnacm) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
xnacm0 = NULL;
|
xnacm0 = NULL;
|
||||||
|
/* Initial NACM steps and common to all NACM access validation. */
|
||||||
if ((retval = nacm_access(mode, xnacm, username)) < 0)
|
if ((retval = nacm_access(mode, xnacm, username)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (retval == 0){ /* if retval == 0 then return an xml nacm tree */
|
if (retval == 0){ /* if retval == 0 then return an xml nacm tree */
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ static const map_str2int startup_mode_map[] = {
|
||||||
{NULL, -1}
|
{NULL, -1}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mapping between Clicon privilegese modes string <--> constants,
|
/* Mapping between Clicon privileges modes string <--> constants,
|
||||||
* see clixon-config.yang type priv_mode */
|
* see clixon-config.yang type priv_mode */
|
||||||
static const map_str2int priv_mode_map[] = {
|
static const map_str2int priv_mode_map[] = {
|
||||||
{"none", PM_NONE},
|
{"none", PM_NONE},
|
||||||
|
|
@ -110,6 +110,16 @@ static const map_str2int priv_mode_map[] = {
|
||||||
{NULL, -1}
|
{NULL, -1}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Mapping between Clicon nacm user credential string <--> constants,
|
||||||
|
* see clixon-config.yang type nacm_cred_mode */
|
||||||
|
static const map_str2int nacm_credentials_map[] = {
|
||||||
|
{"none", NC_NONE},
|
||||||
|
{"exact", NC_EXACT},
|
||||||
|
{"except", NC_EXCEPT},
|
||||||
|
{NULL, -1}
|
||||||
|
};
|
||||||
|
|
||||||
/* Mapping between datastore cache string <--> constants,
|
/* Mapping between datastore cache string <--> constants,
|
||||||
* see clixon-config.yang type datastore_cache */
|
* see clixon-config.yang type datastore_cache */
|
||||||
static const map_str2int datastore_cache_map[] = {
|
static const map_str2int datastore_cache_map[] = {
|
||||||
|
|
@ -706,7 +716,7 @@ clicon_startup_mode(clicon_handle h)
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @retval mode Privileges mode
|
* @retval mode Privileges mode
|
||||||
*/
|
*/
|
||||||
int
|
enum priv_mode_t
|
||||||
clicon_backend_privileges_mode(clicon_handle h)
|
clicon_backend_privileges_mode(clicon_handle h)
|
||||||
{
|
{
|
||||||
char *mode;
|
char *mode;
|
||||||
|
|
@ -716,6 +726,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
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @retval mode Privileges mode
|
||||||
|
*/
|
||||||
|
enum nacm_credentials_t
|
||||||
|
clicon_nacm_credentials(clicon_handle h)
|
||||||
|
{
|
||||||
|
char *mode;
|
||||||
|
|
||||||
|
if ((mode = clicon_option_str(h, "CLICON_NACM_CREDENTIALS")) == NULL)
|
||||||
|
return -1;
|
||||||
|
return clicon_str2int(nacm_credentials_map, mode);
|
||||||
|
}
|
||||||
|
|
||||||
/*! Which datastore cache method to use
|
/*! Which datastore cache method to use
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @retval method Datastore cache method
|
* @retval method Datastore cache method
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,37 @@ name2uid(const char *name,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Translate uid to user name
|
||||||
|
* @param[in] uid User id
|
||||||
|
* @param[out] name User name
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error. or not found
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
uid2name(const uid_t uid,
|
||||||
|
char **name)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char buf[1024];
|
||||||
|
struct passwd pwbuf;
|
||||||
|
struct passwd *pwbufp = NULL;
|
||||||
|
|
||||||
|
if (getpwuid_r(uid, &pwbuf, buf, sizeof(buf), &pwbufp) != 0){
|
||||||
|
clicon_err(OE_UNIX, errno, "getpwuid_r(%u)", uid);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (pwbufp == NULL){
|
||||||
|
clicon_err(OE_UNIX, 0, "No such user: %u", uid);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (name)
|
||||||
|
*name = pwbufp->pw_name;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Privileges drop perm, temp and restore
|
/* Privileges drop perm, temp and restore
|
||||||
* @see https://www.usenix.org/legacy/events/sec02/full_papers/chen/chen.pdf
|
* @see https://www.usenix.org/legacy/events/sec02/full_papers/chen/chen.pdf
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,9 @@
|
||||||
* Variables
|
* Variables
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Mapping between xpath_tree node name string <--> int */
|
/* Mapping between xpath_tree node name string <--> int
|
||||||
|
* @see xpath_tree_int2str
|
||||||
|
*/
|
||||||
static const map_str2int xpath_tree_map[] = {
|
static const map_str2int xpath_tree_map[] = {
|
||||||
{"expr", XP_EXP},
|
{"expr", XP_EXP},
|
||||||
{"andexpr", XP_AND},
|
{"andexpr", XP_AND},
|
||||||
|
|
@ -115,11 +117,42 @@ static const map_str2int xpath_tree_map[] = {
|
||||||
{NULL, -1}
|
{NULL, -1}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Mapping between axis_type string <--> int
|
||||||
|
* @see axis_type_int2str
|
||||||
|
*/
|
||||||
|
static const map_str2int axis_type_map[] = {
|
||||||
|
{"NaN", A_NAN},
|
||||||
|
{"ancestor", A_ANCESTOR},
|
||||||
|
{"ancestor-or-selgf", A_ANCESTOR_OR_SELF},
|
||||||
|
{"attribute", A_ATTRIBUTE},
|
||||||
|
{"child", A_CHILD},
|
||||||
|
{"descendant", A_DESCENDANT},
|
||||||
|
{"descendeant-or-self", A_DESCENDANT_OR_SELF},
|
||||||
|
{"following", A_FOLLOWING},
|
||||||
|
{"following-sibling", A_FOLLOWING_SIBLING},
|
||||||
|
{"namespace", A_NAMESPACE},
|
||||||
|
{"parent", A_PARENT},
|
||||||
|
{"preceding", A_PRECEDING},
|
||||||
|
{"preceding-sibling", A_PRECEDING_SIBLING},
|
||||||
|
{"self", A_SELF},
|
||||||
|
{"root", A_ROOT},
|
||||||
|
{NULL, -1}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XPATH parse tree type
|
* XPATH parse tree type
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*! Map from axis-type int to string
|
||||||
|
*/
|
||||||
|
char*
|
||||||
|
axis_type_int2str(int axis_type)
|
||||||
|
{
|
||||||
|
return (char*)clicon_int2str(axis_type_map, axis_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Map from xpath_tree node name int to string
|
/*! Map from xpath_tree node name int to string
|
||||||
*/
|
*/
|
||||||
char*
|
char*
|
||||||
|
|
@ -135,11 +168,21 @@ xpath_tree_print0(cbuf *cb,
|
||||||
int level)
|
int level)
|
||||||
{
|
{
|
||||||
cprintf(cb, "%*s%s:", level*3, "", xpath_tree_int2str(xs->xs_type));
|
cprintf(cb, "%*s%s:", level*3, "", xpath_tree_int2str(xs->xs_type));
|
||||||
if (xs->xs_s0){
|
if (xs->xs_s0)
|
||||||
cprintf(cb, "\"%s\" ", xs->xs_s0);
|
cprintf(cb, "\"%s\" ", xs->xs_s0);
|
||||||
if (xs->xs_s1)
|
if (xs->xs_s1)
|
||||||
cprintf(cb,"\"%s\" ", xs->xs_s1);
|
cprintf(cb,"\"%s\" ", xs->xs_s1);
|
||||||
|
if (xs->xs_int)
|
||||||
|
switch (xs->xs_type){
|
||||||
|
case XP_STEP:
|
||||||
|
cprintf(cb, "%s", axis_type_int2str(xs->xs_int));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cprintf(cb, "%d ", xs->xs_int);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if (xs->xs_double)
|
||||||
|
cprintf(cb,"%lf ", xs->xs_double);
|
||||||
cprintf(cb, "\n");
|
cprintf(cb, "\n");
|
||||||
if (xs->xs_c0)
|
if (xs->xs_c0)
|
||||||
xpath_tree_print0(cb, xs->xs_c0,level+1);
|
xpath_tree_print0(cb, xs->xs_c0,level+1);
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@ nodetest_eval_node(cxobj *x,
|
||||||
name2, nsxpath);
|
name2, nsxpath);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
done: /* retval set in preceeding statement */
|
done: /* retval set in preceding statement */
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,12 +303,13 @@ xp_eval_step(xp_ctx *xc0,
|
||||||
x = NULL;
|
x = NULL;
|
||||||
while ((x = xml_child_each(xv, x, CX_ELMNT)) != NULL) {
|
while ((x = xml_child_each(xv, x, CX_ELMNT)) != NULL) {
|
||||||
/* xs->xs_c0 is nodetest */
|
/* xs->xs_c0 is nodetest */
|
||||||
if (nodetest == NULL || nodetest_eval(x, nodetest, nsc) == 1)
|
if (nodetest == NULL || nodetest_eval(x, nodetest, nsc) == 1){
|
||||||
if (cxvec_append(x, &vec, &veclen) < 0)
|
if (cxvec_append(x, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ctx_nodeset_replace(xc, vec, veclen);
|
ctx_nodeset_replace(xc, vec, veclen);
|
||||||
break;
|
break;
|
||||||
case A_DESCENDANT:
|
case A_DESCENDANT:
|
||||||
|
|
@ -342,9 +343,9 @@ xp_eval_step(xp_ctx *xc0,
|
||||||
vec = NULL;
|
vec = NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case A_PRECEEDING:
|
case A_PRECEDING:
|
||||||
break;
|
break;
|
||||||
case A_PRECEEDING_SIBLING:
|
case A_PRECEDING_SIBLING:
|
||||||
break;
|
break;
|
||||||
case A_SELF:
|
case A_SELF:
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -128,8 +128,8 @@ real ({digit}+[.]{digit}*)|({digit}*[.]{digit}+)
|
||||||
<TOKEN>following-sibling:: { clixon_xpath_parselval.intval = A_FOLLOWING_SIBLING; return AXISNAME; }
|
<TOKEN>following-sibling:: { clixon_xpath_parselval.intval = A_FOLLOWING_SIBLING; return AXISNAME; }
|
||||||
<TOKEN>namespace:: { clixon_xpath_parselval.intval = A_NAMESPACE; return AXISNAME; }
|
<TOKEN>namespace:: { clixon_xpath_parselval.intval = A_NAMESPACE; return AXISNAME; }
|
||||||
<TOKEN>parent:: { clixon_xpath_parselval.intval = A_PARENT; return AXISNAME; }
|
<TOKEN>parent:: { clixon_xpath_parselval.intval = A_PARENT; return AXISNAME; }
|
||||||
<TOKEN>preceding:: { clixon_xpath_parselval.intval = A_PRECEEDING; return AXISNAME; }
|
<TOKEN>preceding:: { clixon_xpath_parselval.intval = A_PRECEDING; return AXISNAME; }
|
||||||
<TOKEN>preceding-sibling:: { clixon_xpath_parselval.intval = A_PRECEEDING_SIBLING; return AXISNAME; }
|
<TOKEN>preceding-sibling:: { clixon_xpath_parselval.intval = A_PRECEDING_SIBLING; return AXISNAME; }
|
||||||
<TOKEN>self:: { clixon_xpath_parselval.intval = A_SELF; return AXISNAME; }
|
<TOKEN>self:: { clixon_xpath_parselval.intval = A_SELF; return AXISNAME; }
|
||||||
|
|
||||||
<TOKEN>current { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
<TOKEN>current { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ cat <<EOF > $cfg
|
||||||
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
|
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
|
||||||
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
||||||
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||||
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
|
|
||||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||||
</clixon-config>
|
</clixon-config>
|
||||||
EOF
|
EOF
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
# Authentication and authorization and IETF NACM
|
# Authentication and authorization and IETF NACM
|
||||||
# See RFC 8341 A.2
|
# See RFC 8341 A.2
|
||||||
# But replaced ietf-netconf-monitoring with *
|
# But replaced ietf-netconf-monitoring with *
|
||||||
|
# Note credenials check set to none since USER poses as different users.
|
||||||
|
|
||||||
# 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
|
||||||
|
|
@ -31,6 +32,7 @@ cat <<EOF > $cfg
|
||||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||||
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
||||||
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
|
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
|
||||||
|
<CLICON_NACM_CREDENTIALS>none</CLICON_NACM_CREDENTIALS>
|
||||||
</clixon-config>
|
</clixon-config>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
|
||||||
239
test/test_nacm_credentials.sh
Executable file
239
test/test_nacm_credentials.sh
Executable file
|
|
@ -0,0 +1,239 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Test matrching of Unix peer credentials with NACM users
|
||||||
|
# Use raw unix socket instead of clients (cli/netconf/restconf) since they do
|
||||||
|
# magic things with the username and here it needs to be handled explicitly.
|
||||||
|
# test matrix:
|
||||||
|
# - mode: none, exact, except
|
||||||
|
# - username: olof, admin, null, sudo
|
||||||
|
# - socket family: unix|ip
|
||||||
|
|
||||||
|
# Magic line must be first in script (see README.md)
|
||||||
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
|
||||||
|
# Raw unit tester of backend unix socket
|
||||||
|
: ${clixon_util_socket:=clixon_util_socket}
|
||||||
|
|
||||||
|
APPNAME=example
|
||||||
|
|
||||||
|
# Common NACM scripts
|
||||||
|
. ./nacm.sh
|
||||||
|
|
||||||
|
cfg=$dir/conf_yang.xml
|
||||||
|
fyang=$dir/nacm-example.yang
|
||||||
|
|
||||||
|
cat <<EOF > $fyang
|
||||||
|
module nacm-example{
|
||||||
|
yang-version 1.1;
|
||||||
|
namespace "urn:example:nacm";
|
||||||
|
prefix nacm;
|
||||||
|
import clixon-example {
|
||||||
|
prefix ex;
|
||||||
|
}
|
||||||
|
import ietf-netconf-acm {
|
||||||
|
prefix nacm;
|
||||||
|
}
|
||||||
|
leaf x{
|
||||||
|
type int32;
|
||||||
|
description "something to edit";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# The groups are slightly modified from RFC8341 A.1
|
||||||
|
# The rule-list is from A.2
|
||||||
|
RULES=$(cat <<EOF
|
||||||
|
<nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
|
||||||
|
<enable-nacm>false</enable-nacm>
|
||||||
|
<read-default>permit</read-default>
|
||||||
|
<write-default>deny</write-default>
|
||||||
|
<exec-default>deny</exec-default>
|
||||||
|
|
||||||
|
$NGROUPS
|
||||||
|
|
||||||
|
<rule-list>
|
||||||
|
<name>guest-acl</name>
|
||||||
|
<group>guest</group>
|
||||||
|
<rule>
|
||||||
|
<name>deny-ncm</name>
|
||||||
|
<module-name>*</module-name>
|
||||||
|
<access-operations>*</access-operations>
|
||||||
|
<action>deny</action>
|
||||||
|
<comment>
|
||||||
|
Do not allow guests any access to the NETCONF
|
||||||
|
monitoring information.
|
||||||
|
</comment>
|
||||||
|
</rule>
|
||||||
|
</rule-list>
|
||||||
|
<rule-list>
|
||||||
|
<name>limited-acl</name>
|
||||||
|
<group>limited</group>
|
||||||
|
<rule>
|
||||||
|
<name>permit-get</name>
|
||||||
|
<rpc-name>get</rpc-name>
|
||||||
|
<module-name>*</module-name>
|
||||||
|
<access-operations>exec</access-operations>
|
||||||
|
<action>permit</action>
|
||||||
|
<comment>
|
||||||
|
Allow get
|
||||||
|
</comment>
|
||||||
|
</rule>
|
||||||
|
<rule>
|
||||||
|
<name>permit-get-config</name>
|
||||||
|
<rpc-name>get-config</rpc-name>
|
||||||
|
<module-name>*</module-name>
|
||||||
|
<access-operations>exec</access-operations>
|
||||||
|
<action>permit</action>
|
||||||
|
<comment>
|
||||||
|
Allow get-config
|
||||||
|
</comment>
|
||||||
|
</rule>
|
||||||
|
</rule-list>
|
||||||
|
|
||||||
|
$NADMIN
|
||||||
|
|
||||||
|
</nacm>
|
||||||
|
<x xmlns="urn:example:nacm">0</x>
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set cred mode and run nacm operations
|
||||||
|
# Arguments:
|
||||||
|
# - mode (none,exact,except)
|
||||||
|
# - xml/nacm-username
|
||||||
|
# - socket family
|
||||||
|
# - socket file/addr
|
||||||
|
# - precommand /(eg sudo to raise to root)
|
||||||
|
testrun(){
|
||||||
|
mode=$1
|
||||||
|
username=$2
|
||||||
|
family=$3
|
||||||
|
sock=$4
|
||||||
|
exp=$5
|
||||||
|
precmd=$6
|
||||||
|
|
||||||
|
cat <<EOF > $cfg
|
||||||
|
<clixon-config xmlns="http://clicon.org/config">
|
||||||
|
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||||
|
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
|
||||||
|
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
|
||||||
|
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
|
||||||
|
<CLICON_SOCK_FAMILY>$family</CLICON_SOCK_FAMILY>
|
||||||
|
<CLICON_SOCK>$sock</CLICON_SOCK>
|
||||||
|
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||||
|
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||||
|
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||||
|
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
|
||||||
|
<CLICON_NACM_CREDENTIALS>$mode</CLICON_NACM_CREDENTIALS>
|
||||||
|
</clixon-config>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
new "test params: -f $cfg"
|
||||||
|
if [ $BE -ne 0 ]; then
|
||||||
|
new "kill old backend"
|
||||||
|
sudo clixon_backend -zf $cfg
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
new "start backend -s init -f $cfg"
|
||||||
|
start_backend -s init -f $cfg
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "waiting"
|
||||||
|
wait_backend
|
||||||
|
|
||||||
|
# First push in nacm rules via regular means
|
||||||
|
new "auth set authentication config"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><edit-config><target><candidate/></target><config>$RULES</config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "enable nacm"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"><enable-nacm>true</enable-nacm></nacm></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
new "commit it"
|
||||||
|
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
|
# raw socket test
|
||||||
|
if [ -n "$username" ]; then
|
||||||
|
XML="<rpc username=\"$username\"><get-config><source><running/></source><filter type=\"xpath\" select=\"/ex:x\" xmlns:ex=\"urn:example:nacm\"/></get-config></rpc>"
|
||||||
|
else
|
||||||
|
XML="<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/ex:x\" xmlns:ex=\"urn:example:nacm\"/></get-config></rpc>"
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "get-config mode:$mode user:$username $family $precmd"
|
||||||
|
expecteof "$precmd $clixon_util_socket -a $family -s $sock -D $DBG" 0 "$XML" "$ex"
|
||||||
|
|
||||||
|
if [ $BE -ne 0 ]; then # Bring your own backend
|
||||||
|
new "Kill backend"
|
||||||
|
# Check if premature kill
|
||||||
|
pid=$(pgrep -u root -f clixon_backend)
|
||||||
|
if [ -z "$pid" ]; then
|
||||||
|
err "backend already dead"
|
||||||
|
fi
|
||||||
|
# kill backend
|
||||||
|
stop_backend -f $cfg
|
||||||
|
fi
|
||||||
|
} # testrun
|
||||||
|
|
||||||
|
OK='^<rpc-reply><data><x xmlns="urn:example:nacm">0</x></data></rpc-reply>$'
|
||||||
|
ERROR='^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>access-denied</error-tag><error-severity>error</error-severity><error-message>'
|
||||||
|
|
||||||
|
# UNIX socket, no user, loop mode. All fail since null user cant access anything
|
||||||
|
if true; then
|
||||||
|
new "Credentials: mode=none, fam=UNIX user=none"
|
||||||
|
testrun none "" UNIX $dir/backend.sock "$OK" ""
|
||||||
|
|
||||||
|
new "Credentials: mode=exact, fam=UNIX user=none"
|
||||||
|
testrun exact "" UNIX $dir/backend.sock "$OK" ""
|
||||||
|
|
||||||
|
new "Credentials: mode=except, fam=UNIX user=none"
|
||||||
|
testrun except "" UNIX $dir/backend.sock "$OK" ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# UNIX socket, myuser, loop mode. All should work
|
||||||
|
if true; then
|
||||||
|
new "Credentials: mode=none, fam=UNIX user=me"
|
||||||
|
testrun none "$USER" UNIX $dir/backend.sock "$OK" ""
|
||||||
|
|
||||||
|
new "Credentials: mode=exact, fam=UNIX user=me"
|
||||||
|
testrun exact "$USER" UNIX $dir/backend.sock "$OK" ""
|
||||||
|
|
||||||
|
new "Credentials: mode=except, fam=UNIX user=me"
|
||||||
|
testrun except "$USER" UNIX $dir/backend.sock "$OK" ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# UNIX socket, admin user. First should work
|
||||||
|
if true; then
|
||||||
|
new "Credentials: mode=none, fam=UNIX user=admin"
|
||||||
|
testrun none admin UNIX $dir/backend.sock "$OK" ""
|
||||||
|
|
||||||
|
new "Credentials: mode=exact, fam=UNIX user=admin"
|
||||||
|
testrun exact admin UNIX $dir/backend.sock "$ERROR" ""
|
||||||
|
|
||||||
|
new "Credentials: mode=except, fam=UNIX user=admin"
|
||||||
|
testrun except admin UNIX $dir/backend.sock "$ERROR" ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# UNIX socket, admin user. sudo self to root. First and last should work
|
||||||
|
if true; then
|
||||||
|
new "Credentials: mode=none, fam=UNIX user=admin sudo"
|
||||||
|
testrun none admin UNIX $dir/backend.sock "$OK" sudo
|
||||||
|
|
||||||
|
new "Credentials: mode=exact, fam=UNIX user=admin sudo"
|
||||||
|
testrun exact admin UNIX $dir/backend.sock "$ERROR" sudo
|
||||||
|
|
||||||
|
new "Credentials: mode=except, fam=UNIX user=admin sudo"
|
||||||
|
testrun except admin UNIX $dir/backend.sock "$OK" sudo
|
||||||
|
fi
|
||||||
|
|
||||||
|
# IPv4 socket, admin user. First should work
|
||||||
|
if true; then
|
||||||
|
new "Credentials: mode=none, fam=UNIX user=admin sudo"
|
||||||
|
testrun none $USER IPv4 127.0.0.1 "$OK" ""
|
||||||
|
|
||||||
|
new "Credentials: mode=exact, fam=UNIX user=admin sudo"
|
||||||
|
testrun exact $USER IPv4 127.0.0.1 "$ERROR" ""
|
||||||
|
|
||||||
|
new "Credentials: mode=except, fam=UNIX user=admin sudo"
|
||||||
|
testrun except $USER IPv4 127.0.0.1 "$ERROR" ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf $dir
|
||||||
|
|
@ -32,6 +32,7 @@ cat <<EOF > $cfg
|
||||||
<CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN>
|
<CLICON_XMLDB_PLUGIN>/usr/local/lib/xmldb/text.so</CLICON_XMLDB_PLUGIN>
|
||||||
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
||||||
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
|
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
|
||||||
|
<CLICON_NACM_CREDENTIALS>none</CLICON_NACM_CREDENTIALS>
|
||||||
<CLICON_XMLDB_FORMAT>$format</CLICON_XMLDB_FORMAT>
|
<CLICON_XMLDB_FORMAT>$format</CLICON_XMLDB_FORMAT>
|
||||||
</clixon-config>
|
</clixon-config>
|
||||||
EOF
|
EOF
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ cat <<EOF > $cfg
|
||||||
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
||||||
<CLICON_NACM_MODE>external</CLICON_NACM_MODE>
|
<CLICON_NACM_MODE>external</CLICON_NACM_MODE>
|
||||||
<CLICON_NACM_FILE>$nacmfile</CLICON_NACM_FILE>
|
<CLICON_NACM_FILE>$nacmfile</CLICON_NACM_FILE>
|
||||||
|
<CLICON_NACM_CREDENTIALS>none</CLICON_NACM_CREDENTIALS>
|
||||||
</clixon-config>
|
</clixon-config>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ cat <<EOF > $cfg
|
||||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||||
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
||||||
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
|
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
|
||||||
|
<CLICON_NACM_CREDENTIALS>none</CLICON_NACM_CREDENTIALS>
|
||||||
</clixon-config>
|
</clixon-config>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ cat <<EOF > $cfg
|
||||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||||
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
||||||
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
|
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
|
||||||
|
<CLICON_NACM_CREDENTIALS>none</CLICON_NACM_CREDENTIALS>
|
||||||
</clixon-config>
|
</clixon-config>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ cat <<EOF > $cfg
|
||||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||||
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
<CLICON_RESTCONF_PRETTY>false</CLICON_RESTCONF_PRETTY>
|
||||||
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
|
<CLICON_NACM_MODE>internal</CLICON_NACM_MODE>
|
||||||
|
<CLICON_NACM_CREDENTIALS>none</CLICON_NACM_CREDENTIALS>
|
||||||
</clixon-config>
|
</clixon-config>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ APPNAME=example
|
||||||
cfg=$dir/conf_startup.xml
|
cfg=$dir/conf_startup.xml
|
||||||
|
|
||||||
if [ $valgrindtest -ne 0 ]; then
|
if [ $valgrindtest -ne 0 ]; then
|
||||||
return -1 # skip
|
echo "...skipped "
|
||||||
|
return 0 # skip
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Here $dir is created by the user that runs the script
|
# Here $dir is created by the user that runs the script
|
||||||
|
|
|
||||||
81
test/test_sock.sh
Executable file
81
test/test_sock.sh
Executable file
|
|
@ -0,0 +1,81 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Simple Unix and IP internal socket tests
|
||||||
|
# See also test_nacm_credentials.sh for more advanced credential tests
|
||||||
|
|
||||||
|
# Magic line must be first in script (see README.md)
|
||||||
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# client <---> backend
|
||||||
|
# ^ is unix, ipv4, ipv6 socket
|
||||||
|
|
||||||
|
APPNAME=example
|
||||||
|
|
||||||
|
cfg=$dir/conf.xml
|
||||||
|
fyang=$dir/socket.yang
|
||||||
|
|
||||||
|
# Set socket family and start backend and run a single cli command to
|
||||||
|
# check socket works
|
||||||
|
# 1: UNIX|IPv4|IPv6
|
||||||
|
# 2: unix file or ipv4 address or ipv6 address
|
||||||
|
# 3: sock port (if ipv4 or ipv6)
|
||||||
|
testrun(){
|
||||||
|
family=$1
|
||||||
|
sock=$2
|
||||||
|
port=$3
|
||||||
|
|
||||||
|
cat <<EOF > $cfg
|
||||||
|
<clixon-config xmlns="http://clicon.org/config">
|
||||||
|
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||||
|
<CLICON_FEATURE>*:*</CLICON_FEATURE>
|
||||||
|
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
|
||||||
|
<CLICON_YANG_MODULE_MAIN>clixon-example</CLICON_YANG_MODULE_MAIN>
|
||||||
|
<CLICON_SOCK_FAMILY>$family</CLICON_SOCK_FAMILY>
|
||||||
|
<CLICON_SOCK_PORT>$port</CLICON_SOCK_PORT>
|
||||||
|
<CLICON_SOCK>$sock</CLICON_SOCK>
|
||||||
|
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
|
||||||
|
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
||||||
|
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
|
||||||
|
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||||
|
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||||
|
<CLICON_STARTUP_MODE>init</CLICON_STARTUP_MODE>
|
||||||
|
<CLICON_MODULE_LIBRARY_RFC7895>false</CLICON_MODULE_LIBRARY_RFC7895>
|
||||||
|
</clixon-config>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
new "test params: -f $cfg"
|
||||||
|
if [ $BE -ne 0 ]; then
|
||||||
|
new "kill old backend"
|
||||||
|
sudo clixon_backend -zf $cfg
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
new "start backend -s init -f $cfg"
|
||||||
|
start_backend -s init -f $cfg
|
||||||
|
fi
|
||||||
|
|
||||||
|
new "$clixon_cli -1f $cfg show version"
|
||||||
|
expectfn "$clixon_cli -1f $cfg show version" 0 "$version."
|
||||||
|
|
||||||
|
if [ $BE -ne 0 ]; then
|
||||||
|
new "Kill backend"
|
||||||
|
# Check if premature kill
|
||||||
|
pid=$(pgrep -u root -f clixon_backend)
|
||||||
|
if [ -z "$pid" ]; then
|
||||||
|
err "backend already dead"
|
||||||
|
fi
|
||||||
|
# kill backend
|
||||||
|
stop_backend -f $cfg
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
new "Unix socket"
|
||||||
|
testrun UNIX $dir/sock 0
|
||||||
|
|
||||||
|
new "IPv4 socket"
|
||||||
|
testrun IPv4 127.0.0.1 7878
|
||||||
|
|
||||||
|
#new "IPv6 socket" NYI
|
||||||
|
#testrun IPv6 ::1 7878
|
||||||
|
|
||||||
|
rm -rf $dir
|
||||||
|
|
@ -78,6 +78,9 @@ APPSRC += clixon_util_regexp.c
|
||||||
ifeq ($(with_restconf),yes)
|
ifeq ($(with_restconf),yes)
|
||||||
APPSRC += clixon_util_stream.c # Needs curl
|
APPSRC += clixon_util_stream.c # Needs curl
|
||||||
endif
|
endif
|
||||||
|
APPSRC += clixon_util_socket.c
|
||||||
|
APPSRC += clixon_util_ssl.c
|
||||||
|
APPSRC += clixon_util_grpc.c
|
||||||
|
|
||||||
APPS = $(APPSRC:.c=)
|
APPS = $(APPSRC:.c=)
|
||||||
|
|
||||||
|
|
@ -117,6 +120,15 @@ clixon_util_stream: clixon_util_stream.c $(LIBDEPS)
|
||||||
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $(LDFLAGS) $^ $(LIBS) -lcurl -o $@
|
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $(LDFLAGS) $^ $(LIBS) -lcurl -o $@
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
clixon_util_socket: clixon_util_socket.c $(LIBDEPS)
|
||||||
|
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $(LDFLAGS) $^ $(LIBS) -o $@
|
||||||
|
|
||||||
|
clixon_util_ssl: clixon_util_ssl.c $(LIBDEPS)
|
||||||
|
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $(LDFLAGS) $^ $(LIBS) -lnghttp2 -lssl -lcrypto -o $@
|
||||||
|
|
||||||
|
clixon_util_grpc: clixon_util_grpc.c $(LIBDEPS)
|
||||||
|
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $(LDFLAGS) $^ $(LIBS) -lnghttp2 -lssl -lcrypto -o $@
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f Makefile *~ .depend
|
rm -f Makefile *~ .depend
|
||||||
|
|
||||||
|
|
|
||||||
184
util/clixon_util_socket.c
Normal file
184
util/clixon_util_socket.c
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
||||||
|
|
||||||
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Alternatively, the contents of this file may be used under the terms of
|
||||||
|
the GNU General Public License Version 3 or later (the "GPL"),
|
||||||
|
in which case the provisions of the GPL are applicable instead
|
||||||
|
of those above. If you wish to allow use of your version of this file only
|
||||||
|
under the terms of the GPL, and not to allow others to
|
||||||
|
use your version of this file under the terms of Apache License version 2,
|
||||||
|
indicate your decision by deleting the provisions above and replace them with
|
||||||
|
the notice and other provisions required by the GPL. If you do not delete
|
||||||
|
the provisions above, a recipient may use your version of this file under
|
||||||
|
the terms of any one of the Apache License version 2 or the GPL.
|
||||||
|
|
||||||
|
***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
|
* Unit test for testting the backend socket, ie simulating a client by
|
||||||
|
* directly sending XML to the backend.
|
||||||
|
* Precondition:
|
||||||
|
* The backend must have been started using socket path goven as -s
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
/* cligen */
|
||||||
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
|
/* clixon */
|
||||||
|
#include "clixon/clixon.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
usage(char *argv0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "usage:%s [options] with xml on stdin (unless -f)\n"
|
||||||
|
"where options are\n"
|
||||||
|
"\t-h \t\tHelp\n"
|
||||||
|
"\t-D <level> \tDebug\n"
|
||||||
|
"\t-a <family>\tSocket address family (default UNIX)\n"
|
||||||
|
"\t-s <sockpath> \tPath to unix domain socket (or IP addr)\n"
|
||||||
|
"\t-f <file>\tXML input file (overrides stdin)\n"
|
||||||
|
"\t-J \t\tInput as JSON (instead of XML)\n"
|
||||||
|
,
|
||||||
|
argv0);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc,
|
||||||
|
char **argv)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
int c;
|
||||||
|
int logdst = CLICON_LOG_STDERR;
|
||||||
|
struct clicon_msg *msg = NULL;
|
||||||
|
char *sockpath;
|
||||||
|
char *retdata = NULL;
|
||||||
|
int jsonin = 0;
|
||||||
|
char *input_filename = NULL;
|
||||||
|
int fd = 0; /* stdin */
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
cxobj *xc;
|
||||||
|
cxobj *xerr = NULL;
|
||||||
|
char *family = "UNIX";
|
||||||
|
int ret;
|
||||||
|
cbuf *cb = cbuf_new();
|
||||||
|
|
||||||
|
/* In the startup, logs to stderr & debug flag set later */
|
||||||
|
clicon_log_init(__FILE__, LOG_INFO, CLICON_LOG_STDERR);
|
||||||
|
|
||||||
|
optind = 1;
|
||||||
|
opterr = 0;
|
||||||
|
while ((c = getopt(argc, argv, "hD:s:f:Ja:")) != -1)
|
||||||
|
switch (c) {
|
||||||
|
case 'h':
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
if (sscanf(optarg, "%d", &debug) != 1)
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sockpath = optarg;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
input_filename = optarg;
|
||||||
|
break;
|
||||||
|
case 'J':
|
||||||
|
jsonin++;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
family = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
clicon_log_init(__FILE__, debug?LOG_DEBUG:LOG_INFO, logdst);
|
||||||
|
if (sockpath == NULL){
|
||||||
|
fprintf(stderr, "Mandatory option missing: -s <sockpath>\n");
|
||||||
|
usage(argv[0]);
|
||||||
|
}
|
||||||
|
if (input_filename){
|
||||||
|
if ((fd = open(input_filename, O_RDONLY)) < 0){
|
||||||
|
clicon_err(OE_YANG, errno, "open(%s)", input_filename);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 2. Parse data (xml/json) */
|
||||||
|
if (jsonin){
|
||||||
|
if ((ret = json_parse_file(fd, NULL, &xt, &xerr)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (ret == 0){
|
||||||
|
fprintf(stderr, "Invalid JSON\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (xml_parse_file(fd, NULL, NULL, &xt) < 0){
|
||||||
|
fprintf(stderr, "xml parse error: %s\n", clicon_err_reason);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((xc = xml_child_i(xt, 0)) == NULL){
|
||||||
|
fprintf(stderr, "No xml\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (clicon_xml2cbuf(cb, xc, 0, 0, -1) < 0)
|
||||||
|
goto done;
|
||||||
|
if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) < 0)
|
||||||
|
goto done;
|
||||||
|
if (strcmp(family, "UNIX")==0){
|
||||||
|
if (clicon_rpc_connect_unix(msg, sockpath, &retdata, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (clicon_rpc_connect_inet(msg, sockpath, 4535, &retdata, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
fprintf(stdout, "%s\n", retdata);
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xerr)
|
||||||
|
xml_free(xerr);
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
if (msg)
|
||||||
|
free(msg);
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -64,19 +64,10 @@
|
||||||
/* clixon */
|
/* clixon */
|
||||||
#include "clixon/clixon.h"
|
#include "clixon/clixon.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* Turn this on to get a xml parse and pretty print test program
|
|
||||||
* Usage: xpath
|
|
||||||
* read xml from input
|
|
||||||
* Example compile:
|
|
||||||
gcc -g -o xml -I. -I../clixon ./clixon_xml.c -lclixon -lcligen
|
|
||||||
* Example run:
|
|
||||||
echo "<a><b/></a>" | xml
|
|
||||||
*/
|
|
||||||
static int
|
static int
|
||||||
usage(char *argv0)
|
usage(char *argv0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "usage:%s [options] with xml on stdin\n"
|
fprintf(stderr, "usage:%s [options] with xml on stdin (unless -f)\n"
|
||||||
"where options are\n"
|
"where options are\n"
|
||||||
"\t-h \t\tHelp\n"
|
"\t-h \t\tHelp\n"
|
||||||
"\t-D <level> \tDebug\n"
|
"\t-D <level> \tDebug\n"
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,9 @@ module clixon-config {
|
||||||
revision 2019-09-11 {
|
revision 2019-09-11 {
|
||||||
description
|
description
|
||||||
"Added: CLICON_BACKEND_USER: drop of privileges to user,
|
"Added: CLICON_BACKEND_USER: drop of privileges to user,
|
||||||
CLICON_BACKEND_PRIVILEGES: how to drop privileges";
|
CLICON_BACKEND_PRIVILEGES: how to drop privileges
|
||||||
|
CLICON_NACM_CREDENTIALS: If and how to check backend sock priveleges with NACM
|
||||||
|
CLICON_NACM_RECOVERY_USER: Name of NACM recovery user.";
|
||||||
}
|
}
|
||||||
revision 2019-06-05 {
|
revision 2019-06-05 {
|
||||||
description
|
description
|
||||||
|
|
@ -203,6 +205,29 @@ module clixon-config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
typedef nacm_cred_mode{
|
||||||
|
description
|
||||||
|
"How NACM user should be matched with unix socket peer credentials.
|
||||||
|
This means nacm user must match socket peer user accessing the
|
||||||
|
backend socket. For IP sockets only mode none makes sense.";
|
||||||
|
type enumeration{
|
||||||
|
enum none {
|
||||||
|
description
|
||||||
|
"Dont match NACM user to any user credentials. Any user can pose
|
||||||
|
as any other user. Set this for IP sockets, or dont use NACM.";
|
||||||
|
}
|
||||||
|
enum exact {
|
||||||
|
description
|
||||||
|
"Exact match between NACM user and unix socket peer user.
|
||||||
|
Except for root user that can pose as any user.";
|
||||||
|
}
|
||||||
|
enum except {
|
||||||
|
description
|
||||||
|
"Exact match between NACM user and unix socket peer user, except
|
||||||
|
for root and www user (restconf).";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
container clixon-config {
|
container clixon-config {
|
||||||
leaf-list CLICON_FEATURE {
|
leaf-list CLICON_FEATURE {
|
||||||
|
|
@ -421,7 +446,12 @@ module clixon-config {
|
||||||
default "UNIX";
|
default "UNIX";
|
||||||
description
|
description
|
||||||
"Address family for communicating with clixon_backend
|
"Address family for communicating with clixon_backend
|
||||||
(UNIX|IPv4|IPv6)";
|
(UNIX|IPv4). IPv6 not yet implemented.
|
||||||
|
Note that UNIX socket makes credential check as follows:
|
||||||
|
(1) client needs rw access to the socket
|
||||||
|
(2) NACM credentials can be checked according to CLICON_NACM_CREDENTIALS
|
||||||
|
Warning: IPv4 and IPv6 sockets have no credential mechanism.
|
||||||
|
";
|
||||||
}
|
}
|
||||||
leaf CLICON_SOCK {
|
leaf CLICON_SOCK {
|
||||||
type string;
|
type string;
|
||||||
|
|
@ -543,6 +573,26 @@ module clixon-config {
|
||||||
type string;
|
type string;
|
||||||
description "RFC8341 NACM external configuration file";
|
description "RFC8341 NACM external configuration file";
|
||||||
}
|
}
|
||||||
|
leaf CLICON_NACM_CREDENTIALS {
|
||||||
|
type nacm_cred_mode;
|
||||||
|
default except;
|
||||||
|
description
|
||||||
|
"Verify nacm user credentials with unix socket peer cred.
|
||||||
|
This means nacm user must match unix user accessing the backend
|
||||||
|
socket.
|
||||||
|
Except for recovery user and www user (for restconf)";
|
||||||
|
}
|
||||||
|
leaf CLICON_NACM_RECOVERY_USER {
|
||||||
|
type string;
|
||||||
|
default "_nacm_recovery";
|
||||||
|
description
|
||||||
|
"C8341 defines a 'recovery session' as outside the scope. Clixon
|
||||||
|
defines this user as having special admin rights to exempt from
|
||||||
|
all access control enforcements.
|
||||||
|
Note setting of CLICON_NACM_CREDENTIALS is important, if set to
|
||||||
|
exact for example, this user must exist and be used, otherwise
|
||||||
|
another user (such as root or www) can pose as it.";
|
||||||
|
}
|
||||||
leaf CLICON_MODULE_LIBRARY_RFC7895 {
|
leaf CLICON_MODULE_LIBRARY_RFC7895 {
|
||||||
type boolean;
|
type boolean;
|
||||||
default true;
|
default true;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue