* Restructure and more generic plugin API (cli,backend,restconf,netconf)
* For preparation for authorization RFC8341
* Plugins add clixon_plugin_init() and api struct for function pointers, eg:
```
static const struct clixon_plugin_api api = {
"example",
clixon_plugin_init,
...
}
clixon_plugin_api *clixon_plugin_init(clicon_handle h)
{
return (void*)&api;
}
```
* Moved specific plugin functions from apps/ to generic functions in lib/
* New generic plugin load function: clixon_plugins_load()
* Removed client-local netconf plugins netconf_plugin_callbacks()
* This was code used before generic YANG rpc calls
* Added username to clixon handle:
* clicon_username_get() / clicon_username_set()
* Added authentication plugin callback
* Removed some obscure plugin code that seem not to be used (please report if needed!)
* CLI parse hook
* CLICON_FIND_PLUGIN
* clicon_valcb()
* Removed username to rpc calls (added below)
This commit is contained in:
parent
b8e35742b9
commit
79e3fbdaa9
41 changed files with 470 additions and 772 deletions
29
CHANGELOG.md
29
CHANGELOG.md
|
|
@ -4,6 +4,32 @@
|
|||
|
||||
|
||||
### Major changes:
|
||||
* Restructure and more generic plugin API (cli,backend,restconf,netconf)
|
||||
* For preparation for authorization RFC8341
|
||||
* Plugins add clixon_plugin_init() and api struct for function pointers, eg:
|
||||
```
|
||||
static const struct clixon_plugin_api api = {
|
||||
"example",
|
||||
clixon_plugin_init,
|
||||
...
|
||||
}
|
||||
clixon_plugin_api *clixon_plugin_init(clicon_handle h)
|
||||
{
|
||||
return (void*)&api;
|
||||
}
|
||||
```
|
||||
* Moved specific plugin functions from apps/ to generic functions in lib/
|
||||
* New generic plugin load function: clixon_plugins_load()
|
||||
* Removed client-local netconf plugins netconf_plugin_callbacks()
|
||||
* This was code used before generic YANG rpc calls
|
||||
* Added username to clixon handle:
|
||||
* clicon_username_get() / clicon_username_set()
|
||||
* Added authentication plugin callback
|
||||
* Removed some obscure plugin code that seem not to be used (please report if needed!)
|
||||
* CLI parse hook
|
||||
* CLICON_FIND_PLUGIN
|
||||
* clicon_valcb()
|
||||
|
||||
* Added Clixon Restconf library
|
||||
* Builds and installs a new restconf library: libclixon_restconf.so and clixon_restconf.h
|
||||
* The restconf library can be included by a restconf plugin.
|
||||
|
|
@ -20,6 +46,7 @@
|
|||
|
||||
### Minor changes:
|
||||
|
||||
* Removed username to rpc calls (added below)
|
||||
* README.md extended with new yang, netconf, restconf, datastore, and auth sections.
|
||||
* The key-value datastore is no longer supported. Use the default text datastore.
|
||||
* Add username to rpc calls to prepare for authorization for backend:
|
||||
|
|
@ -92,7 +119,7 @@ enables saved files to be used as datastore without any editing. Thanks Matt.
|
|||
* New CLICON_XML_SORT configuration option. Default is true. Disable by setting to false.
|
||||
* Added yang ordered-by user. The default (ordered-by system) will now sort lists and leaf-lists alphabetically to increase search performance. Note that this may change outputs.
|
||||
* If you need legacy order, either set CLICON_XML_SORT to false, or set that list to "ordered-by user".
|
||||
* This replaces XML hash experimental code, ie xml_child_hash variables and all xml_hash_ functions have been removed.
|
||||
* This replaces XML hash experimental code, ie xml_child_hash variables and all xmlv_hash_ functions have been removed.
|
||||
* Implementation detail: Cached keys are stored in in yang Y_LIST nodes as cligen vector, see ys_populate_list()
|
||||
|
||||
* Datastore cache introduced: cache XML tree in memory for faster get access.
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ Clixon is an automatic configuration manager where you generate
|
|||
interactive CLI, NETCONF, RESTCONF and embedded databases with
|
||||
transaction support from a YANG specification.
|
||||
|
||||
Topics
|
||||
======
|
||||
* [Background](#background)
|
||||
* [Frequently asked questions](doc/FAQ.md)
|
||||
* [Installation](#installation)
|
||||
|
|
@ -38,7 +36,7 @@ Users of clixon currently include:
|
|||
* [CloudMon360](http://cloudmon360.com)
|
||||
* [Grideye](http://hagsand.se/grideye)
|
||||
* [Netclean](https://www.netclean.com/solutions/whitebox) # only CLIgen
|
||||
* [Prosilient's PTAnalyzer](http://www.prosilient.com) # only CLIgen
|
||||
* [Prosilient's PTAnalyzer](https://prosilient.com) # only CLIgen
|
||||
|
||||
See also [Clicon project page](http://clicon.org).
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@
|
|||
* @note the following should match the prototypes in clixon_backend.h
|
||||
*/
|
||||
#define PLUGIN_RESET "plugin_reset"
|
||||
typedef int (plgreset_t)(clicon_handle h, const char *db); /* Reset system status */
|
||||
|
||||
|
||||
/*! Plugin callback, if defined called to get state data from plugin
|
||||
* @param[in] h Clicon handle
|
||||
|
|
@ -82,7 +82,7 @@ typedef int (plgreset_t)(clicon_handle h, const char *db); /* Reset system statu
|
|||
* @see xmldb_get
|
||||
*/
|
||||
#define PLUGIN_STATEDATA "plugin_statedata"
|
||||
typedef int (plgstatedata_t)(clicon_handle h, char *xpath, cxobj *xtop);
|
||||
|
||||
|
||||
#define PLUGIN_TRANS_BEGIN "transaction_begin"
|
||||
#define PLUGIN_TRANS_VALIDATE "transaction_validate"
|
||||
|
|
@ -92,8 +92,6 @@ typedef int (plgstatedata_t)(clicon_handle h, char *xpath, cxobj *xtop);
|
|||
#define PLUGIN_TRANS_ABORT "transaction_abort"
|
||||
|
||||
|
||||
typedef int (trans_cb_t)(clicon_handle h, transaction_data td); /* Transaction cbs */
|
||||
|
||||
/* Backend (config) plugins */
|
||||
struct plugin {
|
||||
char p_name[PATH_MAX]; /* Plugin name */
|
||||
|
|
@ -118,28 +116,6 @@ struct plugin {
|
|||
static int _nplugins = 0;
|
||||
static struct plugin *_plugins = NULL;
|
||||
|
||||
/*! Find a plugin by name and return the dlsym handl
|
||||
* Used by libclicon code to find callback funcctions in plugins.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] h Name of plugin
|
||||
* @retval handle Plugin handle if found
|
||||
* @retval NULL Not found
|
||||
*/
|
||||
static void *
|
||||
config_find_plugin(clicon_handle h,
|
||||
char *name)
|
||||
{
|
||||
int i;
|
||||
struct plugin *p;
|
||||
|
||||
for (i = 0; i < _nplugins; i++){
|
||||
p = &_plugins[i];
|
||||
if (strcmp(p->p_name, name) == 0)
|
||||
return p->p_handle;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Initialize plugin code (not the plugins themselves)
|
||||
* @param[in] h Clicon handle
|
||||
* @retval 0 OK
|
||||
|
|
@ -148,14 +124,6 @@ config_find_plugin(clicon_handle h,
|
|||
int
|
||||
backend_plugin_init(clicon_handle h)
|
||||
{
|
||||
find_plugin_t *fp = config_find_plugin;
|
||||
clicon_hash_t *data = clicon_data(h);
|
||||
|
||||
/* Register CLICON_FIND_PLUGIN in data hash */
|
||||
if (hash_add(data, "CLICON_FIND_PLUGIN", &fp, sizeof(fp)) == NULL) {
|
||||
clicon_err(OE_UNIX, errno, "failed to register CLICON_FIND_PLUGIN");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,8 +92,6 @@ int subscription_delete(clicon_handle h, char *stream,
|
|||
struct handle_subscription *subscription_each(clicon_handle h,
|
||||
struct handle_subscription *hprev);
|
||||
|
||||
/* XXX backward compat */
|
||||
#define backend_netconf_register_callback(a,b,c,d) backend_rpc_cb_register(a,b,c,d)
|
||||
int backend_rpc_cb_register(clicon_handle h, backend_rpc_cb cb, void *arg,
|
||||
char *tag);
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ typedef int (*downcall_cb)(clicon_handle h, uint16_t op, uint16_t len,
|
|||
* (defined in config_dbdep.c)
|
||||
* @see transaction_data_t internal structure
|
||||
*/
|
||||
typedef void *transaction_data;
|
||||
uint64_t transaction_id(transaction_data td);
|
||||
void *transaction_arg(transaction_data td);
|
||||
cxobj *transaction_src(transaction_data td);
|
||||
|
|
|
|||
|
|
@ -654,13 +654,13 @@ compare_dbs(clicon_handle h,
|
|||
astext = cv_int32_get(cvec_i(argv, 0));
|
||||
else
|
||||
astext = 0;
|
||||
if (clicon_rpc_get_config(h, "running", "/", NULL, &xc1) < 0)
|
||||
if (clicon_rpc_get_config(h, "running", "/", &xc1) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xc1, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
if (clicon_rpc_get_config(h, "candidate", "/", NULL, &xc2) < 0)
|
||||
if (clicon_rpc_get_config(h, "candidate", "/", &xc2) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xc2, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
|
|
@ -827,7 +827,7 @@ save_config_file(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
filename = cv_string_get(cv);
|
||||
if (clicon_rpc_get_config(h, dbstr,"/", NULL, &xt) < 0)
|
||||
if (clicon_rpc_get_config(h, dbstr,"/", &xt) < 0)
|
||||
goto done;
|
||||
if (xt == NULL){
|
||||
clicon_err(OE_CFG, 0, "get config: empty tree"); /* Shouldnt happen */
|
||||
|
|
@ -1180,7 +1180,7 @@ cli_copy_config(clicon_handle h,
|
|||
cprintf(cb, xpath, keyname, fromname);
|
||||
|
||||
/* Get from object configuration and store in x1 */
|
||||
if (clicon_rpc_get_config(h, db, cbuf_get(cb), NULL, &x1) < 0)
|
||||
if (clicon_rpc_get_config(h, db, cbuf_get(cb), &x1) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(x1, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
|
|
|
|||
|
|
@ -66,13 +66,11 @@
|
|||
#include "cli_plugin.h"
|
||||
#include "cli_handle.h"
|
||||
|
||||
|
||||
/*! Name of master plugin functions
|
||||
* More in clicon_plugin.h
|
||||
* @note not really used consider documenting or remove
|
||||
*/
|
||||
#define PLUGIN_PROMPT_HOOK "plugin_prompt_hook"
|
||||
#define PLUGIN_PARSE_HOOK "plugin_parse_hook"
|
||||
#define PLUGIN_SUSP_HOOK "plugin_susp_hook"
|
||||
|
||||
/*
|
||||
|
|
@ -380,7 +378,6 @@ cli_plugin_load_dir(clicon_handle h,
|
|||
struct stat st;
|
||||
int retval = -1;
|
||||
|
||||
|
||||
/* Format master plugin path */
|
||||
if ((master_plugin = clicon_master_plugin(h)) == NULL){
|
||||
clicon_err(OE_PLUGIN, 0, "clicon_master_plugin option not set");
|
||||
|
|
@ -403,8 +400,6 @@ cli_plugin_load_dir(clicon_handle h,
|
|||
/* Look up certain call-backs in master plugin */
|
||||
stx->stx_prompt_hook =
|
||||
dlsym(cp->cp_handle, PLUGIN_PROMPT_HOOK);
|
||||
stx->stx_parse_hook =
|
||||
dlsym(cp->cp_handle, PLUGIN_PARSE_HOOK);
|
||||
stx->stx_susp_hook =
|
||||
dlsym(cp->cp_handle, PLUGIN_SUSP_HOOK);
|
||||
INSQ(cp, stx->stx_plugins);
|
||||
|
|
@ -679,15 +674,6 @@ clicon_parse(clicon_handle h,
|
|||
goto done;
|
||||
case CG_NOMATCH: /* no match */
|
||||
smode = NULL;
|
||||
if (stx->stx_parse_hook) {
|
||||
/* Try to find a match in upper modes, a'la IOS. */
|
||||
if ((modename = stx->stx_parse_hook(h, cmd, modename)) != NULL) {
|
||||
if ((smode = syntax_mode_find(stx, modename, 0)) != NULL)
|
||||
continue;
|
||||
else
|
||||
cli_output(f, "Can't find syntax mode '%s'\n", modename);
|
||||
}
|
||||
}
|
||||
/* clicon_err(OE_CFG, 0, "CLI syntax error: \"%s\": %s",
|
||||
cmd, cli_nomatch(h));*/
|
||||
cli_output(f, "CLI syntax error: \"%s\": %s\n",
|
||||
|
|
@ -745,42 +731,14 @@ clicon_cliread(clicon_handle h)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* cli_find_plugin
|
||||
* Find a plugin by name and return the dlsym handl
|
||||
* Used by libclicon code to find callback funcctions in plugins.
|
||||
*/
|
||||
static void *
|
||||
cli_find_plugin(clicon_handle h, char *plugin)
|
||||
{
|
||||
struct cli_plugin *p;
|
||||
|
||||
p = plugin_find_cli(cli_syntax(h), plugin);
|
||||
if (p)
|
||||
return p->cp_handle;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*! Initialize plugin code (not the plugins themselves)
|
||||
*/
|
||||
int
|
||||
cli_plugin_init(clicon_handle h)
|
||||
{
|
||||
find_plugin_t *fp = cli_find_plugin;
|
||||
clicon_hash_t *data = clicon_data(h);
|
||||
|
||||
/* Register CLICON_FIND_PLUGIN in data hash */
|
||||
if (hash_add(data, "CLICON_FIND_PLUGIN", &fp, sizeof(fp)) == NULL) {
|
||||
clicon_err(OE_UNIX, errno, "failed to register CLICON_FIND_PLUGIN");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* CLI PLUGIN INTERFACE, PUBLIC SECTION
|
||||
|
|
@ -816,7 +774,6 @@ cli_syntax_mode(clicon_handle h)
|
|||
return csm->csm_name;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Callback from cli_set_prompt(). Set prompt format for syntax mode
|
||||
* Arguments:
|
||||
|
|
@ -880,7 +837,6 @@ prompt_fmt (char *prompt, size_t plen, char *fmt, ...)
|
|||
cprintf(cb, "%c", *s);
|
||||
s++;
|
||||
}
|
||||
|
||||
done:
|
||||
if (cb)
|
||||
fmt = cbuf_get(cb);
|
||||
|
|
@ -905,55 +861,3 @@ cli_prompt(char *fmt)
|
|||
return prompt;
|
||||
}
|
||||
|
||||
/*! Find a cli plugin based on name and resolve a function pointer in it.
|
||||
* Callback from clicon_dbvars_parse()
|
||||
* Find a cli plugin based on name if given and use dlsym to resolve a
|
||||
* function pointer in it.
|
||||
* Call the resolved function to get the cgv populated
|
||||
*/
|
||||
int
|
||||
clicon_valcb(void *arg, cvec *vars, cg_var *cgv, char *fname, cg_var *funcarg)
|
||||
{
|
||||
char *func;
|
||||
char *plgnam = NULL;
|
||||
void *handle;
|
||||
struct cli_plugin *p;
|
||||
cli_valcb_t *cb;
|
||||
clicon_handle h = (clicon_handle)arg;
|
||||
|
||||
/* Make copy */
|
||||
if ((fname = strdup(fname)) == NULL) {
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Extract plugin name if any */
|
||||
if ((func = strstr(fname, "::")) != NULL) {
|
||||
*func = '\0';
|
||||
func += 2;
|
||||
plgnam = fname;
|
||||
}
|
||||
else
|
||||
func = fname;
|
||||
|
||||
/* If we have specified a plugin name, find the handle to be used
|
||||
* with dlsym()
|
||||
*/
|
||||
handle = NULL;
|
||||
if (plgnam && (p = plugin_find_cli(cli_syntax(h), plgnam)))
|
||||
handle = p->cp_handle;
|
||||
|
||||
/* Look up function pointer */
|
||||
if ((cb = dlsym(handle, func)) == NULL) {
|
||||
clicon_err(OE_UNIX, errno, "unable to find %s()", func);
|
||||
free(fname);
|
||||
return -1;
|
||||
}
|
||||
free(fname);
|
||||
|
||||
if (cb(vars, cgv, funcarg) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,10 +77,9 @@ typedef struct {
|
|||
int stx_nplugins; /* Number of plugins */
|
||||
struct cli_plugin *stx_plugins; /* List of plugins */
|
||||
int stx_nmodes; /* Number of syntax modes */
|
||||
cli_syntaxmode_t *stx_active_mode; /* Current active syntax mode */
|
||||
cli_syntaxmode_t *stx_modes; /* List of syntax modes */
|
||||
cli_syntaxmode_t *stx_active_mode; /* Current active syntax mode */
|
||||
cli_syntaxmode_t *stx_modes; /* List of syntax modes */
|
||||
cli_prompthook_t *stx_prompt_hook; /* Prompt hook */
|
||||
cli_parsehook_t *stx_parse_hook; /* Parse mode hook */
|
||||
cli_susphook_t *stx_susp_hook; /* Ctrl-Z hook from getline() */
|
||||
} cli_syntax_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ expand_dbvar(void *h,
|
|||
goto done;
|
||||
|
||||
/* XXX read whole configuration, why not send xpath? */
|
||||
if (clicon_rpc_get_config(h, dbstr, "/", NULL, &xt) < 0)
|
||||
if (clicon_rpc_get_config(h, dbstr, "/", &xt) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
|
|
@ -487,7 +487,7 @@ cli_show_config(clicon_handle h,
|
|||
else
|
||||
cprintf(cbxpath, "%s", xpath);
|
||||
/* Get configuration from database */
|
||||
if (clicon_rpc_get_config(h, db, cbuf_get(cbxpath), NULL, &xt) < 0)
|
||||
if (clicon_rpc_get_config(h, db, cbuf_get(cbxpath), &xt) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
|
|
@ -571,7 +571,7 @@ show_conf_xpath(clicon_handle h,
|
|||
}
|
||||
cv = cvec_find_var(cvv, "xpath");
|
||||
xpath = cv_string_get(cv);
|
||||
if (clicon_rpc_get_config(h, str, xpath, NULL, &xt) < 0)
|
||||
if (clicon_rpc_get_config(h, str, xpath, &xt) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ MYLIBLINK = lib$(MYNAME)$(SH_SUFFIX)
|
|||
MYLIB = $(MYLIBLINK).$(CLIXON_MAJOR).$(CLIXON_MINOR)
|
||||
MYLIBSO = $(MYLIBLINK).$(CLIXON_MAJOR)
|
||||
|
||||
LIBSRC = netconf_hello.c netconf_rpc.c netconf_filter.c netconf_lib.c netconf_plugin.c
|
||||
LIBSRC = netconf_hello.c netconf_rpc.c netconf_filter.c netconf_lib.c
|
||||
LIBOBJS = $(LIBSRC:.c=.o)
|
||||
|
||||
all: $(MYLIB) $(APPL)
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@
|
|||
#include "clixon_netconf.h"
|
||||
#include "netconf_lib.h"
|
||||
#include "netconf_hello.h"
|
||||
#include "netconf_plugin.h"
|
||||
#include "netconf_rpc.h"
|
||||
|
||||
/* Command line options to be passed to getopt(3) */
|
||||
|
|
@ -307,6 +306,7 @@ main(int argc,
|
|||
int quiet = 0;
|
||||
clicon_handle h;
|
||||
int use_syslog;
|
||||
char *dir;
|
||||
|
||||
/* Defaults */
|
||||
use_syslog = 0;
|
||||
|
|
@ -383,13 +383,14 @@ main(int argc,
|
|||
goto done;
|
||||
|
||||
/* Initialize plugins group */
|
||||
if (netconf_plugin_load(h) < 0)
|
||||
goto done;
|
||||
if ((dir = clicon_netconf_dir(h)) != NULL)
|
||||
if (clixon_plugins_load(h, dir) < 0)
|
||||
goto done;
|
||||
|
||||
/* Call start function is all plugins before we go interactive */
|
||||
tmp = *(argv-1);
|
||||
*(argv-1) = argv0;
|
||||
netconf_plugin_start(h, argc+1, argv-1);
|
||||
clixon_plugin_start(h, argc+1, argv-1);
|
||||
*(argv-1) = tmp;
|
||||
|
||||
if (!quiet)
|
||||
|
|
@ -401,7 +402,7 @@ main(int argc,
|
|||
if (event_loop() < 0)
|
||||
goto done;
|
||||
done:
|
||||
netconf_plugin_unload(h);
|
||||
clixon_plugin_unload(h);
|
||||
netconf_terminate(h);
|
||||
clicon_log_init(__PROGRAM__, LOG_INFO, 0); /* Log on syslog no stderr */
|
||||
clicon_log(LOG_NOTICE, "%s: %u Terminated\n", __PROGRAM__, getpid());
|
||||
|
|
|
|||
|
|
@ -1,237 +0,0 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
*
|
||||
* handling netconf plugins
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
#include <dirent.h>
|
||||
#include <grp.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clicon */
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
/* clicon netconf*/
|
||||
#include "clixon_netconf.h"
|
||||
#include "netconf_lib.h"
|
||||
#include "netconf_plugin.h"
|
||||
|
||||
/* Database dependency description */
|
||||
struct netconf_reg {
|
||||
qelem_t nr_qelem; /* List header */
|
||||
netconf_cb_t nr_callback; /* Validation/Commit Callback */
|
||||
void *nr_arg; /* Application specific argument to cb */
|
||||
char *nr_tag; /* Xml tag when matched, callback called */
|
||||
};
|
||||
typedef struct netconf_reg netconf_reg_t;
|
||||
|
||||
static int nplugins = 0;
|
||||
static plghndl_t *plugins = NULL;
|
||||
static netconf_reg_t *deps = NULL;
|
||||
|
||||
/*! Load all plugins you can find in CLICON_NETCONF_DIR
|
||||
*/
|
||||
int
|
||||
netconf_plugin_load(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
char *dir;
|
||||
int ndp;
|
||||
struct dirent *dp = NULL;
|
||||
int i;
|
||||
char filename[MAXPATHLEN];
|
||||
plghndl_t *handle;
|
||||
|
||||
/* If no DIR defined, then dont load plugins */
|
||||
if ((dir = clicon_netconf_dir(h)) == NULL){
|
||||
retval = 0;
|
||||
goto quit;
|
||||
}
|
||||
|
||||
/* Get plugin objects names from plugin directory */
|
||||
if((ndp = clicon_file_dirent(dir, &dp, "(.so)$", S_IFREG))<0)
|
||||
goto quit;
|
||||
|
||||
/* Load all plugins */
|
||||
for (i = 0; i < ndp; i++) {
|
||||
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name);
|
||||
clicon_debug(1, "DEBUG: Loading plugin '%.*s' ...",
|
||||
(int)strlen(filename), filename);
|
||||
if ((handle = plugin_load(h, filename, RTLD_NOW)) == NULL)
|
||||
goto quit;
|
||||
if ((plugins = realloc(plugins, (nplugins+1) * sizeof (*plugins))) == NULL) {
|
||||
clicon_err(OE_UNIX, errno, "realloc");
|
||||
goto quit;
|
||||
}
|
||||
plugins[nplugins++] = handle;
|
||||
}
|
||||
retval = 0;
|
||||
quit:
|
||||
if (dp)
|
||||
free(dp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Unload all netconf plugins */
|
||||
int
|
||||
netconf_plugin_unload(clicon_handle h)
|
||||
{
|
||||
int i;
|
||||
netconf_reg_t *nr;
|
||||
|
||||
while((nr = deps) != NULL) {
|
||||
DELQ(nr, deps, netconf_reg_t *);
|
||||
if (nr->nr_tag)
|
||||
free(nr->nr_tag);
|
||||
free(nr);
|
||||
}
|
||||
for (i = 0; i < nplugins; i++)
|
||||
plugin_unload(h, plugins[i]);
|
||||
if (plugins){
|
||||
free(plugins);
|
||||
plugins = NULL;
|
||||
}
|
||||
nplugins = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Call plugin_start in all plugins
|
||||
*/
|
||||
int
|
||||
netconf_plugin_start(clicon_handle h, int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
plgstart_t *startfn;
|
||||
|
||||
for (i = 0; i < nplugins; i++) {
|
||||
/* Call exit function is it exists */
|
||||
if ((startfn = dlsym(plugins[i], PLUGIN_START)) == NULL)
|
||||
break;
|
||||
optind = 0;
|
||||
if (startfn(h, argc, argv) < 0) {
|
||||
clicon_debug(1, "plugin_start() failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*! Register netconf callback
|
||||
* Called from plugin to register a callback for a specific netconf XML tag.
|
||||
*/
|
||||
int
|
||||
netconf_register_callback(clicon_handle h,
|
||||
netconf_cb_t cb, /* Callback called */
|
||||
void *arg, /* Arg to send to callback */
|
||||
char *tag) /* Xml tag when callback is made */
|
||||
{
|
||||
netconf_reg_t *nr;
|
||||
|
||||
if ((nr = malloc(sizeof(netconf_reg_t))) == NULL) {
|
||||
clicon_err(OE_DB, errno, "malloc: %s", strerror(errno));
|
||||
goto catch;
|
||||
}
|
||||
memset (nr, 0, sizeof (*nr));
|
||||
nr->nr_callback = cb;
|
||||
nr->nr_arg = arg;
|
||||
nr->nr_tag = strdup(tag); /* strdup */
|
||||
INSQ(nr, deps);
|
||||
return 0;
|
||||
catch:
|
||||
if (nr){
|
||||
if (nr->nr_tag)
|
||||
free(nr->nr_tag);
|
||||
free(nr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*! See if there is any callback registered for this tag
|
||||
*
|
||||
* Look for local (client-side) netconf plugins. This feature may no
|
||||
* longer be necessary as generic RPC:s should be handled by backend.
|
||||
*
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] xn Sub-tree (under xorig) at child of rpc: <rpc><xn></rpc>.
|
||||
* @param[out] xret Return XML, error or OK
|
||||
*
|
||||
* @retval -1 Error
|
||||
* @retval 0 OK, not found handler.
|
||||
* @retval 1 OK, handler called
|
||||
*/
|
||||
int
|
||||
netconf_plugin_callbacks(clicon_handle h,
|
||||
cxobj *xn,
|
||||
cxobj **xret)
|
||||
{
|
||||
int retval = -1;
|
||||
netconf_reg_t *nreg;
|
||||
|
||||
if (deps != NULL){
|
||||
nreg = deps;
|
||||
do {
|
||||
if (strcmp(nreg->nr_tag, xml_name(xn)) == 0){
|
||||
if ((retval = nreg->nr_callback(h, xn, xret, nreg->nr_arg)) < 0)
|
||||
goto done;
|
||||
retval = 1; /* handled */
|
||||
goto done;
|
||||
}
|
||||
nreg = NEXTQ(netconf_reg_t *, nreg);
|
||||
} while (nreg != deps);
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
*
|
||||
* handling netconf plugins
|
||||
*****************************************************************************/
|
||||
#ifndef _NETCONF_PLUGIN_H_
|
||||
#define _NETCONF_PLUGIN_H_
|
||||
|
||||
/*
|
||||
* Types
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int netconf_plugin_load(clicon_handle h);
|
||||
|
||||
int netconf_plugin_start(clicon_handle h, int argc, char **argv);
|
||||
|
||||
int netconf_plugin_unload(clicon_handle h);
|
||||
|
||||
int netconf_plugin_callbacks(clicon_handle h, cxobj *xn, cxobj **xret);
|
||||
|
||||
#endif /* _NETCONF_PLUGIN_H_ */
|
||||
|
|
@ -65,7 +65,6 @@
|
|||
#include "clixon_netconf.h"
|
||||
#include "netconf_lib.h"
|
||||
#include "netconf_filter.h"
|
||||
#include "netconf_plugin.h"
|
||||
#include "netconf_rpc.h"
|
||||
|
||||
/*
|
||||
|
|
@ -1018,14 +1017,8 @@ netconf_rpc_dispatch(clicon_handle h,
|
|||
}
|
||||
/* Others */
|
||||
else {
|
||||
/* Look for local (client-side) netconf plugins. This feature may no
|
||||
* longer be necessary as generic RPC:s should be handled by backend.
|
||||
*/
|
||||
if ((retval = netconf_plugin_callbacks(h, xe, xret)) < 0)
|
||||
if ((retval = netconf_application_rpc(h, xe, xret)) < 0)
|
||||
goto done;
|
||||
if (retval == 0)
|
||||
if ((retval = netconf_application_rpc(h, xe, xret)) < 0)
|
||||
goto done;
|
||||
if (retval == 0){ /* not handled by callback */
|
||||
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ LIBDEPS = $(top_srcdir)/lib/src/$(CLIXON_LIB)
|
|||
|
||||
LIBS = -L$(top_srcdir)/lib/src @LIBS@ -l:$(CLIXON_LIB)
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@ -fPIC
|
||||
|
||||
INCLUDES = -I. -I$(top_srcdir)/lib/src -I$(top_srcdir)/lib -I$(top_srcdir)/include -I$(top_srcdir) @INCLUDES@
|
||||
|
||||
|
|
|
|||
|
|
@ -60,11 +60,6 @@ int notimplemented(FCGX_Request *r);
|
|||
int clicon_debug_xml(int dbglevel, char *str, cxobj *cx);
|
||||
int test(FCGX_Request *r, int dbg);
|
||||
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 restconf_credentials(clicon_handle h, FCGX_Request *r, char **user);
|
||||
int get_user_cookie(char *cookiestr, char *attribute, char **val);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -358,129 +358,6 @@ readdata(FCGX_Request *r)
|
|||
return cb;
|
||||
}
|
||||
|
||||
|
||||
static int nplugins = 0;
|
||||
static plghndl_t *plugins = NULL;
|
||||
static plgcredentials_t *_credentials_fn = NULL; /* Credentials callback */
|
||||
|
||||
/*! Load all plugins you can find in CLICON_RESTCONF_DIR
|
||||
*/
|
||||
int
|
||||
restconf_plugin_load(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
char *dir;
|
||||
int ndp;
|
||||
struct dirent *dp = NULL;
|
||||
int i;
|
||||
plghndl_t *handle;
|
||||
char filename[MAXPATHLEN];
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((dir = clicon_restconf_dir(h)) == NULL){
|
||||
retval = 0;
|
||||
goto quit;
|
||||
}
|
||||
/* Get plugin objects names from plugin directory */
|
||||
if((ndp = clicon_file_dirent(dir, &dp, "(.so)$", S_IFREG))<0)
|
||||
goto quit;
|
||||
/* Load all plugins */
|
||||
for (i = 0; i < ndp; i++) {
|
||||
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name);
|
||||
clicon_debug(1, "DEBUG: Loading plugin '%.*s' ...",
|
||||
(int)strlen(filename), filename);
|
||||
if ((handle = plugin_load(h, filename, RTLD_NOW)) == NULL)
|
||||
goto quit;
|
||||
if ((_credentials_fn = dlsym(handle, PLUGIN_CREDENTIALS)) == NULL)
|
||||
clicon_debug(1, "Failed to load %s", PLUGIN_CREDENTIALS);
|
||||
else
|
||||
clicon_debug(1, "%s callback loaded", PLUGIN_CREDENTIALS);
|
||||
if ((plugins = realloc(plugins, (nplugins+1) * sizeof (*plugins))) == NULL) {
|
||||
clicon_err(OE_UNIX, errno, "realloc");
|
||||
goto quit;
|
||||
}
|
||||
plugins[nplugins++] = handle;
|
||||
}
|
||||
retval = 0;
|
||||
quit:
|
||||
if (dp)
|
||||
free(dp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Unload all restconf plugins */
|
||||
int
|
||||
restconf_plugin_unload(clicon_handle h)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nplugins; i++)
|
||||
plugin_unload(h, plugins[i]);
|
||||
if (plugins){
|
||||
free(plugins);
|
||||
plugins = NULL;
|
||||
}
|
||||
nplugins = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Call plugin_start in all plugins
|
||||
*/
|
||||
int
|
||||
restconf_plugin_start(clicon_handle h,
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
int i;
|
||||
plgstart_t *startfn;
|
||||
|
||||
for (i = 0; i < nplugins; i++) {
|
||||
/* Call exit function is it exists */
|
||||
if ((startfn = dlsym(plugins[i], PLUGIN_START)) == NULL)
|
||||
break;
|
||||
optind = 0;
|
||||
if (startfn(h, argc, argv) < 0) {
|
||||
clicon_debug(1, "plugin_start() failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Run the restconf user-defined credentials callback if present
|
||||
* The callback is expected to return the authenticated user, or NULL if not
|
||||
* authenticasted.
|
||||
* If no callback exists, return user "none"
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] r Fastcgi request handle
|
||||
* @param[out] user The authenticated user (or NULL). Malloced, must be freed.
|
||||
*/
|
||||
int
|
||||
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 (_credentials_fn == NULL){
|
||||
if ((*user = strdup("none")) == NULL){
|
||||
clicon_err(OE_XML, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
goto ok;
|
||||
}
|
||||
if (_credentials_fn(h, r, user) < 0)
|
||||
*user = NULL;
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d user:%s", __FUNCTION__, retval, *user);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Parse a cookie string and return value of cookie attribute
|
||||
* @param[in] cookiestr cookie string according to rfc6265 (modified)
|
||||
* @param[in] attribute cookie attribute
|
||||
|
|
|
|||
|
|
@ -57,11 +57,6 @@ int notimplemented(FCGX_Request *r);
|
|||
int clicon_debug_xml(int dbglevel, char *str, cxobj *cx);
|
||||
int test(FCGX_Request *r, int dbg);
|
||||
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 restconf_credentials(clicon_handle h, FCGX_Request *r, char **user);
|
||||
int get_user_cookie(char *cookiestr, char *attribute, char **val);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,6 @@
|
|||
* @param[in] pi Offset, where to start pcvec
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] dvec Stream input daat
|
||||
* @param[in] username Authenticated user
|
||||
*/
|
||||
static int
|
||||
api_data(clicon_handle h,
|
||||
|
|
@ -101,8 +100,7 @@ api_data(clicon_handle h,
|
|||
cvec *pcvec,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
char *username)
|
||||
char *data)
|
||||
{
|
||||
int retval = -1;
|
||||
char *request_method;
|
||||
|
|
@ -127,17 +125,17 @@ api_data(clicon_handle h,
|
|||
if (strcmp(request_method, "OPTIONS")==0)
|
||||
retval = api_data_options(h, r);
|
||||
else if (strcmp(request_method, "HEAD")==0)
|
||||
retval = api_data_head(h, r, pcvec, pi, qvec, username, pretty, use_xml);
|
||||
retval = api_data_head(h, r, pcvec, pi, qvec, pretty, use_xml);
|
||||
else if (strcmp(request_method, "GET")==0)
|
||||
retval = api_data_get(h, r, pcvec, pi, qvec, username, pretty, use_xml);
|
||||
retval = api_data_get(h, r, pcvec, pi, qvec, pretty, use_xml);
|
||||
else if (strcmp(request_method, "POST")==0)
|
||||
retval = api_data_post(h, r, api_path, pcvec, pi, qvec, data, username, pretty, use_xml, parse_xml);
|
||||
retval = api_data_post(h, r, api_path, pcvec, pi, qvec, data, pretty, use_xml, parse_xml);
|
||||
else if (strcmp(request_method, "PUT")==0)
|
||||
retval = api_data_put(h, r, api_path, pcvec, pi, qvec, data, username, pretty, use_xml, parse_xml);
|
||||
retval = api_data_put(h, r, api_path, pcvec, pi, qvec, data, pretty, use_xml, parse_xml);
|
||||
else if (strcmp(request_method, "PATCH")==0)
|
||||
retval = api_data_patch(h, r, api_path, pcvec, pi, qvec, data, username);
|
||||
retval = api_data_patch(h, r, api_path, pcvec, pi, qvec, data);
|
||||
else if (strcmp(request_method, "DELETE")==0)
|
||||
retval = api_data_delete(h, r, api_path, pi, username, pretty, use_xml);
|
||||
retval = api_data_delete(h, r, api_path, pi, pretty, use_xml);
|
||||
else
|
||||
retval = notfound(r);
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
|
|
@ -152,7 +150,6 @@ api_data(clicon_handle h,
|
|||
* @param[in] pi Offset, where to start pcvec
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] data Stream input data
|
||||
* @param[in] username Authenticated user
|
||||
*/
|
||||
static int
|
||||
api_operations(clicon_handle h,
|
||||
|
|
@ -161,8 +158,7 @@ api_operations(clicon_handle h,
|
|||
cvec *pcvec,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
char *username)
|
||||
char *data)
|
||||
{
|
||||
int retval = -1;
|
||||
char *request_method;
|
||||
|
|
@ -185,9 +181,9 @@ api_operations(clicon_handle h,
|
|||
parse_xml++;
|
||||
|
||||
if (strcmp(request_method, "GET")==0)
|
||||
retval = api_operations_get(h, r, path, pcvec, pi, qvec, data, username, pretty, use_xml);
|
||||
retval = api_operations_get(h, r, path, pcvec, pi, qvec, data, pretty, use_xml);
|
||||
else if (strcmp(request_method, "POST")==0)
|
||||
retval = api_operations_post(h, r, path, pcvec, pi, qvec, data, username,
|
||||
retval = api_operations_post(h, r, path, pcvec, pi, qvec, data,
|
||||
pretty, use_xml, parse_xml);
|
||||
else
|
||||
retval = notfound(r);
|
||||
|
|
@ -338,7 +334,7 @@ api_restconf(clicon_handle h,
|
|||
cvec *pcvec = NULL; /* for rest api */
|
||||
cbuf *cb = NULL;
|
||||
char *data;
|
||||
char *username = NULL;
|
||||
int authenticated = 0;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
path = FCGX_GetParam("REQUEST_URI", r->envp);
|
||||
|
|
@ -384,12 +380,14 @@ api_restconf(clicon_handle h,
|
|||
/* If present, check credentials. See "plugin_credentials" in plugin
|
||||
* See RFC 8040 section 2.5
|
||||
*/
|
||||
if (restconf_credentials(h, r, &username) < 0)
|
||||
if ((authenticated = clixon_plugin_auth(h, r)) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s username:%s", __FUNCTION__, username);
|
||||
clicon_debug(1, "%s credentials ok username:%s (should be non-NULL)",
|
||||
__FUNCTION__, username);
|
||||
if (username == NULL){
|
||||
/* If set but no user, we set a dummy user */
|
||||
if (authenticated){
|
||||
if (clicon_username_get(h) == NULL)
|
||||
clicon_username_set(h, "none");
|
||||
}
|
||||
else{
|
||||
unauthorized(r);
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -398,11 +396,11 @@ api_restconf(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
else if (strcmp(method, "data") == 0){ /* restconf, skip /api/data */
|
||||
if (api_data(h, r, path, pcvec, 2, qvec, data, username) < 0)
|
||||
if (api_data(h, r, path, pcvec, 2, qvec, data) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(method, "operations") == 0){ /* rpc */
|
||||
if (api_operations(h, r, path, pcvec, 2, qvec, data, username) < 0)
|
||||
if (api_operations(h, r, path, pcvec, 2, qvec, data) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(method, "test") == 0)
|
||||
|
|
@ -423,8 +421,6 @@ api_restconf(clicon_handle h,
|
|||
cvec_free(pcvec);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (username)
|
||||
free(username);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -500,6 +496,7 @@ main(int argc,
|
|||
char *path;
|
||||
clicon_handle h;
|
||||
char *yangspec=NULL;
|
||||
char *dir;
|
||||
|
||||
/* In the startup, logs to stderr & debug flag set later */
|
||||
clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_SYSLOG);
|
||||
|
|
@ -556,8 +553,9 @@ main(int argc,
|
|||
clicon_option_str_set(h, "CLICON_YANG_MODULE_MAIN", yangspec);
|
||||
|
||||
/* Initialize plugins group */
|
||||
if (restconf_plugin_load(h) < 0)
|
||||
return -1;
|
||||
if ((dir = clicon_restconf_dir(h)) != NULL)
|
||||
if (clixon_plugins_load(h, clicon_restconf_dir(h)) < 0)
|
||||
return -1;
|
||||
|
||||
/* Parse yang database spec file */
|
||||
if (yang_spec_main(h) == NULL)
|
||||
|
|
@ -605,7 +603,7 @@ main(int argc,
|
|||
}
|
||||
retval = 0;
|
||||
done:
|
||||
restconf_plugin_unload(h);
|
||||
clixon_plugin_unload(h);
|
||||
restconf_terminate(h);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -227,7 +227,6 @@ api_return_err(clicon_handle h,
|
|||
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
|
||||
* @param[in] pi Offset, where path starts
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] username Authenticated user
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] use_xml Set to 0 for JSON and 1 for XML
|
||||
* @param[in] head If 1 is HEAD, otherwise GET
|
||||
|
|
@ -254,7 +253,6 @@ api_data_get2(clicon_handle h,
|
|||
cvec *pcvec,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
char *username,
|
||||
int pretty,
|
||||
int use_xml,
|
||||
int head)
|
||||
|
|
@ -284,7 +282,7 @@ api_data_get2(clicon_handle h,
|
|||
}
|
||||
path = cbuf_get(cbpath);
|
||||
clicon_debug(1, "%s path:%s", __FUNCTION__, path);
|
||||
if (clicon_rpc_get(h, path, username, &xret) < 0){
|
||||
if (clicon_rpc_get(h, path, &xret) < 0){
|
||||
notfound(r);
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -362,7 +360,6 @@ api_data_get2(clicon_handle h,
|
|||
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
|
||||
* @param[in] pi Offset, where path starts
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] username Authenticated user
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] use_xml Set to 0 for JSON and 1 for XML
|
||||
*
|
||||
|
|
@ -377,11 +374,10 @@ api_data_head(clicon_handle h,
|
|||
cvec *pcvec,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
char *username,
|
||||
int pretty,
|
||||
int use_xml)
|
||||
{
|
||||
return api_data_get2(h, r, pcvec, pi, qvec, username, pretty, use_xml, 1);
|
||||
return api_data_get2(h, r, pcvec, pi, qvec, pretty, use_xml, 1);
|
||||
}
|
||||
|
||||
/*! REST GET method
|
||||
|
|
@ -391,7 +387,6 @@ api_data_head(clicon_handle h,
|
|||
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
|
||||
* @param[in] pi Offset, where path starts
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] username Authenticated user
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] use_xml Set to 0 for JSON and 1 for XML
|
||||
* @code
|
||||
|
|
@ -416,11 +411,10 @@ api_data_get(clicon_handle h,
|
|||
cvec *pcvec,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
char *username,
|
||||
int pretty,
|
||||
int use_xml)
|
||||
{
|
||||
return api_data_get2(h, r, pcvec, pi, qvec, username, pretty, use_xml, 0);
|
||||
return api_data_get2(h, r, pcvec, pi, qvec, pretty, use_xml, 0);
|
||||
}
|
||||
|
||||
/*! Generic REST POST method
|
||||
|
|
@ -431,7 +425,6 @@ api_data_get(clicon_handle h,
|
|||
* @param[in] pi Offset, where to start pcvec
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] data Stream input data
|
||||
* @param[in] username Authenticated user
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] use_xml Set to 0 for JSON and 1 for XML for output data
|
||||
* @param[in] parse_xml Set to 0 for JSON and 1 for XML for input data
|
||||
|
|
@ -464,7 +457,6 @@ api_data_post(clicon_handle h,
|
|||
int pi,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
char *username,
|
||||
int pretty,
|
||||
int use_xml,
|
||||
int parse_xml)
|
||||
|
|
@ -484,6 +476,7 @@ api_data_post(clicon_handle h,
|
|||
cxobj *xret = NULL;
|
||||
cxobj *xretcom = NULL;
|
||||
cxobj *xerr;
|
||||
char *username;
|
||||
|
||||
clicon_debug(1, "%s api_path:\"%s\" json:\"%s\"",
|
||||
__FUNCTION__,
|
||||
|
|
@ -501,7 +494,7 @@ api_data_post(clicon_handle h,
|
|||
xbot = xtop;
|
||||
/* For internal XML protocol: add username attribute for backend access control
|
||||
*/
|
||||
if (username){
|
||||
if ((username = clicon_username_get(h)) != NULL){
|
||||
if ((xu = xml_new("username", xtop, NULL)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xu, CX_ATTR);
|
||||
|
|
@ -645,7 +638,6 @@ match_list_keys(yang_stmt *y,
|
|||
* @param[in] pi Offset, where to start pcvec
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] data Stream input data
|
||||
* @param[in] username Authenticated user
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] use_xml Set to 0 for JSON and 1 for XML for output data
|
||||
* @param[in] parse_xml Set to 0 for JSON and 1 for XML for input data
|
||||
|
|
@ -670,7 +662,6 @@ api_data_put(clicon_handle h,
|
|||
int pi,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
char *username,
|
||||
int pretty,
|
||||
int use_xml,
|
||||
int parse_xml)
|
||||
|
|
@ -692,6 +683,7 @@ api_data_put(clicon_handle h,
|
|||
cxobj *xret = NULL;
|
||||
cxobj *xretcom = NULL;
|
||||
cxobj *xerr;
|
||||
char *username;
|
||||
|
||||
clicon_debug(1, "%s api_path:\"%s\" json:\"%s\"",
|
||||
__FUNCTION__, api_path0, data);
|
||||
|
|
@ -709,7 +701,7 @@ api_data_put(clicon_handle h,
|
|||
xbot = xtop;
|
||||
/* For internal XML protocol: add username attribute for backend access control
|
||||
*/
|
||||
if (username){
|
||||
if ((username = clicon_username_get(h)) != NULL){
|
||||
if ((xu = xml_new("username", xtop, NULL)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xu, CX_ATTR);
|
||||
|
|
@ -824,7 +816,6 @@ api_data_put(clicon_handle h,
|
|||
* @param[in] pi Offset, where to start pcvec
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] data Stream input data
|
||||
* @param[in] username Authenticated user
|
||||
* Netconf: <edit-config> (nc:operation="merge")
|
||||
* See RFC8040 Sec 4.6
|
||||
*/
|
||||
|
|
@ -835,8 +826,7 @@ api_data_patch(clicon_handle h,
|
|||
cvec *pcvec,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
char *username)
|
||||
char *data)
|
||||
{
|
||||
notimplemented(r);
|
||||
return 0;
|
||||
|
|
@ -847,7 +837,6 @@ api_data_patch(clicon_handle h,
|
|||
* @param[in] r Fastcgi request handle
|
||||
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
|
||||
* @param[in] pi Offset, where path starts
|
||||
* @param[in] username Authenticated user
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] use_xml Set to 0 for JSON and 1 for XML
|
||||
* See RFC 8040 Sec 4.7
|
||||
|
|
@ -860,7 +849,6 @@ api_data_delete(clicon_handle h,
|
|||
FCGX_Request *r,
|
||||
char *api_path,
|
||||
int pi,
|
||||
char *username,
|
||||
int pretty,
|
||||
int use_xml)
|
||||
{
|
||||
|
|
@ -877,6 +865,7 @@ api_data_delete(clicon_handle h,
|
|||
cxobj *xret = NULL;
|
||||
cxobj *xretcom = NULL;
|
||||
cxobj *xerr;
|
||||
char *username;
|
||||
|
||||
clicon_debug(1, "%s api_path:%s", __FUNCTION__, api_path);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
|
|
@ -891,7 +880,7 @@ api_data_delete(clicon_handle h,
|
|||
xbot = xtop;
|
||||
/* For internal XML protocol: add username attribute for backend access control
|
||||
*/
|
||||
if (username){
|
||||
if ((username = clicon_username_get(h)) != NULL){
|
||||
if ((xu = xml_new("username", xtop, NULL)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xu, CX_ATTR);
|
||||
|
|
@ -955,7 +944,6 @@ api_data_delete(clicon_handle h,
|
|||
* @param[in] pi Offset, where path starts
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] data Stream input data
|
||||
* @param[in] username Authenticated user
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] use_xml Set to 0 for JSON and 1 for XML
|
||||
*
|
||||
|
|
@ -976,7 +964,6 @@ api_operations_get(clicon_handle h,
|
|||
int pi,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
char *username,
|
||||
int pretty,
|
||||
int use_xml)
|
||||
{
|
||||
|
|
@ -1047,7 +1034,6 @@ api_operations_get(clicon_handle h,
|
|||
* @param[in] pi Offset, where to start pcvec
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] data Stream input data
|
||||
* @param[in] username Authenticated user
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] use_xml Set to 0 for JSON and 1 for XML for output data
|
||||
* @param[in] parse_xml Set to 0 for JSON and 1 for XML for input data
|
||||
|
|
@ -1063,7 +1049,6 @@ api_operations_post(clicon_handle h,
|
|||
int pi,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
char *username,
|
||||
int pretty,
|
||||
int use_xml,
|
||||
int parse_xml)
|
||||
|
|
@ -1085,6 +1070,7 @@ api_operations_post(clicon_handle h,
|
|||
cxobj *xoutput;
|
||||
cxobj *x;
|
||||
cxobj *xa;
|
||||
char *username;
|
||||
|
||||
clicon_debug(1, "%s json:\"%s\" path:\"%s\"", __FUNCTION__, data, path);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
|
|
@ -1112,7 +1098,7 @@ api_operations_post(clicon_handle h,
|
|||
xbot = xtop;
|
||||
/* For internal XML protocol: add username attribute for backend access control
|
||||
*/
|
||||
if (username){
|
||||
if ((username = clicon_username_get(h)) != NULL){
|
||||
if ((xa = xml_new("username", xtop, NULL)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
|
|
|
|||
|
|
@ -46,31 +46,31 @@
|
|||
*/
|
||||
int api_data_options(clicon_handle h, FCGX_Request *r);
|
||||
int api_data_head(clicon_handle h, FCGX_Request *r, cvec *pcvec, int pi,
|
||||
cvec *qvec, char *username, int pretty, int use_xml);
|
||||
cvec *qvec, int pretty, int use_xml);
|
||||
int api_data_get(clicon_handle h, FCGX_Request *r, cvec *pcvec, int pi,
|
||||
cvec *qvec, char *username, int pretty, int use_xml);
|
||||
cvec *qvec, int pretty, int use_xml);
|
||||
int api_data_post(clicon_handle h, FCGX_Request *r, char *api_path,
|
||||
cvec *pcvec, int pi,
|
||||
cvec *qvec, char *data, char *username,
|
||||
cvec *qvec, char *data,
|
||||
int pretty, int use_xml, int parse_xml);
|
||||
int api_data_put(clicon_handle h, FCGX_Request *r, char *api_path,
|
||||
cvec *pcvec, int pi,
|
||||
cvec *qvec, char *data, char *username,
|
||||
cvec *qvec, char *data,
|
||||
int pretty, int use_xml, int parse_xml);
|
||||
int api_data_patch(clicon_handle h, FCGX_Request *r, char *api_path,
|
||||
cvec *pcvec, int pi,
|
||||
cvec *qvec, char *data, char *username);
|
||||
cvec *qvec, char *data);
|
||||
int api_data_delete(clicon_handle h, FCGX_Request *r, char *api_path, int pi,
|
||||
char *username, int pretty, int use_xml);
|
||||
int pretty, int use_xml);
|
||||
|
||||
int api_operations_get(clicon_handle h, FCGX_Request *r,
|
||||
char *path,
|
||||
cvec *pcvec, int pi, cvec *qvec, char *data, char *username,
|
||||
cvec *pcvec, int pi, cvec *qvec, char *data,
|
||||
int pretty, int use_xml);
|
||||
|
||||
int api_operations_post(clicon_handle h, FCGX_Request *r,
|
||||
char *path,
|
||||
cvec *pcvec, int pi, cvec *qvec, char *data,
|
||||
char *username, int pretty, int use_xml, int parse_xml);
|
||||
int pretty, int use_xml, int parse_xml);
|
||||
|
||||
#endif /* _RESTCONF_METHODS_H_ */
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv)
|
|||
|
||||
/* Show eth0 interfaces config using XPATH */
|
||||
if (clicon_rpc_get_config(h, "running","/interfaces/interface[name=eth0]",
|
||||
NULL, &xret) < 0)
|
||||
&xret) < 0)
|
||||
goto done;
|
||||
|
||||
xml_print(stdout, xret);
|
||||
|
|
|
|||
|
|
@ -46,18 +46,7 @@
|
|||
#include <clixon/clixon.h>
|
||||
#include <clixon/clixon_netconf.h>
|
||||
|
||||
|
||||
/*
|
||||
* Plugin initialization
|
||||
*/
|
||||
int
|
||||
plugin_init(clicon_handle h)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Plugin start
|
||||
/*! Plugin start
|
||||
* Called once everything has been initialized, right before
|
||||
* the main event loop is entered.
|
||||
*/
|
||||
|
|
@ -73,3 +62,21 @@ plugin_exit(clicon_handle h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
clixon_plugin_api * clixon_plugin_init(clicon_handle h);
|
||||
|
||||
static const struct clixon_plugin_api api = {
|
||||
"example",
|
||||
clixon_plugin_init,
|
||||
plugin_start,
|
||||
plugin_exit,
|
||||
NULL
|
||||
};
|
||||
|
||||
/*! Netconf plugin initialization
|
||||
*/
|
||||
clixon_plugin_api *
|
||||
clixon_plugin_init(clicon_handle h)
|
||||
{
|
||||
return (void*)&api;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,15 +187,16 @@ b64_decode(const char *src,
|
|||
* @param[in] r Fastcgi request handle
|
||||
* @param[out] username Malloced username, or NULL.
|
||||
* @retval -1 Fatal error
|
||||
* @retval 0 OK
|
||||
* @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,
|
||||
FCGX_Request *r,
|
||||
char **username)
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
FCGX_Request *r = (FCGX_Request *)arg;
|
||||
cxobj *xt = NULL;
|
||||
cxobj *x;
|
||||
char *xbody;
|
||||
|
|
@ -208,19 +209,18 @@ plugin_credentials(clicon_handle h,
|
|||
int ret;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
*username = NULL; /* unauthorized */
|
||||
/* Check if basic_auth set, if not return OK */
|
||||
if (clicon_rpc_get_config(h, "running", "/", NULL, &xt) < 0)
|
||||
if (clicon_rpc_get_config(h, "running", "/", &xt) < 0)
|
||||
goto done;
|
||||
if ((x = xpath_first(xt, "basic_auth")) == NULL)
|
||||
goto none;
|
||||
goto ok;
|
||||
if ((xbody = xml_body(x)) == NULL)
|
||||
goto none;
|
||||
goto ok;
|
||||
if (strcmp(xbody, "true"))
|
||||
goto none;
|
||||
goto ok;
|
||||
/* At this point in the code we must use HTTP basic authentication */
|
||||
if ((auth = FCGX_GetParam("HTTP_AUTHORIZATION", r->envp)) == NULL)
|
||||
goto done;
|
||||
goto fail;
|
||||
if (strlen(auth) < strlen("Basic "))
|
||||
goto fail;
|
||||
if (strncmp("Basic ", auth, strlen("Basic ")))
|
||||
|
|
@ -245,17 +245,15 @@ plugin_credentials(clicon_handle h,
|
|||
cprintf(cb, "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;
|
||||
if ((*username = strdup(user)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
retval = 1;
|
||||
if (clicon_username_set(h, user) < 0)
|
||||
goto done;
|
||||
}
|
||||
fail:
|
||||
retval = 0;
|
||||
done:
|
||||
ok: /* authenticated */
|
||||
retval = 1;
|
||||
done: /* error */
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (user)
|
||||
free(user);
|
||||
|
|
@ -264,24 +262,26 @@ plugin_credentials(clicon_handle h,
|
|||
if (xt)
|
||||
xml_free(xt);
|
||||
return retval;
|
||||
none: /* basic_auth is not enabled, harcode authenticated user "none" */
|
||||
if ((*username = strdup("none")) == NULL){
|
||||
clicon_err(OE_XML, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
goto fail;
|
||||
fail: /* unauthenticated */
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
clixon_plugin_api * clixon_plugin_init(clicon_handle h);
|
||||
|
||||
static const struct clixon_plugin_api api = {
|
||||
"example",
|
||||
clixon_plugin_init,
|
||||
NULL,
|
||||
NULL,
|
||||
plugin_credentials,
|
||||
};
|
||||
|
||||
/*! Restconf plugin initialization
|
||||
*/
|
||||
int
|
||||
plugin_init(clicon_handle h)
|
||||
clixon_plugin_api *
|
||||
clixon_plugin_init(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
clicon_debug(1, "%s restconf", __FUNCTION__);
|
||||
retval = 0;
|
||||
// done:
|
||||
return retval;
|
||||
return (void*)&api;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ typedef struct {float a;} *clicon_handle;
|
|||
typedef void *clicon_handle;
|
||||
#endif
|
||||
|
||||
/* The dynamicically loadable plugin object handle (should be in clixon_plugin.h) */
|
||||
typedef void *plghndl_t;
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -179,4 +179,9 @@ int clicon_xmldb_api_set(clicon_handle h, void *xa_api);
|
|||
void *clicon_xmldb_handle_get(clicon_handle h);
|
||||
int clicon_xmldb_handle_set(clicon_handle h, void *xh);
|
||||
|
||||
/**/
|
||||
/* Set and get authorized user name */
|
||||
char *clicon_username_get(clicon_handle h);
|
||||
int clicon_username_set(clicon_handle h, void *username);
|
||||
|
||||
#endif /* _CLIXON_OPTIONS_H_ */
|
||||
|
|
|
|||
|
|
@ -44,13 +44,6 @@
|
|||
/* The dynamicically loadable plugin object handle */
|
||||
typedef void *plghndl_t;
|
||||
|
||||
/* Find plugin by name callback. XXX Should be clicon internal */
|
||||
typedef void *(find_plugin_t)(clicon_handle, char *);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
|
|
@ -64,6 +57,7 @@ typedef void *(find_plugin_t)(clicon_handle, char *);
|
|||
* @see plginit_t
|
||||
*/
|
||||
#define PLUGIN_INIT "plugin_init"
|
||||
|
||||
typedef void * (plginit_t)(clicon_handle); /* Clixon plugin Init */
|
||||
|
||||
/* Called when backend started with cmd-line arguments from daemon call.
|
||||
|
|
@ -77,36 +71,86 @@ typedef int (plgstart_t)(clicon_handle, int, char **); /* Plugin start */
|
|||
#define PLUGIN_EXIT "plugin_exit"
|
||||
typedef int (plgexit_t)(clicon_handle); /* Plugin exit */
|
||||
|
||||
/*! Called by restconf to ceck credentials and return username
|
||||
/*! Called by restconf to check credentials and return username
|
||||
*/
|
||||
#define PLUGIN_CREDENTIALS "plugin_credentials"
|
||||
|
||||
/* Plugin credentials
|
||||
/* Plugin authorization. Set username option (or not)
|
||||
* @param[in] Clicon handle
|
||||
* @param[in] void*, eg Fastcgihandle request restconf
|
||||
* @param[out] username should be freed after use
|
||||
* @retval 0 if credentials OK
|
||||
* @retval -1 credentials not OK
|
||||
*/
|
||||
typedef int (plgcredentials_t)(clicon_handle, void *, char **username);
|
||||
typedef int (plgauth_t)(clicon_handle, void *);
|
||||
|
||||
typedef int (plgreset_t)(clicon_handle h, const char *db); /* Reset system status */
|
||||
typedef int (plgstatedata_t)(clicon_handle h, char *xpath, cxobj *xtop);
|
||||
|
||||
/* grideye agent plugin init struct for the api
|
||||
* Note: Implicit init function, see PLUGIN_INIT_FN_V2
|
||||
typedef void *transaction_data;
|
||||
|
||||
/* Transaction callbacks */
|
||||
typedef int (trans_cb_t)(clicon_handle h, transaction_data td);
|
||||
|
||||
/* plugin init struct for the api
|
||||
* Note: Implicit init function
|
||||
*/
|
||||
struct clixon_plugin_api;
|
||||
typedef struct clixon_plugin_api* (plginit2_t)(clicon_handle); /* Clixon plugin Init */
|
||||
|
||||
struct clixon_plugin_api{
|
||||
plgcredentials_t *cp_auth;
|
||||
char ca_name[PATH_MAX]; /* Name of plugin */
|
||||
plginit2_t *ca_init; /* Clixon plugin Init (implicit) */
|
||||
plgstart_t *ca_start; /* Plugin start */
|
||||
plgexit_t *ca_exit; /* Plugin exit */
|
||||
plgauth_t *ca_auth; /* Auth credentials */
|
||||
};
|
||||
|
||||
struct clixon_backend_api{
|
||||
char ca_name[PATH_MAX]; /* Name of plugin */
|
||||
plginit2_t *ca_init; /* Clixon plugin Init (implicit) */
|
||||
plgstart_t *ca_start; /* Plugin start */
|
||||
plgexit_t *ca_exit; /* Plugin exit */
|
||||
plgauth_t *ca_auth; /* Auth credentials */
|
||||
/*--Above here common fields with clixon_netconf_api, clixon_restconf_api,
|
||||
* etc ----------*/
|
||||
plgreset_t *ca_reset; /* Reset system status (backend only) */
|
||||
|
||||
plgstatedata_t *ca_statedata; /* Get state data from plugin (backend only) */
|
||||
trans_cb_t *ca_trans_begin; /* Transaction start */
|
||||
trans_cb_t *ca_trans_validate; /* Transaction validation */
|
||||
trans_cb_t *ca_trans_complete; /* Transaction validation complete */
|
||||
trans_cb_t *ca_trans_commit; /* Transaction commit */
|
||||
trans_cb_t *ca_trans_end; /* Transaction completed */
|
||||
trans_cb_t *ca_trans_abort; /* Transaction aborted */
|
||||
};
|
||||
typedef struct clixon_plugin_api clixon_plugin_api;
|
||||
|
||||
#define CLIXON_PLUGIN_INIT "clixon_plugin_init" /* Nextgen */
|
||||
/*! Called when plugin loaded. Only mandadory callback. All others optional
|
||||
* @see plginit_t
|
||||
*/
|
||||
|
||||
/* Internal plugin structure with dlopen() handle and plugin_api
|
||||
*/
|
||||
struct clixon_plugin{
|
||||
plghndl_t cp_handle; /* Handle to plugin using dlopen(3) */
|
||||
struct clixon_plugin_api cp_api;
|
||||
};
|
||||
typedef struct clixon_plugin clixon_plugin;
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
|
||||
/* Find a function in global namespace or a plugin. XXX clicon internal */
|
||||
void *clicon_find_func(clicon_handle h, char *plugin, char *func);
|
||||
int clixon_plugins_load(clicon_handle h, char *dir);
|
||||
|
||||
plghndl_t plugin_load (clicon_handle h, char *file, int dlflags);
|
||||
|
||||
int plugin_unload(clicon_handle h, plghndl_t *handle);
|
||||
|
||||
int clixon_plugin_unload(clicon_handle h);
|
||||
|
||||
int clixon_plugin_start(clicon_handle h, int argc, char **argv);
|
||||
|
||||
int clixon_plugin_auth(clicon_handle h, void *arg);
|
||||
|
||||
#endif /* _CLIXON_PLUGIN_H_ */
|
||||
|
|
|
|||
|
|
@ -45,14 +45,14 @@ int clicon_rpc_msg(clicon_handle h, struct clicon_msg *msg, cxobj **xret0,
|
|||
int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp);
|
||||
int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp);
|
||||
int clicon_rpc_generate_error(char *format, cxobj *xerr);
|
||||
int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, char *username, cxobj **xret);
|
||||
int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, cxobj **xret);
|
||||
int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op,
|
||||
char *xml);
|
||||
int clicon_rpc_copy_config(clicon_handle h, char *db1, char *db2);
|
||||
int clicon_rpc_delete_config(clicon_handle h, char *db);
|
||||
int clicon_rpc_lock(clicon_handle h, char *db);
|
||||
int clicon_rpc_unlock(clicon_handle h, char *db);
|
||||
int clicon_rpc_get(clicon_handle h, char *xpath, char *username, cxobj **xret);
|
||||
int clicon_rpc_get(clicon_handle h, char *xpath, cxobj **xret);
|
||||
int clicon_rpc_close_session(clicon_handle h);
|
||||
int clicon_rpc_kill_session(clicon_handle h, int session_id);
|
||||
int clicon_rpc_validate(clicon_handle h, char *db);
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@
|
|||
#include "clixon_queue.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_plugin.h"
|
||||
#include "clixon_options.h"
|
||||
|
||||
#define CLICON_MAGIC 0x99aafabe
|
||||
|
|
@ -61,15 +61,19 @@
|
|||
|
||||
/*! Internal structure of basic handle. Also header of all other handles.
|
||||
* @note If you change here, you must also change the structs below:
|
||||
* @see struct cli_handle, struct backend_handle
|
||||
* @see struct cli_handle
|
||||
* @see struct backend_handle
|
||||
*/
|
||||
struct clicon_handle {
|
||||
int ch_magic; /* magic (HDR) */
|
||||
clicon_hash_t *ch_copt; /* clicon option list (HDR) */
|
||||
clicon_hash_t *ch_data; /* internal clicon data (HDR) */
|
||||
int ch_magic; /* magic (HDR) */
|
||||
clicon_hash_t *ch_copt; /* clicon option list (HDR) */
|
||||
clicon_hash_t *ch_data; /* internal clicon data (HDR) */
|
||||
};
|
||||
|
||||
/*! Internal call to allocate a CLICON handle.
|
||||
*
|
||||
* @param[in] size Size of handle (internal) struct.
|
||||
* @retval h Clicon handle
|
||||
*
|
||||
* There may be different variants of handles with some common options.
|
||||
* So far the only common options is a MAGIC cookie for sanity checks and
|
||||
|
|
@ -102,6 +106,7 @@ clicon_handle_init0(int size)
|
|||
|
||||
/*! Basic CLICON init functions returning a handle for API access.
|
||||
*
|
||||
* @retval h Clicon handle
|
||||
* This is the first call to CLICON basic API which returns a handle to be
|
||||
* used in the API functions. There are other clicon_init functions for more
|
||||
* elaborate applications (cli/backend/netconf). This should be used by the most
|
||||
|
|
@ -114,6 +119,7 @@ clicon_handle_init(void)
|
|||
}
|
||||
|
||||
/*! Deallocate clicon handle, including freeing handle data.
|
||||
* @param[in] h Clicon handle
|
||||
* @Note: handle 'h' cannot be used in calls after this
|
||||
*/
|
||||
int
|
||||
|
|
@ -131,9 +137,10 @@ clicon_handle_exit(clicon_handle h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check struct magic number for sanity checks
|
||||
* return 0 if OK, -1 if fail.
|
||||
/*! Check struct magic number for sanity checks
|
||||
* @param[in] h Clicon handle
|
||||
* @retval 0 Sanity check OK
|
||||
* @retval -1 Sanity check failed
|
||||
*/
|
||||
int
|
||||
clicon_handle_check(clicon_handle h)
|
||||
|
|
@ -144,8 +151,8 @@ clicon_handle_check(clicon_handle h)
|
|||
return ch->ch_magic == CLICON_MAGIC ? 0 : -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return clicon options (hash-array) given a handle.
|
||||
/*! Return clicon options (hash-array) given a handle.
|
||||
* @param[in] h Clicon handle
|
||||
*/
|
||||
clicon_hash_t *
|
||||
clicon_options(clicon_handle h)
|
||||
|
|
@ -155,8 +162,8 @@ clicon_options(clicon_handle h)
|
|||
return ch->ch_copt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return clicon data (hash-array) given a handle.
|
||||
/*! Return clicon data (hash-array) given a handle.
|
||||
* @param[in] h Clicon handle
|
||||
*/
|
||||
clicon_hash_t *
|
||||
clicon_data(clicon_handle h)
|
||||
|
|
@ -165,4 +172,3 @@ clicon_data(clicon_handle h)
|
|||
|
||||
return ch->ch_data;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,9 +64,9 @@
|
|||
#include "clixon_handle.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_plugin.h"
|
||||
#include "clixon_options.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_plugin.h"
|
||||
#include "clixon_xsl.h"
|
||||
#include "clixon_xml_map.h"
|
||||
|
||||
|
|
@ -715,3 +715,32 @@ clicon_xmldb_handle_set(clicon_handle h,
|
|||
}
|
||||
|
||||
|
||||
/*! Get authorized user name
|
||||
* @param[in] h Clicon handle
|
||||
* @retval xh XMLDB storage handle. If not connected return NULL
|
||||
*/
|
||||
char *
|
||||
clicon_username_get(clicon_handle h)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
|
||||
return (char*)hash_value(cdat, "username", NULL);
|
||||
}
|
||||
|
||||
/*! Set authorized user name
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xh XMLDB storage handle. If NULL reset it
|
||||
* @note Just keep note of it, dont allocate it or so.
|
||||
*/
|
||||
int
|
||||
clicon_username_set(clicon_handle h,
|
||||
void *username)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
|
||||
if (username == NULL)
|
||||
return hash_del(cdat, "username");
|
||||
return hash_add(cdat, "username", username, strlen(username)+1)==NULL?-1:0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -38,52 +38,130 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_file.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_plugin.h"
|
||||
|
||||
/* XXX The below should be placed in clixon handle when done */
|
||||
static clixon_plugin *_clixon_plugins = NULL; /* List of plugins (of client) */
|
||||
static int _clixon_nplugins = 0; /* Number of plugins */
|
||||
|
||||
static find_plugin_t *
|
||||
clicon_find_plugin(clicon_handle h)
|
||||
/*! Load a dynamic plugin object and call its init-function
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] file Which plugin to load
|
||||
* @param[in] dlflags See man(3) dlopen
|
||||
* @retval cp Clixon plugin structure
|
||||
* @retval NULL Error
|
||||
* @see clixon_plugins_load Load all plugins
|
||||
*/
|
||||
static clixon_plugin *
|
||||
plugin_load_one(clicon_handle h,
|
||||
char *file,
|
||||
int dlflags)
|
||||
{
|
||||
void *p;
|
||||
find_plugin_t *fp = NULL;
|
||||
clicon_hash_t *data = clicon_data(h);
|
||||
char *error;
|
||||
void *handle = NULL;
|
||||
plginit2_t *initfn;
|
||||
clixon_plugin_api *api = NULL;
|
||||
clixon_plugin *cp = NULL;
|
||||
|
||||
if ((p = hash_value(data, "CLICON_FIND_PLUGIN", NULL)) != NULL)
|
||||
memcpy(&fp, p, sizeof(fp));
|
||||
|
||||
return fp;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
dlerror(); /* Clear any existing error */
|
||||
if ((handle = dlopen (file, dlflags)) == NULL) {
|
||||
error = (char*)dlerror();
|
||||
clicon_err(OE_PLUGIN, errno, "dlopen: %s\n", error ? error : "Unknown error");
|
||||
goto done;
|
||||
}
|
||||
/* call plugin_init() if defined */
|
||||
if ((initfn = dlsym(handle, CLIXON_PLUGIN_INIT)) == NULL){
|
||||
clicon_err(OE_PLUGIN, errno, "Failed to find %s when loading clixon plugin %s", CLIXON_PLUGIN_INIT, file);
|
||||
goto err;
|
||||
}
|
||||
if ((error = (char*)dlerror()) != NULL) {
|
||||
clicon_err(OE_UNIX, 0, "dlsym: %s: %s", file, error);
|
||||
goto done;
|
||||
}
|
||||
if ((api = initfn(h)) == NULL) {
|
||||
clicon_err(OE_PLUGIN, errno, "Failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
|
||||
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
|
||||
clicon_err(OE_DB, 0, "Unknown error: %s: plugin_init does not make clicon_err call on error",
|
||||
file);
|
||||
goto err;
|
||||
}
|
||||
if ((cp = (clixon_plugin *)malloc(sizeof(*cp))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
cp->cp_handle = handle;
|
||||
cp->cp_api = *api;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
done:
|
||||
return cp;
|
||||
err:
|
||||
if (handle)
|
||||
dlclose(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*! Return a function pointer based on name of plugin and function.
|
||||
* If plugin is specified, ask daemon registered function to return
|
||||
* the dlsym handle of the plugin.
|
||||
/*! Load a set of plugin objects from a directory and and call their init-function
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] dir Directory. .so files in this dir will be loaded.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
void *
|
||||
clicon_find_func(clicon_handle h, char *plugin, char *func)
|
||||
int
|
||||
clixon_plugins_load(clicon_handle h,
|
||||
char *dir)
|
||||
{
|
||||
find_plugin_t *plgget;
|
||||
void *dlhandle = NULL;
|
||||
int retval = -1;
|
||||
int ndp;
|
||||
struct dirent *dp = NULL;
|
||||
int i;
|
||||
char filename[MAXPATHLEN];
|
||||
clixon_plugin *cp;
|
||||
|
||||
if (plugin) {
|
||||
/* find clicon_plugin_get() in global namespace */
|
||||
if ((plgget = clicon_find_plugin(h)) == NULL) {
|
||||
clicon_err(OE_UNIX, errno, "Specified plugin not supported");
|
||||
return NULL;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
/* Get plugin objects names from plugin directory */
|
||||
if((ndp = clicon_file_dirent(dir, &dp, "(.so)$", S_IFREG))<0)
|
||||
goto done;
|
||||
/* Load all plugins */
|
||||
for (i = 0; i < ndp; i++) {
|
||||
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name);
|
||||
clicon_debug(1, "DEBUG: Loading plugin '%.*s' ...",
|
||||
(int)strlen(filename), filename);
|
||||
if ((cp = plugin_load_one(h, filename, RTLD_NOW)) == NULL)
|
||||
goto done;
|
||||
_clixon_nplugins++;
|
||||
if ((_clixon_plugins = realloc(_clixon_plugins, _clixon_nplugins*sizeof(clixon_plugin))) == NULL) {
|
||||
clicon_err(OE_UNIX, errno, "realloc");
|
||||
goto done;
|
||||
}
|
||||
dlhandle = plgget(h, plugin);
|
||||
_clixon_plugins[_clixon_nplugins-1] = *cp;
|
||||
free(cp);
|
||||
}
|
||||
|
||||
return dlsym(dlhandle, func);
|
||||
retval = 0;
|
||||
done:
|
||||
if (dp)
|
||||
free(dp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Load a dynamic plugin object and call its init-function
|
||||
|
|
@ -91,6 +169,7 @@ clicon_find_func(clicon_handle h, char *plugin, char *func)
|
|||
* @param[in] h Clicon handle
|
||||
* @param[in] file Which plugin to load
|
||||
* @param[in] dlflags See man(3) dlopen
|
||||
* @see plugin_load_one for netxgen, this is soon OBSOLETE
|
||||
*/
|
||||
plghndl_t
|
||||
plugin_load(clicon_handle h,
|
||||
|
|
@ -103,14 +182,14 @@ plugin_load(clicon_handle h,
|
|||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
dlerror(); /* Clear any existing error */
|
||||
if ((handle = dlopen (file, dlflags)) == NULL) {
|
||||
if ((handle = dlopen(file, dlflags)) == NULL) {
|
||||
error = (char*)dlerror();
|
||||
clicon_err(OE_PLUGIN, errno, "dlopen: %s\n", error ? error : "Unknown error");
|
||||
goto done;
|
||||
}
|
||||
/* call plugin_init() if defined */
|
||||
if ((initfn = dlsym(handle, PLUGIN_INIT)) == NULL){
|
||||
clicon_err(OE_PLUGIN, errno, "Failed to find plugin_init when loading restconf plugin %s", file);
|
||||
clicon_err(OE_PLUGIN, errno, "Failed to find plugin_init when loading clixon plugin %s", file);
|
||||
goto err;
|
||||
}
|
||||
if ((error = (char*)dlerror()) != NULL) {
|
||||
|
|
@ -158,3 +237,81 @@ plugin_unload(clicon_handle h,
|
|||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Unload all plugins
|
||||
* @param[in] h Clicon handle
|
||||
*/
|
||||
int
|
||||
clixon_plugin_unload(clicon_handle h)
|
||||
{
|
||||
clixon_plugin *cp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _clixon_nplugins; i++) {
|
||||
cp = &_clixon_plugins[i];
|
||||
plugin_unload(h, cp->cp_handle);
|
||||
}
|
||||
if (_clixon_plugins){
|
||||
free(_clixon_plugins);
|
||||
_clixon_plugins = NULL;
|
||||
}
|
||||
_clixon_nplugins = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Call plugin_start in all plugins
|
||||
* @param[in] h Clicon handle
|
||||
*/
|
||||
int
|
||||
clixon_plugin_start(clicon_handle h,
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
clixon_plugin *cp;
|
||||
int i;
|
||||
plgstart_t *startfn; /* Plugin start */
|
||||
|
||||
for (i = 0; i < _clixon_nplugins; i++) {
|
||||
cp = &_clixon_plugins[i];
|
||||
if ((startfn = cp->cp_api.ca_start) == NULL)
|
||||
continue;
|
||||
if (startfn(h, argc, argv) < 0) {
|
||||
clicon_debug(1, "plugin_start() failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Run the restconf user-defined credentials callback if present
|
||||
* Find first authentication callback and call that, then return.
|
||||
* The callback is to set the authenticated user
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] arg Argument, such as fastcgi handler for restconf
|
||||
* @retval -1 Error
|
||||
* @retval 0 Not authenticated
|
||||
* @retval 1 Authenticated
|
||||
* @note If authenticated either a callback was called and clicon_username_set()
|
||||
* Or no callback was found.
|
||||
*/
|
||||
int
|
||||
clixon_plugin_auth(clicon_handle h,
|
||||
void *arg)
|
||||
{
|
||||
clixon_plugin *cp;
|
||||
int i;
|
||||
plgauth_t *authfn; /* Plugin auth */
|
||||
int retval = 1;
|
||||
|
||||
for (i = 0; i < _clixon_nplugins; i++) {
|
||||
cp = &_clixon_plugins[i];
|
||||
if ((authfn = cp->cp_api.ca_auth) == NULL)
|
||||
continue;
|
||||
if ((retval = authfn(h, arg)) < 0) {
|
||||
clicon_debug(1, "plugin_start() failed\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syslog.h>
|
||||
|
|
@ -60,9 +61,9 @@
|
|||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_plugin.h"
|
||||
#include "clixon_options.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_plugin.h"
|
||||
#include "clixon_xsl.h"
|
||||
#include "clixon_proto.h"
|
||||
#include "clixon_err.h"
|
||||
|
|
@ -236,14 +237,13 @@ clicon_rpc_generate_error(char *format,
|
|||
* @param[in] h CLICON handle
|
||||
* @param[in] db Name of database
|
||||
* @param[in] xpath XPath (or "")
|
||||
* @param[in] username Authenticated user (extra attribute)
|
||||
* @param[out] xt XML tree. Free with xml_free.
|
||||
* Either <config> or <rpc-error>.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error, fatal or xml
|
||||
* @code
|
||||
* cxobj *xt = NULL;
|
||||
* if (clicon_rpc_get_config(h, "running", "/", username, &xt) < 0)
|
||||
* if (clicon_rpc_get_config(h, "running", "/", &xt) < 0)
|
||||
* err;
|
||||
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
* clicon_rpc_generate_error("", xerr);
|
||||
|
|
@ -258,7 +258,6 @@ int
|
|||
clicon_rpc_get_config(clicon_handle h,
|
||||
char *db,
|
||||
char *xpath,
|
||||
char *username,
|
||||
cxobj **xt)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -266,11 +265,12 @@ clicon_rpc_get_config(clicon_handle h,
|
|||
cbuf *cb = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xd;
|
||||
char *username;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
cprintf(cb, "<rpc");
|
||||
if (username)
|
||||
if ((username = clicon_username_get(h)) != NULL)
|
||||
cprintf(cb, " username=\"%s\"", username);
|
||||
cprintf(cb, "><get-config><source><%s/></source>", db);
|
||||
if (xpath && strlen(xpath))
|
||||
|
|
@ -498,7 +498,6 @@ clicon_rpc_unlock(clicon_handle h,
|
|||
/*! Get database configuration and state data
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] xpath XPath (or "")
|
||||
* @param[in] username Authenticated user (extra attribute)
|
||||
* @param[out] xt XML tree. Free with xml_free.
|
||||
* Either <config> or <rpc-error>.
|
||||
* @retval 0 OK
|
||||
|
|
@ -519,7 +518,6 @@ clicon_rpc_unlock(clicon_handle h,
|
|||
int
|
||||
clicon_rpc_get(clicon_handle h,
|
||||
char *xpath,
|
||||
char *username,
|
||||
cxobj **xt)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -527,11 +525,12 @@ clicon_rpc_get(clicon_handle h,
|
|||
cbuf *cb = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xd;
|
||||
char *username;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
cprintf(cb, "<rpc");
|
||||
if (username)
|
||||
if ((username = clicon_username_get(h)) != NULL)
|
||||
cprintf(cb, " username=\"%s\"", username);
|
||||
cprintf(cb, "><get>");
|
||||
if (xpath && strlen(xpath))
|
||||
|
|
|
|||
|
|
@ -43,9 +43,11 @@
|
|||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
|
|
|||
|
|
@ -61,10 +61,11 @@
|
|||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
/* cligen */
|
||||
|
|
@ -79,9 +80,9 @@
|
|||
#include "clixon_string.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_yang_type.h"
|
||||
#include "clixon_plugin.h"
|
||||
#include "clixon_options.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_plugin.h"
|
||||
#include "clixon_xsl.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_err.h"
|
||||
|
|
@ -833,7 +834,6 @@ yang2api_path_fmt(yang_stmt *ys,
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Transform an xml key format and a vector of values to an XML key
|
||||
* Used for actual key, eg in clicon_rpc_change(), xmldb_put_xkey()
|
||||
* Example:
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@
|
|||
#include "clixon_file.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_plugin.h"
|
||||
#include "clixon_options.h"
|
||||
#include "clixon_yang_type.h"
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@
|
|||
#include "clixon_handle.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_plugin.h"
|
||||
#include "clixon_options.h"
|
||||
#include "clixon_yang.h"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ clixon_cli=clixon_cli
|
|||
|
||||
# For memcheck / performance
|
||||
#clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf"
|
||||
# clixon_netconf="valgrind --tool=callgrind clixon_netconf
|
||||
#clixon_netconf="valgrind --tool=callgrind clixon_netconf"
|
||||
clixon_netconf=clixon_netconf
|
||||
|
||||
# How to run restconf stand-alone and using valgrind
|
||||
|
|
|
|||
|
|
@ -39,8 +39,7 @@ if [ $? -ne 0 ]; then
|
|||
err
|
||||
fi
|
||||
|
||||
new "netconf tests"
|
||||
|
||||
new "netconf get-config"
|
||||
expecteof "$clixon_netconf -qf $cfg" '<rpc message-id="101"><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply message-id="101"><data/></rpc-reply>]]>]]>$'
|
||||
|
||||
new "Add subtree eth/0/0 using none which should not change anything"
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ new "kill old restconf daemon"
|
|||
sudo pkill -u www-data clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -Df $cfg -y $fyang
|
||||
sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang # -D
|
||||
|
||||
sleep 1
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ new "kill old restconf daemon"
|
|||
sudo pkill -u www-data clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -Df $cfg
|
||||
sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg # -D
|
||||
|
||||
sleep 1
|
||||
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ module clixon-config {
|
|||
type string;
|
||||
default "master";
|
||||
description
|
||||
"Name of master plugin (both frontend and backend).
|
||||
"Name of master plugin (cli, netconf, restconf and backend).
|
||||
Master plugin has special callbacks for frontends.
|
||||
See clicon user manual for more info. (Obsolete?)";
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue