From 67c0abead789c8479a59e5428b3279cbdc7d7da9 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sat, 21 Apr 2018 16:32:46 +0200 Subject: [PATCH] Fixed issue https://github.com/clicon/clixon/issues/17 special character in strings can break RPCs --- CHANGELOG.md | 1 + apps/backend/backend_client.c | 6 +- apps/cli/cli_show.c | 8 +- datastore/keyvalue/clixon_keyvalue.c | 10 +- lib/clixon/clixon_string.h | 5 +- lib/src/clixon_netconf_lib.c | 248 ++++++++++++++++++++------- lib/src/clixon_string.c | 125 ++++++++++++-- lib/src/clixon_xml.c | 30 +++- lib/src/clixon_xml_map.c | 25 +-- lib/src/clixon_xml_parse.h | 1 + lib/src/clixon_xml_parse.l | 48 +++--- lib/src/clixon_xml_parse.y | 16 +- test/test_cli.sh | 5 + test/test_netconf.sh | 10 +- test/test_type.sh | 3 +- 15 files changed, 405 insertions(+), 136 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36450023..bbf2c9a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index b21611fc..2debcfc2 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -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: diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index 8937bfde..6714413a 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -516,12 +516,12 @@ cli_show_config(clicon_handle h, xml2txt(stdout, xc, 0); /* tree-formed text */ break; case FORMAT_CLI: + /* 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){ - if ((gt = clicon_cli_genmodel_type(h)) == GT_ERR) - goto done; + while ((xc = xml_child_each(xt, xc, -1)) != NULL) xml2cli(stdout, xc, NULL, gt); /* cli syntax */ - } break; case FORMAT_NETCONF: fprintf(stdout, "\n"); diff --git a/datastore/keyvalue/clixon_keyvalue.c b/datastore/keyvalue/clixon_keyvalue.c index c1ad1911..aa529477 100644 --- a/datastore/keyvalue/clixon_keyvalue.c +++ b/datastore/keyvalue/clixon_keyvalue.c @@ -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; diff --git a/lib/clixon/clixon_string.h b/lib/clixon/clixon_string.h index 86088743..311702b5 100644 --- a/lib/clixon/clixon_string.h +++ b/lib/clixon/clixon_string.h @@ -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); diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index a2a70fc0..866efec6 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -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" @@ -73,20 +74,27 @@ netconf_in_use(cbuf *cb, char *type, char *message) { - int retval = -1; - + int retval = -1; + char *encstr = NULL; + if (cprintf(cb, "" "in-use" "%s" "error", type) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -105,7 +113,8 @@ netconf_invalid_value(cbuf *cb, char *type, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "invalid-value" @@ -113,12 +122,18 @@ netconf_invalid_value(cbuf *cb, "error", type) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <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, "" "too-big" @@ -146,12 +162,18 @@ netconf_too_big(cbuf *cb, "error", type) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -172,7 +194,8 @@ netconf_missing_attribute(cbuf *cb, char *info, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "missing-attribute" @@ -181,8 +204,12 @@ netconf_missing_attribute(cbuf *cb, "error", type, info) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; @@ -208,7 +235,8 @@ netconf_bad_attribute(cbuf *cb, char *info, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "bad-attribute" @@ -217,12 +245,18 @@ netconf_bad_attribute(cbuf *cb, "error", type, info) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -243,7 +277,8 @@ netconf_unknown_attribute(cbuf *cb, char *info, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "unknown-attribute" @@ -252,19 +287,24 @@ netconf_unknown_attribute(cbuf *cb, "error", type, info) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <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. @@ -279,7 +319,8 @@ netconf_missing_element(cbuf *cb, char *info, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "missing-element" @@ -288,12 +329,18 @@ netconf_missing_element(cbuf *cb, "error", type, info) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -315,7 +362,8 @@ netconf_bad_element(cbuf *cb, char *info, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "bad-element" @@ -324,12 +372,18 @@ netconf_bad_element(cbuf *cb, "error", type, info) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -350,8 +404,8 @@ netconf_unknown_element(cbuf *cb, char *info, char *message) { - int retval = -1; - + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "unknown-element" @@ -360,12 +414,18 @@ netconf_unknown_element(cbuf *cb, "error", type, info) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -386,7 +446,8 @@ netconf_unknown_namespace(cbuf *cb, char *info, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "unknown-namespace" @@ -395,12 +456,18 @@ netconf_unknown_namespace(cbuf *cb, "error", type, info) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <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, "" "access-denied" @@ -427,12 +495,18 @@ netconf_access_denied(cbuf *cb, "error", type) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -484,7 +558,8 @@ netconf_lock_denied(cbuf *cb, char *info, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "lock-denied" @@ -493,12 +568,18 @@ netconf_lock_denied(cbuf *cb, "error", info) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -517,20 +598,27 @@ netconf_resource_denied(cbuf *cb, char *type, char *message) { - int retval = -1; - + int retval = -1; + char *encstr = NULL; + if (cprintf(cb, "" "resource-denied" "%s" "error", type) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -550,7 +638,8 @@ netconf_rollback_failed(cbuf *cb, char *type, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "rollback-failed" @@ -558,12 +647,18 @@ netconf_rollback_failed(cbuf *cb, "error", type) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -582,19 +677,26 @@ int netconf_data_exists(cbuf *cb, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "data-exists" "application" "error") <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -613,19 +715,26 @@ int netconf_data_missing(cbuf *cb, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "data-missing" "application" "error") <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -645,7 +754,8 @@ netconf_operation_not_supported(cbuf *cb, char *type, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "operation-not-supported" @@ -653,12 +763,18 @@ netconf_operation_not_supported(cbuf *cb, "error", type) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -678,7 +794,8 @@ netconf_operation_failed(cbuf *cb, char *type, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "operation-failed" @@ -686,12 +803,18 @@ netconf_operation_failed(cbuf *cb, "error", type) <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") < 0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); @@ -744,19 +867,26 @@ int netconf_malformed_message(cbuf *cb, char *message) { - int retval = -1; + int retval = -1; + char *encstr = NULL; if (cprintf(cb, "" "malformed-message" "rpc" "error") <0) goto err; - if (message && cprintf(cb, "%s", message) < 0) - goto err; + if (message){ + if (xml_chardata_encode(message, &encstr) < 0) + goto done; + if (cprintf(cb, "%s", encstr) < 0) + goto err; + } if (cprintf(cb, "") <0) goto err; retval = 0; done: + if (encstr) + free(encstr); return retval; err: clicon_err(OE_XML, errno, "cprintf"); diff --git a/lib/src/clixon_string.c b/lib/src/clixon_string.c index d02bf5ff..d9892e90 100644 --- a/lib/src/clixon_string.c +++ b/lib/src/clixon_string.c @@ -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,12 +163,18 @@ 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, - char **escp) +uri_percent_encode(char *str, + char **escp) { int retval = -1; char *esc = NULL; @@ -184,7 +190,7 @@ percent_encode(char *str, memset(esc, 0, len); j = 0; for (i=0; i "& " must + * < -> "< " must + * > -> "> " must for backward compatibility + * ' -> "' " may + * ' -> "" " 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': + len += strlen("> "); + 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': + if ((l=snprintf(&esc[j], 6, "> ")) < 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"); diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index 6811e550..8204b04b 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -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 instead of */ 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 diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index 701615e8..7741a14e 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -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,15 +214,15 @@ xml2cli(FILE *f, } if (prepend0) cprintf(cbpre, "%s", prepend0); -/* bool determines when to print a variable keyword: - !leaf T for all (ie parameter) - index GT_NONE F - index GT_VARS F - index GT_ALL T - !index GT_NONE F - !index GT_VARS T - !index GT_ALL T - */ + /* bool determines when to print a variable keyword: + !leaf T for all (ie parameter) + index GT_NONE F + index GT_VARS F + index GT_ALL T + !index GT_NONE F + !index GT_VARS T + !index GT_ALL T + */ bool = !leaf(x) || gt == GT_ALL || (gt == GT_VARS); // bool = (!x->xn_index || gt == GT_ALL); if (bool){ @@ -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 */ diff --git a/lib/src/clixon_xml_parse.h b/lib/src/clixon_xml_parse.h index 83950abb..3122e8f0 100644 --- a/lib/src/clixon_xml_parse.h +++ b/lib/src/clixon_xml_parse.h @@ -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; diff --git a/lib/src/clixon_xml_parse.l b/lib/src/clixon_xml_parse.l index e16ffaae..c6f1726a 100644 --- a/lib/src/clixon_xml_parse.l +++ b/lib/src/clixon_xml_parse.l @@ -76,6 +76,7 @@ int clixon_xml_parsewrap(void) %x START %s STATEA +%s AMPERSAND %s CMNT %s STR %s TEXTDECL @@ -88,24 +89,31 @@ int clixon_xml_parsewrap(void) } [ \t]+ ; \: return *clixon_xml_parsetext; -\n { _YA->ya_linenum++;} -""/>" { BEGIN(STATEA); return ESLASH; } -"" { BEGIN(START); return ECOMMENT; } \n _YA->ya_linenum++; @@ -117,15 +125,15 @@ int clixon_xml_parsewrap(void) \" { BEGIN(STRDQ); return *clixon_xml_parsetext; } \' { BEGIN(STRSQ); return *clixon_xml_parsetext; } -[^\"]+ { clixon_xml_parselval.string = strdup(yytext); return CHAR; } +[^\"]+ { clixon_xml_parselval.string = strdup(yytext); return CHARDATA; } \" { BEGIN(START); return *clixon_xml_parsetext; } -1\.[0-9]+ { clixon_xml_parselval.string = strdup(yytext); return CHAR; } -[^\"]+ { clixon_xml_parselval.string = strdup(yytext); return CHAR; } +1\.[0-9]+ { clixon_xml_parselval.string = strdup(yytext); return CHARDATA; } +[^\"]+ { clixon_xml_parselval.string = strdup(yytext); return CHARDATA; } \" { BEGIN(TEXTDECL); return *clixon_xml_parsetext; } -1\.[0-9]+ { clixon_xml_parselval.string = strdup(yytext); return CHAR; } -[^\']+ { clixon_xml_parselval.string = strdup(yytext); return CHAR; } +1\.[0-9]+ { clixon_xml_parselval.string = strdup(yytext); return CHARDATA; } +[^\']+ { clixon_xml_parselval.string = strdup(yytext); return CHARDATA; } \' { BEGIN(TEXTDECL); return *clixon_xml_parsetext; } %% diff --git a/lib/src/clixon_xml_parse.y b/lib/src/clixon_xml_parse.y index 1e774e29..ab9d5193 100644 --- a/lib/src/clixon_xml_parse.y +++ b/lib/src/clixon_xml_parse.y @@ -41,7 +41,7 @@ %start topxml -%token NAME CHAR +%token 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 */} ; diff --git a/test/test_cli.sh b/test/test_cli.sh index 338ba060..51a2ea5e 100755 --- a/test/test_cli.sh +++ b/test/test_cli.sh @@ -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" diff --git a/test/test_netconf.sh b/test/test_netconf.sh index 9877c770..5b872e67 100755 --- a/test/test_netconf.sh +++ b/test/test_netconf.sh @@ -98,11 +98,17 @@ expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^]]>]]>$" -new "netconf edit config replace XXX is merge?" +new "netconf edit config merge" expecteof "$clixon_netconf -qf $cfg" "eth2ethmerge]]>]]>" "^]]>]]>$" +new "netconf edit ampersand encoding(<&): name:'eth&' type:'t<>'" +expecteof "$clixon_netconf -qf $cfg" "eth& t< > ]]>]]>" "^]]>]]>$" + new "netconf get replaced config" -expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^eth1ethtrueeth2ethtrue]]>]]>$" +expecteof "$clixon_netconf -qf $cfg" "]]>]]>" "^eth& t< > trueeth1ethtrueeth2ethtrue]]>]]>$" + +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" "]]>]]>" "^]]>]]>$" diff --git a/test/test_type.sh b/test/test_type.sh index 8eaaba92..7788ee02 100755 --- a/test/test_type.sh +++ b/test/test_type.sh @@ -8,7 +8,6 @@ APPNAME=example cfg=$dir/conf_yang.xml fyang=$dir/type.yang - cat < $cfg $cfg @@ -164,7 +163,7 @@ new "netconf validate ok" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" new "netconf set ab wrong" -expecteof "$clixon_netconf -qf $cfg -y $fyang" "a.b&c.d]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "a.b& c.d]]>]]>" "^]]>]]>$" new "netconf validate" expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^"