* Netconf message-id attribute changed from optional to mandatory
* Made NETCONF message handling more strict according to RFC 6241 * Set `CLICON_NETCONF_MESSAGE_ID_OPTIONAL` to true to accept omission of message-id attribute * Fixed: [need make sure message-id exist in rpc validate #240](https://github.com/clicon/clixon/issues/240)
This commit is contained in:
parent
96c9296056
commit
85e2945ec9
22 changed files with 196 additions and 89 deletions
|
|
@ -170,9 +170,10 @@ clixon_client_lock(int sock,
|
|||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(msg, "<rpc xmlns=\"%s\">"
|
||||
cprintf(msg, "<rpc xmlns=\"%s\" %s>"
|
||||
"<%slock><target><%s/></target></%slock></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
NETCONF_MESSAGE_ID_ATTR,
|
||||
lock?"":"un", db, lock?"":"un");
|
||||
if (clicon_rpc1(sock, msg, msgret) < 0)
|
||||
goto done;
|
||||
|
|
@ -422,6 +423,7 @@ clixon_client_get_xdata(int sock,
|
|||
cprintf(msg, "<rpc xmlns=\"%s\"", NETCONF_BASE_NAMESPACE);
|
||||
cprintf(msg, " xmlns:%s=\"%s\"",
|
||||
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
||||
cprintf(msg, " %s", NETCONF_MESSAGE_ID_ATTR);
|
||||
cprintf(msg, "><get-config><source><%s/></source>", db);
|
||||
if (xpath && strlen(xpath)){
|
||||
cprintf(msg, "<%s:filter %s:type=\"xpath\" xmlns=\"%s\" %s:select=\"%s\"",
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@
|
|||
#include "clixon_xml.h"
|
||||
#include "clixon_options.h"
|
||||
#include "clixon_data.h"
|
||||
#include "clixon_xml_bind.h"
|
||||
#include "clixon_xml_map.h"
|
||||
#include "clixon_xml_io.h"
|
||||
#include "clixon_xpath_ctx.h"
|
||||
|
|
@ -228,44 +229,82 @@ netconf_too_big(cbuf *cb,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*! Create Netconf missing-attribute error XML tree according to RFC 6241 App A
|
||||
*
|
||||
* An expected attribute is missing.
|
||||
* @param[out] xret Error XML tree. Free with xml_free after use
|
||||
* @param[in] type Error type: "rpc", "application" or "protocol"
|
||||
* @param[in] attr bad-attribute and/or bad-element xml
|
||||
* @param[in] message Error message (will be XML encoded)
|
||||
*/
|
||||
int
|
||||
netconf_missing_attribute_xml(cxobj **xret,
|
||||
char *type,
|
||||
char *attr,
|
||||
char *message)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xerr = NULL;
|
||||
char *encstr = NULL;
|
||||
cxobj *xa;
|
||||
|
||||
if (*xret == NULL){
|
||||
if ((*xret = xml_new("rpc-reply", NULL, CX_ELMNT)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
else if (xml_name_set(*xret, "rpc-reply") < 0)
|
||||
goto done;
|
||||
if ((xa = xml_new("xmlns", *xret, CX_ATTR)) == NULL)
|
||||
goto done;
|
||||
if (xml_value_set(xa, NETCONF_BASE_NAMESPACE) < 0)
|
||||
goto done;
|
||||
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
|
||||
goto done;
|
||||
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>%s</error-type>"
|
||||
"<error-tag>missing-attribute</error-tag>"
|
||||
"<error-info><bad-attribute>%s</bad-attribute></error-info>"
|
||||
"<error-severity>error</error-severity>", type, attr) < 0)
|
||||
goto done;
|
||||
if (message){
|
||||
if (xml_chardata_encode(&encstr, "%s", message) < 0)
|
||||
goto done;
|
||||
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
|
||||
encstr) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (encstr)
|
||||
free(encstr);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Create Netconf missing-attribute error XML tree according to RFC 6241 App A
|
||||
*
|
||||
* An expected attribute is missing.
|
||||
* @param[out] cb CLIgen buf. Error XML is written in this buffer
|
||||
* @param[in] type Error type: "rpc", "application" or "protocol"
|
||||
* @param[in] info bad-attribute or bad-element xml
|
||||
* @param[in] message Error message (will be XML encoded)
|
||||
* @param[in] attr bad-attribute
|
||||
* @param[in] message Error message (will be XML encoded) or NULL
|
||||
*/
|
||||
int
|
||||
netconf_missing_attribute(cbuf *cb,
|
||||
char *type,
|
||||
char *info,
|
||||
char *attr,
|
||||
char *message)
|
||||
{
|
||||
int retval = -1;
|
||||
char *encstr = NULL;
|
||||
int retval = -1;
|
||||
cxobj *xret = NULL;
|
||||
|
||||
if (cprintf(cb, "<rpc-reply xmlns=\"%s\"><rpc-error>"
|
||||
"<error-type>%s</error-type>"
|
||||
"<error-tag>missing-attribute</error-tag>"
|
||||
"<error-info>%s</error-info>"
|
||||
"<error-severity>error</error-severity>",
|
||||
NETCONF_BASE_NAMESPACE, type, info) <0)
|
||||
goto err;
|
||||
if (message){
|
||||
if (xml_chardata_encode(&encstr, "%s", message) < 0)
|
||||
goto done;
|
||||
if (cprintf(cb, "<error-message>%s</error-message>", encstr) < 0)
|
||||
goto err;
|
||||
}
|
||||
if (cprintf(cb, "</rpc-error></rpc-reply>") <0)
|
||||
goto err;
|
||||
if (netconf_missing_attribute_xml(&xret, type, attr, message) < 0)
|
||||
goto done;
|
||||
if (clicon_xml2cbuf(cb, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
return retval;
|
||||
err:
|
||||
clicon_err(OE_XML, errno, "cprintf");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Create Netconf bad-attribute error XML tree according to RFC 6241 App A
|
||||
|
|
@ -1429,6 +1468,16 @@ netconf_module_load(clicon_handle h)
|
|||
/* Load restconf yang. Note this is also a part of clixon-config */
|
||||
if (yang_spec_parse_module(h, "clixon-restconf", NULL, yspec)< 0)
|
||||
goto done;
|
||||
#if 1
|
||||
/* XXX: Both the following settings are because clicon-handle is not part of all API
|
||||
* functions
|
||||
* Treat unknown XML as anydata */
|
||||
if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1)
|
||||
xml_bind_yang_unknown_anydata(1);
|
||||
/* Make message-id attribute optional */
|
||||
if (clicon_option_bool(h, "CLICON_NETCONF_MESSAGE_ID_OPTIONAL") == 1)
|
||||
xml_bind_netconf_message_id_optional(1);
|
||||
#endif
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -451,6 +451,7 @@ clicon_rpc_get_config(clicon_handle h,
|
|||
cprintf(cb, " username=\"%s\"", username);
|
||||
cprintf(cb, " xmlns:%s=\"%s\"",
|
||||
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
||||
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
|
||||
cprintf(cb, "><get-config><source><%s/></source>", db);
|
||||
if (xpath && strlen(xpath)){
|
||||
cprintf(cb, "<%s:filter %s:type=\"xpath\" %s:select=\"%s\"",
|
||||
|
|
@ -541,6 +542,7 @@ clicon_rpc_edit_config(clicon_handle h,
|
|||
cprintf(cb, " xmlns:%s=\"%s\"", NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
||||
if ((username = clicon_username_get(h)) != NULL)
|
||||
cprintf(cb, " username=\"%s\"", username);
|
||||
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
|
||||
cprintf(cb, "><edit-config><target><%s/></target>", db);
|
||||
cprintf(cb, "<default-operation>%s</default-operation>",
|
||||
xml_operation2str(op));
|
||||
|
|
@ -595,10 +597,11 @@ clicon_rpc_copy_config(clicon_handle h,
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(session_id,
|
||||
"<rpc xmlns=\"%s\" username=\"%s\">"
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
|
||||
"<copy-config><source><%s/></source><target><%s/></target></copy-config></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
username?username:"",
|
||||
NETCONF_MESSAGE_ID_ATTR,
|
||||
db1, db2)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||
|
|
@ -641,10 +644,12 @@ clicon_rpc_delete_config(clicon_handle h,
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(session_id,
|
||||
"<rpc xmlns=\"%s\" username=\"%s\">"
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
|
||||
"<edit-config><target><%s/></target><default-operation>none</default-operation><config operation=\"delete\"/></edit-config></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
username?username:"", db)) == NULL)
|
||||
username?username:"",
|
||||
NETCONF_MESSAGE_ID_ATTR,
|
||||
db)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||
goto done;
|
||||
|
|
@ -682,10 +687,12 @@ clicon_rpc_lock(clicon_handle h,
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(session_id,
|
||||
"<rpc xmlns=\"%s\" username=\"%s\">"
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
|
||||
"<lock><target><%s/></target></lock></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
username?username:"", db)) == NULL)
|
||||
username?username:"",
|
||||
NETCONF_MESSAGE_ID_ATTR,
|
||||
db)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||
goto done;
|
||||
|
|
@ -723,10 +730,12 @@ clicon_rpc_unlock(clicon_handle h,
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(session_id,
|
||||
"<rpc xmlns=\"%s\" username=\"%s\">"
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" %s>"
|
||||
"<unlock><target><%s/></target></unlock></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
username?username:"", db)) == NULL)
|
||||
username?username:"",
|
||||
NETCONF_MESSAGE_ID_ATTR,
|
||||
db)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||
goto done;
|
||||
|
|
@ -805,6 +814,7 @@ clicon_rpc_get(clicon_handle h,
|
|||
cprintf(cb, " username=\"%s\"", username);
|
||||
cprintf(cb, " xmlns:%s=\"%s\"",
|
||||
NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE);
|
||||
cprintf(cb, " %s", NETCONF_MESSAGE_ID_ATTR);
|
||||
cprintf(cb, "><get");
|
||||
/* Clixon extension, content=all,config, or nonconfig */
|
||||
if ((int)content != -1)
|
||||
|
|
@ -889,8 +899,9 @@ clicon_rpc_close_session(clicon_handle h)
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(session_id,
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" message-id=\"%u\"><close-session/></rpc>",
|
||||
NETCONF_BASE_NAMESPACE, username?username:"", 42)) == NULL)
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" %s><close-session/></rpc>",
|
||||
NETCONF_BASE_NAMESPACE, username?username:"",
|
||||
NETCONF_MESSAGE_ID_ATTR)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||
goto done;
|
||||
|
|
@ -932,9 +943,11 @@ clicon_rpc_kill_session(clicon_handle h,
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(my_session_id,
|
||||
"<rpc xmlns=\"%s\" username=\"%s\"><kill-session><session-id>%u</session-id></kill-session></rpc>",
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" %s><kill-session><session-id>%u</session-id></kill-session></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
username?username:"", session_id)) == NULL)
|
||||
username?username:"",
|
||||
NETCONF_MESSAGE_ID_ATTR,
|
||||
session_id)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||
goto done;
|
||||
|
|
@ -972,9 +985,11 @@ clicon_rpc_validate(clicon_handle h,
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(session_id,
|
||||
"<rpc xmlns=\"%s\" username=\"%s\"><validate><source><%s/></source></validate></rpc>",
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" %s><validate><source><%s/></source></validate></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
username?username:"", db)) == NULL)
|
||||
username?username:"",
|
||||
NETCONF_MESSAGE_ID_ATTR,
|
||||
db)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||
goto done;
|
||||
|
|
@ -1010,9 +1025,10 @@ clicon_rpc_commit(clicon_handle h)
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(session_id,
|
||||
"<rpc xmlns=\"%s\" username=\"%s\"><commit/></rpc>",
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" %s><commit/></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
username?username:"")) == NULL)
|
||||
username?username:"",
|
||||
NETCONF_MESSAGE_ID_ATTR)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||
goto done;
|
||||
|
|
@ -1048,9 +1064,10 @@ clicon_rpc_discard_changes(clicon_handle h)
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(session_id,
|
||||
"<rpc xmlns=\"%s\" username=\"%s\"><discard-changes/></rpc>",
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" %s><discard-changes/></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
username?username:"")) == NULL)
|
||||
username?username:"",
|
||||
NETCONF_MESSAGE_ID_ATTR)) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||
goto done;
|
||||
|
|
@ -1094,12 +1111,13 @@ clicon_rpc_create_subscription(clicon_handle h,
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(session_id,
|
||||
"<rpc xmlns=\"%s\" username=\"%s\"><create-subscription xmlns=\"%s\">"
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" %s><create-subscription xmlns=\"%s\">"
|
||||
"<stream>%s</stream>"
|
||||
"<filter type=\"xpath\" select=\"%s\" />"
|
||||
"</create-subscription></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
username?username:"",
|
||||
NETCONF_MESSAGE_ID_ATTR,
|
||||
EVENT_RFC5277_NAMESPACE,
|
||||
stream?stream:"", filter?filter:"")) == NULL)
|
||||
goto done;
|
||||
|
|
@ -1139,9 +1157,10 @@ clicon_rpc_debug(clicon_handle h,
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(session_id,
|
||||
"<rpc xmlns=\"%s\" username=\"%s\"><debug xmlns=\"%s\"><level>%d</level></debug></rpc>",
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" %s><debug xmlns=\"%s\"><level>%d</level></debug></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
username?username:"",
|
||||
NETCONF_MESSAGE_ID_ATTR,
|
||||
CLIXON_LIB_NS,
|
||||
level)) == NULL)
|
||||
goto done;
|
||||
|
|
@ -1189,9 +1208,10 @@ clicon_rpc_restconf_debug(clicon_handle h,
|
|||
goto done;
|
||||
username = clicon_username_get(h);
|
||||
if ((msg = clicon_msg_encode(session_id,
|
||||
"<rpc xmlns=\"%s\" username=\"%s\"><edit-config><target><candidate/></target><config><restconf xmlns=\"%s\"><debug>%d</debug></restconf></config></edit-config></rpc>",
|
||||
"<rpc xmlns=\"%s\" username=\"%s\" %s><edit-config><target><candidate/></target><config><restconf xmlns=\"%s\"><debug>%d</debug></restconf></config></edit-config></rpc>",
|
||||
NETCONF_BASE_NAMESPACE,
|
||||
username?username:"",
|
||||
NETCONF_MESSAGE_ID_ATTR,
|
||||
CLIXON_RESTCONF_NS,
|
||||
level)) == NULL)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@
|
|||
* Local variables
|
||||
*/
|
||||
static int _yang_unknown_anydata = 0;
|
||||
static int _netconf_message_id_optional = 0;
|
||||
|
||||
/*! Kludge to equate unknown XML with anydata
|
||||
* The problem with this is that its global and should be bound to a handle
|
||||
|
|
@ -94,6 +95,16 @@ xml_bind_yang_unknown_anydata(int val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Kludge to set message_id_optional
|
||||
* The problem with this is that its global and should be bound to a handle
|
||||
*/
|
||||
int
|
||||
xml_bind_netconf_message_id_optional(int val)
|
||||
{
|
||||
_netconf_message_id_optional = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! After yang binding, bodies of containers and lists are stripped from XML bodies
|
||||
* May apply to other nodes?
|
||||
*/
|
||||
|
|
@ -510,16 +521,16 @@ xml_bind_yang0(cxobj *xt,
|
|||
* @retval -1 Error
|
||||
* The
|
||||
* @code
|
||||
* if (xml_bind_yang_rpc(h, x, NULL) < 0)
|
||||
* if (xml_bind_yang_rpc(x, NULL) < 0)
|
||||
* err;
|
||||
* @endcode
|
||||
* @see xml_bind_yang For other generic cases
|
||||
* @see xml_bind_yang_rpc_reply
|
||||
*/
|
||||
int
|
||||
xml_bind_yang_rpc(cxobj *xrpc,
|
||||
yang_stmt *yspec,
|
||||
cxobj **xerr)
|
||||
xml_bind_yang_rpc(cxobj *xrpc,
|
||||
yang_stmt *yspec,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yrpc = NULL; /* yang node */
|
||||
|
|
@ -576,6 +587,17 @@ xml_bind_yang_rpc(cxobj *xrpc,
|
|||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if (_netconf_message_id_optional == 0){
|
||||
/* RFC 6241 4.1:
|
||||
* The <rpc> element has a mandatory attribute "message-id"
|
||||
*/
|
||||
if (xml_find_type(xrpc, NULL, "message-id", CX_ATTR) == NULL){
|
||||
if (xerr &&
|
||||
netconf_missing_attribute_xml(xerr, "rpc", "message-id", "Incoming rpc") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(xrpc, x, CX_ELMNT)) != NULL) {
|
||||
rpcname = xml_name(x);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue