restricted NACM recovery user
This commit is contained in:
parent
5c3f18c2da
commit
a7737c283c
7 changed files with 126 additions and 99 deletions
18
CHANGELOG.md
18
CHANGELOG.md
|
|
@ -1,6 +1,6 @@
|
||||||
# Clixon Changelog
|
# Clixon Changelog
|
||||||
|
|
||||||
* [4.6.0](#460) Expected: July 2020
|
* [4.6.0](#460) Expected: August 2020
|
||||||
* [4.5.0](#450) 12 May 2020
|
* [4.5.0](#450) 12 May 2020
|
||||||
* [4.4.0](#440) 5 April 2020
|
* [4.4.0](#440) 5 April 2020
|
||||||
* [4.3.0](#430) 1 January 2020
|
* [4.3.0](#430) 1 January 2020
|
||||||
|
|
@ -49,22 +49,6 @@ Expected: July 2020
|
||||||
* NACM default behaviour is read-only (empty configs are dead-lockedd)
|
* NACM default behaviour is read-only (empty configs are dead-lockedd)
|
||||||
* This applies if NACM is loaded and `CLICON_NACM_MODE` is `internal`
|
* This applies if NACM is loaded and `CLICON_NACM_MODE` is `internal`
|
||||||
* Due to the previous bult (top-level default leafs)
|
* Due to the previous bult (top-level default leafs)
|
||||||
* This means that empty configs or empty NACM configs are not writable (deadlocked).
|
|
||||||
* Workarounds:
|
|
||||||
1. Access the system with the recovery user, see clixon option CLICON_NACM_RECOVERY_USER
|
|
||||||
|
|
||||||
* This means that empty configs or empty NACM configs are not writable (deadlocked).
|
|
||||||
* Workarounds:
|
|
||||||
1. Access the system with the recovery user, see clixon option CLICON_NACM_RECOVERY_USER
|
|
||||||
|
|
||||||
* This means that empty configs or empty NACM configs are not writable (deadlocked).
|
|
||||||
* Workarounds:
|
|
||||||
1. Access the system with the recovery user, see clixon option CLICON_NACM_RECOVERY_USER
|
|
||||||
|
|
||||||
* This means that empty configs or empty NACM configs are not writable (deadlocked).
|
|
||||||
* Workarounds:
|
|
||||||
1. Access the system with the recovery user, see clixon option CLICON_NACM_RECOVERY_USER
|
|
||||||
|
|
||||||
* This means that empty configs or empty NACM configs are not writable (deadlocked).
|
* This means that empty configs or empty NACM configs are not writable (deadlocked).
|
||||||
* Workarounds:
|
* Workarounds:
|
||||||
1. Access the system with the recovery user, see clixon option CLICON_NACM_RECOVERY_USER
|
1. Access the system with the recovery user, see clixon option CLICON_NACM_RECOVERY_USER
|
||||||
|
|
|
||||||
|
|
@ -1490,69 +1490,6 @@ from_client_restart_plugin(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! 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;
|
|
||||||
#ifdef WITH_RESTCONF
|
|
||||||
if (strcmp(peername, WWWUSER) == 0)
|
|
||||||
goto ok;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
|
|
@ -1670,9 +1607,16 @@ from_client_msg(clicon_handle h,
|
||||||
/* Pre-NACM access step */
|
/* Pre-NACM access step */
|
||||||
xnacm = NULL;
|
xnacm = NULL;
|
||||||
|
|
||||||
if ((ret = nacm_access_pre(h, username, &xnacm)) < 0)
|
/* NACM intial pre- access control enforcements. Retval:
|
||||||
|
* 0: Use NACM validation and xnacm is set.
|
||||||
|
* 1: Permit, skip NACM
|
||||||
|
* Therefore, xnacm=NULL means no NACM checks needed.
|
||||||
|
*/
|
||||||
|
if ((ret = nacm_access_pre(h, ce->ce_username, username, &xnacm)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Cache XML NACM tree here. Use with caution, only valid on from_client_msg stack */
|
/* Cache XML NACM tree here. Use with caution, only valid on from_client_msg stack
|
||||||
|
*
|
||||||
|
*/
|
||||||
if (clicon_nacm_cache_set(h, xnacm) < 0)
|
if (clicon_nacm_cache_set(h, xnacm) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (ret == 0){ /* Do NACM RPC validation */
|
if (ret == 0){ /* Do NACM RPC validation */
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,7 @@ startup_common(clicon_handle h,
|
||||||
/* Print upgraded db: -q backend switch */
|
/* Print upgraded db: -q backend switch */
|
||||||
if (clicon_quit_upgrade_get(h) == 1){
|
if (clicon_quit_upgrade_get(h) == 1){
|
||||||
/* bind yang */
|
/* bind yang */
|
||||||
if (ret = (xml_bind_yang(xt, YB_MODULE, yspec, &xret) < 1)){
|
if ((ret = (xml_bind_yang(xt, YB_MODULE, yspec, &xret)) < 1)){
|
||||||
if (ret == 0){
|
if (ret == 0){
|
||||||
/* invalid */
|
/* invalid */
|
||||||
clicon_err(OE_XML, EFAULT, "invalid configuration");
|
clicon_err(OE_XML, EFAULT, "invalid configuration");
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ int nacm_datanode_read(clicon_handle h, cxobj *xt, cxobj **xvec, size_t xlen, ch
|
||||||
int nacm_datanode_write(clicon_handle h, cxobj *xr, cxobj *xt,
|
int nacm_datanode_write(clicon_handle h, cxobj *xr, cxobj *xt,
|
||||||
enum nacm_access access,
|
enum nacm_access access,
|
||||||
char *username, cxobj *xnacm, cbuf *cbret);
|
char *username, cxobj *xnacm, cbuf *cbret);
|
||||||
int nacm_access_pre(clicon_handle h, char *username, cxobj **xnacmp);
|
int nacm_access_pre(clicon_handle h, char *peername, char *username, cxobj **xnacmp);
|
||||||
|
int verify_nacm_user(enum nacm_credentials_t cred, char *peername, char *nacmname, cbuf *cbret);
|
||||||
|
|
||||||
#endif /* _CLIXON_NACM_H */
|
#endif /* _CLIXON_NACM_H */
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ enum priv_mode_t{
|
||||||
|
|
||||||
/*! See clixon-config.yang type nacm_cred_mode (user credentials) */
|
/*! See clixon-config.yang type nacm_cred_mode (user credentials) */
|
||||||
enum nacm_credentials_t{
|
enum nacm_credentials_t{
|
||||||
NC_NONE=0, /* "Dont match NACM user to any user credentials. */
|
NC_NONE=0, /* Dont match NACM user to any user credentials. */
|
||||||
NC_EXACT, /* Exact match between NACM user and unix socket peer user. */
|
NC_EXACT, /* Exact match between NACM user and unix socket peer user. */
|
||||||
NC_EXCEPT /* Exact match except for root and www user */
|
NC_EXCEPT /* Exact match except for root and www user */
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1075,7 +1075,7 @@ nacm_datanode_read(clicon_handle h,
|
||||||
* @retval 0 OK but not validated. Need to do NACM step using xnacm
|
* @retval 0 OK but not validated. Need to do NACM step using xnacm
|
||||||
* @retval 1 OK permitted. You do not need to do next NACM step
|
* @retval 1 OK permitted. You do not need to do next NACM step
|
||||||
* @code
|
* @code
|
||||||
* if ((ret = nacm_access(h, mode, xnacm, username)) < 0)
|
* if ((ret = nacm_access_check(h, mode, xnacm, peername, username)) < 0)
|
||||||
* err;
|
* err;
|
||||||
* if (ret == 0){
|
* if (ret == 0){
|
||||||
* // Next step NACM processing
|
* // Next step NACM processing
|
||||||
|
|
@ -1085,14 +1085,16 @@ nacm_datanode_read(clicon_handle h,
|
||||||
* @see RFC8341 3.4 Access Control Enforcement Procedures
|
* @see RFC8341 3.4 Access Control Enforcement Procedures
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
nacm_access(clicon_handle h,
|
nacm_access_check(clicon_handle h,
|
||||||
cxobj *xnacm,
|
cxobj *xnacm,
|
||||||
char *username)
|
char *peername,
|
||||||
|
char *username)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *enabled;
|
char *enabled;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
cvec *nsc = NULL;
|
cvec *nsc = NULL;
|
||||||
|
char *recovery_user;
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
|
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
|
||||||
|
|
@ -1108,11 +1110,40 @@ nacm_access(clicon_handle h,
|
||||||
enabled = xml_body(x);
|
enabled = xml_body(x);
|
||||||
if (strcmp(enabled, "true") != 0)
|
if (strcmp(enabled, "true") != 0)
|
||||||
goto permit;
|
goto permit;
|
||||||
|
recovery_user=clicon_nacm_recovery_user(h);
|
||||||
/* 2. If the requesting session is identified as a recovery session,
|
/* 2. If the requesting session is identified as a recovery session,
|
||||||
then the protocol operation is permitted. NYI */
|
* then the protocol operation is permitted.
|
||||||
if (username && strcmp(username, clicon_nacm_recovery_user(h)) == 0)
|
*/
|
||||||
goto permit;
|
if (username && peername && recovery_user &&
|
||||||
|
strcmp(username, recovery_user) == 0){
|
||||||
|
/* Recovery session in clixon is defined as
|
||||||
|
* 1) username (sent in message) is recovery user
|
||||||
|
* AND
|
||||||
|
* if cred is EXACT:
|
||||||
|
* 2a) peername is also recovery user
|
||||||
|
* if cred is EXCEPT/NONE:;
|
||||||
|
* 2b) peername is recovery user/root/WWWUSER
|
||||||
|
*/
|
||||||
|
if (strcmp(peername, recovery_user) == 0)
|
||||||
|
goto permit;
|
||||||
|
switch(clicon_nacm_credentials(h)){
|
||||||
|
case NC_EXACT:
|
||||||
|
break;
|
||||||
|
case NC_NONE:
|
||||||
|
goto permit;
|
||||||
|
break;
|
||||||
|
case NC_EXCEPT:
|
||||||
|
if (strcmp(username, recovery_user) == 0 &&
|
||||||
|
strcmp(peername, "root") == 0)
|
||||||
|
goto permit;
|
||||||
|
#ifdef WITH_RESTCONF
|
||||||
|
if (strcmp(username, recovery_user) == 0 &&
|
||||||
|
strcmp(peername, WWWUSER) == 0)
|
||||||
|
goto permit;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
retval = 0; /* not permitted yet. continue with next NACM step */
|
retval = 0; /* not permitted yet. continue with next NACM step */
|
||||||
done:
|
done:
|
||||||
if (nsc)
|
if (nsc)
|
||||||
|
|
@ -1133,10 +1164,10 @@ nacm_access(clicon_handle h,
|
||||||
* @param[out] xncam NACM XML tree, set if retval=0. Free after use
|
* @param[out] xncam NACM XML tree, set if retval=0. Free after use
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @retval 0 OK but not validated. Need to do NACM step using xnacm
|
* @retval 0 OK but not validated. Need to do NACM step using xnacm
|
||||||
* @retval 1 OK permitted. You do not need to do next NACM step
|
* @retval 1 OK permitted. You do not need to do next NACM step.
|
||||||
* @code
|
* @code
|
||||||
* cxobj *xnacm = NULL;
|
* cxobj *xnacm = NULL;
|
||||||
* if ((ret = nacm_access_pre(h, username, &xnacm)) < 0)
|
* if ((ret = nacm_access_pre(h, peername, username, &xnacm)) < 0)
|
||||||
* err;
|
* err;
|
||||||
* if (ret == 0){
|
* if (ret == 0){
|
||||||
* // Next step NACM processing
|
* // Next step NACM processing
|
||||||
|
|
@ -1147,6 +1178,7 @@ nacm_access(clicon_handle h,
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
nacm_access_pre(clicon_handle h,
|
nacm_access_pre(clicon_handle h,
|
||||||
|
char *peername,
|
||||||
char *username,
|
char *username,
|
||||||
cxobj **xnacmp)
|
cxobj **xnacmp)
|
||||||
{
|
{
|
||||||
|
|
@ -1189,7 +1221,7 @@ nacm_access_pre(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
xnacm0 = NULL;
|
xnacm0 = NULL;
|
||||||
/* Initial NACM steps and common to all NACM access validation. */
|
/* Initial NACM steps and common to all NACM access validation. */
|
||||||
if ((retval = nacm_access(h, xnacm, username)) < 0)
|
if ((retval = nacm_access_check(h, xnacm, peername, 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 */
|
||||||
*xnacmp = xnacm;
|
*xnacmp = xnacm;
|
||||||
|
|
@ -1208,3 +1240,70 @@ nacm_access_pre(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! 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
|
||||||
|
* - cred mode is NONE,
|
||||||
|
* Otherwise both NACM user AND peer user must exist, and
|
||||||
|
* if cred mode is EXACT and
|
||||||
|
* - peer user is same as NACM user
|
||||||
|
* or if cred mode is EXCEPT 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)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
verify_nacm_user(enum nacm_credentials_t cred,
|
||||||
|
char *peername,
|
||||||
|
char *nacmname,
|
||||||
|
cbuf *cbret)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cbmsg = NULL;
|
||||||
|
|
||||||
|
if (cred == 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 (cred == NC_EXCEPT){
|
||||||
|
if (strcmp(peername, "root") == 0)
|
||||||
|
goto ok;
|
||||||
|
#ifdef WITH_RESTCONF
|
||||||
|
if (strcmp(peername, WWWUSER) == 0)
|
||||||
|
goto ok;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -704,8 +704,7 @@ module clixon-config {
|
||||||
description
|
description
|
||||||
"Verify nacm user credentials with unix socket peer cred.
|
"Verify nacm user credentials with unix socket peer cred.
|
||||||
This means nacm user must match unix user accessing the backend
|
This means nacm user must match unix user accessing the backend
|
||||||
socket.
|
socket.";
|
||||||
Except for recovery user and www user (for restconf)";
|
|
||||||
}
|
}
|
||||||
leaf CLICON_NACM_RECOVERY_USER {
|
leaf CLICON_NACM_RECOVERY_USER {
|
||||||
type string;
|
type string;
|
||||||
|
|
@ -716,7 +715,7 @@ module clixon-config {
|
||||||
all access control enforcements.
|
all access control enforcements.
|
||||||
Note setting of CLICON_NACM_CREDENTIALS is important, if set to
|
Note setting of CLICON_NACM_CREDENTIALS is important, if set to
|
||||||
exact for example, this user must exist and be used, otherwise
|
exact for example, this user must exist and be used, otherwise
|
||||||
another user (such as root or www) can pose as it.";
|
another user (such as root or www) can pose as the recovery user.";
|
||||||
}
|
}
|
||||||
leaf CLICON_NACM_DISABLED_ON_EMPTY {
|
leaf CLICON_NACM_DISABLED_ON_EMPTY {
|
||||||
type boolean;
|
type boolean;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue