Fixed issue https://github.com/clicon/clixon/issues/17 special character in strings can break RPCs

This commit is contained in:
Olof hagsand 2018-04-21 16:32:46 +02:00
parent 7650803475
commit 67c0abead7
15 changed files with 405 additions and 136 deletions

View file

@ -103,6 +103,7 @@ enables saved files to be used as datastore without any editing. Thanks Matt.
* Added cli_show_version()
### Corrected Bugs
* Fixed issue https://github.com/clicon/clixon/issues/17 special character in strings can break RPCs
* Fixed three-key list entry problem (reported by jdl@netgate)
* Translate xml->json \n correctly
* Fix issue: https://github.com/clicon/clixon/issues/15 Replace whole config

View file

@ -1083,12 +1083,12 @@ from_client_msg(clicon_handle h,
goto done;
}
if (clicon_msg_decode(msg, &xt) < 0){
if (netconf_malformed_message(cbret, "Not recognized, rpc expected")< 0)
if (netconf_malformed_message(cbret, "XML parse error")< 0)
goto done;
goto reply;
}
if ((x = xpath_first(xt, "/rpc")) == NULL){
if (netconf_malformed_message(cbret, "Not recognized, rpc expected")< 0)
if (netconf_malformed_message(cbret, "rpc keyword expected")< 0)
goto done;
goto reply;
}
@ -1187,6 +1187,8 @@ from_client_msg(clicon_handle h,
if (netconf_operation_failed(cbret, "application", clicon_err_reason)< 0)
goto done;
clicon_debug(1, "%s cbret:%s", __FUNCTION__, cbuf_get(cbret));
/* XXX problem here is that cbret has not been parsed so may contain
parse errors */
if (send_msg_reply(ce->ce_s, cbuf_get(cbret), cbuf_len(cbret)+1) < 0){
switch (errno){
case EPIPE:

View file

@ -516,12 +516,12 @@ cli_show_config(clicon_handle h,
xml2txt(stdout, xc, 0); /* tree-formed text */
break;
case FORMAT_CLI:
xc = NULL; /* Dont print xt itself */
while ((xc = xml_child_each(xt, xc, -1)) != NULL){
/* get CLI generatade mode: VARS|ALL */
if ((gt = clicon_cli_genmodel_type(h)) == GT_ERR)
goto done;
xc = NULL; /* Dont print xt itself */
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
xml2cli(stdout, xc, NULL, gt); /* cli syntax */
}
break;
case FORMAT_NETCONF:
fprintf(stdout, "<rpc><edit-config><target><candidate/></target><config>\n");

View file

@ -211,7 +211,7 @@ append_listkeys(cbuf *ckey,
xml_name(xt), keyname);
goto done;
}
if (percent_encode(xml_body(xkey), &bodyenc) < 0)
if (uri_percent_encode(xml_body(xkey), &bodyenc) < 0)
goto done;
if (i++)
cprintf(ckey, ",");
@ -328,7 +328,7 @@ get(char *dbname,
* If xml element is a leaf-list, then the next element is expected to
* be a value
*/
if (percent_decode(restval, &argdec) < 0)
if (uri_percent_decode(restval, &argdec) < 0)
goto done;
if ((xc = xml_find(x, name))==NULL ||
(xb = xml_find(xc, argdec))==NULL){
@ -373,7 +373,7 @@ get(char *dbname,
if (j>=nvalvec)
break;
arg = valvec[j++];
if (percent_decode(arg, &argdec) < 0)
if (uri_percent_decode(arg, &argdec) < 0)
goto done;
cprintf(cb, "[%s=%s]", cv_string_get(cvi), argdec);
free(argdec);
@ -391,7 +391,7 @@ get(char *dbname,
break;
arg = valvec[j++];
keyname = cv_string_get(cvi);
if (percent_decode(arg, &argdec) < 0)
if (uri_percent_decode(arg, &argdec) < 0)
goto done;
if (create_keyvalues(xc,
ykey,
@ -681,7 +681,7 @@ put(char *dbfile,
goto done;
break;
case Y_LEAF_LIST:
if (percent_encode(body, &bodyenc) < 0)
if (uri_percent_encode(body, &bodyenc) < 0)
goto done;
cprintf(cbxk, "=%s", bodyenc);
break;

View file

@ -74,8 +74,9 @@ static inline char * strdup4(char *str)
char **clicon_strsep(char *string, char *delim, int *nvec0);
char *clicon_strjoin (int argc, char **argv, char *delim);
int str2cvec(char *string, char delim1, char delim2, cvec **cvp);
int percent_encode(char *str, char **escp);
int percent_decode(char *esc, char **str);
int uri_percent_encode(char *str, char **escp);
int uri_percent_decode(char *esc, char **str);
int xml_chardata_encode(char *str, char **escp);
const char *clicon_int2str(const map_str2int *mstab, int i);
int clicon_str2int(const map_str2int *mstab, char *str);

View file

@ -54,6 +54,7 @@
/* clixon */
#include "clixon_queue.h"
#include "clixon_hash.h"
#include "clixon_string.h"
#include "clixon_err.h"
#include "clixon_handle.h"
#include "clixon_yang.h"
@ -74,6 +75,7 @@ netconf_in_use(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>in-use</error-tag>"
@ -81,12 +83,18 @@ netconf_in_use(cbuf *cb,
"<error-severity>error</error-severity>",
type) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -106,6 +114,7 @@ netconf_invalid_value(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>invalid-value</error-tag>"
@ -113,12 +122,18 @@ netconf_invalid_value(cbuf *cb,
"<error-severity>error</error-severity>",
type) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -139,6 +154,7 @@ netconf_too_big(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>too-big</error-tag>"
@ -146,12 +162,18 @@ netconf_too_big(cbuf *cb,
"<error-severity>error</error-severity>",
type) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -173,6 +195,7 @@ netconf_missing_attribute(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>missing-attribute</error-tag>"
@ -181,8 +204,12 @@ netconf_missing_attribute(cbuf *cb,
"<error-severity>error</error-severity>",
type, info) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
@ -209,6 +236,7 @@ netconf_bad_attribute(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>bad-attribute</error-tag>"
@ -217,12 +245,18 @@ netconf_bad_attribute(cbuf *cb,
"<error-severity>error</error-severity>",
type, info) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -244,6 +278,7 @@ netconf_unknown_attribute(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>unknown-attribute</error-tag>"
@ -252,19 +287,24 @@ netconf_unknown_attribute(cbuf *cb,
"<error-severity>error</error-severity>",
type, info) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
goto done;
}
/*! Create Netconf missing-element error XML tree according to RFC 6241 App A
*
* An expected element is missing.
@ -280,6 +320,7 @@ netconf_missing_element(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>missing-element</error-tag>"
@ -288,12 +329,18 @@ netconf_missing_element(cbuf *cb,
"<error-severity>error</error-severity>",
type, info) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -316,6 +363,7 @@ netconf_bad_element(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>bad-element</error-tag>"
@ -324,12 +372,18 @@ netconf_bad_element(cbuf *cb,
"<error-severity>error</error-severity>",
type, info) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -351,7 +405,7 @@ netconf_unknown_element(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>unknown-element</error-tag>"
@ -360,12 +414,18 @@ netconf_unknown_element(cbuf *cb,
"<error-severity>error</error-severity>",
type, info) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -387,6 +447,7 @@ netconf_unknown_namespace(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>unknown-namespace</error-tag>"
@ -395,12 +456,18 @@ netconf_unknown_namespace(cbuf *cb,
"<error-severity>error</error-severity>",
type, info) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -420,6 +487,7 @@ netconf_access_denied(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>access-denied</error-tag>"
@ -427,12 +495,18 @@ netconf_access_denied(cbuf *cb,
"<error-severity>error</error-severity>",
type) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -485,6 +559,7 @@ netconf_lock_denied(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>lock-denied</error-tag>"
@ -493,12 +568,18 @@ netconf_lock_denied(cbuf *cb,
"<error-severity>error</error-severity>",
info) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -518,6 +599,7 @@ netconf_resource_denied(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>resource-denied</error-tag>"
@ -525,12 +607,18 @@ netconf_resource_denied(cbuf *cb,
"<error-severity>error</error-severity>",
type) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -551,6 +639,7 @@ netconf_rollback_failed(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>rollback-failed</error-tag>"
@ -558,12 +647,18 @@ netconf_rollback_failed(cbuf *cb,
"<error-severity>error</error-severity>",
type) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -583,18 +678,25 @@ netconf_data_exists(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>data-exists</error-tag>"
"<error-type>application</error-type>"
"<error-severity>error</error-severity>") <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -614,18 +716,25 @@ netconf_data_missing(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>data-missing</error-tag>"
"<error-type>application</error-type>"
"<error-severity>error</error-severity>") <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -646,6 +755,7 @@ netconf_operation_not_supported(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>operation-not-supported</error-tag>"
@ -653,12 +763,18 @@ netconf_operation_not_supported(cbuf *cb,
"<error-severity>error</error-severity>",
type) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -679,6 +795,7 @@ netconf_operation_failed(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>operation-failed</error-tag>"
@ -686,12 +803,18 @@ netconf_operation_failed(cbuf *cb,
"<error-severity>error</error-severity>",
type) <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");
@ -745,18 +868,25 @@ netconf_malformed_message(cbuf *cb,
char *message)
{
int retval = -1;
char *encstr = NULL;
if (cprintf(cb, "<rpc-reply><rpc-error>"
"<error-tag>malformed-message</error-tag>"
"<error-type>rpc</error-type>"
"<error-severity>error</error-severity>") <0)
goto err;
if (message && cprintf(cb, "<error-message>%s</error-message>", message) < 0)
if (message){
if (xml_chardata_encode(message, &encstr) < 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;
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
err:
clicon_err(OE_XML, errno, "cprintf");

View file

@ -140,7 +140,7 @@ clicon_strjoin(int argc,
}
static int
unreserved(unsigned char in)
uri_unreserved(unsigned char in)
{
switch(in) {
case '0': case '1': case '2': case '3': case '4':
@ -163,11 +163,17 @@ unreserved(unsigned char in)
return 0;
}
/*! Percent encoding according to RFC 3896
* @param[out] esc Deallocate with free()
/*! Percent encoding according to RFC 3986 URI Syntax
* @param[in] str Not-encoded input string
* @param[out] escp Encoded/escaped malloced output string
* @retval 0 OK
* @retval -1 Error
* @see RFC 3986 Uniform Resource Identifier (URI): Generic Syntax
* @see uri_percent_decode
* @see xml_chardata_encode
*/
int
percent_encode(char *str,
uri_percent_encode(char *str,
char **escp)
{
int retval = -1;
@ -184,7 +190,7 @@ percent_encode(char *str,
memset(esc, 0, len);
j = 0;
for (i=0; i<strlen(str); i++){
if (unreserved(str[i]))
if (uri_unreserved(str[i]))
esc[j++] = str[i];
else{
snprintf(&esc[j], 4, "%%%02X", str[i]&0xff);
@ -199,11 +205,16 @@ percent_encode(char *str,
return retval;
}
/*! Percent decoding according to RFC 3896
* @param[out] str Deallocate with free()
/*! Percent decoding according to RFC 3986 URI Syntax
* @param[in] esc Escaped/encoded input string
* @param[out] strp Decoded malloced output string. Deallocate with free()
* @retval 0 OK
* @retval -1 Error
* @see RFC 3986 Uniform Resource Identifier (URI): Generic Syntax
* @see uri_percent_encode
*/
int
percent_decode(char *esc,
uri_percent_decode(char *esc,
char **strp)
{
int retval = -1;
@ -243,6 +254,98 @@ percent_decode(char *esc,
return retval;
}
/*! Escape characters according to XML definition
* @param[in] str Not-encoded input string
* @param[out] escp Encoded/escaped malloced output string
* @retval 0 OK
* @retval -1 Error
* @see https://www.w3.org/TR/2008/REC-xml-20081126/#syntax chapter 2.6
* @see uri_percent_encode
* @see AMPERSAND mode in clixon_xml_parse.l
* @code
* char *encstr = NULL;
* char *val = "a<>b";
* if (xml_chardata_encode(str, &encstr) < 0)
* err;
* if (encstr)
* free(encstr);
* @endcode
* Essentially encode as follows:
* & -> "&amp; " must
* < -> "&lt; " must
* > -> "&gt; " must for backward compatibility
* ' -> "&apos; " may
* ' -> "&quot; " may
* Optionally >
*/
int
xml_chardata_encode(char *str,
char **escp)
{
int retval = -1;
char *esc = NULL;
int l;
int len;
int i, j;
len = 0;
for (i=0; i<strlen(str); i++){
switch (str[i]){
case '&':
len += strlen("&amp; ");
break;
case '<':
len += strlen("&lt; ");
break;
case '>':
len += strlen("&gt; ");
break;
default:
len++;
}
}
len++; /* trailing \0 */
if ((esc = malloc(len)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
memset(esc, 0, len);
j = 0;
for (i=0; i<strlen(str); i++){
switch (str[i]){
case '&':
if ((l=snprintf(&esc[j], 7, "&amp; ")) < 0){
clicon_err(OE_UNIX, errno, "snprintf");
goto done;
}
j += l;
break;
case '<':
if ((l=snprintf(&esc[j], 6, "&lt; ")) < 0){
clicon_err(OE_UNIX, errno, "snprintf");
goto done;
}
j += l;
break;
case '>':
if ((l=snprintf(&esc[j], 6, "&gt; ")) < 0){
clicon_err(OE_UNIX, errno, "snprintf");
goto done;
}
j += l;
break;
default:
esc[j++] = str[i];
}
}
*escp = esc;
retval = 0;
done:
if (retval < 0 && esc)
free(esc);
return retval;
}
/*! Split a string into a cligen variable vector using 1st and 2nd delimiter
* Split a string first into elements delimited by delim1, then into
* pairs delimited by delim2.
@ -295,7 +398,7 @@ str2cvec(char *string,
*(snext++) = '\0';
if ((val = index(s, delim2)) != NULL){
*(val++) = '\0';
if (percent_decode(val, &valu) < 0)
if (uri_percent_decode(val, &valu) < 0)
goto err;
if ((cv = cvec_add(cvv, CGV_STRING)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_add");

View file

@ -950,7 +950,7 @@ xml_free(cxobj *x)
* XML printing functions. Output a parse tree to file, string cligen buf
*------------------------------------------------------------------------*/
/*! Print an XML tree structure to an output stream
/*! Print an XML tree structure to an output stream and encode chars "<>&"
*
* Uses clicon_xml2cbuf internally
*
@ -975,13 +975,17 @@ clicon_xml2file(FILE *f,
int hasbody;
int haselement;
char *val;
char *encstr = NULL; /* xml encoded string */
name = xml_name(x);
namespace = xml_namespace(x);
switch(xml_type(x)){
case CX_BODY:
if ((val = xml_value(x)) != NULL) /* incomplete tree */
fprintf(f, "%s", xml_value(x));
if ((val = xml_value(x)) == NULL) /* incomplete tree */
break;
if (xml_chardata_encode(val, &encstr) < 0)
goto done;
fprintf(f, "%s", encstr);
break;
case CX_ATTR:
fprintf(f, " ");
@ -1044,6 +1048,8 @@ clicon_xml2file(FILE *f,
}/* switch */
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
}
@ -1063,8 +1069,7 @@ xml_print(FILE *f,
return clicon_xml2file(f, xn, 0, 1);
}
/*! Print an XML tree structure to a cligen buffer
/*! Print an XML tree structure to a cligen buffer and encode chars "<>&"
*
* @param[in,out] cb Cligen buffer to write to
* @param[in] xn Clicon xml tree
@ -1093,12 +1098,18 @@ clicon_xml2cbuf(cbuf *cb,
int hasbody;
int haselement;
char *namespace;
char *encstr = NULL; /* xml encoded string */
char *val;
name = xml_name(x);
namespace = xml_namespace(x);
switch(xml_type(x)){
case CX_BODY:
cprintf(cb, "%s", xml_value(x));
if ((val = xml_value(x)) == NULL) /* incomplete tree */
break;
if (xml_chardata_encode(val, &encstr) < 0)
goto done;
cprintf(cb, "%s", encstr);
break;
case CX_ATTR:
cprintf(cb, " ");
@ -1130,7 +1141,6 @@ clicon_xml2cbuf(cbuf *cb,
default:
break;
}
/* Check for special case <a/> instead of <a></a> */
if (hasbody==0 && haselement==0)
cprintf(cb, "/>");
@ -1158,6 +1168,8 @@ clicon_xml2cbuf(cbuf *cb,
}/* switch */
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
}
/*! Print actual xml tree datastructures (not xml), mainly for debugging

View file

@ -189,7 +189,9 @@ xml2cli(FILE *f,
int nr;
int i;
cbuf *cbpre;
// yang_stmt *ys;
// ys = yang_spec(x);
/* Create prepend variable string */
if ((cbpre = cbuf_new()) == NULL){
clicon_err(OE_PLUGIN, errno, "cbuf_new");
@ -212,7 +214,7 @@ xml2cli(FILE *f,
}
if (prepend0)
cprintf(cbpre, "%s", prepend0);
/* bool determines when to print a variable keyword:
/* bool determines when to print a variable keyword:
!leaf T for all (ie parameter)
index GT_NONE F
index GT_VARS F
@ -269,7 +271,6 @@ validate_leafref(cxobj *xt,
char *leafrefbody;
char *leafbody;
if ((leafrefbody = xml_body(xt)) == NULL)
return 0;
if ((ypath = yang_find((yang_node*)ytype, Y_PATH, NULL)) == NULL){
@ -901,7 +902,7 @@ api_path_fmt2api_path(char *api_path_fmt,
clicon_err(OE_UNIX, errno, "cv2str_dup");
goto done;
}
if (percent_encode(str, &strenc) < 0)
if (uri_percent_encode(str, &strenc) < 0)
goto done;
cprintf(cb, "%s", strenc);
free(strenc); strenc = NULL;
@ -1495,7 +1496,7 @@ api_path2xml_vec(char **vec,
if ((restval_enc = index(name, '=')) != NULL){
*restval_enc = '\0';
restval_enc++;
if (percent_decode(restval_enc, &restval) < 0)
if (uri_percent_decode(restval_enc, &restval) < 0)
goto done;
}
/* Split into prefix and localname, ignore prefix for now */

View file

@ -51,6 +51,7 @@ struct xml_parse_yacc_arg{
cxobj *ya_xparent; /* xml parent element*/
int ya_skipspace; /* If set, remove all non-terminal bodies (strip pretty-print) */
yang_spec *ya_yspec; /* If set, top-level yang-spec */
int ya_lex_state; /* lex start condition (AMPERSAND) */
};
extern char *clixon_xml_parsetext;

View file

@ -76,6 +76,7 @@ int clixon_xml_parsewrap(void)
%x START
%s STATEA
%s AMPERSAND
%s CMNT
%s STR
%s TEXTDECL
@ -98,14 +99,21 @@ int clixon_xml_parsewrap(void)
<START>\> { BEGIN(STATEA); return *clixon_xml_parsetext; }
<START>\" { BEGIN(STR); return *clixon_xml_parsetext; }
<START>. { clixon_xml_parselval.string = yytext; return CHAR; /*XXX:optimize*/ }
<START>. { clixon_xml_parselval.string = yytext; return CHARDATA; /*XXX:optimize*/ }
<STATEA>"</" { BEGIN(START); return BSLASH; }
<STATEA>"<!--" { BEGIN(CMNT); return BCOMMENT; }
<STATEA>\< { BEGIN(START); return *clixon_xml_parsetext; }
<STATEA>\n { clixon_xml_parselval.string = yytext;_YA->ya_linenum++; return (CHAR);}
<STATEA>. { clixon_xml_parselval.string = yytext; return CHAR; /*XXX:optimize*/}
<STATEA>& { _YA->ya_lex_state =STATEA;BEGIN(AMPERSAND);}
<STATEA>\n { clixon_xml_parselval.string = yytext;_YA->ya_linenum++; return (CHARDATA);}
<STATEA>. { clixon_xml_parselval.string = yytext; return CHARDATA; /*XXX:optimize*/}
/* @see xml_chardata_encode */
<AMPERSAND>"amp; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = strdup("&"); return CHARDATA;}
<AMPERSAND>"lt; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = strdup("<"); return CHARDATA;}
<AMPERSAND>"gt; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = strdup(">"); return CHARDATA;}
<AMPERSAND>"apos; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = strdup("'"); return CHARDATA;}
<AMPERSAND>"aquot; " {BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = strdup("'"); return CHARDATA;}
<CMNT>"-->" { BEGIN(START); return ECOMMENT; }
<CMNT>\n _YA->ya_linenum++;
@ -117,15 +125,15 @@ int clixon_xml_parsewrap(void)
<TEXTDECL>\" { BEGIN(STRDQ); return *clixon_xml_parsetext; }
<TEXTDECL>\' { BEGIN(STRSQ); return *clixon_xml_parsetext; }
<STR>[^\"]+ { clixon_xml_parselval.string = strdup(yytext); return CHAR; }
<STR>[^\"]+ { clixon_xml_parselval.string = strdup(yytext); return CHARDATA; }
<STR>\" { BEGIN(START); return *clixon_xml_parsetext; }
<STRDQ>1\.[0-9]+ { clixon_xml_parselval.string = strdup(yytext); return CHAR; }
<STRDQ>[^\"]+ { clixon_xml_parselval.string = strdup(yytext); return CHAR; }
<STRDQ>1\.[0-9]+ { clixon_xml_parselval.string = strdup(yytext); return CHARDATA; }
<STRDQ>[^\"]+ { clixon_xml_parselval.string = strdup(yytext); return CHARDATA; }
<STRDQ>\" { BEGIN(TEXTDECL); return *clixon_xml_parsetext; }
<STRSQ>1\.[0-9]+ { clixon_xml_parselval.string = strdup(yytext); return CHAR; }
<STRSQ>[^\']+ { clixon_xml_parselval.string = strdup(yytext); return CHAR; }
<STRSQ>1\.[0-9]+ { clixon_xml_parselval.string = strdup(yytext); return CHARDATA; }
<STRSQ>[^\']+ { clixon_xml_parselval.string = strdup(yytext); return CHARDATA; }
<STRSQ>\' { BEGIN(TEXTDECL); return *clixon_xml_parsetext; }
%%

View file

@ -41,7 +41,7 @@
%start topxml
%token <string> NAME CHAR
%token <string> NAME CHARDATA
%token VER ENC
%token BSLASH ESLASH
%token BTEXT ETEXT
@ -329,15 +329,15 @@ topxml : list
dcl : BTEXT info encode ETEXT { clicon_debug(3, "dcl->info encode"); }
;
info : VER '=' '\"' CHAR '\"'
info : VER '=' '\"' CHARDATA '\"'
{ if (xml_parse_version(_YA, $4) <0) YYABORT; }
| VER '=' '\'' CHAR '\''
| VER '=' '\'' CHARDATA '\''
{ if (xml_parse_version(_YA, $4) <0) YYABORT; }
|
;
encode : ENC '=' '\"' CHAR '\"' {free($4);}
| ENC '=' '\'' CHAR '\'' {free($4);}
encode : ENC '=' '\"' CHARDATA '\"' {free($4);}
| ENC '=' '\'' CHARDATA '\'' {free($4);}
;
element : '<' qname attrs element1
@ -372,8 +372,8 @@ list : list content { clicon_debug(3, "list -> list content"); }
content : element { clicon_debug(3, "content -> element"); }
| comment { clicon_debug(3, "content -> comment"); }
| CHAR { if (xml_parse_content(_YA, $1) < 0) YYABORT;
clicon_debug(3, "content -> CHAR %s", $1); }
| CHARDATA { if (xml_parse_content(_YA, $1) < 0) YYABORT;
clicon_debug(3, "content -> CHARDATA %s", $1); }
| { clicon_debug(3, "content -> "); }
;
@ -394,7 +394,7 @@ attqname : NAME {$$ = $1;}
;
attvalue : '\"' CHAR '\"' { $$=$2; /* $2 must be consumed */}
attvalue : '\"' CHARDATA '\"' { $$=$2; /* $2 must be consumed */}
| '\"' '\"' { $$=strdup(""); /* $2 must be consumed */}
;

View file

@ -60,6 +60,11 @@ expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0" "^$"
new "cli show configuration"
expectfn "$clixon_cli -1 -f $cfg show conf cli" "^interfaces interface name eth/0/0" "interfaces interface enabled true$"
new "cli configure using encoded chars data <&"
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description \"foo<&bar\"" ""
new "cli configure using encoded chars name <&"
expectfn "$clixon_cli -1 -f $cfg set interfaces interface fddi&< type eth" ""
new "cli failed validate"
expectfn "$clixon_cli -1 -f $cfg -l o validate" "Missing mandatory variable"

View file

@ -98,11 +98,17 @@ expecteof "$clixon_netconf -qf $cfg" "<rpc><validate><source><candidate/></sourc
new "netconf commit"
expecteof "$clixon_netconf -qf $cfg" "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf edit config replace XXX is merge?"
new "netconf edit config merge"
expecteof "$clixon_netconf -qf $cfg" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth2</name><type>eth</type></interface></interfaces></config><default-operation>merge</default-operation></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf edit ampersand encoding(<&): name:'eth&' type:'t<>'"
expecteof "$clixon_netconf -qf $cfg" "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth&amp; </name><type>t&lt; &gt; </type></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf get replaced config"
expecteof "$clixon_netconf -qf $cfg" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><interfaces><interface><name>eth1</name><type>eth</type><enabled>true</enabled></interface><interface><name>eth2</name><type>eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
expecteof "$clixon_netconf -qf $cfg" "<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><interfaces><interface><name>eth&amp; </name><type>t&lt; &gt; </type><enabled>true</enabled></interface><interface><name>eth1</name><type>eth</type><enabled>true</enabled></interface><interface><name>eth2</name><type>eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
new "cli show configuration eth& - encoding tests"
expectfn "$clixon_cli -1 -f $cfg show conf cli" "interfaces interface name eth&"
new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg" "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"

View file

@ -8,7 +8,6 @@ APPNAME=example
cfg=$dir/conf_yang.xml
fyang=$dir/type.yang
cat <<EOF > $cfg
<config>
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -164,7 +163,7 @@ new "netconf validate ok"
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf set ab wrong"
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><list><ip>a.b&c.d</ip></list></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><edit-config><target><candidate/></target><config><list><ip>a.b&amp; c.d</ip></list></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"