Adding upstream version 2.0.24.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e508fcfeb9
commit
afb0a8fea7
118 changed files with 45084 additions and 0 deletions
69
src/config.h.in
Normal file
69
src/config.h.in
Normal file
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* \file config.h
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2 various configuration settings.
|
||||
*
|
||||
* Copyright (c) 2015 - 2017 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_CONFIG_H_
|
||||
#define NC_CONFIG_H_
|
||||
|
||||
/*
|
||||
* Mark all objects as hidden and export only objects explicitly marked to be part of the public API or
|
||||
* those marked as mock objects for testing purpose
|
||||
*/
|
||||
#define API __attribute__((visibility("default")))
|
||||
#define MOCK __attribute__((visibility("default")))
|
||||
|
||||
/*
|
||||
* Support for getpeereid
|
||||
*/
|
||||
#cmakedefine HAVE_GETPEEREID
|
||||
|
||||
/*
|
||||
* Support for shadow file manipulation
|
||||
*/
|
||||
#cmakedefine HAVE_SHADOW
|
||||
|
||||
/*
|
||||
* Support for crypt.h
|
||||
*/
|
||||
#cmakedefine HAVE_CRYPT
|
||||
|
||||
/*
|
||||
* Location of installed basic YANG modules on the system
|
||||
*/
|
||||
#define NC_YANG_DIR "@YANG_MODULE_DIR@"
|
||||
|
||||
/*
|
||||
* Inactive read timeout
|
||||
*/
|
||||
#define NC_READ_INACT_TIMEOUT @READ_INACTIVE_TIMEOUT@
|
||||
|
||||
/*
|
||||
* Active read timeout in seconds
|
||||
* (also used for internal <get-schema> RPC reply timeout)
|
||||
*/
|
||||
#define NC_READ_ACT_TIMEOUT @READ_ACTIVE_TIMEOUT@
|
||||
|
||||
/*
|
||||
* pspoll structure queue size (also found in nc_server.h)
|
||||
*/
|
||||
#define NC_PS_QUEUE_SIZE @MAX_PSPOLL_THREAD_COUNT@
|
||||
|
||||
/* Microseconds after which tasks are repeated until the full timeout elapses.
|
||||
* A millisecond (1000) should be divisible by this number without remain.
|
||||
*/
|
||||
#define NC_TIMEOUT_STEP @TIMEOUT_STEP@
|
||||
|
||||
/* Portability feature-check macros. */
|
||||
#cmakedefine HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP
|
||||
|
||||
#endif /* NC_CONFIG_H_ */
|
669
src/libnetconf.h
Normal file
669
src/libnetconf.h
Normal file
|
@ -0,0 +1,669 @@
|
|||
/**
|
||||
* @file libnetconf.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 main internal header.
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_LIBNETCONF_H_
|
||||
#define NC_LIBNETCONF_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "log_p.h"
|
||||
#include "messages_p.h"
|
||||
#include "netconf.h"
|
||||
#include "session_p.h"
|
||||
|
||||
/* Tests whether string is empty or non-empty. */
|
||||
#define strisempty(str) ((str)[0] == '\0')
|
||||
#define strnonempty(str) ((str)[0] != '\0')
|
||||
|
||||
/**
|
||||
* @mainpage About
|
||||
*
|
||||
* libnetconf2 is a NETCONF library in C handling NETCONF authentication and all NETCONF
|
||||
* RPC communication both server and client-side. Note that NETCONF datastore implementation
|
||||
* is not a part of this library. The library supports both NETCONF 1.0
|
||||
* ([RFC 4741](https://tools.ietf.org/html/rfc4741)) as well as NETCONF 1.1
|
||||
* ([RFC 6241](https://tools.ietf.org/html/rfc6241)).
|
||||
*
|
||||
* @section about-features Main Features
|
||||
*
|
||||
* - Creating SSH ([RFC 4742](https://tools.ietf.org/html/rfc4742), [RFC 6242](https://tools.ietf.org/html/rfc6242)),
|
||||
* using [libssh](https://www.libssh.org/), or TLS ([RFC 7589](https://tools.ietf.org/html/rfc7589)),
|
||||
* using [OpenSSL](https://www.openssl.org/), authenticated NETCONF sessions.
|
||||
* - Creating NETCONF sessions with a pre-established transport protocol
|
||||
* (using this mechanism the communication can be tunneled through sshd(8), for instance).
|
||||
* - Creating NETCONF Call Home sessions ([RFC 8071](https://tools.ietf.org/html/rfc8071)).
|
||||
* - Creating, sending, receiving, and replying to RPCs ([RFC 4741](https://tools.ietf.org/html/rfc4741),
|
||||
* [RFC 6241](https://tools.ietf.org/html/rfc6241)).
|
||||
* - Creating, sending and receiving NETCONF Event Notifications ([RFC 5277](https://tools.ietf.org/html/rfc5277)),
|
||||
*
|
||||
* @section about-license License
|
||||
*
|
||||
* Copyright (c) 2015-2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* (The BSD 3-Clause License)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name of the Company nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page howto How To ...
|
||||
*
|
||||
* - @subpage howtoinit
|
||||
* - @subpage howtoclient
|
||||
* - @subpage howtoserver
|
||||
* - @subpage howtoclientcomm
|
||||
* - @subpage howtoservercomm
|
||||
* - @subpage howtotimeouts
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page howtoinit Init and Thread-safety Information
|
||||
*
|
||||
* Before working with the library, it must be initialized using ::nc_client_init()
|
||||
* or ::nc_server_init(). Based on how the library was compiled, also _libssh_ and/or
|
||||
* _libssh_/_libcrypto_ are initialized (for multi-threaded use) too. To prevent
|
||||
* any reachable memory at the end of your application, there are complementary
|
||||
* destroy functions (::nc_server_destroy() and ::nc_client_destroy() available. If your
|
||||
* application is multi-threaded, call the destroy functions in the main thread,
|
||||
* after all the other threads have ended. In every other thread you should call
|
||||
* ::nc_thread_destroy() just before it exits.
|
||||
*
|
||||
* If _libnetconf2_ is used in accordance with this information, there should
|
||||
* not be memory leaks of any kind at program exit. For thread-safety details
|
||||
* of _libssh_, _libssl_, and _libcrypto_, please refer to the corresponding project
|
||||
* documentation. _libnetconf2_ thread-safety information is below.
|
||||
*
|
||||
* Client
|
||||
* ------
|
||||
*
|
||||
* Optionally, a client can specify two alternative ways to get schemas needed when connecting
|
||||
* with a server. The primary way is to read local files in searchpath (and its subdirectories)
|
||||
* specified via ::nc_client_set_schema_searchpath(). Alternatively, _libnetconf2_ can use callback
|
||||
* provided via ::nc_client_set_schema_callback(). If these ways do not succeed and the server
|
||||
* implements NETCONF \<get-schema\> operation, the schema is retrieved from the server and stored
|
||||
* localy into the searchpath (if specified) for a future use. If none of these methods succeed to
|
||||
* load particular schema, the data from this schema are ignored during the communication with the
|
||||
* server.
|
||||
*
|
||||
* Besides the mentioned setters, there are many other @ref howtoclientssh "SSH", @ref howtoclienttls "TLS"
|
||||
* and @ref howtoclientch "Call Home" getter/setter functions to manipulate with various settings. All these
|
||||
* settings are internally placed in a thread-specific context so they are independent and
|
||||
* initialized to the default values within each new thread. However, the context can be shared among
|
||||
* the threads using ::nc_client_get_thread_context() and ::nc_client_set_thread_context() functions. In such
|
||||
* a case, be careful and avoid concurrent execution of the mentioned setters/getters and functions
|
||||
* creating connection (no matter if it is a standard NETCONF connection or Call Home).
|
||||
*
|
||||
* In the client, it is thread-safe to work with distinguish NETCONF sessions since the client
|
||||
* settings are thread-specific as described above.
|
||||
*
|
||||
* Server
|
||||
* ------
|
||||
*
|
||||
* Server is __FULLY__ thread-safe meaning you can set all the (thread-shared in contrast to
|
||||
* client) options simultaneously while listening for or accepting new sessions or
|
||||
* polling the existing ones. It is even safe to poll one session in several
|
||||
* pollsession structures or one pollsession structure in several threads. Generally,
|
||||
* servers can use more threads without any problems as long as they keep their workflow sane
|
||||
* (behavior such as freeing sessions only after no thread uses them or similar).
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_client.h__.
|
||||
*
|
||||
* - ::nc_client_init()
|
||||
* - ::nc_client_destroy()
|
||||
*
|
||||
* - ::nc_client_set_schema_searchpath()
|
||||
* - ::nc_client_get_schema_searchpath()
|
||||
* - ::nc_client_set_schema_callback()
|
||||
* - ::nc_client_get_schema_callback()
|
||||
*
|
||||
* - ::nc_client_set_thread_context()
|
||||
* - ::nc_client_get_thread_context()
|
||||
*
|
||||
* Available in __nc_server.h__.
|
||||
*
|
||||
* - ::nc_server_init()
|
||||
* - ::nc_server_destroy()
|
||||
*
|
||||
* Available in both __nc_client.h__ and __nc_server.h__.
|
||||
*
|
||||
* - ::nc_thread_destroy()
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page howtoclient Client sessions
|
||||
*
|
||||
* To connect to a NETCONF server, a NETCONF session must be established,
|
||||
* which requires a working transport session. It is possible to create
|
||||
* NETCONF sessions with SSH (using _libssh_) or TLS (using _libssl/libcrypto_)
|
||||
* as the underlying transport protocol. It is also possible to establish
|
||||
* the transport protocol outside _libnetconf2_ and then provide these file
|
||||
* descriptors (FD) for full NETCONF session creation.
|
||||
*
|
||||
* There are a lot of options for both an SSH and a TLS client. All of them
|
||||
* have setters and getters so that there is no need to duplicate them in
|
||||
* a client.
|
||||
*
|
||||
* @anchor howtoclientssh
|
||||
* SSH
|
||||
* ===
|
||||
*
|
||||
* Connecting to a server using SSH does not strictly require to set any
|
||||
* options, there are sensible default values for all the basic ones.
|
||||
* Except all the SSH options, optionally some authetication callbacks can be set,
|
||||
* which are particulary useful in automated clients (passwords cannot be
|
||||
* asked a user) or simply if any additional information is retrieved some
|
||||
* other way than from standard terminal input.
|
||||
*
|
||||
* Having the default options or changing any unsuitable ones, there are 2 functions
|
||||
* to use for a new server connection. ::nc_connect_ssh() is the standard function
|
||||
* that creates sessions using the set options. If there are some options, which
|
||||
* cannot be changed with the provided API, there is ::nc_connect_libssh() available.
|
||||
* It requires a _libssh_ session, in which all the SSH options can be modified
|
||||
* and even the connection established. This allows for full customization and
|
||||
* should fit any specific situation.
|
||||
*
|
||||
* New NETCONF sessions can also be created on existing authenticated SSH sessions.
|
||||
* There is a new SSH channel needed, on which the NETCONF session is then created.
|
||||
* Use ::nc_connect_ssh_channel() for this purpose.
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_client.h__.
|
||||
*
|
||||
* - ::nc_client_ssh_set_auth_hostkey_check_clb()
|
||||
* - ::nc_client_ssh_get_auth_hostkey_check_clb()
|
||||
* - ::nc_client_ssh_set_auth_password_clb()
|
||||
* - ::nc_client_ssh_get_auth_password_clb()
|
||||
* - ::nc_client_ssh_set_auth_interactive_clb()
|
||||
* - ::nc_client_ssh_get_auth_interactive_clb()
|
||||
* - ::nc_client_ssh_set_auth_privkey_passphrase_clb()
|
||||
* - ::nc_client_ssh_get_auth_privkey_passphrase_clb()
|
||||
* - ::nc_client_ssh_add_keypair()
|
||||
* - ::nc_client_ssh_del_keypair()
|
||||
* - ::nc_client_ssh_get_keypair_count()
|
||||
* - ::nc_client_ssh_get_keypair()
|
||||
* - ::nc_client_ssh_set_auth_pref()
|
||||
* - ::nc_client_ssh_get_auth_pref()
|
||||
* - ::nc_client_ssh_set_username()
|
||||
* - ::nc_client_ssh_get_username()
|
||||
*
|
||||
* - ::nc_connect_ssh()
|
||||
* - ::nc_connect_libssh()
|
||||
* - ::nc_connect_ssh_channel()
|
||||
*
|
||||
* @anchor howtoclienttls
|
||||
* TLS
|
||||
* ===
|
||||
*
|
||||
* To connect to a server using TLS, there must be some client identification
|
||||
* options set. Client must specify its certificate with a private key using
|
||||
* ::nc_client_tls_set_cert_key_paths(). Also, the Certificate Authority of
|
||||
* a server certificate must be considered trusted. Paths to all the trusted
|
||||
* CA certificates can be set by ::nc_client_tls_set_trusted_ca_paths().
|
||||
*
|
||||
* Then there are again 2 functions for connecting, ::nc_connect_tls() being
|
||||
* the standard way of connecting. ::nc_connect_libssl() again enables
|
||||
* to customize the TLS session in every way _libssl_ allows.
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_client.h__.
|
||||
*
|
||||
* - ::nc_client_tls_set_cert_key_paths()
|
||||
* - ::nc_client_tls_get_cert_key_paths()
|
||||
* - ::nc_client_tls_set_trusted_ca_paths()
|
||||
* - ::nc_client_tls_get_trusted_ca_paths()
|
||||
* - ::nc_client_tls_set_crl_paths()
|
||||
* - ::nc_client_tls_get_crl_paths()
|
||||
*
|
||||
* - ::nc_connect_tls()
|
||||
* - ::nc_connect_libssl()
|
||||
*
|
||||
*
|
||||
* FD and UNIX socket
|
||||
* ==================
|
||||
*
|
||||
* If you authenticated the connection using some tunneling software, you
|
||||
* can pass its file descriptors to _libnetconf2_ using ::nc_connect_inout(),
|
||||
* which will continue to establish a full NETCONF session. To connect locally
|
||||
* on a UNIX socket avoiding all cryptography use ::nc_connect_unix().
|
||||
*
|
||||
* Funtions List
|
||||
* -------------
|
||||
*
|
||||
* Available in __nc_client.h__.
|
||||
*
|
||||
* - ::nc_connect_inout()
|
||||
* - ::nc_connect_unix()
|
||||
*
|
||||
*
|
||||
* @anchor howtoclientch
|
||||
* Call Home
|
||||
* =========
|
||||
*
|
||||
* Call Home needs the same options set as standard SSH or TLS and the functions
|
||||
* reflect it exactly. However, to accept a connection, the client must first
|
||||
* specify addresses and ports, which to listen on by ::nc_client_ssh_ch_add_bind_listen()
|
||||
* and ::nc_client_tls_ch_add_bind_listen(). Then connections can be
|
||||
* accepted using ::nc_accept_callhome().
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_client.h__.
|
||||
*
|
||||
* - ::nc_client_ssh_ch_set_auth_hostkey_check_clb()
|
||||
* - ::nc_client_ssh_ch_set_auth_password_clb()
|
||||
* - ::nc_client_ssh_ch_set_auth_interactive_clb()
|
||||
* - ::nc_client_ssh_ch_set_auth_privkey_passphrase_clb()
|
||||
* - ::nc_client_ssh_ch_add_bind_listen()
|
||||
* - ::nc_client_ssh_ch_del_bind()
|
||||
* - ::nc_client_ssh_ch_add_keypair()
|
||||
* - ::nc_client_ssh_ch_del_keypair()
|
||||
* - ::nc_client_ssh_ch_get_keypair_count()
|
||||
* - ::nc_client_ssh_ch_get_keypair()
|
||||
* - ::nc_client_ssh_ch_set_auth_pref()
|
||||
* - ::nc_client_ssh_ch_get_auth_pref()
|
||||
* - ::nc_client_ssh_ch_set_username()
|
||||
* - ::nc_client_ssh_ch_get_username()
|
||||
*
|
||||
* - ::nc_client_tls_ch_add_bind_listen()
|
||||
* - ::nc_client_tls_ch_del_bind()
|
||||
* - ::nc_client_tls_ch_set_cert_key_paths()
|
||||
* - ::nc_client_tls_ch_get_cert_key_paths()
|
||||
* - ::nc_client_tls_ch_set_trusted_ca_paths()
|
||||
* - ::nc_client_tls_ch_get_trusted_ca_paths()
|
||||
* - ::nc_client_tls_ch_set_crl_paths()
|
||||
* - ::nc_client_tls_ch_get_crl_paths()
|
||||
*
|
||||
* - ::nc_accept_callhome()
|
||||
*
|
||||
*
|
||||
* Cleanup
|
||||
* =======
|
||||
*
|
||||
* These options and the schema searchpath are stored in dynamically
|
||||
* allocated memory. They are freed as a part of [destroying the client](@ref howtoinit).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page howtoserver Server sessions
|
||||
*
|
||||
* Init
|
||||
* ====
|
||||
*
|
||||
* Server takes an argument for its [initialization function](@ref howtoinit).
|
||||
* In it, you set the server context, which determines what modules it
|
||||
* supports and what capabilities to advertise. Few capabilities that
|
||||
* cannot be learnt from the context are set with separate functions
|
||||
* ::nc_server_set_capab_withdefaults() and generally ::nc_server_set_capability().
|
||||
* Timeout for receiving the _hello_ message on a new session can be set
|
||||
* by ::nc_server_set_hello_timeout() and the timeout for disconnecting
|
||||
* an inactive session by ::nc_server_set_idle_timeout().
|
||||
*
|
||||
* Context does not only determine server modules, but its overall
|
||||
* functionality as well. For every RPC the server should support,
|
||||
* an nc_rpc_clb callback should be set on that node in the context using ::nc_set_rpc_callback().
|
||||
* Server then calls these as appropriate [during poll](@ref howtoservercomm).
|
||||
*
|
||||
* Just like in the [client](@ref howtoclient), you can let _libnetconf2_
|
||||
* establish SSH or TLS transport or do it yourself and only provide the file
|
||||
* descriptors of the connection.
|
||||
*
|
||||
* Server options can be only set, there are no getters.
|
||||
*
|
||||
* To be able to accept any connections, endpoints must first be added
|
||||
* with ::nc_server_add_endpt() and configured with ::nc_server_endpt_set_address()
|
||||
* and ::nc_server_endpt_set_port(). For unix sockets, ::nc_server_endpt_set_perms()
|
||||
* is available to set the unix socket file permissions, and ::nc_server_endpt_set_port()
|
||||
* is invalid.
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_server.h__.
|
||||
*
|
||||
* - ::nc_server_set_capab_withdefaults()
|
||||
* - ::nc_server_set_capability()
|
||||
* - ::nc_server_set_hello_timeout()
|
||||
* - ::nc_server_set_idle_timeout()
|
||||
*
|
||||
* - ::nc_server_add_endpt()
|
||||
* - ::nc_server_del_endpt()
|
||||
* - ::nc_server_endpt_set_address()
|
||||
* - ::nc_server_endpt_set_port()
|
||||
* - ::nc_server_endpt_set_perms()
|
||||
*
|
||||
*
|
||||
* SSH
|
||||
* ===
|
||||
*
|
||||
* To successfully accept an SSH session you must set at least the host key using
|
||||
* ::nc_server_ssh_endpt_add_hostkey(), which are ordered. This way you simply add
|
||||
* some hostkey identifier, but the key itself will be retrieved always when needed
|
||||
* by calling the callback set by ::nc_server_ssh_set_hostkey_clb().
|
||||
*
|
||||
* There are also some other optional settings. Note that authorized
|
||||
* public keys are set for the server as a whole, not endpoint-specifically.
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_server.h__.
|
||||
*
|
||||
* - ::nc_server_ssh_endpt_add_hostkey()
|
||||
* - ::nc_server_ssh_endpt_del_hostkey()
|
||||
* - ::nc_server_ssh_endpt_mov_hostkey()
|
||||
* - ::nc_server_ssh_endpt_mod_hostkey()
|
||||
* - ::nc_server_ssh_endpt_set_auth_methods()
|
||||
* - ::nc_server_ssh_endpt_set_auth_attempts()
|
||||
* - ::nc_server_ssh_endpt_set_auth_timeout()
|
||||
*
|
||||
* - ::nc_server_ssh_set_hostkey_clb()
|
||||
*
|
||||
* - ::nc_server_ssh_add_authkey()
|
||||
* - ::nc_server_ssh_add_authkey_path()
|
||||
* - ::nc_server_ssh_del_authkey()
|
||||
*
|
||||
*
|
||||
* TLS
|
||||
* ===
|
||||
*
|
||||
* TLS works with endpoints too, but its options differ
|
||||
* significantly from the SSH ones, especially in the _cert-to-name_
|
||||
* options that TLS uses to derive usernames from client certificates.
|
||||
* So, after starting listening on an endpoint you need to set the server
|
||||
* certificate (::nc_server_tls_endpt_set_server_cert()). Its actual content
|
||||
* together with the matching private key will be loaded using a callback
|
||||
* from ::nc_server_tls_set_server_cert_clb(). Additional certificates needed
|
||||
* for the client to verify the server's certificate chain can be loaded using
|
||||
* a callback from ::nc_server_tls_set_server_cert_chain_clb().
|
||||
*
|
||||
* To accept client certificates, they must first be considered trusted,
|
||||
* which you have three ways of achieving. You can add each of their Certificate Authority
|
||||
* certificates to the trusted ones or mark a specific client certificate
|
||||
* as trusted. Lastly, you can set paths with all the trusted CA certificates
|
||||
* with ::nc_server_tls_endpt_set_trusted_ca_paths(). Adding specific certificates
|
||||
* is also performed only as an arbitrary identificator and later retrieved from
|
||||
* callback set by ::nc_server_tls_set_trusted_cert_list_clb(). But, you can add
|
||||
* certficates as whole lists, not one-by-one.
|
||||
*
|
||||
* Then, from each trusted client certificate a username must be derived
|
||||
* for the NETCONF session. This is accomplished by finding a matching
|
||||
* _cert-to-name_ entry. They are added using ::nc_server_tls_endpt_add_ctn().
|
||||
*
|
||||
* If you need to remove trusted certificates, you can do so with ::nc_server_tls_endpt_del_trusted_cert_list().
|
||||
* To clear all Certificate Revocation Lists use ::nc_server_tls_endpt_clear_crls().
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_server.h__.
|
||||
*
|
||||
* - ::nc_server_tls_endpt_set_server_cert()
|
||||
* - ::nc_server_tls_endpt_add_trusted_cert_list()
|
||||
* - ::nc_server_tls_endpt_del_trusted_cert_list()
|
||||
* - ::nc_server_tls_endpt_set_trusted_ca_paths()
|
||||
* - ::nc_server_tls_endpt_set_crl_paths()
|
||||
* - ::nc_server_tls_endpt_clear_crls()
|
||||
* - ::nc_server_tls_endpt_add_ctn()
|
||||
* - ::nc_server_tls_endpt_del_ctn()
|
||||
* - ::nc_server_tls_endpt_get_ctn()
|
||||
*
|
||||
* - ::nc_server_tls_set_server_cert_clb()
|
||||
* - ::nc_server_tls_set_server_cert_chain_clb()
|
||||
* - ::nc_server_tls_set_trusted_cert_list_clb()
|
||||
*
|
||||
* FD
|
||||
* ==
|
||||
*
|
||||
* If you used a tunneling software, which does its own authentication,
|
||||
* you can accept a NETCONF session on its file descriptors with
|
||||
* ::nc_accept_inout().
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_server.h__.
|
||||
*
|
||||
* - ::nc_accept_inout()
|
||||
*
|
||||
*
|
||||
* Call Home
|
||||
* =========
|
||||
*
|
||||
* _Call Home_ works with endpoints just like standard sessions, but
|
||||
* the options are organized a bit differently and endpoints are added
|
||||
* for CH clients. However, one important difference is that
|
||||
* once all the mandatory options are set, _libnetconf2_ __will not__
|
||||
* immediately start connecting to a client. It will do so only after
|
||||
* calling ::nc_connect_ch_client_dispatch() in a separate thread.
|
||||
*
|
||||
* Lastly, monitoring of these sessions is up to the application.
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_server.h__.
|
||||
*
|
||||
* - ::nc_server_ch_add_client()
|
||||
* - ::nc_server_ch_del_client()
|
||||
* - ::nc_server_ch_is_client()
|
||||
* - ::nc_server_ch_client_add_endpt()
|
||||
* - ::nc_server_ch_client_del_endpt()
|
||||
* - ::nc_server_ch_client_is_endpt()
|
||||
* - ::nc_server_ch_client_endpt_set_address()
|
||||
* - ::nc_server_ch_client_endpt_set_port()
|
||||
* - ::nc_server_ch_client_endpt_enable_keepalives()
|
||||
* - ::nc_server_ch_client_endpt_set_keepalives()
|
||||
* - ::nc_server_ch_client_set_conn_type()
|
||||
* - ::nc_server_ch_client_periodic_set_period()
|
||||
* - ::nc_server_ch_client_periodic_set_anchor_time()
|
||||
* - ::nc_server_ch_client_periodic_set_idle_timeout()
|
||||
* - ::nc_server_ch_client_set_start_with()
|
||||
* - ::nc_server_ch_client_set_max_attempts()
|
||||
* - ::nc_connect_ch_client_dispatch()
|
||||
*
|
||||
* - ::nc_server_ssh_ch_client_endpt_add_hostkey()
|
||||
* - ::nc_server_ssh_ch_client_endpt_del_hostkey()
|
||||
* - ::nc_server_ssh_ch_client_endpt_mov_hostkey()
|
||||
* - ::nc_server_ssh_ch_client_endpt_set_auth_methods()
|
||||
* - ::nc_server_ssh_ch_client_endpt_get_auth_methods()
|
||||
* - ::nc_server_ssh_ch_client_endpt_set_auth_attempts()
|
||||
* - ::nc_server_ssh_ch_client_endpt_set_auth_timeout()
|
||||
*
|
||||
* - ::nc_server_tls_ch_client_endpt_set_server_cert()
|
||||
* - ::nc_server_tls_ch_client_endpt_add_trusted_cert_list()
|
||||
* - ::nc_server_tls_ch_client_endpt_del_trusted_cert_list()
|
||||
* - ::nc_server_tls_ch_client_endpt_set_trusted_ca_paths()
|
||||
* - ::nc_server_tls_ch_client_endpt_set_crl_paths()
|
||||
* - ::nc_server_tls_ch_client_endpt_clear_crls()
|
||||
* - ::nc_server_tls_ch_client_endpt_add_ctn()
|
||||
* - ::nc_server_tls_ch_client_endpt_del_ctn()
|
||||
* - ::nc_server_tls_ch_client_endpt_get_ctn()
|
||||
*
|
||||
*
|
||||
* Connecting And Cleanup
|
||||
* ======================
|
||||
*
|
||||
* When accepting connections with ::nc_accept(), all the endpoints are examined
|
||||
* and the first with a pending connection is used. To remove all CH clients,
|
||||
* endpoints, and free any used dynamic memory, [destroy](@ref howtoinit) the server.
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_server.h__.
|
||||
*
|
||||
* - ::nc_accept()
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page howtoclientcomm Client communication
|
||||
*
|
||||
* To send RPCs on a session, you simply create an RPC, send it using ::nc_send_rpc(),
|
||||
* and then wait for a reply using ::nc_recv_reply(). If you are subscribed, there are 2 ways
|
||||
* of receiving notifications. Either you wait for them the same way
|
||||
* as for standard replies with ::nc_recv_notif() or you create a dispatcher
|
||||
* with ::nc_recv_notif_dispatch() that asynchronously (in a separate thread)
|
||||
* reads notifications and passes them to your callback.
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_client.h__.
|
||||
*
|
||||
* - ::nc_rpc_act_generic()
|
||||
* - ::nc_rpc_act_generic_xml()
|
||||
* - ::nc_rpc_getconfig()
|
||||
* - ::nc_rpc_edit()
|
||||
* - ::nc_rpc_copy()
|
||||
* - ::nc_rpc_delete()
|
||||
* - ::nc_rpc_lock()
|
||||
* - ::nc_rpc_unlock()
|
||||
* - ::nc_rpc_get()
|
||||
* - ::nc_rpc_kill()
|
||||
* - ::nc_rpc_commit()
|
||||
* - ::nc_rpc_discard()
|
||||
* - ::nc_rpc_cancel()
|
||||
* - ::nc_rpc_validate()
|
||||
* - ::nc_rpc_getschema()
|
||||
* - ::nc_rpc_subscribe()
|
||||
* - ::nc_rpc_getdata()
|
||||
* - ::nc_rpc_editdata()
|
||||
* - ::nc_rpc_establishsub()
|
||||
* - ::nc_rpc_modifysub()
|
||||
* - ::nc_rpc_deletesub()
|
||||
* - ::nc_rpc_killsub()
|
||||
* - ::nc_rpc_establishpush_periodic()
|
||||
* - ::nc_rpc_establishpush_onchange()
|
||||
* - ::nc_rpc_modifypush_periodic()
|
||||
* - ::nc_rpc_modifypush_onchange()
|
||||
* - ::nc_rpc_resyncsub()
|
||||
*
|
||||
* - ::nc_send_rpc()
|
||||
* - ::nc_recv_reply()
|
||||
* - ::nc_recv_notif()
|
||||
* - ::nc_recv_notif_dispatch()
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page howtoservercomm Server communication
|
||||
*
|
||||
* Once at least one session is established, an nc_pollsession structure
|
||||
* should be created with ::nc_ps_new(), filled with the session using
|
||||
* ::nc_ps_add_session() and finally polled with ::nc_ps_poll(). Based on
|
||||
* the return value from the poll, further actions can be taken. More
|
||||
* sessions can be polled at the same time and any requests received on
|
||||
* the sessions are [handled internally](@ref howtoserver).
|
||||
*
|
||||
* If an SSH NETCONF session asks for a new channel, you can accept
|
||||
* this request with ::nc_ps_accept_ssh_channel() or ::nc_session_accept_ssh_channel()
|
||||
* depending on the structure you want to use as the argument.
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_server.h__.
|
||||
*
|
||||
* - ::nc_ps_new()
|
||||
* - ::nc_ps_add_session()
|
||||
* - ::nc_ps_del_session()
|
||||
* - ::nc_ps_session_count()
|
||||
* - ::nc_ps_free()
|
||||
*
|
||||
* - ::nc_ps_poll()
|
||||
* - ::nc_ps_clear()
|
||||
* - ::nc_ps_accept_ssh_channel()
|
||||
* - ::nc_session_accept_ssh_channel()
|
||||
*/
|
||||
|
||||
/**
|
||||
* @page howtotimeouts Timeouts
|
||||
*
|
||||
* There are several timeouts which are used throughout _libnetconf2_ to
|
||||
* assure that it will never indefinitely hang on any operation. Normally,
|
||||
* you should not need to worry about them much necause they are set by
|
||||
* default to reasonable values for common systems. However, if your
|
||||
* platform is not common (embedded, ...), adjusting these timeouts may
|
||||
* save a lot of debugging and time.
|
||||
*
|
||||
* Compile Options
|
||||
* ---------------
|
||||
*
|
||||
* You can adjust active and inactive read timeout using `cmake` variables.
|
||||
* For details look into `README.md`.
|
||||
*
|
||||
* API Functions
|
||||
* -------------
|
||||
*
|
||||
* Once a new connection is established including transport protocol negotiations,
|
||||
* _hello_ message is exchanged. You can set how long will the server wait for
|
||||
* receiving this message from a client before dropping it.
|
||||
*
|
||||
* Having a NETCONF session working, it may not communicate for a longer time.
|
||||
* To free up some resources, it is possible to adjust the maximum idle period
|
||||
* of a session before it is disconnected. In _Call Home_, for both a persistent
|
||||
* and periodic connection can this idle timeout be specified separately for each
|
||||
* client using corresponding functions.
|
||||
*
|
||||
* Lastly, SSH user authentication timeout can be also modified. It is the time
|
||||
* a client has to successfully authenticate after connecting before it is disconnected.
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_server.h__.
|
||||
*
|
||||
* - ::nc_server_set_hello_timeout()
|
||||
* - ::nc_server_get_hello_timeout()
|
||||
* - ::nc_server_set_idle_timeout()
|
||||
* - ::nc_server_get_idle_timeout()
|
||||
* - ::nc_server_ch_client_periodic_set_idle_timeout()
|
||||
* - ::nc_server_ssh_ch_client_endpt_set_auth_timeout()
|
||||
* - ::nc_server_ssh_ch_client_endpt_set_auth_timeout()
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup misc Miscellaneous
|
||||
* @brief Miscellaneous macros, types, structure and functions for a generic use by both server and client applications.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup client Client
|
||||
* @brief NETCONF client functionality.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup server Server
|
||||
* @brief NETCONF server functionality.
|
||||
*/
|
||||
|
||||
#endif /* NC_LIBNETCONF_H_ */
|
148
src/log.c
Normal file
148
src/log.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/**
|
||||
* \file log.c
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2 - log functions
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
#include <libssh/libssh.h>
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "libnetconf.h"
|
||||
#include "log.h"
|
||||
|
||||
/**
|
||||
* @brief libnetconf verbose level variable
|
||||
*/
|
||||
volatile uint8_t verbose_level = 0;
|
||||
|
||||
void (*depr_print_clb)(NC_VERB_LEVEL level, const char *msg);
|
||||
void (*print_clb)(const struct nc_session *session, NC_VERB_LEVEL level, const char *msg);
|
||||
|
||||
API void
|
||||
nc_verbosity(NC_VERB_LEVEL level)
|
||||
{
|
||||
verbose_level = level;
|
||||
ly_log_level((LY_LOG_LEVEL)level);
|
||||
}
|
||||
|
||||
struct {
|
||||
NC_VERB_LEVEL level;
|
||||
const char *label;
|
||||
} verb[] = {
|
||||
{NC_VERB_ERROR, "[ERR]"},
|
||||
{NC_VERB_WARNING, "[WRN]"},
|
||||
{NC_VERB_VERBOSE, "[INF]"},
|
||||
{NC_VERB_DEBUG, "[DBG]"},
|
||||
{NC_VERB_DEBUG_LOWLVL, "[DBL]"}
|
||||
};
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
|
||||
API void
|
||||
nc_libssh_thread_verbosity(int level)
|
||||
{
|
||||
ssh_set_log_level(level);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
prv_vprintf(const struct nc_session *session, NC_VERB_LEVEL level, const char *format, va_list args)
|
||||
{
|
||||
#define PRV_MSG_INIT_SIZE 256
|
||||
va_list args2;
|
||||
char *prv_msg;
|
||||
void *mem;
|
||||
int req_len;
|
||||
|
||||
prv_msg = malloc(PRV_MSG_INIT_SIZE);
|
||||
if (!prv_msg) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_copy(args2, args);
|
||||
|
||||
req_len = vsnprintf(prv_msg, PRV_MSG_INIT_SIZE - 1, format, args);
|
||||
if (req_len == -1) {
|
||||
goto cleanup;
|
||||
} else if (req_len >= PRV_MSG_INIT_SIZE - 1) {
|
||||
/* the length is not enough */
|
||||
++req_len;
|
||||
mem = realloc(prv_msg, req_len);
|
||||
if (!mem) {
|
||||
goto cleanup;
|
||||
}
|
||||
prv_msg = mem;
|
||||
|
||||
/* now print the full message */
|
||||
req_len = vsnprintf(prv_msg, req_len, format, args2);
|
||||
if (req_len == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (print_clb) {
|
||||
print_clb(session, level, prv_msg);
|
||||
} else if (depr_print_clb) {
|
||||
depr_print_clb(level, prv_msg);
|
||||
} else if (session && session->id) {
|
||||
fprintf(stderr, "Session %u %s: %s\n", session->id, verb[level].label, prv_msg);
|
||||
} else {
|
||||
fprintf(stderr, "%s: %s\n", verb[level].label, prv_msg);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(prv_msg);
|
||||
#undef PRV_MSG_INIT_SIZE
|
||||
}
|
||||
|
||||
void
|
||||
prv_printf(const struct nc_session *session, NC_VERB_LEVEL level, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
prv_vprintf(session, level, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void
|
||||
nc_ly_log_clb(LY_LOG_LEVEL lvl, const char *msg, const char *UNUSED(path))
|
||||
{
|
||||
if (print_clb) {
|
||||
print_clb(NULL, (NC_VERB_LEVEL)lvl, msg);
|
||||
} else if (depr_print_clb) {
|
||||
depr_print_clb((NC_VERB_LEVEL)lvl, msg);
|
||||
}
|
||||
}
|
||||
|
||||
API void
|
||||
nc_set_print_clb(void (*clb)(NC_VERB_LEVEL, const char *))
|
||||
{
|
||||
print_clb = NULL;
|
||||
depr_print_clb = clb;
|
||||
ly_set_log_clb(nc_ly_log_clb, 1);
|
||||
}
|
||||
|
||||
API void
|
||||
nc_set_print_clb_session(void (*clb)(const struct nc_session *, NC_VERB_LEVEL, const char *))
|
||||
{
|
||||
print_clb = clb;
|
||||
depr_print_clb = NULL;
|
||||
ly_set_log_clb(nc_ly_log_clb, 1);
|
||||
}
|
96
src/log.h
Normal file
96
src/log.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* @file log.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @brief libnetconf2 logger
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_LOG_H_
|
||||
#define NC_LOG_H_
|
||||
|
||||
struct nc_session;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup misc
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Verbosity levels.
|
||||
*/
|
||||
typedef enum NC_VERB_LEVEL {
|
||||
NC_VERB_ERROR = 0, /**< Print only error messages. */
|
||||
NC_VERB_WARNING = 1, /**< Print error and warning messages. */
|
||||
NC_VERB_VERBOSE = 2, /**< Besides errors and warnings, print some other verbose messages. */
|
||||
NC_VERB_DEBUG = 3, /**< Print almost all messages including some development debug messages. */
|
||||
NC_VERB_DEBUG_LOWLVL = 4 /**< Print all messages including low level debug messages. */
|
||||
} NC_VERB_LEVEL;
|
||||
|
||||
/**
|
||||
* @brief Set libnetconf's verbosity level.
|
||||
*
|
||||
* This level is set for libnetconf2 and alo libyang that is used internally. libyang
|
||||
* verbose level can be set explicitly, but must be done so after calling this function.
|
||||
* However, if debug verbosity is used, selecting displayed libyang debug message groups
|
||||
* must be done explicitly.
|
||||
*
|
||||
* @param[in] level Enabled verbosity level (includes all the levels with higher priority).
|
||||
*/
|
||||
void nc_verbosity(NC_VERB_LEVEL level);
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
|
||||
/**
|
||||
* @brief Set libssh verbosity level.
|
||||
*
|
||||
* libssh verbosity is set separately because it defines more verbose levels than libnetconf2.
|
||||
* Also, you need to set this for every thread unlike libnetconf verbosity.
|
||||
*
|
||||
* Values:
|
||||
* - 0 - no logging,
|
||||
* - 1 - rare conditions or warnings,
|
||||
* - 2 - API-accessible entrypoints,
|
||||
* - 3 - packet id and size,
|
||||
* - 4 - functions entering and leaving.
|
||||
*
|
||||
* @param[in] level libssh verbosity level.
|
||||
*/
|
||||
void nc_libssh_thread_verbosity(int level);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Deprecated, use ::nc_set_print_clb_session() instead.
|
||||
*
|
||||
* @param[in] clb Callback that is called for every message.
|
||||
*/
|
||||
void nc_set_print_clb(void (*clb)(NC_VERB_LEVEL, const char *));
|
||||
|
||||
/**
|
||||
* @brief Set libnetconf print callback.
|
||||
*
|
||||
* This callback is set for libnetconf2 and also libyang that is used internally. libyang
|
||||
* callback can be set explicitly, but must be done so after calling this function.
|
||||
*
|
||||
* @param[in] clb Callback that is called for every message.
|
||||
*/
|
||||
void nc_set_print_clb_session(void (*clb)(const struct nc_session *, NC_VERB_LEVEL, const char *));
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NC_LOG_H_ */
|
54
src/log_p.h
Normal file
54
src/log_p.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* @file log.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @brief libnetconf2 logger
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_LOG_PRIVATE_H_
|
||||
#define NC_LOG_PRIVATE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
/*
|
||||
* libnetconf's message printing
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Internal printing function
|
||||
*
|
||||
* @param[in] session Optional NETCONF session that generated the message
|
||||
* @param[in] level Verbose level
|
||||
* @param[in] format Formatting string
|
||||
*/
|
||||
void prv_printf(const struct nc_session *session, NC_VERB_LEVEL level, const char *format, ...);
|
||||
|
||||
/**
|
||||
* @brief Verbose level variable
|
||||
*/
|
||||
extern volatile uint8_t verbose_level;
|
||||
|
||||
/*
|
||||
* Verbose printing macros
|
||||
*/
|
||||
#define ERR(session, format, args ...) prv_printf(session,NC_VERB_ERROR,format,##args)
|
||||
#define WRN(session, format, args ...) if(verbose_level>=NC_VERB_WARNING){prv_printf(session,NC_VERB_WARNING,format,##args);}
|
||||
#define VRB(session, format, args ...) if(verbose_level>=NC_VERB_VERBOSE){prv_printf(session,NC_VERB_VERBOSE,format,##args);}
|
||||
#define DBG(session, format, args ...) if(verbose_level>=NC_VERB_DEBUG){prv_printf(session,NC_VERB_DEBUG,format,##args);}
|
||||
#define DBL(session, format, args ...) if(verbose_level>=NC_VERB_DEBUG_LOWLVL){prv_printf(session,NC_VERB_DEBUG_LOWLVL,format,##args);}
|
||||
|
||||
#define ERRMEM ERR(NULL, "%s: memory reallocation failed (%s:%d).", __func__, __FILE__, __LINE__)
|
||||
#define ERRARG(arg) ERR(NULL, "%s: invalid argument (%s).", __func__, arg)
|
||||
#define ERRINIT ERR(NULL, "%s: libnetconf2 not initialized.", __func__)
|
||||
#define ERRINT ERR(NULL, "%s: internal error (%s:%d).", __func__, __FILE__, __LINE__)
|
||||
|
||||
#endif /* NC_LOG_PRIVATE_H_ */
|
1234
src/messages_client.c
Normal file
1234
src/messages_client.c
Normal file
File diff suppressed because it is too large
Load diff
555
src/messages_client.h
Normal file
555
src/messages_client.h
Normal file
|
@ -0,0 +1,555 @@
|
|||
/**
|
||||
* @file messages_client.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2's public functions and structures of NETCONF client messages.
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_MESSAGES_CLIENT_H_
|
||||
#define NC_MESSAGES_CLIENT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "netconf.h"
|
||||
|
||||
/**
|
||||
* @defgroup client_msg Client Messages
|
||||
* @ingroup client
|
||||
*
|
||||
* @brief Functions to create NETCONF RPCs (or actions) and process replies received from the server.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Enumeration of RPC types
|
||||
*
|
||||
* Note that NC_RPC_CLOSE is not defined since sending \<close-session\> is done implicitly by nc_session_free()
|
||||
*/
|
||||
typedef enum {
|
||||
NC_RPC_UNKNOWN = 0, /**< invalid RPC. */
|
||||
NC_RPC_ACT_GENERIC, /**< user-defined generic RPC/action. */
|
||||
|
||||
/* ietf-netconf */
|
||||
NC_RPC_GETCONFIG, /**< \<get-config\> RPC. */
|
||||
NC_RPC_EDIT, /**< \<edit-config\> RPC. */
|
||||
NC_RPC_COPY, /**< \<copy-config\> RPC. */
|
||||
NC_RPC_DELETE, /**< \<delete-config\> RPC. */
|
||||
NC_RPC_LOCK, /**< \<lock\> RPC. */
|
||||
NC_RPC_UNLOCK, /**< \<unlock\> RPC. */
|
||||
NC_RPC_GET, /**< \<get\> RPC. */
|
||||
NC_RPC_KILL, /**< \<kill-session\> RPC. */
|
||||
NC_RPC_COMMIT, /**< \<commit\> RPC. */
|
||||
NC_RPC_DISCARD, /**< \<discard-changes\> RPC. */
|
||||
NC_RPC_CANCEL, /**< \<cancel-commit\> RPC. */
|
||||
NC_RPC_VALIDATE, /**< \<validate\> RPC. */
|
||||
|
||||
/* ietf-netconf-monitoring */
|
||||
NC_RPC_GETSCHEMA, /**< \<get-schema\> RPC. */
|
||||
|
||||
/* notifications */
|
||||
NC_RPC_SUBSCRIBE, /**< \<create-subscription\> RPC. */
|
||||
|
||||
/* ietf-netconf-nmda */
|
||||
NC_RPC_GETDATA, /**< \<get-data\> RPC. */
|
||||
NC_RPC_EDITDATA, /**< \<edit-data\> RPC. */
|
||||
|
||||
/* ietf-subscribed-notifications */
|
||||
NC_RPC_ESTABLISHSUB, /**< \<establish-subscription\> RPC. */
|
||||
NC_RPC_MODIFYSUB, /**< \<modify-subscription\> RPC. */
|
||||
NC_RPC_DELETESUB, /**< \<delete-subscription\> RPC. */
|
||||
NC_RPC_KILLSUB, /**< \<kill-subscription\> RPC. */
|
||||
|
||||
/* ietf-yang-push */
|
||||
NC_RPC_ESTABLISHPUSH, /**< \<establish-subscription\> RPC with augments. */
|
||||
NC_RPC_MODIFYPUSH, /**< \<modify-subscription\> RPC with augments. */
|
||||
NC_RPC_RESYNCSUB /**< \<resync-subscription\> RPC. */
|
||||
} NC_RPC_TYPE;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of \<edit-config\> default operation
|
||||
*/
|
||||
typedef enum {
|
||||
NC_RPC_EDIT_DFLTOP_UNKNOWN = 0, /**< unknown default operation */
|
||||
NC_RPC_EDIT_DFLTOP_MERGE, /**< default operation merge */
|
||||
NC_RPC_EDIT_DFLTOP_REPLACE, /**< default operation replace */
|
||||
NC_RPC_EDIT_DFLTOP_NONE /**< default operation none */
|
||||
} NC_RPC_EDIT_DFLTOP;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of \<edit-config\> test option
|
||||
*/
|
||||
typedef enum {
|
||||
NC_RPC_EDIT_TESTOPT_UNKNOWN = 0, /**< unknown test option */
|
||||
NC_RPC_EDIT_TESTOPT_TESTSET, /**< test-then-set option */
|
||||
NC_RPC_EDIT_TESTOPT_SET, /**< set option */
|
||||
NC_RPC_EDIT_TESTOPT_TEST /**< test-only option */
|
||||
} NC_RPC_EDIT_TESTOPT;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of \<edit-config\> error option
|
||||
*/
|
||||
typedef enum {
|
||||
NC_RPC_EDIT_ERROPT_UNKNOWN = 0, /**< unknown error option */
|
||||
NC_RPC_EDIT_ERROPT_STOP, /**< stop-on-error option */
|
||||
NC_RPC_EDIT_ERROPT_CONTINUE, /**< continue-on-error option */
|
||||
NC_RPC_EDIT_ERROPT_ROLLBACK /**< rollback-on-error option */
|
||||
} NC_RPC_EDIT_ERROPT;
|
||||
|
||||
/**
|
||||
* @brief NETCONF error structure representation
|
||||
*/
|
||||
struct nc_err {
|
||||
/** @brief \<error-type\>, error layer where the error occurred. */
|
||||
const char *type;
|
||||
/** @brief \<error-tag\>. */
|
||||
const char *tag;
|
||||
/** @brief \<error-severity\>. */
|
||||
const char *severity;
|
||||
/** @brief \<error-app-tag\>, the data-model-specific or implementation-specific error condition, if one exists. */
|
||||
const char *apptag;
|
||||
/** @brief \<error-path\>, XPATH expression identifying the element with the error. */
|
||||
const char *path;
|
||||
/** @brief \<error-message\>, Human-readable description of the error. */
|
||||
const char *message;
|
||||
/** @brief xml:lang attribute of the error-message. */
|
||||
const char *message_lang;
|
||||
|
||||
/* <error-info> */
|
||||
|
||||
/** @brief \<session-id\>, session ID of the session holding the requested lock. Part of \<error-info\>. */
|
||||
const char *sid;
|
||||
/** @brief \<bad-attr\>, array of the names of the data-model-specific XML attributes that caused the error. Part of \<error-info\>. */
|
||||
const char **attr;
|
||||
/** @brief \<bad-element\>, array of the names of the data-model-specific XML element that caused the error. Part of \<error-info\>. */
|
||||
const char **elem;
|
||||
/** @brief \<bad-namespace\>, array of the unexpected XML namespaces that caused the error. Part of \<error-info\>. */
|
||||
const char **ns;
|
||||
/** @brief List of the remaining non-standard opaque nodes. */
|
||||
struct lyd_node *other;
|
||||
|
||||
/** @brief Number of items in the attr array */
|
||||
uint16_t attr_count;
|
||||
/** @brief Number of items in the elem array */
|
||||
uint16_t elem_count;
|
||||
/** @brief Number of items in the ns array */
|
||||
uint16_t ns_count;
|
||||
/** @brief Number of items in the other array */
|
||||
uint16_t other_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct nc_rpc
|
||||
* @brief NETCONF client RPC object
|
||||
*
|
||||
* Note that any stored parameters are not checked for validity because it is performed later,
|
||||
* while sending the RPC via a specific NETCONF session (::nc_send_rpc()) since the NETCONF
|
||||
* capabilities of the session are needed for such a check. An RPC object can be sent via any
|
||||
* NETCONF session which supports all the needed NETCONF capabilities for the RPC.
|
||||
*/
|
||||
struct nc_rpc;
|
||||
|
||||
/**
|
||||
* @brief Get the type of the RPC
|
||||
*
|
||||
* @param[in] rpc RPC to check the type of.
|
||||
* @return Type of @p rpc.
|
||||
*/
|
||||
NC_RPC_TYPE nc_rpc_get_type(const struct nc_rpc *rpc);
|
||||
|
||||
/**
|
||||
* @brief Create a generic NETCONF RPC or action
|
||||
*
|
||||
* Note that created object can be sent via any NETCONF session that shares the context
|
||||
* of the @p data.
|
||||
*
|
||||
* @note In case of action, the \<action\> element is added automatically and should not be in @p data.
|
||||
*
|
||||
* @param[in] data NETCONF RPC data as a data tree.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_act_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create a generic NETCONF RPC or action from an XML string
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @note In case of action, the \<action\> element is added automatically and should not be in @p xml_str.
|
||||
*
|
||||
* @param[in] xml_str NETCONF RPC data as an XML string.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_act_generic_xml(const char *xml_str, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<get-config\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] source Source datastore being queried.
|
||||
* @param[in] filter Optional filter data, an XML subtree or XPath expression (with JSON prefixes).
|
||||
* @param[in] wd_mode Optional with-defaults capability mode.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_getconfig(NC_DATASTORE source, const char *filter, NC_WD_MODE wd_mode,
|
||||
NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<edit-config\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] target Target datastore being edited.
|
||||
* @param[in] default_op Optional default operation.
|
||||
* @param[in] test_opt Optional test option.
|
||||
* @param[in] error_opt Optional error option.
|
||||
* @param[in] edit_content Config or URL where the config to perform is to be found.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_edit(NC_DATASTORE target, NC_RPC_EDIT_DFLTOP default_op, NC_RPC_EDIT_TESTOPT test_opt,
|
||||
NC_RPC_EDIT_ERROPT error_opt, const char *edit_content, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<copy-config\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] target Target datastore.
|
||||
* @param[in] url_trg Used instead @p target if the target is an URL.
|
||||
* @param[in] source Source datastore.
|
||||
* @param[in] url_or_config_src Used instead @p source if the source is an URL or a config.
|
||||
* @param[in] wd_mode Optional with-defaults capability mode.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_copy(NC_DATASTORE target, const char *url_trg, NC_DATASTORE source,
|
||||
const char *url_or_config_src, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<delete-config\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] target Target datastore to delete.
|
||||
* @param[in] url Used instead @p target if the target is an URL.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_delete(NC_DATASTORE target, const char *url, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<lock\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] target Target datastore of the operation.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_lock(NC_DATASTORE target);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<unlock\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] target Target datastore of the operation.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_unlock(NC_DATASTORE target);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<get\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] filter Optional filter data, an XML subtree or XPath expression (with JSON prefixes).
|
||||
* @param[in] wd_mode Optional with-defaults capability mode.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_get(const char *filter, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<kill-session\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] session_id Session ID of the session to kill.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_kill(uint32_t session_id);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<commit\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] confirmed Whether the commit is to be confirmed.
|
||||
* @param[in] confirm_timeout Optional confirm timeout.
|
||||
* @param[in] persist Optional identification string of a new persistent confirmed commit.
|
||||
* @param[in] persist_id Optional identification string of a persistent confirmed commit to be commited.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_commit(int confirmed, uint32_t confirm_timeout, const char *persist, const char *persist_id,
|
||||
NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<discard-changes\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_discard(void);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<cancel-commit\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] persist_id Optional identification string of a persistent confirmed commit.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_cancel(const char *persist_id, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<validate\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] source Source datastore being validated.
|
||||
* @param[in] url_or_config Used instead @p source if the source is an URL or a config.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_validate(NC_DATASTORE source, const char *url_or_config, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<get-schema\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] identifier Requested model identifier.
|
||||
* @param[in] version Optional model version, either YANG version (1.0/1.1) or revision date.
|
||||
* @param[in] format Optional format of the model (default is YANG).
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_getschema(const char *identifier, const char *version, const char *format, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<create-subscription\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] stream_name Optional name of a NETCONF stream to subscribe to.
|
||||
* @param[in] filter Optional filter data, an XML subtree or XPath expression (with JSON prefixes).
|
||||
* @param[in] start_time Optional YANG datetime identifying the start of the subscription.
|
||||
* @param[in] stop_time Optional YANG datetime identifying the end of the subscription.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_subscribe(const char *stream_name, const char *filter, const char *start_time,
|
||||
const char *stop_time, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<get-data\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] datastore Source datastore, foreign identity so a module name prefix is required.
|
||||
* @param[in] filter Optional filter data, an XML subtree or XPath expression (with JSON prefixes).
|
||||
* @param[in] config_filter Optional config filter, "true" for config-only data, "false" for state-only data.
|
||||
* @param[in] origin_filter Optional origin filter array, selects only nodes of this or derived origin.
|
||||
* @param[in] origin_filter_count Count of filters is @p origin_filter.
|
||||
* @param[in] neg_origin_filter Whether origin filters are negated or not.
|
||||
* @param[in] max_depth Maximum depth of returned subtrees, 0 for unlimited.
|
||||
* @param[in] with_origin Whether return data origin.
|
||||
* @param[in] wd_mode Optional with-defaults capability mode.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_getdata(const char *datastore, const char *filter, const char *config_filter, char **origin_filter,
|
||||
int origin_filter_count, int neg_origin_filter, uint16_t max_depth, int with_origin, NC_WD_MODE wd_mode,
|
||||
NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<get-data\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] datastore Source datastore, foreign identity so a module name prefix is required.
|
||||
* @param[in] default_op Optional default operation.
|
||||
* @param[in] edit_content Config or URL where the config to perform is to be found.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_editdata(const char *datastore, NC_RPC_EDIT_DFLTOP default_op, const char *edit_content,
|
||||
NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<establish-subscription\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] filter Optional filter data, an XML subtree, XPath expression (with JSON prefixes),
|
||||
* or filter reference, selected based on the first character.
|
||||
* @param[in] stream_name Name of a NETCONF stream to subscribe to.
|
||||
* @param[in] start_time Optional YANG datetime identifying the start of the subscription.
|
||||
* @param[in] stop_time Optional YANG datetime identifying the end of the subscription.
|
||||
* @param[in] encoding Optional specific encoding to use.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_establishsub(const char *filter, const char *stream_name, const char *start_time,
|
||||
const char *stop_time, const char *encoding, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<modify-subscription\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] id Subscription ID to modify.
|
||||
* @param[in] filter Optional new filter data, an XML subtree, XPath expression (with JSON prefixes),
|
||||
* or filter reference, selected based on the first character.
|
||||
* @param[in] stop_time Optional new YANG datetime identifying the end of the subscription.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_modifysub(uint32_t id, const char *filter, const char *stop_time, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<delete-subscription\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] id Subscription ID to delete.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_deletesub(uint32_t id);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<kill-subscription\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] id Subscription ID to kill.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_killsub(uint32_t id);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<establish-subscription\> with augments from ietf-yang-push for a periodic subscription
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] datastore Source datastore, foreign identity so a module name prefix is required.
|
||||
* @param[in] filter Optional filter data, an XML subtree, XPath expression (with JSON prefixes),
|
||||
* or filter reference, selected based on the first character.
|
||||
* @param[in] stop_time Optional YANG datetime identifying the end of the subscription.
|
||||
* @param[in] encoding Optional specific encoding to use.
|
||||
* @param[in] period Subscription period in centiseconds (0.01s).
|
||||
* @param[in] anchor_time Optional anchor datetime for the period.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_establishpush_periodic(const char *datastore, const char *filter, const char *stop_time,
|
||||
const char *encoding, uint32_t period, const char *anchor_time, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<establish-subscription\> with augments from ietf-yang-push for an on-change subscription
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] datastore Source datastore, foreign identity so a module name prefix is required.
|
||||
* @param[in] filter Optional filter data, an XML subtree, XPath expression (with JSON prefixes),
|
||||
* or filter reference, selected based on the first character.
|
||||
* @param[in] stop_time Optional YANG datetime identifying the end of the subscription.
|
||||
* @param[in] encoding Optional specific encoding to use.
|
||||
* @param[in] dampening_period Optional dampening period of the notifications.
|
||||
* @param[in] sync_on_start Whether to send a full push-update notification on subscription start.
|
||||
* @param[in] excluded_change Optional NULL-terminated array of excluded changes.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_establishpush_onchange(const char *datastore, const char *filter, const char *stop_time,
|
||||
const char *encoding, uint32_t dampening_period, int sync_on_start, const char **excluded_change,
|
||||
NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<modify-subscription\> with augments from ietf-yang-push for a periodic subscription
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] id Subscription ID to modify.
|
||||
* @param[in] datastore Source datastore, foreign identity so a module name prefix is required.
|
||||
* @param[in] filter Optional filter data, an XML subtree, XPath expression (with JSON prefixes),
|
||||
* or filter reference, selected based on the first character.
|
||||
* @param[in] stop_time Optional YANG datetime identifying the end of the subscription.
|
||||
* @param[in] period Subscription period in centiseconds (0.01s).
|
||||
* @param[in] anchor_time Optional anchor datetime for the period.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_modifypush_periodic(uint32_t id, const char *datastore, const char *filter, const char *stop_time,
|
||||
uint32_t period, const char *anchor_time, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<modify-subscription\> with augments from ietf-yang-push for an on-change subscription
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] id Subscription ID to modify.
|
||||
* @param[in] datastore Source datastore, foreign identity so a module name prefix is required.
|
||||
* @param[in] filter Optional filter data, an XML subtree, XPath expression (with JSON prefixes),
|
||||
* or filter reference, selected based on the first character.
|
||||
* @param[in] stop_time Optional YANG datetime identifying the end of the subscription.
|
||||
* @param[in] dampening_period Optional dampening period of the notifications.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_modifypush_onchange(uint32_t id, const char *datastore, const char *filter, const char *stop_time,
|
||||
uint32_t dampening_period, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create NETCONF RPC \<resync-subscription\>
|
||||
*
|
||||
* For details, see ::nc_rpc.
|
||||
*
|
||||
* @param[in] id Subscription ID to resync.
|
||||
* @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
|
||||
*/
|
||||
struct nc_rpc *nc_rpc_resyncsub(uint32_t id);
|
||||
|
||||
/**
|
||||
* @brief Free the NETCONF RPC object.
|
||||
*
|
||||
* @param[in] rpc Object to free.
|
||||
*/
|
||||
void nc_rpc_free(struct nc_rpc *rpc);
|
||||
|
||||
/** @} Client Messages */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NC_MESSAGES_CLIENT_H_ */
|
263
src/messages_p.h
Normal file
263
src/messages_p.h
Normal file
|
@ -0,0 +1,263 @@
|
|||
/**
|
||||
* @file messages_p.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @brief libnetconf2's private functions and structures of NETCONF messages.
|
||||
*
|
||||
* Copyright (c) 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_MESSAGES_P_H_
|
||||
#define NC_MESSAGES_P_H_
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "messages_client.h"
|
||||
#include "messages_server.h"
|
||||
|
||||
extern const char *rpcedit_dfltop2str[];
|
||||
extern const char *rpcedit_testopt2str[];
|
||||
extern const char *rpcedit_erropt2str[];
|
||||
|
||||
struct nc_server_reply {
|
||||
NC_RPL type;
|
||||
};
|
||||
|
||||
struct nc_server_reply_data {
|
||||
NC_RPL type;
|
||||
struct lyd_node *data;
|
||||
int free;
|
||||
NC_WD_MODE wd;
|
||||
};
|
||||
|
||||
struct nc_server_reply_error {
|
||||
NC_RPL type;
|
||||
struct lyd_node *err;
|
||||
};
|
||||
|
||||
struct nc_server_rpc {
|
||||
struct lyd_node *envp; /**< NETCONF-specific RPC envelopes */
|
||||
struct lyd_node *rpc; /**< RPC data tree */
|
||||
};
|
||||
|
||||
struct nc_server_notif {
|
||||
char *eventtime; /**< eventTime of the notification */
|
||||
struct lyd_node *ntf; /**< notification data tree of the message */
|
||||
int free;
|
||||
};
|
||||
|
||||
struct nc_client_reply_error {
|
||||
NC_RPL type;
|
||||
struct nc_err *err;
|
||||
uint32_t count;
|
||||
struct ly_ctx *ctx;
|
||||
};
|
||||
|
||||
struct nc_rpc {
|
||||
NC_RPC_TYPE type;
|
||||
};
|
||||
|
||||
struct nc_rpc_act_generic {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_ACT_GENERIC */
|
||||
int has_data; /**< 1 for content.data, 0 for content.xml_str */
|
||||
union {
|
||||
struct lyd_node *data; /**< parsed RPC data */
|
||||
char *xml_str; /**< raw XML string */
|
||||
} content;
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_getconfig {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_GETCONFIG */
|
||||
NC_DATASTORE source; /**< NETCONF datastore being queried */
|
||||
char *filter; /**< either XML subtree (starts with '<') or an XPath (starts with '/' or an alpha) */
|
||||
NC_WD_MODE wd_mode;
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_edit {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_EDIT */
|
||||
NC_DATASTORE target;
|
||||
NC_RPC_EDIT_DFLTOP default_op;
|
||||
NC_RPC_EDIT_TESTOPT test_opt;
|
||||
NC_RPC_EDIT_ERROPT error_opt;
|
||||
char *edit_cont; /**< either URL (starts with aplha) or config (starts with '<') */
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_copy {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_COPY */
|
||||
NC_DATASTORE target;
|
||||
char *url_trg;
|
||||
NC_DATASTORE source;
|
||||
char *url_config_src; /**< either URL (starts with aplha) or config (starts with '<') */
|
||||
NC_WD_MODE wd_mode;
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_delete {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_DELETE */
|
||||
NC_DATASTORE target;
|
||||
char *url;
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_lock {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_LOCK or NC_RPC_UNLOCK */
|
||||
NC_DATASTORE target;
|
||||
};
|
||||
|
||||
struct nc_rpc_get {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_GET */
|
||||
char *filter; /**< either XML subtree (starts with '<') or an XPath (starts with '/' or an alpha) */
|
||||
NC_WD_MODE wd_mode;
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_kill {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_KILL */
|
||||
uint32_t sid;
|
||||
};
|
||||
|
||||
struct nc_rpc_commit {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_COMMIT */
|
||||
int confirmed;
|
||||
uint32_t confirm_timeout;
|
||||
char *persist;
|
||||
char *persist_id;
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_cancel {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_CANCEL */
|
||||
char *persist_id;
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_validate {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_VALIDATE */
|
||||
NC_DATASTORE source;
|
||||
char *url_config_src; /**< either URL (starts with alpha) or config (starts with '<') */
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_getschema {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_GETSCHEMA */
|
||||
char *identifier; /**< requested model identifier */
|
||||
char *version; /**< either YANG version (1.0/1.1) or revision date */
|
||||
char *format; /**< model format */
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_subscribe {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_SUBSCRIBE */
|
||||
char *stream; /**< stream name */
|
||||
char *filter; /**< either XML subtree (starts with '<') or an XPath (starts with '/' or an alpha) */
|
||||
char *start;
|
||||
char *stop;
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_getdata {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_GETDATA */
|
||||
char *datastore; /**< target datastore identity */
|
||||
char *filter; /**< either XML subtree (starts with '<') or an XPath (starts with '/' or an alpha) */
|
||||
char *config_filter; /**< config filter ("true"/"false") */
|
||||
char **origin_filter; /**< origin filters */
|
||||
int origin_filter_count; /**< origin filter count */
|
||||
int negated_origin_filter; /**< whether origin filter is negated or not */
|
||||
int max_depth; /**< max depth of returned subtrees, 0 for unlimited */
|
||||
int with_origin; /**< whether to return origin of data */
|
||||
NC_WD_MODE wd_mode;
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_editdata {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_EDITDATA */
|
||||
char *datastore; /**< target datastore identity */
|
||||
NC_RPC_EDIT_DFLTOP default_op;
|
||||
char *edit_cont; /**< either URL (starts with aplha) or config (starts with '<') */
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_establishsub {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_ESTABLISHSUB */
|
||||
char *filter; /**< XML subtree (starts with '<'), an XPath (starts with '/'), or reference (start with alpha) */
|
||||
char *stream; /**< stream name */
|
||||
char *start;
|
||||
char *stop;
|
||||
char *encoding;
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_modifysub {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_MODIFYSUB */
|
||||
uint32_t id;
|
||||
char *filter; /**< XML subtree (starts with '<'), an XPath (starts with '/'), or reference (start with alpha) */
|
||||
char *stop;
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_deletesub {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_DELETESUB */
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
struct nc_rpc_killsub {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_KILLSUB */
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
struct nc_rpc_establishpush {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_ESTABLISHPUSH */
|
||||
char *datastore;
|
||||
char *filter; /**< XML subtree (starts with '<'), an XPath (starts with '/'), or reference (start with alpha) */
|
||||
char *stop;
|
||||
char *encoding;
|
||||
int periodic;
|
||||
union {
|
||||
struct {
|
||||
uint32_t period;
|
||||
char *anchor_time;
|
||||
};
|
||||
struct {
|
||||
uint32_t dampening_period;
|
||||
int sync_on_start;
|
||||
char **excluded_change;
|
||||
};
|
||||
};
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_modifypush {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_MODIFYPUSH */
|
||||
uint32_t id;
|
||||
char *datastore;
|
||||
char *filter; /**< XML subtree (starts with '<'), an XPath (starts with '/'), or reference (start with alpha) */
|
||||
char *stop;
|
||||
int periodic;
|
||||
union {
|
||||
struct {
|
||||
uint32_t period;
|
||||
char *anchor_time;
|
||||
};
|
||||
uint32_t dampening_period;
|
||||
};
|
||||
char free;
|
||||
};
|
||||
|
||||
struct nc_rpc_resyncsub {
|
||||
NC_RPC_TYPE type; /**< NC_RPC_RESYNCSUB */
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
void nc_server_rpc_free(struct nc_server_rpc *rpc);
|
||||
|
||||
void nc_client_err_clean(struct nc_err *err, struct ly_ctx *ctx);
|
||||
|
||||
#endif /* NC_MESSAGES_P_H_ */
|
901
src/messages_server.c
Normal file
901
src/messages_server.c
Normal file
|
@ -0,0 +1,901 @@
|
|||
/**
|
||||
* \file messages_server.c
|
||||
* \author Michal Vasko <mvasko@cesnet.cz>
|
||||
* \brief libnetconf2 - server NETCONF messages functions
|
||||
*
|
||||
* Copyright (c) 2015 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "libnetconf.h"
|
||||
#include "session_server.h"
|
||||
|
||||
extern struct nc_server_opts server_opts;
|
||||
|
||||
API struct nc_server_reply *
|
||||
nc_server_reply_ok(void)
|
||||
{
|
||||
struct nc_server_reply *ret;
|
||||
|
||||
ret = malloc(sizeof *ret);
|
||||
if (!ret) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->type = NC_RPL_OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
API struct nc_server_reply *
|
||||
nc_server_reply_data(struct lyd_node *data, NC_WD_MODE wd, NC_PARAMTYPE paramtype)
|
||||
{
|
||||
struct nc_server_reply_data *ret;
|
||||
|
||||
if (!data) {
|
||||
ERRARG("data");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = malloc(sizeof *ret);
|
||||
if (!ret) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->type = NC_RPL_DATA;
|
||||
ret->wd = wd;
|
||||
if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
|
||||
if (lyd_dup_single(data, NULL, LYD_DUP_RECURSIVE, &ret->data)) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
ret->data = data;
|
||||
}
|
||||
if (paramtype != NC_PARAMTYPE_CONST) {
|
||||
ret->free = 1;
|
||||
} else {
|
||||
ret->free = 0;
|
||||
}
|
||||
return (struct nc_server_reply *)ret;
|
||||
}
|
||||
|
||||
API struct nc_server_reply *
|
||||
nc_server_reply_err(struct lyd_node *err)
|
||||
{
|
||||
struct nc_server_reply_error *ret;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = malloc(sizeof *ret);
|
||||
if (!ret) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->type = NC_RPL_ERROR;
|
||||
ret->err = err;
|
||||
return (struct nc_server_reply *)ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_reply_add_err(struct nc_server_reply *reply, struct lyd_node *err)
|
||||
{
|
||||
struct nc_server_reply_error *err_rpl;
|
||||
|
||||
if (!reply || (reply->type != NC_RPL_ERROR)) {
|
||||
ERRARG("reply");
|
||||
return -1;
|
||||
} else if (!err) {
|
||||
ERRARG("err");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err_rpl = (struct nc_server_reply_error *)reply;
|
||||
lyd_insert_sibling(err_rpl->err, err, &err_rpl->err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
API const struct lyd_node *
|
||||
nc_server_reply_get_last_err(const struct nc_server_reply *reply)
|
||||
{
|
||||
struct nc_server_reply_error *err_rpl;
|
||||
|
||||
if (!reply || (reply->type != NC_RPL_ERROR)) {
|
||||
ERRARG("reply");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err_rpl = (struct nc_server_reply_error *)reply;
|
||||
if (!err_rpl->err) {
|
||||
return NULL;
|
||||
}
|
||||
return err_rpl->err->prev;
|
||||
}
|
||||
|
||||
static const char *
|
||||
nc_err_tag2str(NC_ERR tag)
|
||||
{
|
||||
switch (tag) {
|
||||
case NC_ERR_IN_USE:
|
||||
return "in-use";
|
||||
case NC_ERR_INVALID_VALUE:
|
||||
return "invalid-value";
|
||||
case NC_ERR_ACCESS_DENIED:
|
||||
return "access-denied";
|
||||
case NC_ERR_ROLLBACK_FAILED:
|
||||
return "rollback-failed";
|
||||
case NC_ERR_OP_NOT_SUPPORTED:
|
||||
return "operation-not-supported";
|
||||
case NC_ERR_TOO_BIG:
|
||||
return "too-big";
|
||||
case NC_ERR_RES_DENIED:
|
||||
return "resource-denied";
|
||||
case NC_ERR_MISSING_ATTR:
|
||||
return "missing-attribute";
|
||||
case NC_ERR_BAD_ATTR:
|
||||
return "bad-attribute";
|
||||
case NC_ERR_UNKNOWN_ATTR:
|
||||
return "unknown-attribute";
|
||||
case NC_ERR_MISSING_ELEM:
|
||||
return "missing-element";
|
||||
case NC_ERR_BAD_ELEM:
|
||||
return "bad-element";
|
||||
case NC_ERR_UNKNOWN_ELEM:
|
||||
return "unknown-element";
|
||||
case NC_ERR_UNKNOWN_NS:
|
||||
return "unknown-namespace";
|
||||
case NC_ERR_LOCK_DENIED:
|
||||
return "lock-denied";
|
||||
case NC_ERR_DATA_EXISTS:
|
||||
return "data-exists";
|
||||
case NC_ERR_DATA_MISSING:
|
||||
return "data-missing";
|
||||
case NC_ERR_OP_FAILED:
|
||||
return "operation-failed";
|
||||
case NC_ERR_MALFORMED_MSG:
|
||||
return "malformed-message";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static NC_ERR
|
||||
nc_err_str2tag(const char *str)
|
||||
{
|
||||
if (!strcmp(str, "in-use")) {
|
||||
return NC_ERR_IN_USE;
|
||||
} else if (!strcmp(str, "invalid-value")) {
|
||||
return NC_ERR_INVALID_VALUE;
|
||||
} else if (!strcmp(str, "access-denied")) {
|
||||
return NC_ERR_ACCESS_DENIED;
|
||||
} else if (!strcmp(str, "rollback-failed")) {
|
||||
return NC_ERR_ROLLBACK_FAILED;
|
||||
} else if (!strcmp(str, "operation-not-supported")) {
|
||||
return NC_ERR_OP_NOT_SUPPORTED;
|
||||
} else if (!strcmp(str, "too-big")) {
|
||||
return NC_ERR_TOO_BIG;
|
||||
} else if (!strcmp(str, "resource-denied")) {
|
||||
return NC_ERR_RES_DENIED;
|
||||
} else if (!strcmp(str, "missing-attribute")) {
|
||||
return NC_ERR_MISSING_ATTR;
|
||||
} else if (!strcmp(str, "bad-attribute")) {
|
||||
return NC_ERR_BAD_ATTR;
|
||||
} else if (!strcmp(str, "unknown-attribute")) {
|
||||
return NC_ERR_UNKNOWN_ATTR;
|
||||
} else if (!strcmp(str, "missing-element")) {
|
||||
return NC_ERR_MISSING_ELEM;
|
||||
} else if (!strcmp(str, "bad-element")) {
|
||||
return NC_ERR_BAD_ELEM;
|
||||
} else if (!strcmp(str, "unknown-element")) {
|
||||
return NC_ERR_UNKNOWN_ELEM;
|
||||
} else if (!strcmp(str, "unknown-namespace")) {
|
||||
return NC_ERR_UNKNOWN_NS;
|
||||
} else if (!strcmp(str, "lock-denied")) {
|
||||
return NC_ERR_LOCK_DENIED;
|
||||
} else if (!strcmp(str, "data-exists")) {
|
||||
return NC_ERR_DATA_EXISTS;
|
||||
} else if (!strcmp(str, "data-missing")) {
|
||||
return NC_ERR_DATA_MISSING;
|
||||
} else if (!strcmp(str, "operation-failed")) {
|
||||
return NC_ERR_OP_FAILED;
|
||||
} else if (!strcmp(str, "malformed-message")) {
|
||||
return NC_ERR_MALFORMED_MSG;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *
|
||||
nc_err_type2str(NC_ERR_TYPE type)
|
||||
{
|
||||
switch (type) {
|
||||
case NC_ERR_TYPE_TRAN:
|
||||
return "transport";
|
||||
case NC_ERR_TYPE_RPC:
|
||||
return "rpc";
|
||||
case NC_ERR_TYPE_PROT:
|
||||
return "protocol";
|
||||
case NC_ERR_TYPE_APP:
|
||||
return "application";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static NC_ERR_TYPE
|
||||
nc_err_str2type(const char *str)
|
||||
{
|
||||
if (!strcmp(str, "transport")) {
|
||||
return NC_ERR_TYPE_TRAN;
|
||||
} else if (!strcmp(str, "rpc")) {
|
||||
return NC_ERR_TYPE_RPC;
|
||||
} else if (!strcmp(str, "protocol")) {
|
||||
return NC_ERR_TYPE_PROT;
|
||||
} else if (!strcmp(str, "application")) {
|
||||
return NC_ERR_TYPE_APP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API struct lyd_node *
|
||||
nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct lyd_node *err = NULL;
|
||||
NC_ERR_TYPE type;
|
||||
const char *arg1, *arg2;
|
||||
uint32_t sid;
|
||||
|
||||
if (!tag) {
|
||||
ERRARG("tag");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* rpc-error */
|
||||
if (lyd_new_opaq2(NULL, ctx, "rpc-error", NULL, NULL, NC_NS_BASE, &err)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
va_start(ap, tag);
|
||||
|
||||
/* error-type */
|
||||
switch (tag) {
|
||||
case NC_ERR_IN_USE:
|
||||
case NC_ERR_INVALID_VALUE:
|
||||
case NC_ERR_ACCESS_DENIED:
|
||||
case NC_ERR_ROLLBACK_FAILED:
|
||||
case NC_ERR_OP_NOT_SUPPORTED:
|
||||
type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
|
||||
if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
|
||||
ERRARG("type");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case NC_ERR_TOO_BIG:
|
||||
case NC_ERR_RES_DENIED:
|
||||
type = (NC_ERR_TYPE)va_arg(ap, int);
|
||||
break;
|
||||
case NC_ERR_MISSING_ATTR:
|
||||
case NC_ERR_BAD_ATTR:
|
||||
case NC_ERR_UNKNOWN_ATTR:
|
||||
type = (NC_ERR_TYPE)va_arg(ap, int);
|
||||
if (type == NC_ERR_TYPE_TRAN) {
|
||||
ERRARG("type");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case NC_ERR_MISSING_ELEM:
|
||||
case NC_ERR_BAD_ELEM:
|
||||
case NC_ERR_UNKNOWN_ELEM:
|
||||
type = (NC_ERR_TYPE)va_arg(ap, int);
|
||||
if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
|
||||
ERRARG("type");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case NC_ERR_UNKNOWN_NS:
|
||||
type = (NC_ERR_TYPE)va_arg(ap, int);
|
||||
if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
|
||||
ERRARG("type");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case NC_ERR_LOCK_DENIED:
|
||||
type = NC_ERR_TYPE_PROT;
|
||||
break;
|
||||
case NC_ERR_DATA_EXISTS:
|
||||
case NC_ERR_DATA_MISSING:
|
||||
type = NC_ERR_TYPE_APP;
|
||||
break;
|
||||
case NC_ERR_OP_FAILED:
|
||||
type = (NC_ERR_TYPE)va_arg(ap, int);
|
||||
if (type == NC_ERR_TYPE_TRAN) {
|
||||
ERRARG("type");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case NC_ERR_MALFORMED_MSG:
|
||||
type = NC_ERR_TYPE_RPC;
|
||||
break;
|
||||
default:
|
||||
ERRARG("tag");
|
||||
goto fail;
|
||||
}
|
||||
if (lyd_new_opaq2(err, NULL, "error-type", nc_err_type2str(type), NULL, NC_NS_BASE, NULL)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* error-tag */
|
||||
if (lyd_new_opaq2(err, NULL, "error-tag", nc_err_tag2str(tag), NULL, NC_NS_BASE, NULL)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* error-severity */
|
||||
if (lyd_new_opaq2(err, NULL, "error-severity", "error", NULL, NC_NS_BASE, NULL)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* error-message */
|
||||
switch (tag) {
|
||||
case NC_ERR_IN_USE:
|
||||
nc_err_set_msg(err, "The request requires a resource that already is in use.", "en");
|
||||
break;
|
||||
case NC_ERR_INVALID_VALUE:
|
||||
nc_err_set_msg(err, "The request specifies an unacceptable value for one or more parameters.", "en");
|
||||
break;
|
||||
case NC_ERR_TOO_BIG:
|
||||
nc_err_set_msg(err, "The request or response (that would be generated) is too large for the implementation to handle.", "en");
|
||||
break;
|
||||
case NC_ERR_MISSING_ATTR:
|
||||
nc_err_set_msg(err, "An expected attribute is missing.", "en");
|
||||
break;
|
||||
case NC_ERR_BAD_ATTR:
|
||||
nc_err_set_msg(err, "An attribute value is not correct.", "en");
|
||||
break;
|
||||
case NC_ERR_UNKNOWN_ATTR:
|
||||
nc_err_set_msg(err, "An unexpected attribute is present.", "en");
|
||||
break;
|
||||
case NC_ERR_MISSING_ELEM:
|
||||
nc_err_set_msg(err, "An expected element is missing.", "en");
|
||||
break;
|
||||
case NC_ERR_BAD_ELEM:
|
||||
nc_err_set_msg(err, "An element value is not correct.", "en");
|
||||
break;
|
||||
case NC_ERR_UNKNOWN_ELEM:
|
||||
nc_err_set_msg(err, "An unexpected element is present.", "en");
|
||||
break;
|
||||
case NC_ERR_UNKNOWN_NS:
|
||||
nc_err_set_msg(err, "An unexpected namespace is present.", "en");
|
||||
break;
|
||||
case NC_ERR_ACCESS_DENIED:
|
||||
nc_err_set_msg(err, "Access to the requested protocol operation or data model is denied because authorization failed.", "en");
|
||||
break;
|
||||
case NC_ERR_LOCK_DENIED:
|
||||
nc_err_set_msg(err, "Access to the requested lock is denied because the lock is currently held by another entity.", "en");
|
||||
break;
|
||||
case NC_ERR_RES_DENIED:
|
||||
nc_err_set_msg(err, "Request could not be completed because of insufficient resources.", "en");
|
||||
break;
|
||||
case NC_ERR_ROLLBACK_FAILED:
|
||||
nc_err_set_msg(err, "Request to roll back some configuration change was not completed for some reason.", "en");
|
||||
break;
|
||||
case NC_ERR_DATA_EXISTS:
|
||||
nc_err_set_msg(err, "Request could not be completed because the relevant data model content already exists.", "en");
|
||||
break;
|
||||
case NC_ERR_DATA_MISSING:
|
||||
nc_err_set_msg(err, "Request could not be completed because the relevant data model content does not exist.", "en");
|
||||
break;
|
||||
case NC_ERR_OP_NOT_SUPPORTED:
|
||||
nc_err_set_msg(err, "Request could not be completed because the requested operation is not supported by this implementation.", "en");
|
||||
break;
|
||||
case NC_ERR_OP_FAILED:
|
||||
nc_err_set_msg(err, "Request could not be completed because the requested operation failed for a non-specific reason.", "en");
|
||||
break;
|
||||
case NC_ERR_MALFORMED_MSG:
|
||||
nc_err_set_msg(err, "A message could not be handled because it failed to be parsed correctly.", "en");
|
||||
break;
|
||||
default:
|
||||
ERRARG("tag");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* error-info */
|
||||
switch (tag) {
|
||||
case NC_ERR_IN_USE:
|
||||
case NC_ERR_INVALID_VALUE:
|
||||
case NC_ERR_ACCESS_DENIED:
|
||||
case NC_ERR_ROLLBACK_FAILED:
|
||||
case NC_ERR_OP_NOT_SUPPORTED:
|
||||
case NC_ERR_TOO_BIG:
|
||||
case NC_ERR_RES_DENIED:
|
||||
case NC_ERR_DATA_EXISTS:
|
||||
case NC_ERR_DATA_MISSING:
|
||||
case NC_ERR_OP_FAILED:
|
||||
case NC_ERR_MALFORMED_MSG:
|
||||
break;
|
||||
case NC_ERR_MISSING_ATTR:
|
||||
case NC_ERR_BAD_ATTR:
|
||||
case NC_ERR_UNKNOWN_ATTR:
|
||||
arg1 = va_arg(ap, const char *);
|
||||
arg2 = va_arg(ap, const char *);
|
||||
|
||||
nc_err_add_bad_attr(err, arg1);
|
||||
nc_err_add_bad_elem(err, arg2);
|
||||
break;
|
||||
case NC_ERR_MISSING_ELEM:
|
||||
case NC_ERR_BAD_ELEM:
|
||||
case NC_ERR_UNKNOWN_ELEM:
|
||||
arg1 = va_arg(ap, const char *);
|
||||
|
||||
nc_err_add_bad_elem(err, arg1);
|
||||
break;
|
||||
case NC_ERR_UNKNOWN_NS:
|
||||
arg1 = va_arg(ap, const char *);
|
||||
arg2 = va_arg(ap, const char *);
|
||||
|
||||
nc_err_add_bad_elem(err, arg1);
|
||||
nc_err_add_bad_ns(err, arg2);
|
||||
break;
|
||||
case NC_ERR_LOCK_DENIED:
|
||||
sid = va_arg(ap, uint32_t);
|
||||
|
||||
nc_err_set_sid(err, sid);
|
||||
break;
|
||||
default:
|
||||
ERRARG("tag");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
return err;
|
||||
|
||||
fail:
|
||||
va_end(ap);
|
||||
lyd_free_siblings(err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
API NC_ERR_TYPE
|
||||
nc_err_get_type(const struct lyd_node *err)
|
||||
{
|
||||
struct lyd_node *match;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-type", &match);
|
||||
if (match) {
|
||||
return nc_err_str2type(((struct lyd_node_opaq *)match)->value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API NC_ERR
|
||||
nc_err_get_tag(const struct lyd_node *err)
|
||||
{
|
||||
struct lyd_node *match;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-tag", &match);
|
||||
if (match) {
|
||||
return nc_err_str2tag(((struct lyd_node_opaq *)match)->value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_err_set_app_tag(struct lyd_node *err, const char *error_app_tag)
|
||||
{
|
||||
struct lyd_node *match;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return -1;
|
||||
} else if (!error_app_tag) {
|
||||
ERRARG("error_app_tag");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* remove previous node */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
|
||||
if (match) {
|
||||
lyd_free_tree(match);
|
||||
}
|
||||
|
||||
if (lyd_new_opaq2(err, NULL, "error-app-tag", error_app_tag, NULL, NC_NS_BASE, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API const char *
|
||||
nc_err_get_app_tag(const struct lyd_node *err)
|
||||
{
|
||||
struct lyd_node *match;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
|
||||
if (match) {
|
||||
return ((struct lyd_node_opaq *)match)->value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_err_set_path(struct lyd_node *err, const char *error_path)
|
||||
{
|
||||
struct lyd_node *match;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return -1;
|
||||
} else if (!error_path) {
|
||||
ERRARG("error_path");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* remove previous node */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
|
||||
if (match) {
|
||||
lyd_free_tree(match);
|
||||
}
|
||||
|
||||
if (lyd_new_opaq2(err, NULL, "error-path", error_path, NULL, NC_NS_BASE, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API const char *
|
||||
nc_err_get_path(const struct lyd_node *err)
|
||||
{
|
||||
struct lyd_node *match;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
|
||||
if (match) {
|
||||
return ((struct lyd_node_opaq *)match)->value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_err_set_msg(struct lyd_node *err, const char *error_message, const char *lang)
|
||||
{
|
||||
struct lyd_node *match;
|
||||
struct lyd_attr *attr;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return -1;
|
||||
} else if (!error_message) {
|
||||
ERRARG("error_message");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* remove previous message */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
|
||||
if (match) {
|
||||
lyd_free_tree(match);
|
||||
}
|
||||
|
||||
if (lyd_new_opaq2(err, NULL, "error-message", error_message, NULL, NC_NS_BASE, &match)) {
|
||||
return -1;
|
||||
}
|
||||
if (lang && lyd_new_attr(match, NULL, "xml:lang", lang, &attr)) {
|
||||
lyd_free_tree(match);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API const char *
|
||||
nc_err_get_msg(const struct lyd_node *err)
|
||||
{
|
||||
struct lyd_node *match;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
|
||||
if (match) {
|
||||
return ((struct lyd_node_opaq *)match)->value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_err_set_sid(struct lyd_node *err, uint32_t session_id)
|
||||
{
|
||||
struct lyd_node *match, *info;
|
||||
char buf[22];
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* find error-info */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
|
||||
if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* remove previous node */
|
||||
lyd_find_sibling_opaq_next(lyd_child(info), "session-id", &match);
|
||||
if (match) {
|
||||
lyd_free_tree(match);
|
||||
}
|
||||
|
||||
sprintf(buf, "%" PRIu32, session_id);
|
||||
if (lyd_new_opaq2(info, NULL, "session-id", buf, NULL, NC_NS_BASE, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_err_add_bad_attr(struct lyd_node *err, const char *attr_name)
|
||||
{
|
||||
struct lyd_node *info;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return -1;
|
||||
} else if (!attr_name) {
|
||||
ERRARG("attr_name");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* find error-info */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
|
||||
if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lyd_new_opaq2(info, NULL, "bad-attribute", attr_name, NULL, NC_NS_BASE, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_err_add_bad_elem(struct lyd_node *err, const char *elem_name)
|
||||
{
|
||||
struct lyd_node *info;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return -1;
|
||||
} else if (!elem_name) {
|
||||
ERRARG("elem_name");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* find error-info */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
|
||||
if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lyd_new_opaq2(info, NULL, "bad-element", elem_name, NULL, NC_NS_BASE, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_err_add_bad_ns(struct lyd_node *err, const char *ns_name)
|
||||
{
|
||||
struct lyd_node *info;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return -1;
|
||||
} else if (!ns_name) {
|
||||
ERRARG("ns_name");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* find error-info */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
|
||||
if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lyd_new_opaq2(info, NULL, "bad-namespace", ns_name, NULL, NC_NS_BASE, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_err_add_info_other(struct lyd_node *err, struct lyd_node *other)
|
||||
{
|
||||
struct lyd_node *info;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return -1;
|
||||
} else if (!other) {
|
||||
ERRARG("other");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* find error-info */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
|
||||
if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
lyd_insert_child(info, other);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nc_server_rpc_free(struct nc_server_rpc *rpc)
|
||||
{
|
||||
if (!rpc) {
|
||||
return;
|
||||
}
|
||||
|
||||
lyd_free_tree(rpc->envp);
|
||||
|
||||
/* may be action */
|
||||
lyd_free_all(rpc->rpc);
|
||||
|
||||
free(rpc);
|
||||
}
|
||||
|
||||
API void
|
||||
nc_server_reply_free(struct nc_server_reply *reply)
|
||||
{
|
||||
struct nc_server_reply_data *data_rpl;
|
||||
struct nc_server_reply_error *error_rpl;
|
||||
|
||||
if (!reply) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (reply->type) {
|
||||
case NC_RPL_DATA:
|
||||
data_rpl = (struct nc_server_reply_data *)reply;
|
||||
if (data_rpl->free) {
|
||||
lyd_free_siblings(data_rpl->data);
|
||||
}
|
||||
break;
|
||||
case NC_RPL_OK:
|
||||
/* nothing to free */
|
||||
break;
|
||||
case NC_RPL_ERROR:
|
||||
error_rpl = (struct nc_server_reply_error *)reply;
|
||||
lyd_free_siblings(error_rpl->err);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(reply);
|
||||
}
|
||||
|
||||
API struct nc_server_notif *
|
||||
nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramtype)
|
||||
{
|
||||
struct nc_server_notif *ntf;
|
||||
struct lyd_node *elem;
|
||||
int found;
|
||||
|
||||
if (!event) {
|
||||
ERRARG("event");
|
||||
return NULL;
|
||||
} else if (!eventtime) {
|
||||
ERRARG("eventtime");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check that there is a notification */
|
||||
found = 0;
|
||||
LYD_TREE_DFS_BEGIN(event, elem) {
|
||||
if (elem->schema->nodetype == LYS_NOTIF) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
LYD_TREE_DFS_END(event, elem);
|
||||
}
|
||||
if (!found) {
|
||||
ERRARG("event");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ntf = malloc(sizeof *ntf);
|
||||
if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
|
||||
ntf->eventtime = strdup(eventtime);
|
||||
if (lyd_dup_single(event, NULL, LYD_DUP_RECURSIVE, &ntf->ntf)) {
|
||||
free(ntf);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
ntf->eventtime = eventtime;
|
||||
ntf->ntf = event;
|
||||
}
|
||||
ntf->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
|
||||
|
||||
return ntf;
|
||||
}
|
||||
|
||||
API void
|
||||
nc_server_notif_free(struct nc_server_notif *notif)
|
||||
{
|
||||
if (!notif) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (notif->free) {
|
||||
lyd_free_tree(notif->ntf);
|
||||
free(notif->eventtime);
|
||||
}
|
||||
free(notif);
|
||||
}
|
||||
|
||||
API const char *
|
||||
nc_server_notif_get_time(const struct nc_server_notif *notif)
|
||||
{
|
||||
if (!notif) {
|
||||
ERRARG("notif");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return notif->eventtime;
|
||||
}
|
340
src/messages_server.h
Normal file
340
src/messages_server.h
Normal file
|
@ -0,0 +1,340 @@
|
|||
/**
|
||||
* @file messages_server.h
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2's functions and structures of server NETCONF messages.
|
||||
*
|
||||
* Copyright (c) 2015-2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_MESSAGES_SERVER_H_
|
||||
#define NC_MESSAGES_SERVER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "netconf.h"
|
||||
#include "session.h"
|
||||
|
||||
/**
|
||||
* @defgroup server_msg Server Messages
|
||||
* @ingroup server
|
||||
*
|
||||
* @brief Functions to create NETCONF Event notifications and replies to the NETCONF RPCs (or actions).
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Enumeration of NETCONF errors
|
||||
*/
|
||||
typedef enum NC_ERROR {
|
||||
NC_ERR_UNKNOWN = 0, /**< unknown error */
|
||||
NC_ERR_IN_USE, /**< in-use error */
|
||||
NC_ERR_INVALID_VALUE, /**< invalid-value error */
|
||||
NC_ERR_TOO_BIG, /**< too-big error */
|
||||
NC_ERR_MISSING_ATTR, /**< missing-attribute error */
|
||||
NC_ERR_BAD_ATTR, /**< bad-attribute error */
|
||||
NC_ERR_UNKNOWN_ATTR, /**< unknown-attribute error */
|
||||
NC_ERR_MISSING_ELEM, /**< missing-element error */
|
||||
NC_ERR_BAD_ELEM, /**< bad-element error */
|
||||
NC_ERR_UNKNOWN_ELEM, /**< unknown-element error */
|
||||
NC_ERR_UNKNOWN_NS, /**< unknown-namespace error */
|
||||
NC_ERR_ACCESS_DENIED, /**< access-denied error */
|
||||
NC_ERR_LOCK_DENIED, /**< lock-denied error */
|
||||
NC_ERR_RES_DENIED, /**< resource-denied error */
|
||||
NC_ERR_ROLLBACK_FAILED, /**< rollback-failed error */
|
||||
NC_ERR_DATA_EXISTS, /**< data-exists error */
|
||||
NC_ERR_DATA_MISSING, /**< data-missing error */
|
||||
NC_ERR_OP_NOT_SUPPORTED, /**< operation-not-supported error */
|
||||
NC_ERR_OP_FAILED, /**< operation-failed error */
|
||||
NC_ERR_MALFORMED_MSG /**< malformed-message error */
|
||||
} NC_ERR;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of NETCONF error type (layer)
|
||||
*/
|
||||
typedef enum NC_ERROR_TYPE {
|
||||
NC_ERR_TYPE_UNKNOWN = 0, /**< unknown layer */
|
||||
NC_ERR_TYPE_TRAN, /**< transport layer */
|
||||
NC_ERR_TYPE_RPC, /**< RPC layer */
|
||||
NC_ERR_TYPE_PROT, /**< protocol layer */
|
||||
NC_ERR_TYPE_APP /**< application layer */
|
||||
} NC_ERR_TYPE;
|
||||
|
||||
/**
|
||||
* @brief NETCONF server rpc-reply object
|
||||
*/
|
||||
struct nc_server_reply;
|
||||
|
||||
/**
|
||||
* @brief NETCONF server Event Notification object
|
||||
*/
|
||||
struct nc_server_notif;
|
||||
|
||||
/**
|
||||
* @brief NETCONF server error structure
|
||||
*/
|
||||
struct nc_server_error;
|
||||
|
||||
/**
|
||||
* @brief Create an OK rpc-reply object.
|
||||
*
|
||||
* @return rpc-reply object, NULL on error.
|
||||
*/
|
||||
struct nc_server_reply *nc_server_reply_ok(void);
|
||||
|
||||
/**
|
||||
* @brief Create a DATA rpc-reply object.
|
||||
*
|
||||
* @param[in] data Reply data tree. This tree must be valid according to
|
||||
* the RPC output of the RPC this is a reply to.
|
||||
* @param[in] wd with-default mode if applicable
|
||||
* @param[in] paramtype Determines how the @p data parameter is treated.
|
||||
* @return rpc-reply object, NULL on error.
|
||||
*/
|
||||
struct nc_server_reply *nc_server_reply_data(struct lyd_node *data, NC_WD_MODE wd, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Create an ERROR rpc-reply object.
|
||||
*
|
||||
* @param[in] err Errors as opaque data node tree. It will be freed with the returned object.
|
||||
* @return rpc-reply object, NULL on error.
|
||||
*/
|
||||
struct nc_server_reply *nc_server_reply_err(struct lyd_node *err);
|
||||
|
||||
/**
|
||||
* @brief Add another error opaque data node tree to an ERROR rpc-reply object.
|
||||
*
|
||||
* @param[in] reply ERROR reply to add to.
|
||||
* @param[in] err Error as opaque data node tree. It will be freed with the returned object.
|
||||
* @return 0 on success, -1 on errror.
|
||||
*/
|
||||
int nc_server_reply_add_err(struct nc_server_reply *reply, struct lyd_node *err);
|
||||
|
||||
/**
|
||||
* @brief Get last error from an ERROR rpc-reply object.
|
||||
*
|
||||
* @param[in] reply ERROR reply to read from.
|
||||
* @return Last error opaque data tree, NULL on failure.
|
||||
*/
|
||||
const struct lyd_node *nc_server_reply_get_last_err(const struct nc_server_reply *reply);
|
||||
|
||||
/**
|
||||
* @brief Create a server error structure. Its \<error-message\> is filled with
|
||||
* a general description of the specific error.
|
||||
*
|
||||
* @param[in] ctx libyang context to use.
|
||||
* @param[in] tag \<error-tag\> of the server error specified as #NC_ERR value. According to the tag, the
|
||||
* specific additional parameters are required:
|
||||
* - #NC_ERR_IN_USE
|
||||
* - #NC_ERR_INVALID_VALUE
|
||||
* - #NC_ERR_ACCESS_DENIED
|
||||
* - #NC_ERR_ROLLBACK_FAILED
|
||||
* - #NC_ERR_OP_NOT_SUPPORTED
|
||||
* - #NC_ERR_TOO_BIG
|
||||
* - #NC_ERR_RES_DENIED
|
||||
* - #NC_ERR_OP_FAILED
|
||||
* - `NC_ERR_TYPE type;` - type (layer) of the error.
|
||||
* - #NC_ERR_MISSING_ATTR
|
||||
* - #NC_ERR_BAD_ATTR
|
||||
* - #NC_ERR_UNKNOWN_ATTR
|
||||
* - `NC_ERR_TYPE type;` - type (layer) of the error.
|
||||
* - `const char *attr_name;` - error \<bad-attribute\> value.
|
||||
* - `const char *elem_name;` - error \<bad-element\> value.
|
||||
* - #NC_ERR_MISSING_ELEM
|
||||
* - #NC_ERR_BAD_ELEM
|
||||
* - #NC_ERR_UNKNOWN_ELEM
|
||||
* - `NC_ERR_TYPE type;` - type (layer) of the error.
|
||||
* - `const char *elem_name;` - error \<bad-element\> value.
|
||||
* - #NC_ERR_UNKNOWN_NS
|
||||
* - `NC_ERR_TYPE type;` - type (layer) of the error.
|
||||
* - `const char *elem_name;` - error \<bad-element\> value.
|
||||
* - `const char *nc_name;` - error \<bad-namespace\> value.
|
||||
* - #NC_ERR_LOCK_DENIED
|
||||
* - `uint32_t session_id;` - error \<session-id\> value.
|
||||
* - #NC_ERR_DATA_EXISTS
|
||||
* - #NC_ERR_DATA_MISSING
|
||||
* - #NC_ERR_MALFORMED_MSG
|
||||
* - no additional arguments
|
||||
* @return Opaque data node tree representing the error.
|
||||
*/
|
||||
struct lyd_node *nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...);
|
||||
|
||||
/**
|
||||
* @brief Get the \<error-type\> of a server error.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to read from.
|
||||
* @return Server error type, 0 on error.
|
||||
*/
|
||||
NC_ERR_TYPE nc_err_get_type(const struct lyd_node *err);
|
||||
|
||||
/**
|
||||
* @brief Get the \<error-tag\> of a server error.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to read from.
|
||||
* @return Server error tag, 0 on error.
|
||||
*/
|
||||
NC_ERR nc_err_get_tag(const struct lyd_node *err);
|
||||
|
||||
/**
|
||||
* @brief Set the \<error-app-tag\> element of an error. Any previous value will be overwritten.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to modify.
|
||||
* @param[in] error_app_tag New value of \<error-app-tag\>.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_err_set_app_tag(struct lyd_node *err, const char *error_app_tag);
|
||||
|
||||
/**
|
||||
* @brief Get the \<error-app-tag\> of a server error.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to read from.
|
||||
* @return Server error app tag, NULL on error.
|
||||
*/
|
||||
const char *nc_err_get_app_tag(const struct lyd_node *err);
|
||||
|
||||
/**
|
||||
* @brief Set the \<error-path\> element of an error. Any previous value will be overwritten.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to modify.
|
||||
* @param[in] error_path New value of \<error-path\>.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_err_set_path(struct lyd_node *err, const char *error_path);
|
||||
|
||||
/**
|
||||
* @brief Get the \<error-path\> of a server error.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to read from.
|
||||
* @return Server error path, NULL on error.
|
||||
*/
|
||||
const char *nc_err_get_path(const struct lyd_node *err);
|
||||
|
||||
/**
|
||||
* @brief Set the \<error-message\> element of an error. Any previous value will be overwritten.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to modify.
|
||||
* @param[in] error_message New value of \<error-message\>.
|
||||
* @param[in] lang Optional language of @p error_message.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_err_set_msg(struct lyd_node *err, const char *error_message, const char *lang);
|
||||
|
||||
/**
|
||||
* @brief Get the \<error-message\> of a server error.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to read from.
|
||||
* @return Server error message, NULL on error.
|
||||
*/
|
||||
const char *nc_err_get_msg(const struct lyd_node *err);
|
||||
|
||||
/**
|
||||
* @brief Set the \<session-id\> element of an error. Any previous value will be overwritten.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to modify.
|
||||
* @param[in] session_id New value of \<session-id\>.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_err_set_sid(struct lyd_node *err, uint32_t session_id);
|
||||
|
||||
/**
|
||||
* @brief Add a \<bad-attribute\> element to an error.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to modify.
|
||||
* @param[in] attr_name Value of the new \<bad-attribute\> element.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_err_add_bad_attr(struct lyd_node *err, const char *attr_name);
|
||||
|
||||
/**
|
||||
* @brief Add a \<bad-element\> element to an error.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to modify.
|
||||
* @param[in] elem_name Value of the new \<bad-element\> element.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_err_add_bad_elem(struct lyd_node *err, const char *elem_name);
|
||||
|
||||
/**
|
||||
* @brief Add a \<bad-namespace\> element to an error.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to modify.
|
||||
* @param[in] ns_name Value of the new \<bad-namespace\> element.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_err_add_bad_ns(struct lyd_node *err, const char *ns_name);
|
||||
|
||||
/**
|
||||
* @brief Add an additional custom element to an error.
|
||||
*
|
||||
* @param[in] err Error opaque data node tree to modify.
|
||||
* @param[in] other Other error opaque data node tree.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_err_add_info_other(struct lyd_node *err, struct lyd_node *other);
|
||||
|
||||
/**
|
||||
* @brief Free a server rpc-reply object.
|
||||
*
|
||||
* @param[in] reply Server rpc-reply object to free.
|
||||
*/
|
||||
void nc_server_reply_free(struct nc_server_reply *reply);
|
||||
|
||||
/**
|
||||
* @brief Create Event Notification object to be sent to the subscribed client(s).
|
||||
*
|
||||
* @param[in] event Notification data tree (valid as LYD_OPT_NOTIF) from libyang. The tree is directly used in created
|
||||
* object, so the caller is supposed to not free the tree on its own, but only via freeng the created object.
|
||||
* @param[in] eventtime YANG dateTime format value of the time when the event was generated by the event source.
|
||||
* Caller can use nc_timespec2datetime() to create the value from a timespec value.
|
||||
* @param[in] paramtype How to further manage data parameters.
|
||||
* @return Newly created structure of the Event Notification object to be sent to the clients via nc_server_send_notif()
|
||||
* and freed using nc_server_notif_free().
|
||||
*/
|
||||
struct nc_server_notif *nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramtype);
|
||||
|
||||
/**
|
||||
* @brief Send NETCONF Event Notification via the session.
|
||||
*
|
||||
* @param[in] session NETCONF session where the Event Notification will be written.
|
||||
* @param[in] notif NETCOFN Notification object to send via specified session. Object can be created by
|
||||
* nc_notif_new() function.
|
||||
* @param[in] timeout Timeout for writing in milliseconds. Use negative value for infinite
|
||||
* waiting and 0 for return if data cannot be sent immediately.
|
||||
* @return #NC_MSG_NOTIF on success,
|
||||
* #NC_MSG_WOULDBLOCK in case of a busy session, and
|
||||
* #NC_MSG_ERROR on error.
|
||||
*/
|
||||
NC_MSG_TYPE nc_server_notif_send(struct nc_session *session, struct nc_server_notif *notif, int timeout);
|
||||
|
||||
/**
|
||||
* @brief Free a server Event Notification object.
|
||||
*
|
||||
* @param[in] notif Server Event Notification object to free.
|
||||
*/
|
||||
void nc_server_notif_free(struct nc_server_notif *notif);
|
||||
|
||||
/**
|
||||
* @brief Get the notification timestamp.
|
||||
*
|
||||
* @param[in] notif Server notification to read from.
|
||||
* @return Datetime timestamp of the notification, NULL on error.
|
||||
*/
|
||||
const char *nc_server_notif_get_time(const struct nc_server_notif *notif);
|
||||
|
||||
/** @} Client Messages */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NC_MESSAGES_SERVER_H_ */
|
134
src/netconf.h
Normal file
134
src/netconf.h
Normal file
|
@ -0,0 +1,134 @@
|
|||
/**
|
||||
* @file netconf.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @brief libnetconf2's general public functions and structures definitions.
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_NETCONF_H_
|
||||
#define NC_NETCONF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/**
|
||||
* @addtogroup misc
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Base NETCONF namespace */
|
||||
#define NC_NS_BASE "urn:ietf:params:xml:ns:netconf:base:1.0"
|
||||
/** @brief Notifications namespace */
|
||||
#define NC_NS_NOTIF "urn:ietf:params:xml:ns:netconf:notification:1.0"
|
||||
|
||||
/** @brief Default NETCONF over SSH port */
|
||||
#define NC_PORT_SSH 830
|
||||
/** @brief Default NETCONF over SSH Call Home port */
|
||||
#define NC_PORT_CH_SSH 4334
|
||||
|
||||
/** @brief Default NETCONF over TLS port */
|
||||
#define NC_PORT_TLS 6513
|
||||
/** @brief Default NETCONF over TLS Call Home port */
|
||||
#define NC_PORT_CH_TLS 4335
|
||||
|
||||
/**
|
||||
* @brief Set RPC callback to a schema node.
|
||||
*
|
||||
* @param[in] node const struct lysc_node *node
|
||||
* @param[in] cb nc_rpc_clb cb
|
||||
*/
|
||||
#define nc_set_rpc_callback(node, cb) (node->priv = cb)
|
||||
|
||||
/**
|
||||
* @brief Enumeration of reasons of the NETCONF session termination as defined in RFC 6470.
|
||||
*/
|
||||
typedef enum NC_SESSION_TERM_REASON {
|
||||
NC_SESSION_TERM_ERR = -1, /**< error return code for function getting the session termination reason */
|
||||
NC_SESSION_TERM_NONE = 0, /**< session still running */
|
||||
NC_SESSION_TERM_CLOSED, /**< closed by client in a normal fashion */
|
||||
NC_SESSION_TERM_KILLED, /**< session was terminated by \<kill-session\> operation */
|
||||
NC_SESSION_TERM_DROPPED, /**< transport layer connection was unexpectedly closed */
|
||||
NC_SESSION_TERM_TIMEOUT, /**< terminated because of inactivity */
|
||||
NC_SESSION_TERM_BADHELLO, /**< \<hello\> message was invalid */
|
||||
NC_SESSION_TERM_OTHER /**< terminated for some other reason */
|
||||
} NC_SESSION_TERM_REASON;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of NETCONF message types.
|
||||
*/
|
||||
typedef enum NC_MSG_TYPE {
|
||||
NC_MSG_ERROR, /**< error return value */
|
||||
NC_MSG_WOULDBLOCK, /**< timeout return value */
|
||||
NC_MSG_NONE, /**< no message at input or message was processed internally */
|
||||
NC_MSG_HELLO, /**< \<hello\> message */
|
||||
NC_MSG_BAD_HELLO, /**< \<hello\> message parsing failed */
|
||||
NC_MSG_RPC, /**< \<rpc\> message */
|
||||
NC_MSG_REPLY, /**< \<rpc-reply\> message */
|
||||
NC_MSG_REPLY_ERR_MSGID, /**< \<rpc-reply\> message with missing or wrong message-id attribute value */
|
||||
NC_MSG_NOTIF /**< \<notification\> message */
|
||||
} NC_MSG_TYPE;
|
||||
|
||||
/**
|
||||
* @brief Messages of NETCONF message type enum.
|
||||
*/
|
||||
extern const char *nc_msgtype2str[];
|
||||
|
||||
/**
|
||||
* @brief Enumeration of the supported types of datastores defined by NETCONF
|
||||
*/
|
||||
typedef enum NC_DATASTORE_TYPE {
|
||||
NC_DATASTORE_ERROR = 0, /**< error state of functions returning the datastore type */
|
||||
NC_DATASTORE_CONFIG, /**< value describing that the datastore is set as config */
|
||||
NC_DATASTORE_URL, /**< value describing that the datastore data should be given from the URL */
|
||||
NC_DATASTORE_RUNNING, /**< base NETCONF's datastore containing the current device configuration */
|
||||
NC_DATASTORE_STARTUP, /**< separated startup datastore as defined in Distinct Startup Capability */
|
||||
NC_DATASTORE_CANDIDATE /**< separated working datastore as defined in Candidate Configuration Capability */
|
||||
} NC_DATASTORE;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of NETCONF with-defaults capability modes.
|
||||
*/
|
||||
typedef enum NC_WITHDEFAULTS_MODE {
|
||||
NC_WD_UNKNOWN = 0, /**< invalid mode */
|
||||
NC_WD_ALL, /**< report-all mode */
|
||||
NC_WD_ALL_TAG, /**< report-all-tagged mode */
|
||||
NC_WD_TRIM, /**< trim mode */
|
||||
NC_WD_EXPLICIT /**< explicit mode */
|
||||
} NC_WD_MODE;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of NETCONF (both server and client) rpc-reply types.
|
||||
*/
|
||||
typedef enum NC_REPLY {
|
||||
NC_RPL_OK, /**< OK rpc-reply */
|
||||
NC_RPL_DATA, /**< DATA rpc-reply */
|
||||
NC_RPL_ERROR, /**< ERROR rpc-reply */
|
||||
NC_RPL_NOTIF /**< notification (client-only) */
|
||||
} NC_RPL;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of function parameter treatments.
|
||||
*/
|
||||
typedef enum NC_PARAMTYPE {
|
||||
NC_PARAMTYPE_CONST, /**< use the parameter directly, do not free */
|
||||
NC_PARAMTYPE_FREE, /**< use the parameter directly, free afterwards */
|
||||
NC_PARAMTYPE_DUP_AND_FREE /**< make a copy of the argument, free afterwards */
|
||||
} NC_PARAMTYPE;
|
||||
|
||||
/** @} Miscellaneous */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NC_NETCONF_H_ */
|
1694
src/session.c
Normal file
1694
src/session.c
Normal file
File diff suppressed because it is too large
Load diff
244
src/session.h
Normal file
244
src/session.h
Normal file
|
@ -0,0 +1,244 @@
|
|||
/**
|
||||
* \file session.h
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2 session manipulation
|
||||
*
|
||||
* Copyright (c) 2015 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_SESSION_H_
|
||||
#define NC_SESSION_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "netconf.h"
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
|
||||
/**
|
||||
* @brief Enumeration of NETCONF SSH authentication methods
|
||||
*/
|
||||
typedef enum {
|
||||
NC_SSH_AUTH_PUBLICKEY = 0x01, /**< publickey SSH authentication */
|
||||
NC_SSH_AUTH_PASSWORD = 0x02, /**< password SSH authentication */
|
||||
NC_SSH_AUTH_INTERACTIVE = 0x04 /**< interactive SSH authentication */
|
||||
} NC_SSH_AUTH_TYPE;
|
||||
|
||||
#endif /* NC_ENABLED_SSH */
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
|
||||
/**
|
||||
* @brief Enumeration of cert-to-name mapping types
|
||||
*/
|
||||
typedef enum {
|
||||
NC_TLS_CTN_UNKNOWN = 0, /**< unknown mapping */
|
||||
NC_TLS_CTN_SPECIFIED, /**< username explicitly specified */
|
||||
NC_TLS_CTN_SAN_RFC822_NAME, /**< email address as username */
|
||||
NC_TLS_CTN_SAN_DNS_NAME, /**< DNS name as username */
|
||||
NC_TLS_CTN_SAN_IP_ADDRESS, /**< IP address as username */
|
||||
NC_TLS_CTN_SAN_ANY, /**< any certificate Subject Alternative Name as username */
|
||||
NC_TLS_CTN_COMMON_NAME /**< common name as username */
|
||||
} NC_TLS_CTN_MAPTYPE;
|
||||
|
||||
#endif /* NC_ENABLED_TLS */
|
||||
|
||||
/**
|
||||
* @brief Enumeration of possible session statuses
|
||||
*/
|
||||
typedef enum {
|
||||
NC_STATUS_ERR = -1, /**< error return code for function getting the session status */
|
||||
NC_STATUS_STARTING = 0, /**< session is not yet fully initiated */
|
||||
NC_STATUS_CLOSING, /**< session is being closed */
|
||||
NC_STATUS_INVALID, /**< session is not running and is supposed to be closed (nc_session_free()) */
|
||||
NC_STATUS_RUNNING /**< up and running */
|
||||
} NC_STATUS;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of transport implementations (ways how libnetconf implements NETCONF transport protocol)
|
||||
*/
|
||||
typedef enum {
|
||||
NC_TI_NONE = 0, /**< none - session is not connected yet */
|
||||
NC_TI_FD, /**< file descriptors - use standard input/output, transport protocol is implemented
|
||||
outside the current application */
|
||||
NC_TI_UNIX, /**< unix socket */
|
||||
#ifdef NC_ENABLED_SSH
|
||||
NC_TI_LIBSSH, /**< libssh - use libssh library, only for NETCONF over SSH transport */
|
||||
#endif
|
||||
#ifdef NC_ENABLED_TLS
|
||||
NC_TI_OPENSSL /**< OpenSSL - use OpenSSL library, only for NETCONF over TLS transport */
|
||||
#endif
|
||||
} NC_TRANSPORT_IMPL;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of Call Home connection types.
|
||||
*/
|
||||
typedef enum {
|
||||
NC_CH_CT_NOT_SET = 0,
|
||||
NC_CH_PERSIST,
|
||||
NC_CH_PERIOD
|
||||
} NC_CH_CONN_TYPE;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of Call Home client priority policy.
|
||||
*/
|
||||
typedef enum {
|
||||
NC_CH_FIRST_LISTED = 0, // default
|
||||
NC_CH_LAST_CONNECTED,
|
||||
NC_CH_RANDOM
|
||||
} NC_CH_START_WITH;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of SSH key types.
|
||||
*/
|
||||
typedef enum {
|
||||
NC_SSH_KEY_UNKNOWN = 0,
|
||||
NC_SSH_KEY_DSA,
|
||||
NC_SSH_KEY_RSA,
|
||||
NC_SSH_KEY_ECDSA
|
||||
} NC_SSH_KEY_TYPE;
|
||||
|
||||
/**
|
||||
* @brief NETCONF session object
|
||||
*/
|
||||
struct nc_session;
|
||||
|
||||
/**
|
||||
* @brief Get session status.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return Session status.
|
||||
*/
|
||||
NC_STATUS nc_session_get_status(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Get session termination reason.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return Session termination reason enum value.
|
||||
*/
|
||||
NC_SESSION_TERM_REASON nc_session_get_term_reason(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Get session killer session ID.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return Session killer ID.
|
||||
*/
|
||||
uint32_t nc_session_get_killed_by(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Get session ID.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return Session ID.
|
||||
*/
|
||||
uint32_t nc_session_get_id(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Get session NETCONF version.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return 0 for version 1.0, non-zero for version 1.1.
|
||||
*/
|
||||
int nc_session_get_version(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Get session transport used.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return Session transport.
|
||||
*/
|
||||
NC_TRANSPORT_IMPL nc_session_get_ti(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Get session username.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return Session username.
|
||||
*/
|
||||
const char *nc_session_get_username(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Get session host.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return Session host.
|
||||
*/
|
||||
const char *nc_session_get_host(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Get session port.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return Session port.
|
||||
*/
|
||||
uint16_t nc_session_get_port(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Get session path (unix socket only).
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return Session unix socket path.
|
||||
*/
|
||||
const char *nc_session_get_path(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Get session context.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return Session context.
|
||||
*/
|
||||
struct ly_ctx *nc_session_get_ctx(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Assign arbitrary data to a session.
|
||||
*
|
||||
* @param[in] session Session to modify.
|
||||
* @param[in] data Data to be stored in the session.
|
||||
*/
|
||||
void nc_session_set_data(struct nc_session *session, void *data);
|
||||
|
||||
/**
|
||||
* @brief Get the data assigned to a session.
|
||||
*
|
||||
* @param[in] session Session to get the data from.
|
||||
* @return Session-specific data.
|
||||
*/
|
||||
void *nc_session_get_data(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Free the NETCONF session object.
|
||||
*
|
||||
* @param[in] session Object to free.
|
||||
* @param[in] data_free Session user data destructor.
|
||||
*/
|
||||
void nc_session_free(struct nc_session *session, void (*data_free)(void *));
|
||||
|
||||
#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS)
|
||||
|
||||
/**
|
||||
* @brief Free all the dynamically allocated thread-specific libssl/libcrypto
|
||||
* resources.
|
||||
*
|
||||
* This function should be called only if init (nc_client_init(), respectively nc_server_init()) was called.
|
||||
* Call it in every thread your application creates just before the thread exits. In the last thread
|
||||
* (usually the main one) call nc_client_destroy(), respectively nc_server_destroy().
|
||||
*/
|
||||
void nc_thread_destroy(void);
|
||||
|
||||
#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NC_SESSION_H_ */
|
2946
src/session_client.c
Normal file
2946
src/session_client.c
Normal file
File diff suppressed because it is too large
Load diff
631
src/session_client.h
Normal file
631
src/session_client.h
Normal file
|
@ -0,0 +1,631 @@
|
|||
/**
|
||||
* @file session_client.h
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 session client manipulation
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_SESSION_CLIENT_H_
|
||||
#define NC_SESSION_CLIENT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
# include <libssh/libssh.h>
|
||||
#endif
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
# include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#include "messages_client.h"
|
||||
#include "netconf.h"
|
||||
#include "session.h"
|
||||
|
||||
/**
|
||||
* @addtogroup client
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set location where libnetconf tries to search for YANG/YIN schemas.
|
||||
*
|
||||
* The location is searched when connecting to a NETCONF server and building
|
||||
* YANG context for further processing of the NETCONF messages and data.
|
||||
*
|
||||
* The searchpath is also used to store schemas retreived via \<get-schema\>
|
||||
* operation - if the schema is not found in searchpath neither via schema
|
||||
* callback provided via nc_client_set_schema_callback() and server supports
|
||||
* the NETCONF \<get-schema\> operation, the schema is retrieved this way and
|
||||
* stored into the searchpath (if specified).
|
||||
*
|
||||
* @param[in] path Directory where to search for YANG/YIN schemas.
|
||||
* @return 0 on success, 1 on (memory allocation) failure.
|
||||
*/
|
||||
int nc_client_set_schema_searchpath(const char *path);
|
||||
|
||||
/**
|
||||
* @brief Get schema searchpath that was set by nc_client_set_schema_searchpath().
|
||||
*
|
||||
* @return Schema searchpath directory, NULL if not set.
|
||||
*/
|
||||
const char *nc_client_get_schema_searchpath(void);
|
||||
|
||||
/**
|
||||
* @brief Set callback function to get missing schemas.
|
||||
*
|
||||
* @param[in] clb Callback responsible for returning the missing model.
|
||||
* @param[in] user_data Arbitrary data that will always be passed to the callback @p clb.
|
||||
* @return 0 on success, 1 on (memory allocation) failure.
|
||||
*/
|
||||
int nc_client_set_schema_callback(ly_module_imp_clb clb, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Get callback function used to get missing schemas.
|
||||
*
|
||||
* @param[out] user_data Optionally return the private data set with the callback.
|
||||
* Note that the caller is responsible for freeing the private data, so before
|
||||
* changing the callback, private data used for the previous callback should be
|
||||
* freed.
|
||||
* @return Pointer to the set callback, NULL if no such callback was set.
|
||||
*/
|
||||
ly_module_imp_clb nc_client_get_schema_callback(void **user_data);
|
||||
|
||||
/**
|
||||
* @brief Use the provided thread-specific client's context in the current thread.
|
||||
*
|
||||
* Note that from this point the context is shared with the thread from which the context was taken and any
|
||||
* nc_client_*set* functions and functions creating connection in these threads should be protected from the
|
||||
* concurrent execution.
|
||||
*
|
||||
* Context contains schema searchpath/callback, call home binds, TLS and SSH authentication data (username, keys,
|
||||
* various certificates and callbacks).
|
||||
*
|
||||
* @param[in] context Client's thread-specific context provided by nc_client_get_thread_context().
|
||||
*/
|
||||
void nc_client_set_thread_context(void *context);
|
||||
|
||||
/**
|
||||
* @brief Get thread-specific client context for sharing with some other thread using
|
||||
* nc_client_set_thread_context().
|
||||
*
|
||||
* @return Pointer to the client's context of the current thread.
|
||||
*/
|
||||
void *nc_client_get_thread_context(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize libssh and/or libssl/libcrypto for use in the client.
|
||||
*/
|
||||
void nc_client_init(void);
|
||||
|
||||
/**
|
||||
* @brief Destroy all libssh and/or libssl/libcrypto dynamic memory and
|
||||
* the client options, for both SSH and TLS, and for Call Home too.
|
||||
*/
|
||||
void nc_client_destroy(void);
|
||||
|
||||
/** @} Client */
|
||||
|
||||
/**
|
||||
* @defgroup client_session Client Session
|
||||
* @ingroup client
|
||||
*
|
||||
* @brief Client-side NETCONF session manipulation.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Connect to the NETCONF server via proviaded input/output file descriptors.
|
||||
*
|
||||
* Transport layer is supposed to be already set. Function do not cover authentication
|
||||
* or any other manipulation with the transport layer, it only establish NETCONF session
|
||||
* by sending and processing NETCONF \<hello\> messages.
|
||||
*
|
||||
* @param[in] fdin Input file descriptor for reading (clear) data from NETCONF server.
|
||||
* @param[in] fdout Output file descriptor for writing (clear) data for NETCONF server.
|
||||
* @param[in] ctx Optional parameter. If set, provides strict YANG context for the session
|
||||
* (ignoring what is actually supported by the server side). If not set,
|
||||
* YANG context is created for the session using \<get-schema\> (if supported
|
||||
* by the server side) or/and by searching for YANG schemas in the searchpath
|
||||
* (see nc_client_schema_searchpath()). In every case except not providing context
|
||||
* to connect to a server supporting \<get-schema\> it is possible that
|
||||
* the session context will not include all the models supported by the server.
|
||||
* @return Created NETCONF session object or NULL in case of error.
|
||||
*/
|
||||
struct nc_session *nc_connect_inout(int fdin, int fdout, struct ly_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Connect to the NETCONF server via unix socket.
|
||||
*
|
||||
* Connect to netconf server via an unix socket. Function do not cover authentication
|
||||
* or any other manipulation with the transport layer, it only establish NETCONF session
|
||||
* by sending and processing NETCONF \<hello\> messages.
|
||||
*
|
||||
* @param[in] address Path to the unix socket.
|
||||
* @param[in] ctx Optional parameter. If set, provides strict YANG context for the session
|
||||
* (ignoring what is actually supported by the server side). If not set,
|
||||
* YANG context is created for the session using \<get-schema\> (if supported
|
||||
* by the server side) or/and by searching for YANG schemas in the searchpath
|
||||
* (see nc_client_schema_searchpath()). In every case except not providing context
|
||||
* to connect to a server supporting \<get-schema\> it is possible that
|
||||
* the session context will not include all the models supported by the server.
|
||||
* @return Created NETCONF session object or NULL in case of error.
|
||||
*/
|
||||
struct nc_session *nc_connect_unix(const char *address, struct ly_ctx *ctx);
|
||||
|
||||
/** @} Client Session */
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
|
||||
/**
|
||||
* @defgroup client_ssh Client SSH
|
||||
* @ingroup client
|
||||
*
|
||||
* @brief Client-side settings for SSH connections.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set SSH authentication hostkey check (knownhosts) callback.
|
||||
*
|
||||
* Repetitive calling causes replacing of the previous callback and its private data. Caller is responsible for
|
||||
* freeing the private data when necessary (the private data can be obtained by
|
||||
* nc_client_ssh_get_auth_hostkey_check_clb()).
|
||||
*
|
||||
* @param[in] auth_hostkey_check Function to call, returns 0 on success, non-zero in error.
|
||||
* If NULL, the default callback is set.
|
||||
* @param[in] priv Optional private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_set_auth_hostkey_check_clb(int (*auth_hostkey_check)(const char *hostname, ssh_session session, void *priv),
|
||||
void *priv);
|
||||
|
||||
/**
|
||||
* @brief Get currently set SSH authentication hostkey check (knownhosts) callback and its private data previously set
|
||||
* by nc_client_ssh_set_auth_hostkey_check_clb().
|
||||
*
|
||||
* @param[out] auth_hostkey_check Currently set callback, NULL in case of the default callback.
|
||||
* @param[out] priv Currently set (optional) private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_get_auth_hostkey_check_clb(int (**auth_hostkey_check)(const char *hostname, ssh_session session, void *priv),
|
||||
void **priv);
|
||||
|
||||
/**
|
||||
* @brief Set SSH password authentication callback.
|
||||
*
|
||||
* Repetitive calling causes replacing of the previous callback and its private data. Caller is responsible for
|
||||
* freeing the private data when necessary (the private data can be obtained by
|
||||
* nc_client_ssh_get_auth_password_clb()).
|
||||
*
|
||||
* @param[in] auth_password Function to call, returns the password for username\@hostname.
|
||||
* If NULL, the default callback is set.
|
||||
* @param[in] priv Optional private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_set_auth_password_clb(char *(*auth_password)(const char *username, const char *hostname, void *priv),
|
||||
void *priv);
|
||||
|
||||
/**
|
||||
* @brief Get currently set SSH password authentication callback and its private data previously set
|
||||
* by nc_client_ssh_set_auth_password_clb().
|
||||
*
|
||||
* @param[out] auth_password Currently set callback, NULL in case of the default callback.
|
||||
* @param[out] priv Currently set (optional) private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_get_auth_password_clb(char *(**auth_password)(const char *username, const char *hostname, void *priv),
|
||||
void **priv);
|
||||
|
||||
/**
|
||||
* @brief Set SSH interactive authentication callback.
|
||||
*
|
||||
* Repetitive calling causes replacing of the previous callback and its private data. Caller is responsible for
|
||||
* freeing the private data when necessary (the private data can be obtained by
|
||||
* nc_client_ssh_get_auth_interactive_clb()).
|
||||
*
|
||||
* @param[in] auth_interactive Function to call for every question, returns the answer for
|
||||
* authentication name with instruction and echoing prompt.
|
||||
* If NULL, the default callback is set.
|
||||
* @param[in] priv Optional private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_set_auth_interactive_clb(char *(*auth_interactive)(const char *auth_name, const char *instruction,
|
||||
const char *prompt, int echo, void *priv),
|
||||
void *priv);
|
||||
|
||||
/**
|
||||
* @brief Get currently set SSH interactive authentication callback and its private data previously set
|
||||
* by nc_client_ssh_set_auth_interactive_clb().
|
||||
*
|
||||
* @param[out] auth_interactive Currently set callback, NULL in case of the default callback.
|
||||
* @param[out] priv Currently set (optional) private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_get_auth_interactive_clb(char *(**auth_interactive)(const char *auth_name, const char *instruction,
|
||||
const char *prompt, int echo, void *priv),
|
||||
void **priv);
|
||||
|
||||
/**
|
||||
* @brief Set SSH publickey authentication encrypted private key passphrase callback.
|
||||
*
|
||||
* Repetitive calling causes replacing of the previous callback and its private data. Caller is responsible for
|
||||
* freeing the private data when necessary (the private data can be obtained by
|
||||
* nc_client_ssh_get_auth_privkey_passphrase_clb()).
|
||||
*
|
||||
* @param[in] auth_privkey_passphrase Function to call for every question, returns
|
||||
* the passphrase for the specific private key.
|
||||
* @param[in] priv Optional private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_set_auth_privkey_passphrase_clb(char *(*auth_privkey_passphrase)(const char *privkey_path, void *priv),
|
||||
void *priv);
|
||||
|
||||
/**
|
||||
* @brief Get currently set SSH publickey authentication encrypted private key passphrase callback and its private data
|
||||
* previously set by nc_client_ssh_set_auth_privkey_passphrase_clb().
|
||||
*
|
||||
* @param[out] auth_privkey_passphrase Currently set callback, NULL in case of the default callback.
|
||||
* @param[out] priv Currently set (optional) private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_get_auth_privkey_passphrase_clb(char *(**auth_privkey_passphrase)(const char *privkey_path, void *priv),
|
||||
void **priv);
|
||||
|
||||
/**
|
||||
* @brief Add an SSH public and private key pair to be used for client authentication.
|
||||
*
|
||||
* Private key can be encrypted, the passphrase will be asked for before using it.
|
||||
*
|
||||
* @param[in] pub_key Path to the public key.
|
||||
* @param[in] priv_key Path to the private key.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_ssh_add_keypair(const char *pub_key, const char *priv_key);
|
||||
|
||||
/**
|
||||
* @brief Remove an SSH public and private key pair that was used for client authentication.
|
||||
*
|
||||
* @param[in] idx Index of the keypair starting with 0.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_ssh_del_keypair(int idx);
|
||||
|
||||
/**
|
||||
* @brief Get the number of public an private key pairs set to be used for client authentication.
|
||||
*
|
||||
* @return Keypair count.
|
||||
*/
|
||||
int nc_client_ssh_get_keypair_count(void);
|
||||
|
||||
/**
|
||||
* @brief Get a specific keypair set to be used for client authentication.
|
||||
*
|
||||
* @param[in] idx Index of the specific keypair.
|
||||
* @param[out] pub_key Path to the public key.
|
||||
* @param[out] priv_key Path to the private key.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_ssh_get_keypair(int idx, const char **pub_key, const char **priv_key);
|
||||
|
||||
/**
|
||||
* @brief Set SSH authentication method preference.
|
||||
*
|
||||
* The default preference is as follows:
|
||||
* - interactive authentication (3)
|
||||
* - password authentication (2)
|
||||
* - public key authentication (1)
|
||||
*
|
||||
* @param[in] auth_type Authentication method to modify the preference of.
|
||||
* @param[in] pref Preference of @p auth_type. Higher number increases priority, negative values disable the method.
|
||||
*/
|
||||
void nc_client_ssh_set_auth_pref(NC_SSH_AUTH_TYPE auth_type, int16_t pref);
|
||||
|
||||
/**
|
||||
* @brief Get SSH authentication method preference.
|
||||
*
|
||||
* @param[in] auth_type Authentication method to retrieve the prefrence of.
|
||||
* @return Preference of the @p auth_type.
|
||||
*/
|
||||
int16_t nc_client_ssh_get_auth_pref(NC_SSH_AUTH_TYPE auth_type);
|
||||
|
||||
/**
|
||||
* @brief Set client SSH username used for authentication.
|
||||
*
|
||||
* @param[in] username Username to use.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_ssh_set_username(const char *username);
|
||||
|
||||
/**
|
||||
* @brief Get client SSH username used for authentication.
|
||||
*
|
||||
* @return Username used.
|
||||
*/
|
||||
const char *nc_client_ssh_get_username(void);
|
||||
|
||||
/**
|
||||
* @brief Connect to the NETCONF server using SSH transport (via libssh).
|
||||
*
|
||||
* SSH session is created with default options. If the caller needs to use specific SSH session properties,
|
||||
* they are supposed to use nc_connect_libssh().
|
||||
*
|
||||
* @param[in] host Hostname or address (both Ipv4 and IPv6 are accepted) of the target server.
|
||||
* 'localhost' is used by default if NULL is specified.
|
||||
* @param[in] port Port number of the target server. Default value 830 is used if 0 is specified.
|
||||
* @param[in] ctx Optional parameter. If set, provides strict YANG context for the session
|
||||
* (ignoring what is actually supported by the server side). If not set,
|
||||
* YANG context is created for the session using \<get-schema\> (if supported
|
||||
* by the server side) or/and by searching for YANG schemas in the searchpath
|
||||
* (see nc_client_schema_searchpath()). In every case except not providing context
|
||||
* to connect to a server supporting \<get-schema\> it is possible that
|
||||
* the session context will not include all the models supported by the server.
|
||||
* @return Created NETCONF session object or NULL on error.
|
||||
*/
|
||||
struct nc_session *nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Connect to the NETCONF server using the provided SSH (libssh) session.
|
||||
*
|
||||
* SSH session can have any options set, they will not be modified. If no options were set,
|
||||
* host 'localhost', port 22, and the username detected from the EUID is used. If socket is
|
||||
* set and connected only the host and the username must be set/is detected. Or the @p ssh_session
|
||||
* can already be authenticated in which case it is used directly.
|
||||
*
|
||||
* @param[in] ssh_session libssh structure representing SSH session object. After passing it
|
||||
* to libnetconf2 this way, it is fully managed by it (including freeing!).
|
||||
* @param[in] ctx Optional parameter. If set, provides strict YANG context for the session
|
||||
* (ignoring what is actually supported by the server side). If not set,
|
||||
* YANG context is created for the session using \<get-schema\> (if supported
|
||||
* by the server side) or/and by searching for YANG schemas in the searchpath
|
||||
* (see nc_client_schema_searchpath()). In every case except not providing context
|
||||
* to connect to a server supporting \<get-schema\> it is possible that
|
||||
* the session context will not include all the models supported by the server.
|
||||
* @return Created NETCONF session object or NULL on error.
|
||||
*/
|
||||
struct nc_session *nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Create another NETCONF session on existing SSH session using separated SSH channel.
|
||||
*
|
||||
* @param[in] session Existing NETCONF session. The session has to be created on SSH transport layer using libssh -
|
||||
* it has to be created by nc_connect_ssh(), nc_connect_libssh() or nc_connect_ssh_channel().
|
||||
* @param[in] ctx Optional parameter. If set, provides strict YANG context for the session
|
||||
* (ignoring what is actually supported by the server side). If not set,
|
||||
* YANG context is created for the session using \<get-schema\> (if supported
|
||||
* by the server side) or/and by searching for YANG schemas in the searchpath
|
||||
* (see nc_client_schema_searchpath()). In every case except not providing context
|
||||
* to connect to a server supporting \<get-schema\> it is possible that
|
||||
* the session context will not include all the models supported by the server.
|
||||
* @return Created NETCONF session object or NULL on error.
|
||||
*/
|
||||
struct nc_session *nc_connect_ssh_channel(struct nc_session *session, struct ly_ctx *ctx);
|
||||
|
||||
/** @} Client SSH */
|
||||
|
||||
#endif /* NC_ENABLED_SSH */
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
|
||||
/**
|
||||
* @defgroup client_tls Client TLS
|
||||
* @ingroup client
|
||||
*
|
||||
* @brief Client-side settings for TLS connections.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set client authentication identity - a certificate and a private key.
|
||||
*
|
||||
* @param[in] client_cert Path to the file containing the client certificate.
|
||||
* @param[in] client_key Path to the file containing the private key for the @p client_cert.
|
||||
* If NULL, key is expected to be stored with @p client_cert.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_tls_set_cert_key_paths(const char *client_cert, const char *client_key);
|
||||
|
||||
/**
|
||||
* @brief Get client authentication identity - a certificate and a private key.
|
||||
*
|
||||
* @param[out] client_cert Path to the file containing the client certificate. Can be NULL.
|
||||
* @param[out] client_key Path to the file containing the private key for the @p client_cert. Can be NULL.
|
||||
*/
|
||||
void nc_client_tls_get_cert_key_paths(const char **client_cert, const char **client_key);
|
||||
|
||||
/**
|
||||
* @brief Set client trusted CA certificates paths.
|
||||
*
|
||||
* @param[in] ca_file Location of the CA certificate file used to verify server certificates.
|
||||
* For more info, see the documentation for SSL_CTX_load_verify_locations() from OpenSSL.
|
||||
* @param[in] ca_dir Location of the CA certificates directory used to verify the server certificates.
|
||||
* For more info, see the documentation for SSL_CTX_load_verify_locations() from OpenSSL.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_tls_set_trusted_ca_paths(const char *ca_file, const char *ca_dir);
|
||||
|
||||
/**
|
||||
* @brief Get client trusted CA certificates paths.
|
||||
*
|
||||
* @param[out] ca_file Location of the CA certificate file used to verify server certificates.
|
||||
* Can be NULL.
|
||||
* @param[out] ca_dir Location of the CA certificates directory used to verify the server certificates.
|
||||
* Can be NULL.
|
||||
*/
|
||||
void nc_client_tls_get_trusted_ca_paths(const char **ca_file, const char **ca_dir);
|
||||
|
||||
/**
|
||||
* @brief Set client Certificate Revocation List paths.
|
||||
*
|
||||
* @param[in] crl_file Location of the CRL certificate file used to check for revocated certificates.
|
||||
* @param[in] crl_dir Location of the CRL certificate directory used to check for revocated certificates.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_tls_set_crl_paths(const char *crl_file, const char *crl_dir);
|
||||
|
||||
/**
|
||||
* @brief Get client Certificate Revocation List paths.
|
||||
*
|
||||
* @param[out] crl_file Location of the CRL certificate file used to check for revocated certificates.
|
||||
* @param[out] crl_dir Location of the CRL certificate directory used to check for revocated certificates.
|
||||
*/
|
||||
void nc_client_tls_get_crl_paths(const char **crl_file, const char **crl_dir);
|
||||
|
||||
/**
|
||||
* @brief Connect to the NETCONF server using TLS transport (via libssl)
|
||||
*
|
||||
* TLS session is created with the certificates set using nc_client_tls_* functions, which must be called beforehand!
|
||||
* If the caller needs to use specific TLS session properties, they are supposed to use nc_connect_libssl().
|
||||
*
|
||||
* @param[in] host Hostname or address (both Ipv4 and IPv6 are accepted) of the target server.
|
||||
* 'localhost' is used by default if NULL is specified.
|
||||
* @param[in] port Port number of the target server. Default value 6513 is used if 0 is specified.
|
||||
* @param[in] ctx Optional parameter. If set, provides strict YANG context for the session
|
||||
* (ignoring what is actually supported by the server side). If not set,
|
||||
* YANG context is created for the session using \<get-schema\> (if supported
|
||||
* by the server side) or/and by searching for YANG schemas in the searchpath
|
||||
* (see nc_client_schema_searchpath()). In every case except not providing context
|
||||
* to connect to a server supporting \<get-schema\> it is possible that
|
||||
* the session context will not include all the models supported by the server.
|
||||
* @return Created NETCONF session object or NULL on error.
|
||||
*/
|
||||
struct nc_session *nc_connect_tls(const char *host, uint16_t port, struct ly_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Connect to the NETCONF server using the provided TLS (libssl) session.
|
||||
*
|
||||
* The TLS session supplied is expected to be fully connected and authenticated!
|
||||
*
|
||||
* @param[in] tls libssl structure representing the TLS session object.
|
||||
* @param[in] ctx Optional parameter. If set, provides strict YANG context for the session
|
||||
* (ignoring what is actually supported by the server side). If not set,
|
||||
* YANG context is created for the session using \<get-schema\> (if supported
|
||||
* by the server side) or/and by searching for YANG schemas in the searchpath
|
||||
* (see nc_client_schema_searchpath()). In every case except not providing context
|
||||
* to connect to a server supporting \<get-schema\> it is possible that
|
||||
* the session context will not include all the models supported by the server.
|
||||
* @return Created NETCONF session object or NULL on error.
|
||||
*/
|
||||
struct nc_session *nc_connect_libssl(SSL *tls, struct ly_ctx *ctx);
|
||||
|
||||
/** @} Client TLS */
|
||||
|
||||
#endif /* NC_ENABLED_TLS */
|
||||
|
||||
/**
|
||||
* @addtogroup client_session
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get session capabilities.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return NULL-terminated array of the @p session capabilities.
|
||||
*/
|
||||
const char * const *nc_session_get_cpblts(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Check capability presence in a session.
|
||||
*
|
||||
* @param[in] session Session to check.
|
||||
* @param[in] capab Capability to look for, capability with any additional suffix will match.
|
||||
* @return Matching capability, NULL if none found.
|
||||
*/
|
||||
const char *nc_session_cpblt(const struct nc_session *session, const char *capab);
|
||||
|
||||
/**
|
||||
* @brief Check whether the session has a notification thread running.
|
||||
*
|
||||
* @param[in] session Session to check.
|
||||
* @return 1 if notfication thread is running, 0 otherwise.
|
||||
*/
|
||||
int nc_session_ntf_thread_running(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Receive NETCONF RPC reply.
|
||||
*
|
||||
* @note This function can be called in a single thread only.
|
||||
*
|
||||
* @param[in] session NETCONF session from which the function gets data. It must be the
|
||||
* client side session object.
|
||||
* @param[in] rpc Original RPC this should be the reply to.
|
||||
* @param[in] msgid Expected message ID of the reply.
|
||||
* @param[in] timeout Timeout for reading in milliseconds. Use negative value for infinite
|
||||
* waiting and 0 for immediate return if data are not available on the wire.
|
||||
* @param[out] envp NETCONF rpc-reply XML envelopes.
|
||||
* @param[out] op Parsed NETCONF reply data, if any (none for \<ok\> or error replies). Set only on #NC_MSG_REPLY
|
||||
* and #NC_MSG_REPLY_ERR_MSGID return.
|
||||
* @return #NC_MSG_REPLY for success,
|
||||
* #NC_MSG_WOULDBLOCK if @p timeout has elapsed,
|
||||
* #NC_MSG_ERROR if reading has failed,
|
||||
* #NC_MSG_NOTIF if a notification was read instead (call this function again to get the reply), and
|
||||
* #NC_MSG_REPLY_ERR_MSGID if a reply with missing or wrong message-id was received.
|
||||
*/
|
||||
NC_MSG_TYPE nc_recv_reply(struct nc_session *session, struct nc_rpc *rpc, uint64_t msgid, int timeout,
|
||||
struct lyd_node **envp, struct lyd_node **op);
|
||||
|
||||
/**
|
||||
* @brief Receive NETCONF Notification.
|
||||
*
|
||||
* @param[in] session NETCONF session from which the function gets data. It must be the
|
||||
* client side session object.
|
||||
* @param[in] timeout Timeout for reading in milliseconds. Use negative value for infinite
|
||||
* waiting and 0 for immediate return if data are not available on the wire.
|
||||
* @param[out] envp NETCONF notification XML envelopes.
|
||||
* @param[out] op Parsed NETCONF notification data.
|
||||
* @return #NC_MSG_NOTIF for success,
|
||||
* #NC_MSG_WOULDBLOCK if @p timeout has elapsed,
|
||||
* #NC_MSG_ERROR if reading has failed, and
|
||||
* #NC_MSG_REPLY if a reply was read instead (call this function again to get a notification).
|
||||
*/
|
||||
NC_MSG_TYPE nc_recv_notif(struct nc_session *session, int timeout, struct lyd_node **envp, struct lyd_node **op);
|
||||
|
||||
/**
|
||||
* @brief Receive NETCONF Notifications in a separate thread until the session is terminated
|
||||
* or \<notificationComplete\> is received.
|
||||
*
|
||||
* @param[in] session Netconf session to read notifications from.
|
||||
* @param[in] notif_clb Function that is called for every received notification (including
|
||||
* \<notificationComplete\>). Parameters are the session the notification was received on
|
||||
* and the notification data.
|
||||
* @return 0 if the thread was successfully created, -1 on error.
|
||||
*/
|
||||
int nc_recv_notif_dispatch(struct nc_session *session,
|
||||
void (*notif_clb)(struct nc_session *session, const struct lyd_node *envp, const struct lyd_node *op));
|
||||
|
||||
/**
|
||||
* @brief Send NETCONF RPC message via the session.
|
||||
*
|
||||
* @param[in] session NETCONF session where the RPC will be written.
|
||||
* @param[in] rpc NETCONF RPC object to send via the specified session.
|
||||
* @param[in] timeout Timeout for writing in milliseconds. Use negative value for infinite
|
||||
* waiting and 0 for return if data cannot be sent immediately.
|
||||
* @param[out] msgid If RPC was successfully sent, this is it's message ID.
|
||||
* @return #NC_MSG_RPC on success,
|
||||
* #NC_MSG_WOULDBLOCK in case of a busy session, and
|
||||
* #NC_MSG_ERROR on error.
|
||||
*/
|
||||
NC_MSG_TYPE nc_send_rpc(struct nc_session *session, struct nc_rpc *rpc, int timeout, uint64_t *msgid);
|
||||
|
||||
/**
|
||||
* @brief Make a session not strict when sending RPCs and receiving RPC replies. In other words,
|
||||
* it will silently skip unknown nodes without an error.
|
||||
*
|
||||
* Generally, no such data should be worked with, so use this function only when you know what you
|
||||
* are doing and you understand the consequences.
|
||||
*
|
||||
* @param[in] session NETCONF client session.
|
||||
*/
|
||||
void nc_client_session_set_not_strict(struct nc_session *session);
|
||||
|
||||
/** @} Client Session */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NC_SESSION_CLIENT_H_ */
|
354
src/session_client_ch.h
Normal file
354
src/session_client_ch.h
Normal file
|
@ -0,0 +1,354 @@
|
|||
/**
|
||||
* @file session_client_ch.h
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 Call Home session client manipulation
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_SESSION_CLIENT_CH_H_
|
||||
#define NC_SESSION_CLIENT_CH_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
# include <libssh/libssh.h>
|
||||
#endif
|
||||
|
||||
#include "messages_client.h"
|
||||
#include "netconf.h"
|
||||
#include "session.h"
|
||||
|
||||
#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS)
|
||||
|
||||
/**
|
||||
* @defgroup client_ch Client-side Call Home
|
||||
* @ingroup client
|
||||
*
|
||||
* @brief Call Home functionality for client-side applications.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Accept a Call Home connection on any of the listening binds.
|
||||
*
|
||||
* @param[in] timeout Timeout for receiving a new connection in milliseconds, 0 for
|
||||
* non-blocking call, -1 for infinite waiting.
|
||||
* @param[in] ctx Session context to use. Can be NULL.
|
||||
* @param[out] session New session.
|
||||
* @return 1 on success, 0 on timeout, -1 on error.
|
||||
*/
|
||||
int nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **session);
|
||||
|
||||
/** @} Client-side Call Home */
|
||||
|
||||
#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
|
||||
/**
|
||||
* @defgroup client_ch_ssh Client-side Call Home on SSH
|
||||
* @ingroup client_ch
|
||||
*
|
||||
* @brief SSH settings for the Call Home functionality
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set SSH Call Home authentication hostkey check (knownhosts) callback.
|
||||
*
|
||||
* Repetitive calling causes replacing of the previous callback and its private data. Caller is responsible for
|
||||
* freeing the private data when necessary (the private data can be obtained by
|
||||
* nc_client_ssh_ch_get_auth_hostkey_check_clb()).
|
||||
*
|
||||
* @param[in] auth_hostkey_check Function to call, returns 0 on success, non-zero in error.
|
||||
* If NULL, the default callback is set.
|
||||
* @param[in] priv Optional private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_ch_set_auth_hostkey_check_clb(int (*auth_hostkey_check)(const char *hostname, ssh_session session, void *priv),
|
||||
void *priv);
|
||||
|
||||
/**
|
||||
* @brief Get currently set SSH Call Home authentication hostkey check (knownhosts) callback and its private data
|
||||
* previously set by nc_client_ssh_ch_set_auth_hostkey_check_clb().
|
||||
*
|
||||
* @param[out] auth_hostkey_check Currently set callback, NULL in case of the default callback.
|
||||
* @param[out] priv Currently set (optional) private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_ch_get_auth_hostkey_check_clb(int (**auth_hostkey_check)(const char *hostname, ssh_session session, void *priv),
|
||||
void **priv);
|
||||
/**
|
||||
* @brief Set SSH Call Home password authentication callback.
|
||||
*
|
||||
* Repetitive calling causes replacing of the previous callback and its private data. Caller is responsible for
|
||||
* freeing the private data when necessary (the private data can be obtained by
|
||||
* nc_client_ssh_ch_get_auth_password_clb()).
|
||||
*
|
||||
* @param[in] auth_password Function to call, returns the password for username\@hostname.
|
||||
* If NULL, the default callback is set.
|
||||
* @param[in] priv Optional private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_ch_set_auth_password_clb(char *(*auth_password)(const char *username, const char *hostname, void *priv),
|
||||
void *priv);
|
||||
|
||||
/**
|
||||
* @brief Get currently set SSH Call Home password authentication callback and its private data
|
||||
* previously set by nc_client_ssh_ch_set_auth_password_clb().
|
||||
*
|
||||
* @param[out] auth_password Currently set callback, NULL in case of the default callback.
|
||||
* @param[out] priv Currently set (optional) private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_ch_get_auth_password_clb(char *(**auth_password)(const char *username, const char *hostname, void *priv),
|
||||
void **priv);
|
||||
|
||||
/**
|
||||
* @brief Set SSH Call Home interactive authentication callback.
|
||||
*
|
||||
* Repetitive calling causes replacing of the previous callback and its private data. Caller is responsible for
|
||||
* freeing the private data when necessary (the private data can be obtained by
|
||||
* nc_client_ssh_ch_get_auth_interactive_clb()).
|
||||
*
|
||||
* @param[in] auth_interactive Function to call for every question, returns the answer for
|
||||
* authentication name with instruction and echoing prompt.
|
||||
* If NULL, the default callback is set.
|
||||
* @param[in] priv Optional private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_ch_set_auth_interactive_clb(char *(*auth_interactive)(const char *auth_name, const char *instruction,
|
||||
const char *prompt, int echo, void *priv),
|
||||
void *priv);
|
||||
|
||||
/**
|
||||
* @brief Get currently set SSH Call Home interactive authentication callback and its private data
|
||||
* previously set by nc_client_ssh_ch_set_auth_interactive_clb().
|
||||
*
|
||||
* @param[out] auth_interactive Currently set callback, NULL in case of the default callback.
|
||||
* @param[out] priv Currently set (optional) private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_ch_get_auth_interactive_clb(char *(**auth_interactive)(const char *auth_name, const char *instruction,
|
||||
const char *prompt, int echo, void *priv),
|
||||
void **priv);
|
||||
|
||||
/**
|
||||
* @brief Set SSH Call Home publickey authentication encrypted private key passphrase callback.
|
||||
*
|
||||
* Repetitive calling causes replacing of the previous callback and its private data. Caller is responsible for
|
||||
* freeing the private data when necessary (the private data can be obtained by
|
||||
* nc_client_ssh_ch_get_auth_privkey_passphrase_clb()).
|
||||
*
|
||||
* @param[in] auth_privkey_passphrase Function to call for every question, returns
|
||||
* the passphrase for the specific private key.
|
||||
* @param[in] priv Optional private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_ch_set_auth_privkey_passphrase_clb(char *(*auth_privkey_passphrase)(const char *privkey_path, void *priv),
|
||||
void *priv);
|
||||
|
||||
/**
|
||||
* @brief Get currently set SSH Call Home publickey authentication encrypted private key passphrase callback and its
|
||||
* private data previously set by nc_client_ssh_ch_set_auth_privkey_passphrase_clb().
|
||||
*
|
||||
* @param[out] auth_privkey_passphrase Currently set callback, NULL in case of the default callback.
|
||||
* @param[out] priv Currently set (optional) private data to be passed to the callback function.
|
||||
*/
|
||||
void nc_client_ssh_ch_get_auth_privkey_passphrase_clb(char *(**auth_privkey_passphrase)(const char *privkey_path, void *priv),
|
||||
void **priv);
|
||||
|
||||
/**
|
||||
* @brief Add a new client bind and start listening on it for SSH Call Home connections.
|
||||
*
|
||||
* @param[in] address IP address to bind to.
|
||||
* @param[in] port Port to bind to.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_ssh_ch_add_bind_listen(const char *address, uint16_t port);
|
||||
|
||||
/**
|
||||
* @brief Remove an SSH listening client bind.
|
||||
*
|
||||
* @param[in] address IP address the socket was bound to. NULL matches all.
|
||||
* @param[in] port Port the socket was bound to. 0 matches all.
|
||||
* @return 0 on success, -1 on not found.
|
||||
*/
|
||||
int nc_client_ssh_ch_del_bind(const char *address, uint16_t port);
|
||||
|
||||
/**
|
||||
* @brief Add an SSH public and private key pair to be used for Call Home client authentication.
|
||||
*
|
||||
* Private key can be encrypted, the passphrase will be asked for before using it.
|
||||
*
|
||||
* @param[in] pub_key Path to the public key.
|
||||
* @param[in] priv_key Path to the private key.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_ssh_ch_add_keypair(const char *pub_key, const char *priv_key);
|
||||
|
||||
/**
|
||||
* @brief Remove an SSH public and private key pair that was used for Call Home client authentication.
|
||||
*
|
||||
* @param[in] idx Index of the keypair starting with 0.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_ssh_ch_del_keypair(int idx);
|
||||
|
||||
/**
|
||||
* @brief Get the number of public an private key pairs set to be used for Call Home client authentication.
|
||||
*
|
||||
* @return Keypair count.
|
||||
*/
|
||||
int nc_client_ssh_ch_get_keypair_count(void);
|
||||
|
||||
/**
|
||||
* @brief Get a specific keypair set to be used for Call Home client authentication.
|
||||
*
|
||||
* @param[in] idx Index of the specific keypair.
|
||||
* @param[out] pub_key Path to the public key.
|
||||
* @param[out] priv_key Path to the private key.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_ssh_ch_get_keypair(int idx, const char **pub_key, const char **priv_key);
|
||||
|
||||
/**
|
||||
* @brief Set SSH Call Home authentication method preference.
|
||||
*
|
||||
* The default preference is as follows:
|
||||
* - public key authentication (3)
|
||||
* - password authentication (2)
|
||||
* - interactive authentication (1)
|
||||
*
|
||||
* @param[in] auth_type Authentication method to modify the preference of.
|
||||
* @param[in] pref Preference of @p auth_type. Higher number increases priority, negative values disable the method.
|
||||
*/
|
||||
void nc_client_ssh_ch_set_auth_pref(NC_SSH_AUTH_TYPE auth_type, int16_t pref);
|
||||
|
||||
/**
|
||||
* @brief Get SSH Call Home authentication method preference.
|
||||
*
|
||||
* @param[in] auth_type Authentication method to retrieve the prefrence of.
|
||||
* @return Preference of the @p auth_type.
|
||||
*/
|
||||
int16_t nc_client_ssh_ch_get_auth_pref(NC_SSH_AUTH_TYPE auth_type);
|
||||
|
||||
/**
|
||||
* @brief Set client Call Home SSH username used for authentication.
|
||||
*
|
||||
* @param[in] username Username to use.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_ssh_ch_set_username(const char *username);
|
||||
|
||||
/**
|
||||
* @brief Get client Call Home SSH username used for authentication.
|
||||
*
|
||||
* @return Username used.
|
||||
*/
|
||||
const char *nc_client_ssh_ch_get_username(void);
|
||||
|
||||
/** @} Client-side Call Home on SSH */
|
||||
|
||||
#endif /* NC_ENABLED_SSH */
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
|
||||
/**
|
||||
* @defgroup client_ch_tls Client-side Call Home on TLS
|
||||
* @ingroup client_ch
|
||||
*
|
||||
* @brief TLS settings for the Call Home functionality
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Add a new client bind and start listening on it for TLS Call Home connections.
|
||||
*
|
||||
* @param[in] address IP address to bind to.
|
||||
* @param[in] port Port to bind to.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_tls_ch_add_bind_listen(const char *address, uint16_t port);
|
||||
|
||||
/**
|
||||
* @brief Remove a TLS listening client bind.
|
||||
*
|
||||
* @param[in] address IP address the socket was bound to. NULL matches all.
|
||||
* @param[in] port Port the socket was bound to. 0 matches all.
|
||||
* @return 0 on success, -1 on not found.
|
||||
*/
|
||||
int nc_client_tls_ch_del_bind(const char *address, uint16_t port);
|
||||
|
||||
/**
|
||||
* @brief Set client Call Home authentication identity - a certificate and a private key.
|
||||
*
|
||||
* @param[in] client_cert Path to the file containing the client certificate.
|
||||
* @param[in] client_key Path to the file containing the private key for the @p client_cert.
|
||||
* If NULL, key is expected to be stored with @p client_cert.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_tls_ch_set_cert_key_paths(const char *client_cert, const char *client_key);
|
||||
|
||||
/**
|
||||
* @brief Get client Call Home authentication identity - a certificate and a private key.
|
||||
*
|
||||
* @param[out] client_cert Path to the file containing the client certificate. Can be NULL.
|
||||
* @param[out] client_key Path to the file containing the private key for the @p client_cert.
|
||||
* Can be NULL.
|
||||
*/
|
||||
void nc_client_tls_ch_get_cert_key_paths(const char **client_cert, const char **client_key);
|
||||
|
||||
/**
|
||||
* @brief Set client Call Home trusted CA certificates.
|
||||
*
|
||||
* @param[in] ca_file Location of the CA certificate file used to verify server certificates.
|
||||
* For more info, see the documentation for SSL_CTX_load_verify_locations() from OpenSSL.
|
||||
* @param[in] ca_dir Location of the CA certificates directory used to verify the server certificates.
|
||||
* For more info, see the documentation for SSL_CTX_load_verify_locations() from OpenSSL.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_tls_ch_set_trusted_ca_paths(const char *ca_file, const char *ca_dir);
|
||||
|
||||
/**
|
||||
* @brief Get client Call Home trusted CA certificates.
|
||||
*
|
||||
* @param[out] ca_file Location of the CA certificate file used to verify server certificates.
|
||||
* Can be NULL.
|
||||
* @param[out] ca_dir Location of the CA certificates directory used to verify the server certificates.
|
||||
* Can be NULL.
|
||||
*/
|
||||
void nc_client_tls_ch_get_trusted_ca_paths(const char **ca_file, const char **ca_dir);
|
||||
|
||||
/**
|
||||
* @brief Set client Call Home Certificate Revocation Lists.
|
||||
*
|
||||
* @param[in] crl_file Location of the CRL certificate file used to check for revocated certificates.
|
||||
* @param[in] crl_dir Location of the CRL certificate directory used to check for revocated certificates.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_tls_ch_set_crl_paths(const char *crl_file, const char *crl_dir);
|
||||
|
||||
/**
|
||||
* @brief Get client Call Home Certificate Revocation Lists.
|
||||
*
|
||||
* @param[out] crl_file Location of the CRL certificate file used to check for revocated certificates.
|
||||
* Can be NULL.
|
||||
* @param[out] crl_dir Location of the CRL certificate directory used to check for revocated certificates.
|
||||
* Can be NULL.
|
||||
*/
|
||||
void nc_client_tls_ch_get_crl_paths(const char **crl_file, const char **crl_dir);
|
||||
|
||||
/** @} Client-side Call Home on TLS */
|
||||
|
||||
#endif /* NC_ENABLED_TLS */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NC_SESSION_CLIENT_CH_H_ */
|
1911
src/session_client_ssh.c
Normal file
1911
src/session_client_ssh.c
Normal file
File diff suppressed because it is too large
Load diff
848
src/session_client_tls.c
Normal file
848
src/session_client_tls.c
Normal file
|
@ -0,0 +1,848 @@
|
|||
/**
|
||||
* \file session_client_tls.c
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \author Michal Vasko <mvasko@cesnet.cz>
|
||||
* \brief libnetconf2 - TLS specific session client transport functions
|
||||
*
|
||||
* This source is compiled only with libssl.
|
||||
*
|
||||
* Copyright (c) 2015 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include "libnetconf.h"
|
||||
#include "session_client.h"
|
||||
#include "session_client_ch.h"
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
#define X509_STORE_CTX_get_by_subject X509_STORE_get_by_subject
|
||||
#endif
|
||||
|
||||
struct nc_client_context *nc_client_context_location(void);
|
||||
int nc_session_new_ctx(struct nc_session *session, struct ly_ctx *ctx);
|
||||
|
||||
#define client_opts nc_client_context_location()->opts
|
||||
#define tls_opts nc_client_context_location()->tls_opts
|
||||
#define tls_ch_opts nc_client_context_location()->tls_ch_opts
|
||||
|
||||
static int tlsauth_ch;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0
|
||||
|
||||
static int
|
||||
tlsauth_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
{
|
||||
X509_STORE_CTX *store_ctx;
|
||||
X509_OBJECT *obj;
|
||||
X509_NAME *subject, *issuer;
|
||||
X509 *cert;
|
||||
X509_CRL *crl;
|
||||
X509_REVOKED *revoked;
|
||||
EVP_PKEY *pubkey;
|
||||
int i, n, rc;
|
||||
const ASN1_TIME *next_update = NULL;
|
||||
struct nc_client_tls_opts *opts;
|
||||
|
||||
if (!preverify_ok) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
opts = (tlsauth_ch ? &tls_ch_opts : &tls_opts);
|
||||
|
||||
if (!opts->crl_store) {
|
||||
/* nothing to check */
|
||||
return 1;
|
||||
}
|
||||
|
||||
cert = X509_STORE_CTX_get_current_cert(x509_ctx);
|
||||
subject = X509_get_subject_name(cert);
|
||||
issuer = X509_get_issuer_name(cert);
|
||||
|
||||
/* try to retrieve a CRL corresponding to the _subject_ of
|
||||
* the current certificate in order to verify it's integrity */
|
||||
store_ctx = X509_STORE_CTX_new();
|
||||
obj = X509_OBJECT_new();
|
||||
X509_STORE_CTX_init(store_ctx, opts->crl_store, NULL, NULL);
|
||||
rc = X509_STORE_CTX_get_by_subject(store_ctx, X509_LU_CRL, subject, obj);
|
||||
X509_STORE_CTX_free(store_ctx);
|
||||
crl = X509_OBJECT_get0_X509_CRL(obj);
|
||||
if ((rc > 0) && crl) {
|
||||
next_update = X509_CRL_get0_nextUpdate(crl);
|
||||
|
||||
/* verify the signature on this CRL */
|
||||
pubkey = X509_get_pubkey(cert);
|
||||
if (X509_CRL_verify(crl, pubkey) <= 0) {
|
||||
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
|
||||
X509_OBJECT_free(obj);
|
||||
if (pubkey) {
|
||||
EVP_PKEY_free(pubkey);
|
||||
}
|
||||
return 0; /* fail */
|
||||
}
|
||||
if (pubkey) {
|
||||
EVP_PKEY_free(pubkey);
|
||||
}
|
||||
|
||||
/* check date of CRL to make sure it's not expired */
|
||||
if (!next_update) {
|
||||
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
|
||||
X509_OBJECT_free(obj);
|
||||
return 0; /* fail */
|
||||
}
|
||||
if (X509_cmp_current_time(next_update) < 0) {
|
||||
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED);
|
||||
X509_OBJECT_free(obj);
|
||||
return 0; /* fail */
|
||||
}
|
||||
X509_OBJECT_free(obj);
|
||||
}
|
||||
|
||||
/* try to retrieve a CRL corresponding to the _issuer_ of
|
||||
* the current certificate in order to check for revocation */
|
||||
store_ctx = X509_STORE_CTX_new();
|
||||
obj = X509_OBJECT_new();
|
||||
X509_STORE_CTX_init(store_ctx, opts->crl_store, NULL, NULL);
|
||||
rc = X509_STORE_CTX_get_by_subject(store_ctx, X509_LU_CRL, issuer, obj);
|
||||
X509_STORE_CTX_free(store_ctx);
|
||||
crl = X509_OBJECT_get0_X509_CRL(obj);
|
||||
if ((rc > 0) && crl) {
|
||||
/* check if the current certificate is revoked by this CRL */
|
||||
n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
|
||||
for (i = 0; i < n; i++) {
|
||||
revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
|
||||
if (ASN1_INTEGER_cmp(X509_REVOKED_get0_serialNumber(revoked), X509_get_serialNumber(cert)) == 0) {
|
||||
ERR(NULL, "Certificate revoked!");
|
||||
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED);
|
||||
X509_OBJECT_free(obj);
|
||||
return 0; /* fail */
|
||||
}
|
||||
}
|
||||
X509_OBJECT_free(obj);
|
||||
}
|
||||
|
||||
return 1; /* success */
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
tlsauth_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
{
|
||||
X509_STORE_CTX store_ctx;
|
||||
X509_OBJECT obj;
|
||||
X509_NAME *subject, *issuer;
|
||||
X509 *cert;
|
||||
X509_CRL *crl;
|
||||
X509_REVOKED *revoked;
|
||||
EVP_PKEY *pubkey;
|
||||
int i, n, rc;
|
||||
ASN1_TIME *next_update = NULL;
|
||||
struct nc_client_tls_opts *opts;
|
||||
|
||||
if (!preverify_ok) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
opts = (tlsauth_ch ? &tls_ch_opts : &tls_opts);
|
||||
|
||||
if (!opts->crl_store) {
|
||||
/* nothing to check */
|
||||
return 1;
|
||||
}
|
||||
|
||||
cert = X509_STORE_CTX_get_current_cert(x509_ctx);
|
||||
subject = X509_get_subject_name(cert);
|
||||
issuer = X509_get_issuer_name(cert);
|
||||
|
||||
/* try to retrieve a CRL corresponding to the _subject_ of
|
||||
* the current certificate in order to verify it's integrity */
|
||||
memset((char *)&obj, 0, sizeof obj);
|
||||
X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL);
|
||||
rc = X509_STORE_CTX_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj);
|
||||
X509_STORE_CTX_cleanup(&store_ctx);
|
||||
crl = obj.data.crl;
|
||||
if ((rc > 0) && crl) {
|
||||
next_update = X509_CRL_get_nextUpdate(crl);
|
||||
|
||||
/* verify the signature on this CRL */
|
||||
pubkey = X509_get_pubkey(cert);
|
||||
if (X509_CRL_verify(crl, pubkey) <= 0) {
|
||||
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
|
||||
X509_OBJECT_free_contents(&obj);
|
||||
if (pubkey) {
|
||||
EVP_PKEY_free(pubkey);
|
||||
}
|
||||
return 0; /* fail */
|
||||
}
|
||||
if (pubkey) {
|
||||
EVP_PKEY_free(pubkey);
|
||||
}
|
||||
|
||||
/* check date of CRL to make sure it's not expired */
|
||||
if (!next_update) {
|
||||
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
|
||||
X509_OBJECT_free_contents(&obj);
|
||||
return 0; /* fail */
|
||||
}
|
||||
if (X509_cmp_current_time(next_update) < 0) {
|
||||
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED);
|
||||
X509_OBJECT_free_contents(&obj);
|
||||
return 0; /* fail */
|
||||
}
|
||||
X509_OBJECT_free_contents(&obj);
|
||||
}
|
||||
|
||||
/* try to retrieve a CRL corresponding to the _issuer_ of
|
||||
* the current certificate in order to check for revocation */
|
||||
memset((char *)&obj, 0, sizeof obj);
|
||||
X509_STORE_CTX_init(&store_ctx, opts->crl_store, NULL, NULL);
|
||||
rc = X509_STORE_CTX_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj);
|
||||
X509_STORE_CTX_cleanup(&store_ctx);
|
||||
crl = obj.data.crl;
|
||||
if ((rc > 0) && crl) {
|
||||
/* check if the current certificate is revoked by this CRL */
|
||||
n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
|
||||
for (i = 0; i < n; i++) {
|
||||
revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
|
||||
if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(cert)) == 0) {
|
||||
ERR(NULL, "Certificate revoked!");
|
||||
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED);
|
||||
X509_OBJECT_free_contents(&obj);
|
||||
return 0; /* fail */
|
||||
}
|
||||
}
|
||||
X509_OBJECT_free_contents(&obj);
|
||||
}
|
||||
|
||||
return 1; /* success */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
_nc_client_tls_destroy_opts(struct nc_client_tls_opts *opts)
|
||||
{
|
||||
free(opts->cert_path);
|
||||
free(opts->key_path);
|
||||
free(opts->ca_file);
|
||||
free(opts->ca_dir);
|
||||
SSL_CTX_free(opts->tls_ctx);
|
||||
|
||||
free(opts->crl_file);
|
||||
free(opts->crl_dir);
|
||||
X509_STORE_free(opts->crl_store);
|
||||
|
||||
memset(opts, 0, sizeof *opts);
|
||||
}
|
||||
|
||||
void
|
||||
nc_client_tls_destroy_opts(void)
|
||||
{
|
||||
_nc_client_tls_destroy_opts(&tls_opts);
|
||||
_nc_client_tls_destroy_opts(&tls_ch_opts);
|
||||
}
|
||||
|
||||
static int
|
||||
_nc_client_tls_set_cert_key_paths(const char *client_cert, const char *client_key, struct nc_client_tls_opts *opts)
|
||||
{
|
||||
if (!client_cert) {
|
||||
ERRARG("client_cert");
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(opts->cert_path);
|
||||
free(opts->key_path);
|
||||
|
||||
opts->cert_path = strdup(client_cert);
|
||||
if (!opts->cert_path) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (client_key) {
|
||||
opts->key_path = strdup(client_key);
|
||||
if (!opts->key_path) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
opts->key_path = NULL;
|
||||
}
|
||||
|
||||
opts->tls_ctx_change = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_client_tls_set_cert_key_paths(const char *client_cert, const char *client_key)
|
||||
{
|
||||
return _nc_client_tls_set_cert_key_paths(client_cert, client_key, &tls_opts);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_client_tls_ch_set_cert_key_paths(const char *client_cert, const char *client_key)
|
||||
{
|
||||
return _nc_client_tls_set_cert_key_paths(client_cert, client_key, &tls_ch_opts);
|
||||
}
|
||||
|
||||
static void
|
||||
_nc_client_tls_get_cert_key_paths(const char **client_cert, const char **client_key, struct nc_client_tls_opts *opts)
|
||||
{
|
||||
if (!client_cert && !client_key) {
|
||||
ERRARG("client_cert and client_key");
|
||||
return;
|
||||
}
|
||||
|
||||
if (client_cert) {
|
||||
*client_cert = opts->cert_path;
|
||||
}
|
||||
if (client_key) {
|
||||
*client_key = opts->key_path;
|
||||
}
|
||||
}
|
||||
|
||||
API void
|
||||
nc_client_tls_get_cert_key_paths(const char **client_cert, const char **client_key)
|
||||
{
|
||||
_nc_client_tls_get_cert_key_paths(client_cert, client_key, &tls_opts);
|
||||
}
|
||||
|
||||
API void
|
||||
nc_client_tls_ch_get_cert_key_paths(const char **client_cert, const char **client_key)
|
||||
{
|
||||
_nc_client_tls_get_cert_key_paths(client_cert, client_key, &tls_ch_opts);
|
||||
}
|
||||
|
||||
static int
|
||||
_nc_client_tls_set_trusted_ca_paths(const char *ca_file, const char *ca_dir, struct nc_client_tls_opts *opts)
|
||||
{
|
||||
if (!ca_file && !ca_dir) {
|
||||
ERRARG("ca_file and ca_dir");
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(opts->ca_file);
|
||||
free(opts->ca_dir);
|
||||
|
||||
if (ca_file) {
|
||||
opts->ca_file = strdup(ca_file);
|
||||
if (!opts->ca_file) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
opts->ca_file = NULL;
|
||||
}
|
||||
|
||||
if (ca_dir) {
|
||||
opts->ca_dir = strdup(ca_dir);
|
||||
if (!opts->ca_dir) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
opts->ca_dir = NULL;
|
||||
}
|
||||
|
||||
opts->tls_ctx_change = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_client_tls_set_trusted_ca_paths(const char *ca_file, const char *ca_dir)
|
||||
{
|
||||
return _nc_client_tls_set_trusted_ca_paths(ca_file, ca_dir, &tls_opts);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_client_tls_ch_set_trusted_ca_paths(const char *ca_file, const char *ca_dir)
|
||||
{
|
||||
return _nc_client_tls_set_trusted_ca_paths(ca_file, ca_dir, &tls_ch_opts);
|
||||
}
|
||||
|
||||
static void
|
||||
_nc_client_tls_get_trusted_ca_paths(const char **ca_file, const char **ca_dir, struct nc_client_tls_opts *opts)
|
||||
{
|
||||
if (!ca_file && !ca_dir) {
|
||||
ERRARG("ca_file and ca_dir");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ca_file) {
|
||||
*ca_file = opts->ca_file;
|
||||
}
|
||||
if (ca_dir) {
|
||||
*ca_dir = opts->ca_dir;
|
||||
}
|
||||
}
|
||||
|
||||
API void
|
||||
nc_client_tls_get_trusted_ca_paths(const char **ca_file, const char **ca_dir)
|
||||
{
|
||||
_nc_client_tls_get_trusted_ca_paths(ca_file, ca_dir, &tls_opts);
|
||||
}
|
||||
|
||||
API void
|
||||
nc_client_tls_ch_get_trusted_ca_paths(const char **ca_file, const char **ca_dir)
|
||||
{
|
||||
_nc_client_tls_get_trusted_ca_paths(ca_file, ca_dir, &tls_ch_opts);
|
||||
}
|
||||
|
||||
static int
|
||||
_nc_client_tls_set_crl_paths(const char *crl_file, const char *crl_dir, struct nc_client_tls_opts *opts)
|
||||
{
|
||||
if (!crl_file && !crl_dir) {
|
||||
ERRARG("crl_file and crl_dir");
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(opts->crl_file);
|
||||
free(opts->crl_dir);
|
||||
|
||||
if (crl_file) {
|
||||
opts->crl_file = strdup(crl_file);
|
||||
if (!opts->crl_file) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
opts->crl_file = NULL;
|
||||
}
|
||||
|
||||
if (crl_dir) {
|
||||
opts->crl_dir = strdup(crl_dir);
|
||||
if (!opts->crl_dir) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
opts->crl_dir = NULL;
|
||||
}
|
||||
|
||||
opts->crl_store_change = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_client_tls_set_crl_paths(const char *crl_file, const char *crl_dir)
|
||||
{
|
||||
return _nc_client_tls_set_crl_paths(crl_file, crl_dir, &tls_opts);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_client_tls_ch_set_crl_paths(const char *crl_file, const char *crl_dir)
|
||||
{
|
||||
return _nc_client_tls_set_crl_paths(crl_file, crl_dir, &tls_ch_opts);
|
||||
}
|
||||
|
||||
static void
|
||||
_nc_client_tls_get_crl_paths(const char **crl_file, const char **crl_dir, struct nc_client_tls_opts *opts)
|
||||
{
|
||||
if (!crl_file && !crl_dir) {
|
||||
ERRARG("crl_file and crl_dir");
|
||||
return;
|
||||
}
|
||||
|
||||
if (crl_file) {
|
||||
*crl_file = opts->crl_file;
|
||||
}
|
||||
if (crl_dir) {
|
||||
*crl_dir = opts->crl_dir;
|
||||
}
|
||||
}
|
||||
|
||||
API void
|
||||
nc_client_tls_get_crl_paths(const char **crl_file, const char **crl_dir)
|
||||
{
|
||||
_nc_client_tls_get_crl_paths(crl_file, crl_dir, &tls_opts);
|
||||
}
|
||||
|
||||
API void
|
||||
nc_client_tls_ch_get_crl_paths(const char **crl_file, const char **crl_dir)
|
||||
{
|
||||
_nc_client_tls_get_crl_paths(crl_file, crl_dir, &tls_ch_opts);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_client_tls_ch_add_bind_listen(const char *address, uint16_t port)
|
||||
{
|
||||
return nc_client_ch_add_bind_listen(address, port, NC_TI_OPENSSL);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_client_tls_ch_del_bind(const char *address, uint16_t port)
|
||||
{
|
||||
return nc_client_ch_del_bind(address, port, NC_TI_OPENSSL);
|
||||
}
|
||||
|
||||
static int
|
||||
nc_client_tls_update_opts(struct nc_client_tls_opts *opts)
|
||||
{
|
||||
char *key;
|
||||
X509_LOOKUP *lookup;
|
||||
|
||||
if (!opts->tls_ctx || opts->tls_ctx_change) {
|
||||
SSL_CTX_free(opts->tls_ctx);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0
|
||||
/* prepare global SSL context, highest available method is negotiated autmatically */
|
||||
if (!(opts->tls_ctx = SSL_CTX_new(TLS_client_method())))
|
||||
#else
|
||||
/* prepare global SSL context, allow only mandatory TLS 1.2 */
|
||||
if (!(opts->tls_ctx = SSL_CTX_new(TLSv1_2_client_method())))
|
||||
#endif
|
||||
{
|
||||
ERR(NULL, "Unable to create OpenSSL context (%s).", ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
SSL_CTX_set_verify(opts->tls_ctx, SSL_VERIFY_PEER, tlsauth_verify_callback);
|
||||
|
||||
/* get peer certificate */
|
||||
if (SSL_CTX_use_certificate_file(opts->tls_ctx, opts->cert_path, SSL_FILETYPE_PEM) != 1) {
|
||||
ERR(NULL, "Loading the client certificate from \'%s\' failed (%s).", opts->cert_path,
|
||||
ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if the file with private key not specified, expect that the private key is stored with the certificate */
|
||||
if (!opts->key_path) {
|
||||
key = opts->cert_path;
|
||||
} else {
|
||||
key = opts->key_path;
|
||||
}
|
||||
if (SSL_CTX_use_PrivateKey_file(opts->tls_ctx, key, SSL_FILETYPE_PEM) != 1) {
|
||||
ERR(NULL, "Loading the client priavte key from \'%s\' failed (%s).", key,
|
||||
ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!SSL_CTX_load_verify_locations(opts->tls_ctx, opts->ca_file, opts->ca_dir)) {
|
||||
ERR(NULL, "Failed to load the locations of trusted CA certificates (%s).",
|
||||
ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->crl_store_change || (!opts->crl_store && (opts->crl_file || opts->crl_dir))) {
|
||||
/* set the revocation store with the correct paths for the callback */
|
||||
X509_STORE_free(opts->crl_store);
|
||||
|
||||
opts->crl_store = X509_STORE_new();
|
||||
if (!opts->crl_store) {
|
||||
ERR(NULL, "Unable to create a certificate store (%s).", ERR_reason_error_string(ERR_get_error()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L // < 1.1.0
|
||||
/* whaveter this does... */
|
||||
opts->crl_store->cache = 0;
|
||||
#endif
|
||||
|
||||
if (opts->crl_file) {
|
||||
if (!(lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_file()))) {
|
||||
ERR(NULL, "Failed to add lookup method to CRL checking.");
|
||||
return -1;
|
||||
}
|
||||
if (X509_LOOKUP_add_dir(lookup, opts->crl_file, X509_FILETYPE_PEM) != 1) {
|
||||
ERR(NULL, "Failed to add the revocation lookup file \"%s\".", opts->crl_file);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->crl_dir) {
|
||||
if (!(lookup = X509_STORE_add_lookup(opts->crl_store, X509_LOOKUP_hash_dir()))) {
|
||||
ERR(NULL, "Failed to add lookup method to CRL checking.");
|
||||
return -1;
|
||||
}
|
||||
if (X509_LOOKUP_add_dir(lookup, opts->crl_dir, X509_FILETYPE_PEM) != 1) {
|
||||
ERR(NULL, "Failed to add the revocation lookup directory \"%s\".", opts->crl_dir);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
API struct nc_session *
|
||||
nc_connect_tls(const char *host, unsigned short port, struct ly_ctx *ctx)
|
||||
{
|
||||
struct nc_session *session = NULL;
|
||||
int sock, verify, ret;
|
||||
unsigned long tls_err;
|
||||
struct timespec ts_timeout, ts_cur;
|
||||
const char *peername;
|
||||
char *ip_host = NULL;
|
||||
|
||||
if (!tls_opts.cert_path || (!tls_opts.ca_file && !tls_opts.ca_dir)) {
|
||||
ERRINIT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* process parameters */
|
||||
if (!host || strisempty(host)) {
|
||||
host = "localhost";
|
||||
}
|
||||
|
||||
if (!port) {
|
||||
port = NC_PORT_TLS;
|
||||
}
|
||||
|
||||
/* create/update TLS structures */
|
||||
if (nc_client_tls_update_opts(&tls_opts)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* prepare session structure */
|
||||
session = nc_new_session(NC_CLIENT, 0);
|
||||
if (!session) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
session->status = NC_STATUS_STARTING;
|
||||
|
||||
/* fill the session */
|
||||
session->ti_type = NC_TI_OPENSSL;
|
||||
if (!(session->ti.tls = SSL_new(tls_opts.tls_ctx))) {
|
||||
ERR(NULL, "Failed to create a new TLS session structure (%s).", ERR_reason_error_string(ERR_get_error()));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* create and assign socket */
|
||||
sock = nc_sock_connect(host, port, -1, &client_opts.ka, NULL, &ip_host);
|
||||
if (sock == -1) {
|
||||
ERR(NULL, "Unable to connect to %s:%u (%s).", host, port, strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
SSL_set_fd(session->ti.tls, sock);
|
||||
|
||||
/* set the SSL_MODE_AUTO_RETRY flag to allow OpenSSL perform re-handshake automatically */
|
||||
SSL_set_mode(session->ti.tls, SSL_MODE_AUTO_RETRY);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0
|
||||
/* server identity (hostname) verification */
|
||||
if (!SSL_set1_host(session->ti.tls, host)) {
|
||||
ERR(NULL, "Failed to set expected server hostname.");
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* connect and perform the handshake */
|
||||
nc_gettimespec_mono(&ts_timeout);
|
||||
nc_addtimespec(&ts_timeout, NC_TRANSPORT_TIMEOUT);
|
||||
tlsauth_ch = 0;
|
||||
while (((ret = SSL_connect(session->ti.tls)) != 1) && (SSL_get_error(session->ti.tls, ret) == SSL_ERROR_WANT_READ)) {
|
||||
usleep(NC_TIMEOUT_STEP);
|
||||
nc_gettimespec_mono(&ts_cur);
|
||||
if (nc_difftimespec(&ts_cur, &ts_timeout) < 1) {
|
||||
ERR(NULL, "SSL_connect timeout.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (ret != 1) {
|
||||
switch (SSL_get_error(session->ti.tls, ret)) {
|
||||
case SSL_ERROR_SYSCALL:
|
||||
ERR(NULL, "SSL_connect failed (%s).", errno ? strerror(errno) : "unexpected EOF");
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
tls_err = ERR_get_error();
|
||||
ERR(NULL, "SSL_connect failed (%s).", ERR_reason_error_string(tls_err));
|
||||
break;
|
||||
default:
|
||||
ERR(NULL, "SSL_connect failed.");
|
||||
break;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* check certificate verification result */
|
||||
verify = SSL_get_verify_result(session->ti.tls);
|
||||
switch (verify) {
|
||||
case X509_V_OK:
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L // >= 1.1.0
|
||||
peername = SSL_get0_peername(session->ti.tls);
|
||||
VRB(NULL, "Server certificate successfully verified (domain \"%s\").", peername ? peername : "<unknown>");
|
||||
#else
|
||||
(void)peername;
|
||||
VRB(NULL, "Server certificate successfully verified.");
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
WRN(NULL, "Server certificate verification problem (%s).", X509_verify_cert_error_string(verify));
|
||||
}
|
||||
|
||||
if (nc_session_new_ctx(session, ctx) != EXIT_SUCCESS) {
|
||||
goto fail;
|
||||
}
|
||||
ctx = session->ctx;
|
||||
|
||||
/* NETCONF handshake */
|
||||
if (nc_handshake_io(session) != NC_MSG_HELLO) {
|
||||
goto fail;
|
||||
}
|
||||
session->status = NC_STATUS_RUNNING;
|
||||
|
||||
if (nc_ctx_check_and_fill(session) == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* store information into session and the dictionary */
|
||||
lydict_insert_zc(ctx, ip_host, &session->host);
|
||||
session->port = port;
|
||||
lydict_insert(ctx, "certificate-based", 0, &session->username);
|
||||
|
||||
return session;
|
||||
|
||||
fail:
|
||||
free(ip_host);
|
||||
nc_session_free(session, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
API struct nc_session *
|
||||
nc_connect_libssl(SSL *tls, struct ly_ctx *ctx)
|
||||
{
|
||||
struct nc_session *session;
|
||||
|
||||
if (!tls) {
|
||||
ERRARG("tls");
|
||||
return NULL;
|
||||
} else if (!SSL_is_init_finished(tls)) {
|
||||
ERR(NULL, "Supplied TLS session is not fully connected!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* prepare session structure */
|
||||
session = nc_new_session(NC_CLIENT, 0);
|
||||
if (!session) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
session->status = NC_STATUS_STARTING;
|
||||
session->ti_type = NC_TI_OPENSSL;
|
||||
session->ti.tls = tls;
|
||||
|
||||
if (nc_session_new_ctx(session, ctx) != EXIT_SUCCESS) {
|
||||
goto fail;
|
||||
}
|
||||
ctx = session->ctx;
|
||||
|
||||
/* NETCONF handshake */
|
||||
if (nc_handshake_io(session) != NC_MSG_HELLO) {
|
||||
goto fail;
|
||||
}
|
||||
session->status = NC_STATUS_RUNNING;
|
||||
|
||||
if (nc_ctx_check_and_fill(session) == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return session;
|
||||
|
||||
fail:
|
||||
session->ti.tls = NULL;
|
||||
nc_session_free(session, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nc_session *
|
||||
nc_accept_callhome_tls_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx, int timeout)
|
||||
{
|
||||
int verify, ret;
|
||||
SSL *tls = NULL;
|
||||
struct nc_session *session = NULL;
|
||||
struct timespec ts_timeout, ts_cur;
|
||||
|
||||
if (nc_client_tls_update_opts(&tls_ch_opts)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!(tls = SSL_new(tls_ch_opts.tls_ctx))) {
|
||||
ERR(NULL, "Failed to create new TLS session structure (%s).", ERR_reason_error_string(ERR_get_error()));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
SSL_set_fd(tls, sock);
|
||||
|
||||
/* set the SSL_MODE_AUTO_RETRY flag to allow OpenSSL perform re-handshake automatically */
|
||||
SSL_set_mode(tls, SSL_MODE_AUTO_RETRY);
|
||||
|
||||
/* connect and perform the handshake */
|
||||
if (timeout > -1) {
|
||||
nc_gettimespec_mono(&ts_timeout);
|
||||
nc_addtimespec(&ts_timeout, timeout);
|
||||
}
|
||||
tlsauth_ch = 1;
|
||||
while (((ret = SSL_connect(tls)) == -1) && (SSL_get_error(tls, ret) == SSL_ERROR_WANT_READ)) {
|
||||
usleep(NC_TIMEOUT_STEP);
|
||||
if (timeout > -1) {
|
||||
nc_gettimespec_mono(&ts_cur);
|
||||
if (nc_difftimespec(&ts_cur, &ts_timeout) < 1) {
|
||||
ERR(NULL, "SSL_connect timeout.");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret != 1) {
|
||||
switch (SSL_get_error(tls, ret)) {
|
||||
case SSL_ERROR_SYSCALL:
|
||||
ERR(NULL, "SSL_connect failed (%s).", strerror(errno));
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
ERR(NULL, "SSL_connect failed (%s).", ERR_reason_error_string(ERR_get_error()));
|
||||
break;
|
||||
default:
|
||||
ERR(NULL, "SSL_connect failed.");
|
||||
break;
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* check certificate verification result */
|
||||
verify = SSL_get_verify_result(tls);
|
||||
switch (verify) {
|
||||
case X509_V_OK:
|
||||
VRB(NULL, "Server certificate successfully verified.");
|
||||
break;
|
||||
default:
|
||||
WRN(NULL, "Server certificate verification problem (%s).", X509_verify_cert_error_string(verify));
|
||||
}
|
||||
|
||||
/* connect */
|
||||
session = nc_connect_libssl(tls, ctx);
|
||||
if (!session) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
session->flags |= NC_SESSION_CALLHOME;
|
||||
|
||||
/* store information into session and the dictionary */
|
||||
lydict_insert(session->ctx, host, 0, &session->host);
|
||||
session->port = port;
|
||||
lydict_insert(session->ctx, "certificate-based", 0, &session->username);
|
||||
|
||||
cleanup:
|
||||
if (!session) {
|
||||
SSL_free(tls);
|
||||
close(sock);
|
||||
}
|
||||
return session;
|
||||
}
|
861
src/session_p.h
Normal file
861
src/session_p.h
Normal file
|
@ -0,0 +1,861 @@
|
|||
/**
|
||||
* @file session_p.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 session manipulation
|
||||
*
|
||||
* Copyright (c) 2017 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_SESSION_PRIVATE_H_
|
||||
#define NC_SESSION_PRIVATE_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "libnetconf.h"
|
||||
#include "messages_client.h"
|
||||
#include "netconf.h"
|
||||
#include "session.h"
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
|
||||
# include <libssh/callbacks.h>
|
||||
# include <libssh/libssh.h>
|
||||
# include <libssh/server.h>
|
||||
|
||||
/* seconds */
|
||||
# define NC_SSH_TIMEOUT 10
|
||||
/* number of all supported authentication methods */
|
||||
# define NC_SSH_AUTH_COUNT 3
|
||||
|
||||
/* ACCESS unlocked */
|
||||
struct nc_client_ssh_opts {
|
||||
/* SSH authentication method preferences */
|
||||
struct {
|
||||
NC_SSH_AUTH_TYPE type;
|
||||
int16_t value;
|
||||
} auth_pref[NC_SSH_AUTH_COUNT];
|
||||
|
||||
/* SSH key pairs */
|
||||
struct {
|
||||
char *pubkey_path;
|
||||
char *privkey_path;
|
||||
int8_t privkey_crypt;
|
||||
} *keys;
|
||||
uint16_t key_count;
|
||||
|
||||
/* SSH authentication callbacks */
|
||||
int (*auth_hostkey_check)(const char *, ssh_session, void *);
|
||||
char *(*auth_password)(const char *, const char *, void *);
|
||||
char *(*auth_interactive)(const char *, const char *, const char *, int, void *);
|
||||
char *(*auth_privkey_passphrase)(const char *, void *);
|
||||
|
||||
/* private data for the callbacks */
|
||||
void *auth_hostkey_check_priv;
|
||||
void *auth_password_priv;
|
||||
void *auth_interactive_priv;
|
||||
void *auth_privkey_passphrase_priv;
|
||||
|
||||
char *username;
|
||||
};
|
||||
|
||||
/* ACCESS locked, separate locks */
|
||||
struct nc_server_ssh_opts {
|
||||
/* SSH bind options */
|
||||
const char **hostkeys;
|
||||
uint8_t hostkey_count;
|
||||
|
||||
int auth_methods;
|
||||
uint16_t auth_attempts;
|
||||
uint16_t auth_timeout;
|
||||
};
|
||||
|
||||
#endif /* NC_ENABLED_SSH */
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
|
||||
# include <openssl/bio.h>
|
||||
# include <openssl/ssl.h>
|
||||
|
||||
/* ACCESS unlocked */
|
||||
struct nc_client_tls_opts {
|
||||
char *cert_path;
|
||||
char *key_path;
|
||||
char *ca_file;
|
||||
char *ca_dir;
|
||||
int8_t tls_ctx_change;
|
||||
SSL_CTX *tls_ctx;
|
||||
|
||||
char *crl_file;
|
||||
char *crl_dir;
|
||||
int8_t crl_store_change;
|
||||
X509_STORE *crl_store;
|
||||
};
|
||||
|
||||
/* ACCESS locked, separate locks */
|
||||
struct nc_server_tls_opts {
|
||||
const char *server_cert;
|
||||
const char **trusted_cert_lists;
|
||||
uint16_t trusted_cert_list_count;
|
||||
const char *trusted_ca_file;
|
||||
const char *trusted_ca_dir;
|
||||
X509_STORE *crl_store;
|
||||
|
||||
struct nc_ctn {
|
||||
uint32_t id;
|
||||
const char *fingerprint;
|
||||
NC_TLS_CTN_MAPTYPE map_type;
|
||||
const char *name;
|
||||
struct nc_ctn *next;
|
||||
} *ctn;
|
||||
};
|
||||
|
||||
#endif /* NC_ENABLED_TLS */
|
||||
|
||||
/* ACCESS unlocked */
|
||||
struct nc_keepalives {
|
||||
int enabled;
|
||||
uint16_t idle_time;
|
||||
uint16_t max_probes;
|
||||
uint16_t probe_interval;
|
||||
};
|
||||
|
||||
/* ACCESS unlocked */
|
||||
struct nc_server_unix_opts {
|
||||
mode_t mode;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
};
|
||||
|
||||
/* ACCESS unlocked */
|
||||
struct nc_client_opts {
|
||||
char *schema_searchpath;
|
||||
ly_module_imp_clb schema_clb;
|
||||
void *schema_clb_data;
|
||||
struct nc_keepalives ka;
|
||||
|
||||
struct nc_bind {
|
||||
const char *address;
|
||||
uint16_t port;
|
||||
int sock;
|
||||
int pollin;
|
||||
} *ch_binds;
|
||||
NC_TRANSPORT_IMPL *ch_bind_ti;
|
||||
uint16_t ch_bind_count;
|
||||
};
|
||||
|
||||
/* ACCESS unlocked */
|
||||
struct nc_client_context {
|
||||
unsigned int refcount;
|
||||
struct nc_client_opts opts;
|
||||
#ifdef NC_ENABLED_SSH
|
||||
struct nc_client_ssh_opts ssh_opts;
|
||||
struct nc_client_ssh_opts ssh_ch_opts;
|
||||
#endif /* NC_ENABLED_SSH */
|
||||
#ifdef NC_ENABLED_TLS
|
||||
struct nc_client_tls_opts tls_opts;
|
||||
struct nc_client_tls_opts tls_ch_opts;
|
||||
#endif /* NC_ENABLED_TLS */
|
||||
};
|
||||
|
||||
struct nc_server_opts {
|
||||
/* ACCESS unlocked (dictionary locked internally in libyang) */
|
||||
struct ly_ctx *ctx;
|
||||
|
||||
/* ACCESS unlocked */
|
||||
NC_WD_MODE wd_basic_mode;
|
||||
int wd_also_supported;
|
||||
uint32_t capabilities_count;
|
||||
const char **capabilities;
|
||||
char *(*content_id_clb)(void *user_data);
|
||||
void *content_id_data;
|
||||
void (*content_id_data_free)(void *data);
|
||||
|
||||
/* ACCESS unlocked */
|
||||
uint16_t hello_timeout;
|
||||
uint16_t idle_timeout;
|
||||
#ifdef NC_ENABLED_SSH
|
||||
int (*passwd_auth_clb)(const struct nc_session *session, const char *password, void *user_data);
|
||||
void *passwd_auth_data;
|
||||
void (*passwd_auth_data_free)(void *data);
|
||||
|
||||
int (*pubkey_auth_clb)(const struct nc_session *session, ssh_key key, void *user_data);
|
||||
void *pubkey_auth_data;
|
||||
void (*pubkey_auth_data_free)(void *data);
|
||||
|
||||
int (*interactive_auth_clb)(const struct nc_session *session, ssh_message msg, void *user_data);
|
||||
void *interactive_auth_data;
|
||||
void (*interactive_auth_data_free)(void *data);
|
||||
#endif
|
||||
#ifdef NC_ENABLED_TLS
|
||||
int (*user_verify_clb)(const struct nc_session *session);
|
||||
|
||||
int (*server_cert_clb)(const char *name, void *user_data, char **cert_path, char **cert_data, char **privkey_path,
|
||||
char **privkey_data, NC_SSH_KEY_TYPE *privkey_type);
|
||||
void *server_cert_data;
|
||||
void (*server_cert_data_free)(void *data);
|
||||
|
||||
int (*server_cert_chain_clb)(const char *name, void *user_data, char ***cert_paths, int *cert_path_count,
|
||||
char ***cert_data, int *cert_data_count);
|
||||
void *server_cert_chain_data;
|
||||
void (*server_cert_chain_data_free)(void *data);
|
||||
|
||||
int (*trusted_cert_list_clb)(const char *name, void *user_data, char ***cert_paths, int *cert_path_count,
|
||||
char ***cert_data, int *cert_data_count);
|
||||
void *trusted_cert_list_data;
|
||||
void (*trusted_cert_list_data_free)(void *data);
|
||||
#endif
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
/* ACCESS locked with authkey_lock */
|
||||
struct {
|
||||
const char *path;
|
||||
const char *base64;
|
||||
NC_SSH_KEY_TYPE type;
|
||||
const char *username;
|
||||
} *authkeys;
|
||||
uint16_t authkey_count;
|
||||
pthread_mutex_t authkey_lock;
|
||||
|
||||
int (*hostkey_clb)(const char *name, void *user_data, char **privkey_path, char **privkey_data, NC_SSH_KEY_TYPE *privkey_type);
|
||||
void *hostkey_data;
|
||||
void (*hostkey_data_free)(void *data);
|
||||
#endif
|
||||
|
||||
/* ACCESS locked, add/remove endpts/binds - bind_lock + WRITE endpt_lock (strict order!)
|
||||
* modify endpts - WRITE endpt_lock
|
||||
* access endpts - READ endpt_lock
|
||||
* modify/poll binds - bind_lock */
|
||||
struct nc_bind *binds;
|
||||
pthread_mutex_t bind_lock;
|
||||
struct nc_endpt {
|
||||
const char *name;
|
||||
NC_TRANSPORT_IMPL ti;
|
||||
struct nc_keepalives ka;
|
||||
union {
|
||||
#ifdef NC_ENABLED_SSH
|
||||
struct nc_server_ssh_opts *ssh;
|
||||
#endif
|
||||
#ifdef NC_ENABLED_TLS
|
||||
struct nc_server_tls_opts *tls;
|
||||
#endif
|
||||
struct nc_server_unix_opts *unixsock;
|
||||
} opts;
|
||||
} *endpts;
|
||||
uint16_t endpt_count;
|
||||
pthread_rwlock_t endpt_lock;
|
||||
|
||||
/* ACCESS locked, add/remove CH clients - WRITE lock ch_client_lock
|
||||
* modify CH clients - READ lock ch_client_lock + ch_client_lock */
|
||||
struct nc_ch_client {
|
||||
const char *name;
|
||||
struct nc_ch_endpt {
|
||||
const char *name;
|
||||
NC_TRANSPORT_IMPL ti;
|
||||
const char *address;
|
||||
uint16_t port;
|
||||
int sock_pending;
|
||||
int sock_retries;
|
||||
struct nc_keepalives ka;
|
||||
union {
|
||||
#ifdef NC_ENABLED_SSH
|
||||
struct nc_server_ssh_opts *ssh;
|
||||
#endif
|
||||
#ifdef NC_ENABLED_TLS
|
||||
struct nc_server_tls_opts *tls;
|
||||
#endif
|
||||
} opts;
|
||||
} *ch_endpts;
|
||||
uint16_t ch_endpt_count;
|
||||
NC_CH_CONN_TYPE conn_type;
|
||||
union {
|
||||
struct {
|
||||
uint16_t period;
|
||||
time_t anchor_time;
|
||||
uint16_t idle_timeout;
|
||||
} period;
|
||||
} conn;
|
||||
NC_CH_START_WITH start_with;
|
||||
uint8_t max_attempts;
|
||||
uint32_t id;
|
||||
pthread_mutex_t lock;
|
||||
} *ch_clients;
|
||||
uint16_t ch_client_count;
|
||||
pthread_rwlock_t ch_client_lock;
|
||||
|
||||
/* Atomic IDs */
|
||||
ATOMIC_T new_session_id;
|
||||
ATOMIC_T new_client_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sleep time in usec to wait between nc_recv_notif() calls.
|
||||
*/
|
||||
#define NC_CLIENT_NOTIF_THREAD_SLEEP 10000
|
||||
|
||||
/**
|
||||
* Timeout in msec for transport-related data to arrive (ssh_handle_key_exchange(), SSL_accept(), SSL_connect()).
|
||||
* It can be quite a lot on slow machines (waiting for TLS cert-to-name resolution, ...).
|
||||
*/
|
||||
#define NC_TRANSPORT_TIMEOUT 10000
|
||||
|
||||
/**
|
||||
* Timeout in msec for acquiring a lock of a session (used with a condition, so higher numbers could be required
|
||||
* only in case of extreme concurrency).
|
||||
*/
|
||||
#define NC_SESSION_LOCK_TIMEOUT 500
|
||||
|
||||
/**
|
||||
* Timeout in msec for acquiring a lock of a session that is supposed to be freed.
|
||||
*/
|
||||
#define NC_SESSION_FREE_LOCK_TIMEOUT 1000
|
||||
|
||||
/**
|
||||
* Timeout in msec for acquiring a lock of a pollsession structure.
|
||||
*/
|
||||
#define NC_PS_LOCK_TIMEOUT 200
|
||||
|
||||
/**
|
||||
* Timeout in msec for a thread to wait for its turn to work with a pollsession structure.
|
||||
*/
|
||||
#define NC_PS_QUEUE_TIMEOUT 5000
|
||||
|
||||
/**
|
||||
* Time slept in msec if no endpoint was created for a running Call Home client.
|
||||
*/
|
||||
#define NC_CH_NO_ENDPT_WAIT 1000
|
||||
|
||||
/**
|
||||
* Time slept in msec after a failed Call Home endpoint session creation.
|
||||
*/
|
||||
#define NC_CH_ENDPT_FAIL_WAIT 1000
|
||||
|
||||
/**
|
||||
* Number of sockets kept waiting to be accepted.
|
||||
*/
|
||||
#define NC_REVERSE_QUEUE 5
|
||||
|
||||
/**
|
||||
* Timeout for connecting Call Home socket to a client (s).
|
||||
*/
|
||||
#define NC_SOCKET_CH_TIMEOUT 5
|
||||
|
||||
/**
|
||||
* Number of retires of connection Call Home socket to a client.
|
||||
*/
|
||||
#define NC_SOCKET_CH_RETRIES 5
|
||||
|
||||
/**
|
||||
* @brief Type of the session
|
||||
*/
|
||||
typedef enum {
|
||||
NC_CLIENT, /**< client side */
|
||||
NC_SERVER /**< server side */
|
||||
} NC_SIDE;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of the supported NETCONF protocol versions
|
||||
*/
|
||||
typedef enum {
|
||||
NC_VERSION_10 = 0, /**< NETCONF 1.0 - RFC 4741, 4742 */
|
||||
NC_VERSION_11 = 1 /**< NETCONF 1.1 - RFC 6241, 6242 */
|
||||
} NC_VERSION;
|
||||
|
||||
#define NC_VERSION_10_ENDTAG "]]>]]>"
|
||||
#define NC_VERSION_10_ENDTAG_LEN 6
|
||||
|
||||
/**
|
||||
* @brief Container to serialize RPC messages
|
||||
*/
|
||||
struct nc_msg_cont {
|
||||
struct ly_in *msg;
|
||||
NC_MSG_TYPE type; /**< can be either NC_MSG_REPLY or NC_MSG_NOTIF */
|
||||
struct nc_msg_cont *next;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief NETCONF session structure
|
||||
*/
|
||||
struct nc_session {
|
||||
NC_STATUS status; /**< status of the session */
|
||||
NC_SESSION_TERM_REASON term_reason; /**< reason of termination, if status is NC_STATUS_INVALID */
|
||||
uint32_t killed_by; /**< session responsible for termination, if term_reason is NC_SESSION_TERM_KILLED */
|
||||
NC_SIDE side; /**< side of the session: client or server */
|
||||
|
||||
/* NETCONF data */
|
||||
uint32_t id; /**< NETCONF session ID (session-id-type) */
|
||||
NC_VERSION version; /**< NETCONF protocol version */
|
||||
|
||||
/* Transport implementation */
|
||||
NC_TRANSPORT_IMPL ti_type; /**< transport implementation type to select items from ti union */
|
||||
pthread_mutex_t *io_lock; /**< input/output lock, note that in case of libssh TI, it will be shared with
|
||||
other NETCONF sessions on the same SSH session (but different SSH channel) */
|
||||
|
||||
union {
|
||||
struct {
|
||||
int in; /**< input file descriptor */
|
||||
int out; /**< output file descriptor */
|
||||
} fd; /**< NC_TI_FD transport implementation structure */
|
||||
struct {
|
||||
int sock; /**< socket file descriptor */
|
||||
} unixsock; /**< NC_TI_UNIX transport implementation structure */
|
||||
#ifdef NC_ENABLED_SSH
|
||||
struct {
|
||||
ssh_channel channel;
|
||||
ssh_session session;
|
||||
struct nc_session *next; /**< pointer to the next NETCONF session on the same
|
||||
SSH session, but different SSH channel. If no such session exists, it is NULL.
|
||||
otherwise there is a ring list of the NETCONF sessions */
|
||||
} libssh;
|
||||
#endif
|
||||
#ifdef NC_ENABLED_TLS
|
||||
SSL *tls;
|
||||
#endif
|
||||
} ti; /**< transport implementation data */
|
||||
const char *username;
|
||||
const char *host;
|
||||
uint16_t port;
|
||||
const char *path; /**< socket path in case of unix socket */
|
||||
|
||||
/* other */
|
||||
struct ly_ctx *ctx; /**< libyang context of the session */
|
||||
void *data; /**< arbitrary user data */
|
||||
uint8_t flags; /**< various flags of the session */
|
||||
#define NC_SESSION_SHAREDCTX 0x01
|
||||
#define NC_SESSION_CALLHOME 0x02
|
||||
|
||||
union {
|
||||
struct {
|
||||
/* client side only data */
|
||||
uint64_t msgid;
|
||||
char **cpblts; /**< list of server's capabilities on client side */
|
||||
pthread_mutex_t msgs_lock; /**< lock for the msgs buffer */
|
||||
struct nc_msg_cont *msgs; /**< queue for messages received of different type than expected */
|
||||
ATOMIC_T ntf_thread; /**< flag whether notification thread for this session is running or not,
|
||||
2 means it should quit */
|
||||
|
||||
/* client flags */
|
||||
/* some server modules failed to load so the data from them will be ignored - not use strict flag for parsing */
|
||||
# define NC_SESSION_CLIENT_NOT_STRICT 0x40
|
||||
} client;
|
||||
struct {
|
||||
/* server side only data */
|
||||
time_t session_start; /**< real time the session was created */
|
||||
time_t last_rpc; /**< monotonic time (seconds) the last RPC was received on this session */
|
||||
int ntf_status; /**< flag (count) whether the session is subscribed to notifications */
|
||||
|
||||
pthread_mutex_t rpc_lock; /**< lock indicating RPC processing, this lock is always locked before io_lock!! */
|
||||
pthread_cond_t rpc_cond; /**< RPC condition (tied with rpc_lock and rpc_inuse) */
|
||||
int rpc_inuse; /**< variable indicating whether there is RPC being processed or not (tied with
|
||||
rpc_cond and rpc_lock) */
|
||||
|
||||
pthread_mutex_t ch_lock; /**< Call Home thread lock */
|
||||
pthread_cond_t ch_cond; /**< Call Home thread condition */
|
||||
|
||||
/* server flags */
|
||||
#ifdef NC_ENABLED_SSH
|
||||
/* SSH session authenticated */
|
||||
# define NC_SESSION_SSH_AUTHENTICATED 0x04
|
||||
/* netconf subsystem requested */
|
||||
# define NC_SESSION_SSH_SUBSYS_NETCONF 0x08
|
||||
/* new SSH message arrived */
|
||||
# define NC_SESSION_SSH_NEW_MSG 0x10
|
||||
/* this session is passed to nc_sshcb_msg() */
|
||||
# define NC_SESSION_SSH_MSG_CB 0x20
|
||||
|
||||
uint16_t ssh_auth_attempts; /**< number of failed SSH authentication attempts */
|
||||
#endif
|
||||
#ifdef NC_ENABLED_TLS
|
||||
X509 *client_cert; /**< TLS client certificate if used for authentication */
|
||||
#endif
|
||||
} server;
|
||||
} opts;
|
||||
};
|
||||
|
||||
enum nc_ps_session_state {
|
||||
NC_PS_STATE_NONE = 0, /**< session is not being worked with */
|
||||
NC_PS_STATE_BUSY, /**< session is being polled or communicated on (and locked) */
|
||||
NC_PS_STATE_INVALID /**< session is invalid and was already returned by another poll */
|
||||
};
|
||||
|
||||
struct nc_ps_session {
|
||||
struct nc_session *session;
|
||||
enum nc_ps_session_state state;
|
||||
};
|
||||
|
||||
/* ACCESS locked */
|
||||
struct nc_pollsession {
|
||||
struct nc_ps_session **sessions;
|
||||
uint16_t session_count;
|
||||
uint16_t last_event_session;
|
||||
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t lock;
|
||||
uint8_t queue[NC_PS_QUEUE_SIZE]; /**< round buffer, queue is empty when queue_len == 0 */
|
||||
uint8_t queue_begin; /**< queue starts on queue[queue_begin] */
|
||||
uint8_t queue_len; /**< queue ends on queue[(queue_begin + queue_len - 1) % NC_PS_QUEUE_SIZE] */
|
||||
};
|
||||
|
||||
struct nc_ntf_thread_arg {
|
||||
struct nc_session *session;
|
||||
void (*notif_clb)(struct nc_session *session, const struct lyd_node *envp, const struct lyd_node *op);
|
||||
};
|
||||
|
||||
void *nc_realloc(void *ptr, size_t size);
|
||||
|
||||
struct passwd *nc_getpwuid(uid_t uid, struct passwd *pwd_buf, char **buf, size_t *buf_size);
|
||||
|
||||
NC_MSG_TYPE nc_send_msg_io(struct nc_session *session, int io_timeout, struct lyd_node *op);
|
||||
|
||||
int nc_gettimespec_mono(struct timespec *ts);
|
||||
|
||||
int nc_gettimespec_real(struct timespec *ts);
|
||||
|
||||
int32_t nc_difftimespec(const struct timespec *ts1, const struct timespec *ts2);
|
||||
|
||||
void nc_addtimespec(struct timespec *ts, uint32_t msec);
|
||||
|
||||
const char *nc_keytype2str(NC_SSH_KEY_TYPE type);
|
||||
|
||||
int nc_sock_enable_keepalive(int sock, struct nc_keepalives *ka);
|
||||
|
||||
struct nc_session *nc_new_session(NC_SIDE side, int shared_ti);
|
||||
|
||||
int nc_session_rpc_lock(struct nc_session *session, int timeout, const char *func);
|
||||
|
||||
int nc_session_rpc_unlock(struct nc_session *session, int timeout, const char *func);
|
||||
|
||||
/**
|
||||
* @brief Lock IO lock on a session.
|
||||
*
|
||||
* @param[in] session Session to lock.
|
||||
* @param[in] timeout Timeout in msec to use.
|
||||
* @param[in] func Caller function for logging.
|
||||
* @return 1 on success;
|
||||
* @return 0 on timeout;
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nc_session_io_lock(struct nc_session *session, int timeout, const char *func);
|
||||
|
||||
/**
|
||||
* @brief Unlock IO lock on a session.
|
||||
*
|
||||
* @param[in] session Session to unlock.
|
||||
* @param[in] func Caller function for logging.
|
||||
* @return 1 on success;
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nc_session_io_unlock(struct nc_session *session, const char *func);
|
||||
|
||||
/**
|
||||
* @brief Lock MSGS lock on a session.
|
||||
*
|
||||
* @param[in] session Session to lock.
|
||||
* @param[in,out] timeout Timeout in msec to use. If positive and on successful lock, is updated based on what was elapsed.
|
||||
* @param[in] func Caller function for logging.
|
||||
* @return 1 on success;
|
||||
* @return 0 on timeout;
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nc_session_client_msgs_lock(struct nc_session *session, int *timeout, const char *func);
|
||||
|
||||
/**
|
||||
* @brief Unlock MSGS lock on a session.
|
||||
*
|
||||
* @param[in] session Session to unlock.
|
||||
* @param[in] func Caller function for logging.
|
||||
* @return 1 on success;
|
||||
* @return -1 on error.
|
||||
*/
|
||||
int nc_session_client_msgs_unlock(struct nc_session *session, const char *func);
|
||||
|
||||
int nc_ps_lock(struct nc_pollsession *ps, uint8_t *id, const char *func);
|
||||
|
||||
int nc_ps_unlock(struct nc_pollsession *ps, uint8_t id, const char *func);
|
||||
|
||||
/**
|
||||
* @brief Fill libyang context in @p session. Context models are based on the stored session
|
||||
* capabilities. If the server does not support \<get-schema\>, the models are searched
|
||||
* for in the directory set using nc_client_schema_searchpath().
|
||||
*
|
||||
* @param[in] session Session to create the context for.
|
||||
* @return 0 on success, 1 on some missing schemas, -1 on error.
|
||||
*/
|
||||
int nc_ctx_check_and_fill(struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Perform NETCONF handshake on @p session.
|
||||
*
|
||||
* @param[in] session NETCONF session to use.
|
||||
* @return NC_MSG_HELLO on success, NC_MSG_BAD_HELLO on client \<hello\> message parsing fail
|
||||
* (server-side only), NC_MSG_WOULDBLOCK on timeout, NC_MSG_ERROR on other error.
|
||||
*/
|
||||
NC_MSG_TYPE nc_handshake_io(struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Create a socket connection.
|
||||
*
|
||||
* @param[in] host Hostname to connect to.
|
||||
* @param[in] port Port to connect on.
|
||||
* @param[in] timeout for blocking the connect+select call (-1 for infinite).
|
||||
* @param[in] ka Keepalives parameters.
|
||||
* @param[in,out] sock_pending for exchanging the pending socket, if the blocking timeout was != -1
|
||||
* @param[out] ip_host Optional parameter with string IP address of the connected host.
|
||||
* @return Connected socket or -1 on error.
|
||||
*/
|
||||
int nc_sock_connect(const char *host, uint16_t port, int timeout, struct nc_keepalives *ka, int *sock_pending, char **ip_host);
|
||||
|
||||
/**
|
||||
* @brief Accept a new socket connection.
|
||||
*
|
||||
* @param[in] sock Listening socket.
|
||||
* @param[in] timeout Timeout in milliseconds.
|
||||
* @param[out] peer_host Host the new connection was initiated from. Can be NULL.
|
||||
* @param[out] peer_port Port the new connection is connected on. Can be NULL.
|
||||
* @return Connected socket with the new connection, -1 on error.
|
||||
*/
|
||||
int nc_sock_accept(int sock, int timeout, char **peer_host, uint16_t *peer_port);
|
||||
|
||||
/**
|
||||
* @brief Create a listening socket (AF_INET or AF_INET6).
|
||||
*
|
||||
* @param[in] address IP address to listen on.
|
||||
* @param[in] port Port to listen on.
|
||||
* @param[in] ka Keepalives parameters.
|
||||
* @return Listening socket, -1 on error.
|
||||
*/
|
||||
int nc_sock_listen_inet(const char *address, uint16_t port, struct nc_keepalives *ka);
|
||||
|
||||
/**
|
||||
* @brief Create a listening socket (AF_UNIX).
|
||||
*
|
||||
* @param[in] address UNIX address to listen on.
|
||||
* @param[in] opts The server options (unix permissions).
|
||||
* @return Listening socket, -1 on error.
|
||||
*/
|
||||
int nc_sock_listen_unix(const char *address, const struct nc_server_unix_opts *opts);
|
||||
|
||||
/**
|
||||
* @brief Accept a new connection on a listening socket.
|
||||
*
|
||||
* @param[in] binds Structure with the listening sockets.
|
||||
* @param[in] bind_count Number of @p binds.
|
||||
* @param[in] timeout Timeout for accepting.
|
||||
* @param[out] host Host of the remote peer. Can be NULL.
|
||||
* @param[out] port Port of the new connection. Can be NULL.
|
||||
* @param[out] idx Index of the bind that was accepted. Can be NULL.
|
||||
* @return Accepted socket of the new connection, -1 on error.
|
||||
*/
|
||||
int nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, char **host, uint16_t *port, uint16_t *idx);
|
||||
|
||||
/**
|
||||
* @brief Lock endpoint structures for reading and the specific endpoint.
|
||||
*
|
||||
* @param[in] name Name of the endpoint.
|
||||
* @param[in] ti Expected transport.
|
||||
* @param[out] idx Index of the endpoint. Optional.
|
||||
* @return Endpoint structure.
|
||||
*/
|
||||
struct nc_endpt *nc_server_endpt_lock_get(const char *name, NC_TRANSPORT_IMPL ti, uint16_t *idx);
|
||||
|
||||
/**
|
||||
* @brief Lock CH client structures for reading and lock the specific client.
|
||||
*
|
||||
* @param[in] name Name of the CH client.
|
||||
* @param[in] endpt_name Endpoint of the CH client.
|
||||
* @param[in] ti Expected transport.
|
||||
* @param[out] client_p Pointer to the CH client.
|
||||
* @return CH endpoint structure.
|
||||
*/
|
||||
struct nc_ch_endpt *nc_server_ch_client_lock(const char *name, const char *endpt_name, NC_TRANSPORT_IMPL ti,
|
||||
struct nc_ch_client **client_p);
|
||||
|
||||
/**
|
||||
* @brief Unlock CH client strcutures and the specific client.
|
||||
*
|
||||
* @param[in] endpt Locked CH client structure.
|
||||
*/
|
||||
void nc_server_ch_client_unlock(struct nc_ch_client *client);
|
||||
|
||||
/**
|
||||
* @brief Add a client Call Home bind, listen on it.
|
||||
*
|
||||
* @param[in] address Address to bind to.
|
||||
* @param[in] port Port to bind to.
|
||||
* @param[in] ti Transport to use.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_ch_add_bind_listen(const char *address, uint16_t port, NC_TRANSPORT_IMPL ti);
|
||||
|
||||
/**
|
||||
* @brief Remove a client Call Home bind, stop listening on it.
|
||||
*
|
||||
* @param[in] address Address of the bind. NULL matches any address.
|
||||
* @param[in] port Port of the bind. 0 matches all ports.
|
||||
* @param[in] ti Transport of the bind. 0 matches all transports.
|
||||
* @return 0 on success, -1 on no matches found.
|
||||
*/
|
||||
int nc_client_ch_del_bind(const char *address, uint16_t port, NC_TRANSPORT_IMPL ti);
|
||||
|
||||
/**
|
||||
* @brief Connect to a listening NETCONF client using Call Home.
|
||||
*
|
||||
* @param[in] host Hostname to connect to.
|
||||
* @param[in] port Port to connect to.
|
||||
* @param[in] ti Transport fo the connection.
|
||||
* @param[out] session New Call Home session.
|
||||
* @return NC_MSG_HELLO on success, NC_MSG_BAD_HELLO on client \<hello\> message
|
||||
* parsing fail, NC_MSG_WOULDBLOCK on timeout, NC_MSG_ERROR on other errors.
|
||||
*/
|
||||
NC_MSG_TYPE nc_connect_callhome(const char *host, uint16_t port, NC_TRANSPORT_IMPL ti, struct nc_session **session);
|
||||
|
||||
void nc_init(void);
|
||||
|
||||
void nc_destroy(void);
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
|
||||
/**
|
||||
* @brief Accept a server Call Home connection on a socket.
|
||||
*
|
||||
* @param[in] sock Socket with a new connection.
|
||||
* @param[in] host Hostname of the server.
|
||||
* @param[in] port Port of the server.
|
||||
* @param[in] ctx Context for the session. Can be NULL.
|
||||
* @param[in] timeout Transport operations timeout in msec.
|
||||
* @return New session, NULL on error.
|
||||
*/
|
||||
struct nc_session *nc_accept_callhome_ssh_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx, int timeout);
|
||||
|
||||
/**
|
||||
* @brief Establish SSH transport on a socket.
|
||||
*
|
||||
* @param[in] session Session structure of the new connection.
|
||||
* @param[in] sock Socket of the new connection.
|
||||
* @param[in] timeout Transport operations timeout in msec (not SSH authentication one).
|
||||
* @return 1 on success, 0 on timeout, -1 on error.
|
||||
*/
|
||||
int nc_accept_ssh_session(struct nc_session *session, int sock, int timeout);
|
||||
|
||||
/**
|
||||
* @brief Callback called when a new SSH message is received.
|
||||
*
|
||||
* @param[in] sshsession SSH session the message arrived on.
|
||||
* @param[in] msg SSH message itself.
|
||||
* @param[in] data NETCONF session running on @p sshsession.
|
||||
* @return 0 if the message was handled, 1 if it is left up to libssh.
|
||||
*/
|
||||
int nc_sshcb_msg(ssh_session sshsession, ssh_message msg, void *data);
|
||||
|
||||
void nc_server_ssh_clear_opts(struct nc_server_ssh_opts *opts);
|
||||
|
||||
void nc_client_ssh_destroy_opts(void);
|
||||
void _nc_client_ssh_destroy_opts(struct nc_client_ssh_opts *opts);
|
||||
|
||||
#endif /* NC_ENABLED_SSH */
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
|
||||
struct nc_session *nc_accept_callhome_tls_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx, int timeout);
|
||||
|
||||
/**
|
||||
* @brief Establish TLS transport on a socket.
|
||||
*
|
||||
* @param[in] session Session structure of the new connection.
|
||||
* @param[in] sock Socket of the new connection.
|
||||
* @param[in] timeout Transport operations timeout in msec.
|
||||
* @return 1 on success, 0 on timeout, -1 on error.
|
||||
*/
|
||||
int nc_accept_tls_session(struct nc_session *session, int sock, int timeout);
|
||||
|
||||
void nc_server_tls_clear_opts(struct nc_server_tls_opts *opts);
|
||||
|
||||
void nc_client_tls_destroy_opts(void);
|
||||
void _nc_client_tls_destroy_opts(struct nc_client_tls_opts *opts);
|
||||
|
||||
#endif /* NC_ENABLED_TLS */
|
||||
|
||||
/**
|
||||
* Functions
|
||||
* - io.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Read message from the wire.
|
||||
*
|
||||
* Accepts hello, rpc, rpc-reply and notification. Received string is transformed into
|
||||
* libyang XML tree and the message type is detected from the top level element.
|
||||
*
|
||||
* @param[in] session NETCONF session from which the message is being read.
|
||||
* @param[in] io_timeout Timeout in milliseconds. Negative value means infinite timeout,
|
||||
* zero value causes to return immediately.
|
||||
* @param[out] msg Input handled with the NETCONF message (application layer data).
|
||||
* @return 1 on success.
|
||||
* @return 0 on timeout.
|
||||
* @return -1 on error.
|
||||
* @return -2 on malformed message error.
|
||||
*/
|
||||
int nc_read_msg_poll_io(struct nc_session *session, int io_timeout, struct ly_in **msg);
|
||||
|
||||
/**
|
||||
* @brief Read a message from the wire.
|
||||
*
|
||||
* @param[in] session NETCONF session from which the message is being read.
|
||||
* @param[in] io_timeout Timeout in milliseconds. Negative value means infinite timeout,
|
||||
* zero value causes to return immediately.
|
||||
* @param[out] msg Input handled with the NETCONF message (application layer data).
|
||||
* @param[in] passing_io_lock True if @p session IO lock is already held. This function always unlocks
|
||||
* it before returning!
|
||||
* @return 1 on success.
|
||||
* @return 0 on timeout.
|
||||
* @return -1 on error.
|
||||
* @return -2 on malformed message error.
|
||||
*/
|
||||
int nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, int passing_io_lock);
|
||||
|
||||
/**
|
||||
* @brief Write message into wire.
|
||||
*
|
||||
* @param[in] session NETCONF session to which the message will be written.
|
||||
* @param[in] io_timeout Timeout in milliseconds. Negative value means infinite timeout,
|
||||
* zero value causes to return immediately.
|
||||
* @param[in] type The type of the message to write, specified as #NC_MSG_TYPE value. According to the type, the
|
||||
* specific additional parameters are required or accepted:
|
||||
* - #NC_MSG_RPC
|
||||
* - `struct lyd_node *op;` - operation (content of the \<rpc/\> to be sent. Required parameter.
|
||||
* - `const char *attrs;` - additional attributes to be added into the \<rpc/\> element. Required parameter.
|
||||
* - #NC_MSG_REPLY
|
||||
* - `struct lyd_node_opaq *rpc_envp;` - parsed envelopes of the RPC to reply to. Required parameter.
|
||||
* - `struct nc_server_reply *reply;` - RPC reply. Required parameter.
|
||||
* - #NC_MSG_NOTIF
|
||||
* - `struct nc_server_notif *notif;` - notification object. Required parameter.
|
||||
* - #NC_MSG_HELLO
|
||||
* - `const char **capabs;` - capabilities array ended with NULL. Required parameter.
|
||||
* - `uint32_t *sid;` - session ID to be included in the hello message. Optional parameter.
|
||||
*
|
||||
* @return Type of the written message. #NC_MSG_WOULDBLOCK is returned if timeout is positive
|
||||
* (or zero) value and IO lock could not be acquired in that time. #NC_MSG_ERROR is
|
||||
* returned on error and #NC_MSG_NONE is never returned by this function.
|
||||
*/
|
||||
NC_MSG_TYPE nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...);
|
||||
|
||||
/**
|
||||
* @brief Check whether a session is still connected (on transport layer).
|
||||
*
|
||||
* @param[in] session Session to check.
|
||||
* @return 1 if connected, 0 if not.
|
||||
*/
|
||||
int nc_session_is_connected(struct nc_session *session);
|
||||
|
||||
#endif /* NC_SESSION_PRIVATE_H_ */
|
3665
src/session_server.c
Normal file
3665
src/session_server.c
Normal file
File diff suppressed because it is too large
Load diff
930
src/session_server.h
Normal file
930
src/session_server.h
Normal file
|
@ -0,0 +1,930 @@
|
|||
/**
|
||||
* @file session_server.h
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 session server manipulation
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_SESSION_SERVER_H_
|
||||
#define NC_SESSION_SERVER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
# include <openssl/x509.h>
|
||||
#endif
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
# include <libssh/callbacks.h>
|
||||
# include <libssh/libssh.h>
|
||||
# include <libssh/server.h>
|
||||
#endif
|
||||
|
||||
#include "netconf.h"
|
||||
#include "session.h"
|
||||
|
||||
/**
|
||||
* @defgroup server_session Server Session
|
||||
* @ingroup server
|
||||
*
|
||||
* @brief Server-side NETCONF session manipulation.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Prototype of callbacks that are called if some RPCs are received.
|
||||
*
|
||||
* If @p session termination reason is changed in the callback, one last reply
|
||||
* is sent and then the session is considered invalid.
|
||||
*
|
||||
* The callback is set via nc_set_global_rpc_clb().
|
||||
*
|
||||
* @param[in] rpc Parsed client RPC request.
|
||||
* @param[in] session Session the RPC arrived on.
|
||||
* @return Server reply. If NULL, an operation-failed error will be sent to the client.
|
||||
*/
|
||||
typedef struct nc_server_reply *(*nc_rpc_clb)(struct lyd_node *rpc, struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Set the termination reason for a session. Use only in #nc_rpc_clb callbacks.
|
||||
*
|
||||
* @param[in] session Session to modify.
|
||||
* @param[in] reason Reason of termination.
|
||||
*/
|
||||
void nc_session_set_term_reason(struct nc_session *session, NC_SESSION_TERM_REASON reason);
|
||||
|
||||
/**
|
||||
* @brief Set the session-id of the session responsible for this session's termination.
|
||||
*
|
||||
* @param[in] session Session to modify. Must have term_reason set to #NC_SESSION_TERM_KILLED.
|
||||
* @param[in] sid SID of the killing session.
|
||||
*/
|
||||
void nc_session_set_killed_by(struct nc_session *session, uint32_t sid);
|
||||
|
||||
/**
|
||||
* @brief Set the status of a session.
|
||||
*
|
||||
* @param[in] session Session to modify.
|
||||
* @param[in] status Status of the session.
|
||||
*/
|
||||
void nc_session_set_status(struct nc_session *session, NC_STATUS status);
|
||||
|
||||
/**
|
||||
* @brief Set a global nc_rpc_clb that is called if the particular RPC request is
|
||||
* received and the private field in the corresponding RPC schema node is NULL.
|
||||
*
|
||||
* @param[in] clb An user-defined nc_rpc_clb function callback, NULL to default.
|
||||
*/
|
||||
void nc_set_global_rpc_clb(nc_rpc_clb clb);
|
||||
|
||||
/** @} Server Session */
|
||||
|
||||
/**
|
||||
* @addtogroup server
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initialize libssh and/or libssl/libcrypto and the server using a libyang context.
|
||||
*
|
||||
* The context is not modified internally, only its dictionary is used for holding
|
||||
* all the strings, which is thread-safe. Reading models is considered thread-safe
|
||||
* as models cannot be removed and are rarely modified (augments or deviations).
|
||||
*
|
||||
* If the RPC callbacks on schema nodes (mentioned in @ref howtoserver) are modified after
|
||||
* server initialization with that particular context, they will be called (changes
|
||||
* will take effect). However, there could be race conditions as the access to
|
||||
* these callbacks is not thread-safe.
|
||||
*
|
||||
* Server capabilities are generated based on its content. Changing the context
|
||||
* in ways that result in changed capabilities (adding models, changing features)
|
||||
* is discouraged after sessions are established as it is not possible to change
|
||||
* capabilities of a session.
|
||||
*
|
||||
* This context can safely be destroyed only after calling the last libnetconf2
|
||||
* function in an application.
|
||||
*
|
||||
* Supported RPCs of models in the context are expected to have their callback
|
||||
* in the corresponding RPC schema node set to a nc_rpc_clb function callback using nc_set_rpc_callback().
|
||||
* This callback is called by nc_ps_poll() if the particular RPC request is
|
||||
* received. Callbacks for ietf-netconf:get-schema (supporting YANG and YIN format
|
||||
* only) and ietf-netconf:close-session are set internally if left unset.
|
||||
*
|
||||
* @param[in] ctx Core NETCONF server context.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_init(struct ly_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Destroy any dynamically allocated libssh and/or libssl/libcrypto and
|
||||
* server resources.
|
||||
*/
|
||||
void nc_server_destroy(void);
|
||||
|
||||
/**
|
||||
* @brief Set the with-defaults capability extra parameters.
|
||||
*
|
||||
* For the capability to be actually advertised, the server context must also
|
||||
* include the ietf-netconf-with-defaults model.
|
||||
*
|
||||
* Changing this option has the same ill effects as changing capabilities while
|
||||
* sessions are already established.
|
||||
*
|
||||
* @param[in] basic_mode basic-mode with-defaults parameter.
|
||||
* @param[in] also_supported NC_WD_MODE bit array, also-supported with-defaults
|
||||
* parameter.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_set_capab_withdefaults(NC_WD_MODE basic_mode, int also_supported);
|
||||
|
||||
/**
|
||||
* @brief Get with-defaults capability extra parameters.
|
||||
*
|
||||
* At least one argument must be non-NULL.
|
||||
*
|
||||
* @param[in,out] basic_mode basic-mode parameter.
|
||||
* @param[in,out] also_supported also-supported parameter.
|
||||
*/
|
||||
void nc_server_get_capab_withdefaults(NC_WD_MODE *basic_mode, int *also_supported);
|
||||
|
||||
/**
|
||||
* @brief Set capability of the server.
|
||||
*
|
||||
* Capability can be used when some behavior or extension of the server is not defined
|
||||
* as a YANG module. The provided value will be advertised in the server's \<hello\>
|
||||
* messages. Note, that libnetconf only checks that the provided value is non-empty
|
||||
* string.
|
||||
*
|
||||
* @param[in] value Capability string to be advertised in server's \<hello\> messages.
|
||||
*/
|
||||
int nc_server_set_capability(const char *value);
|
||||
|
||||
/**
|
||||
* @brief Set the callback for getting yang-library capability identifier. If none is set, libyang context change count is used.
|
||||
*
|
||||
* @param[in] content_id_clb Callback that should return the yang-library content identifier.
|
||||
* @param[in] user_data Optional arbitrary user data that will be passed to @p content_id_clb.
|
||||
* @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data.
|
||||
*/
|
||||
void nc_server_set_content_id_clb(char *(*content_id_clb)(void *user_data), void *user_data,
|
||||
void (*free_user_data)(void *user_data));
|
||||
|
||||
/**
|
||||
* @brief Set server timeout for receiving a hello message.
|
||||
*
|
||||
* @param[in] hello_timeout Hello message timeout. 0 for infinite waiting.
|
||||
*/
|
||||
void nc_server_set_hello_timeout(uint16_t hello_timeout);
|
||||
|
||||
/**
|
||||
* @brief get server timeout for receiving a hello message.
|
||||
*
|
||||
* @return Hello message timeout, 0 is infinite.
|
||||
*/
|
||||
uint16_t nc_server_get_hello_timeout(void);
|
||||
|
||||
/**
|
||||
* @brief Set server timeout for dropping an idle session.
|
||||
*
|
||||
* @param[in] idle_timeout Idle session timeout. 0 to never drop a session
|
||||
* because of inactivity.
|
||||
*/
|
||||
void nc_server_set_idle_timeout(uint16_t idle_timeout);
|
||||
|
||||
/**
|
||||
* @brief Get server timeout for dropping an idle session.
|
||||
*
|
||||
* @return Idle session timeout, 0 for for never dropping
|
||||
* a session because of inactivity.
|
||||
*/
|
||||
uint16_t nc_server_get_idle_timeout(void);
|
||||
|
||||
/**
|
||||
* @brief Get all the server capabilities including all the schemas.
|
||||
*
|
||||
* A few capabilities (with-defaults, interleave) depend on the current
|
||||
* server options.
|
||||
*
|
||||
* @param[in] ctx Context to read most capabilities from.
|
||||
* @return Array of capabilities stored in the @p ctx dictionary, NULL on error.
|
||||
*/
|
||||
const char **nc_server_get_cpblts(struct ly_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Get the server capabilities including the schemas with the specified YANG version.
|
||||
*
|
||||
* A few capabilities (with-defaults, interleave) depend on the current
|
||||
* server options.
|
||||
*
|
||||
* @param[in] ctx Context to read most capabilities from.
|
||||
* @param[in] version YANG version of the schemas to be included in result, with
|
||||
* LYS_VERSION_UNDEF the result is the same as from nc_server_get_cpblts().
|
||||
* @return Array of capabilities stored in the @p ctx dictionary, NULL on error.
|
||||
*/
|
||||
const char **nc_server_get_cpblts_version(struct ly_ctx *ctx, LYS_VERSION version);
|
||||
|
||||
/** @} Server */
|
||||
|
||||
/**
|
||||
* @addtogroup server_session
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Accept a new session on a pre-established transport session.
|
||||
*
|
||||
* @param[in] fdin File descriptor to read (unencrypted) XML data from.
|
||||
* @param[in] fdout File descriptor to write (unencrypted) XML data to.
|
||||
* @param[in] username NETCONF username as provided by the transport protocol.
|
||||
* @param[out] session New session on success.
|
||||
* @return NC_MSG_HELLO on success, NC_MSG_BAD_HELLO on client \<hello\> message
|
||||
* parsing fail, NC_MSG_WOULDBLOCK on timeout, NC_MSG_ERROR on other errors.
|
||||
*/
|
||||
NC_MSG_TYPE nc_accept_inout(int fdin, int fdout, const char *username, struct nc_session **session);
|
||||
|
||||
/**
|
||||
* @brief Create an empty structure for polling sessions.
|
||||
*
|
||||
* @return Empty pollsession structure, NULL on error.
|
||||
*/
|
||||
struct nc_pollsession *nc_ps_new(void);
|
||||
|
||||
/**
|
||||
* @brief Free a pollsession structure.
|
||||
*
|
||||
* !IMPORTANT! Make sure that @p ps is not accessible (is not used)
|
||||
* by any thread before and after this call!
|
||||
*
|
||||
* @param[in] ps Pollsession structure to free.
|
||||
*/
|
||||
void nc_ps_free(struct nc_pollsession *ps);
|
||||
|
||||
/**
|
||||
* @brief Add a session to a pollsession structure.
|
||||
*
|
||||
* @param[in] ps Pollsession structure to modify.
|
||||
* @param[in] session Session to add to @p ps.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_ps_add_session(struct nc_pollsession *ps, struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Remove a session from a pollsession structure.
|
||||
*
|
||||
* @param[in] ps Pollsession structure to modify.
|
||||
* @param[in] session Session to remove from @p ps.
|
||||
* @return 0 on success, -1 on not found.
|
||||
*/
|
||||
int nc_ps_del_session(struct nc_pollsession *ps, struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Get a session from a pollsession structure matching the session ID.
|
||||
*
|
||||
* @param[in] ps Pollsession structure to read from.
|
||||
* @param[in] idx Index of the session.
|
||||
* @return Session on index, NULL if out-of-bounds.
|
||||
*/
|
||||
struct nc_session *nc_ps_get_session(const struct nc_pollsession *ps, uint16_t idx);
|
||||
|
||||
/**
|
||||
* @brief Learn the number of sessions in a pollsession structure.
|
||||
*
|
||||
* Does not lock @p ps structure for efficiency.
|
||||
*
|
||||
* @param[in] ps Pollsession structure to check.
|
||||
* @return Number of sessions (even invalid ones) in @p ps, -1 on error.
|
||||
*/
|
||||
uint16_t nc_ps_session_count(struct nc_pollsession *ps);
|
||||
|
||||
#define NC_PSPOLL_NOSESSIONS 0x0001 /**< No sessions to poll. */
|
||||
#define NC_PSPOLL_TIMEOUT 0x0002 /**< Timeout elapsed. */
|
||||
#define NC_PSPOLL_RPC 0x0004 /**< RPC was correctly parsed and processed. */
|
||||
#define NC_PSPOLL_BAD_RPC 0x0008 /**< RPC was received, but failed to be parsed. */
|
||||
#define NC_PSPOLL_REPLY_ERROR 0x0010 /**< Response to the RPC was a \<rpc-reply\> of type error. */
|
||||
#define NC_PSPOLL_SESSION_TERM 0x0020 /**< Some session was terminated. */
|
||||
#define NC_PSPOLL_SESSION_ERROR 0x0040 /**< Some session was terminated incorrectly (not by a \<close-session\> or \<kill-session\> RPC). */
|
||||
#define NC_PSPOLL_ERROR 0x0080 /**< Other fatal errors (they are printed). */
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
# define NC_PSPOLL_SSH_MSG 0x00100 /**< SSH message received (and processed, if relevant, only with SSH support). */
|
||||
# define NC_PSPOLL_SSH_CHANNEL 0x0200 /**< New SSH channel opened on an existing session (only with SSH support). */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Poll sessions and process any received RPCs.
|
||||
*
|
||||
* Only one event on one session is handled in one function call. If this event
|
||||
* is a session termination (#NC_PSPOLL_SESSION_TERM returned), the session
|
||||
* should be removed from @p ps.
|
||||
*
|
||||
* @param[in] ps Pollsession structure to use.
|
||||
* @param[in] timeout Poll timeout in milliseconds. 0 for non-blocking call, -1 for
|
||||
* infinite waiting.
|
||||
* @param[in] session Session that was processed and that specific return bits concern.
|
||||
* Can be NULL.
|
||||
* @return Bitfield of NC_PSPOLL_* macros.
|
||||
*/
|
||||
int nc_ps_poll(struct nc_pollsession *ps, int timeout, struct nc_session **session);
|
||||
|
||||
/**
|
||||
* @brief Remove sessions from a pollsession structure and
|
||||
* call nc_session_free() on them.
|
||||
*
|
||||
* Calling this function with @p all false makes sense if nc_ps_poll() returned #NC_PSPOLL_SESSION_TERM.
|
||||
*
|
||||
* @param[in] ps Pollsession structure to clear.
|
||||
* @param[in] all Whether to free all sessions, or only the invalid ones.
|
||||
* @param[in] data_free Session user data destructor.
|
||||
*/
|
||||
void nc_ps_clear(struct nc_pollsession *ps, int all, void (*data_free)(void *));
|
||||
|
||||
/** @} Server Session */
|
||||
|
||||
/**
|
||||
* @addtogroup server
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Add a new endpoint.
|
||||
*
|
||||
* Before the endpoint can accept any connections, its address and port must
|
||||
* be set via nc_server_endpt_set_address() and nc_server_endpt_set_port().
|
||||
*
|
||||
* @param[in] name Arbitrary unique endpoint name.
|
||||
* @param[in] ti Transport protocol to use.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_add_endpt(const char *name, NC_TRANSPORT_IMPL ti);
|
||||
|
||||
/**
|
||||
* @brief Stop listening on and remove an endpoint.
|
||||
*
|
||||
* @param[in] name Endpoint name. NULL matches all endpoints.
|
||||
* @param[in] ti Endpoint transport protocol. NULL matches any protocol.
|
||||
* Redundant to set if @p name is set, endpoint names are
|
||||
* unique disregarding their protocol.
|
||||
* @return 0 on success, -1 on not finding any match.
|
||||
*/
|
||||
int nc_server_del_endpt(const char *name, NC_TRANSPORT_IMPL ti);
|
||||
|
||||
/**
|
||||
* @brief Get the number of currently configured listening endpoints.
|
||||
* Note that an ednpoint without address and/or port will be included
|
||||
* even though it is not, in fact, listening.
|
||||
*
|
||||
* @return Number of added listening endpoints.
|
||||
*/
|
||||
int nc_server_endpt_count(void);
|
||||
|
||||
/**
|
||||
* @brief Check if an endpoint exists.
|
||||
*
|
||||
* @param[in] name Endpoint name.
|
||||
* @return 0 if does not exists, non-zero otherwise.
|
||||
*/
|
||||
int nc_server_is_endpt(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Change endpoint listening address.
|
||||
*
|
||||
* On error the previous listening socket (if any) is left untouched.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] address New listening address.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_endpt_set_address(const char *endpt_name, const char *address);
|
||||
|
||||
#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS)
|
||||
|
||||
/**
|
||||
* @brief Change endpoint listening port.
|
||||
*
|
||||
* This is only valid on SSH/TLS transport endpoint.
|
||||
* On error the previous listening socket (if any) is left untouched.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] port New listening port.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_endpt_set_port(const char *endpt_name, uint16_t port);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Change endpoint permissions.
|
||||
*
|
||||
* This is only valid on UNIX transport endpoint.
|
||||
* On error the previous listening socket (if any) is left untouched.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] mode New mode, -1 to use default.
|
||||
* @param[in] uid New uid, -1 to use default.
|
||||
* @param[in] gid New gid, -1 to use default.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_endpt_set_perms(const char *endpt_name, mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
/**
|
||||
* @brief Change endpoint keepalives state. Affects only new connections.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] enable Whether to enable or disable keepalives.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_endpt_enable_keepalives(const char *endpt_name, int enable);
|
||||
|
||||
/**
|
||||
* @brief Change endpoint keepalives parameters. Affects only new connections.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] idle_time Keepalive idle time in seconds, 1 by default, -1 to keep previous value.
|
||||
* @param[in] max_probes Keepalive max probes sent, 10 by default, -1 to keep previous value.
|
||||
* @param[in] probe_interval Keepalive probe interval in seconds, 5 by default, -1 to keep previous value.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_endpt_set_keepalives(const char *endpt_name, int idle_time, int max_probes, int probe_interval);
|
||||
|
||||
/** @} Server */
|
||||
|
||||
/**
|
||||
* @addtogroup server_session
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Accept new sessions on all the listening endpoints.
|
||||
*
|
||||
* Once a new (TCP/IP) conection is established a different (quite long) timeout
|
||||
* is used for waiting for transport-related data, which means this call can block
|
||||
* for much longer that @p timeout, but only with slow/faulty/malicious clients.
|
||||
*
|
||||
* @param[in] timeout Timeout for receiving a new connection in milliseconds, 0 for
|
||||
* non-blocking call, -1 for infinite waiting.
|
||||
* @param[out] session New session.
|
||||
* @return NC_MSG_HELLO on success, NC_MSG_BAD_HELLO on client \<hello\> message
|
||||
* parsing fail, NC_MSG_WOULDBLOCK on timeout, NC_MSG_ERROR on other errors.
|
||||
*/
|
||||
NC_MSG_TYPE nc_accept(int timeout, struct nc_session **session);
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
|
||||
/**
|
||||
* @brief Accept a new NETCONF session on an SSH session of a running NETCONF @p orig_session.
|
||||
* Call this function only when nc_ps_poll() returns #NC_PSPOLL_SSH_CHANNEL on @p orig_session.
|
||||
*
|
||||
* @param[in] orig_session Session that has a new SSH channel ready.
|
||||
* @param[out] session New session.
|
||||
* @return NC_MSG_HELLO on success, NC_MSG_BAD_HELLO on client \<hello\> message
|
||||
* parsing fail, NC_MSG_WOULDBLOCK on timeout, NC_MSG_ERROR on other errors.
|
||||
*/
|
||||
NC_MSG_TYPE nc_session_accept_ssh_channel(struct nc_session *orig_session, struct nc_session **session);
|
||||
|
||||
/**
|
||||
* @brief Accept a new NETCONF session on an SSH session of a running NETCONF session
|
||||
* that was polled in @p ps. Call this function only when nc_ps_poll() on @p ps returns #NC_PSPOLL_SSH_CHANNEL.
|
||||
* The new session is only returned in @p session, it is not added to @p ps.
|
||||
*
|
||||
* @param[in] ps Unmodified pollsession structure from the previous nc_ps_poll() call.
|
||||
* @param[out] session New session.
|
||||
* @return NC_MSG_HELLO on success, NC_MSG_BAD_HELLO on client \<hello\> message
|
||||
* parsing fail, NC_MSG_WOULDBLOCK on timeout, NC_MSG_ERROR on other errors.
|
||||
*/
|
||||
NC_MSG_TYPE nc_ps_accept_ssh_channel(struct nc_pollsession *ps, struct nc_session **session);
|
||||
|
||||
/** @} Server Session */
|
||||
|
||||
/**
|
||||
* @defgroup server_ssh Server SSH
|
||||
* @ingroup server
|
||||
*
|
||||
* @brief Server-side settings for SSH connections.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Add an authorized client SSH public key. This public key can be used for
|
||||
* publickey authentication (for any SSH connection, even Call Home) afterwards.
|
||||
*
|
||||
* @param[in] pubkey_base64 Authorized public key binary content encoded in base64.
|
||||
* @param[in] type Authorized public key SSH type.
|
||||
* @param[in] username Username that the client with the public key must use.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_add_authkey(const char *pubkey_base64, NC_SSH_KEY_TYPE type, const char *username);
|
||||
|
||||
/**
|
||||
* @brief Add an authorized client SSH public key. This public key can be used for
|
||||
* publickey authentication (for any SSH connection, even Call Home) afterwards.
|
||||
*
|
||||
* @param[in] pubkey_path Path to the public key.
|
||||
* @param[in] username Username that the client with the public key must use.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_add_authkey_path(const char *pubkey_path, const char *username);
|
||||
|
||||
/**
|
||||
* @brief Remove an authorized client SSH public key.
|
||||
*
|
||||
* @param[in] pubkey_path Path to an authorized public key. NULL matches all the keys.
|
||||
* @param[in] pubkey_base64 Authorized public key content. NULL matches any key.
|
||||
* @param[in] type Authorized public key type. 0 matches all types.
|
||||
* @param[in] username Username for an authorized public key. NULL matches all the usernames.
|
||||
* @return 0 on success, -1 on not finding any match.
|
||||
*/
|
||||
int nc_server_ssh_del_authkey(const char *pubkey_path, const char *pubkey_base64, NC_SSH_KEY_TYPE type,
|
||||
const char *username);
|
||||
|
||||
/**
|
||||
* @brief Set the callback for SSH password authentication. If none is set, local system users are used.
|
||||
*
|
||||
* @param[in] passwd_auth_clb Callback that should authenticate the user. Username can be directly obtained from @p session.
|
||||
* Zero return indicates success, non-zero an error.
|
||||
* @param[in] user_data Optional arbitrary user data that will be passed to @p passwd_auth_clb.
|
||||
* @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data.
|
||||
*/
|
||||
void nc_server_ssh_set_passwd_auth_clb(int (*passwd_auth_clb)(const struct nc_session *session, const char *password,
|
||||
void *user_data), void *user_data, void (*free_user_data)(void *user_data));
|
||||
|
||||
/**
|
||||
* @brief Set the callback for SSH interactive authentication. If none is set, local system users are used.
|
||||
*
|
||||
* @param[in] interactive_auth_clb Callback that should authenticate the user.
|
||||
* Zero return indicates success, non-zero an error.
|
||||
* @param[in] user_data Optional arbitrary user data that will be passed to @p passwd_auth_clb.
|
||||
* @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data.
|
||||
*/
|
||||
void nc_server_ssh_set_interactive_auth_clb(int (*interactive_auth_clb)(const struct nc_session *session,
|
||||
const ssh_message msg, void *user_data), void *user_data, void (*free_user_data)(void *user_data));
|
||||
|
||||
/**
|
||||
* @brief Set the callback for SSH public key authentication. If none is set, local system users are used.
|
||||
*
|
||||
* @param[in] pubkey_auth_clb Callback that should authenticate the user.
|
||||
* Zero return indicates success, non-zero an error.
|
||||
* @param[in] user_data Optional arbitrary user data that will be passed to @p passwd_auth_clb.
|
||||
* @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data.
|
||||
*/
|
||||
void nc_server_ssh_set_pubkey_auth_clb(int (*pubkey_auth_clb)(const struct nc_session *session, ssh_key key,
|
||||
void *user_data), void *user_data, void (*free_user_data)(void *user_data));
|
||||
|
||||
/**
|
||||
* @brief Set the callback for retrieving host keys. Any RSA, DSA, and ECDSA keys can be added. However,
|
||||
* a maximum of one key of each type will be used during SSH authentication, later keys replacing
|
||||
* the earlier ones.
|
||||
*
|
||||
* @param[in] hostkey_clb Callback that should return the key itself. Zero return indicates success, non-zero
|
||||
* an error. On success exactly ONE of @p privkey_path or @p privkey_data is expected
|
||||
* to be set. The one set will be freed.
|
||||
* - @p privkey_path expects a PEM file,
|
||||
* - @p privkey_data expects a base-64 encoded ANS.1 DER data,
|
||||
* - @p privkey_type type of the key in @p privkey_data. Use ::NC_SSH_KEY_UNKNOWN for
|
||||
* PKCS#8 key that includes the information about the key in its data.
|
||||
* @param[in] user_data Optional arbitrary user data that will be passed to @p hostkey_clb.
|
||||
* @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data.
|
||||
*/
|
||||
void nc_server_ssh_set_hostkey_clb(int (*hostkey_clb)(const char *name, void *user_data, char **privkey_path,
|
||||
char **privkey_data, NC_SSH_KEY_TYPE *privkey_type), void *user_data, void (*free_user_data)(void *user_data));
|
||||
|
||||
/**
|
||||
* @brief Add endpoint SSH host keys the server will identify itself with. Only the name is set, the key itself
|
||||
* wil be retrieved using a callback.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] name Arbitrary name of the host key.
|
||||
* @param[in] idx Optional index where to add the key. -1 adds at the end.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_endpt_add_hostkey(const char *endpt_name, const char *name, int16_t idx);
|
||||
|
||||
/**
|
||||
* @brief Delete endpoint SSH host key. Their order is preserved.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] name Name of the host key. NULL matches all the keys, but if @p idx != -1 then this must be NULL.
|
||||
* @param[in] idx Index of the hostkey. -1 matches all indices, but if @p name != NULL then this must be -1.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_endpt_del_hostkey(const char *endpt_name, const char *name, int16_t idx);
|
||||
|
||||
/**
|
||||
* @brief Move endpoint SSH host key.
|
||||
*
|
||||
* @param[in] endpt_name Exisitng endpoint name.
|
||||
* @param[in] key_mov Name of the host key that will be moved.
|
||||
* @param[in] key_after Name of the key that will preceed @p key_mov. NULL if @p key_mov is to be moved at the beginning.
|
||||
* @return 0 in success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_endpt_mov_hostkey(const char *endpt_name, const char *key_mov, const char *key_after);
|
||||
|
||||
/**
|
||||
* @brief Modify endpoint SSH host key.
|
||||
*
|
||||
* @param[in] endpt_name Exisitng endpoint name.
|
||||
* @param[in] name Name of an existing host key.
|
||||
* @param[in] new_name New name of the host key @p name.
|
||||
* @return 0 in success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_endpt_mod_hostkey(const char *endpt_name, const char *name, const char *new_name);
|
||||
|
||||
/**
|
||||
* @brief Set endpoint accepted SSH authentication methods. All (publickey, password, interactive)
|
||||
* are supported by default.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] auth_methods Accepted authentication methods bit field of NC_SSH_AUTH_TYPE.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_endpt_set_auth_methods(const char *endpt_name, int auth_methods);
|
||||
|
||||
/**
|
||||
* @brief Get endpoint accepted SSH authentication methods.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @return Accepted authentication methods bit field of NC_SSH_AUTH_TYPE.
|
||||
*/
|
||||
int nc_server_ssh_endpt_get_auth_methods(const char *endpt_name);
|
||||
|
||||
/**
|
||||
* @brief Set endpoint SSH authentication attempts of every client. 3 by default.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] auth_attempts Failed authentication attempts before a client is dropped.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_endpt_set_auth_attempts(const char *endpt_name, uint16_t auth_attempts);
|
||||
|
||||
/**
|
||||
* @brief Set endpoint SSH authentication timeout. 30 seconds by default.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] auth_timeout Number of seconds before an unauthenticated client is dropped.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_endpt_set_auth_timeout(const char *endpt_name, uint16_t auth_timeout);
|
||||
|
||||
/** @} Server SSH */
|
||||
|
||||
#endif /* NC_ENABLED_SSH */
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
|
||||
/**
|
||||
* @defgroup server_tls Server TLS
|
||||
* @ingroup server
|
||||
*
|
||||
* @brief Server-side settings for TLS connections.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set the server TLS certificate. Only the name is set, the certificate itself
|
||||
* wil be retrieved using a callback.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] name Arbitrary certificate name.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_tls_endpt_set_server_cert(const char *endpt_name, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Set the callback for retrieving server certificate and matching private key.
|
||||
*
|
||||
* @param[in] cert_clb Callback that should return the certificate and the key itself. Zero return indicates success,
|
||||
* non-zero an error. On success exactly ONE of @p cert_path or @p cert_data and ONE of
|
||||
* @p privkey_path and @p privkey_data is expected to be set. Those set will be freed.
|
||||
* - @p cert_path expects a PEM file,
|
||||
* - @p cert_data expects a base-64 encoded ASN.1 DER data,
|
||||
* - @p privkey_path expects a PEM file,
|
||||
* - @p privkey_data expects a base-64 encoded ANS.1 DER data,
|
||||
* - @p privkey_type type of the key in @p privkey_data.
|
||||
* @param[in] user_data Optional arbitrary user data that will be passed to @p cert_clb.
|
||||
* @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data.
|
||||
*/
|
||||
void nc_server_tls_set_server_cert_clb(int (*cert_clb)(const char *name, void *user_data, char **cert_path, char **cert_data,
|
||||
char **privkey_path, char **privkey_data, NC_SSH_KEY_TYPE *privkey_type), void *user_data,
|
||||
void (*free_user_data)(void *user_data));
|
||||
|
||||
/**
|
||||
* @brief Set the callback for retrieving server certificate chain
|
||||
*
|
||||
* @param[in] cert_chain_clb Callback that should return all the certificates of the chain. Zero return indicates success,
|
||||
* non-zero an error. On success, @p cert_paths and @p cert_data are expected to be set or left
|
||||
* NULL. Both will be (deeply) freed.
|
||||
* - @p cert_paths expect an array of PEM files,
|
||||
* - @p cert_path_count number of @p cert_paths array members,
|
||||
* - @p cert_data expect an array of base-64 encoded ASN.1 DER cert data,
|
||||
* - @p cert_data_count number of @p cert_data array members.
|
||||
* @param[in] user_data Optional arbitrary user data that will be passed to @p cert_clb.
|
||||
* @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data.
|
||||
*/
|
||||
void nc_server_tls_set_server_cert_chain_clb(int (*cert_chain_clb)(const char *name, void *user_data, char ***cert_paths,
|
||||
int *cert_path_count, char ***cert_data, int *cert_data_count), void *user_data, void (*free_user_data)(void *user_data));
|
||||
|
||||
/**
|
||||
* @brief Add a trusted certificate list. Can be both a CA or a client one. Can be
|
||||
* safely used together with nc_server_tls_endpt_set_trusted_ca_paths().
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] name Arbitary name identifying this certificate list.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_tls_endpt_add_trusted_cert_list(const char *endpt_name, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Set the callback for retrieving trusted certificates.
|
||||
*
|
||||
* @param[in] cert_list_clb Callback that should return all the certificates of a list. Zero return indicates success,
|
||||
* non-zero an error. On success, @p cert_paths and @p cert_data are expected to be set or left
|
||||
* NULL. Both will be (deeply) freed.
|
||||
* - @p cert_paths expect an array of PEM files,
|
||||
* - @p cert_path_count number of @p cert_paths array members,
|
||||
* - @p cert_data expect an array of base-64 encoded ASN.1 DER cert data,
|
||||
* - @p cert_data_count number of @p cert_data array members.
|
||||
* @param[in] user_data Optional arbitrary user data that will be passed to @p cert_clb.
|
||||
* @param[in] free_user_data Optional callback that will be called during cleanup to free any @p user_data.
|
||||
*/
|
||||
void nc_server_tls_set_trusted_cert_list_clb(int (*cert_list_clb)(const char *name, void *user_data, char ***cert_paths,
|
||||
int *cert_path_count, char ***cert_data, int *cert_data_count), void *user_data, void (*free_user_data)(void *user_data));
|
||||
|
||||
/**
|
||||
* @brief Remove a trusted certificate.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] name Name of the certificate list to delete. NULL deletes all the lists.
|
||||
* @return 0 on success, -1 on not found.
|
||||
*/
|
||||
int nc_server_tls_endpt_del_trusted_cert_list(const char *endpt_name, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Set trusted Certificate Authority certificate locations. There can only be
|
||||
* one file and one directory, they are replaced if already set. Can be safely
|
||||
* used with nc_server_tls_endpt_add_trusted_cert() or its _path variant.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] ca_file Path to a trusted CA cert store file in PEM format. Can be NULL.
|
||||
* @param[in] ca_dir Path to a trusted CA cert store hashed directory (c_rehash utility
|
||||
* can be used to create hashes) with PEM files. Can be NULL.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_tls_endpt_set_trusted_ca_paths(const char *endpt_name, const char *ca_file, const char *ca_dir);
|
||||
|
||||
/**
|
||||
* @brief Set Certificate Revocation List locations. There can only be one file
|
||||
* and one directory, they are replaced if already set.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] crl_file Path to a CRL store file in PEM format. Can be NULL.
|
||||
* @param[in] crl_dir Path to a CRL store hashed directory (c_rehash utility
|
||||
* can be used to create hashes) with PEM files. Can be NULL.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_tls_endpt_set_crl_paths(const char *endpt_name, const char *crl_file, const char *crl_dir);
|
||||
|
||||
/**
|
||||
* @brief Destroy and clean CRLs. Certificates, private keys, and CTN entries are
|
||||
* not affected.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
*/
|
||||
void nc_server_tls_endpt_clear_crls(const char *endpt_name);
|
||||
|
||||
/**
|
||||
* @brief Add a cert-to-name entry.
|
||||
*
|
||||
* It is possible to add an entry step-by-step, specifying first only @p ip and in later calls
|
||||
* @p fingerprint, @p map_type, and optionally @p name spearately.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] id Priority of the entry. It must be unique. If already exists, the entry with this id
|
||||
* is modified.
|
||||
* @param[in] fingerprint Matching certificate fingerprint. If NULL, kept temporarily unset.
|
||||
* @param[in] map_type Type of username-certificate mapping. If 0, kept temporarily unset.
|
||||
* @param[in] name Specific username used only if @p map_type == NC_TLS_CTN_SPECIFED.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_tls_endpt_add_ctn(const char *endpt_name, uint32_t id, const char *fingerprint,
|
||||
NC_TLS_CTN_MAPTYPE map_type, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Remove a cert-to-name entry.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] id Priority of the entry. -1 matches all the priorities.
|
||||
* @param[in] fingerprint Fingerprint fo the entry. NULL matches all the fingerprints.
|
||||
* @param[in] map_type Mapping type of the entry. 0 matches all the mapping types.
|
||||
* @param[in] name Specific username for the entry. NULL matches all the usernames.
|
||||
* @return 0 on success, -1 on not finding any match.
|
||||
*/
|
||||
int nc_server_tls_endpt_del_ctn(const char *endpt_name, int64_t id, const char *fingerprint,
|
||||
NC_TLS_CTN_MAPTYPE map_type, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Get a cert-to-name entry.
|
||||
*
|
||||
* If a parameter is NULL, it is ignored. If its dereferenced value is NULL,
|
||||
* it is filled and returned. If the value is set, it is used as a filter.
|
||||
* Returns first matching entry.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in,out] id Priority of the entry.
|
||||
* @param[in,out] fingerprint Fingerprint fo the entry.
|
||||
* @param[in,out] map_type Mapping type of the entry.
|
||||
* @param[in,out] name Specific username for the entry.
|
||||
* @return 0 on success, -1 on not finding any match.
|
||||
*/
|
||||
int nc_server_tls_endpt_get_ctn(const char *endpt_name, uint32_t *id, char **fingerprint, NC_TLS_CTN_MAPTYPE *map_type,
|
||||
char **name);
|
||||
|
||||
/**
|
||||
* @brief Get client certificate.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return Const session client certificate.
|
||||
*/
|
||||
const X509 *nc_session_get_client_cert(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Set TLS authentication additional verify callback.
|
||||
*
|
||||
* Server will always perform cert-to-name based on its configuration. Only after it passes
|
||||
* and this callback is set, it is also called. It should return exactly what OpenSSL
|
||||
* verify callback meaning 1 for success, 0 to deny the user.
|
||||
*
|
||||
* @param[in] verify_clb Additional user verify callback.
|
||||
*/
|
||||
void nc_server_tls_set_verify_clb(int (*verify_clb)(const struct nc_session *session));
|
||||
|
||||
/** @} Server TLS */
|
||||
|
||||
#endif /* NC_ENABLED_TLS */
|
||||
|
||||
/**
|
||||
* @addtogroup server_session
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get session start time.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return Session start time.
|
||||
*/
|
||||
time_t nc_session_get_start_time(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Increase session notification subscription flag count.
|
||||
* Supports multiple subscriptions on one session.
|
||||
*
|
||||
* It is used only to ignore timeouts, because they are
|
||||
* ignored for sessions with active subscriptions.
|
||||
*
|
||||
* @param[in] session Session to modify.
|
||||
*/
|
||||
void nc_session_inc_notif_status(struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Decrease session notification subscription flag count.
|
||||
* Supports multiple subscriptions on one session.
|
||||
*
|
||||
* @param[in] session Session to modify.
|
||||
*/
|
||||
void nc_session_dec_notif_status(struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Get session notification subscription flag.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return 0 for no active subscription, non-zero for an active subscription.
|
||||
*/
|
||||
int nc_session_get_notif_status(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Learn whether a session was created using Call Home or not.
|
||||
* Works only for server sessions.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return 0 if a standard session, non-zero if a Call Home session.
|
||||
*/
|
||||
int nc_session_is_callhome(const struct nc_session *session);
|
||||
|
||||
/** @} Server Session */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NC_SESSION_SERVER_H_ */
|
436
src/session_server_ch.h
Normal file
436
src/session_server_ch.h
Normal file
|
@ -0,0 +1,436 @@
|
|||
/**
|
||||
* @file session_server_ch.h
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 Call Home session server manipulation
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef NC_SESSION_SERVER_CH_H_
|
||||
#define NC_SESSION_SERVER_CH_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "netconf.h"
|
||||
#include "session.h"
|
||||
|
||||
#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS)
|
||||
|
||||
/**
|
||||
* @defgroup server_ch Server-side Call Home
|
||||
* @ingroup server
|
||||
*
|
||||
* @brief Call Home functionality for server-side applications.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Add a new Call Home client.
|
||||
*
|
||||
* @param[in] name Arbitrary unique client name.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_add_client(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Drop any connections, stop connecting and remove a client.
|
||||
*
|
||||
* @param[in] name Client name. NULL matches all the clients.
|
||||
* @return 0 on success, -1 on not finding any match.
|
||||
*/
|
||||
int nc_server_ch_del_client(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Check if a Call Home client exists.
|
||||
*
|
||||
* @param[in] name Client name.
|
||||
* @return 0 if does not exists, non-zero otherwise.
|
||||
*/
|
||||
int nc_server_ch_is_client(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Add a new Call Home client endpoint.
|
||||
*
|
||||
* @param[in] client_name Existing client name.
|
||||
* @param[in] endpt_name Arbitrary unique (within the client) endpoint name.
|
||||
* @param[in] ti Transport protocol to use.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_client_add_endpt(const char *client_name, const char *endpt_name, NC_TRANSPORT_IMPL ti);
|
||||
|
||||
/**
|
||||
* @brief Remove a Call Home client endpoint.
|
||||
*
|
||||
* @param[in] client_name Existing client name.
|
||||
* @param[in] endpt_name Existing endpoint of @p client_name. NULL matches all endpoints.
|
||||
* @param[in] ti Client transport protocol. NULL matches any protocol.
|
||||
* Redundant to set if @p endpt_name is set, client names are
|
||||
* unique disregarding their protocol.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_client_del_endpt(const char *client_name, const char *endpt_name, NC_TRANSPORT_IMPL ti);
|
||||
|
||||
/**
|
||||
* @brief Check if an endpoint of a Call Home client exists.
|
||||
*
|
||||
* @param[in] client_name Client name.
|
||||
* @param[in] endpt_name Endpoint name.
|
||||
* @return 0 if does not exists, non-zero otherwise.
|
||||
*/
|
||||
int nc_server_ch_client_is_endpt(const char *client_name, const char *endpt_name);
|
||||
|
||||
/**
|
||||
* @brief Change Call Home client endpoint listening address.
|
||||
*
|
||||
* On error the previous listening socket (if any) is left untouched.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of @p client_name.
|
||||
* @param[in] address New listening address.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_client_endpt_set_address(const char *client_name, const char *endpt_name, const char *address);
|
||||
|
||||
/**
|
||||
* @brief Change Call Home client endpoint listening port.
|
||||
*
|
||||
* On error the previous listening socket (if any) is left untouched.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of @p client_name.
|
||||
* @param[in] port New listening port.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_client_endpt_set_port(const char *client_name, const char *endpt_name, uint16_t port);
|
||||
|
||||
/**
|
||||
* @brief Change Call Home client endpoint keepalives state. Affects only new connections.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of @p client_name.
|
||||
* @param[in] enable Whether to enable or disable keepalives.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_client_endpt_enable_keepalives(const char *client_name, const char *endpt_name, int enable);
|
||||
|
||||
/**
|
||||
* @brief Change Call Home client endpoint keepalives parameters. Affects only new connections.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of @p client_name.
|
||||
* @param[in] idle_time Keepalive idle time in seconds, 1 by default, -1 to keep previous value.
|
||||
* @param[in] max_probes Keepalive max probes sent, 10 by default, -1 to keep previous value.
|
||||
* @param[in] probe_interval Keepalive probe interval in seconds, 5 by default, -1 to keep previous value.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_client_endpt_set_keepalives(const char *client_name, const char *endpt_name, int idle_time,
|
||||
int max_probes, int probe_interval);
|
||||
|
||||
/**
|
||||
* @brief Set Call Home client connection type.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] conn_type Call Home connection type.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_client_set_conn_type(const char *client_name, NC_CH_CONN_TYPE conn_type);
|
||||
|
||||
/**
|
||||
* @brief Set Call Home client periodic connection period for reconnecting.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] period Call Home periodic connection period in minutes.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_client_periodic_set_period(const char *client_name, uint16_t period);
|
||||
|
||||
/**
|
||||
* @brief Set Call Home client periodic connection period anchor time.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] anchor_time Call Home periodic connection anchor time for the period.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_client_periodic_set_anchor_time(const char *client_name, time_t anchor_time);
|
||||
|
||||
/**
|
||||
* @brief Set Call Home client periodic connection idle timeout.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] idle_timeout Call Home periodic idle timeout.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_client_periodic_set_idle_timeout(const char *client_name, uint16_t idle_timeout);
|
||||
|
||||
/**
|
||||
* @brief Set Call Home client start-with policy.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] start_with Call Home client start-with.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_client_set_start_with(const char *client_name, NC_CH_START_WITH start_with);
|
||||
|
||||
/**
|
||||
* @brief Set Call Home client overall max attempts.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] max_attempts Call Home overall max reconnect attempts.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ch_client_set_max_attempts(const char *client_name, uint8_t max_attempts);
|
||||
|
||||
/**
|
||||
* @brief Establish a Call Home connection with a listening NETCONF client.
|
||||
*
|
||||
* @param[in] client_name Existing client name.
|
||||
* @param[out] session_clb Function that is called for every established session on the client. @p new_session
|
||||
* pointer is internally discarded afterwards. If the callback returns non-zero, the @p new_session is freed.
|
||||
* @return 0 if the thread was successfully created, -1 on error.
|
||||
*/
|
||||
int nc_connect_ch_client_dispatch(const char *client_name,
|
||||
int (*session_clb)(const char *client_name, struct nc_session *new_session));
|
||||
|
||||
/** @} Server-side Call Home */
|
||||
|
||||
#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
|
||||
/**
|
||||
* @defgroup server_ch_ssh Server-side Call Home on SSH
|
||||
* @ingroup server_ch
|
||||
*
|
||||
* @brief SSH settings for the Call Home functionality
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Add Call Home SSH host keys the server will identify itself with. Only the name is set, the key itself
|
||||
* wil be retrieved using a callback.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] name Arbitrary name of the host key.
|
||||
* @param[in] idx Optional index where to add the key. -1 adds at the end.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_ch_client_endpt_add_hostkey(const char *client_name, const char *endpt_name, const char *name, int16_t idx);
|
||||
|
||||
/**
|
||||
* @brief Delete Call Home SSH host keys. Their order is preserved.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] name Name of the host key. NULL matches all the keys, but if @p idx != -1 then this must be NULL.
|
||||
* @param[in] idx Index of the hostkey. -1 matches all indices, but if @p name != NULL then this must be -1.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_ch_client_endpt_del_hostkey(const char *client_name, const char *endpt_name, const char *name, int16_t idx);
|
||||
|
||||
/**
|
||||
* @brief Move Call Home SSH host key.
|
||||
*
|
||||
* @param[in] client_name Exisitng Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] key_mov Name of the host key that will be moved.
|
||||
* @param[in] key_after Name of the key that will preceed @p key_mov. NULL if @p key_mov is to be moved at the beginning.
|
||||
* @return 0 in success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_ch_client_endpt_mov_hostkey(const char *client_name, const char *endpt_name, const char *key_mov,
|
||||
const char *key_after);
|
||||
|
||||
/**
|
||||
* @brief Set accepted Call Home SSH authentication methods. All (publickey, password, interactive)
|
||||
* are supported by default.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] auth_methods Accepted authentication methods bit field of NC_SSH_AUTH_TYPE.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_ch_client_endpt_set_auth_methods(const char *client_name, const char *endpt_name, int auth_methods);
|
||||
|
||||
/**
|
||||
* @brief Get accepted Call Home SSH authentication methods.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @return Accepted authentication methods bit field of NC_SSH_AUTH_TYPE.
|
||||
*/
|
||||
int nc_server_ssh_ch_client_endpt_get_auth_methods(const char *client_name, const char *endpt_name);
|
||||
|
||||
/**
|
||||
* @brief Set Call Home SSH authentication attempts of every client. 3 by default.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] auth_attempts Failed authentication attempts before a client is dropped.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_ch_client_endpt_set_auth_attempts(const char *client_name, const char *endpt_name, uint16_t auth_attempts);
|
||||
|
||||
/**
|
||||
* @brief Set Call Home SSH authentication timeout. 30 seconds by default.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] auth_timeout Number of seconds before an unauthenticated client is dropped.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_ssh_ch_client_endpt_set_auth_timeout(const char *client_name, const char *endpt_name, uint16_t auth_timeout);
|
||||
|
||||
/** @} Server-side Call Home on SSH */
|
||||
|
||||
#endif /* NC_ENABLED_SSH */
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
|
||||
/**
|
||||
* @defgroup server_ch_tls Server-side Call Home on TLS
|
||||
* @ingroup server_ch
|
||||
*
|
||||
* @brief TLS settings for the Call Home functionality
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set the server Call Home TLS certificate. Only the name is set, the certificate itself
|
||||
* wil be retrieved using a callback.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] name Arbitrary certificate name.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_tls_ch_client_endpt_set_server_cert(const char *client_name, const char *endpt_name, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Add a Call Home trusted certificate list. Can be both a CA or a client one.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] name Arbitary name identifying this certificate list.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_tls_ch_client_endpt_add_trusted_cert_list(const char *client_name, const char *endpt_name, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Remove a set Call Home trusted certificate list. CRLs and CTN entries are not affected.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] name Name of the certificate list to delete. NULL deletes all the lists.
|
||||
* @return 0 on success, -1 on not found.
|
||||
*/
|
||||
int nc_server_tls_ch_client_endpt_del_trusted_cert_list(const char *client_name, const char *endpt_name, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Set trusted Call Home Certificate Authority certificate locations. There
|
||||
* can only be one file and one directory, they are replaced if already set.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] ca_file Path to a trusted CA cert store file in PEM format.
|
||||
* Can be NULL.
|
||||
* @param[in] ca_dir Path to a trusted CA cert store hashed directory
|
||||
* (c_rehash utility can be used to create hashes)
|
||||
* with PEM files. Can be NULL.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_tls_ch_client_endpt_set_trusted_ca_paths(const char *client_name, const char *endpt_name, const char *ca_file,
|
||||
const char *ca_dir);
|
||||
|
||||
/**
|
||||
* @brief Set Call Home Certificate Revocation List locations. There can only be
|
||||
* one file and one directory, they are replaced if already set.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] crl_file Path to a CRL store file in PEM format. Can be NULL.
|
||||
* @param[in] crl_dir Path to a CRL store hashed directory (c_rehash utility
|
||||
* can be used to create hashes) with PEM files. Can be NULL.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_tls_ch_client_endpt_set_crl_paths(const char *client_name, const char *endpt_name, const char *crl_file,
|
||||
const char *crl_dir);
|
||||
|
||||
/**
|
||||
* @brief Destroy and clean Call Home CRLs. Call Home certificates, private keys,
|
||||
* and CTN entries are not affected.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
*/
|
||||
void nc_server_tls_ch_client_endpt_clear_crls(const char *client_name, const char *endpt_name);
|
||||
|
||||
/**
|
||||
* @brief Add a cert-to-name entry.
|
||||
*
|
||||
* It is possible to add an entry step-by-step, specifying first only @p ip and in later calls
|
||||
* @p fingerprint, @p map_type, and optionally @p name spearately.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] id Priority of the entry. It must be unique. If already exists, the entry with this id
|
||||
* is modified.
|
||||
* @param[in] fingerprint Matching certificate fingerprint. If NULL, kept temporarily unset.
|
||||
* @param[in] map_type Type of username-certificate mapping. If 0, kept temporarily unset.
|
||||
* @param[in] name Specific username used only if @p map_type == NC_TLS_CTN_SPECIFED.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_tls_ch_client_endpt_add_ctn(const char *client_name, const char *endpt_name, uint32_t id,
|
||||
const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Remove a Call Home cert-to-name entry.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in] id Priority of the entry. -1 matches all the priorities.
|
||||
* @param[in] fingerprint Fingerprint fo the entry. NULL matches all the fingerprints.
|
||||
* @param[in] map_type Mapping type of the entry. 0 matches all the mapping types.
|
||||
* @param[in] name Specific username for the entry. NULL matches all the usernames.
|
||||
* @return 0 on success, -1 on not finding any match.
|
||||
*/
|
||||
int nc_server_tls_ch_client_endpt_del_ctn(const char *client_name, const char *endpt_name, int64_t id,
|
||||
const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Get a Call Home cert-to-name entry.
|
||||
*
|
||||
* If a parameter is NULL, it is ignored. If its dereferenced value is NULL,
|
||||
* it is filled and returned. If the value is set, it is used as a filter.
|
||||
* Returns first matching entry.
|
||||
*
|
||||
* @param[in] client_name Existing Call Home client name.
|
||||
* @param[in] endpt_name Existing endpoint name of the client.
|
||||
* @param[in,out] id Priority of the entry.
|
||||
* @param[in,out] fingerprint Fingerprint fo the entry.
|
||||
* @param[in,out] map_type Mapping type of the entry.
|
||||
* @param[in,out] name Specific username for the entry.
|
||||
* @return 0 on success, -1 on not finding any match.
|
||||
*/
|
||||
int nc_server_tls_ch_client_endpt_get_ctn(const char *client_name, const char *endpt_name, uint32_t *id, char **fingerprint,
|
||||
NC_TLS_CTN_MAPTYPE *map_type, char **name);
|
||||
|
||||
/** @} Server-side Call Home on TLS */
|
||||
|
||||
#endif /* NC_ENABLED_TLS */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NC_SESSION_SERVER_CH_H_ */
|
1709
src/session_server_ssh.c
Normal file
1709
src/session_server_ssh.c
Normal file
File diff suppressed because it is too large
Load diff
2005
src/session_server_tls.c
Normal file
2005
src/session_server_tls.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue