From 602f5034b4d2f4832e4b362322a8672107fcb4b5 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Mon, 23 Apr 2018 23:09:55 +0200 Subject: [PATCH] NACM external file support. CLICON_NACM_FILE config option, if CLICON_NACM_MODE is external --- CHANGELOG.md | 1 + apps/backend/backend_client.c | 36 +- apps/backend/backend_handle.h | 4 + apps/backend/backend_main.c | 61 +++- apps/backend/clixon_backend_handle.c | 23 ++ apps/cli/Makefile.in | 2 +- example/Makefile.in | 2 +- example/example.xml | 2 + example/example_restconf.c | 7 +- lib/src/clixon_options.c | 2 +- lib/src/clixon_xml.c | 23 +- lib/src/clixon_xml_map.c | 9 +- test/test_auth.sh | 2 +- test/test_auth_ext.sh | 241 ++++++++++++++ yang/Makefile.in | 1 + yang/clixon-config@2018-02-12.yang | 9 +- yang/ietf-yang-types@2013-07-15.yang | 481 +++++++++++++++++++++++++++ 17 files changed, 867 insertions(+), 39 deletions(-) create mode 100644 test/test_auth_ext.sh create mode 100644 yang/ietf-yang-types@2013-07-15.yang diff --git a/CHANGELOG.md b/CHANGELOG.md index e56752d8..1d3d88b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Major changes: * Experimental NACM RFC8341 Network Configuration Access Control Model. * CLICON_NACM_MODE config option, default is disabled. + * CLICON_NACM_FILE config option, if CLICON_NACM_MODE is "external" * Added username attribute to all rpc:s from frontend to backend * Added NACM backend module in example * Restructure and more generic plugin API (cli,backend,restconf,netconf). diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 1f8ac9c2..fc619640 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -904,7 +904,9 @@ nacm_match_rule(clicon_handle h, /*! Make nacm access control * @param[in] h Clicon handle + * @param[in] mode NACMmode, internal or external * @param[in] name rpc name + * @param[in] username * @param[out] cbret Cligen buffer result. Set to an error msg if retval=0. * @retval -1 Error * @retval 0 Not access and cbret set @@ -913,6 +915,7 @@ nacm_match_rule(clicon_handle h, */ static int nacm_access(clicon_handle h, + char *mode, char *name, char *username, cbuf *cbret) @@ -935,10 +938,26 @@ nacm_access(clicon_handle h, int ret; clicon_debug(1, "%s", __FUNCTION__); + /* 0. If nacm-mode is external, get NACM defintion from separet tree, + otherwise get it from internal configuration */ + if (strcmp(mode, "external")==0){ + if ((xtop = backend_nacm_list_get(h)) == NULL){ + clicon_err(OE_XML, 0, "No nacm external tree"); + goto done; + } + } + else if (strcmp(mode, "internal")==0){ + if (xmldb_get(h, "running", "nacm", 0, &xtop) < 0) + goto done; + } + else{ + clicon_err(OE_UNIX, 0, "Invalid NACM mode: %s", mode); + goto done; + } + /* 1. If the "enable-nacm" leaf is set to "false", then the protocol operation is permitted. (or config does not exist) */ - if (xmldb_get(h, "running", "nacm", 0, &xtop) < 0) - goto done; + if ((xacm = xpath_first(xtop, "nacm")) == NULL) goto permit; exec_default = xml_find_body(xacm, "exec-default"); @@ -1033,7 +1052,7 @@ nacm_access(clicon_handle h, retval = 1; done: clicon_debug(1, "%s retval:%d (0:deny 1:permit)", __FUNCTION__, retval); - if (xtop) + if (strcmp(mode, "internal")==0 && xtop) xml_free(xtop); if (gvec) free(gvec); @@ -1097,15 +1116,14 @@ from_client_msg(clicon_handle h, while ((xe = xml_child_each(x, xe, CX_ELMNT)) != NULL) { name = xml_name(xe); clicon_debug(1, "%s name:%s", __FUNCTION__, name); -#if 1 /* NACM */ /* Make NACM access control if enabled as "internal"*/ nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE"); - if (nacm_mode && strcmp(nacm_mode,"internal") == 0) - if ((ret = nacm_access(h, name, username, cbret)) < 0) + if (nacm_mode && strcmp(nacm_mode, "disabled") != 0){ + if ((ret = nacm_access(h, nacm_mode, name, username, cbret)) < 0) goto done; - if (!ret) - goto reply; -#endif + if (!ret) + goto reply; + } if (strcmp(name, "get-config") == 0){ if (from_client_get_config(h, xe, cbret) <0) goto done; diff --git a/apps/backend/backend_handle.h b/apps/backend/backend_handle.h index 8eb3e073..676cc50c 100644 --- a/apps/backend/backend_handle.h +++ b/apps/backend/backend_handle.h @@ -52,4 +52,8 @@ struct client_entry *backend_client_list(clicon_handle h); int backend_client_delete(clicon_handle h, struct client_entry *ce); +int backend_nacm_list_set(clicon_handle h, cxobj *xnacm); + +cxobj * backend_nacm_list_get(clicon_handle h); + #endif /* _BACKEND_HANDLE_H_ */ diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 346cf859..9babb24e 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -260,6 +260,59 @@ plugin_start_useroptions(clicon_handle h, return 0; } +/*! Load external NACM file + */ +static int +nacm_load_external(clicon_handle h) +{ + int retval = -1; + char *filename; /* NACM config file */ + yang_spec *yspec = NULL; + cxobj *xt = NULL; + struct stat st; + FILE *f = NULL; + int fd; + + filename = clicon_option_str(h, "CLICON_NACM_FILE"); + if (filename == NULL || strlen(filename)==0){ + clicon_err(OE_UNIX, errno, "CLICON_NACM_FILE not set in NACM external mode"); + goto done; + } + if (stat(filename, &st) < 0){ + clicon_err(OE_UNIX, errno, "%s", filename); + goto done; + } + if (!S_ISREG(st.st_mode)){ + clicon_err(OE_UNIX, 0, "%s is not a regular file", filename); + goto done; + } + if ((f = fopen(filename, "r")) == NULL) { + clicon_err(OE_UNIX, errno, "configure file: %s", filename); + return -1; + } + if ((yspec = yspec_new()) == NULL) + goto done; + if (yang_parse(h, CLIXON_DATADIR, "ietf-netconf-acm", NULL, yspec) < 0) + goto done; + fd = fileno(f); + /* Read configfile */ + if (xml_parse_file(fd, "", yspec, &xt) < 0) + goto done; + if (xt == NULL){ + clicon_err(OE_XML, 0, "No xml tree in %s", filename); + goto done; + } + if (backend_nacm_list_set(h, xt) < 0) + goto done; + retval = 0; + done: + if (yspec) /* The clixon yang-spec is not used after this */ + yspec_free(yspec); + if (f) + fclose(f); + return retval; +} + /*! Merge xml in filename into database */ static int @@ -498,6 +551,7 @@ main(int argc, int xml_cache; int xml_pretty; char *xml_format; + char *nacm_mode; /* In the startup, logs to stderr & syslog and debug flag set later */ clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_STDERR|CLICON_LOG_SYSLOG); @@ -551,7 +605,12 @@ main(int argc, usage(argv[0], h); return -1; } - + /* External NACM file? */ + nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE"); + if (nacm_mode && strcmp(nacm_mode, "external") == 0) + if (nacm_load_external(h) < 0) + goto done; + /* Now run through the operational args */ opterr = 1; optind = 1; diff --git a/apps/backend/clixon_backend_handle.c b/apps/backend/clixon_backend_handle.c index c4568b28..dfb9461a 100644 --- a/apps/backend/clixon_backend_handle.c +++ b/apps/backend/clixon_backend_handle.c @@ -90,6 +90,7 @@ struct backend_handle { struct client_entry *bh_ce_list; /* The client list */ int bh_ce_nr; /* Number of clients, just increment */ struct handle_subscription *bh_subscription; /* Event subscription list */ + cxobj *bh_nacm; /* NACM external struct */ }; /*! Creates and returns a clicon config handle for other CLICON API calls @@ -106,11 +107,14 @@ backend_handle_init(void) int backend_handle_exit(clicon_handle h) { + struct backend_handle *bh = handle(h); struct client_entry *ce; /* only delete client structs, not close sockets, etc, see backend_client_rm */ while ((ce = backend_client_list(h)) != NULL) backend_client_delete(h, ce); + if (bh->bh_nacm) + xml_free(bh->bh_nacm); clicon_handle_exit(h); /* frees h and options */ return 0; } @@ -431,3 +435,22 @@ subscription_each(clicon_handle h, return hs; } +int +backend_nacm_list_set(clicon_handle h, + cxobj *xnacm) +{ + struct backend_handle *bh = handle(h); + + if (bh->bh_nacm) + xml_free(bh->bh_nacm); + bh->bh_nacm = xnacm; + return 0; +} + +cxobj * +backend_nacm_list_get(clicon_handle h) +{ + struct backend_handle *bh = handle(h); + + return bh->bh_nacm; +} diff --git a/apps/cli/Makefile.in b/apps/cli/Makefile.in index 1272bc83..bdea3b9e 100644 --- a/apps/cli/Makefile.in +++ b/apps/cli/Makefile.in @@ -103,7 +103,7 @@ distclean: clean # Put config file in etc/ install: install-lib $(APPL) install -d -m 0755 $(DESTDIR)$(bindir) - install -m 0644 -s $(APPL) $(DESTDIR)$(bindir) + install -m 0755 -s $(APPL) $(DESTDIR)$(bindir) install-lib: $(MYLIB) install -d -m 0755 $(DESTDIR)$(libdir) diff --git a/example/Makefile.in b/example/Makefile.in index b043dbef..05433e6a 100644 --- a/example/Makefile.in +++ b/example/Makefile.in @@ -118,7 +118,7 @@ install: $(YANGSPECS) $(CLISPECS) $(BE_PLUGIN) $(BE2_PLUGIN) $(CLI_PLUGIN) $(NET install -d -m 0755 $(DESTDIR)$(clixon_LIBDIR)/cli install -m 0644 -s $(CLI_PLUGIN) $(DESTDIR)$(clixon_LIBDIR)/cli install -d -m 0755 $(DESTDIR)$(clixon_LIBDIR)/backend - install -m 0644 -s $(BE_PLUGIN) $(DESTDIR)$(clixon_LIBDIR)/backend + install -m 0644 -s $(BE_PLUGIN) $(BE2_PLUGIN) $(DESTDIR)$(clixon_LIBDIR)/backend install -d -m 0755 $(DESTDIR)$(clixon_LIBDIR)/netconf install -m 0644 -s $(NETCONF_PLUGIN) $(DESTDIR)$(clixon_LIBDIR)/netconf install -d -m 0755 $(DESTDIR)$(clixon_LIBDIR)/restconf diff --git a/example/example.xml b/example/example.xml index e93b840a..337048bb 100644 --- a/example/example.xml +++ b/example/example.xml @@ -11,8 +11,10 @@ /usr/local/var/example/example.sock /usr/local/var/example/example.pidfile 1 + VARS /usr/local/var/example /usr/local/lib/xmldb/text.so 0 init + disabled diff --git a/example/example_restconf.c b/example/example_restconf.c index f16199e1..bace08fd 100644 --- a/example/example_restconf.c +++ b/example/example_restconf.c @@ -197,7 +197,6 @@ plugin_credentials(clicon_handle h, FCGX_Request *r = (FCGX_Request *)arg; cxobj *xt = NULL; cxobj *x; - char *xbody; char *auth; char *user = NULL; char *passwd; @@ -205,11 +204,12 @@ plugin_credentials(clicon_handle h, size_t authlen; cbuf *cb = NULL; int ret; - + char *xbody; + + clicon_debug(1, "%s", __FUNCTION__); /* XXX This is a kludge to reset the user not remaining from previous */ if (clicon_username_set(h, "admin") < 0) goto done; - clicon_debug(1, "%s", __FUNCTION__); /* Check if basic_auth set, if not return OK */ if (clicon_rpc_get_config(h, "running", "authentication", &xt) < 0) goto done; @@ -249,7 +249,6 @@ plugin_credentials(clicon_handle h, cprintf(cb, "authentication/auth[user=%s]", user); if ((x = xpath_first(xt, cbuf_get(cb))) == NULL) goto fail; - passwd2 = xml_find_body(x, "password"); if (strcmp(passwd, passwd2)) goto fail; diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c index 43611c6a..45c642e0 100644 --- a/lib/src/clixon_options.c +++ b/lib/src/clixon_options.c @@ -209,7 +209,7 @@ clicon_options_main(clicon_handle h) /* If file ends with .xml, assume it is new format */ if ((suffix = rindex(configfile, '.')) != NULL){ suffix++; - xml = strcmp(suffix,"xml") == 0; + xml = strcmp(suffix, "xml") == 0; } if (xml){ /* Read clixon yang file */ if ((yspec = yspec_new()) == NULL) diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index 8204b04b..15e25d1a 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -164,7 +164,7 @@ xml_name_set(cxobj *xn, } if (name){ if ((xn->x_name = strdup(name)) == NULL){ - clicon_err(OE_XML, errno, "%s: strdup", __FUNCTION__); + clicon_err(OE_XML, errno, "strdup"); return -1; } } @@ -197,7 +197,7 @@ xml_namespace_set(cxobj *xn, } if (namespace){ if ((xn->x_namespace = strdup(namespace)) == NULL){ - clicon_err(OE_XML, errno, "%s: strdup", __FUNCTION__); + clicon_err(OE_XML, errno, "strdup"); return -1; } } @@ -288,7 +288,7 @@ xml_value_set(cxobj *xn, } if (val){ if ((xn->x_value = strdup(val)) == NULL){ - clicon_err(OE_XML, errno, "%s: strdup", __FUNCTION__); + clicon_err(OE_XML, errno, "strdup"); return -1; } } @@ -480,7 +480,7 @@ xml_child_append(cxobj *x, x->x_childvec_len++; x->x_childvec = realloc(x->x_childvec, x->x_childvec_len*sizeof(cxobj*)); if (x->x_childvec == NULL){ - clicon_err(OE_XML, errno, "%s: realloc", __FUNCTION__); + clicon_err(OE_XML, errno, "realloc"); return -1; } x->x_childvec[x->x_childvec_len-1] = xc; @@ -538,7 +538,7 @@ xml_new(char *name, cxobj *x; if ((x = malloc(sizeof(cxobj))) == NULL){ - clicon_err(OE_XML, errno, "%s: malloc", __FUNCTION__); + clicon_err(OE_XML, errno, "malloc"); return NULL; } memset(x, 0, sizeof(cxobj)); @@ -1314,15 +1314,14 @@ xml_parse_file(int fd, if (endtag != NULL) endtaglen = strlen(endtag); if ((xmlbuf = malloc(xmlbuflen)) == NULL){ - clicon_err(OE_XML, errno, "%s: malloc", __FUNCTION__); + clicon_err(OE_XML, errno, "malloc"); goto done; } memset(xmlbuf, 0, xmlbuflen); ptr = xmlbuf; while (1){ if ((ret = read(fd, &ch, 1)) < 0){ - clicon_err(OE_XML, errno, "%s: read: [pid:%d]\n", - __FUNCTION__, + clicon_err(OE_XML, errno, "read: [pid:%d]\n", (int)getpid()); break; } @@ -1345,7 +1344,7 @@ xml_parse_file(int fd, oldxmlbuflen = xmlbuflen; xmlbuflen *= 2; if ((xmlbuf = realloc(xmlbuf, xmlbuflen)) == NULL){ - clicon_err(OE_XML, errno, "%s: realloc", __FUNCTION__); + clicon_err(OE_XML, errno, "realloc"); goto done; } memset(xmlbuf+oldxmlbuflen, 0, xmlbuflen-oldxmlbuflen); @@ -1455,7 +1454,7 @@ xml_copy_one(cxobj *x0, xml_type_set(x1, xml_type(x0)); if (xml_value(x0)){ /* malloced string */ if ((x1->x_value = strdup(x0->x_value)) == NULL){ - clicon_err(OE_XML, errno, "%s: strdup", __FUNCTION__); + clicon_err(OE_XML, errno, "strdup"); return -1; } } @@ -1464,7 +1463,7 @@ xml_copy_one(cxobj *x0, return -1; if (xml_cv_get(x0)){ if ((cv1 = cv_dup(xml_cv_get(x0))) == NULL){ - clicon_err(OE_XML, errno, "%s: cv_dup", __FUNCTION__); + clicon_err(OE_XML, errno, "cv_dup"); return -1; } if ((xml_cv_set(x1, cv1)) < 0) @@ -1561,7 +1560,7 @@ cxvec_append(cxobj *x, int retval = -1; if ((*vec = realloc(*vec, sizeof(cxobj *) * (*len+1))) == NULL){ - clicon_err(OE_XML, errno, "%s: realloc", __FUNCTION__); + clicon_err(OE_XML, errno, "realloc"); goto done; } (*vec)[(*len)++] = x; diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index 8524a413..1be9d750 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -116,26 +116,19 @@ xml2txt(FILE *f, int children=0; char *term = NULL; int retval = -1; - int encr=0; xe = NULL; /* count children */ while ((xe = xml_child_each(x, xe, -1)) != NULL) children++; if (!children){ if (xml_type(x) == CX_BODY){ - /* Kludge for escaping encrypted passwords */ - if (strcmp(xml_name(xml_parent(x)), "encrypted-password")==0) - encr++; term = xml_value(x); } else{ fprintf(f, "%*s", 4*level, ""); term = xml_name(x); } - if (encr) - fprintf(f, "\"%s\";\n", term); - else - fprintf(f, "%s;\n", term); + fprintf(f, "%s;\n", term); retval = 0; goto done; } diff --git a/test/test_auth.sh b/test/test_auth.sh index 68339ab8..163edfa8 100755 --- a/test/test_auth.sh +++ b/test/test_auth.sh @@ -15,7 +15,7 @@ cat < $cfg $cfg /usr/local/share/$APPNAME/yang - $APPNAME + $fyang /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/restconf /usr/local/lib/$APPNAME/cli diff --git a/test/test_auth_ext.sh b/test/test_auth_ext.sh new file mode 100644 index 00000000..68339ab8 --- /dev/null +++ b/test/test_auth_ext.sh @@ -0,0 +1,241 @@ +#!/bin/bash +# Authentication and authorization and IETF NACM +# See RFC 8321 A.2 +# But replaced ietf-netconf-monitoring with * + +APPNAME=example +# include err() and new() functions and creates $dir +. ./lib.sh + +cfg=$dir/conf_yang.xml +fyang=$dir/test.yang +fyangerr=$dir/err.yang + +cat < $cfg + + $cfg + /usr/local/share/$APPNAME/yang + $APPNAME + /usr/local/lib/$APPNAME/clispec + /usr/local/lib/$APPNAME/restconf + /usr/local/lib/$APPNAME/cli + $APPNAME + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/var/$APPNAME/$APPNAME.pidfile + 1 + /usr/local/var/$APPNAME + /usr/local/lib/xmldb/text.so + false + internal + +EOF + +cat < $fyang +module $APPNAME{ + prefix ex; + import ietf-netconf-acm { + prefix nacm; + } + container authentication { + description "Example code for enabling www basic auth and some example + users"; + leaf basic_auth{ + description "Basic user / password authentication as in HTTP basic auth"; + type boolean; + default false; + } + list auth { + description "user / password entries. Valid if basic_auth=true"; + key user; + leaf user{ + description "User name"; + type string; + } + leaf password{ + description "Password"; + type string; + } + } + } + leaf x{ + type int32; + description "something to edit"; + } +} +EOF + +RULES=$(cat < + true + + adm1bar + + + wilmabar + + + guestbar + + + + false + deny + deny + deny + + + admin + admin + adm1 + olof + + + limited + wilma + bam-bam + + + guest + guest + guest@example.com + + + + guest-acl + guest + + deny-ncm + * + * + deny + + Do not allow guests any access to any information. + + + + + limited-acl + limited + + permit-get + get + * + exec + permit + + Allow get + + + + permit-get-config + get-config + * + exec + permit + + Allow get-config + + + + + admin-acl + admin + + permit-all + * + * + permit + + Allow the 'admin' group complete access to all operations and data. + + + + + 0 +EOF +) + +# kill old backend (if any) +new "kill old backend" +sudo clixon_backend -zf $cfg -y $fyang +if [ $? -ne 0 ]; then + err +fi + +new "start backend -s init -f $cfg -y $fyang" +# start new backend +sudo clixon_backend -s init -f $cfg -y $fyang +if [ $? -ne 0 ]; then + err +fi + +new "kill old restconf daemon" +sudo pkill -u www-data clixon_restconf +sleep 1 +new "start restconf daemon" +sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang + +sleep 1 + +new "restconf DELETE whole datastore" +expecteq "$(curl -u adm1:bar -sS -X DELETE http://localhost/restconf/data)" "" + +new2 "auth get" +expecteq "$(curl -u adm1:bar -sS -X GET http://localhost/restconf/data)" '{"data": null} + ' + +new "auth set authentication config" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "$RULES]]>]]>" "^]]>]]>$" + +new "commit it" +expecteof "$clixon_netconf -qf $cfg -y $fyang" "]]>]]>" "^]]>]]>$" + +new2 "auth get (no user: access denied)" +expecteq "$(curl -sS -X GET -H \"Accept:\ application/yang-data+json\" http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "The requested URL was unauthorized"}}} ' + +new2 "auth get (wrong passwd: access denied)" +expecteq "$(curl -u adm1:foo -sS -X GET http://localhost/restconf/data)" '{"ietf-restconf:errors" : {"error": {"error-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "The requested URL was unauthorized"}}} ' + +new2 "auth get (access)" +expecteq "$(curl -u adm1:bar -sS -X GET http://localhost/restconf/data/x)" '{"x": 0} + ' + +#----------------Enable NACM + +new "enable nacm" +expecteq "$(curl -u adm1:bar -sS -X PUT -d '{"enable-nacm": true}' http://localhost/restconf/data/nacm/enable-nacm)" "" + +new2 "admin get nacm" +expecteq "$(curl -u adm1:bar -sS -X GET http://localhost/restconf/data/x)" '{"x": 0} + ' + +new2 "limited get nacm" +expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/x)" '{"x": 0} + ' + +new2 "guest get nacm" +expecteq "$(curl -u guest:bar -sS -X GET http://localhost/restconf/data/x)" '{"ietf-restconf:errors" : {"error": {"error-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "access denied"}}} ' + +new "admin edit nacm" +expecteq "$(curl -u adm1:bar -sS -X PUT -d '{"x": 1}' http://localhost/restconf/data/x)" "" + +new2 "limited edit nacm" +expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"x": 2}' http://localhost/restconf/data/x)" '{"ietf-restconf:errors" : {"error": {"error-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "default deny"}}} ' + +new2 "guest edit nacm" +expecteq "$(curl -u guest:bar -sS -X PUT -d '{"x": 3}' http://localhost/restconf/data/x)" '{"ietf-restconf:errors" : {"error": {"error-tag": "access-denied","error-type": "protocol","error-severity": "error","error-message": "access denied"}}} ' + +new "Kill restconf daemon" +sudo pkill -u www-data clixon_restconf + +pid=`pgrep clixon_backend` +if [ -z "$pid" ]; then + err "backend already dead" +fi +# kill backend +sudo clixon_backend -zf $cfg +if [ $? -ne 0 ]; then + err "kill backend" +fi + +rm -rf $dir diff --git a/yang/Makefile.in b/yang/Makefile.in index e4a8aaf9..965c0655 100644 --- a/yang/Makefile.in +++ b/yang/Makefile.in @@ -42,6 +42,7 @@ YANGSPECS = clixon-config@2018-02-12.yang YANGSPECS += ietf-netconf@2011-06-01.yang YANGSPECS += ietf-netconf-acm@2018-02-14.yang YANGSPECS += ietf-inet-types@2013-07-15.yang +YANGSPECS += ietf-yang-types@2013-07-15.yang APPNAME = clixon # subdir ehere these files are installed diff --git a/yang/clixon-config@2018-02-12.yang b/yang/clixon-config@2018-02-12.yang index 84dc8622..c629a3c7 100644 --- a/yang/clixon-config@2018-02-12.yang +++ b/yang/clixon-config@2018-02-12.yang @@ -341,6 +341,13 @@ module clixon-config { leaf CLICON_NACM_MODE { type nacm_mode; default disabled; - description "RFC8341 network access configuration control model"; } + description "RFC8341 network access configuration control model + (NACM) mode: disabled, in regular (internal) config + or separate external file given by CLICON_NACM_FILE"; + } + leaf CLICON_NACM_FILE { + type string; + description "RFC8341 NACM external configuration file"; + } } } diff --git a/yang/ietf-yang-types@2013-07-15.yang b/yang/ietf-yang-types@2013-07-15.yang new file mode 100644 index 00000000..07834130 --- /dev/null +++ b/yang/ietf-yang-types@2013-07-15.yang @@ -0,0 +1,481 @@ + module ietf-yang-types { + + namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types"; + prefix "yang"; + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: + WG List: + + WG Chair: David Kessens + + + WG Chair: Juergen Schoenwaelder + + + Editor: Juergen Schoenwaelder + "; + + description + "This module contains a collection of generally useful derived + YANG data types. + + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6991; see + the RFC itself for full legal notices."; + + revision 2013-07-15 { + description + "This revision adds the following new data types: + - yang-identifier + - hex-string + - uuid + - dotted-quad"; + reference + "RFC 6991: Common YANG Data Types"; + } + + revision 2010-09-24 { + description + "Initial revision."; + reference + "RFC 6021: Common YANG Data Types"; + } + + /*** collection of counter and gauge types ***/ + + typedef counter32 { + type uint32; + description + "The counter32 type represents a non-negative integer + that monotonically increases until it reaches a + maximum value of 2^32-1 (4294967295 decimal), when it + wraps around and starts increasing again from zero. + + Counters have no defined 'initial' value, and thus, a + single value of a counter has (in general) no information + content. Discontinuities in the monotonically increasing + value normally occur at re-initialization of the + management system, and at other times as specified in the + description of a schema node using this type. If such + other times can occur, for example, the creation of + a schema node of type counter32 at times other than + re-initialization, then a corresponding schema node + should be defined, with an appropriate type, to indicate + the last discontinuity. + + The counter32 type should not be used for configuration + schema nodes. A default statement SHOULD NOT be used in + combination with the type counter32. + + In the value set and its semantics, this type is equivalent + to the Counter32 type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 + (SMIv2)"; + } + + typedef zero-based-counter32 { + type yang:counter32; + default "0"; + description + "The zero-based-counter32 type represents a counter32 + that has the defined 'initial' value zero. + + A schema node of this type will be set to zero (0) on creation + and will thereafter increase monotonically until it reaches + a maximum value of 2^32-1 (4294967295 decimal), when it + wraps around and starts increasing again from zero. + + Provided that an application discovers a new schema node + of this type within the minimum time to wrap, it can use the + 'initial' value as a delta. It is important for a management + station to be aware of this minimum time and the actual time + between polls, and to discard data if the actual time is too + long or there is no defined minimum time. + + In the value set and its semantics, this type is equivalent + to the ZeroBasedCounter32 textual convention of the SMIv2."; + reference + "RFC 4502: Remote Network Monitoring Management Information + Base Version 2"; + } + + typedef counter64 { + type uint64; + description + "The counter64 type represents a non-negative integer + that monotonically increases until it reaches a + maximum value of 2^64-1 (18446744073709551615 decimal), + when it wraps around and starts increasing again from zero. + + Counters have no defined 'initial' value, and thus, a + single value of a counter has (in general) no information + content. Discontinuities in the monotonically increasing + value normally occur at re-initialization of the + management system, and at other times as specified in the + description of a schema node using this type. If such + other times can occur, for example, the creation of + a schema node of type counter64 at times other than + re-initialization, then a corresponding schema node + should be defined, with an appropriate type, to indicate + the last discontinuity. + + The counter64 type should not be used for configuration + schema nodes. A default statement SHOULD NOT be used in + combination with the type counter64. + + In the value set and its semantics, this type is equivalent + to the Counter64 type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 + (SMIv2)"; + } + + typedef zero-based-counter64 { + type yang:counter64; + default "0"; + description + "The zero-based-counter64 type represents a counter64 that + has the defined 'initial' value zero. + + + + + A schema node of this type will be set to zero (0) on creation + and will thereafter increase monotonically until it reaches + a maximum value of 2^64-1 (18446744073709551615 decimal), + when it wraps around and starts increasing again from zero. + + Provided that an application discovers a new schema node + of this type within the minimum time to wrap, it can use the + 'initial' value as a delta. It is important for a management + station to be aware of this minimum time and the actual time + between polls, and to discard data if the actual time is too + long or there is no defined minimum time. + + In the value set and its semantics, this type is equivalent + to the ZeroBasedCounter64 textual convention of the SMIv2."; + reference + "RFC 2856: Textual Conventions for Additional High Capacity + Data Types"; + } + + typedef gauge32 { + type uint32; + description + "The gauge32 type represents a non-negative integer, which + may increase or decrease, but shall never exceed a maximum + value, nor fall below a minimum value. The maximum value + cannot be greater than 2^32-1 (4294967295 decimal), and + the minimum value cannot be smaller than 0. The value of + a gauge32 has its maximum value whenever the information + being modeled is greater than or equal to its maximum + value, and has its minimum value whenever the information + being modeled is smaller than or equal to its minimum value. + If the information being modeled subsequently decreases + below (increases above) the maximum (minimum) value, the + gauge32 also decreases (increases). + + In the value set and its semantics, this type is equivalent + to the Gauge32 type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 + (SMIv2)"; + } + + typedef gauge64 { + type uint64; + description + "The gauge64 type represents a non-negative integer, which + may increase or decrease, but shall never exceed a maximum + value, nor fall below a minimum value. The maximum value + cannot be greater than 2^64-1 (18446744073709551615), and + the minimum value cannot be smaller than 0. The value of + a gauge64 has its maximum value whenever the information + being modeled is greater than or equal to its maximum + value, and has its minimum value whenever the information + being modeled is smaller than or equal to its minimum value. + If the information being modeled subsequently decreases + below (increases above) the maximum (minimum) value, the + gauge64 also decreases (increases). + + In the value set and its semantics, this type is equivalent + to the CounterBasedGauge64 SMIv2 textual convention defined + in RFC 2856"; + reference + "RFC 2856: Textual Conventions for Additional High Capacity + Data Types"; + } + + /*** collection of identifier-related types ***/ + + typedef object-identifier { + type string { + pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))' + + '(\.(0|([1-9]\d*)))*'; + } + description + "The object-identifier type represents administratively + assigned names in a registration-hierarchical-name tree. + + Values of this type are denoted as a sequence of numerical + non-negative sub-identifier values. Each sub-identifier + value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers + are separated by single dots and without any intermediate + whitespace. + + The ASN.1 standard restricts the value space of the first + sub-identifier to 0, 1, or 2. Furthermore, the value space + of the second sub-identifier is restricted to the range + 0 to 39 if the first sub-identifier is 0 or 1. Finally, + the ASN.1 standard requires that an object identifier + has always at least two sub-identifiers. The pattern + captures these restrictions. + + Although the number of sub-identifiers is not limited, + module designers should realize that there may be + implementations that stick with the SMIv2 limit of 128 + sub-identifiers. + + This type is a superset of the SMIv2 OBJECT IDENTIFIER type + since it is not restricted to 128 sub-identifiers. Hence, + this type SHOULD NOT be used to represent the SMIv2 OBJECT + IDENTIFIER type; the object-identifier-128 type SHOULD be + used instead."; + reference + "ISO9834-1: Information technology -- Open Systems + Interconnection -- Procedures for the operation of OSI + Registration Authorities: General procedures and top + arcs of the ASN.1 Object Identifier tree"; + } + + typedef object-identifier-128 { + type object-identifier { + pattern '\d*(\.\d*){1,127}'; + } + description + "This type represents object-identifiers restricted to 128 + sub-identifiers. + + In the value set and its semantics, this type is equivalent + to the OBJECT IDENTIFIER type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 + (SMIv2)"; + } + + typedef yang-identifier { + type string { + length "1..max"; + pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*'; + pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*'; + } + description + "A YANG identifier string as defined by the 'identifier' + rule in Section 12 of RFC 6020. An identifier must + start with an alphabetic character or an underscore + followed by an arbitrary sequence of alphabetic or + numeric characters, underscores, hyphens, or dots. + + A YANG identifier MUST NOT start with any possible + combination of the lowercase or uppercase character + sequence 'xml'."; + reference + "RFC 6020: YANG - A Data Modeling Language for the Network + Configuration Protocol (NETCONF)"; + } + + /*** collection of types related to date and time***/ + + typedef date-and-time { + type string { + pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?' + + '(Z|[\+\-]\d{2}:\d{2})'; + } + description + "The date-and-time type is a profile of the ISO 8601 + standard for representation of dates and times using the + Gregorian calendar. The profile is defined by the + date-time production in Section 5.6 of RFC 3339. + + The date-and-time type is compatible with the dateTime XML + schema type with the following notable exceptions: + + (a) The date-and-time type does not allow negative years. + + (b) The date-and-time time-offset -00:00 indicates an unknown + time zone (see RFC 3339) while -00:00 and +00:00 and Z + all represent the same time zone in dateTime. + + (c) The canonical format (see below) of data-and-time values + differs from the canonical format used by the dateTime XML + schema type, which requires all times to be in UTC using + the time-offset 'Z'. + + This type is not equivalent to the DateAndTime textual + convention of the SMIv2 since RFC 3339 uses a different + separator between full-date and full-time and provides + higher resolution of time-secfrac. + + The canonical format for date-and-time values with a known time + zone uses a numeric time zone offset that is calculated using + the device's configured known offset to UTC time. A change of + the device's offset to UTC time will cause date-and-time values + to change accordingly. Such changes might happen periodically + in case a server follows automatically daylight saving time + (DST) time zone offset changes. The canonical format for + date-and-time values with an unknown time zone (usually + referring to the notion of local time) uses the time-offset + -00:00."; + reference + "RFC 3339: Date and Time on the Internet: Timestamps + RFC 2579: Textual Conventions for SMIv2 + XSD-TYPES: XML Schema Part 2: Datatypes Second Edition"; + } + + typedef timeticks { + type uint32; + description + "The timeticks type represents a non-negative integer that + represents the time, modulo 2^32 (4294967296 decimal), in + hundredths of a second between two epochs. When a schema + node is defined that uses this type, the description of + the schema node identifies both of the reference epochs. + + In the value set and its semantics, this type is equivalent + to the TimeTicks type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 + (SMIv2)"; + } + + typedef timestamp { + type yang:timeticks; + description + "The timestamp type represents the value of an associated + timeticks schema node at which a specific occurrence + happened. The specific occurrence must be defined in the + description of any schema node defined using this type. When + the specific occurrence occurred prior to the last time the + associated timeticks attribute was zero, then the timestamp + value is zero. Note that this requires all timestamp values + to be reset to zero when the value of the associated timeticks + attribute reaches 497+ days and wraps around to zero. + + The associated timeticks schema node must be specified + in the description of any schema node using this type. + + In the value set and its semantics, this type is equivalent + to the TimeStamp textual convention of the SMIv2."; + reference + "RFC 2579: Textual Conventions for SMIv2"; + } + + /*** collection of generic address types ***/ + + typedef phys-address { + type string { + pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?'; + } + + + + + description + "Represents media- or physical-level addresses represented + as a sequence octets, each octet represented by two hexadecimal + numbers. Octets are separated by colons. The canonical + representation uses lowercase characters. + + In the value set and its semantics, this type is equivalent + to the PhysAddress textual convention of the SMIv2."; + reference + "RFC 2579: Textual Conventions for SMIv2"; + } + + typedef mac-address { + type string { + pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}'; + } + description + "The mac-address type represents an IEEE 802 MAC address. + The canonical representation uses lowercase characters. + + In the value set and its semantics, this type is equivalent + to the MacAddress textual convention of the SMIv2."; + reference + "IEEE 802: IEEE Standard for Local and Metropolitan Area + Networks: Overview and Architecture + RFC 2579: Textual Conventions for SMIv2"; + } + + /*** collection of XML-specific types ***/ + + typedef xpath1.0 { + type string; + description + "This type represents an XPATH 1.0 expression. + + When a schema node is defined that uses this type, the + description of the schema node MUST specify the XPath + context in which the XPath expression is evaluated."; + reference + "XPATH: XML Path Language (XPath) Version 1.0"; + } + + /*** collection of string types ***/ + + typedef hex-string { + type string { + pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?'; + } + description + "A hexadecimal string with octets represented as hex digits + separated by colons. The canonical representation uses + lowercase characters."; + } + + typedef uuid { + type string { + pattern '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-' + + '[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'; + } + description + "A Universally Unique IDentifier in the string representation + defined in RFC 4122. The canonical representation uses + lowercase characters. + + The following is an example of a UUID in string representation: + f81d4fae-7dec-11d0-a765-00a0c91e6bf6 + "; + reference + "RFC 4122: A Universally Unique IDentifier (UUID) URN + Namespace"; + } + + typedef dotted-quad { + type string { + pattern + '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}' + + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'; + } + description + "An unsigned 32-bit number expressed in the dotted-quad + notation, i.e., four octets written as decimal numbers + and separated with the '.' (full stop) character."; + } + } +