The Clixon API has been extended with namespaces, or namespace contexts in the following cases:

* CLIspec functions have added namespace parameter:
    * `cli_show_config <db> <format> <xpath>` --> `cli_show_config <db> <format> <xpath> <namespace>`
    * `cli_copy_config <db> <xpath> ...` --> `cli_copy_config <db> <xpath> <namespace> ...`
  * Xpath API
    * `xpath_first(x, format, ...)` --> `xpath_first(x, nsc, format, ...)`
    * `xpath_vec(x, format, vec, veclen, ...)` --> `xpath_vec(x, nsc, format, vec, veclen, ...)`
    * `xpath_vec_flag(x, format, flags, vec, veclen, ...)` --> `xpath_vec_flag(x, format, flags, vec, veclen, ...)`
    * `xpath_vec_bool(x, format, ...)` --> `xpath_vec_bool(x, nsc, format, ...)`
    * `xpath_vec_ctx(x, xpath, xp)` --> `xpath_vec_ctx(x, nsc, xpath, xp)`
  * xmldb_get0 has an added `nsc` parameter:
    * `xmldb_get0(h, db, xpath, copy, xret, msd)` --> `xmldb_get0(h, db, nsc, xpath, copy, xret, msd)`
  * The plugin statedata callback (ca_statedata) has been extended with an nsc parameter:
    * `int example_statedata(clicon_handle h, cvec *nsc, char *xpath, cxobj *xstate);`
  * rpc get and get-config api function has an added namespace argument:
    * `clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, char *namespace, cxobj **xt);`
    * `int clicon_rpc_get(clicon_handle h, char *xpath, char *namespace, cxobj **xt);`
This commit is contained in:
Olof hagsand 2019-07-08 10:36:37 +02:00
parent 73d8e97a01
commit 67b8685bab
78 changed files with 1507 additions and 538 deletions

View file

@ -68,8 +68,12 @@
#include "clixon_xpath.h"
#include "clixon_yang_module.h"
#include "clixon_datastore.h"
#include "clixon_xml_nsctx.h"
#include "clixon_nacm.h"
/* NACM namespace for use with xml namespace contexts and xpath */
#define NACM_NS "urn:ietf:params:xml:ns:yang:ietf-netconf-acm"
/*! Match nacm access operations according to RFC8341 3.4.4.
* Incoming RPC Message Validation Step 7 (c)
* The rule's "access-operations" leaf has the "exec" bit set or
@ -191,7 +195,11 @@ nacm_rpc(char *rpc,
char *gname;
char *action;
int match= 0;
cvec *nsc = NULL;
/* Create namespace context for with nacm namespace as default */
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
goto done;
/* 3. If the requested operation is the NETCONF <close-session>
protocol operation, then the protocol operation is permitted.
*/
@ -204,8 +212,9 @@ nacm_rpc(char *rpc,
transport layer.) */
if (username == NULL)
goto step10;
/* User's group */
if (xpath_vec(xnacm, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
goto done;
/* 5. If no groups are found, continue with step 10. */
if (glen == 0)
@ -214,14 +223,14 @@ nacm_rpc(char *rpc,
configuration. If a rule-list's "group" leaf-list does not
match any of the user's groups, proceed to the next rule-list
entry. */
if (xpath_vec(xnacm, "rule-list", &rlistvec, &rlistlen) < 0)
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
goto done;
for (i=0; i<rlistlen; i++){
rlist = rlistvec[i];
/* Loop through user's group to find match in this rule-list */
for (j=0; j<glen; j++){
gname = xml_find_body(gvec[j], "name");
if (xpath_first(rlist, ".[group='%s']", gname)!=NULL)
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL)
break; /* found */
}
if (j==glen) /* not found */
@ -230,7 +239,7 @@ nacm_rpc(char *rpc,
until a rule that matches the requested access operation is
found.
*/
if (xpath_vec(rlist, "rule", &rvec, &rlen) < 0)
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
goto done;
for (j=0; j<rlen; j++){
xrule = rvec[j];
@ -283,6 +292,8 @@ nacm_rpc(char *rpc,
retval = 1;
done:
clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
if (nsc)
xml_nsctx_free(nsc);
if (gvec)
free(gvec);
if (rlistvec)
@ -321,7 +332,11 @@ nacm_rule_datanode(cxobj *xt,
char *module;
cxobj *xpath; /* xpath match */
cxobj *xp; /* parent */
cvec *nsc = NULL;
/* Create namespace context for with nacm namespace as default */
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
goto done;
/* 6a) The rule's "module-name" leaf is "*" or equals the name of
* the YANG module where the requested data node is defined. */
if ((module_rule = xml_find_body(xrule, "module-name")) == NULL)
@ -375,7 +390,7 @@ nacm_rule_datanode(cxobj *xt,
}
/* Here module is matched, now check for path if any NYI */
if (path){
if ((xpath = xpath_first(xt, "%s", path)) == NULL)
if ((xpath = xpath_first(xt, nsc, "%s", path)) == NULL)
goto nomatch;
/* The requested node xr is the node specified by the path or is a
* descendant node of the path:
@ -390,6 +405,8 @@ nacm_rule_datanode(cxobj *xt,
match:
retval = 1;
done:
if (nsc)
xml_nsctx_free(nsc);
return retval;
nomatch:
retval = 0;
@ -403,7 +420,8 @@ nacm_rule_datanode(cxobj *xt,
* @param[in] glen Length of gvec
* @param[in] rlistvec NACM rule-list entries
* @param[in] rlistlen Length of rlistvec
* @param[out] xrulep If set, then points to matching rule
* @param[in] nsc NACM namespace context for xpaths
* @param[out] xrulep If set, then points to matching rule
*/
static int
nacm_data_read_xr(cxobj *xt,
@ -412,6 +430,7 @@ nacm_data_read_xr(cxobj *xt,
size_t glen,
cxobj **rlistvec,
size_t rlistlen,
cvec *nsc,
cxobj **xrulep)
{
int retval = -1;
@ -428,7 +447,7 @@ nacm_data_read_xr(cxobj *xt,
/* Loop through user's group to find match in this rule-list */
for (j=0; j<glen; j++){
gname = xml_find_body(gvec[j], "name");
if (xpath_first(rlist, ".[group='%s']", gname)!=NULL)
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL)
break; /* found */
}
if (j==glen) /* not found */
@ -437,7 +456,7 @@ nacm_data_read_xr(cxobj *xt,
until a rule that matches the requested access operation is
found. (see 6 sub rules in nacm_rule_datanode
*/
if (xpath_vec(rlist, "rule", &rvec, &rlen) < 0)
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
goto done;
for (j=0; j<rlen; j++){ /* Loop through rules */
xrule = rvec[j];
@ -556,7 +575,11 @@ nacm_datanode_read(cxobj *xt,
char *read_default = NULL;
cxobj *xrule;
char *action;
cvec *nsc = NULL;
/* Create namespace context for with nacm namespace as default */
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
goto done;
/* 3. Check all the "group" entries to see if any of them contain a
"user-name" entry that equals the username for the session
making the request. (If the "enable-external-groups" leaf is
@ -565,7 +588,7 @@ nacm_datanode_read(cxobj *xt,
if (username == NULL)
goto step9;
/* User's group */
if (xpath_vec(xnacm, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
goto done;
/* 4. If no groups are found (glen=0), continue and check read-default
in step 11. */
@ -573,7 +596,7 @@ nacm_datanode_read(cxobj *xt,
configuration. If a rule-list's "group" leaf-list does not
match any of the user's groups, proceed to the next rule-list
entry. */
if (xpath_vec(xnacm, "rule-list", &rlistvec, &rlistlen) < 0)
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
goto done;
/* read-default has default permit so should never be NULL */
if ((read_default = xml_find_body(xnacm, "read-default")) == NULL){
@ -587,7 +610,7 @@ nacm_datanode_read(cxobj *xt,
xrule = NULL;
/* Skip if no groups */
if (glen && nacm_data_read_xr(xt, xr, gvec, glen, rlistvec, rlistlen,
&xrule) < 0)
nsc, &xrule) < 0)
goto done;
if (xrule){ /* xrule match requested node xr */
if ((action = xml_find_body(xrule, "action")) == NULL)
@ -628,6 +651,8 @@ nacm_datanode_read(cxobj *xt,
retval = 0;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
if (nsc)
xml_nsctx_free(nsc);
if (gvec)
free(gvec);
if (rlistvec)
@ -673,7 +698,11 @@ nacm_datanode_write(cxobj *xt,
int match = 0;
char *action;
char *write_default = NULL;
cvec *nsc = NULL;
/* Create namespace context for with nacm namespace as default */
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
goto done;
if (xnacm == NULL)
goto permit;
/* 3. Check all the "group" entries to see if any of them contain a
@ -684,7 +713,7 @@ nacm_datanode_write(cxobj *xt,
if (username == NULL)
goto step9;
/* User's group */
if (xpath_vec(xnacm, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
goto done;
/* 4. If no groups are found, continue with step 9. */
if (glen == 0)
@ -693,19 +722,19 @@ nacm_datanode_write(cxobj *xt,
configuration. If a rule-list's "group" leaf-list does not
match any of the user's groups, proceed to the next rule-list
entry. */
if (xpath_vec(xnacm, "rule-list", &rlistvec, &rlistlen) < 0)
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
goto done;
for (i=0; i<rlistlen; i++){
rlist = rlistvec[i];
/* Loop through user's group to find match in this rule-list */
for (j=0; j<glen; j++){
gname = xml_find_body(gvec[j], "name");
if (xpath_first(rlist, ".[group='%s']", gname)!=NULL)
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL)
break; /* found */
}
if (j==glen) /* not found */
continue;
if (xpath_vec(rlist, "rule", &rvec, &rlen) < 0)
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
goto done;
/* 6. For each rule-list entry found, process all rules, in order,
until a rule that matches the requested access operation is
@ -765,6 +794,8 @@ nacm_datanode_write(cxobj *xt,
retval = 1;
done:
clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
if (nsc)
xml_nsctx_free(nsc);
if (gvec)
free(gvec);
if (rlistvec)
@ -811,8 +842,11 @@ nacm_access(char *mode,
cxobj *xnacm0 = NULL;
char *enabled;
cxobj *x;
cvec *nsc = NULL;
clicon_debug(1, "%s", __FUNCTION__);
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
goto done;
if (mode == NULL || strcmp(mode, "disabled") == 0)
goto permit;
/* 0. If nacm-mode is external, get NACM defintion from separet tree,
@ -828,7 +862,7 @@ nacm_access(char *mode,
* RFC8341 3.4 */
/* 1. If the "enable-nacm" leaf is set to "false", then the protocol
operation is permitted. */
if ((x = xpath_first(xnacm, "enable-nacm")) == NULL)
if ((x = xpath_first(xnacm, nsc, "enable-nacm")) == NULL)
goto permit;
enabled = xml_body(x);
if (strcmp(enabled, "true") != 0)
@ -840,6 +874,8 @@ nacm_access(char *mode,
retval = 0; /* not permitted yet. continue with next NACM step */
done:
if (nsc)
xml_nsctx_free(nsc);
if (retval != 0 && xnacm0)
xml_free(xnacm0);
clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval);
@ -882,7 +918,10 @@ nacm_access_pre(clicon_handle h,
cxobj *x;
cxobj *xnacm0 = NULL;
cxobj *xnacm = NULL;
cvec *nsc = NULL;
if ((nsc = xml_nsctx_init(NULL, NACM_NS)) == NULL)
goto done;
if ((mode = clicon_option_str(h, "CLICON_NACM_MODE")) != NULL){
if (strcmp(mode, "external")==0){
if ((x = clicon_nacm_ext(h)))
@ -890,7 +929,7 @@ nacm_access_pre(clicon_handle h,
goto done;
}
else if (strcmp(mode, "internal")==0){
if (xmldb_get(h, "running", "nacm", &xnacm0) < 0)
if (xmldb_get0(h, "running", nsc, "nacm", 1, &xnacm0, NULL) < 0)
goto done;
}
}
@ -898,7 +937,7 @@ nacm_access_pre(clicon_handle h,
if (xnacm0 == NULL)
goto permit;
/* If config does not exist then the operation is permitted(?) */
if ((xnacm = xpath_first(xnacm0, "nacm")) == NULL)
if ((xnacm = xpath_first(xnacm0, nsc, "nacm")) == NULL)
goto permit;
if (xml_rootchild_node(xnacm0, xnacm) < 0)
goto done;
@ -910,6 +949,8 @@ nacm_access_pre(clicon_handle h,
xnacm = NULL;
}
done:
if (nsc)
xml_nsctx_free(nsc);
if (xnacm0)
xml_free(xnacm0);
else if (xnacm)