Stricter incoming RPC sanity checking, error messages may have changed

This commit is contained in:
Olof hagsand 2020-04-07 20:54:24 +02:00
parent f9998c441c
commit ac5637a46a
30 changed files with 163 additions and 99 deletions

View file

@ -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)`

View file

@ -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 ((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){

View file

@ -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,

View file

@ -978,6 +978,7 @@ cli_notification_cb(int s,
cxobj *xe;
cxobj *x;
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) {

View file

@ -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;

View file

@ -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;

View file

@ -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");

View file

@ -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

View file

@ -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>

View file

@ -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.

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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 \

View file

@ -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)

View file

@ -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

View file

@ -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 */

View file

@ -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.

View file

@ -1321,8 +1321,8 @@ 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.
* @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)
@ -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
*/

View file

@ -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 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

View file

@ -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"

View file

@ -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

View file

@ -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;
goto fail;
}
if (yang_config(ys) != 0){

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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"}}}'

View file

@ -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

View file

@ -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)

View file

@ -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"}}} '