* Added a "user" parameter to plugin_credentials() restconf callback.
To enable authentication and in preparation for access control a la RFC 6536. * yang string length "max" keyword set to MAXPATHLEN
This commit is contained in:
parent
3ffe68d124
commit
e40d785d5c
12 changed files with 514 additions and 34 deletions
|
|
@ -3,6 +3,7 @@
|
|||
## 3.5.0 (Upcoming)
|
||||
|
||||
### Major changes:
|
||||
* Added a "user" parameter to plugin_credentials() restconf callback. To enable authentication and in preparation for access control a la RFC 6536.
|
||||
* Major Restconf feature update to compy to RFC 8040. Thanks Stephen Jones for getting right.
|
||||
* GET well-known, top-level resource, yang library version,
|
||||
* PUT whole datastore, check for different keys in put lists.
|
||||
|
|
@ -10,7 +11,7 @@
|
|||
|
||||
### Minor changes:
|
||||
|
||||
|
||||
* Added RFC 6536 ietf-netconf-acm@2012-02-22.yang access control (but not implemented).
|
||||
* The following backward compatible options to configure have been obsoleted. If you havent already migrated this code you must do this now.
|
||||
* Backend startup modes prior to 3.3.3. As enabled with `configure --with-startup-compat`. Configure option CLICON_USE_STARTUP_CONFIG is also obsoleted.
|
||||
* Configuration files (non-XML) prior to 3.3.3. As enabled with `configure --with-config-compat`. The template clicon.conf.cpp files are also removed.
|
||||
|
|
@ -25,6 +26,7 @@
|
|||
* /etc/clixon.xml
|
||||
|
||||
### Corrected Bugs
|
||||
* yang string length "max" keyword set to MAXPATHLEN
|
||||
* Corrected "No yang spec" printed on tty on leafref CLI usage
|
||||
* xml2cvec: range error (eg 1000 for int8) is not treated as error, just log and skip.
|
||||
|
||||
|
|
|
|||
|
|
@ -238,12 +238,21 @@ yang2cli_var_sub(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
else{ /* Cligen does not have 'max' keyword in range so need to find actual
|
||||
max value of type if yang range expression is 0..max */
|
||||
if ((r = cvtype_max2str_dup(cvtype)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvtype_max2str");
|
||||
goto done;
|
||||
max value of type if yang range expression is 0..max
|
||||
*/
|
||||
if (cvtype==CGV_STRING){
|
||||
if ((r = malloc(512)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
snprintf(r, 512, "%d", MAXPATHLEN);
|
||||
}
|
||||
else if ((r = cvtype_max2str_dup(cvtype)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvtype_max2str");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
cprintf(cb, "%s]", r);
|
||||
free(r);
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@
|
|||
* Returns an expand-type list of commands as used by cligen 'expand'
|
||||
* functionality.
|
||||
*
|
||||
* Assume callback given in a cligen spec: a <x:int expand_dbvar("arg")
|
||||
* Assume callback given in a cligen spec: a <x:int expand_dbvar("db" "<xmlkeyfmt>")
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] name Name of this function (eg "expand_dbvar")
|
||||
* @param[in] cvv The command so far. Eg: cvec [0]:"a 5 b"; [1]: x=5;
|
||||
|
|
|
|||
|
|
@ -296,11 +296,10 @@ readdata(FCGX_Request *r)
|
|||
return cb;
|
||||
}
|
||||
|
||||
typedef int (credentials_t)(clicon_handle h, FCGX_Request *r);
|
||||
|
||||
static int nplugins = 0;
|
||||
static plghndl_t *plugins = NULL;
|
||||
static credentials_t *p_credentials = NULL; /* Credentials callback */
|
||||
static plgcredentials_t *_credentials_fn = NULL; /* Credentials callback */
|
||||
|
||||
/*! Load all plugins you can find in CLICON_RESTCONF_DIR
|
||||
*/
|
||||
|
|
@ -330,7 +329,7 @@ restconf_plugin_load(clicon_handle h)
|
|||
(int)strlen(filename), filename);
|
||||
if ((handle = plugin_load(h, filename, RTLD_NOW)) == NULL)
|
||||
goto quit;
|
||||
p_credentials = dlsym(handle, PLUGIN_CREDENTIALS);
|
||||
_credentials_fn = dlsym(handle, PLUGIN_CREDENTIALS);
|
||||
if ((plugins = realloc(plugins, (nplugins+1) * sizeof (*plugins))) == NULL) {
|
||||
clicon_err(OE_UNIX, errno, "realloc");
|
||||
goto quit;
|
||||
|
|
@ -385,23 +384,24 @@ restconf_plugin_start(clicon_handle h,
|
|||
}
|
||||
|
||||
int
|
||||
plugin_credentials(clicon_handle h,
|
||||
FCGX_Request *r,
|
||||
int *auth)
|
||||
restconf_credentials(clicon_handle h,
|
||||
FCGX_Request *r,
|
||||
char **user)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
/* If no authentication callback then allow anything. Is this OK? */
|
||||
if (p_credentials == 0){
|
||||
*auth = 1;
|
||||
if (_credentials_fn == NULL){
|
||||
if ((*user = strdup("none")) == NULL){
|
||||
clicon_err(OE_XML, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
if (p_credentials(h, r) < 0)
|
||||
*auth = 0;
|
||||
else
|
||||
*auth = 1;
|
||||
if (_credentials_fn(h, r, user) < 0)
|
||||
user = NULL;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ cbuf *readdata(FCGX_Request *r);
|
|||
int restconf_plugin_load(clicon_handle h);
|
||||
int restconf_plugin_start(clicon_handle h, int argc, char **argv);
|
||||
int restconf_plugin_unload(clicon_handle h);
|
||||
int plugin_credentials(clicon_handle h, FCGX_Request *r, int *auth);
|
||||
int restconf_credentials(clicon_handle h, FCGX_Request *r, char **user);
|
||||
int get_user_cookie(char *cookiestr, char *attribute, char **val);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -142,7 +142,8 @@ api_operations(clicon_handle h,
|
|||
cvec *pcvec,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
char *data)
|
||||
char *data,
|
||||
char *username)
|
||||
{
|
||||
int retval = -1;
|
||||
char *request_method;
|
||||
|
|
@ -153,7 +154,7 @@ api_operations(clicon_handle h,
|
|||
if (strcmp(request_method, "GET")==0)
|
||||
retval = api_operation_get(h, r, path, pcvec, pi, qvec, data);
|
||||
else if (strcmp(request_method, "POST")==0)
|
||||
retval = api_operation_post(h, r, path, pcvec, pi, qvec, data);
|
||||
retval = api_operation_post(h, r, path, pcvec, pi, qvec, data, username);
|
||||
else
|
||||
retval = notfound(r);
|
||||
return retval;
|
||||
|
|
@ -275,7 +276,7 @@ api_restconf(clicon_handle h,
|
|||
cvec *pcvec = NULL; /* for rest api */
|
||||
cbuf *cb = NULL;
|
||||
char *data;
|
||||
int auth = 0;
|
||||
char *username = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
path = FCGX_GetParam("REQUEST_URI", r->envp);
|
||||
|
|
@ -318,20 +319,21 @@ api_restconf(clicon_handle h,
|
|||
|
||||
retval = 0;
|
||||
test(r, 1);
|
||||
/* If present, check credentials */
|
||||
if (plugin_credentials(h, r, &auth) < 0)
|
||||
/* If present, check credentials. See "plugin_credentials" in plugin
|
||||
* See RFC 8040 section 2.5
|
||||
*/
|
||||
if (restconf_credentials(h, r, &username) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s credentials ok auth:%d (should be 1)",
|
||||
__FUNCTION__, auth);
|
||||
if (auth == 0)
|
||||
clicon_debug(1, "%s credentials ok username:%s (should be non-NULL)",
|
||||
__FUNCTION__, username);
|
||||
if (username == NULL)
|
||||
goto done;
|
||||
clicon_debug(1, "%s credentials ok 2", __FUNCTION__);
|
||||
if (strcmp(method, "yang-library-version")==0)
|
||||
retval = api_yang_library_version(h, r);
|
||||
else if (strcmp(method, "data") == 0) /* restconf, skip /api/data */
|
||||
retval = api_data(h, r, path, pcvec, 2, qvec, data);
|
||||
else if (strcmp(method, "operations") == 0) /* rpc */
|
||||
retval = api_operations(h, r, path, pcvec, 2, qvec, data);
|
||||
retval = api_operations(h, r, path, pcvec, 2, qvec, data, username);
|
||||
else if (strcmp(method, "test") == 0)
|
||||
retval = test(r, 0);
|
||||
else
|
||||
|
|
@ -348,6 +350,8 @@ api_restconf(clicon_handle h,
|
|||
cvec_free(pcvec);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (username)
|
||||
free(username);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -846,7 +846,8 @@ api_operation_post(clicon_handle h,
|
|||
cvec *pcvec,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
char *data)
|
||||
char *data,
|
||||
char *username)
|
||||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
|
|
@ -869,7 +870,8 @@ api_operation_post(clicon_handle h,
|
|||
char *media_accept;
|
||||
int use_xml = 0; /* By default return JSON */
|
||||
int pretty;
|
||||
|
||||
cxobj *xa;
|
||||
|
||||
clicon_debug(1, "%s json:\"%s\" path:\"%s\"", __FUNCTION__, data, path);
|
||||
pretty = clicon_option_bool(h, "CLICON_RESTCONF_PRETTY");
|
||||
if ((media_accept = FCGX_GetParam("HTTP_ACCEPT", r->envp)) &&
|
||||
|
|
@ -939,8 +941,17 @@ api_operation_post(clicon_handle h,
|
|||
}
|
||||
}
|
||||
}
|
||||
/* Non-standard: add cookie as attribute for backend
|
||||
/* Non-standard: add username attribute for backend ACM (RFC 6536)
|
||||
*
|
||||
*/
|
||||
if (username){
|
||||
if ((xa = xml_new("username", xtop, NULL)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, username) < 0)
|
||||
goto done;
|
||||
}
|
||||
#ifdef obsolete
|
||||
{
|
||||
cxobj *xa;
|
||||
char *cookie;
|
||||
|
|
@ -957,6 +968,7 @@ api_operation_post(clicon_handle h,
|
|||
free(cookieval);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Send to backend */
|
||||
if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ int api_operation_get(clicon_handle h, FCGX_Request *r,
|
|||
|
||||
int api_operation_post(clicon_handle h, FCGX_Request *r,
|
||||
char *path,
|
||||
cvec *pcvec, int pi, cvec *qvec, char *data);
|
||||
cvec *pcvec, int pi, cvec *qvec, char *data,
|
||||
char *username);
|
||||
|
||||
#endif /* _RESTCONF_METHODS_H_ */
|
||||
|
|
|
|||
|
|
@ -77,7 +77,10 @@ typedef int (plgexit_t)(clicon_handle); /* Plugin exit */
|
|||
* Returns 0 if credentials OK, -1 if failed
|
||||
*/
|
||||
#define PLUGIN_CREDENTIALS "plugin_credentials"
|
||||
typedef int (plgcredentials_t)(clicon_handle, void *); /* Plugin credentials */
|
||||
/* Plugin credentials
|
||||
* username should be freed after use
|
||||
*/
|
||||
typedef int (plgcredentials_t)(clicon_handle, void *, char **username);
|
||||
|
||||
/* Find a function in global namespace or a plugin. XXX clicon internal */
|
||||
void *clicon_find_func(clicon_handle h, char *plugin, char *func);
|
||||
|
|
|
|||
|
|
@ -1704,6 +1704,7 @@ xml_apply_ancestor(cxobj *xn,
|
|||
* @param[out] cvp CLIgen variable containing the parsed value
|
||||
* @note free cv with cv_free after use.
|
||||
* @see xml_body_int32 etc, for type-specific parse functions
|
||||
* @note range check failure returns 0
|
||||
*/
|
||||
int
|
||||
xml_body_parse(cxobj *xb,
|
||||
|
|
@ -1751,6 +1752,7 @@ xml_body_parse(cxobj *xb,
|
|||
* alloc error.
|
||||
* @note extend to all other cligen var types and generalize
|
||||
* @note use yang type info?
|
||||
* @note range check failure returns 0
|
||||
*/
|
||||
int
|
||||
xml_body_int32(cxobj *xb,
|
||||
|
|
@ -1774,6 +1776,7 @@ xml_body_int32(cxobj *xb,
|
|||
* alloc error.
|
||||
* @note extend to all other cligen var types and generalize
|
||||
* @note use yang type info?
|
||||
* @note range check failure returns 0
|
||||
*/
|
||||
int
|
||||
xml_body_uint32(cxobj *xb,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ datarootdir = @datarootdir@
|
|||
|
||||
YANGSPECS = clixon-config@2017-12-27.yang
|
||||
YANGSPECS += ietf-netconf@2011-06-01.yang
|
||||
YANGSPECS += ietf-netconf-acm@2012-02-22.yang
|
||||
YANGSPECS += ietf-inet-types@2013-07-15.yang
|
||||
|
||||
APPNAME = clixon # subdir ehere these files are installed
|
||||
|
|
|
|||
445
yang/ietf-netconf-acm@2012-02-22.yang
Normal file
445
yang/ietf-netconf-acm@2012-02-22.yang
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
module ietf-netconf-acm {
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm";
|
||||
prefix "nacm";
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <http://tools.ietf.org/wg/netconf/>
|
||||
WG List: <mailto:netconf@ietf.org>
|
||||
|
||||
WG Chair: Mehmet Ersue
|
||||
<mailto:mehmet.ersue@nsn.com>
|
||||
|
||||
WG Chair: Bert Wijnen
|
||||
<mailto:bertietf@bwijnen.net>
|
||||
|
||||
Editor: Andy Bierman
|
||||
<mailto:andy@yumaworks.com>
|
||||
|
||||
Editor: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com>";
|
||||
|
||||
description
|
||||
"NETCONF Access Control Model.
|
||||
|
||||
Copyright (c) 2012 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 6536; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision "2012-02-22" {
|
||||
description
|
||||
"Initial version";
|
||||
reference
|
||||
"RFC 6536: Network Configuration Protocol (NETCONF)
|
||||
Access Control Model";
|
||||
}
|
||||
|
||||
/*
|
||||
* Extension statements
|
||||
*/
|
||||
|
||||
extension default-deny-write {
|
||||
description
|
||||
"Used to indicate that the data model node
|
||||
represents a sensitive security system parameter.
|
||||
|
||||
If present, and the NACM module is enabled (i.e.,
|
||||
/nacm/enable-nacm object equals 'true'), the NETCONF server
|
||||
will only allow the designated 'recovery session' to have
|
||||
write access to the node. An explicit access control rule is
|
||||
required for all other users.
|
||||
|
||||
The 'default-deny-write' extension MAY appear within a data
|
||||
definition statement. It is ignored otherwise.";
|
||||
}
|
||||
|
||||
extension default-deny-all {
|
||||
description
|
||||
"Used to indicate that the data model node
|
||||
controls a very sensitive security system parameter.
|
||||
|
||||
If present, and the NACM module is enabled (i.e.,
|
||||
/nacm/enable-nacm object equals 'true'), the NETCONF server
|
||||
will only allow the designated 'recovery session' to have
|
||||
read, write, or execute access to the node. An explicit
|
||||
access control rule is required for all other users.
|
||||
|
||||
The 'default-deny-all' extension MAY appear within a data
|
||||
definition statement, 'rpc' statement, or 'notification'
|
||||
statement. It is ignored otherwise.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Derived types
|
||||
*/
|
||||
|
||||
typedef user-name-type {
|
||||
type string {
|
||||
length "1..max";
|
||||
}
|
||||
description
|
||||
"General Purpose Username string.";
|
||||
}
|
||||
|
||||
typedef matchall-string-type {
|
||||
type string {
|
||||
pattern "\*";
|
||||
}
|
||||
description
|
||||
"The string containing a single asterisk '*' is used
|
||||
to conceptually represent all possible values
|
||||
for the particular leaf using this data type.";
|
||||
}
|
||||
|
||||
typedef access-operations-type {
|
||||
type bits {
|
||||
bit create {
|
||||
description
|
||||
"Any protocol operation that creates a
|
||||
new data node.";
|
||||
}
|
||||
bit read {
|
||||
description
|
||||
"Any protocol operation or notification that
|
||||
returns the value of a data node.";
|
||||
}
|
||||
bit update {
|
||||
description
|
||||
"Any protocol operation that alters an existing
|
||||
data node.";
|
||||
}
|
||||
bit delete {
|
||||
description
|
||||
"Any protocol operation that removes a data node.";
|
||||
}
|
||||
bit exec {
|
||||
description
|
||||
"Execution access to the specified protocol operation.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"NETCONF Access Operation.";
|
||||
}
|
||||
|
||||
typedef group-name-type {
|
||||
type string {
|
||||
length "1..max";
|
||||
pattern "[^\*].*";
|
||||
}
|
||||
description
|
||||
"Name of administrative group to which
|
||||
users can be assigned.";
|
||||
}
|
||||
|
||||
typedef action-type {
|
||||
type enumeration {
|
||||
enum permit {
|
||||
description
|
||||
"Requested action is permitted.";
|
||||
}
|
||||
enum deny {
|
||||
description
|
||||
"Requested action is denied.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Action taken by the server when a particular
|
||||
rule matches.";
|
||||
}
|
||||
|
||||
typedef node-instance-identifier {
|
||||
type yang:xpath1.0;
|
||||
description
|
||||
"Path expression used to represent a special
|
||||
data node instance identifier string.
|
||||
|
||||
A node-instance-identifier value is an
|
||||
unrestricted YANG instance-identifier expression.
|
||||
All the same rules as an instance-identifier apply
|
||||
except predicates for keys are optional. If a key
|
||||
predicate is missing, then the node-instance-identifier
|
||||
represents all possible server instances for that key.
|
||||
|
||||
This XPath expression is evaluated in the following context:
|
||||
|
||||
o The set of namespace declarations are those in scope on
|
||||
the leaf element where this type is used.
|
||||
|
||||
o The set of variable bindings contains one variable,
|
||||
'USER', which contains the name of the user of the current
|
||||
session.
|
||||
|
||||
o The function library is the core function library, but
|
||||
note that due to the syntax restrictions of an
|
||||
instance-identifier, no functions are allowed.
|
||||
|
||||
o The context node is the root node in the data tree.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Data definition statements
|
||||
*/
|
||||
|
||||
container nacm {
|
||||
/* nacm:default-deny-all; XXX How is this parsed ?? */
|
||||
|
||||
description
|
||||
"Parameters for NETCONF Access Control Model.";
|
||||
|
||||
leaf enable-nacm {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"Enables or disables all NETCONF access control
|
||||
enforcement. If 'true', then enforcement
|
||||
is enabled. If 'false', then enforcement
|
||||
is disabled.";
|
||||
}
|
||||
|
||||
leaf read-default {
|
||||
type action-type;
|
||||
default "permit";
|
||||
description
|
||||
"Controls whether read access is granted if
|
||||
no appropriate rule is found for a
|
||||
particular read request.";
|
||||
}
|
||||
|
||||
leaf write-default {
|
||||
type action-type;
|
||||
default "deny";
|
||||
description
|
||||
"Controls whether create, update, or delete access
|
||||
is granted if no appropriate rule is found for a
|
||||
particular write request.";
|
||||
}
|
||||
|
||||
leaf exec-default {
|
||||
type action-type;
|
||||
default "permit";
|
||||
description
|
||||
"Controls whether exec access is granted if no appropriate
|
||||
rule is found for a particular protocol operation request.";
|
||||
}
|
||||
|
||||
leaf enable-external-groups {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"Controls whether the server uses the groups reported by the
|
||||
NETCONF transport layer when it assigns the user to a set of
|
||||
NACM groups. If this leaf has the value 'false', any group
|
||||
names reported by the transport layer are ignored by the
|
||||
server.";
|
||||
}
|
||||
|
||||
leaf denied-operations {
|
||||
type yang:zero-based-counter32;
|
||||
config false;
|
||||
mandatory true;
|
||||
description
|
||||
"Number of times since the server last restarted that a
|
||||
protocol operation request was denied.";
|
||||
}
|
||||
|
||||
leaf denied-data-writes {
|
||||
type yang:zero-based-counter32;
|
||||
config false;
|
||||
mandatory true;
|
||||
description
|
||||
"Number of times since the server last restarted that a
|
||||
protocol operation request to alter
|
||||
a configuration datastore was denied.";
|
||||
}
|
||||
|
||||
leaf denied-notifications {
|
||||
type yang:zero-based-counter32;
|
||||
config false;
|
||||
mandatory true;
|
||||
description
|
||||
"Number of times since the server last restarted that
|
||||
a notification was dropped for a subscription because
|
||||
access to the event type was denied.";
|
||||
}
|
||||
|
||||
container groups {
|
||||
description
|
||||
"NETCONF Access Control Groups.";
|
||||
|
||||
list group {
|
||||
key name;
|
||||
|
||||
description
|
||||
"One NACM Group Entry. This list will only contain
|
||||
configured entries, not any entries learned from
|
||||
any transport protocols.";
|
||||
|
||||
leaf name {
|
||||
type group-name-type;
|
||||
description
|
||||
"Group name associated with this entry.";
|
||||
}
|
||||
|
||||
leaf-list user-name {
|
||||
type user-name-type;
|
||||
description
|
||||
"Each entry identifies the username of
|
||||
a member of the group associated with
|
||||
this entry.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list rule-list {
|
||||
key "name";
|
||||
ordered-by user;
|
||||
description
|
||||
"An ordered collection of access control rules.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length "1..max";
|
||||
}
|
||||
description
|
||||
"Arbitrary name assigned to the rule-list.";
|
||||
}
|
||||
leaf-list group {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type group-name-type;
|
||||
}
|
||||
description
|
||||
"List of administrative groups that will be
|
||||
assigned the associated access rights
|
||||
defined by the 'rule' list.
|
||||
|
||||
The string '*' indicates that all groups apply to the
|
||||
entry.";
|
||||
}
|
||||
|
||||
list rule {
|
||||
key "name";
|
||||
ordered-by user;
|
||||
description
|
||||
"One access control rule.
|
||||
|
||||
Rules are processed in user-defined order until a match is
|
||||
found. A rule matches if 'module-name', 'rule-type', and
|
||||
'access-operations' match the request. If a rule
|
||||
matches, the 'action' leaf determines if access is granted
|
||||
or not.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length "1..max";
|
||||
}
|
||||
description
|
||||
"Arbitrary name assigned to the rule.";
|
||||
}
|
||||
|
||||
leaf module-name {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type string;
|
||||
}
|
||||
default "*";
|
||||
description
|
||||
"Name of the module associated with this rule.
|
||||
|
||||
This leaf matches if it has the value '*' or if the
|
||||
object being accessed is defined in the module with the
|
||||
specified module name.";
|
||||
}
|
||||
choice rule-type {
|
||||
description
|
||||
"This choice matches if all leafs present in the rule
|
||||
match the request. If no leafs are present, the
|
||||
choice matches all requests.";
|
||||
case protocol-operation {
|
||||
leaf rpc-name {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type string;
|
||||
}
|
||||
description
|
||||
"This leaf matches if it has the value '*' or if
|
||||
its value equals the requested protocol operation
|
||||
name.";
|
||||
}
|
||||
}
|
||||
case notification {
|
||||
leaf notification-name {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type string;
|
||||
}
|
||||
description
|
||||
"This leaf matches if it has the value '*' or if its
|
||||
value equals the requested notification name.";
|
||||
}
|
||||
}
|
||||
case data-node {
|
||||
leaf path {
|
||||
type node-instance-identifier;
|
||||
mandatory true;
|
||||
description
|
||||
"Data Node Instance Identifier associated with the
|
||||
data node controlled by this rule.
|
||||
|
||||
Configuration data or state data instance
|
||||
identifiers start with a top-level data node. A
|
||||
complete instance identifier is required for this
|
||||
type of path value.
|
||||
|
||||
The special value '/' refers to all possible
|
||||
datastore contents.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leaf access-operations {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type access-operations-type;
|
||||
}
|
||||
default "*";
|
||||
description
|
||||
"Access operations associated with this rule.
|
||||
|
||||
This leaf matches if it has the value '*' or if the
|
||||
bit corresponding to the requested operation is set.";
|
||||
}
|
||||
|
||||
leaf action {
|
||||
type action-type;
|
||||
mandatory true;
|
||||
description
|
||||
"The access control action associated with the
|
||||
rule. If a rule is determined to match a
|
||||
particular request, then this object is used
|
||||
to determine whether to permit or deny the
|
||||
request.";
|
||||
}
|
||||
|
||||
leaf comment {
|
||||
type string;
|
||||
description
|
||||
"A textual description of the access rule.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue