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
|
||||
|
||||
* [4.6.0](#460) Expected: July 2020
|
||||
* [4.6.0](#460) Expected: August 2020
|
||||
* [4.5.0](#450) 12 May 2020
|
||||
* [4.4.0](#440) 5 April 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)
|
||||
* This applies if NACM is loaded and `CLICON_NACM_MODE` is `internal`
|
||||
* 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).
|
||||
* Workarounds:
|
||||
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;
|
||||
}
|
||||
|
||||
/*! 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
|
||||
|
|
@ -1670,9 +1607,16 @@ from_client_msg(clicon_handle h,
|
|||
/* Pre-NACM access step */
|
||||
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;
|
||||
/* 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)
|
||||
goto done;
|
||||
if (ret == 0){ /* Do NACM RPC validation */
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ startup_common(clicon_handle h,
|
|||
/* Print upgraded db: -q backend switch */
|
||||
if (clicon_quit_upgrade_get(h) == 1){
|
||||
/* 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){
|
||||
/* invalid */
|
||||
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,
|
||||
enum nacm_access access,
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ enum priv_mode_t{
|
|||
|
||||
/*! 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_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 */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1075,7 +1075,7 @@ nacm_datanode_read(clicon_handle h,
|
|||
* @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
|
||||
* @code
|
||||
* if ((ret = nacm_access(h, mode, xnacm, username)) < 0)
|
||||
* if ((ret = nacm_access_check(h, mode, xnacm, peername, username)) < 0)
|
||||
* err;
|
||||
* if (ret == 0){
|
||||
* // Next step NACM processing
|
||||
|
|
@ -1085,14 +1085,16 @@ nacm_datanode_read(clicon_handle h,
|
|||
* @see RFC8341 3.4 Access Control Enforcement Procedures
|
||||
*/
|
||||
static int
|
||||
nacm_access(clicon_handle h,
|
||||
cxobj *xnacm,
|
||||
char *username)
|
||||
nacm_access_check(clicon_handle h,
|
||||
cxobj *xnacm,
|
||||
char *peername,
|
||||
char *username)
|
||||
{
|
||||
int retval = -1;
|
||||
char *enabled;
|
||||
cxobj *x;
|
||||
cvec *nsc = NULL;
|
||||
char *recovery_user;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
|
||||
|
|
@ -1108,11 +1110,40 @@ nacm_access(clicon_handle h,
|
|||
enabled = xml_body(x);
|
||||
if (strcmp(enabled, "true") != 0)
|
||||
goto permit;
|
||||
recovery_user=clicon_nacm_recovery_user(h);
|
||||
/* 2. If the requesting session is identified as a recovery session,
|
||||
then the protocol operation is permitted. NYI */
|
||||
if (username && strcmp(username, clicon_nacm_recovery_user(h)) == 0)
|
||||
goto permit;
|
||||
|
||||
* then the protocol operation is permitted.
|
||||
*/
|
||||
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 */
|
||||
done:
|
||||
if (nsc)
|
||||
|
|
@ -1133,10 +1164,10 @@ nacm_access(clicon_handle h,
|
|||
* @param[out] xncam NACM XML tree, set if retval=0. Free after use
|
||||
* @retval -1 Error
|
||||
* @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
|
||||
* cxobj *xnacm = NULL;
|
||||
* if ((ret = nacm_access_pre(h, username, &xnacm)) < 0)
|
||||
* if ((ret = nacm_access_pre(h, peername, username, &xnacm)) < 0)
|
||||
* err;
|
||||
* if (ret == 0){
|
||||
* // Next step NACM processing
|
||||
|
|
@ -1147,6 +1178,7 @@ nacm_access(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
nacm_access_pre(clicon_handle h,
|
||||
char *peername,
|
||||
char *username,
|
||||
cxobj **xnacmp)
|
||||
{
|
||||
|
|
@ -1189,7 +1221,7 @@ nacm_access_pre(clicon_handle h,
|
|||
goto done;
|
||||
xnacm0 = NULL;
|
||||
/* 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;
|
||||
if (retval == 0){ /* if retval == 0 then return an xml nacm tree */
|
||||
*xnacmp = xnacm;
|
||||
|
|
@ -1208,3 +1240,70 @@ nacm_access_pre(clicon_handle h,
|
|||
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
|
||||
"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)";
|
||||
socket.";
|
||||
}
|
||||
leaf CLICON_NACM_RECOVERY_USER {
|
||||
type string;
|
||||
|
|
@ -716,7 +715,7 @@ module clixon-config {
|
|||
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.";
|
||||
another user (such as root or www) can pose as the recovery user.";
|
||||
}
|
||||
leaf CLICON_NACM_DISABLED_ON_EMPTY {
|
||||
type boolean;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue