* NACM extension (RFC8341)
* NACM module support (RFC8341 A1+A2)
* Recovery user "_nacm_recovery" added.
* Example use is restconf PUT when NACM edit-config is permitted, then automatic commit and discard are permitted using recovery user.
* Example user changed adm1 to andy to comply with RFC8341 example
* Yang code upgrade (RFC7950)
* RPC method input parameters validated
* see https://github.com/clicon/clixon/issues/4
* Correct XML namespace handling
* XML multiple modules was based on "loose" semantics so that yang modules were found by iterating thorugh namespaces until a match was made. This did not adhere to proper [XML namespace handling](https://www.w3.org/TR/2009/REC-xml-names-20091208), and causes problems with overlapping names and false positives. Below see XML accepted (but wrong), and correct namespace declaration:
```
<rpc><my-own-method></rpc> # Wrong but accepted
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> # Correct
<my-own-method xmlns="http://example.net/me/my-own/1.0">
</rpc>
```
* To keep old loose semantics set config option CLICON_XML_NS_ITERATE (true by default)
* XML to JSON translator support for mapping xmlns attribute to module name prefix.
* Default namespace is still "urn:ietf:params:xml:ns:netconf:base:1.0"
* See https://github.com/clicon/clixon/issues/49
* Changed all make tags --> make TAGS
* Keyvalue datastore removed (it has been disabled since 3.3.3)
* debug rpc added in example application (should be in clixon-config).
This commit is contained in:
parent
e5c0b06cf9
commit
ae1af8da9e
63 changed files with 1852 additions and 3492 deletions
|
|
@ -95,6 +95,10 @@ process_incoming_packet(clicon_handle h,
|
|||
|
||||
clicon_debug(1, "RECV");
|
||||
clicon_debug(2, "%s: RCV: \"%s\"", __FUNCTION__, cbuf_get(cb));
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(LOG_ERR, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
yspec = clicon_dbspec_yang(h);
|
||||
if ((str0 = strdup(cbuf_get(cb))) == NULL){
|
||||
clicon_log(LOG_ERR, "%s: strdup: %s", __FUNCTION__, strerror(errno));
|
||||
|
|
@ -103,19 +107,25 @@ process_incoming_packet(clicon_handle h,
|
|||
str = str0;
|
||||
/* Parse incoming XML message */
|
||||
if (xml_parse_string(str, yspec, &xreq) < 0){
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
if (netconf_operation_failed(cbret, "rpc", "internal error")< 0)
|
||||
goto done;
|
||||
netconf_output(1, cbret, "rpc-error");
|
||||
}
|
||||
else
|
||||
clicon_log(LOG_ERR, "%s: cbuf_new", __FUNCTION__);
|
||||
free(str0);
|
||||
if (netconf_operation_failed(cbret, "rpc", "internal error")< 0)
|
||||
goto done;
|
||||
netconf_output(1, cbret, "rpc-error");
|
||||
goto done;
|
||||
}
|
||||
free(str0);
|
||||
if ((xrpc=xpath_first(xreq, "//rpc")) != NULL)
|
||||
if ((xrpc=xpath_first(xreq, "//rpc")) != NULL){
|
||||
int ret;
|
||||
isrpc++;
|
||||
if ((ret = xml_yang_validate_rpc(xrpc)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (netconf_operation_failed(cbret, "application", "Validation failed")< 0)
|
||||
goto done;
|
||||
netconf_output(1, cbret, "rpc-error");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (xpath_first(xreq, "//hello") != NULL)
|
||||
;
|
||||
|
|
@ -134,30 +144,27 @@ process_incoming_packet(clicon_handle h,
|
|||
else{ /* there is a return message in xret */
|
||||
cxobj *xa, *xa2;
|
||||
assert(xret);
|
||||
|
||||
if ((cbret = cbuf_new()) != NULL){
|
||||
if ((xc = xml_child_i(xret,0))!=NULL){
|
||||
xa=NULL;
|
||||
/* Copy message-id attribute from incoming to reply.
|
||||
* RFC 6241:
|
||||
* If additional attributes are present in an <rpc> element, a NETCONF
|
||||
* peer MUST return them unmodified in the <rpc-reply> element. This
|
||||
* includes any "xmlns" attributes.
|
||||
*/
|
||||
while ((xa = xml_child_each(xrpc, xa, CX_ATTR)) != NULL){
|
||||
if ((xa2 = xml_dup(xa)) ==NULL)
|
||||
goto done;
|
||||
if (xml_addsub(xc, xa2) < 0)
|
||||
goto done;
|
||||
}
|
||||
add_preamble(cbret);
|
||||
|
||||
clicon_xml2cbuf(cbret, xml_child_i(xret,0), 0, 0);
|
||||
add_postamble(cbret);
|
||||
if (netconf_output(1, cbret, "rpc-reply") < 0){
|
||||
cbuf_free(cbret);
|
||||
if ((xc = xml_child_i(xret,0))!=NULL){
|
||||
xa=NULL;
|
||||
/* Copy message-id attribute from incoming to reply.
|
||||
* RFC 6241:
|
||||
* If additional attributes are present in an <rpc> element, a NETCONF
|
||||
* peer MUST return them unmodified in the <rpc-reply> element. This
|
||||
* includes any "xmlns" attributes.
|
||||
*/
|
||||
while ((xa = xml_child_each(xrpc, xa, CX_ATTR)) != NULL){
|
||||
if ((xa2 = xml_dup(xa)) ==NULL)
|
||||
goto done;
|
||||
}
|
||||
if (xml_addsub(xc, xa2) < 0)
|
||||
goto done;
|
||||
}
|
||||
add_preamble(cbret);
|
||||
|
||||
clicon_xml2cbuf(cbret, xml_child_i(xret,0), 0, 0);
|
||||
add_postamble(cbret);
|
||||
if (netconf_output(1, cbret, "rpc-reply") < 0){
|
||||
cbuf_free(cbret);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -869,6 +869,7 @@ netconf_application_rpc(clicon_handle h,
|
|||
int retval = -1;
|
||||
yang_spec *yspec = NULL; /* application yspec */
|
||||
yang_stmt *yrpc = NULL;
|
||||
yang_stmt *ymod = NULL;
|
||||
yang_stmt *yinput;
|
||||
yang_stmt *youtput;
|
||||
cxobj *xoutput;
|
||||
|
|
@ -888,26 +889,33 @@ netconf_application_rpc(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
cbuf_reset(cb);
|
||||
if (xml_namespace(xn) == NULL){
|
||||
if (ys_module_by_xml(yspec, xn, &ymod) < 0)
|
||||
goto done;
|
||||
if (ymod == NULL){
|
||||
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-type>rpc</error-type>"
|
||||
"<error-severity>error</error-severity>"
|
||||
"<error-message>%s</error-message>"
|
||||
"<error-info>Not recognized</error-info>"
|
||||
"<error-info>Not recognized module</error-info>"
|
||||
"</rpc-error></rpc-reply>", xml_name(xn));
|
||||
goto ok;
|
||||
}
|
||||
cprintf(cb, "/%s:%s", xml_namespace(xn), xml_name(xn));
|
||||
/* Find yang rpc statement, return yang rpc statement if found */
|
||||
if (yang_abs_schema_nodeid(yspec, xml_spec(xn), cbuf_get(cb), Y_RPC, &yrpc) < 0)
|
||||
goto done;
|
||||
yrpc = yang_find((yang_node*)ymod, Y_RPC, xml_name(xn));
|
||||
if ((yrpc==NULL) && _CLICON_XML_NS_ITERATE){
|
||||
int i;
|
||||
for (i=0; i<yspec->yp_len; i++){
|
||||
ymod = yspec->yp_stmt[i];
|
||||
if ((yrpc = yang_find((yang_node*)ymod, Y_RPC, xml_name(xn))) != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Check if found */
|
||||
if (yrpc != NULL){
|
||||
/* 1. Check xn arguments with input statement. */
|
||||
if ((yinput = yang_find((yang_node*)yrpc, Y_INPUT, NULL)) != NULL){
|
||||
xml_spec_set(xn, yinput); /* needed for xml_spec_populate */
|
||||
if (xml_apply(xn, CX_ELMNT, xml_spec_populate, yinput) < 0)
|
||||
if (xml_apply(xn, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xn, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||
|
|
@ -933,7 +941,7 @@ netconf_application_rpc(clicon_handle h,
|
|||
if ((youtput = yang_find((yang_node*)yrpc, Y_OUTPUT, NULL)) != NULL){
|
||||
xoutput=xpath_first(*xret, "/");
|
||||
xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */
|
||||
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, youtput) < 0)
|
||||
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
if (xml_apply(xoutput, CX_ELMNT,
|
||||
(xml_applyfn_t*)xml_yang_validate_all, NULL) < 0)
|
||||
|
|
@ -954,7 +962,6 @@ netconf_application_rpc(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! The central netconf rpc dispatcher. Look at first tag and dispach to sub-functions.
|
||||
* Call plugin handler if tag not found. If not handled by any handler, return
|
||||
* error.
|
||||
|
|
@ -985,7 +992,6 @@ netconf_rpc_dispatch(clicon_handle h,
|
|||
if (xml_value_set(xa, username) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
xe = NULL;
|
||||
while ((xe = xml_child_each(xn, xe, CX_ELMNT)) != NULL) {
|
||||
if (strcmp(xml_name(xe), "get-config") == 0){
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue