* Restconf authentication callback (ca_auth) signature changed

* Not backward compatible: All uses of the ca-auth callback in restconf plugins must be changed
  * New version is: `int ca_auth(h, req, auth_type, authp, userp)`
    * where `auth_type` is the requested authentication-type (none, client-cert or user-defined)
    * `authp` is the returned authentication flag
    * `userp` is the returned associated authenticated user
    * and the return value is three-valued: -1: Error, 0: ignored, 1: OK
  * For more info see [clixon-docs](https://clixon-docs.readthedocs.io/en/latest/restconf.html)
* New clixon-restconf@2020-12-30.yang revision
This commit is contained in:
Olof hagsand 2021-02-09 21:15:54 +01:00
parent 1f0147f996
commit 710fc76887
54 changed files with 1216 additions and 485 deletions

View file

@ -32,6 +32,7 @@ Expected: February 2021
### New features ### New features
* NETCONF Call Home Call Home RFC 8071 * NETCONF Call Home Call Home RFC 8071
* See [Netconf/ssh callhome](https://clixon-docs.readthedocs.io/en/latest/netconf.html#callhome)
* Solution description using openssh and utility functions, no changes to core clixon * Solution description using openssh and utility functions, no changes to core clixon
* Example: test/test_netconf_ssh_callhome.sh * Example: test/test_netconf_ssh_callhome.sh
* RESTCONF Call home not done * RESTCONF Call home not done
@ -42,6 +43,14 @@ Expected: February 2021
Developers may need to change their code Developers may need to change their code
* Restconf authentication callback (ca_auth) signature changed
* Not backward compatible: All uses of the ca-auth callback in restconf plugins must be changed
* New version is: `int ca_auth(h, req, auth_type, authp, userp)`
* where `auth_type` is the requested authentication-type (none, client-cert or user-defined)
* `authp` is the returned authentication flag
* `userp` is the returned associated authenticated user
* and the return value is three-valued: -1: Error, 0: ignored, 1: OK
* For more info see [clixon-docs](https://clixon-docs.readthedocs.io/en/latest/restconf.html)
* rpc msg C API rearranged to separate socket/connect from connect * rpc msg C API rearranged to separate socket/connect from connect
* Added `cvv_i` output parameter to `api_path_fmt2api_path()` to see how many cvv entries were used. * Added `cvv_i` output parameter to `api_path_fmt2api_path()` to see how many cvv entries were used.
@ -50,6 +59,10 @@ Developers may need to change their code
Users may have to change how they access the system Users may have to change how they access the system
* Handling empty netconf XML messages "]]>]]>" is changed from being accepted to return an error. * Handling empty netconf XML messages "]]>]]>" is changed from being accepted to return an error.
* New clixon-restconf@2020-12-30.yang revision
* Added: debug field
* Added 'none' as default value for auth-type
* Changed http-auth-type enum from 'password' to 'user'
* New clixon-lib@2020-12-30.yang revision * New clixon-lib@2020-12-30.yang revision
* Changed: RPC process-control output parameter status to pid * Changed: RPC process-control output parameter status to pid
* New clixon-config@2020-12-30.yang revision * New clixon-config@2020-12-30.yang revision
@ -710,7 +723,7 @@ Patch release based on testing by Dave Cornejo, Netgate
### Summary ### Summary
The main improvement in this release concerns security in terms of priveleges and credentials of accessing the clixon backend. There is also stricter multi-namespace checks which primarily effects where augmented models are used. The main improvement in this release concerns security in terms of privileges and credentials of accessing the clixon backend. There is also stricter multi-namespace checks which primarily effects where augmented models are used.
### Major New features ### Major New features
* The backend daemon can drop privileges after initialization to run as non-privileged user * The backend daemon can drop privileges after initialization to run as non-privileged user
@ -718,7 +731,7 @@ The main improvement in this release concerns security in terms of priveleges an
* use `-U <user>` clixon_backend command-line option to drop to `user` * use `-U <user>` clixon_backend command-line option to drop to `user`
* Generic options are the following: * Generic options are the following:
* `CLICON_BACKEND_USER` drop of privileges to this user * `CLICON_BACKEND_USER` drop of privileges to this user
* `CLICON_BACKEND_PRIVELEGES` can have the following values: * `CLICON_BACKEND_PRIVILEGES` can have the following values:
* `none` Make no drop/change in privileges. This is currently the default. * `none` Make no drop/change in privileges. This is currently the default.
* `drop_perm` After initialization, drop privileges permanently * `drop_perm` After initialization, drop privileges permanently
* `drop_perm` After initialization, drop privileges temporarily (to a euid) * `drop_perm` After initialization, drop privileges temporarily (to a euid)
@ -749,8 +762,8 @@ a="urn:example:a" xmlns:b="urn:example:b"/>`
* New clixon-config@2019-09-11.yang revision * New clixon-config@2019-09-11.yang revision
* Added: CLICON_BACKEND_USER: Drop of privileges to this user, owner of backend socket (default: `clicon`) * Added: CLICON_BACKEND_USER: Drop of privileges to this user, owner of backend socket (default: `clicon`)
* Therefore new installation should now add a UNIX `clicon` user * Therefore new installation should now add a UNIX `clicon` user
* Added: CLICON_BACKEND_PRIVELEGES: If and how to drop privileges * Added: CLICON_BACKEND_PRIVILEGES: If and how to drop privileges
* Added: CLICON_NACM_CREDENTIALS: If and how to check backend socket priveleges with NACM * Added: CLICON_NACM_CREDENTIALS: If and how to check backend socket privileges with NACM
* Added: CLICON_NACM_RECOVERY_USER: Name of NACM recovery user. * Added: CLICON_NACM_RECOVERY_USER: Name of NACM recovery user.
* Restconf top-level operations GET root resource modified to comply with RFC 8040 Sec 3.1 * Restconf top-level operations GET root resource modified to comply with RFC 8040 Sec 3.1
* non-pretty print remove all spaces, eg `{"operations":{"clixon-example:client-rpc":[null]` * non-pretty print remove all spaces, eg `{"operations":{"clixon-example:client-rpc":[null]`

View file

@ -86,6 +86,7 @@ APPSRC += backend_socket.c
APPSRC += backend_client.c APPSRC += backend_client.c
APPSRC += backend_commit.c APPSRC += backend_commit.c
APPSRC += backend_plugin.c APPSRC += backend_plugin.c
APPSRC += backend_plugin_restconf.c # Pseudo plugin for restconf daemon
APPSRC += backend_startup.c APPSRC += backend_startup.c
APPOBJ = $(APPSRC:.c=.o) APPOBJ = $(APPSRC:.c=.o)

View file

@ -75,6 +75,7 @@
#include "backend_commit.h" #include "backend_commit.h"
#include "backend_handle.h" #include "backend_handle.h"
#include "backend_startup.h" #include "backend_startup.h"
#include "backend_plugin_restconf.h"
/* Command line options to be passed to getopt(3) */ /* Command line options to be passed to getopt(3) */
#define BACKEND_OPTS "hD:f:E:l:d:p:b:Fza:u:P:1qs:c:U:g:y:o:" #define BACKEND_OPTS "hD:f:E:l:d:p:b:Fza:u:P:1qs:c:U:g:y:o:"
@ -388,169 +389,6 @@ ret2status(int ret,
return retval; return retval;
} }
/*---------------------------------------------------------------------
* Restconf process pseudo plugin
*/
#define RESTCONF_PROCESS "restconf"
/*! Process rpc callback function
* - if RPC op is start, if enable is true, start the service, if false, error or ignore it
* - if RPC op is stop, stop the service
* These rules give that if RPC op is start and enable is false -> change op to none
*/
int
restconf_rpc_wrapper(clicon_handle h,
process_entry_t *pe,
char **operation)
{
int retval = -1;
cxobj *xt = NULL;
clicon_debug(1, "%s", __FUNCTION__);
if (strcmp(*operation, "stop") == 0){
/* if RPC op is stop, stop the service */
}
else if (strcmp(*operation, "start") == 0){
/* RPC op is start & enable is true, then start the service,
& enable is false, error or ignore it */
if (xmldb_get(h, "running", NULL, "/restconf", &xt) < 0)
goto done;
if (xt != NULL &&
xpath_first(xt, NULL, "/restconf[enable='false']") != NULL) {
*operation = "none";
}
}
retval = 0;
done:
if (xt)
xml_free(xt);
return retval;
}
/*! Enable process-control of restconf daemon, ie start/stop restconf by registering restconf process
* @param[in] h Clicon handle
* @note Could also look in clixon-restconf and start process if enable is true, but that needs to
* be in start callback using a pseudo plugin.
*/
static int
restconf_pseudo_process_control(clicon_handle h)
{
int retval = -1;
char **argv = NULL;
int i;
int nr;
char dbgstr[8];
char wwwstr[64];
nr = 4;
if (clicon_debug_get() != 0)
nr += 2;
if ((argv = calloc(nr, sizeof(char *))) == NULL){
clicon_err(OE_UNIX, errno, "calloc");
goto done;
}
i = 0;
snprintf(wwwstr, sizeof(wwwstr)-1, "%s/clixon_restconf", clicon_option_str(h, "CLICON_WWWDIR"));
argv[i++] = wwwstr;
argv[i++] = "-f";
argv[i++] = clicon_option_str(h, "CLICON_CONFIGFILE");
if (clicon_debug_get() != 0){
argv[i++] = "-D";
snprintf(dbgstr, sizeof(dbgstr)-1, "%d", clicon_debug_get());
argv[i++] = dbgstr;
}
argv[i++] = NULL;
assert(i==nr);
if (clixon_process_register(h, RESTCONF_PROCESS,
NULL /* XXX network namespace */,
restconf_rpc_wrapper,
argv, nr) < 0)
goto done;
if (argv != NULL)
free(argv);
retval = 0;
done:
return retval;
}
/*! Restconf pseduo-plugin process validate
*/
static int
restconf_pseudo_process_validate(clicon_handle h,
transaction_data td)
{
int retval = -1;
cxobj *xtarget;
clicon_debug(1, "%s", __FUNCTION__);
xtarget = transaction_target(td);
/* If ssl-enable is true and (at least a) socket has ssl,
* then server-cert-path and server-key-path must exist */
if (xpath_first(xtarget, NULL, "restconf/enable[.='true']") &&
xpath_first(xtarget, NULL, "restconf/socket[ssl='true']")){
/* Should filepath be checked? One could claim this is a runtime system,... */
if (xpath_first(xtarget, 0, "restconf/server-cert-path") == NULL){
clicon_err(OE_CFG, 0, "SSL enabled but server-cert-path not set");
return -1; /* induce fail */
}
if (xpath_first(xtarget, 0, "restconf/server-key-path") == NULL){
clicon_err(OE_CFG, 0, "SSL enabled but server-key-path not set");
return -1; /* induce fail */
}
}
retval = 0;
return retval;
}
/*! Restconf pseduo-plugin process commit
*/
static int
restconf_pseudo_process_commit(clicon_handle h,
transaction_data td)
{
int retval = -1;
cxobj *xtarget;
cxobj *cx;
int enabled = 0;
clicon_debug(1, "%s", __FUNCTION__);
xtarget = transaction_target(td);
if (xpath_first(xtarget, NULL, "/restconf[enable='true']") != NULL)
enabled++;
if ((cx = xpath_first(xtarget, NULL, "/restconf/enable")) != NULL &&
xml_flag(cx, XML_FLAG_CHANGE|XML_FLAG_ADD)){
if (clixon_process_operation(h, RESTCONF_PROCESS,
enabled?"start":"stop", 0, NULL) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Register start/stop restconf RPC and create pseudo-plugin to monitor enable flag
* @param[in] h Clixon handle
*/
static int
restconf_pseudo_process_reg(clicon_handle h,
yang_stmt *yspec)
{
int retval = -1;
clixon_plugin *cp = NULL;
if (clixon_pseudo_plugin(h, "restconf pseudo plugin", &cp) < 0)
goto done;
cp->cp_api.ca_trans_commit = restconf_pseudo_process_commit;
cp->cp_api.ca_trans_validate = restconf_pseudo_process_validate;
/* Register generic process-control of restconf daemon, ie start/stop restconf */
if (restconf_pseudo_process_control(h) < 0)
goto done;
retval = 0;
done:
return retval;
}
/* Debug timer */ /* Debug timer */
int int
@ -981,7 +819,7 @@ main(int argc,
goto done; goto done;
/* Check restconf start/stop from backend */ /* Check restconf start/stop from backend */
if (clicon_option_bool(h, "CLICON_BACKEND_RESTCONF_PROCESS")){ if (clicon_option_bool(h, "CLICON_BACKEND_RESTCONF_PROCESS")){
if (restconf_pseudo_process_reg(h, yspec) < 0) if (backend_plugin_restconf_register(h, yspec) < 0)
goto done; goto done;
} }
/* Here all modules are loaded /* Here all modules are loaded

View file

@ -0,0 +1,223 @@
/*
*
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2017-2019 Olof Hagsand
Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC(Netgate)
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 *****
*
* Pseudo backend plugin for starting restconf daemon
*/
#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 <errno.h>
#include <assert.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clixon/clixon.h>
#include "clixon_backend_transaction.h"
#include "backend_plugin_restconf.h"
/*---------------------------------------------------------------------
* Restconf process pseudo plugin
*/
#define RESTCONF_PROCESS "restconf"
/*! Process rpc callback function
* - if RPC op is start, if enable is true, start the service, if false, error or ignore it
* - if RPC op is stop, stop the service
* These rules give that if RPC op is start and enable is false -> change op to none
*/
int
restconf_rpc_wrapper(clicon_handle h,
process_entry_t *pe,
char **operation)
{
int retval = -1;
cxobj *xt = NULL;
clicon_debug(1, "%s", __FUNCTION__);
if (strcmp(*operation, "stop") == 0){
/* if RPC op is stop, stop the service */
}
else if (strcmp(*operation, "start") == 0){
/* RPC op is start & enable is true, then start the service,
& enable is false, error or ignore it */
if (xmldb_get(h, "running", NULL, "/restconf", &xt) < 0)
goto done;
if (xt != NULL &&
xpath_first(xt, NULL, "/restconf[enable='false']") != NULL) {
*operation = "none";
}
}
retval = 0;
done:
if (xt)
xml_free(xt);
return retval;
}
/*! Enable process-control of restconf daemon, ie start/stop restconf by registering restconf process
* @param[in] h Clicon handle
* @note Could also look in clixon-restconf and start process if enable is true, but that needs to
* be in start callback using a pseudo plugin.
*/
static int
restconf_pseudo_process_control(clicon_handle h)
{
int retval = -1;
char **argv = NULL;
int i;
int nr;
char dbgstr[8];
char wwwstr[64];
nr = 4;
if (clicon_debug_get() != 0)
nr += 2;
if ((argv = calloc(nr, sizeof(char *))) == NULL){
clicon_err(OE_UNIX, errno, "calloc");
goto done;
}
i = 0;
snprintf(wwwstr, sizeof(wwwstr)-1, "%s/clixon_restconf", clicon_option_str(h, "CLICON_WWWDIR"));
argv[i++] = wwwstr;
argv[i++] = "-f";
argv[i++] = clicon_option_str(h, "CLICON_CONFIGFILE");
/* Add debug if backend has debug.
* There is also a debug flag in clixon-restconf.yang but it kicks in after it starts
*/
if (clicon_debug_get() != 0){
argv[i++] = "-D";
snprintf(dbgstr, sizeof(dbgstr)-1, "%d", clicon_debug_get());
argv[i++] = dbgstr;
}
argv[i++] = NULL;
assert(i==nr);
if (clixon_process_register(h, RESTCONF_PROCESS,
NULL /* XXX network namespace */,
restconf_rpc_wrapper,
argv, nr) < 0)
goto done;
if (argv != NULL)
free(argv);
retval = 0;
done:
return retval;
}
/*! Restconf pseduo-plugin process validate
*/
static int
restconf_pseudo_process_validate(clicon_handle h,
transaction_data td)
{
int retval = -1;
cxobj *xtarget;
clicon_debug(1, "%s", __FUNCTION__);
xtarget = transaction_target(td);
/* If ssl-enable is true and (at least a) socket has ssl,
* then server-cert-path and server-key-path must exist */
if (xpath_first(xtarget, NULL, "restconf/enable[.='true']") &&
xpath_first(xtarget, NULL, "restconf/socket[ssl='true']")){
/* Should filepath be checked? One could claim this is a runtime system,... */
if (xpath_first(xtarget, 0, "restconf/server-cert-path") == NULL){
clicon_err(OE_CFG, 0, "SSL enabled but server-cert-path not set");
return -1; /* induce fail */
}
if (xpath_first(xtarget, 0, "restconf/server-key-path") == NULL){
clicon_err(OE_CFG, 0, "SSL enabled but server-key-path not set");
return -1; /* induce fail */
}
}
retval = 0;
return retval;
}
/*! Restconf pseduo-plugin process commit
*/
static int
restconf_pseudo_process_commit(clicon_handle h,
transaction_data td)
{
int retval = -1;
cxobj *xtarget;
cxobj *cx;
int enabled = 0;
clicon_debug(1, "%s", __FUNCTION__);
xtarget = transaction_target(td);
if (xpath_first(xtarget, NULL, "/restconf[enable='true']") != NULL)
enabled++;
if ((cx = xpath_first(xtarget, NULL, "/restconf/enable")) != NULL &&
xml_flag(cx, XML_FLAG_CHANGE|XML_FLAG_ADD)){
if (clixon_process_operation(h, RESTCONF_PROCESS,
enabled?"start":"stop", 0, NULL) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Register start/stop restconf RPC and create pseudo-plugin to monitor enable flag
* @param[in] h Clixon handle
*/
int
backend_plugin_restconf_register(clicon_handle h,
yang_stmt *yspec)
{
int retval = -1;
clixon_plugin *cp = NULL;
if (clixon_pseudo_plugin(h, "restconf pseudo plugin", &cp) < 0)
goto done;
cp->cp_api.ca_trans_commit = restconf_pseudo_process_commit;
cp->cp_api.ca_trans_validate = restconf_pseudo_process_validate;
/* Register generic process-control of restconf daemon, ie start/stop restconf */
if (restconf_pseudo_process_control(h) < 0)
goto done;
retval = 0;
done:
return retval;
}

View file

@ -0,0 +1,43 @@
/*
*
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2017-2019 Olof Hagsand
Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC(Netgate)
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 *****
*
* Pseudo backend plugin for starting restconf daemon
*/
#ifndef _BACKEND_PLUGIN_RESTCONF_H_
#define _BACKEND_PLUGIN_RESTCONF_H_
int backend_plugin_restconf_register(clicon_handle h, yang_stmt *yspec);
#endif /* _BACKEND_PLUGIN_RESTCONF_H_ */

View file

@ -61,6 +61,7 @@
/* clicon */ /* clicon */
#include <clixon/clixon.h> #include <clixon/clixon.h>
#include "restconf_lib.h"
#include "restconf_handle.h" #include "restconf_handle.h"
/* header part is copied from struct clicon_handle in lib/src/clixon_handle.c */ /* header part is copied from struct clicon_handle in lib/src/clixon_handle.c */
@ -90,6 +91,7 @@ struct restconf_handle {
/* ------ end of common handle ------ */ /* ------ end of common handle ------ */
clicon_hash_t *rh_params; /* restconf parameters, including http headers */ clicon_hash_t *rh_params; /* restconf parameters, including http headers */
clixon_auth_type_t rh_auth_type; /* authentication type */
}; };
/*! Creates and returns a clicon config handle for other CLICON API calls /*! Creates and returns a clicon config handle for other CLICON API calls
@ -172,3 +174,33 @@ restconf_param_del_all(clicon_handle h)
done: done:
return retval; return retval;
} }
/*! Get restconf http parameter
* @param[in] h Clicon handle
* @retval auth_type
*/
clixon_auth_type_t
restconf_auth_type_get(clicon_handle h)
{
struct restconf_handle *rh = handle(h);
return rh->rh_auth_type;
}
/*! Set restconf http parameter
* @param[in] h Clicon handle
* @param[in] name Data name
* @param[in] val Data value as null-terminated string
* @retval 0 OK
* @retval -1 Error
* Currently using clixon runtime data but there is risk for colliding names
*/
int
restconf_auth_type_set(clicon_handle h,
clixon_auth_type_t type)
{
struct restconf_handle *rh = handle(h);
rh->rh_auth_type = type;
return 0;
}

View file

@ -47,5 +47,7 @@ int restconf_handle_exit(clicon_handle h);
char *restconf_param_get(clicon_handle h, const char *param); char *restconf_param_get(clicon_handle h, const char *param);
int restconf_param_set(clicon_handle h, const char *param, char *val); int restconf_param_set(clicon_handle h, const char *param, char *val);
int restconf_param_del_all(clicon_handle h); int restconf_param_del_all(clicon_handle h);
clixon_auth_type_t restconf_auth_type_get(clicon_handle h);
int restconf_auth_type_set(clicon_handle h, clixon_auth_type_t type);
#endif /* _RESTCONF_HANDLE_H_ */ #endif /* _RESTCONF_HANDLE_H_ */

View file

@ -60,8 +60,9 @@
#include <clixon/clixon.h> #include <clixon/clixon.h>
#include "restconf_api.h" #include "restconf_api.h"
#include "restconf_handle.h"
#include "restconf_lib.h" #include "restconf_lib.h"
#include "restconf_err.h"
#include "restconf_handle.h"
/* See RFC 8040 Section 7: Mapping from NETCONF<error-tag> to Status Code /* See RFC 8040 Section 7: Mapping from NETCONF<error-tag> to Status Code
* and RFC 6241 Appendix A. NETCONF Error list * and RFC 6241 Appendix A. NETCONF Error list
@ -495,3 +496,123 @@ restconf_drop_privileges(clicon_handle h,
return retval; return retval;
} }
/*!
* @param[in] h Clicon handle
* @param[in] req Generic Www handle (can be part of clixon handle)
* @retval -1 Error
* @retval 0 Not authenticated
* @retval 1 Authenticated
*/
int
restconf_authentication_cb(clicon_handle h,
void *req,
int pretty,
restconf_media media_out)
{
int retval = -1;
clixon_auth_type_t auth_type;
int authenticated;
int ret;
char *username = NULL;
cxobj *xret = NULL;
cxobj *xerr;
auth_type = restconf_auth_type_get(h);
clicon_debug(1, "%s auth-type:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type));
ret = 0;
authenticated = 0;
if (auth_type != CLIXON_AUTH_NONE)
if ((ret = clixon_plugin_auth_all(h, req,
auth_type,
&authenticated,
&username)) < 0)
goto done;
if (ret == 1){ /* OK, tag username to handle */
clicon_username_set(h, username);
}
else { /* Default behaviour */
switch (auth_type){
case CLIXON_AUTH_NONE:
clicon_username_set(h, "none");
authenticated = 1;
break;
case CLIXON_AUTH_CLIENT_CERTIFICATE: {
char *cn;
/* Check for cert subject common name (CN) */
if ((cn = restconf_param_get(h, "SSL_CN")) != NULL){
clicon_username_set(h, cn);
authenticated = 1;
}
break;
}
case CLIXON_AUTH_USER:
authenticated = 0;
break;
}
}
if (authenticated == 0){ /* Message is not authenticated (401 returned) */
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if (api_return_err(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto notauth;
}
retval = 0;
goto notauth;
}
/* If set but no user, set a dummy user */
retval = 1;
done:
clicon_debug(1, "%s retval:%d authenticated:%d user:%s",
__FUNCTION__, retval, authenticated, clicon_username_get(h));
if (xret)
xml_free(xret);
return retval;
notauth:
retval = 0;
goto done;
}
/*! Basic config init
* @param[in] h Clixon handle
* @param[in] xrestconf XML config containing clixon-restconf top-level
* @retval -1 Error
* @retval 0 Restconf is disable
* @retval 1 OK
*/
int
restconf_config_init(clicon_handle h,
cxobj *xrestconf)
{
int retval = -1;
char *enable;
cxobj *x;
char *bstr;
cvec *nsc = NULL;
clixon_auth_type_t auth_type;
if ((x = xpath_first(xrestconf, nsc, "enable")) != NULL &&
(enable = xml_body(x)) != NULL){
if (strcmp(enable, "false") == 0){
clicon_debug(1, "%s restconf disabled", __FUNCTION__);
goto disable;
}
}
/* get common fields */
if ((x = xpath_first(xrestconf, nsc, "auth-type")) != NULL &&
(bstr = xml_body(x)) != NULL){
if ((auth_type = clixon_auth_type_str2int(bstr)) < 0){
clicon_err(OE_CFG, EFAULT, "Invalid restconf auth-type: %s", bstr);
goto done;
}
restconf_auth_type_set(h, auth_type);
}
retval = 1;
done:
return retval;
disable:
retval = 0;
goto done;
}

View file

@ -82,6 +82,8 @@ int restconf_insert_attributes(cxobj *xdata, cvec *qvec);
int restconf_main_extension_cb(clicon_handle h, yang_stmt *yext, yang_stmt *ys); int restconf_main_extension_cb(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
char *restconf_uripath(clicon_handle h); char *restconf_uripath(clicon_handle h);
int restconf_drop_privileges(clicon_handle h, char *user); int restconf_drop_privileges(clicon_handle h, char *user);
int restconf_authentication_cb(clicon_handle h, void *req, int pretty, restconf_media media_out);
int restconf_config_init(clicon_handle h, cxobj *xrestconf);
#endif /* _RESTCONF_LIB_H_ */ #endif /* _RESTCONF_LIB_H_ */

View file

@ -83,19 +83,22 @@
#include "restconf_err.h" #include "restconf_err.h"
#include "restconf_root.h" #include "restconf_root.h"
/* Command line options to be passed to getopt(3) */ /* Command line options to be passed to getopt(3) */
#define RESTCONF_OPTS "hD:f:E:l:p:d:y:a:u:ro:" #define RESTCONF_OPTS "hD:f:E:l:p:d:y:a:u:ro:"
/* See see listen(5) */ /* See see listen(5) */
#define SOCKET_LISTEN_BACKLOG 16 #define SOCKET_LISTEN_BACKLOG 16
/* clixon evhtp handle */ /* Clixon evhtp handle
* Global data about evhtp lib,
* See evhtp_request_t *req for per-message state data
*/
typedef struct { typedef struct {
evhtp_t **eh_htpvec; /* One per socket */ clicon_handle eh_h;
int eh_htplen; /* Number of sockets */ evhtp_t **eh_htpvec; /* One per socket */
struct event_base *eh_evbase; /* Change to list */ int eh_htplen; /* Number of sockets */
evhtp_ssl_cfg_t *eh_ssl_config; struct event_base *eh_evbase; /* Change to list */
evhtp_ssl_cfg_t *eh_ssl_config;
} cx_evhtp_handle; } cx_evhtp_handle;
/* Need this global to pass to signal handler /* Need this global to pass to signal handler
@ -150,7 +153,7 @@ restconf_sig_term(int arg)
exit(-1); exit(-1);
if (_EVHTP_HANDLE) /* global */ if (_EVHTP_HANDLE) /* global */
evhtp_terminate(_EVHTP_HANDLE); evhtp_terminate(_EVHTP_HANDLE);
if (_CLICON_HANDLE){ if (_CLICON_HANDLE){ /* could be replaced by eh->eh_h */
// stream_child_freeall(_CLICON_HANDLE); // stream_child_freeall(_CLICON_HANDLE);
restconf_terminate(_CLICON_HANDLE); restconf_terminate(_CLICON_HANDLE);
} }
@ -448,8 +451,9 @@ static void
cx_path_wellknown(evhtp_request_t *req, cx_path_wellknown(evhtp_request_t *req,
void *arg) void *arg)
{ {
clicon_handle h = arg; cx_evhtp_handle *eh = (cx_evhtp_handle*)arg;
int ret; clicon_handle h = eh->eh_h;
int ret;
clicon_debug(1, "------------"); clicon_debug(1, "------------");
/* input debug */ /* input debug */
@ -479,15 +483,15 @@ static void
cx_path_restconf(evhtp_request_t *req, cx_path_restconf(evhtp_request_t *req,
void *arg) void *arg)
{ {
clicon_handle h = arg; cx_evhtp_handle *eh = (cx_evhtp_handle*)arg;
int ret; clicon_handle h = eh->eh_h;
cvec *qvec = NULL; int ret;
cvec *qvec = NULL;
clicon_debug(1, "------------"); clicon_debug(1, "------------");
/* input debug */ /* input debug */
if (clicon_debug_get()) if (clicon_debug_get())
evhtp_headers_for_each(req->headers_in, print_header, h); evhtp_headers_for_each(req->headers_in, print_header, h);
/* get accepted connection */ /* get accepted connection */
/* Query vector, ie the ?a=x&b=y stuff */ /* Query vector, ie the ?a=x&b=y stuff */
@ -844,8 +848,7 @@ cx_evhtp_socket(clicon_handle h,
cvec *nsc, cvec *nsc,
char *server_cert_path, char *server_cert_path,
char *server_key_path, char *server_key_path,
char *server_ca_cert_path, char *server_ca_cert_path)
int auth_type_client_certificate)
{ {
int retval = -1; int retval = -1;
char *netns = NULL; char *netns = NULL;
@ -862,7 +865,6 @@ cx_evhtp_socket(clicon_handle h,
clicon_err(OE_UNIX, errno, "evhtp_new"); clicon_err(OE_UNIX, errno, "evhtp_new");
goto done; goto done;
} }
#ifndef EVHTP_DISABLE_EVTHR /* threads */ #ifndef EVHTP_DISABLE_EVTHR /* threads */
evhtp_use_threads_wexit(htp, NULL, NULL, 4, NULL); evhtp_use_threads_wexit(htp, NULL, NULL, 4, NULL);
#endif #endif
@ -871,12 +873,12 @@ cx_evhtp_socket(clicon_handle h,
/* Callback right after a connection is accepted. */ /* Callback right after a connection is accepted. */
evhtp_set_post_accept_cb(htp, cx_post_accept, h); evhtp_set_post_accept_cb(htp, cx_post_accept, h);
/* Callback to be executed for all /restconf api calls */ /* Callback to be executed for all /restconf api calls */
if (evhtp_set_cb(htp, "/" RESTCONF_API, cx_path_restconf, h) == NULL){ if (evhtp_set_cb(htp, "/" RESTCONF_API, cx_path_restconf, eh) == NULL){
clicon_err(OE_EVENTS, errno, "evhtp_set_cb"); clicon_err(OE_EVENTS, errno, "evhtp_set_cb");
goto done; goto done;
} }
/* Callback to be executed for all /restconf api calls */ /* Callback to be executed for all /restconf api calls */
if (evhtp_set_cb(htp, RESTCONF_WELL_KNOWN, cx_path_wellknown, h) == NULL){ if (evhtp_set_cb(htp, RESTCONF_WELL_KNOWN, cx_path_wellknown, eh) == NULL){
clicon_err(OE_EVENTS, errno, "evhtp_set_cb"); clicon_err(OE_EVENTS, errno, "evhtp_set_cb");
goto done; goto done;
} }
@ -933,41 +935,41 @@ cx_evhtp_init(clicon_handle h,
cvec *nsc, cvec *nsc,
cx_evhtp_handle *eh) cx_evhtp_handle *eh)
{ {
int retval = -1; int retval = -1;
char* enable; int ssl_enable = 0;
int ssl_enable = 0; int dbg = 0;
cxobj **vec = NULL; cxobj **vec = NULL;
size_t veclen; size_t veclen;
char *server_cert_path = NULL; char *server_cert_path = NULL;
char *server_key_path = NULL; char *server_key_path = NULL;
char *server_ca_cert_path = NULL; char *server_ca_cert_path = NULL;
char *auth_type = NULL; cxobj *x;
int auth_type_client_certificate = 0; char *bstr;
cxobj *x; int i;
int i; int ret;
clixon_auth_type_t auth_type;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
if ((x = xpath_first(xrestconf, nsc, "enable")) != NULL && if ((ret = restconf_config_init(h, xrestconf)) < 0)
(enable = xml_body(x)) != NULL){ goto done;
if (strcmp(enable, "false") == 0){ if (ret == 0)
clicon_debug(1, "%s restconf disabled", __FUNCTION__); goto disable;
goto disable; auth_type = restconf_auth_type_get(h);
}
}
/* If at least one socket has ssl then enable global ssl_enable */ /* If at least one socket has ssl then enable global ssl_enable */
ssl_enable = xpath_first(xrestconf, nsc, "socket[ssl='true']") != NULL; ssl_enable = xpath_first(xrestconf, nsc, "socket[ssl='true']") != NULL;
/* get common fields */
if ((x = xpath_first(xrestconf, nsc, "auth-type")) != NULL)
auth_type = xml_body(x);
if (auth_type && strcmp(auth_type, "client-certificate") == 0)
auth_type_client_certificate = 1;
if ((x = xpath_first(xrestconf, nsc, "server-cert-path")) != NULL) if ((x = xpath_first(xrestconf, nsc, "server-cert-path")) != NULL)
server_cert_path = xml_body(x); server_cert_path = xml_body(x);
if ((x = xpath_first(xrestconf, nsc, "server-key-path")) != NULL) if ((x = xpath_first(xrestconf, nsc, "server-key-path")) != NULL)
server_key_path = xml_body(x); server_key_path = xml_body(x);
if ((x = xpath_first(xrestconf, nsc, "server-ca-cert-path")) != NULL) if ((x = xpath_first(xrestconf, nsc, "server-ca-cert-path")) != NULL)
server_ca_cert_path = xml_body(x); server_ca_cert_path = xml_body(x);
if ((x = xpath_first(xrestconf, nsc, "debug")) != NULL &&
(bstr = xml_body(x)) != NULL){
dbg = atoi(bstr);
clicon_debug_init(dbg, NULL);
}
/* Here the daemon either uses SSL or not, ie you cant seem to mix http and https :-( */ /* Here the daemon either uses SSL or not, ie you cant seem to mix http and https :-( */
if (ssl_enable){ if (ssl_enable){
/* Init evhtp ssl config struct */ /* Init evhtp ssl config struct */
@ -982,11 +984,11 @@ cx_evhtp_init(clicon_handle h,
if (cx_get_ssl_server_certs(h, server_cert_path, server_key_path, eh->eh_ssl_config) < 0) if (cx_get_ssl_server_certs(h, server_cert_path, server_key_path, eh->eh_ssl_config) < 0)
goto done; goto done;
/* If client auth get client CA cert */ /* If client auth get client CA cert */
if (auth_type_client_certificate) if (auth_type == CLIXON_AUTH_CLIENT_CERTIFICATE)
if (cx_get_ssl_client_ca_certs(h, server_ca_cert_path, eh->eh_ssl_config) < 0) if (cx_get_ssl_client_ca_certs(h, server_ca_cert_path, eh->eh_ssl_config) < 0)
goto done; goto done;
eh->eh_ssl_config->x509_verify_cb = cx_verify_certs; /* Is extra verification necessary? */ eh->eh_ssl_config->x509_verify_cb = cx_verify_certs; /* Is extra verification necessary? */
if (auth_type_client_certificate){ if (auth_type == CLIXON_AUTH_CLIENT_CERTIFICATE){
eh->eh_ssl_config->verify_peer = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; eh->eh_ssl_config->verify_peer = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
eh->eh_ssl_config->x509_verify_cb = cx_verify_certs; eh->eh_ssl_config->x509_verify_cb = cx_verify_certs;
eh->eh_ssl_config->verify_depth = 2; eh->eh_ssl_config->verify_depth = 2;
@ -998,8 +1000,7 @@ cx_evhtp_init(clicon_handle h,
goto done; goto done;
for (i=0; i<veclen; i++){ for (i=0; i<veclen; i++){
if (cx_evhtp_socket(h, eh, ssl_enable, vec[i], nsc, if (cx_evhtp_socket(h, eh, ssl_enable, vec[i], nsc,
server_cert_path, server_key_path, server_ca_cert_path, server_cert_path, server_key_path, server_ca_cert_path) < 0)
auth_type_client_certificate) < 0)
goto done; goto done;
} }
retval = 1; retval = 1;
@ -1318,16 +1319,24 @@ main(int argc,
/* Access the remaining argv/argc options (after --) w clicon-argv_get() */ /* Access the remaining argv/argc options (after --) w clicon-argv_get() */
clicon_argv_set(h, argv0, argc, argv); clicon_argv_set(h, argv0, argc, argv);
/* Init restconf auth-type */
restconf_auth_type_set(h, CLIXON_AUTH_NONE);
/* Dump configuration options on debug */ /* Dump configuration options on debug */
if (dbg) if (dbg)
clicon_option_dump(h, dbg); clicon_option_dump(h, dbg);
/* Call start function in all plugins before we go interactive */
if (clixon_plugin_start_all(h) < 0)
goto done;
if ((eh = malloc(sizeof *eh)) == NULL){ if ((eh = malloc(sizeof *eh)) == NULL){
clicon_err(OE_UNIX, errno, "malloc"); clicon_err(OE_UNIX, errno, "malloc");
goto done; goto done;
} }
memset(eh, 0, sizeof *eh); memset(eh, 0, sizeof *eh);
eh->eh_h = h;
_EVHTP_HANDLE = eh; /* global */ _EVHTP_HANDLE = eh; /* global */
/* Read config */ /* Read config */

View file

@ -178,6 +178,7 @@ usage(clicon_handle h,
"\t-d <dir>\t Specify restconf plugin directory dir (default: %s)\n" "\t-d <dir>\t Specify restconf plugin directory dir (default: %s)\n"
"\t-y <file>\t Load yang spec file (override yang main module)\n" "\t-y <file>\t Load yang spec file (override yang main module)\n"
"\t-a UNIX|IPv4|IPv6 Internal backend socket family\n" "\t-a UNIX|IPv4|IPv6 Internal backend socket family\n"
"\t-u <path|addr>\t Internal socket domain path or IP addr (see -a)\n" "\t-u <path|addr>\t Internal socket domain path or IP addr (see -a)\n"
"\t-r \t\t Do not drop privileges if run as root\n" "\t-r \t\t Do not drop privileges if run as root\n"
"\t-o \"<option>=<value>\" Give configuration option overriding config file (see clixon-config.yang)\n", "\t-o \"<option>=<value>\" Give configuration option overriding config file (see clixon-config.yang)\n",
@ -215,7 +216,10 @@ main(int argc,
size_t cligen_buflen; size_t cligen_buflen;
size_t cligen_bufthreshold; size_t cligen_bufthreshold;
int dbg = 0; int dbg = 0;
int drop_priveleges = 1; int drop_privileges = 1;
cxobj *xconfig = NULL;
cxobj *xrestconf = NULL;
int ret;
/* In the startup, logs to stderr & debug flag set later */ /* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst); clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
@ -311,7 +315,7 @@ main(int argc,
clicon_option_str_set(h, "CLICON_SOCK", optarg); clicon_option_str_set(h, "CLICON_SOCK", optarg);
break; break;
case 'r':{ /* Do not drop privileges if run as root */ case 'r':{ /* Do not drop privileges if run as root */
drop_priveleges = 0; drop_privileges = 0;
break; break;
} }
case 'o':{ /* Configuration option */ case 'o':{ /* Configuration option */
@ -332,7 +336,10 @@ main(int argc,
/* Access the remaining argv/argc options (after --) w clicon-argv_get() */ /* Access the remaining argv/argc options (after --) w clicon-argv_get() */
clicon_argv_set(h, argv0, argc, argv); clicon_argv_set(h, argv0, argc, argv);
/* Init restconf auth-type */
restconf_auth_type_set(h, CLIXON_AUTH_NONE);
/* Init cligen buffers */ /* Init cligen buffers */
cligen_buflen = clicon_option_int(h, "CLICON_CLI_BUF_START"); cligen_buflen = clicon_option_int(h, "CLICON_CLI_BUF_START");
cligen_bufthreshold = clicon_option_int(h, "CLICON_CLI_BUF_THRESHOLD"); cligen_bufthreshold = clicon_option_int(h, "CLICON_CLI_BUF_THRESHOLD");
@ -418,11 +425,18 @@ main(int argc,
if (dbg) if (dbg)
clicon_option_dump(h, dbg); clicon_option_dump(h, dbg);
/* Call start function in all plugins before we go interactive /* Call start function in all plugins before we go interactive */
*/
if (clixon_plugin_start_all(h) < 0) if (clixon_plugin_start_all(h) < 0)
goto done; goto done;
xconfig = clicon_conf_xml(h); /* Get local config */
if ((xrestconf = xpath_first(xconfig, NULL, "restconf")) != NULL){
if ((ret = restconf_config_init(h, xrestconf)) < 0)
goto done;
if (ret == 0){
clicon_err(OE_DAEMON, EFAULT, "Restconf daemon disabled in config");
goto done;
}
}
if ((sockpath = clicon_option_str(h, "CLICON_RESTCONF_PATH")) == NULL){ if ((sockpath = clicon_option_str(h, "CLICON_RESTCONF_PATH")) == NULL){
clicon_err(OE_CFG, errno, "No CLICON_RESTCONF_PATH in clixon configure file"); clicon_err(OE_CFG, errno, "No CLICON_RESTCONF_PATH in clixon configure file");
goto done; goto done;
@ -454,7 +468,7 @@ main(int argc,
clicon_err(OE_UNIX, errno, "chmod"); clicon_err(OE_UNIX, errno, "chmod");
goto done; goto done;
} }
if (drop_priveleges){ if (drop_privileges){
/* Drop privileges to WWWUSER if started as root */ /* Drop privileges to WWWUSER if started as root */
if (restconf_drop_privileges(h, WWWUSER) < 0) if (restconf_drop_privileges(h, WWWUSER) < 0)
goto done; goto done;

View file

@ -374,15 +374,15 @@ api_operations(clicon_handle h,
} }
/*! Process a /restconf root input, this is the root of the restconf processing /*! Process a /restconf root input, this is the root of the restconf processing
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @param[in] req Generic Www handle (can be part of clixon handle) * @param[in] req Generic Www handle (can be part of clixon handle)
* @param[in] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff * @param[in] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff
* @see api_root_restconf_exact for accessing /restconf/ exact * @see api_root_restconf_exact for accessing /restconf/ exact
*/ */
int int
api_root_restconf(clicon_handle h, api_root_restconf(clicon_handle h,
void *req, void *req,
cvec *qvec) cvec *qvec)
{ {
int retval = -1; int retval = -1;
char *request_method = NULL; /* GET,.. */ char *request_method = NULL; /* GET,.. */
@ -396,9 +396,8 @@ api_root_restconf(clicon_handle h,
char *media_str = NULL; char *media_str = NULL;
restconf_media media_out = YANG_DATA_JSON; restconf_media media_out = YANG_DATA_JSON;
char *indata = NULL; char *indata = NULL;
int authenticated = 0; char *username = NULL;
cxobj *xret = NULL; int ret;
cxobj *xerr;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
if (req == NULL){ if (req == NULL){
@ -426,7 +425,6 @@ api_root_restconf(clicon_handle h,
} }
} }
clicon_debug(1, "%s ACCEPT: %s %s", __FUNCTION__, media_str, restconf_media_int2str(media_out)); clicon_debug(1, "%s ACCEPT: %s %s", __FUNCTION__, media_str, restconf_media_int2str(media_out));
if ((pvec = clicon_strsep(path, "/", &pn)) == NULL) if ((pvec = clicon_strsep(path, "/", &pn)) == NULL)
@ -464,26 +462,10 @@ api_root_restconf(clicon_handle h,
/* If present, check credentials. See "plugin_credentials" in plugin /* If present, check credentials. See "plugin_credentials" in plugin
* See RFC 8040 section 2.5 * See RFC 8040 section 2.5
*/ */
if ((authenticated = clixon_plugin_auth_all(h, req)) < 0) if ((ret = restconf_authentication_cb(h, req, pretty, media_out)) < 0)
goto done; goto done;
clicon_debug(1, "%s auth:%d %s", __FUNCTION__, authenticated, clicon_username_get(h)); if (ret == 0)
/* If set but no user, set a dummy user */
if (authenticated){
if (clicon_username_get(h) == NULL)
clicon_username_set(h, "none");
}
else{
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if (api_return_err(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
}
goto ok; goto ok;
}
clicon_debug(1, "%s auth2:%d %s", __FUNCTION__, authenticated, clicon_username_get(h));
if (strcmp(api_resource, "yang-library-version")==0){ if (strcmp(api_resource, "yang-library-version")==0){
if (api_yang_library_version(h, req, pretty, media_out) < 0) if (api_yang_library_version(h, req, pretty, media_out) < 0)
goto done; goto done;
@ -538,14 +520,14 @@ api_root_restconf(clicon_handle h,
retval = 0; retval = 0;
done: done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
if (username)
free(username);
if (pcvec) if (pcvec)
cvec_free(pcvec); cvec_free(pcvec);
if (pvec) if (pvec)
free(pvec); free(pvec);
if (cb) if (cb)
cbuf_free(cb); cbuf_free(cb);
if (xret)
xml_free(xret);
return retval; return retval;
} }

View file

@ -382,13 +382,11 @@ api_stream(clicon_handle h,
cvec *pcvec = NULL; /* for rest api */ cvec *pcvec = NULL; /* for rest api */
cbuf *cb = NULL; cbuf *cb = NULL;
char *indata; char *indata;
int authenticated = 0;
int pretty; int pretty;
restconf_media media_out = YANG_DATA_XML; /* XXX default */ restconf_media media_out = YANG_DATA_XML; /* XXX default */
cbuf *cbret = NULL; cbuf *cbret = NULL;
cxobj *xret = NULL;
cxobj *xerr;
int s = -1; int s = -1;
int ret;
#ifdef STREAM_FORK #ifdef STREAM_FORK
int pid; int pid;
struct stream_child *sc; struct stream_child *sc;
@ -430,26 +428,10 @@ api_stream(clicon_handle h,
/* If present, check credentials. See "plugin_credentials" in plugin /* If present, check credentials. See "plugin_credentials" in plugin
* See RFC 8040 section 2.5 * See RFC 8040 section 2.5
*/ */
if ((authenticated = clixon_plugin_auth_all(h, req)) < 0) if ((ret = restconf_authentication_cb(h, req, pretty, media_out)) < 0)
goto done; goto done;
clicon_debug(1, "%s auth:%d %s", __FUNCTION__, authenticated, clicon_username_get(h)); if (ret == 0)
/* If set but no user, we set a dummy user */
if (authenticated){
if (clicon_username_get(h) == NULL)
clicon_username_set(h, "none");
}
else{
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
if (api_return_err(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
}
goto ok; goto ok;
}
clicon_debug(1, "%s auth2:%d %s", __FUNCTION__, authenticated, clicon_username_get(h));
if (restconf_stream(h, req, method, qvec, pretty, media_out, &s) < 0) if (restconf_stream(h, req, method, qvec, pretty, media_out, &s) < 0)
goto done; goto done;
if (s != -1){ if (s != -1){
@ -465,8 +447,6 @@ api_stream(clicon_handle h,
cbuf_free(cb); cbuf_free(cb);
if (cbret) if (cbret)
cbuf_free(cbret); cbuf_free(cbret);
if (xret)
xml_free(xret);
#endif /* STREAM_FORK */ #endif /* STREAM_FORK */
/* Listen to backend socket */ /* Listen to backend socket */
if (clixon_event_reg_fd(s, if (clixon_event_reg_fd(s,
@ -523,7 +503,5 @@ api_stream(clicon_handle h,
cbuf_free(cb); cbuf_free(cb);
if (cbret) if (cbret)
cbuf_free(cbret); cbuf_free(cbret);
if (xret)
xml_free(xret);
return retval; return retval;
} }

View file

@ -55,22 +55,12 @@
* -a basic authentication * -a basic authentication
* -s ssl client certificates * -s ssl client certificates
*/ */
#define RESTCONF_EXAMPLE_OPTS "as" #define RESTCONF_EXAMPLE_OPTS ""
static const char Base64[] = static const char Base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '='; static const char Pad64 = '=';
/* Use http basic auth. Set by starting restonf with:
* clixon_restconf ... -- -a
*/
static int basic_auth = 0;
/* Use https ssl client certs, map subject CN to user. Set by starting restonf with:
* clixon_restconf ... -- -s
*/
static int ssl_client_certs = 0;
/* skips all whitespace anywhere. /* skips all whitespace anywhere.
converts characters, four at a time, starting at (or after) converts characters, four at a time, starting at (or after)
src from base - 64 numbers into three 8 bit bytes in the target area. src from base - 64 numbers into three 8 bit bytes in the target area.
@ -199,16 +189,21 @@ b64_decode(const char *src,
} }
/*! HTTP basic authentication example (note hardwired) /*! HTTP basic authentication example (note hardwired)
* @param[in] h Clixon handle * @param[in] h Clicon handle
* @retval -1 Fatal error * @param[in] req Per-message request www handle to use with restconf_api.h
* @retval 0 Unauth * @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set
* @retval 1 Auth * @param[out] userp If retval is OK and auth=1, the associated user, malloced by plugin
* @retval -1 Fatal error
* @retval 0 OK, see auth parameter on result.
* @note user should be malloced
* @note: Three hardwired users: andy, wilma, guest w password "bar". * @note: Three hardwired users: andy, wilma, guest w password "bar".
* Enabled by passing -- -a to the main function * Enabled by passing -- -a to the main function
*/ */
static int static int
example_basic_auth(clicon_handle h, example_basic_auth(clicon_handle h,
void *arg) void *req,
int *authp,
char **userp)
{ {
int retval = -1; int retval = -1;
cxobj *xt = NULL; cxobj *xt = NULL;
@ -220,6 +215,11 @@ example_basic_auth(clicon_handle h,
size_t authlen; size_t authlen;
int ret; int ret;
clicon_debug(1, "%s", __FUNCTION__);
if (authp == NULL || userp == NULL){
clicon_err(OE_PLUGIN, EINVAL, "Output parameter is NULL");
goto done;
}
/* At this point in the code we must use HTTP basic authentication */ /* At this point in the code we must use HTTP basic authentication */
if ((auth = restconf_param_get(h, "HTTP_AUTHORIZATION")) == NULL) if ((auth = restconf_param_get(h, "HTTP_AUTHORIZATION")) == NULL)
goto fail; goto fail;
@ -252,71 +252,61 @@ example_basic_auth(clicon_handle h,
} }
if (strcmp(passwd, passwd2)) if (strcmp(passwd, passwd2))
goto fail; goto fail;
retval = 1;
clicon_debug(1, "%s user:%s", __FUNCTION__, user);
if (clicon_username_set(h, user) < 0)
goto done;
/* authenticated */ /* authenticated */
retval = 1; *userp = user;
*authp = 1;
retval = 0;
done: /* error */ done: /* error */
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); clicon_debug(1, "%s retval:%d authp:%d userp:%s", __FUNCTION__, retval, *authp, *userp);
if (user)
free(user);
if (cb) if (cb)
cbuf_free(cb); cbuf_free(cb);
if (xt) if (xt)
xml_free(xt); xml_free(xt);
return retval; return retval;
fail: /* unauthenticated */ fail: /* unauthenticated */
retval = 0; *authp = 0;
goto done;
}
/*! SSL client cert authentication.
* @param[in] h Clixon handle
* @param[in] arg
* @retval -1 Fatal error
* @retval 0 Unauth
* @retval 1 Auth
*/
static int
example_client_certs(clicon_handle h,
void *arg)
{
int retval = -1;
char *cn;
/* Check for cert subject common name (CN) */
if ((cn = restconf_param_get(h, "SSL_CN")) == NULL)
goto fail;
if (clicon_username_set(h, cn) < 0)
goto done;
/* authenticated */
retval = 1;
done: /* error */
return retval;
fail: /* unauthenticated */
retval = 0; retval = 0;
goto done; goto done;
} }
/*! Authentication callback /*! Authentication callback
* @param[in] h Clixon handle * @param[in] h Clicon handle
* @param[in] arg * @param[in] req Per-message request www handle to use with restconf_api.h
* @retval -1 Fatal error * @param[in] auth_type Authentication type: none, user-defined, or client-cert
* @retval 0 Unauth * @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set
* @retval 1 Auth * @param[out] userp The associated user, malloced by plugin. Only if retval is 1/OK and authp=1,
* @retval -1 Fatal error
* @retval 0 Ignore, undecided, not handled, same as no callback
* @retval 1 OK, see auth parameter on result.
* @note user should be malloced
*/ */
int int
example_restconf_credentials(clicon_handle h, example_restconf_credentials(clicon_handle h,
void *arg) void *req,
clixon_auth_type_t auth_type,
int *authp,
char **userp)
{ {
if (basic_auth) int retval = -1;
return example_basic_auth(h, arg);
else if (ssl_client_certs) clicon_debug(1, "%s auth:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type));
return example_client_certs(h, arg); switch (auth_type){
else case CLIXON_AUTH_NONE:
return 1; /* Shouldnt happen */
retval = 0; /* Ignore, shouldnt happen */
break;
case CLIXON_AUTH_CLIENT_CERTIFICATE:
retval = 0; /* Ignore, use default */
break;
case CLIXON_AUTH_USER:
if (example_basic_auth(h, req, authp, userp) < 0)
goto done;
retval = 1;
break;
}
done:
clicon_debug(1, "%s retval:%d auth:%d user:%s", __FUNCTION__, retval, *authp, *userp);
return retval;
} }
/*! Local example restconf rpc callback /*! Local example restconf rpc callback
@ -394,12 +384,6 @@ clixon_plugin_init(clicon_handle h)
optind = 1; optind = 1;
while ((c = getopt(argc, argv, RESTCONF_EXAMPLE_OPTS)) != -1) while ((c = getopt(argc, argv, RESTCONF_EXAMPLE_OPTS)) != -1)
switch (c) { switch (c) {
case 'a': /* basic authentication */
basic_auth = 1;
break;
case 's': /* ssl client certs */
ssl_client_certs = 1;
break;
default: default:
break; break;
} }

View file

@ -51,6 +51,7 @@
* Types * Types
*/ */
/*! Registered RPC callback function /*! Registered RPC callback function
* @param[in] h Clicon handle * @param[in] h Clicon handle
* @param[in] xn Request: <rpc><xn></rpc> * @param[in] xn Request: <rpc><xn></rpc>
@ -92,9 +93,18 @@ typedef int (*clicon_upgrade_cb)(
cbuf *cbret cbuf *cbret
); );
/* /* Clixon authentication type
* Prototypes * @see http-auth-type in clixon-restconf.yang
* For now only used by restconf frontend
*/ */
enum clixon_auth_type {
CLIXON_AUTH_NONE = 0, /* Message is authenticated automatically, Do not call ca-auth callback */
CLIXON_AUTH_CLIENT_CERTIFICATE, /* TLS Client certification authentication */
CLIXON_AUTH_USER, /* User-defined authentication according to ca-auth callback.
Such as "password" authentication */
};
typedef enum clixon_auth_type clixon_auth_type_t;
/* Common plugin function names, function types and signatures. /* Common plugin function names, function types and signatures.
* This plugin code is exytended by backend, cli, netconf, restconf plugins * This plugin code is exytended by backend, cli, netconf, restconf plugins
* Cli see cli_plugin.c * Cli see cli_plugin.c
@ -135,14 +145,41 @@ typedef int (plgextension_t)(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
/*! Called by restconf on each incoming request to check credentials and return username /*! Called by restconf on each incoming request to check credentials and return username
*/ */
/* Plugin authorization. Set username option (or not) /*! Plugin callback for authenticating messages (for restconf)
* @param[in] Clicon handle *
* @param[in] void*, eg Fastcgihandle request restconf * Given a message (its headers) and authentication type, determine if the message
* @retval -1 Fatal error * passes authentication.
* @retval 0 Credential not OK *
* @retval 1 Credential OK * If the message is not authenticated, an error message is returned with tag: "access denied" and
* HTTP error code 401 Unauthorized - Client is not authenticated
*
* If the message is authenticated, a user is associated with the message. This user can be derived
* from the headers or mapped in an application-dependent way. This user is used internally in Clixon and
* sent via the IPC protocol to the backend where it may be used for NACM authorization.
*
* The auth-type parameter specifies how the authentication is made and what default value is:
* none: Message is authenticated. No callback is called, authenticated user is set to special user
* "none". Typically assumes NACM is not enabled.
* client-cert: Default: Set to authenticated and extract the username from the SSL_CN parameter
* A callback can revise this behavior
* user: Default: Message is not authenticated (401 returned)
* Typically done by basic auth, eg HTTP_AUTHORIZATION header, and verify password
*
* If there are multiple callbacks, the first result which is not "ignore" is returned. This is to allow for
* different callbacks registering different classes, or grouping of authentication.
*
* @param[in] h Clicon handle
* @param[in] req Per-message request www handle to use with restconf_api.h
* @param[in] auth_type Authentication type: none, user-defined, or client-cert
* @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set
* @param[out] userp The associated user, malloced by plugin. Only if retval is 1/OK and authp=1,
* @retval -1 Fatal error
* @retval 0 Ignore, undecided, not handled, same as no callback
* @retval 1 OK, see auth parameter on result.
*
* @note user should be freed by caller
*/ */
typedef int (plgauth_t)(clicon_handle, void *); typedef int (plgauth_t)(clicon_handle h, void *req, clixon_auth_type_t auth_type, int *authp, char **userp);
/*! Reset system status /*! Reset system status
* @param[in] h Clicon handle * @param[in] h Clicon handle
@ -305,8 +342,7 @@ int clixon_plugin_start_all(clicon_handle h);
int clixon_plugin_exit_one(clixon_plugin *cp, clicon_handle h); int clixon_plugin_exit_one(clixon_plugin *cp, clicon_handle h);
int clixon_plugin_exit_all(clicon_handle h); int clixon_plugin_exit_all(clicon_handle h);
int clixon_plugin_auth_one(clixon_plugin *cp, clicon_handle h, void *arg); int clixon_plugin_auth_all(clicon_handle h, void *req, clixon_auth_type_t auth_type, int *authp, char **userp);
int clixon_plugin_auth_all(clicon_handle h, void *arg);
int clixon_plugin_extension_one(clixon_plugin *cp, clicon_handle h, yang_stmt *yext, yang_stmt *ys); int clixon_plugin_extension_one(clixon_plugin *cp, clicon_handle h, yang_stmt *yext, yang_stmt *ys);
int clixon_plugin_extension_all(clicon_handle h, yang_stmt *yext, yang_stmt *ys); int clixon_plugin_extension_all(clicon_handle h, yang_stmt *yext, yang_stmt *ys);
@ -324,4 +360,8 @@ int upgrade_callback_reg_fn(clicon_handle h, clicon_upgrade_cb cb, const char *s
int upgrade_callback_delete_all(clicon_handle h); int upgrade_callback_delete_all(clicon_handle h);
int upgrade_callback_call(clicon_handle h, cxobj *xt, char *ns, uint16_t op, uint32_t from, uint32_t to, cbuf *cbret); int upgrade_callback_call(clicon_handle h, cxobj *xt, char *ns, uint16_t op, uint32_t from, uint32_t to, cbuf *cbret);
const clixon_auth_type_t clixon_auth_type_str2int(char *auth_type);
const char *clixon_auth_type_int2str(clixon_auth_type_t auth_type);
#endif /* _CLIXON_PLUGIN_H_ */ #endif /* _CLIXON_PLUGIN_H_ */

View file

@ -46,6 +46,7 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <dirent.h> #include <dirent.h>
#include <syslog.h> #include <syslog.h>
#include <assert.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/param.h> #include <sys/param.h>
@ -55,6 +56,7 @@
#include "clixon_err.h" #include "clixon_err.h"
#include "clixon_queue.h" #include "clixon_queue.h"
#include "clixon_string.h"
#include "clixon_hash.h" #include "clixon_hash.h"
#include "clixon_log.h" #include "clixon_log.h"
#include "clixon_file.h" #include "clixon_file.h"
@ -462,73 +464,91 @@ clixon_plugin_exit_all(clicon_handle h)
} }
/*! Run the restconf user-defined credentials callback /*! Run the restconf user-defined credentials callback
* @param[in] cp Plugin handle * @param[in] h Clicon handle
* @param[in] h Clicon handle * @param[in] req Per-message request www handle to use with restconf_api.h
* @param[in] arg Argument, such as fastcgi handler for restconf * @param[in] auth_type Authentication type: none, user-defined, or client-cert
* @retval -1 Error * @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set
* @retval 0 Not authenticated * @param[out] userp The associated user, malloced by plugin. Only if retval is 1/OK and authp=1,
* @retval 1 Authenticated * @retval -1 Fatal error
* @retval 0 Ignore, undecided, not handled, same as no callback
* @retval 1 OK, see auth parameter on result.
* @note If authenticated either a callback was called and clicon_username_set() * @note If authenticated either a callback was called and clicon_username_set()
* Or no callback was found. * Or no callback was found.
*/ */
int static int
clixon_plugin_auth_one(clixon_plugin *cp, clixon_plugin_auth_one(clixon_plugin *cp,
clicon_handle h, clicon_handle h,
void *arg) void *req,
clixon_auth_type_t auth_type,
int *authp,
char **userp)
{ {
int retval = 1; /* Authenticated */ int retval = -1;
plgauth_t *fn; /* Plugin auth */ plgauth_t *fn; /* Plugin auth */
clicon_debug(1, "%s", __FUNCTION__);
if ((fn = cp->cp_api.ca_auth) != NULL){ if ((fn = cp->cp_api.ca_auth) != NULL){
if ((retval = fn(h, arg)) < 0) { if ((retval = fn(h, req, auth_type, authp, userp)) < 0) {
if (clicon_errno < 0) if (clicon_errno < 0)
clicon_log(LOG_WARNING, "%s: Internal error: Auth callback in plugin: %s returned -1 but did not make a clicon_err call", clicon_log(LOG_WARNING, "%s: Internal error: Auth callback in plugin: %s returned -1 but did not make a clicon_err call",
__FUNCTION__, cp->cp_name); __FUNCTION__, cp->cp_name);
goto done; goto done;
} }
} }
else
retval = 0; /* Ignored / no callback */
done: done:
clicon_debug(1, "%s retval:%d user:%s", __FUNCTION__, retval, *userp);
return retval; return retval;
} }
/*! Run the restconf user-defined credentials callback for all plugins /*! Run the restconf user-defined credentials callback for all plugins
* Find first authentication callback and call that, then return. * Find first authentication callback and call that, then return.
* The callback is to set the authenticated user * The callback is to set the authenticated user
* @param[in] cp Plugin handle * @param[in] h Clicon handle
* @param[in] h Clicon handle * @param[in] req Per-message request www handle to use with restconf_api.h
* @param[in] arg Argument, such as fastcgi handler for restconf * @param[in] auth_type Authentication type: none, user-defined, or client-cert
* @retval -1 Error * @param[out] authp 0: Credentials failed, no user set (401 returned). 1: Credentials OK and user set
* @retval 0 Not authenticated * @param[out] userp The associated user, malloced by plugin. Only if retval is 1/OK and authp=1,
* @retval 1 Authenticated * @retval -1 Fatal error
* @note If authenticated either a callback was called and clicon_username_set() * @retval 0 Ignore, undecided, not handled, same as no callback
* Or no callback was found. * @retval 1 OK, see auth parameter on result.
*/ */
int int
clixon_plugin_auth_all(clicon_handle h, clixon_plugin_auth_all(clicon_handle h,
void *arg) void *req,
clixon_auth_type_t auth_type,
int *authp,
char **userp)
{ {
int retval = -1; int retval = -1;
clixon_plugin *cp = NULL; clixon_plugin *cp = NULL;
int i = 0; int ret = 0;
int ret;
clicon_debug(1, "%s", __FUNCTION__);
if (authp == NULL || userp == NULL){
clicon_err(OE_PLUGIN, EINVAL, "Output parameter is NULL");
goto done;
}
*authp = -1;
*userp = NULL;
ret = 0; /* ignore */
while ((cp = clixon_plugin_each(h, cp)) != NULL) { while ((cp = clixon_plugin_each(h, cp)) != NULL) {
i++; if ((ret = clixon_plugin_auth_one(cp, h, req, auth_type, authp, userp)) < 0)
if ((ret = clixon_plugin_auth_one(cp, h, arg)) < 0)
goto done; goto done;
if (ret == 1) if (ret == 1)
goto authenticated; break; /* result, not ignored */
break; /* ret == 0, ignore try next */
}
retval = ret;
if (retval == 1){
assert(*authp != -1);
if (*authp == 1)
assert(*userp != NULL);
} }
if (i==0)
retval = 1;
else
retval = 0;
done: done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
return retval; return retval;
authenticated:
retval = 1;
goto done;
} }
/*! Callback for a yang extension (unknown) statement single plugin /*! Callback for a yang extension (unknown) statement single plugin
@ -931,3 +951,29 @@ upgrade_callback_call(clicon_handle h,
goto done; goto done;
} }
/* Authentication type
* @see http-auth-type in clixon-restconf.yang
* @see restconf_media_str2int
*/
static const map_str2int clixon_auth_type[] = {
{"none", CLIXON_AUTH_NONE},
{"client-certificate", CLIXON_AUTH_CLIENT_CERTIFICATE},
{"user", CLIXON_AUTH_USER},
{NULL, -1}
};
/*! Translate from string to auth-type
*/
const clixon_auth_type_t
clixon_auth_type_str2int(char *auth_type)
{
return clicon_str2int(clixon_auth_type, auth_type);
}
/*! Translate from auth-type to string
*/
const char *
clixon_auth_type_int2str(clixon_auth_type_t auth_type)
{
return clicon_int2str(clixon_auth_type, auth_type);
}

View file

@ -196,11 +196,16 @@ fi
# Default restconf configuration: http IPv4 # Default restconf configuration: http IPv4
# Can be placed in clixon-config # Can be placed in clixon-config
# Note that https clause assumes there exists certs and keys in /etc/ssl,... # Note that https clause assumes there exists certs and keys in /etc/ssl,...
if [ $RCPROTO = http ]; then function restconf_config()
RESTCONFIG="<restconf><enable>true</enable><auth-type>password</auth-type><socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket></restconf>" {
else AUTH=$1
RESTCONFIG="<restconf><enable>true</enable><auth-type>password</auth-type><server-cert-path>/etc/ssl/certs/clixon-server-crt.pem</server-cert-path><server-key-path>/etc/ssl/private/clixon-server-key.pem</server-key-path><server-ca-cert-path>/etc/ssl/certs/clixon-ca-crt.pem</server-ca-cert-path><socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket></restconf>" if [ $RCPROTO = http ]; then
fi RESTCONFIG="<restconf><enable>true</enable><auth-type>$AUTH</auth-type><debug>1</debug><socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket></restconf>"
else
RESTCONFIG="<restconf><enable>true</enable><auth-type>$AUTH</auth-type><server-cert-path>/etc/ssl/certs/clixon-server-crt.pem</server-cert-path><server-key-path>/etc/ssl/private/clixon-server-key.pem</server-key-path><server-ca-cert-path>/etc/ssl/certs/clixon-ca-crt.pem</server-ca-cert-path><debug>1</debug><socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket></restconf>"
fi
}
# Some tests may set owner of testdir to something strange and quit, need # Some tests may set owner of testdir to something strange and quit, need
# to reset to me # to reset to me
@ -374,7 +379,7 @@ function new(){
# Evaluate and return # Evaluate and return
# Example: expectpart $(fn arg) 0 "my return" -- "foo" # Example: expectpart $(fn arg) 0 "my return" -- "foo"
# - evaluated expression # - evaluated expression
# - expected command return value (0 if OK) # - expected command return value (0 if OK) or list of values, eg "55 56"
# - expected stdout outcome* # - expected stdout outcome*
# - the token "--not--" # - the token "--not--"
# - not expected stdout outcome* # - not expected stdout outcome*
@ -391,10 +396,24 @@ function expectpart(){
# echo "ret:\"$ret\"" # echo "ret:\"$ret\""
# echo "retval:$retval" # echo "retval:$retval"
# echo "expect:\"$expect\"" # echo "expect:\"$expect\""
if [ $r != $retval ]; then if [ "$retval" -eq "$retval" 2> /dev/null ] ; then # single retval
echo -e "\e[31m\nError ($r != $retval) in Test$testnr [$testname]:" if [ $r != $retval ]; then
echo -e "\e[0m:" echo -e "\e[31m\nError ($r != $retval) in Test$testnr [$testname]:"
exit -1 echo -e "\e[0m:"
exit -1
fi
else # List of retvals
found=0
for rv in $retval; do
if [ $r == $rv ]; then
found=1
fi
done
if [ $found -eq 0 ]; then
echo -e "\e[31m\nError ($r != $retval) in Test$testnr [$testname]:"
echo -e "\e[0m:"
exit -1
fi
fi fi
if [ -z "$ret" -a -z "$expect" ]; then if [ -z "$ret" -a -z "$expect" ]; then
return return

View file

@ -24,6 +24,9 @@ if [ ! -d $pdir ]; then
mkdir $pdir mkdir $pdir
fi fi
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>/tmp/conf_yang.xml</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>/tmp/conf_yang.xml</CLICON_CONFIGFILE>
@ -273,4 +276,7 @@ stop_backend -f $cfg
# unset conditional parameters # unset conditional parameters
unset format unset format
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -23,6 +23,9 @@ cfg=$dir/conf_yang.xml
fyang=$dir/main.yang fyang=$dir/main.yang
fyang2=$dir/ietf-interfaces@2019-03-04.yang fyang2=$dir/ietf-interfaces@2019-03-04.yang
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -273,4 +276,7 @@ if [ $BE -ne 0 ]; then
stop_backend -f $cfg stop_backend -f $cfg
fi fi
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -14,6 +14,9 @@ APPNAME=example
cfg=$dir/choice.xml cfg=$dir/choice.xml
fyang=$dir/type.yang fyang=$dir/type.yang
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -298,4 +301,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -21,6 +21,9 @@ if [ ! -d $pdir ]; then
mkdir $pdir mkdir $pdir
fi fi
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -171,4 +174,7 @@ stop_backend -f $cfg
# unset conditional parameters # unset conditional parameters
unset format unset format
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -29,6 +29,9 @@ cfg=$dir/conf_yang.xml
# Use yang in example # Use yang in example
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -188,4 +191,7 @@ if [ $BE -ne 0 ]; then
stop_backend -f $cfg stop_backend -f $cfg
fi fi
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -10,6 +10,9 @@ APPNAME=example
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang=$dir/example-my-crypto.yang fyang=$dir/example-my-crypto.yang
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -334,4 +337,7 @@ fi
endtest endtest
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -17,6 +17,9 @@ APPNAME=example
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang fyang=$dir/nacm-example.yang
# Define default restconfig config: RESTCONFIG
restconf_config user
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -132,8 +135,8 @@ if [ $RC -ne 0 ]; then
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable basic authentication)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "waiting" new "waiting"
wait_restconf wait_restconf
@ -202,4 +205,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -45,6 +45,9 @@ cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang fyang=$dir/nacm-example.yang
fyang2=$dir/itf.yang fyang2=$dir/itf.yang
# Define default restconfig config: RESTCONFIG
restconf_config user
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -232,8 +235,8 @@ if [ $RC -ne 0 ]; then
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable basic authentication)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "waiting" new "waiting"
wait_restconf wait_restconf
@ -332,4 +335,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -17,6 +17,9 @@ APPNAME=example
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang fyang=$dir/nacm-example.yang
# Define default restconfig config: RESTCONFIG
restconf_config user
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -106,8 +109,8 @@ if [ $RC -ne 0 ]; then
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable basic authentication)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "waiting" new "waiting"
wait_restconf wait_restconf
@ -165,4 +168,7 @@ if [ $BE -ne 0 ]; then # Bring your own backend
stop_backend -f $cfg stop_backend -f $cfg
fi fi
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -25,6 +25,9 @@ cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang fyang=$dir/nacm-example.yang
fyang2=$dir/nacm-example2.yang fyang2=$dir/nacm-example2.yang
# Define default restconfig config: RESTCONFIG
restconf_config user
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -237,8 +240,8 @@ if [ $RC -ne 0 ]; then
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable basic authentication)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "waiting" new "waiting"
wait_restconf wait_restconf
@ -297,4 +300,7 @@ if [ $BE -ne 0 ]; then # Bring your own backend
stop_backend -f $cfg stop_backend -f $cfg
fi fi
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -17,6 +17,9 @@ APPNAME=example
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang fyang=$dir/nacm-example.yang
# Define default restconfig config: RESTCONFIG
restconf_config user
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -233,8 +236,8 @@ if [ $RC -ne 0 ]; then
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable basic authentication)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "waiting" new "waiting"
wait_restconf wait_restconf
@ -295,4 +298,7 @@ if [ $BE -ne 0 ]; then # Bring your own backend
stop_backend -f $cfg stop_backend -f $cfg
fi fi
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -13,6 +13,9 @@ fyang=$dir/nacm-example.yang
# Which format to use as datastore format internally # Which format to use as datastore format internally
: ${format:=xml} : ${format:=xml}
# Define default restconfig config: RESTCONFIG
restconf_config user
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -112,8 +115,8 @@ EOF
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable basic authentication)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "wait restconf" new "wait restconf"
wait_restconf wait_restconf
@ -234,5 +237,8 @@ endtest
rm -rf $dir rm -rf $dir
# Set by restconf_config
unset RESTCONFIG
# unset conditional parameters # unset conditional parameters
unset format unset format

View file

@ -15,6 +15,9 @@ cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang fyang=$dir/nacm-example.yang
nacmfile=$dir/nacmfile nacmfile=$dir/nacmfile
# Define default restconfig config: RESTCONFIG
restconf_config user
# Note filter out example_backend_nacm.so in CLICON_BACKEND_REGEXP below # Note filter out example_backend_nacm.so in CLICON_BACKEND_REGEXP below
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
@ -151,8 +154,8 @@ if [ $RC -ne 0 ]; then
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable http basic auth)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "waiting" new "waiting"
wait_restconf wait_restconf
@ -227,4 +230,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -18,6 +18,9 @@ APPNAME=example
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang fyang=$dir/nacm-example.yang
# Define default restconfig config: RESTCONFIG
restconf_config user
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -134,8 +137,8 @@ if [ $RC -ne 0 ]; then
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable basic authentication)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "waiting" new "waiting"
wait_restconf wait_restconf
@ -270,4 +273,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -31,6 +31,9 @@ APPNAME=example
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang fyang=$dir/nacm-example.yang
# Define default restconfig config: RESTCONFIG
restconf_config user
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -153,8 +156,8 @@ if [ $RC -ne 0 ]; then
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable basic authentication)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "waiting" new "waiting"
wait_restconf wait_restconf
@ -272,4 +275,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -34,6 +34,9 @@ APPNAME=example
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang=$dir/nacm-example.yang fyang=$dir/nacm-example.yang
# Define default restconfig config: RESTCONFIG
restconf_config user
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -155,8 +158,8 @@ if [ $RC -ne 0 ]; then
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable basic authentication)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "waiting" new "waiting"
wait_restconf wait_restconf
@ -168,7 +171,6 @@ expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><ca
new "commit it" new "commit it"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
new "enable nacm" new "enable nacm"
expectpart "$(curl -u andy:bar $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-netconf-acm:enable-nacm": true}' $RCPROTO://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 "HTTP/1.1 204 No Content" expectpart "$(curl -u andy:bar $CURLOPTS -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-netconf-acm:enable-nacm": true}' $RCPROTO://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 "HTTP/1.1 204 No Content"
@ -239,4 +241,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -20,6 +20,9 @@ fyang=$dir/nacm-example.yang
# cred:none, exact, except # cred:none, exact, except
# Define default restconfig config: RESTCONFIG
restconf_config user
cat <<EOF > $fyang cat <<EOF > $fyang
module nacm-example{ module nacm-example{
yang-version 1.1; yang-version 1.1;
@ -103,8 +106,8 @@ EOF
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable basic authentication)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "waiting" new "waiting"
wait_restconf wait_restconf
@ -226,4 +229,7 @@ testrun $CRED $REALUSER $PSEUDO $RECOVERY false false
endtest endtest
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -52,6 +52,9 @@ module scaling{
} }
EOF EOF
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -210,6 +213,9 @@ stop_backend -f $cfg
rm -rf $dir rm -rf $dir
# Set by restconf_config
unset RESTCONFIG
# unset conditional parameters # unset conditional parameters
unset format unset format
unset perfnr unset perfnr

View file

@ -29,6 +29,9 @@ fyang=$dir/$APPNAME.yang
fconfig=$dir/large.xml fconfig=$dir/large.xml
fstate=$dir/state.xml fstate=$dir/state.xml
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -214,4 +217,6 @@ unset format
unset perfnr unset perfnr
unset perfreq unset perfreq
# Set by restconf_config
unset RESTCONFIG

View file

@ -29,6 +29,9 @@ fyang=$dir/$APPNAME.yang
fconfig=$dir/large.xml fconfig=$dir/large.xml
fstate=$dir/state.xml fstate=$dir/state.xml
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -198,9 +201,12 @@ fi
rm -rf $dir rm -rf $dir
# Define default restconfig config: RESTCONFIG
restconf_config none
# unset conditional parameters # unset conditional parameters
unset format unset format
unset perfnr unset perfnr
unset perfreq unset perfreq

View file

@ -37,6 +37,57 @@ if [ -d ${TOP_SRCDIR}/yang/clixon ]; then
else else
cp /usr/local/share/clixon/$y $dir/ cp /usr/local/share/clixon/$y $dir/
fi fi
if [ "${WITH_RESTCONF}" = "evhtp" ]; then
# Create server certs
certdir=$dir/certs
srvkey=$certdir/srv_key.pem
srvcert=$certdir/srv_cert.pem
cakey=$certdir/ca_key.pem # needed?
cacert=$certdir/ca_cert.pem
test -d $certdir || mkdir $certdir
. ./certs.sh
else
# Define default restconfig config: RESTCONFIG
restconf_config none
fi
# This is a fixed 'state' implemented in routing_backend. It is assumed to be always there
state='{"clixon-example:state":{"op":\["41","42","43"\]}'
if $IPv6; then
# For backend config, create 4 sockets, all combinations IPv4/IPv6 + http/https
RESTCONFIG1=$(cat <<EOF
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<auth-type>none</auth-type>
<server-cert-path>$srvcert</server-cert-path>
<server-key-path>$srvkey</server-key-path>
<server-ca-cert-path>$cakey</server-ca-cert-path>
<socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket>
<socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket>
<socket><namespace>default</namespace><address>::</address><port>80</port><ssl>false</ssl></socket>
<socket><namespace>default</namespace><address>::</address><port>443</port><ssl>true</ssl></socket>
</restconf>
EOF
)
else
# For backend config, create 4 sockets, all combinations IPv4/IPv6 + http/https
RESTCONFIG1=$(cat <<EOF
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<auth-type>none</auth-type>
<server-cert-path>$srvcert</server-cert-path>
<server-key-path>$srvkey</server-key-path>
<server-ca-cert-path>$cakey</server-ca-cert-path>
<socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket>
<socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket>
</restconf>
EOF
)
fi
# Start with common config, then append fcgi/evhtp specific config
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -54,54 +105,10 @@ cat <<EOF > $cfg
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE> <CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR> <CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
<CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895> <CLICON_MODULE_LIBRARY_RFC7895>true</CLICON_MODULE_LIBRARY_RFC7895>
$RESTCONFIG <!-- only fcgi -->
</clixon-config> </clixon-config>
EOF EOF
if [ "${WITH_RESTCONF}" = "evhtp" ]; then
# Create server certs
certdir=$dir/certs
srvkey=$certdir/srv_key.pem
srvcert=$certdir/srv_cert.pem
cakey=$certdir/ca_key.pem # needed?
cacert=$certdir/ca_cert.pem
test -d $certdir || mkdir $certdir
. ./certs.sh
fi
# This is a fixed 'state' implemented in routing_backend. It is assumed to be always there
state='{"clixon-example:state":{"op":\["41","42","43"\]}'
if $IPv6; then
# For backend config, create 4 sockets, all combinations IPv4/IPv6 + http/https
RESTCONFIG=$(cat <<EOF
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<auth-type>password</auth-type>
<server-cert-path>$srvcert</server-cert-path>
<server-key-path>$srvkey</server-key-path>
<server-ca-cert-path>$cakey</server-ca-cert-path>
<socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket>
<socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket>
<socket><namespace>default</namespace><address>::</address><port>80</port><ssl>false</ssl></socket>
<socket><namespace>default</namespace><address>::</address><port>443</port><ssl>true</ssl></socket>
</restconf>
EOF
)
else
# For backend config, create 4 sockets, all combinations IPv4/IPv6 + http/https
RESTCONFIG=$(cat <<EOF
<restconf xmlns="http://clicon.org/restconf">
<enable>true</enable>
<auth-type>password</auth-type>
<server-cert-path>$srvcert</server-cert-path>
<server-key-path>$srvkey</server-key-path>
<server-ca-cert-path>$cakey</server-ca-cert-path>
<socket><namespace>default</namespace><address>0.0.0.0</address><port>80</port><ssl>false</ssl></socket>
<socket><namespace>default</namespace><address>0.0.0.0</address><port>443</port><ssl>true</ssl></socket>
</restconf>
EOF
)
fi
# Restconf test routine with arguments: # Restconf test routine with arguments:
# 1. proto:http/https # 1. proto:http/https
@ -132,7 +139,7 @@ function testrun()
wait_backend wait_backend
new "netconf edit config" new "netconf edit config"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config>$RESTCONFIG</config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config>$RESTCONFIG1</config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
new "netconf commit" new "netconf commit"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
@ -403,4 +410,8 @@ done
# unset conditional parameters # unset conditional parameters
unset RCPROTO unset RCPROTO
# Set by restconf_config
unset RESTCONFIG
unset RESTCONFIG1
rm -rf $dir rm -rf $dir

View file

@ -12,6 +12,9 @@ APPNAME=example
cfg=$dir/conf.xml cfg=$dir/conf.xml
fyang=$dir/restconf.yang fyang=$dir/restconf.yang
# Define default restconfig config: RESTCONFIG
restconf_config none
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> # <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
@ -219,4 +222,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -30,6 +30,9 @@ fyang2=$dir/augment.yang
fxml=$dir/initial.xml fxml=$dir/initial.xml
fstate=$dir/state.xml fstate=$dir/state.xml
# Define default restconfig config: RESTCONFIG
restconf_config none
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> # <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
@ -256,4 +259,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -23,6 +23,9 @@ cat <<EOF > $dir/example-system.yang
} }
EOF EOF
# Define default restconfig config: RESTCONFIG
restconf_config none
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> # <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
@ -267,4 +270,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -10,6 +10,9 @@ APPNAME=example
cfg=$dir/conf.xml cfg=$dir/conf.xml
fyang=$dir/list.yang fyang=$dir/list.yang
# Define default restconfig config: RESTCONFIG
restconf_config none
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> # <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
@ -182,4 +185,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -41,7 +41,7 @@ test -d $certdir || mkdir $certdir
RESTCONFIG=$(cat <<EOF RESTCONFIG=$(cat <<EOF
<restconf> <restconf>
<enable>true</enable> <enable>true</enable>
<auth-type>password</auth-type> <auth-type>none</auth-type>
<server-cert-path>$srvcert</server-cert-path> <server-cert-path>$srvcert</server-cert-path>
<server-key-path>$srvkey</server-key-path> <server-key-path>$srvkey</server-key-path>
<server-ca-cert-path>$cakey</server-ca-cert-path> <server-ca-cert-path>$cakey</server-ca-cert-path>

View file

@ -41,6 +41,9 @@ cfg=$dir/conf.xml
fyang=$dir/stream.yang fyang=$dir/stream.yang
xml=$dir/xml.xml xml=$dir/xml.xml
# Define default restconfig config: RESTCONFIG
restconf_config none
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN> # <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
@ -63,6 +66,7 @@ cat <<EOF > $cfg
<CLICON_STREAM_PATH>streams</CLICON_STREAM_PATH> <CLICON_STREAM_PATH>streams</CLICON_STREAM_PATH>
<CLICON_STREAM_URL>https://localhost</CLICON_STREAM_URL> <CLICON_STREAM_URL>https://localhost</CLICON_STREAM_URL>
<CLICON_STREAM_RETENTION>60</CLICON_STREAM_RETENTION> <CLICON_STREAM_RETENTION>60</CLICON_STREAM_RETENTION>
$RESTCONFIG
</clixon-config> </clixon-config>
EOF EOF
@ -285,6 +289,9 @@ fi
rm -rf $dir rm -rf $dir
# Set by restconf_config
unset RESTCONFIG
# unset conditional parameters # unset conditional parameters
unset clixon_util_stream unset clixon_util_stream
unset nr unset nr

View file

@ -3,6 +3,7 @@
# Use nacm module in example/main/example_restconf.c hardcoded to # Use nacm module in example/main/example_restconf.c hardcoded to
# andy:bar and wilma:bar # andy:bar and wilma:bar
# Magic line must be first in script (see README.md) # Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
@ -12,6 +13,9 @@ cfg=$dir/conf.xml
startupdb=$dir/startup_db startupdb=$dir/startup_db
fjukebox=$dir/example-jukebox.yang fjukebox=$dir/example-jukebox.yang
# Define default restconfig config: RESTCONFIG
restconf_config user
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -116,8 +120,8 @@ if [ $RC -ne 0 ]; then
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable basic authentication)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "waiting restconf" new "waiting restconf"
wait_restconf wait_restconf
@ -173,8 +177,8 @@ if [ $RC -ne 0 ]; then
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon (-a is enable basic authentication)" new "start restconf daemon"
start_restconf -f $cfg -- -a start_restconf -f $cfg
new "waiting" new "waiting"
wait_restconf wait_restconf
@ -260,4 +264,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -16,6 +16,9 @@ APPNAME=example
cfg=$dir/conf.xml cfg=$dir/conf.xml
startupdb=$dir/startup_db startupdb=$dir/startup_db
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -324,5 +327,8 @@ sleep $DEMWAIT # Lots of processes need to die before next test
new "endtest" new "endtest"
endtest endtest
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -33,6 +33,8 @@ cacert=$certdir/ca_cert.pem
users="andy guest" # generate certs for some users in nacm.sh users="andy guest" # generate certs for some users in nacm.sh
xusers="limited" # Set invalid cert
# Whether to generate new keys or not (only if $dir is not removed) # Whether to generate new keys or not (only if $dir is not removed)
# Here dont generate keys if restconf started stand-alone (RC=0) # Here dont generate keys if restconf started stand-alone (RC=0)
: ${genkeys:=true} : ${genkeys:=true}
@ -95,7 +97,7 @@ if $genkeys; then
. ./certs.sh . ./certs.sh
# create client certs # create client certs
for name in $users; do for name in $users $xusers; do
cat<<EOF > $dir/$name.cnf cat<<EOF > $dir/$name.cnf
[req] [req]
prompt = no prompt = no
@ -117,6 +119,10 @@ EOF
openssl x509 -req -extfile $dir/$name.cnf -days 1 -passin "pass:password" -in $certdir/$name.csr -CA $cacert -CAkey $cakey -CAcreateserial -out $certdir/$name.crt openssl x509 -req -extfile $dir/$name.cnf -days 1 -passin "pass:password" -in $certdir/$name.csr -CA $cacert -CAkey $cakey -CAcreateserial -out $certdir/$name.crt
done # client key done # client key
# invalid
for name in $xusers; do
openssl x509 -req -extfile $dir/$name.cnf -days 0 -passin "pass:password" -in $certdir/$name.csr -CA $cacert -CAkey $cakey -CAcreateserial -out $certdir/$name.crt
done # invalid
fi # genkeys fi # genkeys
# Write local config # Write local config
@ -145,6 +151,7 @@ cat <<EOF > $cfg
<server-cert-path>$srvcert</server-cert-path> <server-cert-path>$srvcert</server-cert-path>
<server-key-path>$srvkey</server-key-path> <server-key-path>$srvkey</server-key-path>
<server-ca-cert-path>$cacert</server-ca-cert-path> <server-ca-cert-path>$cacert</server-ca-cert-path>
<!--debug>1</debug-->
<socket> <socket>
<namespace>default</namespace> <namespace>default</namespace>
<address>0.0.0.0</address> <address>0.0.0.0</address>
@ -181,8 +188,8 @@ EOF
if [ $RC -ne 0 ]; then if [ $RC -ne 0 ]; then
new "kill old restconf daemon" new "kill old restconf daemon"
stop_restconf_pre stop_restconf_pre
new "start restconf daemon -s -c -- -s" new "start restconf daemon -s -c"
start_restconf -f $cfg -- -s start_restconf -f $cfg
fi fi
new "wait for restconf" new "wait for restconf"
@ -203,6 +210,18 @@ EOF
new "admin get x 42" new "admin get x 42"
expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 200 OK" '{"example:x":42}' expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 200 OK" '{"example:x":42}'
# Negative tests
new "Unknown yyy no cert get x 42"
echo "dummy" > $certdir/yyy.key
echo "dummy" > $certdir/yyy.crt
expectpart "$(curl $CURLOPTS --key $certdir/yyy.key --cert $certdir/yyy.crt -X GET $RCPROTO://localhost/restconf/data/example:x 2>&1)" 58 " could not load PEM client certificate"
new "Certificate required"
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example:x 2>&1)" "55 56"
new "limited invalid cert"
expectpart "$(curl $CURLOPTS --key $certdir/limited.key --cert $certdir/limited.crt -X GET $RCPROTO://localhost/restconf/data/example:x 2>&1)" 56 "certificate expired"
if [ $RC -ne 0 ]; then if [ $RC -ne 0 ]; then
new "Kill restconf daemon" new "Kill restconf daemon"
stop_restconf stop_restconf
@ -226,3 +245,5 @@ rm -rf $dir
# unset conditional parameters # unset conditional parameters
unset RCPROTO unset RCPROTO
endtest

View file

@ -34,6 +34,9 @@ EOF
# Use yang in example # Use yang in example
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -128,4 +131,7 @@ if [ -f $dir/startup_db ]; then
err "startup should not exist" err "startup should not exist"
fi fi
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -13,6 +13,9 @@ APPNAME=example
cfg=$dir/conf.xml cfg=$dir/conf.xml
# Define default restconfig config: RESTCONFIG
restconf_config none
# Use yang in example # Use yang in example
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
@ -199,4 +202,7 @@ fi
# kill backend # kill backend
stop_backend -f $cfg stop_backend -f $cfg
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -27,6 +27,9 @@ fextra=$dir/extra.yang # Referenced from main (with same prefix)
fextra1=$dir/extra1.yang # Referenced from sub1 fextra1=$dir/extra1.yang # Referenced from sub1
fextra2=$dir/extra2.yang # Referenced from sub2 fextra2=$dir/extra2.yang # Referenced from sub2
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -238,4 +241,7 @@ fi
stop_backend -f $cfg stop_backend -f $cfg
sudo pkill -u root -f clixon_backend sudo pkill -u root -f clixon_backend
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -21,6 +21,9 @@ fanydata=$dir/yang/anydata.yang
funknown=$dir/yang/unknown.yang funknown=$dir/yang/unknown.yang
fstate=$dir/state.xml fstate=$dir/state.xml
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $fanydata cat <<EOF > $fanydata
module any{ module any{
yang-version 1.1; yang-version 1.1;
@ -277,4 +280,7 @@ testrun false true
new "startup, treat unknown as anydata----" new "startup, treat unknown as anydata----"
testrun true true testrun true true
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -13,6 +13,9 @@ cfg=$dir/conf_yang.xml
fyang1=$dir/example1.yang fyang1=$dir/example1.yang
fyang2=$dir/example2.yang fyang2=$dir/example2.yang
# Define default restconfig config: RESTCONFIG
restconf_config none
cat <<EOF > $cfg cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config"> <clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
@ -141,4 +144,7 @@ if [ $BE -ne 0 ]; then
stop_backend -f $cfg stop_backend -f $cfg
fi fi
# Set by restconf_config
unset RESTCONFIG
rm -rf $dir rm -rf $dir

View file

@ -45,7 +45,7 @@ YANGSPECS = clixon-config@2020-12-30.yang
YANGSPECS += clixon-lib@2020-12-30.yang YANGSPECS += clixon-lib@2020-12-30.yang
YANGSPECS += clixon-rfc5277@2008-07-01.yang YANGSPECS += clixon-rfc5277@2008-07-01.yang
YANGSPECS += clixon-xml-changelog@2019-03-21.yang YANGSPECS += clixon-xml-changelog@2019-03-21.yang
YANGSPECS += clixon-restconf@2020-10-30.yang YANGSPECS += clixon-restconf@2020-12-30.yang
APPNAME = clixon # subdir ehere these files are installed APPNAME = clixon # subdir ehere these files are installed

View file

@ -0,0 +1,160 @@
module clixon-restconf {
yang-version 1.1;
namespace "http://clicon.org/restconf";
prefix "clrc";
import ietf-inet-types {
prefix inet;
}
organization
"Clixon";
contact
"Olof Hagsand <olof@hagsand.se>";
description
"This YANG module provides a data-model for the Clixon RESTCONF daemon.
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
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 *****";
revision 2020-12-30 {
description
"Added: debug field
Added 'none' as default value for auth-type
Changed http-auth-type enum from 'password' to 'user'";
}
revision 2020-10-30 {
description
"Initial release";
}
typedef http-auth-type {
type enumeration {
enum none {
description
"Incoming message are set to authenticated by default. No ca-auth callback is called,
Authenticated user is set to special user 'none'.
Typically assumes NACM is not enabled.";
}
enum client-certificate {
description
"TLS client certificate validation is made on each incoming message. If it passes
the authenticated user is extracted from the SSL_CN parameter
The ca-auth callback can be used to revise this behavior.";
}
enum user {
description
"User-defined authentication as defined by the ca-auth callback.
One example is some form of password authentication, such as basic auth.";
}
}
description
"Enumeration of HTTP authorization types.";
}
grouping clixon-restconf{
description
"HTTP RESTCONF configuration.";
leaf enable {
type boolean;
default "false";
description
"Enables RESTCONF functionality.
Note that starting/stopping of a restconf daemon is different from it being
enabled or not.
For example, if the restconf daemon is under systemd management, the restconf
daemon will only start if enable=true.";
}
leaf auth-type {
type http-auth-type;
description
"The authentication type.
Note client-certificate applies only if ssl-enable is true and socket has ssl";
default none;
}
leaf server-cert-path {
type string;
description
"Path to server certificate file.
Note only applies if socket has ssl enabled";
}
leaf server-key-path {
type string;
description
"Path to server key file
Note only applies if socket has ssl enabled";
}
leaf server-ca-cert-path {
type string;
description
"Path to server CA cert file
Note only applies if socket has ssl enabled";
}
leaf debug {
description
"Set debug level of restconf daemon.
0 is no debug, 1 is debugging, more is detailed debug.
Debug logs will be directed to syslog with
ident: clixon_restconf and PID
facility: LOG_USER
level: LOG_DEBUG";
type uint32;
default 0;
}
list socket {
key "namespace address port";
leaf namespace {
type string;
description "indicates a namespace for instance. On platforms where namespaces are not suppported, always 'default'";
}
leaf address {
type inet:ip-address;
description "IP address to bind to";
}
leaf port {
type inet:port-number;
description "IP port to bind to";
}
leaf ssl {
type boolean;
default true;
description "Enable for HTTPS otherwise HTTP protocol";
}
}
}
container restconf {
description
"This presence is strictly not necessary since the enable flag
in clixon-restconf is the flag bearing the actual semantics.
However, removing the presence leads to default config in all
clixon installations, even those which do not use backend-started restconf.
One could see this as mostly cosmetically annoying.
Alternative would be to make the inclusion of this yang conditional.";
presence "Enables RESTCONF";
uses clixon-restconf;
}
}