* NACM Data node READ access module support (RFC8341 3.4.5)
* Access control points added for `get` and `get-config` in addition to incoming rpc. * RFC 8341 Example A.2 implemented, see: [test/test_nacm_module.sh] * Added `username` argument on `xmldb_put()` datastore function for NACM data-node write checks * Added `xml_rootchild_node()` lib function as variant of `xml_rootchild()`
This commit is contained in:
parent
04bb05c83f
commit
ffecebf32a
20 changed files with 656 additions and 145 deletions
|
|
@ -177,14 +177,19 @@ netconf_db_find(cxobj *xn,
|
|||
static int
|
||||
from_client_get_config(clicon_handle h,
|
||||
cxobj *xe,
|
||||
char *username,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
char *db;
|
||||
cxobj *xfilter;
|
||||
char *selector = "/";
|
||||
cxobj *xret = NULL;
|
||||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
int retval = -1;
|
||||
char *db;
|
||||
cxobj *xfilter;
|
||||
char *xpath = "/";
|
||||
cxobj *xret = NULL;
|
||||
cbuf *cbx = NULL; /* Assist cbuf */
|
||||
cxobj *xnacm = NULL;
|
||||
cxobj **xvec = NULL;
|
||||
size_t xlen;
|
||||
int ret;
|
||||
|
||||
if ((db = netconf_db_find(xe, "source")) == NULL){
|
||||
clicon_err(OE_XML, 0, "db not found");
|
||||
|
|
@ -201,13 +206,23 @@ from_client_get_config(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
if ((xfilter = xml_find(xe, "filter")) != NULL)
|
||||
if ((selector = xml_find_value(xfilter, "select"))==NULL)
|
||||
selector="/";
|
||||
if (xmldb_get(h, db, selector, 1, &xret) < 0){
|
||||
if ((xpath = xml_find_value(xfilter, "select"))==NULL)
|
||||
xpath="/";
|
||||
if (xmldb_get(h, db, xpath, 1, &xret) < 0){
|
||||
if (netconf_operation_failed(cbret, "application", "read registry")< 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
/* Pre-NACM access step */
|
||||
if ((ret = nacm_access(h, username, &xnacm)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* Do NACM validation */
|
||||
if (xpath_vec(xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
goto done;
|
||||
/* NACM datanode/module read validation */
|
||||
if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbret, "<rpc-reply>");
|
||||
if (xret==NULL)
|
||||
cprintf(cbret, "<data/>");
|
||||
|
|
@ -221,6 +236,10 @@ from_client_get_config(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (xnacm)
|
||||
xml_free(xnacm);
|
||||
if (xvec)
|
||||
free(xvec);
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
if (xret)
|
||||
|
|
@ -356,6 +375,7 @@ client_statedata(clicon_handle h,
|
|||
static int
|
||||
from_client_get(clicon_handle h,
|
||||
cxobj *xe,
|
||||
char *username,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -363,7 +383,10 @@ from_client_get(clicon_handle h,
|
|||
char *xpath = "/";
|
||||
cxobj *xret = NULL;
|
||||
int ret;
|
||||
|
||||
cxobj **xvec = NULL;
|
||||
size_t xlen;
|
||||
cxobj *xnacm = NULL;
|
||||
|
||||
if ((xfilter = xml_find(xe, "filter")) != NULL)
|
||||
if ((xpath = xml_find_value(xfilter, "select"))==NULL)
|
||||
xpath="/";
|
||||
|
|
@ -383,6 +406,16 @@ from_client_get(clicon_handle h,
|
|||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
/* Pre-NACM access step */
|
||||
if ((ret = nacm_access(h, username, &xnacm)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* Do NACM validation */
|
||||
if (xpath_vec(xret, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
goto done;
|
||||
/* NACM datanode/module read validation */
|
||||
if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbret, "<rpc-reply>"); /* OK */
|
||||
if (xret==NULL)
|
||||
cprintf(cbret, "<data/>");
|
||||
|
|
@ -396,6 +429,10 @@ from_client_get(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (xnacm)
|
||||
xml_free(xnacm);
|
||||
if (xvec)
|
||||
free(xvec);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
return retval;
|
||||
|
|
@ -412,6 +449,7 @@ static int
|
|||
from_client_edit_config(clicon_handle h,
|
||||
cxobj *xn,
|
||||
int mypid,
|
||||
char *username,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -485,7 +523,7 @@ from_client_edit_config(clicon_handle h,
|
|||
*/
|
||||
if (xml_apply0(xc, CX_ELMNT, xml_sort, NULL) < 0)
|
||||
goto done;
|
||||
if ((ret = xmldb_put(h, target, operation, xc, cbret)) < 0){
|
||||
if ((ret = xmldb_put(h, target, operation, xc, username, cbret)) < 0){
|
||||
clicon_debug(1, "%s ERROR PUT", __FUNCTION__);
|
||||
if (netconf_operation_failed(cbret, "protocol", clicon_err_reason)< 0)
|
||||
goto done;
|
||||
|
|
@ -963,7 +1001,8 @@ from_client_msg(clicon_handle h,
|
|||
yang_spec *yspec;
|
||||
yang_stmt *ye;
|
||||
yang_stmt *ymod;
|
||||
|
||||
cxobj *xnacm = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
pid = ce->ce_pid;
|
||||
yspec = clicon_dbspec_yang(h);
|
||||
|
|
@ -996,6 +1035,8 @@ from_client_msg(clicon_handle h,
|
|||
goto reply;
|
||||
xe = NULL;
|
||||
username = xml_find_value(x, "username");
|
||||
/* May be used by callbacks, etc */
|
||||
clicon_username_set(h, username);
|
||||
while ((xe = xml_child_each(x, xe, CX_ELMNT)) != NULL) {
|
||||
rpc = xml_name(xe);
|
||||
if ((ye = xml_spec(xe)) == NULL){
|
||||
|
|
@ -1009,17 +1050,25 @@ from_client_msg(clicon_handle h,
|
|||
}
|
||||
module = ymod->ys_argument;
|
||||
clicon_debug(1, "%s module:%s rpc:%s", __FUNCTION__, module, rpc);
|
||||
/* Make NACM access control if enabled as "internal"*/
|
||||
if ((ret = nacm_access(h, rpc, module, username, cbret)) < 0)
|
||||
/* Pre-NACM access step */
|
||||
xnacm = NULL;
|
||||
if ((ret = nacm_access(h, username, &xnacm)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto reply;
|
||||
if (ret == 0){ /* Do NACM validation */
|
||||
/* NACM rpc operation exec validation */
|
||||
if ((ret = nacm_rpc(rpc, module, username, xnacm, cbret)) < 0)
|
||||
goto done;
|
||||
if (xnacm)
|
||||
xml_free(xnacm);
|
||||
if (ret == 0) /* Not permitted and cbret set */
|
||||
goto reply;
|
||||
}
|
||||
if (strcmp(rpc, "get-config") == 0){
|
||||
if (from_client_get_config(h, xe, cbret) <0)
|
||||
if (from_client_get_config(h, xe, username, cbret) <0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(rpc, "edit-config") == 0){
|
||||
if (from_client_edit_config(h, xe, pid, cbret) <0)
|
||||
if (from_client_edit_config(h, xe, pid, username, cbret) <0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(rpc, "copy-config") == 0){
|
||||
|
|
@ -1039,7 +1088,7 @@ from_client_msg(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
else if (strcmp(rpc, "get") == 0){
|
||||
if (from_client_get(h, xe, cbret) < 0)
|
||||
if (from_client_get(h, xe, username, cbret) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(rpc, "close-session") == 0){
|
||||
|
|
|
|||
|
|
@ -285,7 +285,8 @@ candidate_commit(clicon_handle h,
|
|||
|
||||
/* Optionally write (potentially modified) tree back to candidate */
|
||||
if (clicon_option_bool(h, "CLICON_TRANSACTION_MOD")){
|
||||
if ((ret = xmldb_put(h, candidate, OP_REPLACE, td->td_target, cbret)) < 0)
|
||||
if ((ret = xmldb_put(h, candidate, OP_REPLACE, td->td_target,
|
||||
clicon_username_get(h), cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
|
|
@ -440,7 +441,8 @@ from_client_validate(clicon_handle h,
|
|||
}
|
||||
/* Optionally write (potentially modified) tree back to candidate */
|
||||
if (clicon_option_bool(h, "CLICON_TRANSACTION_MOD")){
|
||||
if ((ret = xmldb_put(h, "candidate", OP_REPLACE, td->td_target, cbret)) < 0)
|
||||
if ((ret = xmldb_put(h, "candidate", OP_REPLACE, td->td_target,
|
||||
clicon_username_get(h), cbret)) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ db_merge(clicon_handle h,
|
|||
if (xmldb_get(h, (char*)db1, NULL, 1, &xt) < 0)
|
||||
goto done;
|
||||
/* Merge xml into db2. Without commit */
|
||||
retval = xmldb_put(h, (char*)db2, OP_MERGE, xt, cbret);
|
||||
retval = xmldb_put(h, (char*)db2, OP_MERGE, xt, clicon_username_get(h), cbret);
|
||||
done:
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
|
|
@ -318,7 +318,7 @@ load_extraxml(clicon_handle h,
|
|||
if (xml_rootchild(xt, 0, &xt) < 0)
|
||||
goto done;
|
||||
/* Merge user reset state */
|
||||
retval = xmldb_put(h, (char*)db, OP_MERGE, xt, cbret);
|
||||
retval = xmldb_put(h, (char*)db, OP_MERGE, xt, clicon_username_get(h), cbret);
|
||||
done:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
|
|
@ -857,6 +857,10 @@ main(int argc,
|
|||
goto done;
|
||||
if (xmldb_setopt(h, "pretty", (void*)(intptr_t)clicon_option_bool(h, "CLICON_XMLDB_PRETTY")) < 0)
|
||||
goto done;
|
||||
if (xmldb_setopt(h, "nacm_mode", (void*)nacm_mode) < 0)
|
||||
goto done;
|
||||
if (xmldb_setopt(h, "nacm_xtree", (void*)clicon_nacm_ext(h)) < 0)
|
||||
goto done;
|
||||
/* Startup mode needs to be defined, */
|
||||
startup_mode = clicon_startup_mode(h);
|
||||
if (startup_mode == -1){
|
||||
|
|
@ -906,7 +910,6 @@ main(int argc,
|
|||
}
|
||||
}
|
||||
/* Write pid-file */
|
||||
|
||||
if ((pid = pidfile_write(pidfile)) < 0)
|
||||
goto done;
|
||||
|
||||
|
|
|
|||
|
|
@ -643,18 +643,19 @@ match_list_keys(yang_stmt *y,
|
|||
char *keyd;
|
||||
|
||||
if (y->ys_keyword != Y_LIST &&y->ys_keyword != Y_LEAF_LIST)
|
||||
return -1;
|
||||
goto done;
|
||||
cvk = y->ys_cvec; /* Use Y_LIST cache, see ys_populate_list() */
|
||||
cvi = NULL;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
||||
keyname = cv_string_get(cvi);
|
||||
if ((xkeya = xml_find(xapipath, keyname)) == NULL)
|
||||
goto done; /* No key in api-path */
|
||||
|
||||
keya = xml_body(xkeya);
|
||||
if ((keya = xml_body(xkeya)) == NULL)
|
||||
goto done;
|
||||
if ((xkeyd = xml_find(xdata, keyname)) == NULL)
|
||||
goto done; /* No key in data */
|
||||
keyd = xml_body(xkeyd);
|
||||
if ((keyd = xml_body(xkeyd)) == NULL)
|
||||
goto done;
|
||||
if (strcmp(keya, keyd) != 0)
|
||||
goto done; /* keys dont match */
|
||||
}
|
||||
|
|
@ -778,7 +779,7 @@ api_data_put(clicon_handle h,
|
|||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* The message-body MUST contain exactly one instance of the
|
||||
* expected data resource.
|
||||
*/
|
||||
|
|
@ -807,6 +808,7 @@ api_data_put(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add operation (create/replace) as attribute */
|
||||
if ((xa = xml_new("operation", x, NULL)) == NULL)
|
||||
goto done;
|
||||
|
|
@ -831,6 +833,7 @@ api_data_put(clicon_handle h,
|
|||
xml_name_set(xtop, "config");
|
||||
}
|
||||
else {
|
||||
clicon_debug(1, "%s x:%s xbot:%s",__FUNCTION__, xml_name(x), xml_name(xbot));
|
||||
/* Check same symbol in api-path as data */
|
||||
if (strcmp(xml_name(x), xml_name(xbot))){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0)
|
||||
|
|
@ -896,7 +899,6 @@ api_data_put(clicon_handle h,
|
|||
by NACM */
|
||||
cprintf(cbx, "<rpc username=\"%s\">", NACM_RECOVERY_USER);
|
||||
cprintf(cbx, "<commit/></rpc>");
|
||||
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue