Stricter incoming RPC sanity checking, error messages may have changed
This commit is contained in:
parent
f9998c441c
commit
ac5637a46a
30 changed files with 163 additions and 99 deletions
|
|
@ -24,12 +24,19 @@
|
|||
## 4.5.0
|
||||
Expected: May 2020
|
||||
|
||||
### API changes on existing protocol/config features (You may have have to change how you use Clixon)
|
||||
|
||||
* Stricter incoming RPC sanity checking, error messages may have changed.
|
||||
|
||||
### C-API changes on existing features (you may need to change your plugin C-code)
|
||||
|
||||
* CLI
|
||||
* `clicon_parse()`: Changed signature due to new cligen error and result handling:
|
||||
* Removed: `cli_nomatch()`
|
||||
|
||||
### Minor changes
|
||||
|
||||
|
||||
## 4.4.0
|
||||
5 April 2020
|
||||
|
||||
|
|
@ -115,8 +122,6 @@ features include optimized search functions and a repair callback.
|
|||
|
||||
### Minor changes
|
||||
|
||||
* Added a compile-time option `MOVE_TRANS_END` which changes the semantics of the transaction_end callback. Instead of being called after a transaction, it is called prior to the target database is installed. This is to ensure that the source and target databases are same as for other transaction callbacks.
|
||||
|
||||
* Moved hello example to [clixon-examples](https://github.com/clicon/clixon-examples)
|
||||
* Sanity check of mandatory key statement for Yang LISTs.
|
||||
* If fails, exit with error message, eg: `Yang error: Sanity check failed: LIST vsDataContainer lacks key statement which MUST be present (See RFC 7950 Sec 7.8.2)`
|
||||
|
|
|
|||
|
|
@ -1570,12 +1570,16 @@ from_client_msg(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
/* Decode msg from client -> xml top (ct) and session id */
|
||||
if (clicon_msg_decode(msg, yspec, &id, &xt) < 0){
|
||||
if (netconf_malformed_message(cbret, "XML parse error")< 0)
|
||||
if ((ret = clicon_msg_decode(msg, yspec, &id, &xt, &xret)) < 0){
|
||||
if (netconf_malformed_message(cbret, "XML parse error") < 0)
|
||||
goto done;
|
||||
goto reply;
|
||||
}
|
||||
if (ret == 0){
|
||||
if (clicon_xml2cbuf(cbret, xret, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
goto reply;
|
||||
}
|
||||
|
||||
if ((x = xpath_first(xt, NULL, "/rpc")) == NULL){
|
||||
if ((x = xpath_first(xt, NULL, "/hello")) != NULL){
|
||||
if ((ret = from_client_hello(h, x, ce, cbret)) <0)
|
||||
|
|
@ -1589,12 +1593,6 @@ from_client_msg(clicon_handle h,
|
|||
}
|
||||
}
|
||||
ce->ce_id = id;
|
||||
/* Populate incoming XML tree with yang -
|
||||
* should really have been dealt with by decode above
|
||||
* but it still is needed - test_cli debug test fails
|
||||
*/
|
||||
if (xml_bind_yang_rpc(x, yspec, NULL) < 0)
|
||||
goto done;
|
||||
if ((ret = xml_yang_validate_rpc(h, x, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
|
|
|
|||
|
|
@ -509,8 +509,6 @@ from_validate_common(clicon_handle h,
|
|||
* @retval -1 Error - or validation failed
|
||||
* @retval 0 Validation failed (with cbret set)
|
||||
* @retval 1 Validation OK
|
||||
* @note Need to differentiate between error and validation fail
|
||||
* (only done for validate_common)
|
||||
*/
|
||||
int
|
||||
candidate_commit(clicon_handle h,
|
||||
|
|
|
|||
|
|
@ -977,7 +977,8 @@ cli_notification_cb(int s,
|
|||
cxobj *xt = NULL;
|
||||
cxobj *xe;
|
||||
cxobj *x;
|
||||
enum format_enum format = (enum format_enum)arg;
|
||||
enum format_enum format = (enum format_enum)arg;
|
||||
int ret;
|
||||
|
||||
/* get msg (this is the reason this function is called) */
|
||||
if (clicon_msg_rcv(s, &reply, &eof) < 0)
|
||||
|
|
@ -989,8 +990,13 @@ cli_notification_cb(int s,
|
|||
event_unreg_fd(s, cli_notification_cb);
|
||||
goto done;
|
||||
}
|
||||
if (clicon_msg_decode(reply, NULL, NULL, &xt) < 0) /* XXX pass yang_spec */
|
||||
/* XXX pass yang_spec and use xerr*/
|
||||
if ((ret = clicon_msg_decode(reply, NULL, NULL, &xt, NULL)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* will not happen since no yspec ^*/
|
||||
clicon_err(OE_NETCONF, EFAULT, "Notification malformed");
|
||||
goto done;
|
||||
}
|
||||
if ((xe = xpath_first(xt, NULL, "//event")) != NULL){
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(xe, x, -1)) != NULL) {
|
||||
|
|
|
|||
|
|
@ -425,6 +425,8 @@ netconf_notification_cb(int s,
|
|||
clicon_handle h = (clicon_handle)arg;
|
||||
yang_stmt *yspec = NULL;
|
||||
cvec *nsc = NULL;
|
||||
int ret;
|
||||
cxobj *xerr = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
/* get msg (this is the reason this function is called) */
|
||||
|
|
@ -439,9 +441,12 @@ netconf_notification_cb(int s,
|
|||
goto done;
|
||||
}
|
||||
yspec = clicon_dbspec_yang(h);
|
||||
if (clicon_msg_decode(reply, yspec, NULL, &xt) < 0)
|
||||
if ((ret = clicon_msg_decode(reply, yspec, NULL, &xt, &xerr)) < 0)
|
||||
goto done;
|
||||
|
||||
if (ret == 0){ /* XXX use xerr */
|
||||
clicon_err(OE_NETCONF, EFAULT, "Notification malformed");
|
||||
goto done;
|
||||
}
|
||||
if ((nsc = xml_nsctx_init(NULL, NOTIFICATION_RFC5277_NAMESPACE)) == NULL)
|
||||
goto done;
|
||||
if ((xn = xpath_first(xt, nsc, "notification")) == NULL)
|
||||
|
|
@ -467,6 +472,8 @@ netconf_notification_cb(int s,
|
|||
xml_nsctx_free(nsc);
|
||||
if (xt != NULL)
|
||||
xml_free(xt);
|
||||
if (xerr != NULL)
|
||||
xml_free(xerr);
|
||||
if (reply)
|
||||
free(reply);
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -847,8 +847,17 @@ api_operations_post(clicon_handle h,
|
|||
clicon_log_xml(LOG_DEBUG, xtop, "%s 5. Translate input args:", __FUNCTION__);
|
||||
#endif
|
||||
/* 6. Validate outgoing RPC and fill in defaults */
|
||||
if (xml_bind_yang_rpc(xtop, yspec, NULL) < 0) /* */
|
||||
if ((ret = xml_bind_yang_rpc(xtop, yspec, &xret)) < 0) /* */
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if ((xe = xpath_first(xret, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto ok;
|
||||
}
|
||||
if (api_return_err(h, r, xe, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = xml_yang_validate_rpc(h, xtop, &xret)) < 0)
|
||||
goto done;
|
||||
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ restconf_stream_cb(int s,
|
|||
cxobj *xn; /* notification xml */
|
||||
cbuf *cb = NULL;
|
||||
int pretty = 0; /* XXX should be via arg */
|
||||
int ret;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
/* get msg (this is the reason this function is called) */
|
||||
|
|
@ -180,8 +181,12 @@ restconf_stream_cb(int s,
|
|||
clicon_exit_set();
|
||||
goto done;
|
||||
}
|
||||
if (clicon_msg_decode(reply, NULL, NULL, &xtop) < 0) /* XXX pass yang_spec */
|
||||
if ((ret = clicon_msg_decode(reply, NULL, NULL, &xtop, NULL)) < 0) /* XXX pass yang_spec */
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clicon_err(OE_XML, EFAULT, "Invalid notification");
|
||||
goto done;
|
||||
}
|
||||
/* create event */
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||
|
|
|
|||
|
|
@ -98,10 +98,3 @@
|
|||
*/
|
||||
#define STATE_ORDERED_BY_SYSTEM
|
||||
|
||||
/*! Separate list merge into two separate rounds,
|
||||
* First round search for duplicates where objects are saved, and a second round where
|
||||
* actual merge is done. If in same round, in extreme cases that later
|
||||
* searches are among earlier objects already added
|
||||
* clixon-4.4
|
||||
*/
|
||||
#define XML_MERGE_TWO_ROUNDS
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@
|
|||
#include <clixon/clixon_regex.h>
|
||||
#include <clixon/clixon_path.h>
|
||||
#include <clixon/clixon_xml_map.h>
|
||||
#include <clixon/clixon_xml_bind.h>
|
||||
#include <clixon/clixon_xml_io.h>
|
||||
#include <clixon/clixon_validate.h>
|
||||
#include <clixon/clixon_datastore.h>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
||||
Copyright (C) 2017-2019 Olof Hagsand
|
||||
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ struct clicon_msg *clicon_msg_encode(uint32_t id, char *format, ...) __attribute
|
|||
#else
|
||||
struct clicon_msg *clicon_msg_encode(uint32_t id, char *format, ...);
|
||||
#endif
|
||||
int clicon_msg_decode(struct clicon_msg *msg, yang_stmt *yspec, uint32_t *id, cxobj **xml);
|
||||
int clicon_msg_decode(struct clicon_msg *msg, yang_stmt *yspec, uint32_t *id, cxobj **xml, cxobj **xerr);
|
||||
|
||||
int clicon_connect_unix(clicon_handle h, char *sockpath);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
||||
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
||||
Copyright (C) 2017-2019 Olof Hagsand
|
||||
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
|
@ -102,6 +103,7 @@ int clicon_str2int(const map_str2int *mstab, char *str);
|
|||
int clicon_str2int_search(const map_str2int *mstab, char *str, int upper);
|
||||
int nodeid_split(char *nodeid, char **prefix, char **id);
|
||||
char *clixon_trim(char *str);
|
||||
char *clixon_trim2(char *str, char *trims);
|
||||
int clicon_strcmp(char *s1, char *s2);
|
||||
|
||||
#ifndef HAVE_STRNDUP
|
||||
|
|
|
|||
|
|
@ -120,10 +120,8 @@ enum yang_bind{
|
|||
YB_NONE=0, /* Dont do Yang binding */
|
||||
YB_MODULE, /* Search for matching yang binding among top-level symbols of Yang modules */
|
||||
YB_PARENT, /* Assume yang binding of existing parent and match its children by name */
|
||||
YB_RPC, /* Assume top-level xml is an netconf RPC message (or hello) */
|
||||
|
||||
#ifdef NYI
|
||||
YB_RPC, /* Assume top-level xml is an netconf RPC message */
|
||||
#endif
|
||||
};
|
||||
typedef enum yang_bind yang_bind;
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ INCLUDES = -I. @INCLUDES@ -I$(top_srcdir)/lib/clixon -I$(top_srcdir)/include -I$
|
|||
SRC = clixon_sig.c clixon_uid.c clixon_log.c clixon_err.c clixon_event.c \
|
||||
clixon_string.c clixon_regex.c clixon_handle.c clixon_file.c \
|
||||
clixon_xml.c clixon_xml_io.c clixon_xml_sort.c clixon_xml_map.c clixon_xml_vec.c \
|
||||
clixon_json.c \
|
||||
clixon_xml_bind.c clixon_json.c \
|
||||
clixon_yang.c clixon_yang_type.c clixon_yang_module.c clixon_yang_parse_lib.c \
|
||||
clixon_yang_cardinality.c clixon_xml_changelog.c clixon_xml_nsctx.c \
|
||||
clixon_path.c clixon_validate.c \
|
||||
|
|
|
|||
|
|
@ -362,6 +362,10 @@ text_modify(clicon_handle h,
|
|||
}
|
||||
}
|
||||
if (x1bstr){
|
||||
/* XXX: Do the type lookup here inline instead, there are more
|
||||
* cases where we check for types, eg where we now call clixon_trim2
|
||||
* AND in nacm path where we need proper namespace contexts.
|
||||
*/
|
||||
if (check_identityref(x1, x0, x0p, x1bstr, y0) < 0)
|
||||
goto done;
|
||||
if ((x0b = xml_body_get(x0)) != NULL){
|
||||
|
|
@ -496,7 +500,7 @@ text_modify(clicon_handle h,
|
|||
if (xml_copy(x1, x0) < 0)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
} /* anyxml, anydata */
|
||||
if (x0==NULL){
|
||||
if (op==OP_MERGE && !permit && xnacm){
|
||||
if ((ret = nacm_datanode_write(NULL, x1, NACM_CREATE, username, xnacm, cbret)) < 0)
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@
|
|||
* quoted-string = (DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)
|
||||
* positive-integer-value = (non-zero-digit DIGIT*)
|
||||
* identifier = (ALPHA | "_")(ALPHA | DIGIT | "_" | "-" | ".")*
|
||||
*
|
||||
* RFC 8341: All the same rules as an instance-identifier apply, except that predicates
|
||||
* for keys are optional. If a key predicate is missing, then the
|
||||
* node-instance-identifier represents all possible server instances for that key.
|
||||
*/
|
||||
|
||||
%start start
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@
|
|||
#include "clixon_yang_type.h"
|
||||
#include "clixon_yang_module.h"
|
||||
#include "clixon_xml_sort.h"
|
||||
#include "clixon_xml_bind.h"
|
||||
#include "clixon_xml_map.h"
|
||||
#include "clixon_xml_nsctx.h" /* namespace context */
|
||||
#include "clixon_netconf_lib.h"
|
||||
|
|
@ -1249,6 +1250,12 @@ _json_parse(char *str,
|
|||
break;
|
||||
case YB_NONE:
|
||||
break;
|
||||
case YB_RPC:
|
||||
if ((ret = xml_bind_yang_rpc(x, yspec, xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
failed++;
|
||||
break;
|
||||
}
|
||||
/* Now find leafs with identityrefs (+transitive) and translate
|
||||
* prefixes in values to XML namespaces */
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2020 Olof Hagsand
|
||||
Copyright (C) 2017-2019 Olof Hagsand
|
||||
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
|
|
@ -351,13 +352,13 @@ nacm_rule_datanode(cxobj *xt,
|
|||
|
||||
/* 6b) Either (1) the rule does not have a "rule-type" defined or
|
||||
(2) the "rule-type" is "data-node" and the "path" matches the
|
||||
requested data node, action node, or notification node. A
|
||||
path is considered to match if the requested node is the node
|
||||
specified by the path or is a descendant node of the path.*/
|
||||
requested data node, action node, or notification node. */
|
||||
if ((path = xml_find_body(xrule, "path")) == NULL){
|
||||
if (xml_find_body(xrule, "rpc-name") ||xml_find_body(xrule, "notification-name"))
|
||||
goto nomatch;
|
||||
}
|
||||
else
|
||||
path = clixon_trim2(path, " \t\n");
|
||||
access_operations = xml_find_body(xrule, "access-operations");
|
||||
switch (access){
|
||||
case NACM_READ:
|
||||
|
|
@ -387,10 +388,17 @@ nacm_rule_datanode(cxobj *xt,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
/* Here module is matched, now check for path if any NYI */
|
||||
/* Here module is matched, now check for path if any NYI
|
||||
* A path is considered to match if the requested node is the node
|
||||
* specified by the path or is a descendant node of the path */
|
||||
if (path){
|
||||
#if 0
|
||||
if ((ret = clixon_xml_find_instance_id(xt, yt, xvec, xlen, "%s", path)) == NULL)
|
||||
goto nomatch;
|
||||
#else
|
||||
if ((xpath = xpath_first(xt, nsc, "%s", path)) == NULL)
|
||||
goto nomatch;
|
||||
#endif
|
||||
/* The requested node xr is the node specified by the path or is a
|
||||
* descendant node of the path:
|
||||
* xmatch is one of xvec[] or an ancestor of the xvec[] nodes.
|
||||
|
|
|
|||
|
|
@ -1321,9 +1321,9 @@ api_path_resolve(clixon_path *cplist,
|
|||
* @retval -1 Error
|
||||
* @retval 0 Fail
|
||||
* @retval 1 OK
|
||||
* @note: The spec says: prefixes depend on the XML context in which the value occurs. However,
|
||||
* canonical prefixes/namespaces are used based on loaded yang modules.
|
||||
* This means that prefix=NULL is not allowed.
|
||||
* @note: The spec says: prefixes depend on the XML context in which the value occurs.
|
||||
* However, canonical prefixes/namespaces are used based on loaded yang modules.
|
||||
* This means that prefix=NULL is not allowed.
|
||||
* Reasons for fail (retval = 0) are:
|
||||
* - No prefix of identifier (keynames may omit prefix)
|
||||
* - Prefix does not correspond to existing module.
|
||||
|
|
@ -1564,7 +1564,8 @@ clixon_xml_find_api_path(cxobj *xt,
|
|||
|
||||
/*! Given (instance-id) path and XML tree, return matching xml node vector using stdarg
|
||||
*
|
||||
* Instance-identifier is a subset of XML XPaths and defined in Yang, used in NACM for example.
|
||||
* Instance-identifier is a subset of XML XPaths and defined in Yang, used in NACM for
|
||||
* example.
|
||||
* @param[in] xt Top xml-tree where to search
|
||||
* @param[in] yt Yang statement of top symbol (can be yang-spec if top-level)
|
||||
* @param[out] xvec Vector of xml-trees. Vector must be free():d after use
|
||||
|
|
@ -1588,6 +1589,7 @@ clixon_xml_find_api_path(cxobj *xt,
|
|||
* }
|
||||
* clixon_xvec_free(xvec);
|
||||
* @endcode
|
||||
* @note canonical namespace contexts are used, seexpath2canonical
|
||||
* @see clixon_xml_find_api_path for RESTCONF api-paths
|
||||
* @see RFC7950 Sec 9.13
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
#include <netinet/in.h>
|
||||
#include <sys/un.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
|
@ -170,15 +171,21 @@ clicon_msg_encode(uint32_t id,
|
|||
* @param[in] yspec Yang specification, (can be NULL)
|
||||
* @param[out] id Session id
|
||||
* @param[out] xml XML parse tree
|
||||
* @param[out] xerr Reason for failure (yang assignment not made) if retval =0
|
||||
* @retval 1 Parse OK and all yang assignment made
|
||||
* @retval 0 Parse OK but yang assigment not made (or only partial)
|
||||
* @retval -1 Error with clicon_err called. Includes parse error
|
||||
*/
|
||||
int
|
||||
clicon_msg_decode(struct clicon_msg *msg,
|
||||
yang_stmt *yspec,
|
||||
uint32_t *id,
|
||||
cxobj **xml)
|
||||
cxobj **xml,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
char *xmlstr;
|
||||
int retval = -1;
|
||||
char *xmlstr;
|
||||
int ret;
|
||||
|
||||
/* hdr */
|
||||
if (id)
|
||||
|
|
@ -186,11 +193,16 @@ clicon_msg_decode(struct clicon_msg *msg,
|
|||
/* body */
|
||||
xmlstr = msg->op_body;
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, xmlstr);
|
||||
if (clixon_xml_parse_string(xmlstr, yspec?YB_MODULE:YB_NONE, yspec, xml, NULL) < 0)
|
||||
if ((ret = clixon_xml_parse_string(xmlstr, yspec?YB_RPC:YB_NONE, yspec, xml, xerr)) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
if (ret == 0)
|
||||
goto fail;
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Open local connection using unix domain sockets
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@
|
|||
#include "clixon_stream.h"
|
||||
#include "clixon_err_string.h"
|
||||
#include "clixon_xml_nsctx.h"
|
||||
#include "clixon_xml_map.h"
|
||||
#include "clixon_xml_bind.h"
|
||||
#include "clixon_xml_sort.h"
|
||||
#include "clixon_xml_io.h"
|
||||
#include "clixon_netconf_lib.h"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
|
||||
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
||||
Copyright (C) 2017-2019 Olof Hagsand
|
||||
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
|
|
@ -692,6 +694,29 @@ clixon_trim(char *str)
|
|||
return s;
|
||||
}
|
||||
|
||||
/*! Trim blanks from front and end of a string, return new string
|
||||
* @param[in] str
|
||||
* @param[in] trims Characters to trim: a vector of characters
|
||||
* @retval s Pointer into existing str after trimming blanks
|
||||
*/
|
||||
char *
|
||||
clixon_trim2(char *str,
|
||||
char *trims)
|
||||
{
|
||||
char *s = str;
|
||||
int i;
|
||||
|
||||
while (strlen(s) && index(trims, s[0])) /* trim from front */
|
||||
s++;
|
||||
for (i=strlen(s)-1; i>=0; i--){ /* trim from rear */
|
||||
if (index(trims, s[i]))
|
||||
s[i] = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*! check string equals (NULL is equal)
|
||||
* @param[in] s1 String 1
|
||||
* @param[in] s2 String 2
|
||||
|
|
|
|||
|
|
@ -1090,14 +1090,10 @@ xml_yang_validate_all(clicon_handle h,
|
|||
cprintf(cb, "Failed to find YANG spec of XML node: %s", xml_name(xt));
|
||||
if ((xp = xml_parent(xt)) != NULL)
|
||||
cprintf(cb, " with parent: %s", xml_name(xp));
|
||||
if (namespace){
|
||||
if (namespace)
|
||||
cprintf(cb, " in namespace: %s", namespace);
|
||||
if (netconf_unknown_element_xml(xret, "application", xml_name(xt), cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
if (netconf_unknown_element_xml(xret, "application", xml_name(xt), cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
if (netconf_unknown_element_xml(xret, "application", xml_name(xt), cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if (yang_config(ys) != 0){
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@
|
|||
#include "clixon_log.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_options.h" /* xml_bind_yang */
|
||||
#include "clixon_options.h"
|
||||
#include "clixon_yang_module.h"
|
||||
#include "clixon_xml_map.h" /* xml_bind_yang */
|
||||
#include "clixon_xml_bind.h"
|
||||
#include "clixon_xml_vec.h"
|
||||
#include "clixon_xml_sort.h"
|
||||
#include "clixon_xml_nsctx.h"
|
||||
|
|
@ -455,7 +455,13 @@ _xml_parse(const char *str,
|
|||
if (ret == 0)
|
||||
failed++;
|
||||
break;
|
||||
}
|
||||
case YB_RPC:
|
||||
if ((ret = xml_bind_yang_rpc(x, yspec, xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
failed++;
|
||||
break;
|
||||
} /* switch */
|
||||
}
|
||||
if (failed)
|
||||
goto fail;
|
||||
|
|
@ -601,7 +607,7 @@ clixon_xml_parse_file(int fd,
|
|||
* @param[in] yb How to bind yang to XML top-level when parsing
|
||||
* @param[in] yspec Yang specification, or NULL
|
||||
* @param[in,out] xt Pointer to XML parse tree. If empty will be created.
|
||||
* @param[out] xerr Reason for failure (yang assignment not made)
|
||||
* @param[out] xerr Reason for failure (yang assignment not made) if retval = 0
|
||||
* @retval 1 Parse OK and all yang assignment made
|
||||
* @retval 0 Parse OK but yang assigment not made (or only partial)
|
||||
* @retval -1 Error with clicon_err called. Includes parse error
|
||||
|
|
|
|||
|
|
@ -1304,14 +1304,12 @@ xml_merge1(cxobj *x0, /* the target */
|
|||
char *x1bstr; /* mod body string */
|
||||
yang_stmt *yc; /* yang child */
|
||||
cbuf *cbr = NULL; /* Reason buffer */
|
||||
#ifdef XML_MERGE_TWO_ROUNDS
|
||||
int i;
|
||||
struct {
|
||||
cxobj *w_x0c;
|
||||
cxobj *w_x1c;
|
||||
yang_stmt *w_yc;
|
||||
} *second_wave = NULL;
|
||||
#endif
|
||||
|
||||
assert(x1 && xml_type(x1) == CX_ELMNT);
|
||||
assert(y0);
|
||||
|
|
@ -1347,13 +1345,11 @@ xml_merge1(cxobj *x0, /* the target */
|
|||
}
|
||||
if (assign_namespaces(x1, x0, x0p) < 0)
|
||||
goto done;
|
||||
#ifdef XML_MERGE_TWO_ROUNDS
|
||||
if ((second_wave = calloc(xml_child_nr(x1), sizeof(*second_wave))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "calloc");
|
||||
goto done;
|
||||
}
|
||||
i = 0;
|
||||
#endif
|
||||
/* Loop through children of the modification tree */
|
||||
x1c = NULL;
|
||||
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
|
||||
|
|
@ -1377,7 +1373,6 @@ xml_merge1(cxobj *x0, /* the target */
|
|||
x0c = NULL;
|
||||
if (yc && match_base_child(x0, x1c, yc, &x0c) < 0)
|
||||
goto done;
|
||||
#ifdef XML_MERGE_TWO_ROUNDS
|
||||
/* Save x0c, x1c, yc and merge in second wave, so that x1c entries "interfer"
|
||||
* with itself, ie that later searches are among earlier objects already added
|
||||
* to x0 */
|
||||
|
|
@ -1385,14 +1380,7 @@ xml_merge1(cxobj *x0, /* the target */
|
|||
second_wave[i].w_x1c = x1c;
|
||||
second_wave[i].w_yc = yc;
|
||||
i++;
|
||||
#else
|
||||
if (xml_merge1(x0c, yc, x0, x1c, reason) < 0)
|
||||
goto done;
|
||||
if (*reason != NULL)
|
||||
goto ok;
|
||||
#endif
|
||||
} /* while */
|
||||
#ifdef XML_MERGE_TWO_ROUNDS
|
||||
/* Second run where actual merging is done
|
||||
* Loop through children of the modification tree */
|
||||
x1c = NULL;
|
||||
|
|
@ -1408,7 +1396,6 @@ xml_merge1(cxobj *x0, /* the target */
|
|||
goto ok;
|
||||
i++;
|
||||
}
|
||||
#endif
|
||||
if (xml_parent(x0) == NULL &&
|
||||
xml_insert(x0p, x0, INS_LAST, NULL, NULL) < 0)
|
||||
goto done;
|
||||
|
|
@ -1416,10 +1403,8 @@ xml_merge1(cxobj *x0, /* the target */
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
#ifdef XML_MERGE_TWO_ROUNDS
|
||||
if (second_wave)
|
||||
free(second_wave);
|
||||
#endif
|
||||
if (cbr)
|
||||
cbuf_free(cbr);
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -660,7 +660,8 @@ cv_validate1(clicon_handle h,
|
|||
if (strcmp(restype, "enumeration") == 0){
|
||||
found = 0;
|
||||
yi = NULL;
|
||||
if (str != NULL)
|
||||
if (str != NULL) {
|
||||
str = clixon_trim2(str, " \t\n"); /* May be misplaced, strip earlier? */
|
||||
while ((yi = yn_each(yrestype, yi)) != NULL){
|
||||
if (yang_keyword_get(yi) != Y_ENUM)
|
||||
continue;
|
||||
|
|
@ -669,6 +670,7 @@ cv_validate1(clicon_handle h,
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found){
|
||||
if (reason)
|
||||
*reason = cligen_reason("'%s' does not match enumeration", str);
|
||||
|
|
@ -680,7 +682,7 @@ cv_validate1(clicon_handle h,
|
|||
* of the names of the bits that are set. A zero-length string thus
|
||||
* represents a value where no bits are set.
|
||||
*/
|
||||
|
||||
str = clixon_trim2(str, " \t\n"); /* May be misplaced, strip earlier? */
|
||||
nvec = 0;
|
||||
if ((vec = clicon_strsep(str, " \t", &nvec)) == NULL)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ expectpart "$(curl -s -i -X DELETE http://localhost/restconf/data/example:crypt
|
|||
|
||||
# 2. set identity in other module with restconf , read it with restconf and netconf
|
||||
new "restconf add POST instead of PUT (should fail)"
|
||||
expectpart "$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/example:crypto -d '{"example:crypto":"example-des:des3"}')" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Missing matching yang node"}}}'
|
||||
expectpart "$(curl -s -i -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/example:crypto -d '{"example:crypto":"example-des:des3"}')" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: crypto with parent: crypto in namespace: urn:example:my-crypto"}}}'
|
||||
|
||||
# Alternative error:
|
||||
#'{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Leaf contains sub-element"}}}'
|
||||
|
|
|
|||
|
|
@ -6,17 +6,6 @@
|
|||
# @see test_nacm.sh is slightly modified - this follows the RFC more closely
|
||||
# See RFC 8341 A.1 and A.2
|
||||
# Note: use clixon-example instead of ietf-netconf-monitoring since the latter is
|
||||
# Tests for
|
||||
# deny-ncm: This rule prevents the "guest" group from reading any
|
||||
# monitoring information in the "clixon-example" YANG
|
||||
# module.
|
||||
# permit-ncm: This rule allows the "limited" group to read the
|
||||
# "clixon-example" YANG module.
|
||||
# permit-exec: This rule allows the "limited" group to invoke any
|
||||
# protocol operation supported by the server.
|
||||
# permit-all: This rule allows the "admin" group complete access to
|
||||
# all content in the server. No subsequent rule will match for the
|
||||
# "admin" group because of this module rule
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
|
|
|||
|
|
@ -123,9 +123,10 @@ new "restconf empty rpc, default media type should fail (JSON)"
|
|||
expectpart "$(curl -si -X POST -H "Accept: application/yang-data+json" -d {\"clixon-example:input\":null} http://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 415 Unsupported Media Type'
|
||||
|
||||
new "restconf empty rpc with extra args (should fail)"
|
||||
expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-example:input\":{\"extra\":null}} http://localhost/restconf/operations/clixon-example:empty)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"extra"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: extra with parent: empty in namespace: urn:example:clixon"}}}
'
|
||||
expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-example:input\":{\"extra\":null}} http://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"extra"},"error-severity":"error","error-message":"Unrecognized parameter: extra in rpc: empty"}}}'
|
||||
|
||||
new "restconf debug rpc"
|
||||
# Irritiating to get debugs on the terminal
|
||||
#new "restconf debug rpc"
|
||||
#expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-lib:input\":{\"level\":0}} http://localhost/restconf/operations/clixon-lib:debug)" 0 "HTTP/1.1 204 No Content"
|
||||
|
||||
new "restconf get empty config + state json"
|
||||
|
|
@ -243,19 +244,19 @@ expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"
|
|||
'
|
||||
|
||||
new "restconf rpc using POST json wrong"
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"wrongelement"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: wrongelement with parent: example in namespace: urn:example:clixon"}}}
'
|
||||
expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"wrongelement":"ipv4"}}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"wrongelement"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: wrongelement with parent: example in namespace: urn:example:clixon"}}}'
|
||||
|
||||
new "restconf rpc non-existing rpc without namespace"
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/kalle)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}}
'
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/kalle)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}'
|
||||
|
||||
new "restconf rpc non-existing rpc"
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/clixon-example:kalle)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}}
'
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/clixon-example:kalle)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"kalle"},"error-severity":"error","error-message":"RPC not defined"}}'
|
||||
|
||||
new "restconf rpc missing name"
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"Operation name expected"}}}
'
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations)" 0 'HTTP/1.1 412 Precondition Failed' '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"Operation name expected"}}}'
|
||||
|
||||
new "restconf rpc missing input"
|
||||
expecteq "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/clixon-example:example)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"restconf RPC does not have input statement"}}}
'
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"restconf RPC does not have input statement"}}}'
|
||||
|
||||
new "restconf rpc using POST xml"
|
||||
ret=$(curl -s -X POST -H "Content-Type: application/yang-data+json" -H "Accept: application/yang-data+xml" -d '{"clixon-example:input":{"x":42}}' http://localhost/restconf/operations/clixon-example:example)
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ if [ -z "$match" ]; then
|
|||
fi
|
||||
|
||||
new "restconf empty rpc with input x"
|
||||
expectpart "$(curl -iss -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":0}}' http://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"x"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: x with parent: empty in namespace: urn:example:clixon"}}}
'
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":0}}' http://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"x"},"error-severity":"error","error-message":"Unrecognized parameter: x in rpc: empty"}}}'
|
||||
|
||||
# cornercase: optional has yang input/output sections but test without body
|
||||
new "restconf optional rpc with null input and output"
|
||||
|
|
@ -129,7 +129,7 @@ new "restconf omit mandatory"
|
|||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":null}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"x"},"error-severity":"error","error-message":"Mandatory variable"}}}
'
|
||||
|
||||
new "restconf add extra"
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0","extra":"0"}}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"extra"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: extra with parent: example in namespace: urn:example:clixon"}}}
'
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0","extra":"0"}}' http://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"bad-element","error-info":{"bad-element":"extra"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: extra with parent: example in namespace: urn:example:clixon"}}}'
|
||||
|
||||
new "restconf wrong method"
|
||||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0"}}' http://localhost/restconf/operations/clixon-example:wrong)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"wrong"},"error-severity":"error","error-message":"RPC not defined"}}}
'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue