* Experimental NACM RFC8341 Network Configuration Access Control Model.
* CLICON_NACM_MODE config option, default is disabled. * Added username attribute to all rpc:s from frontend to backend * Added NACM backend module in example
This commit is contained in:
parent
04a3f4db1b
commit
7650803475
32 changed files with 908 additions and 274 deletions
|
|
@ -45,7 +45,7 @@ CFLAGS = @CFLAGS@ -rdynamic -fPIC
|
|||
INCLUDES = -I$(includedir) @INCLUDES@
|
||||
|
||||
BE_PLUGIN = $(APPNAME)_backend.so
|
||||
BE2_PLUGIN = $(APPNAME)_backend_secondary.so
|
||||
BE2_PLUGIN = $(APPNAME)_backend_nacm.so
|
||||
CLI_PLUGIN = $(APPNAME)_cli.so
|
||||
NETCONF_PLUGIN = $(APPNAME)_netconf.so
|
||||
RESTCONF_PLUGIN = $(APPNAME)_restconf.so
|
||||
|
|
@ -75,8 +75,8 @@ BE_OBJ = $(BE_SRC:%.c=%.o)
|
|||
$(BE_PLUGIN): $(BE_OBJ)
|
||||
$(CC) -Wall -shared -o $@ -lc $<
|
||||
|
||||
# Secondary backend plugin
|
||||
BE2_SRC = $(APPNAME)_backend_secondary.c
|
||||
# Secondary NACM backend plugin
|
||||
BE2_SRC = $(APPNAME)_backend_nacm.c
|
||||
BE2_OBJ = $(BE2_SRC:%.c=%.o)
|
||||
$(BE2_PLUGIN): $(BE2_OBJ)
|
||||
$(CC) -Wall -shared -o $@ -lc $<
|
||||
|
|
|
|||
|
|
@ -6,23 +6,30 @@ module example {
|
|||
import ietf-routing {
|
||||
prefix rt;
|
||||
}
|
||||
import ietf-netconf-acm {
|
||||
prefix nacm;
|
||||
}
|
||||
description
|
||||
"Example code that includes ietf-ip and ietf-routing";
|
||||
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;
|
||||
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;
|
||||
}
|
||||
leaf password{
|
||||
description "Password";
|
||||
type string;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
rpc client-rpc {
|
||||
|
|
|
|||
|
|
@ -251,22 +251,18 @@ plugin_start(clicon_handle h,
|
|||
clixon_plugin_api *clixon_plugin_init(clicon_handle h);
|
||||
|
||||
static clixon_plugin_api api = {
|
||||
"example", /* name */
|
||||
"example", /* name */ /*--- Common fields. ---*/
|
||||
clixon_plugin_init, /* init */
|
||||
plugin_start, /* start */
|
||||
NULL, /* exit */
|
||||
NULL, /* auth */
|
||||
NULL, /* cli prompt */
|
||||
NULL, /* cli suspend */
|
||||
NULL, /* cli interrupt */
|
||||
plugin_reset, /* reset */
|
||||
plugin_statedata, /* statedata */
|
||||
NULL, /* trans begin */
|
||||
transaction_validate,/* trans validate */
|
||||
NULL, /* trans complete */
|
||||
transaction_commit, /* trans commit */
|
||||
NULL, /* trans end */
|
||||
NULL /* trans abort */
|
||||
.ca_reset=plugin_reset,/* reset */ /*--- Backend plugin only ---*/
|
||||
.ca_statedata=plugin_statedata, /* statedata */
|
||||
.ca_trans_begin=NULL, /* trans begin */
|
||||
.ca_trans_validate=transaction_validate,/* trans validate */
|
||||
.ca_trans_complete=NULL, /* trans complete */
|
||||
.ca_trans_commit=transaction_commit, /* trans commit */
|
||||
.ca_trans_end=NULL, /* trans end */
|
||||
.ca_trans_abort=NULL /* trans abort */
|
||||
};
|
||||
|
||||
/*! Backend plugin initialization
|
||||
|
|
|
|||
|
|
@ -55,16 +55,41 @@
|
|||
#include <clixon/clixon_backend.h>
|
||||
|
||||
|
||||
int
|
||||
transaction_commit_2(clicon_handle h,
|
||||
transaction_data td)
|
||||
/*! Called to get NACM state data
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||
* @param[in] xtop XML tree, <config/> on entry.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see xmldb_get
|
||||
* @note this example code returns a static statedata used in testing.
|
||||
* Real code would poll state
|
||||
*/
|
||||
int
|
||||
nacm_statedata(clicon_handle h,
|
||||
char *xpath,
|
||||
cxobj *xstate)
|
||||
{
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
return 0;
|
||||
int retval = -1;
|
||||
cxobj **xvec = NULL;
|
||||
|
||||
/* Example of (static) statedata, real code would poll state */
|
||||
if (xml_parse_string("<nacm>"
|
||||
"<denied-data-writes>0</denied-data-writes>"
|
||||
"<denied-operations>0</denied-operations>"
|
||||
"<denied-notifications>0</denied-notifications>"
|
||||
"</nacm>", NULL, &xstate) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xvec)
|
||||
free(xvec);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
plugin_start_2(clicon_handle h,
|
||||
plugin_start(clicon_handle h,
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
|
|
@ -74,19 +99,12 @@ plugin_start_2(clicon_handle h,
|
|||
clixon_plugin_api *clixon_plugin_init(clicon_handle h);
|
||||
|
||||
static clixon_plugin_api api = {
|
||||
"secondary", /* name */
|
||||
"nacm", /* name */ /*--- Common fields. ---*/
|
||||
clixon_plugin_init, /* init */
|
||||
plugin_start_2, /* start */
|
||||
plugin_start, /* start */
|
||||
NULL, /* exit */
|
||||
NULL, /* auth */
|
||||
NULL, /* reset */
|
||||
NULL, /* statedata */
|
||||
NULL, /* trans begin */
|
||||
NULL, /* trans validate */
|
||||
NULL, /* trans complete */
|
||||
transaction_commit_2,/* trans commit */
|
||||
NULL, /* trans end */
|
||||
NULL /* trans abort */
|
||||
.ca_reset=NULL, /* reset */ /*--- Backend plugin only ---*/
|
||||
.ca_statedata=nacm_statedata, /* statedata */
|
||||
};
|
||||
|
||||
/*! Backend plugin initialization
|
||||
|
|
@ -117,10 +117,9 @@ static clixon_plugin_api api = {
|
|||
clixon_plugin_init, /* init */
|
||||
NULL, /* start */
|
||||
NULL, /* exit */
|
||||
NULL, /* auth */
|
||||
NULL, /* cli_prompthook_t */
|
||||
NULL, /* cligen_susp_cb_t */
|
||||
NULL, /* cligen_interrupt_cb_t */
|
||||
.ca_prompt=NULL, /* cli_prompthook_t */
|
||||
.ca_suspend=NULL, /* cligen_susp_cb_t */
|
||||
.ca_interrupt=NULL, /* cligen_interrupt_cb_t */
|
||||
};
|
||||
|
||||
/*! CLI plugin initialization
|
||||
|
|
|
|||
|
|
@ -81,8 +81,7 @@ static struct clixon_plugin_api api = {
|
|||
"example", /* name */
|
||||
clixon_plugin_init, /* init */
|
||||
plugin_start, /* start */
|
||||
plugin_exit, /* exit */
|
||||
NULL /* auth */
|
||||
plugin_exit /* exit */
|
||||
};
|
||||
|
||||
/*! Netconf plugin initialization
|
||||
|
|
|
|||
|
|
@ -180,7 +180,6 @@ b64_decode(const char *src,
|
|||
return (tarindex);
|
||||
}
|
||||
|
||||
|
||||
/*! Process a rest request that requires (cookie) "authentication"
|
||||
* Note, this is loaded as dlsym fixed symbol in plugin
|
||||
* @param[in] h Clixon handle
|
||||
|
|
@ -188,7 +187,7 @@ b64_decode(const char *src,
|
|||
* @retval -1 Fatal error
|
||||
* @retval 0 Unauth
|
||||
* @retval 1 Auth
|
||||
* For grideye, return "u" entry name if it has a valid "user" entry.
|
||||
*
|
||||
*/
|
||||
int
|
||||
plugin_credentials(clicon_handle h,
|
||||
|
|
@ -206,12 +205,17 @@ plugin_credentials(clicon_handle h,
|
|||
size_t authlen;
|
||||
cbuf *cb = NULL;
|
||||
int ret;
|
||||
|
||||
|
||||
/* 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", "/", &xt) < 0)
|
||||
if (clicon_rpc_get_config(h, "running", "authentication", &xt) < 0)
|
||||
goto done;
|
||||
if ((x = xpath_first(xt, "basic_auth")) == NULL)
|
||||
if (clicon_username_set(h, "none") < 0)
|
||||
goto done;
|
||||
if ((x = xpath_first(xt, "authentication/basic_auth")) == NULL)
|
||||
goto ok;
|
||||
if ((xbody = xml_body(x)) == NULL)
|
||||
goto ok;
|
||||
|
|
@ -219,8 +223,8 @@ plugin_credentials(clicon_handle h,
|
|||
goto ok;
|
||||
/* At this point in the code we must use HTTP basic authentication */
|
||||
if ((auth = FCGX_GetParam("HTTP_AUTHORIZATION", r->envp)) == NULL)
|
||||
goto fail;
|
||||
if (strlen(auth) < strlen("Basic "))
|
||||
goto fail;
|
||||
if (strlen(auth) < strlen("Basic "))
|
||||
goto fail;
|
||||
if (strncmp("Basic ", auth, strlen("Basic ")))
|
||||
goto fail;
|
||||
|
|
@ -239,15 +243,18 @@ plugin_credentials(clicon_handle h,
|
|||
*passwd = '\0';
|
||||
passwd++;
|
||||
clicon_debug(1, "%s user:%s passwd:%s", __FUNCTION__, user, passwd);
|
||||
/* Here get auth sub-tree whjere all the users are */
|
||||
if ((cb = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
cprintf(cb, "auth[user=%s]", user);
|
||||
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;
|
||||
retval = 1;
|
||||
clicon_debug(1, "%s user:%s", __FUNCTION__, user);
|
||||
if (clicon_username_set(h, user) < 0)
|
||||
goto done;
|
||||
ok: /* authenticated */
|
||||
|
|
@ -281,7 +288,6 @@ restconf_client_rpc(clicon_handle h,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
clixon_plugin_api * clixon_plugin_init(clicon_handle h);
|
||||
|
||||
static clixon_plugin_api api = {
|
||||
|
|
@ -289,7 +295,7 @@ static clixon_plugin_api api = {
|
|||
clixon_plugin_init, /* init */
|
||||
NULL, /* start */
|
||||
NULL, /* exit */
|
||||
plugin_credentials /* auth */
|
||||
.ca_auth=plugin_credentials /* auth */
|
||||
};
|
||||
|
||||
/*! Restconf plugin initialization
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue