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
213
.github/workflows/ci.yml
vendored
Normal file
213
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,213 @@
|
|||
name: libnetconf2 CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- devel
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- devel
|
||||
|
||||
env:
|
||||
DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev
|
||||
|
||||
jobs:
|
||||
git-branch:
|
||||
name: Get git branch
|
||||
runs-on: ubuntu-18.04
|
||||
outputs:
|
||||
branch-name: ${{ steps.get-git-branch.outputs.branch-name }}
|
||||
steps:
|
||||
- id: get-git-branch
|
||||
run: |
|
||||
if ${{ github.event_name == 'push' }}
|
||||
then export GIT_BRANCH=`echo ${{ github.ref }} | cut -d'/' -f 3`
|
||||
else
|
||||
export GIT_BRANCH=${{ github.base_ref }}
|
||||
fi
|
||||
echo "::set-output name=branch-name::$GIT_BRANCH"
|
||||
|
||||
build:
|
||||
name: ${{ matrix.config.name }}
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
needs: git-branch
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- {
|
||||
name: "Release, Ubuntu 18.04, gcc",
|
||||
os: "ubuntu-18.04",
|
||||
build-type: "Release",
|
||||
dep-build-type: "Release",
|
||||
cc: "gcc",
|
||||
options: "-DENABLE_TESTS=ON -DENABLE_DNSSEC=ON",
|
||||
packages: "",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "Release, Ubuntu 18.04, clang",
|
||||
os: "ubuntu-18.04",
|
||||
build-type: "Release",
|
||||
dep-build-type: "Release",
|
||||
cc: "clang",
|
||||
options: "-DENABLE_TESTS=ON -DENABLE_DNSSEC=ON",
|
||||
packages: "",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "Debug, Ubuntu 18.04, gcc",
|
||||
os: "ubuntu-18.04",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Release",
|
||||
cc: "gcc",
|
||||
options: "-DENABLE_DNSSEC=ON",
|
||||
packages: "valgrind",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "Debug, Ubuntu 18.04, clang",
|
||||
os: "ubuntu-18.04",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Release",
|
||||
cc: "clang",
|
||||
options: "-DENABLE_DNSSEC=ON",
|
||||
packages: "valgrind",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "SSH Only",
|
||||
os: "ubuntu-18.04",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Release",
|
||||
cc: "gcc",
|
||||
options: "-DENABLE_TLS=OFF -DENABLE_SSH=ON",
|
||||
packages: "valgrind",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "TLS Only",
|
||||
os: "ubuntu-18.04",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Release",
|
||||
cc: "gcc",
|
||||
options: "-DENABLE_TLS=ON -DENABLE_SSH=OFF",
|
||||
packages: "valgrind",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "No SSH nor TLS",
|
||||
os: "ubuntu-18.04",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Release",
|
||||
cc: "gcc",
|
||||
options: "-DENABLE_TLS=OFF -DENABLE_SSH=OFF",
|
||||
packages: "valgrind",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "ASAN and UBSAN",
|
||||
os: "ubuntu-18.04",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Release",
|
||||
cc: "clang",
|
||||
options: "-DCMAKE_C_FLAGS=-fsanitize=address,undefined -DENABLE_VALGRIND_TESTS=OFF",
|
||||
packages: "",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "ABI Check",
|
||||
os: "ubuntu-latest",
|
||||
build-type: "ABICheck",
|
||||
dep-build-type: "Debug",
|
||||
cc: "gcc",
|
||||
options: "",
|
||||
packages: "abi-dumper abi-compliance-checker snap",
|
||||
snaps: "core universal-ctags",
|
||||
make-prepend: "",
|
||||
make-target: "abi-check"
|
||||
}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Deps-packages
|
||||
shell: bash
|
||||
run: |
|
||||
sudo add-apt-repository ppa:kedazo/libssh-0.7.x -y
|
||||
sudo apt-get update
|
||||
sudo apt-get install $DEFAULT_PACKAGES ${{ matrix.config.packages }}
|
||||
if ${{ matrix.config.snaps != '' }}
|
||||
then sudo snap refresh; sudo snap install ${{ matrix.config.snaps }}
|
||||
fi
|
||||
|
||||
- name: Deps-uncrustify
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
git clone --branch uncrustify-0.71.0 https://github.com/uncrustify/uncrustify
|
||||
cd uncrustify
|
||||
mkdir build
|
||||
cd build
|
||||
CC=${{ matrix.config.cc }} cmake ..
|
||||
make
|
||||
sudo make install
|
||||
if: ${{ matrix.config.name == 'Debug, Ubuntu 18.04, gcc' }}
|
||||
|
||||
- name: Deps-libyang
|
||||
shell: bash
|
||||
run: |
|
||||
git clone -b ${{needs.git-branch.outputs.branch-name}} https://github.com/CESNET/libyang.git
|
||||
cd libyang
|
||||
mkdir build
|
||||
cd build
|
||||
CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.dep-build-type }} -DENABLE_BUILD_TESTS=OFF ..
|
||||
make -j2
|
||||
sudo make install
|
||||
|
||||
- name: Deps-libval
|
||||
shell: bash
|
||||
run: |
|
||||
git clone https://github.com/DNSSEC-Tools/DNSSEC-Tools.git dnssec-tools
|
||||
cd dnssec-tools/dnssec-tools/validator
|
||||
./configure
|
||||
make -j2
|
||||
sudo make install
|
||||
|
||||
- name: Configure
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.build-type }} ${{ matrix.config.options }} ..
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/build
|
||||
run: |
|
||||
export LC_ALL=C.UTF-8
|
||||
export PATH=/snap/bin:${{ github.workspace }}/coverity-tools/bin:$PATH
|
||||
${{ matrix.config.make-prepend }} make ${{ matrix.config.make-target }}
|
||||
|
||||
- name: Test
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/build
|
||||
run: ctest --output-on-failure
|
145
.github/workflows/devel-push.yml
vendored
Normal file
145
.github/workflows/devel-push.yml
vendored
Normal file
|
@ -0,0 +1,145 @@
|
|||
name: libnetconf2 devel push
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- devel
|
||||
|
||||
env:
|
||||
DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev
|
||||
COVERITY_PROJECT: CESNET%2Flibnetconf2
|
||||
|
||||
jobs:
|
||||
git-branch:
|
||||
name: Get git branch
|
||||
runs-on: ubuntu-18.04
|
||||
outputs:
|
||||
branch-name: ${{ steps.get-git-branch.outputs.branch-name }}
|
||||
steps:
|
||||
- id: get-git-branch
|
||||
run: |
|
||||
if ${{ github.event_name == 'push' }}
|
||||
then export GIT_BRANCH=`echo ${{ github.ref }} | cut -d'/' -f 3`
|
||||
else
|
||||
export GIT_BRANCH=${{ github.base_ref }}
|
||||
fi
|
||||
echo "::set-output name=branch-name::$GIT_BRANCH"
|
||||
|
||||
build:
|
||||
name: ${{ matrix.config.name }}
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
needs: git-branch
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- {
|
||||
name: "Coverity",
|
||||
os: "ubuntu-latest",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Debug",
|
||||
cc: "clang",
|
||||
options: "-DENABLE_DNSSEC=ON",
|
||||
packages: "",
|
||||
snaps: "",
|
||||
make-prepend: "cov-build --dir cov-int",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "Codecov",
|
||||
os: "ubuntu-latest",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Debug",
|
||||
cc: "gcc",
|
||||
options: "-DENABLE_COVERAGE=ON -DENABLE_DNSSEC=ON",
|
||||
packages: "lcov",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Deps-packages
|
||||
shell: bash
|
||||
run: |
|
||||
sudo add-apt-repository ppa:kedazo/libssh-0.7.x -y
|
||||
sudo apt-get update
|
||||
sudo apt-get install $DEFAULT_PACKAGES ${{ matrix.config.packages }}
|
||||
if ${{ matrix.config.snaps != '' }}
|
||||
then sudo snap install ${{ matrix.config.snaps }}
|
||||
fi
|
||||
|
||||
- name: Deps-coverity
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
wget -q https://scan.coverity.com/download/linux64 --post-data "token=$TOKEN&project=$COVERITY_PROJECT" -O coverity-tools.tar.gz
|
||||
mkdir coverity-tools
|
||||
tar xzf coverity-tools.tar.gz --strip 1 -C coverity-tools
|
||||
env:
|
||||
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
if: ${{ matrix.config.name == 'Coverity' }}
|
||||
|
||||
- name: Deps-libyang
|
||||
shell: bash
|
||||
run: |
|
||||
git clone -b ${{needs.git-branch.outputs.branch-name}} https://github.com/CESNET/libyang.git
|
||||
cd libyang
|
||||
mkdir build
|
||||
cd build
|
||||
CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.dep-build-type }} -DENABLE_BUILD_TESTS=OFF ..
|
||||
make -j2
|
||||
sudo make install
|
||||
|
||||
- name: Deps-libval
|
||||
shell: bash
|
||||
run: |
|
||||
git clone https://github.com/DNSSEC-Tools/DNSSEC-Tools.git dnssec-tools
|
||||
cd dnssec-tools/dnssec-tools/validator
|
||||
./configure
|
||||
make -j2
|
||||
sudo make install
|
||||
|
||||
- name: Configure
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.build-type }} ${{ matrix.config.options }} ..
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/build
|
||||
run: |
|
||||
export LC_ALL=C.UTF-8
|
||||
export PATH=/snap/bin:${{ github.workspace }}/coverity-tools/bin:$PATH
|
||||
${{ matrix.config.make-prepend }} make ${{ matrix.config.make-target }}
|
||||
|
||||
- name: Test
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/build
|
||||
run: ctest --output-on-failure
|
||||
|
||||
- name: Upload to Coverity.com
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/build
|
||||
run: |
|
||||
tar czvf libnetconf2.tgz cov-int
|
||||
curl \
|
||||
--form token=$TOKEN \
|
||||
--form email=mvasko@cesnet.cz \
|
||||
--form file=@libnetconf2.tgz \
|
||||
--form version="`grep Version ./libnetconf2.pc | cut -d' ' -f 2`" \
|
||||
--form description="libnetconf2 NETCONF library" \
|
||||
https://scan.coverity.com/builds?project=$COVERITY_PROJECT
|
||||
env:
|
||||
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
if: ${{ matrix.config.name == 'Coverity' }}
|
||||
|
||||
- name: Upload to Codecov.io
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/build
|
||||
run: bash <(curl -s https://codecov.io/bash)
|
||||
if: ${{ matrix.config.name == 'Codecov' }}
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/pkg
|
19
.lgtm.yml
Normal file
19
.lgtm.yml
Normal file
|
@ -0,0 +1,19 @@
|
|||
extraction:
|
||||
cpp:
|
||||
prepare:
|
||||
packages: libpcre2-dev
|
||||
after_prepare:
|
||||
- cd $LGTM_WORKSPACE
|
||||
- git clone -b devel https://github.com/CESNET/libyang.git
|
||||
- cd libyang; mkdir build; cd build
|
||||
- cmake -DCMAKE_INSTALL_PREFIX=$LGTM_WORKSPACE -DENABLE_BUILD_TESTS=OFF ..
|
||||
- make -j2
|
||||
- make install
|
||||
configure:
|
||||
command:
|
||||
- mkdir build; cd build
|
||||
- cmake -DCMAKE_INCLUDE_PATH=$LGTM_WORKSPACE/include -DCMAKE_LIBRARY_PATH=$LGTM_WORKSPACE/lib ..
|
||||
index:
|
||||
build_command:
|
||||
- cd build
|
||||
- make -j2
|
341
CMakeLists.txt
Normal file
341
CMakeLists.txt
Normal file
|
@ -0,0 +1,341 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
project(libnetconf2 C)
|
||||
|
||||
# include custom Modules
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeModules/")
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckCSourceCompiles)
|
||||
include(CheckIncludeFile)
|
||||
include(UseCompat)
|
||||
include(ABICheck)
|
||||
include(SourceFormat)
|
||||
include(GenDoc)
|
||||
include(GenCoverage)
|
||||
|
||||
if(POLICY CMP0075)
|
||||
cmake_policy(SET CMP0075 NEW)
|
||||
endif()
|
||||
|
||||
set(LIBNETCONF2_DESCRIPTION "NETCONF server and client library in C.")
|
||||
|
||||
# check the supported platform
|
||||
if(NOT UNIX)
|
||||
message(FATAL_ERROR "Only *nix like systems are supported.")
|
||||
endif()
|
||||
|
||||
# osx specific
|
||||
set(CMAKE_MACOSX_RPATH TRUE)
|
||||
|
||||
# set default build type if not specified by user
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
# see https://github.com/CESNET/libyang/pull/1692 for why CMAKE_C_FLAGS_<type> are not used directly
|
||||
# normalize build type string
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" BUILD_TYPE_UPPER)
|
||||
if ("${BUILD_TYPE_UPPER}" STREQUAL "RELEASE")
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build Type" FORCE)
|
||||
set(CMAKE_C_FLAGS "-DNDEBUG -O2 ${CMAKE_C_FLAGS}")
|
||||
elseif("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG")
|
||||
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build Type" FORCE)
|
||||
set(CMAKE_C_FLAGS "-g -O0 ${CMAKE_C_FLAGS}")
|
||||
elseif("${BUILD_TYPE_UPPER}" STREQUAL "RELWITHDEBINFO")
|
||||
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Build Type" FORCE)
|
||||
elseif("${BUILD_TYPE_UPPER}" STREQUAL "RELWITHDEBUG")
|
||||
set(CMAKE_BUILD_TYPE "RelWithDebug" CACHE STRING "Build Type" FORCE)
|
||||
elseif("${BUILD_TYPE_UPPER}" STREQUAL "ABICHECK")
|
||||
set(CMAKE_BUILD_TYPE "ABICheck" CACHE STRING "Build Type" FORCE)
|
||||
set(CMAKE_C_FLAGS "-g -Og ${CMAKE_C_FLAGS}")
|
||||
elseif("${BUILD_TYPE_UPPER}" STREQUAL "DOCONLY")
|
||||
set(CMAKE_BUILD_TYPE "DocOnly" CACHE STRING "Build Type" FORCE)
|
||||
endif()
|
||||
|
||||
# Version of the project
|
||||
# Generic version of not only the library. Major version is reserved for really big changes of the project,
|
||||
# minor version changes with added functionality (new tool, functionality of the tool or library, ...) and
|
||||
# micro version is changed with a set of small changes or bugfixes anywhere in the project.
|
||||
set(LIBNETCONF2_MAJOR_VERSION 2)
|
||||
set(LIBNETCONF2_MINOR_VERSION 0)
|
||||
set(LIBNETCONF2_MICRO_VERSION 24)
|
||||
set(LIBNETCONF2_VERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION}.${LIBNETCONF2_MICRO_VERSION})
|
||||
|
||||
# Version of the library
|
||||
# Major version is changed with every backward non-compatible API/ABI change in libyang, minor version changes
|
||||
# with backward compatible change and micro version is connected with any internal change of the library.
|
||||
set(LIBNETCONF2_MAJOR_SOVERSION 2)
|
||||
set(LIBNETCONF2_MINOR_SOVERSION 1)
|
||||
set(LIBNETCONF2_MICRO_SOVERSION 20)
|
||||
set(LIBNETCONF2_SOVERSION_FULL ${LIBNETCONF2_MAJOR_SOVERSION}.${LIBNETCONF2_MINOR_SOVERSION}.${LIBNETCONF2_MICRO_SOVERSION})
|
||||
set(LIBNETCONF2_SOVERSION ${LIBNETCONF2_MAJOR_SOVERSION})
|
||||
|
||||
# libyang SO version required
|
||||
set(LIBYANG_DEP_SOVERSION_MAJOR 2)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fvisibility=hidden -std=gnu99")
|
||||
|
||||
#
|
||||
# options
|
||||
#
|
||||
if(("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG") OR ("${BUILD_TYPE_UPPER}" STREQUAL "RELWITHDEBINFO"))
|
||||
option(ENABLE_TESTS "Build tests" ON)
|
||||
option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" ON)
|
||||
else()
|
||||
option(ENABLE_TESTS "Build tests" OFF)
|
||||
option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" OFF)
|
||||
endif()
|
||||
option(ENABLE_COVERAGE "Build code coverage report from tests" OFF)
|
||||
option(ENABLE_SSH "Enable NETCONF over SSH support (via libssh)" ON)
|
||||
option(ENABLE_TLS "Enable NETCONF over TLS support (via OpenSSL)" ON)
|
||||
option(ENABLE_DNSSEC "Enable support for SSHFP retrieval using DNSSEC for SSH (requires OpenSSL and libval)" OFF)
|
||||
set(READ_INACTIVE_TIMEOUT 20 CACHE STRING "Maximum number of seconds waiting for new data once some data have arrived")
|
||||
set(READ_ACTIVE_TIMEOUT 300 CACHE STRING "Maximum number of seconds for receiving a full message")
|
||||
set(MAX_PSPOLL_THREAD_COUNT 6 CACHE STRING "Maximum number of threads that could simultaneously access a ps_poll structure")
|
||||
set(TIMEOUT_STEP 100 CACHE STRING "Number of microseconds tasks are repeated until timeout elapses")
|
||||
set(YANG_MODULE_DIR "${CMAKE_INSTALL_PREFIX}/share/yang/modules" CACHE STRING "Directory with common YANG modules")
|
||||
|
||||
#
|
||||
# sources
|
||||
#
|
||||
set(libsrc
|
||||
src/io.c
|
||||
src/log.c
|
||||
src/messages_client.c
|
||||
src/messages_server.c
|
||||
src/session.c
|
||||
src/session_client.c
|
||||
src/session_server.c)
|
||||
|
||||
if(ENABLE_SSH)
|
||||
list(APPEND libsrc
|
||||
src/session_client_ssh.c
|
||||
src/session_server_ssh.c)
|
||||
set(SSH_MACRO "#ifndef NC_ENABLED_SSH\n#define NC_ENABLED_SSH\n#endif")
|
||||
endif()
|
||||
|
||||
if(ENABLE_TLS)
|
||||
list(APPEND libsrc
|
||||
src/session_client_tls.c
|
||||
src/session_server_tls.c)
|
||||
set(TLS_MACRO "#ifndef NC_ENABLED_TLS\n#define NC_ENABLED_TLS\n#endif")
|
||||
endif()
|
||||
|
||||
set(headers
|
||||
src/log.h
|
||||
src/netconf.h
|
||||
src/session.h
|
||||
src/messages_client.h
|
||||
src/messages_server.h
|
||||
src/session_client.h
|
||||
src/session_client_ch.h
|
||||
src/session_server.h
|
||||
src/session_server_ch.h)
|
||||
|
||||
# files to generate doxygen from
|
||||
set(doxy_files
|
||||
src/libnetconf.h
|
||||
src/log.h
|
||||
src/netconf.h
|
||||
src/session.h
|
||||
src/messages_client.h
|
||||
src/messages_server.h
|
||||
src/session_client.h
|
||||
src/session_client_ch.h
|
||||
src/session_server.h
|
||||
src/session_server_ch.h)
|
||||
|
||||
# source files to be covered by the 'format' target
|
||||
set(format_sources
|
||||
compat/*.c
|
||||
compat/*.h*
|
||||
src/*.c
|
||||
src/*.h
|
||||
tests/*.c
|
||||
tests/client/*.c)
|
||||
|
||||
#
|
||||
# checks
|
||||
#
|
||||
if(ENABLE_DNSSEC AND NOT ENABLE_SSH)
|
||||
message(WARNING "DNSSEC SSHFP retrieval cannot be used without SSH support.")
|
||||
set(ENABLE_DNSSEC OFF)
|
||||
endif()
|
||||
|
||||
if(ENABLE_VALGRIND_TESTS)
|
||||
find_program(VALGRIND_FOUND valgrind)
|
||||
if(NOT VALGRIND_FOUND)
|
||||
message(WARNING "valgrind executable not found! Disabling memory leaks tests.")
|
||||
set(ENABLE_VALGRIND_TESTS OFF)
|
||||
else()
|
||||
set(ENABLE_TESTS ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
find_package(CMocka 1.0.1)
|
||||
if(NOT CMOCKA_FOUND)
|
||||
message(STATUS "Disabling tests because of missing CMocka")
|
||||
set(ENABLE_TESTS OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_COVERAGE)
|
||||
gen_coverage_enable(${ENABLE_TESTS})
|
||||
endif()
|
||||
|
||||
if ("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG")
|
||||
source_format_enable()
|
||||
endif()
|
||||
|
||||
if("${BUILD_TYPE_UPPER}" STREQUAL "DOCONLY")
|
||||
gen_doc("${doxy_files}" ${LIBNETCONF2_VERSION} ${LIBNETCONF2_DESCRIPTION} "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
#
|
||||
# targets
|
||||
#
|
||||
|
||||
# use compat
|
||||
use_compat()
|
||||
|
||||
# netconf2 target
|
||||
add_library(netconf2 SHARED ${libsrc} ${compatsrc})
|
||||
set_target_properties(netconf2 PROPERTIES VERSION ${LIBNETCONF2_SOVERSION_FULL} SOVERSION ${LIBNETCONF2_SOVERSION})
|
||||
|
||||
# include repository files with highest priority
|
||||
include_directories(${PROJECT_BINARY_DIR}/src)
|
||||
|
||||
# dependencies - pthread
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(netconf2 ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
# check availability for some pthread functions
|
||||
set(CMAKE_REQUIRED_LIBRARIES pthread)
|
||||
check_function_exists(pthread_rwlockattr_setkind_np HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP)
|
||||
|
||||
# dependencies - openssl
|
||||
if(ENABLE_TLS OR ENABLE_DNSSEC OR ENABLE_SSH)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
if(ENABLE_TLS)
|
||||
message(STATUS "OpenSSL found, required for TLS")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_ENABLED_TLS")
|
||||
endif()
|
||||
if(OPENSSL_VERSION VERSION_LESS 1.1.1)
|
||||
message(WARNING "OpenSSL version ${OPENSSL_VERSION} is no longer maintained, consider an update.")
|
||||
endif()
|
||||
|
||||
target_link_libraries(netconf2 ${OPENSSL_LIBRARIES})
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
# dependencies - libssh
|
||||
if(ENABLE_SSH)
|
||||
find_package(LibSSH 0.7.1 REQUIRED)
|
||||
if(LIBSSH_VERSION VERSION_EQUAL 0.9.3 OR LIBSSH_VERSION VERSION_EQUAL 0.9.4)
|
||||
message(FATAL_ERROR "LibSSH ${LIBSSH_VERSION} includes regression bugs and libnetconf2 will NOT work properly, try to use another version")
|
||||
endif()
|
||||
|
||||
target_link_libraries(netconf2 ${LIBSSH_LIBRARIES})
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBSSH_LIBRARIES})
|
||||
include_directories(${LIBSSH_INCLUDE_DIRS})
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_ENABLED_SSH")
|
||||
|
||||
# crypt
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "QNX")
|
||||
target_link_libraries(netconf2 -lcrypt)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES crypt)
|
||||
else()
|
||||
target_link_libraries(netconf2 -llogin)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES login)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# dependencies - libval
|
||||
if(ENABLE_DNSSEC)
|
||||
find_package(LibVAL REQUIRED)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_DNSSEC")
|
||||
target_link_libraries(netconf2 ${LIBVAL_LIBRARIES})
|
||||
include_directories(${LIBVAL_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
# dependencies - libyang
|
||||
find_package(LibYANG ${LIBYANG_DEP_SOVERSION_MAJOR} REQUIRED)
|
||||
target_link_libraries(netconf2 ${LIBYANG_LIBRARIES})
|
||||
include_directories(${LIBYANG_INCLUDE_DIRS})
|
||||
|
||||
# header file compatibility - shadow.h and crypt.h
|
||||
check_include_file("shadow.h" HAVE_SHADOW)
|
||||
check_include_file("crypt.h" HAVE_CRYPT)
|
||||
|
||||
# function compatibility - getpeereid on QNX
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "QNX")
|
||||
target_link_libraries(netconf2 -lsocket)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES socket)
|
||||
list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES pthread)
|
||||
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_QNX_SOURCE)
|
||||
check_symbol_exists(getpeereid "sys/types.h;unistd.h" HAVE_GETPEEREID)
|
||||
list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_QNX_SOURCE)
|
||||
endif()
|
||||
|
||||
# generate files
|
||||
configure_file("${PROJECT_SOURCE_DIR}/src/config.h.in" "${PROJECT_BINARY_DIR}/src/config.h" ESCAPE_QUOTES @ONLY)
|
||||
configure_file(nc_client.h.in nc_client.h)
|
||||
configure_file(nc_server.h.in nc_server.h)
|
||||
|
||||
# install library
|
||||
install(TARGETS netconf2 DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
# install headers
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/nc_client.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/nc_server.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(FILES ${headers} ${PROJECT_BINARY_DIR}/src/config.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libnetconf2)
|
||||
|
||||
# install pkg-config file
|
||||
find_package(PkgConfig)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
configure_file("libnetconf2.pc.in" "libnetconf2.pc" @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libnetconf2.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
# check that pkg-config includes the used path
|
||||
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable pc_path pkg-config RESULT_VARIABLE RETURN OUTPUT_VARIABLE PC_PATH ERROR_QUIET)
|
||||
if(RETURN EQUAL 0)
|
||||
string(REGEX MATCH "${CMAKE_INSTALL_LIBDIR}/pkgconfig" SUBSTR "${PC_PATH}")
|
||||
string(LENGTH "${SUBSTR}" SUBSTR_LEN)
|
||||
if(SUBSTR_LEN EQUAL 0)
|
||||
message(WARNING "pkg-config will not detect the new package after installation, adjust PKG_CONFIG_PATH using \"export PKG_CONFIG_PATH=\${PKG_CONFIG_PATH}:${CMAKE_INSTALL_LIBDIR}/pkgconfig\".")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# tests
|
||||
if(ENABLE_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
# create coverage target for generating coverage reports
|
||||
gen_coverage("test_.*" "test_.*_valgrind")
|
||||
|
||||
# generate doxygen documentation for libnetconf2 API
|
||||
gen_doc("${doxy_files}" ${LIBNETCONF2_VERSION} ${LIBNETCONF2_DESCRIPTION} "")
|
||||
|
||||
# generate API/ABI report
|
||||
if ("${BUILD_TYPE_UPPER}" STREQUAL "ABICHECK")
|
||||
lib_abi_check(netconf2 "${headers}" ${LIBNETCONF2_SOVERSION_FULL} e7402149e5b36de7acab2e38970a3a9d6a8165d5)
|
||||
endif()
|
||||
|
||||
# source files to be covered by the 'format' target and a test with 'format-check' target
|
||||
source_format(${format_sources})
|
||||
|
||||
# clean cmake cache
|
||||
add_custom_target(cleancache
|
||||
COMMAND make clean
|
||||
COMMAND find . -iname '*cmake*' -not -name CMakeLists.txt -exec rm -rf {} +
|
||||
COMMAND rm -rf Makefile Doxyfile
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
# uninstall
|
||||
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_MODULE_PATH}/uninstall.cmake")
|
66
CMakeModules/ABICheck.cmake
Normal file
66
CMakeModules/ABICheck.cmake
Normal file
|
@ -0,0 +1,66 @@
|
|||
# generate API/ABI report
|
||||
macro(LIB_ABI_CHECK LIB_TARGET LIB_HEADERS LIB_SOVERSION_FULL ABI_BASE_HASH)
|
||||
# get short hash
|
||||
string(SUBSTRING "${ABI_BASE_HASH}" 0 8 ABI_BASE_HASH_SHORT)
|
||||
|
||||
# find abi-dumper
|
||||
find_program(ABI_DUMPER abi-dumper)
|
||||
find_package_handle_standard_args(abi-dumper DEFAULT_MSG ABI_DUMPER)
|
||||
if(NOT ABI_DUMPER)
|
||||
message(FATAL_ERROR "Program abi-dumper not found!")
|
||||
endif()
|
||||
|
||||
# find abi-checker
|
||||
find_program(ABI_CHECKER abi-compliance-checker)
|
||||
find_package_handle_standard_args(abi-compliance-checker DEFAULT_MSG ABI_CHECKER)
|
||||
if(NOT ABI_CHECKER)
|
||||
message(FATAL_ERROR "Program abi-compliance-checker not found!")
|
||||
endif()
|
||||
|
||||
# abi-dump target - generating an ABI dump
|
||||
set(PUBLIC_HEADERS ${LIB_HEADERS})
|
||||
string(PREPEND PUBLIC_HEADERS "${CMAKE_SOURCE_DIR}/")
|
||||
string(REPLACE ";" "\n${CMAKE_SOURCE_DIR}/" PUBLIC_HEADERS "${PUBLIC_HEADERS}")
|
||||
file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/public_headers CONTENT "${PUBLIC_HEADERS}")
|
||||
add_custom_target(abi-dump
|
||||
COMMAND ${ABI_DUMPER} ./lib${LIB_TARGET}${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
-o lib${LIB_TARGET}.${LIB_SOVERSION_FULL}.dump
|
||||
-lver ${LIB_SOVERSION_FULL} -public-headers ${CMAKE_BINARY_DIR}/public_headers
|
||||
DEPENDS ${LIB_TARGET}
|
||||
BYPRODUCTS ${CMAKE_BINARY_DIR}/lib${LIB_TARGET}.${LIB_SOVERSION_FULL}.dump
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
COMMENT "Dumping ABI information of version ${LIB_SOVERSION_FULL} for abi-check")
|
||||
|
||||
# get URL for fetching origin
|
||||
execute_process(COMMAND git remote get-url origin OUTPUT_VARIABLE ORIGIN_URL OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
# generate script for generating the base ABI dump
|
||||
file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/abibase.sh CONTENT "#!/bin/sh
|
||||
if [ ! -d abibase ]; then mkdir abibase; fi
|
||||
cd abibase
|
||||
if [ ! -f build/lib${LIB_TARGET}.*.dump ]; then
|
||||
if [ -d .git ] && [ \"${ABI_BASE_HASH}\" != \"`git log --pretty=oneline | cut -d' ' -f1`\" ]; then rm -rf .* 2> /dev/null; fi
|
||||
if [ ! -d .git ]; then
|
||||
git init --initial-branch=master
|
||||
git remote add origin ${ORIGIN_URL}
|
||||
git fetch origin --depth 1 ${ABI_BASE_HASH}
|
||||
git reset --hard FETCH_HEAD
|
||||
fi
|
||||
if [ ! -d build ]; then mkdir build; fi
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=ABICheck ..
|
||||
make abi-dump
|
||||
fi
|
||||
")
|
||||
|
||||
# abi-check target - check ABI compatibility of current version and the base hash version
|
||||
add_custom_target(abi-check
|
||||
COMMAND bash ./abibase.sh
|
||||
COMMAND ${ABI_CHECKER} -l lib${LIB_TARGET}${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
-old abibase/build/lib${LIB_TARGET}.*.dump
|
||||
-new ./lib${LIB_TARGET}.${LIB_SOVERSION_FULL}.dump -s
|
||||
DEPENDS ${LIB_TARGET} abi-dump
|
||||
BYPRODUCTS ${CMAKE_BINARY_DIR}/compat_reports/lib${LIB_TARGET}${CMAKE_SHARED_LIBRARY_SUFFIX}/*_to_${LIB_SOVERSION_FULL}/compat_report.html
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
COMMENT "Checking ABI compatibility of version ${LIB_SOVERSION_FULL} and revision ${ABI_BASE_HASH_SHORT}")
|
||||
endmacro()
|
49
CMakeModules/FindCMocka.cmake
Normal file
49
CMakeModules/FindCMocka.cmake
Normal file
|
@ -0,0 +1,49 @@
|
|||
# - Try to find CMocka
|
||||
# Once done this will define
|
||||
#
|
||||
# CMOCKA_ROOT_DIR - Set this variable to the root installation of CMocka
|
||||
#
|
||||
# Read-Only variables:
|
||||
# CMOCKA_FOUND - system has CMocka
|
||||
# CMOCKA_INCLUDE_DIR - the CMocka include directory
|
||||
# CMOCKA_LIBRARIES - Link these to use CMocka
|
||||
# CMOCKA_DEFINITIONS - Compiler switches required for using CMocka
|
||||
#
|
||||
#=============================================================================
|
||||
# Copyright (c) 2011-2012 Andreas Schneider <asn@cryptomilk.org>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
#
|
||||
|
||||
find_path(CMOCKA_INCLUDE_DIR
|
||||
NAMES
|
||||
cmocka.h
|
||||
PATHS
|
||||
${CMOCKA_ROOT_DIR}/include
|
||||
)
|
||||
|
||||
find_library(CMOCKA_LIBRARY
|
||||
NAMES
|
||||
cmocka
|
||||
PATHS
|
||||
${CMOCKA_ROOT_DIR}/include
|
||||
)
|
||||
|
||||
if(CMOCKA_LIBRARY)
|
||||
set(CMOCKA_LIBRARIES
|
||||
${CMOCKA_LIBRARIES}
|
||||
${CMOCKA_LIBRARY}
|
||||
)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(CMocka DEFAULT_MSG CMOCKA_LIBRARIES CMOCKA_INCLUDE_DIR)
|
||||
|
||||
# show the CMOCKA_INCLUDE_DIR and CMOCKA_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(CMOCKA_INCLUDE_DIR CMOCKA_LIBRARIES)
|
117
CMakeModules/FindLibSSH.cmake
Normal file
117
CMakeModules/FindLibSSH.cmake
Normal file
|
@ -0,0 +1,117 @@
|
|||
# - Try to find LibSSH
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBSSH_FOUND - system has LibSSH
|
||||
# LIBSSH_INCLUDE_DIRS - the LibSSH include directory
|
||||
# LIBSSH_LIBRARIES - link these to use LibSSH
|
||||
# LIBSSH_VERSION -
|
||||
#
|
||||
# Author Michal Vasko <mvasko@cesnet.cz>
|
||||
# Copyright (c) 2020 CESNET, z.s.p.o.
|
||||
#
|
||||
# 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 copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
if(LIBSSH_LIBRARIES AND LIBSSH_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(LIBSSH_FOUND TRUE)
|
||||
else()
|
||||
find_path(LIBSSH_INCLUDE_DIR
|
||||
NAMES
|
||||
libssh/libssh.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
${CMAKE_INCLUDE_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
)
|
||||
|
||||
find_library(LIBSSH_LIBRARY
|
||||
NAMES
|
||||
ssh.so
|
||||
libssh.so
|
||||
libssh.dylib
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
if(LIBSSH_INCLUDE_DIR AND LIBSSH_LIBRARY)
|
||||
# learn libssh version
|
||||
if(EXISTS ${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h)
|
||||
set(LIBSSH_HEADER_PATH ${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h)
|
||||
else()
|
||||
set(LIBSSH_HEADER_PATH ${LIBSSH_INCLUDE_DIR}/libssh/libssh.h)
|
||||
endif()
|
||||
file(STRINGS ${LIBSSH_HEADER_PATH} LIBSSH_VERSION_MAJOR
|
||||
REGEX "#define[ ]+LIBSSH_VERSION_MAJOR[ ]+[0-9]+")
|
||||
if(NOT LIBSSH_VERSION_MAJOR)
|
||||
message(STATUS "LIBSSH_VERSION_MAJOR not found, assuming libssh is too old and cannot be used!")
|
||||
set(LIBSSH_INCLUDE_DIR "LIBSSH_INCLUDE_DIR-NOTFOUND")
|
||||
set(LIBSSH_LIBRARY "LIBSSH_LIBRARY-NOTFOUND")
|
||||
else()
|
||||
string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_MAJOR ${LIBSSH_VERSION_MAJOR})
|
||||
file(STRINGS ${LIBSSH_HEADER_PATH} LIBSSH_VERSION_MINOR
|
||||
REGEX "#define[ ]+LIBSSH_VERSION_MINOR[ ]+[0-9]+")
|
||||
string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_MINOR ${LIBSSH_VERSION_MINOR})
|
||||
file(STRINGS ${LIBSSH_HEADER_PATH} LIBSSH_VERSION_PATCH
|
||||
REGEX "#define[ ]+LIBSSH_VERSION_MICRO[ ]+[0-9]+")
|
||||
string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_PATCH ${LIBSSH_VERSION_PATCH})
|
||||
|
||||
set(LIBSSH_VERSION ${LIBSSH_VERSION_MAJOR}.${LIBSSH_VERSION_MINOR}.${LIBSSH_VERSION_PATCH})
|
||||
|
||||
if(LIBSSH_VERSION VERSION_LESS 0.8.0)
|
||||
# libssh_threads also needs to be linked for these versions
|
||||
string(REPLACE "libssh.so" "libssh_threads.so"
|
||||
LIBSSH_THREADS_LIBRARY
|
||||
${LIBSSH_LIBRARY}
|
||||
)
|
||||
string(REPLACE "libssh.dylib" "libssh_threads.dylib"
|
||||
LIBSSH_THREADS_LIBRARY
|
||||
${LIBSSH_THREADS_LIBRARY}
|
||||
)
|
||||
string(REPLACE "ssh.so" "ssh_threads.so"
|
||||
LIBSSH_THREADS_LIBRARY
|
||||
${LIBSSH_THREADS_LIBRARY}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(LIBSSH_INCLUDE_DIRS ${LIBSSH_INCLUDE_DIR})
|
||||
set(LIBSSH_LIBRARIES ${LIBSSH_LIBRARY} ${LIBSSH_THREADS_LIBRARY})
|
||||
mark_as_advanced(LIBSSH_INCLUDE_DIRS LIBSSH_LIBRARIES)
|
||||
|
||||
find_package_handle_standard_args(LibSSH FOUND_VAR LIBSSH_FOUND
|
||||
REQUIRED_VARS LIBSSH_INCLUDE_DIRS LIBSSH_LIBRARIES
|
||||
VERSION_VAR LIBSSH_VERSION)
|
||||
endif()
|
||||
|
102
CMakeModules/FindLibVAL.cmake
Normal file
102
CMakeModules/FindLibVAL.cmake
Normal file
|
@ -0,0 +1,102 @@
|
|||
# - Try to find LibVAL
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBVAL_FOUND - system has LibVAL
|
||||
# LIBVAL_INCLUDE_DIRS - the LibVAL include directory
|
||||
# LIBVAL_LIBRARIES - link these to use LibVAL
|
||||
#
|
||||
# Author Michal Vasko <mvasko@cesnet.cz>
|
||||
# Copyright (c) 2015 CESNET, z.s.p.o.
|
||||
#
|
||||
# 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 copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
if(LIBVAL_LIBRARIES AND LIBVAL_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(LIBVAL_FOUND TRUE)
|
||||
else()
|
||||
|
||||
find_path(LIBVAL_INCLUDE_DIR
|
||||
NAMES
|
||||
validator/validator.h
|
||||
validator/resolver.h
|
||||
validator/validator-compat.h
|
||||
validator/val_dane.h
|
||||
validator/val_errors.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
${CMAKE_INCLUDE_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
)
|
||||
|
||||
find_library(LIBVAL_LIBRARY
|
||||
NAMES
|
||||
libval-threads
|
||||
val-threads
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/usr/local/lib
|
||||
/usr/local/lib64
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
find_library(LIBSRES_LIBRARY
|
||||
NAMES
|
||||
libsres
|
||||
sres
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/usr/local/lib
|
||||
/usr/local/lib64
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
if(LIBVAL_INCLUDE_DIR AND LIBVAL_LIBRARY AND LIBSRES_LIBRARY)
|
||||
set(LIBVAL_FOUND TRUE)
|
||||
else()
|
||||
set(LIBVAL_FOUND FALSE)
|
||||
endif()
|
||||
|
||||
set(LIBVAL_INCLUDE_DIRS ${LIBVAL_INCLUDE_DIR})
|
||||
set(LIBVAL_LIBRARIES ${LIBSRES_LIBRARY} ${LIBVAL_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LibVAL DEFAULT_MSG LIBVAL_LIBRARIES LIBVAL_INCLUDE_DIRS)
|
||||
|
||||
# show the LIBVAL_INCLUDE_DIRS and LIBVAL_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(LIBVAL_INCLUDE_DIRS LIBVAL_LIBRARIES)
|
||||
|
||||
endif()
|
||||
|
89
CMakeModules/FindLibYANG.cmake
Normal file
89
CMakeModules/FindLibYANG.cmake
Normal file
|
@ -0,0 +1,89 @@
|
|||
# - Try to find LibYANG
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBYANG_FOUND - system has LibYANG
|
||||
# LIBYANG_INCLUDE_DIRS - the LibYANG include directory
|
||||
# LIBYANG_LIBRARIES - Link these to use LibYANG
|
||||
# LIBYANG_VERSION - SO version of the found libyang library
|
||||
#
|
||||
# Author Michal Vasko <mvasko@cesnet.cz>
|
||||
# Copyright (c) 2021 CESNET, z.s.p.o.
|
||||
#
|
||||
# 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 copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
if(LIBYANG_LIBRARIES AND LIBYANG_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(LIBYANG_FOUND TRUE)
|
||||
else()
|
||||
find_path(LIBYANG_INCLUDE_DIR
|
||||
NAMES
|
||||
libyang/libyang.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
${CMAKE_INCLUDE_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
)
|
||||
|
||||
find_library(LIBYANG_LIBRARY
|
||||
NAMES
|
||||
yang
|
||||
libyang
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/usr/local/lib
|
||||
/usr/local/lib64
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
if(LIBYANG_INCLUDE_DIR)
|
||||
find_path(LY_VERSION_PATH "libyang/version.h" HINTS ${LIBYANG_INCLUDE_DIR})
|
||||
if(LY_VERSION_PATH)
|
||||
file(READ "${LY_VERSION_PATH}/libyang/version.h" LY_VERSION_FILE)
|
||||
else()
|
||||
find_path(LY_HEADER_PATH "libyang/libyang.h" HINTS ${LIBYANG_INCLUDE_DIR})
|
||||
file(READ "${LY_HEADER_PATH}/libyang/libyang.h" LY_VERSION_FILE)
|
||||
endif()
|
||||
string(REGEX MATCH "#define LY_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]+\"" LY_VERSION_MACRO "${LY_VERSION_FILE}")
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" LIBYANG_VERSION "${LY_VERSION_MACRO}")
|
||||
endif()
|
||||
|
||||
set(LIBYANG_INCLUDE_DIRS ${LIBYANG_INCLUDE_DIR})
|
||||
set(LIBYANG_LIBRARIES ${LIBYANG_LIBRARY})
|
||||
mark_as_advanced(LIBYANG_INCLUDE_DIRS LIBYANG_LIBRARIES)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set LIBYANG_FOUND to TRUE
|
||||
# if all listed variables are TRUE
|
||||
find_package_handle_standard_args(LibYANG FOUND_VAR LIBYANG_FOUND
|
||||
REQUIRED_VARS LIBYANG_LIBRARY LIBYANG_INCLUDE_DIR
|
||||
VERSION_VAR LIBYANG_VERSION)
|
||||
endif()
|
21
CMakeModules/FindUncrustify.cmake
Normal file
21
CMakeModules/FindUncrustify.cmake
Normal file
|
@ -0,0 +1,21 @@
|
|||
# - Find uncrustify
|
||||
# Find the uncrustify binary.
|
||||
#
|
||||
# UNCRUSTIFY - path ot the binary
|
||||
# UNCRUSTIFY_VERSION - found version
|
||||
# UNCRUSTIFY_FOUND - True if uncrustify found.
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_program(UNCRUSTIFY uncrustify)
|
||||
if(UNCRUSTIFY)
|
||||
execute_process(COMMAND ${UNCRUSTIFY} --version OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE VERSION)
|
||||
string(FIND ${VERSION} "-" START_IDX)
|
||||
math(EXPR START_IDX "${START_IDX} + 1")
|
||||
string(SUBSTRING "${VERSION}" ${START_IDX} -1 VERSION)
|
||||
|
||||
string(FIND ${VERSION} "-" LEN)
|
||||
string(SUBSTRING "${VERSION}" 0 ${LEN} UNCRUSTIFY_VERSION)
|
||||
endif()
|
||||
|
||||
# Handle the QUIETLY and REQUIRED arguments and set UNCRUSTIFY_FOUND to TRUE if all listed variables are TRUE.
|
||||
find_package_handle_standard_args(Uncrustify REQUIRED_VARS UNCRUSTIFY VERSION_VAR UNCRUSTIFY_VERSION)
|
118
CMakeModules/GenCoverage.cmake
Normal file
118
CMakeModules/GenCoverage.cmake
Normal file
|
@ -0,0 +1,118 @@
|
|||
# generate test code coverage report
|
||||
|
||||
# check that coverage tools are available - always use before GEN_COVERAGE
|
||||
macro(GEN_COVERAGE_ENABLE ENABLE_TESTS)
|
||||
# make into normal variable
|
||||
set(TESTS_ENABLED ${ENABLE_TESTS})
|
||||
|
||||
set(GEN_COVERAGE_ENABLED ON)
|
||||
if(NOT TESTS_ENABLED)
|
||||
message(WARNING "You cannot generate coverage when tests are disabled. Enable test by additing parameter -DENABLE_BUILD_TESTS=ON or run cmake with Debug build target.")
|
||||
set(GEN_COVERAGE_ENABLED OFF)
|
||||
endif()
|
||||
|
||||
if(GEN_COVERAGE_ENABLED)
|
||||
find_program(PATH_GCOV NAMES gcov)
|
||||
if(NOT PATH_GCOV)
|
||||
message(WARNING "gcov executable not found! Disabling building code coverage report.")
|
||||
set(GEN_COVERAGE_ENABLED OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(GEN_COVERAGE_ENABLED)
|
||||
find_program(PATH_LCOV NAMES lcov)
|
||||
if(NOT PATH_LCOV)
|
||||
message(WARNING "lcov executable not found! Disabling building code coverage report.")
|
||||
set(GEN_COVERAGE_ENABLED OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(GEN_COVERAGE_ENABLED)
|
||||
find_program(PATH_GENHTML NAMES genhtml)
|
||||
if(NOT PATH_GENHTML)
|
||||
message(WARNING "genhtml executable not found! Disabling building code coverage report.")
|
||||
set(GEN_COVERAGE_ENABLED OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(GEN_COVERAGE_ENABLED)
|
||||
if(NOT CMAKE_COMPILER_IS_GNUCC)
|
||||
message(WARNING "Compiler is not gcc! Coverage may break the tests!")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND bash "-c" "${CMAKE_C_COMPILER} --version | head -n1 | sed \"s/.* (.*) \\([0-9]\\+.[0-9]\\+.[0-9]\\+ .*\\)/\\1/\""
|
||||
OUTPUT_VARIABLE GCC_VERSION_FULL
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
execute_process(
|
||||
COMMAND bash "-c" "${PATH_GCOV} --version | head -n1 | sed \"s/.* (.*) \\([0-9]\\+.[0-9]\\+.[0-9]\\+ .*\\)/\\1/\""
|
||||
OUTPUT_VARIABLE GCOV_VERSION_FULL
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(NOT GCC_VERSION_FULL STREQUAL GCOV_VERSION_FULL)
|
||||
message(WARNING "gcc and gcov versions do not match! Generating coverage may fail with errors.")
|
||||
endif()
|
||||
|
||||
# add specific required compile flags
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# tests are always expected to be in ${CMAKE_SOURCE_DIR}/tests
|
||||
function(GEN_COVERAGE MATCH_TEST_REGEX EXCLUDE_TEST_REGEX)
|
||||
if(NOT GEN_COVERAGE_ENABLED)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# destination
|
||||
set(COVERAGE_DIR "${CMAKE_BINARY_DIR}/code_coverage/")
|
||||
set(COVERAGE_FILE_RAW "${CMAKE_BINARY_DIR}/coverage_raw.info")
|
||||
set(COVERAGE_FILE_CLEAN "${CMAKE_BINARY_DIR}/coverage_clean.info")
|
||||
|
||||
# test match/exclude
|
||||
if(MATCH_TEST_REGEX)
|
||||
set(MATCH_TEST_ARGS -R \"${MATCH_TEST_REGEX}\")
|
||||
endif()
|
||||
if(EXCLUDE_TEST_REGEX)
|
||||
set(EXCLUDE_TEST_ARGS -E \"${EXCLUDE_TEST_REGEX}\")
|
||||
endif()
|
||||
|
||||
# coverage target
|
||||
add_custom_target(coverage
|
||||
COMMENT "Generating code coverage..."
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||
# Cleanup code counters
|
||||
COMMAND "${PATH_LCOV}" --directory . --zerocounters --quiet
|
||||
|
||||
# Run tests
|
||||
COMMAND "${CMAKE_CTEST_COMMAND}" --quiet ${MATCH_TEST_ARGS} ${EXCLUDE_TEST_ARGS}
|
||||
|
||||
# Capture the counters
|
||||
COMMAND "${PATH_LCOV}"
|
||||
--directory .
|
||||
--rc lcov_branch_coverage=1
|
||||
--rc 'lcov_excl_line=assert'
|
||||
--capture --quiet
|
||||
--output-file "${COVERAGE_FILE_RAW}"
|
||||
# Remove coverage of tests, system headers, etc.
|
||||
COMMAND "${PATH_LCOV}"
|
||||
--remove "${COVERAGE_FILE_RAW}" '${CMAKE_SOURCE_DIR}/tests/*'
|
||||
--rc lcov_branch_coverage=1
|
||||
--quiet --output-file "${COVERAGE_FILE_CLEAN}"
|
||||
# Generate HTML report
|
||||
COMMAND "${PATH_GENHTML}"
|
||||
--branch-coverage --function-coverage --quiet --title "${PROJECT_NAME}"
|
||||
--legend --show-details --output-directory "${COVERAGE_DIR}"
|
||||
"${COVERAGE_FILE_CLEAN}"
|
||||
# Delete the counters
|
||||
COMMAND "${CMAKE_COMMAND}" -E remove
|
||||
${COVERAGE_FILE_RAW} ${COVERAGE_FILE_CLEAN}
|
||||
)
|
||||
|
||||
add_custom_command(TARGET coverage POST_BUILD
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests"
|
||||
COMMENT "To see the code coverage report, open ${COVERAGE_DIR}index.html"
|
||||
COMMAND ;
|
||||
)
|
||||
endfunction()
|
28
CMakeModules/GenDoc.cmake
Normal file
28
CMakeModules/GenDoc.cmake
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Prepare building doxygen documentation
|
||||
macro(GEN_DOC INPUT_FILES PROJECT_VERSION PROJECT_DESCRIPTION DOC_LOGO)
|
||||
find_package(Doxygen)
|
||||
if(DOXYGEN_FOUND)
|
||||
find_program(DOT_PATH dot PATH_SUFFIXES graphviz2.38/bin graphviz/bin)
|
||||
if(DOT_PATH)
|
||||
set(HAVE_DOT "YES")
|
||||
else()
|
||||
set(HAVE_DOT "NO")
|
||||
message(AUTHOR_WARNING "Doxygen: to generate UML diagrams please install graphviz")
|
||||
endif()
|
||||
|
||||
# target doc
|
||||
add_custom_target(doc
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
# generate list with spaces as separators
|
||||
string(REPLACE ";" " " DOXY_INPUT "${INPUT_FILES}")
|
||||
|
||||
# make other arguments into variables
|
||||
set(PROJECT_VERSION ${PROJECT_VERSION})
|
||||
set(PROJECT_DESCRIPTION ${PROJECT_DESCRIPTION})
|
||||
set(DOC_LOGO ${DOC_LOGO})
|
||||
|
||||
configure_file(Doxyfile.in Doxyfile)
|
||||
endif()
|
||||
endmacro()
|
32
CMakeModules/SourceFormat.cmake
Normal file
32
CMakeModules/SourceFormat.cmake
Normal file
|
@ -0,0 +1,32 @@
|
|||
# format source files with uncrustify
|
||||
|
||||
# check that format checking is available - always use before SOURCE_FORMAT
|
||||
macro(SOURCE_FORMAT_ENABLE)
|
||||
find_package(Uncrustify 0.71)
|
||||
if(UNCRUSTIFY_FOUND)
|
||||
set(SOURCE_FORMAT_ENABLED TRUE)
|
||||
else()
|
||||
set(SOURCE_FORMAT_ENABLED FALSE)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# files are expected to be a list and relative paths are resolved wtih respect to CMAKE_SOURCE DIR
|
||||
macro(SOURCE_FORMAT)
|
||||
if(NOT ${ARGC})
|
||||
message(FATAL_ERROR "source_format() needs a list of files to format!")
|
||||
endif()
|
||||
|
||||
if(SOURCE_FORMAT_ENABLED)
|
||||
add_custom_target(format
|
||||
COMMAND ${UNCRUSTIFY} -c ${CMAKE_SOURCE_DIR}/uncrustify.cfg --no-backup --replace ${ARGN}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
COMMENT "Formating sources with ${UNCRUSTIFY} ...")
|
||||
|
||||
add_custom_target(format-check
|
||||
COMMAND ${UNCRUSTIFY} -c ${CMAKE_SOURCE_DIR}/uncrustify.cfg --check ${ARGN}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
COMMENT "Checking format of the sources with ${UNCRUSTIFY} ...")
|
||||
|
||||
set(SOURCE_FORMAT_ENABLED TRUE)
|
||||
endif()
|
||||
endmacro()
|
57
CMakeModules/UseCompat.cmake
Normal file
57
CMakeModules/UseCompat.cmake
Normal file
|
@ -0,0 +1,57 @@
|
|||
# - Use compat library providing various functions and macros that may be missing on some systems
|
||||
# Once done this will define
|
||||
#
|
||||
# compatsrc - sources to add to compilation
|
||||
#
|
||||
# Additionally, "compat.h" include directory is added and can be included.
|
||||
#
|
||||
# Author Michal Vasko <mvasko@cesnet.cz>
|
||||
# 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
|
||||
#
|
||||
include(CheckSymbolExists)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFile)
|
||||
include(TestBigEndian)
|
||||
if(POLICY CMP0075)
|
||||
cmake_policy(SET CMP0075 NEW)
|
||||
endif()
|
||||
|
||||
macro(USE_COMPAT)
|
||||
# compatibility checks
|
||||
set(CMAKE_REQUIRED_DEFINITIONS -D_POSIX_C_SOURCE=200809L)
|
||||
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
|
||||
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D__BSD_VISIBLE=1)
|
||||
set(CMAKE_REQUIRED_LIBRARIES pthread)
|
||||
|
||||
check_symbol_exists(vdprintf "stdio.h;stdarg.h" HAVE_VDPRINTF)
|
||||
check_symbol_exists(asprintf "stdio.h" HAVE_ASPRINTF)
|
||||
check_symbol_exists(vasprintf "stdio.h" HAVE_VASPRINTF)
|
||||
check_symbol_exists(getline "stdio.h" HAVE_GETLINE)
|
||||
|
||||
check_symbol_exists(strndup "string.h" HAVE_STRNDUP)
|
||||
check_symbol_exists(strnstr "string.h" HAVE_STRNSTR)
|
||||
check_symbol_exists(strdupa "string.h" HAVE_STRDUPA)
|
||||
check_symbol_exists(strchrnul "string.h" HAVE_STRCHRNUL)
|
||||
|
||||
check_symbol_exists(get_current_dir_name "unistd.h" HAVE_GET_CURRENT_DIR_NAME)
|
||||
|
||||
check_function_exists(pthread_mutex_timedlock HAVE_PTHREAD_MUTEX_TIMEDLOCK)
|
||||
|
||||
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
|
||||
|
||||
check_include_file("stdatomic.h" HAVE_STDATOMIC)
|
||||
|
||||
unset(CMAKE_REQUIRED_DEFINITIONS)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
|
||||
# header and source file (adding the source directly allows for hiding its symbols)
|
||||
configure_file(${PROJECT_SOURCE_DIR}/compat/compat.h.in ${PROJECT_BINARY_DIR}/compat/compat.h @ONLY)
|
||||
include_directories(${PROJECT_BINARY_DIR}/compat)
|
||||
set(compatsrc ${PROJECT_SOURCE_DIR}/compat/compat.c)
|
||||
endmacro()
|
27
CMakeModules/uninstall.cmake
Normal file
27
CMakeModules/uninstall.cmake
Normal file
|
@ -0,0 +1,27 @@
|
|||
cmake_minimum_required(VERSION 3.0.2)
|
||||
|
||||
set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
|
||||
|
||||
if(NOT EXISTS ${MANIFEST})
|
||||
message(FATAL_ERROR "Cannot find install manifest: ${MANIFEST}")
|
||||
endif()
|
||||
|
||||
file(STRINGS ${MANIFEST} files)
|
||||
foreach(file ${files})
|
||||
if(EXISTS ${file} OR IS_SYMLINK ${file})
|
||||
message(STATUS "Removing: ${file}")
|
||||
|
||||
execute_process(COMMAND rm -f ${file}
|
||||
RESULT_VARIABLE result
|
||||
OUTPUT_QUIET
|
||||
ERROR_VARIABLE stderr
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
if(NOT ${result} EQUAL 0)
|
||||
message(FATAL_ERROR "${stderr}")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Does-not-exist: ${file}")
|
||||
endif()
|
||||
endforeach(file)
|
184
CODINGSTYLE.md
Normal file
184
CODINGSTYLE.md
Normal file
|
@ -0,0 +1,184 @@
|
|||
# libnetconf2 Coding Style
|
||||
|
||||
This file describes the coding style used in most C files in the libnetconf2
|
||||
library.
|
||||
|
||||
## Basics
|
||||
|
||||
- Use space instead of tabs for indentations.
|
||||
- There is no strict limit for the line length, However, try to keep lines in a
|
||||
reasonable length (120 characters).
|
||||
- Avoid trailing spaces on lines.
|
||||
- Put one blank line between function definitions.
|
||||
- Don't mix declarations and code within a block. Similarly, don't use
|
||||
declarations in iteration statements.
|
||||
|
||||
## Naming
|
||||
|
||||
Use underscores to separate words in an identifier: `multi_word_name`.
|
||||
|
||||
Use lowercase for most names. Use uppercase for macros, macro parameters and
|
||||
members of enumerations.
|
||||
|
||||
Do not use names that begin with `_`. If you need a name for "internal use
|
||||
only", use `__` as a suffix instead of a prefix.
|
||||
|
||||
## Comments
|
||||
|
||||
Avoid `//` comments. Use `/* ... */` comments, write block comments with the
|
||||
leading asterisk on each line. You may put the `/*` and `*/` on the same line as
|
||||
comment text if you prefer.
|
||||
|
||||
```c
|
||||
/*
|
||||
* comment text
|
||||
*/
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
Put the return type, function name, and the braces that surround the function's
|
||||
code on separate lines, all starting in column 0.
|
||||
|
||||
```c
|
||||
static int
|
||||
foo(int arg)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
When you need to put the function parameters on multiple lines, start new line
|
||||
at column after the opening parenthesis from the initial line.
|
||||
|
||||
```c
|
||||
static int
|
||||
my_function(struct my_struct *p1, struct another_struct *p2,
|
||||
int size)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
In the absence of good reasons for another order, the following parameter order
|
||||
is preferred. One notable exception is that data parameters and their
|
||||
corresponding size parameters should be paired.
|
||||
|
||||
1. The primary object being manipulated, if any (equivalent to the "this"
|
||||
pointer in C++).
|
||||
2. Input-only parameters.
|
||||
3. Input/output parameters.
|
||||
4. Output-only parameters.
|
||||
5. Status parameter.
|
||||
|
||||
Functions that destroy an instance of a dynamically-allocated type should accept
|
||||
and ignore a null pointer argument. Code that calls such a function (including
|
||||
the C standard library function `free()`) should omit a null-pointer check. We
|
||||
find that this usually makes code easier to read.
|
||||
|
||||
### Function Prototypes
|
||||
|
||||
Put the return type and function name on the same line in a function prototype:
|
||||
|
||||
```c
|
||||
static const struct int foo(int arg);
|
||||
```
|
||||
|
||||
## Statements
|
||||
|
||||
- Indent each level of code with 4 spaces.
|
||||
- Put single space between `if`, `while`, `for`, etc. statements and the
|
||||
expression that follow them. On the other hand, function calls has no space
|
||||
between the function name and opening parenthesis.
|
||||
- Opening code block brace is kept at the same line with the `if`, `while`,
|
||||
`for` or `switch` statements.
|
||||
|
||||
```c
|
||||
if (a) {
|
||||
x = exp(a);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
```
|
||||
|
||||
- Start switch's cases at the same column as the switch.
|
||||
|
||||
```c
|
||||
switch (conn->state) {
|
||||
case 0:
|
||||
return "data found";
|
||||
case 1:
|
||||
return "data not found";
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
```
|
||||
|
||||
- Do not put gratuitous parentheses around the expression in a return statement,
|
||||
that is, write `return 0;` and not `return(0);`
|
||||
|
||||
## Types
|
||||
|
||||
Use typedefs sparingly. Code is clearer if the actual type is visible at the
|
||||
point of declaration. Do not, in general, declare a typedef for a struct, union,
|
||||
or enum. Do not declare a typedef for a pointer type, because this can be very
|
||||
confusing to the reader.
|
||||
|
||||
Use the `int<N>_t` and `uint<N>_t` types from `<stdint.h>` for exact-width
|
||||
integer types. Use the `PRId<N>`, `PRIu<N>`, and `PRIx<N>` macros from
|
||||
`<inttypes.h>` for formatting them with `printf()` and related functions.
|
||||
|
||||
Pointer declarators bind to the variable name, not the type name. Write
|
||||
`int *x`, not `int* x` and definitely not `int * x`.
|
||||
|
||||
## Expresions
|
||||
|
||||
Put one space on each side of infix binary and ternary operators:
|
||||
|
||||
```c
|
||||
* / % + - << >> < <= > >= == != & ^ | && || ?: = += -= *= /= %= &= ^= |= <<= >>=
|
||||
```
|
||||
|
||||
Do not put any white space around postfix, prefix, or grouping operators with
|
||||
one exception - `sizeof`, see the note below.
|
||||
|
||||
```c
|
||||
() [] -> . ! ~ ++ -- + - * &
|
||||
```
|
||||
|
||||
The "sizeof" operator is unique among C operators in that it accepts two very
|
||||
different kinds of operands: an expression or a type. In general, prefer to
|
||||
specify an expression
|
||||
```c
|
||||
int *x = calloc(1, sizeof *x);
|
||||
```
|
||||
When the operand of sizeof is an expression, there is no need to parenthesize
|
||||
that operand, and please don't. There is an exception to this rule when you need
|
||||
to work with partially compatible structures:
|
||||
|
||||
```c
|
||||
struct a_s {
|
||||
uint8_t type;
|
||||
}
|
||||
|
||||
struct b_s {
|
||||
uint8_t type;
|
||||
char *str;
|
||||
}
|
||||
|
||||
struct c_s {
|
||||
uint8_t type;
|
||||
uint8_t *u8;
|
||||
}
|
||||
...
|
||||
struct a_s *a;
|
||||
|
||||
switch (type) {
|
||||
case 1:
|
||||
a = (struct a_s *)calloc(1, sizeof(struct b_s));
|
||||
break;
|
||||
case 2:
|
||||
a = (struct a_s *)calloc(1, sizeof(struct c_s));
|
||||
break;
|
||||
...
|
||||
```
|
2457
Doxyfile.in
Normal file
2457
Doxyfile.in
Normal file
File diff suppressed because it is too large
Load diff
38
FAQ.md
Normal file
38
FAQ.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Frequently Asked Questions
|
||||
|
||||
__Q: Having a fresh installation of *netopeer2-server*, when I connect to it I see (or something similar):__
|
||||
```
|
||||
[ERR]: LN: Failed to set hostkey "genkey" (/tmp/dvcjwz).
|
||||
```
|
||||
|
||||
__A:__ You are using *libssh* that was compiled with *gcrypt* library
|
||||
as the crypto backend. It does not support default SSH keys generated
|
||||
during *netopeer2-server* installation. To fix, disable suport for this
|
||||
backend when compiling *libssh* so that some other one is used.
|
||||
|
||||
__Q: When a new NETCONF session is being created, I see the error:__
|
||||
```
|
||||
Starting the SSH session failed ()
|
||||
```
|
||||
|
||||
__A:__ The most likely reason for this is that the SSH key that is used
|
||||
for this session authentication uses an algorithm not supported by
|
||||
your system. The supported algorithms are automatically loaded by *libssh*
|
||||
from OpenSSH configuration files (more info in `ssh_config(5)` and `sshd_config(5)`).
|
||||
|
||||
__Q: When I try to connect to a server I immediately get a timeout after authenticating:__
|
||||
|
||||
__A:__ You are probably using *libssh* version 0.9.3 that includes this
|
||||
[regression bug](https://bugs.libssh.org/T211). To solve it, you must use another version.
|
||||
|
||||
__Q: When I connect to a server, after around 10-20 seconds I get disconnected with an error:__
|
||||
```
|
||||
[ERR]: LN: Session 1: inactive read timeout elapsed.
|
||||
```
|
||||
|
||||
__A:__ There are 2 most common reasons for this error. Either you are not using
|
||||
a NETCONF client to connect (but `ssh(1)`, for example) and the messages received
|
||||
by the server are not properly formatted (even an additional `\n` can cause this problem).
|
||||
To fix, use a NETCONF client instead. Another reason may be that you are using *libssh*
|
||||
version 0.9.4. It includes a [regression bug](https://gitlab.com/libssh/libssh-mirror/-/merge_requests/101)
|
||||
that causes this problem and you must use another version to fix it.
|
85
FindLibNETCONF2.cmake
Normal file
85
FindLibNETCONF2.cmake
Normal file
|
@ -0,0 +1,85 @@
|
|||
# - Try to find LibNETCONF2
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBNETCONF2_FOUND - system has LibNETCONF2
|
||||
# LIBNETCONF2_INCLUDE_DIRS - the LibNETCONF2 include directory
|
||||
# LIBNETCONF2_LIBRARIES - Link these to use LibNETCONF2
|
||||
# LIBNETCONF2_ENABLED_SSH - LibNETCONF2 was compiled with SSH support
|
||||
# LIBNETCONF2_ENABLED_TLS - LibNETCONF2 was compiled with TLS support
|
||||
#
|
||||
# Author Michal Vasko <mvasko@cesnet.cz>
|
||||
# Copyright (c) 2020 CESNET, z.s.p.o.
|
||||
#
|
||||
# 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 copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
include(FindPackageHandleStandardArgs)
|
||||
include(CheckSymbolExists)
|
||||
|
||||
if(LIBNETCONF2_LIBRARIES AND LIBNETCONF2_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(LIBNETCONF2_FOUND TRUE)
|
||||
else()
|
||||
find_path(LIBNETCONF2_INCLUDE_DIR
|
||||
NAMES
|
||||
nc_client.h
|
||||
nc_server.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
${CMAKE_INCLUDE_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
)
|
||||
|
||||
find_library(LIBNETCONF2_LIBRARY
|
||||
NAMES
|
||||
netconf2
|
||||
libnetconf2
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/usr/local/lib
|
||||
/usr/local/lib64
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
set(LIBNETCONF2_INCLUDE_DIRS ${LIBNETCONF2_INCLUDE_DIR})
|
||||
set(LIBNETCONF2_LIBRARIES ${LIBNETCONF2_LIBRARY})
|
||||
mark_as_advanced(LIBNETCONF2_INCLUDE_DIRS LIBNETCONF2_LIBRARIES)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set SYSREPO_FOUND to TRUE
|
||||
# if all listed variables are TRUE
|
||||
find_package_handle_standard_args(LibNETCONF2 DEFAULT_MSG LIBNETCONF2_LIBRARY LIBNETCONF2_INCLUDE_DIR)
|
||||
|
||||
# check the configured options and make them available through cmake
|
||||
list(INSERT CMAKE_REQUIRED_INCLUDES 0 "${LIBNETCONF2_INCLUDE_DIR}")
|
||||
check_symbol_exists("NC_ENABLED_SSH" "nc_client.h" LIBNETCONF2_ENABLED_SSH)
|
||||
check_symbol_exists("NC_ENABLED_TLS" "nc_client.h" LIBNETCONF2_ENABLED_TLS)
|
||||
list(REMOVE_AT CMAKE_REQUIRED_INCLUDES 0)
|
||||
endif()
|
||||
|
27
LICENSE
Normal file
27
LICENSE
Normal file
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2015-2020, CESNET
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
* Neither the name of libnetconf2 nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
285
README.md
Normal file
285
README.md
Normal file
|
@ -0,0 +1,285 @@
|
|||
# libnetconf2 – The NETCONF protocol library
|
||||
|
||||
[](https://opensource.org/licenses/BSD-3-Clause)
|
||||
[](https://github.com/CESNET/libnetconf2/actions?query=workflow%3A%22libnetconf2+CI%22)
|
||||
[](https://netopeer.liberouter.org/doc/libnetconf2/)
|
||||
[](https://scan.coverity.com/projects/7642)
|
||||
[](https://codecov.io/gh/CESNET/libnetconf2)
|
||||
|
||||
**libnetconf2** is a NETCONF library in C intended for building NETCONF clients
|
||||
and servers. NETCONF is the [NETwork CONFiguration protocol](http://trac.tools.ietf.org/wg/netconf/trac/wiki)
|
||||
introduced by IETF.
|
||||
|
||||
**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)). The main features include:
|
||||
|
||||
* NETCONF over SSH ([RFC 4742](https://tools.ietf.org/html/rfc4742), [RFC 6242](https://tools.ietf.org/html/rfc6242)),
|
||||
using [libssh](https://www.libssh.org/).
|
||||
* NETCONF over TLS ([RFC 7589](https://tools.ietf.org/html/rfc7589)), using [OpenSSL](https://www.openssl.org/).
|
||||
* DNSSEC SSH Key Fingerprints ([RFC 4255](https://tools.ietf.org/html/rfc4255))
|
||||
* NETCONF over pre-established transport sessions (using this mechanism the communication can be tunneled through
|
||||
sshd(8), for instance).
|
||||
* NETCONF Call Home ([RFC 8071](https://tools.ietf.org/html/rfc8071)).
|
||||
* NETCONF Event Notifications ([RFC 5277](https://tools.ietf.org/html/rfc5277)),
|
||||
|
||||
**libnetconf2** is maintained and further developed by the [Tools for
|
||||
Monitoring and Configuration](https://www.liberouter.org/) department of
|
||||
[CESNET](http://www.ces.net/). Any testing or improving/fixing the library
|
||||
is welcome. Please inform us about your experiences with using **libnetconf2**
|
||||
via the [issue tracker](https://github.com/CESNET/libnetconf/issues).
|
||||
|
||||
Besides the [**libyang**](https://github.com/CESNET/libyang), **libnetconf2** is
|
||||
another basic building block for the [**Netopeer2** toolset](https://github.com/CESNET/Netopeer2).
|
||||
For a reference implementation of NETCONF client and server, check the
|
||||
**Netopeer2** project.
|
||||
|
||||
## Branches
|
||||
|
||||
The project uses 2 main branches `master` and `devel`. Other branches should not be cloned. In `master` there are files of the
|
||||
last official *release*. Any latest improvements and changes, which were tested at least briefly are found in `devel`. On every
|
||||
new *release*, `devel` is merged into `master`.
|
||||
|
||||
This means that when only stable official releases are to be used, either `master` can be used or specific *releases* downloaded.
|
||||
If all the latest bugfixes should be applied, `devel` branch is the one to be used. Note that whenever **a new issue is created**
|
||||
and it occurs on the `master` branch, the **first response will likely be** to use `devel` before any further provided support.
|
||||
|
||||
## libnetconf vs libnetconf2
|
||||
|
||||
**libnetconf2** was developed with experiences gained from the development
|
||||
of the [**libnetconf**](https://github.com/CESNET/libnetconf) library, which
|
||||
is now obsolete and should not be used.
|
||||
|
||||
# Installation
|
||||
|
||||
## Required Dependencies
|
||||
|
||||
Install the following libraries and tools the libnetconf2 depends on.
|
||||
|
||||
### libyang
|
||||
Follow the [libyang instructions](https://github.com/CESNET/libyang/blob/master/README.md),
|
||||
in short:
|
||||
```
|
||||
$ git clone https://github.com/CESNET/libyang.git
|
||||
$ cd libyang; mkdir build; cd build
|
||||
$ cmake ..
|
||||
$ make
|
||||
# make install
|
||||
```
|
||||
|
||||
### libssh
|
||||
Required version is at least 0.7.1. This dependency can be removed by disabling
|
||||
SSH support (see the [Build Options](#build-options) section). Below si the basic
|
||||
sequence of commands for compiling and installing it from source. However, there
|
||||
are packages for certain Linux distributions available [here](https://www.libssh.org/get-it/).
|
||||
```
|
||||
$ git clone http://git.libssh.org/projects/libssh.git
|
||||
$ cd libssh; mkdir build; cd build
|
||||
$ cmake ..
|
||||
$ make
|
||||
# make install
|
||||
```
|
||||
|
||||
### OpenSSL
|
||||
This dependency is required when the TLS support is enabled, which it is by
|
||||
default but libssh requires it too. So, to remove this dependency, you need
|
||||
to disable both SSH and TLS (see the [Build Options](#build-options) section).
|
||||
|
||||
OpenSSL is a standard part of the most distribution, so ask your package
|
||||
manager for OpenSSL package including the necessary development files
|
||||
(usually -dev or -devel package).
|
||||
|
||||
## Optional Dependencies
|
||||
|
||||
### libval (part of the DNSSEC-Tools suite)
|
||||
It is required only if DNSSEC SSHFP retrieval is enabled (it is disabled by
|
||||
default, see the [Build Options](#build-options) section).
|
||||
|
||||
The easier way of installing it is as the libval-dev package (or a part of
|
||||
the dnssec-tools package), if you can find it for your distribution. Otherwise,
|
||||
compile and install it from [source](https://github.com/DNSSEC-Tools/DNSSEC-Tools/).
|
||||
Only the validator component (`DNSSEC-Tools/dnssec-tools/validator`) is needed.
|
||||
|
||||
### cmocka
|
||||
For running the tests cmocka 1.0.1 is required (see the [Tests](#tests) section for more information).
|
||||
```
|
||||
$ sudo apt-get install libcmocka-dev
|
||||
```
|
||||
|
||||
### Doxygen
|
||||
For building the library documentation.
|
||||
|
||||
Doxygen is a standard part of the most distribution, so ask your package
|
||||
manager for doxygen package.
|
||||
|
||||
### gcov
|
||||
|
||||
For code coverage, `gcov`, `lcov`, and `genhtml` are needed.
|
||||
|
||||
## Building libnetconf2
|
||||
|
||||
```
|
||||
$ mkdir build; cd build
|
||||
$ cmake ..
|
||||
$ make
|
||||
# install
|
||||
```
|
||||
|
||||
The library documentation can be generated directly from the source codes using
|
||||
Doxygen tool:
|
||||
```
|
||||
$ make doc
|
||||
```
|
||||
|
||||
## Build Options
|
||||
|
||||
There are various options to change result of building.
|
||||
|
||||
### Changing Compiler
|
||||
|
||||
Set `CC` environment variable:
|
||||
|
||||
```
|
||||
$ CC=/usr/bin/clang cmake ..
|
||||
```
|
||||
|
||||
### Installation Prefix
|
||||
|
||||
By default, the library is installed with the `/usr/local` prefix, to change
|
||||
it, use the following option:
|
||||
```
|
||||
$ cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
|
||||
```
|
||||
|
||||
### Transport Protocol Support
|
||||
|
||||
The NETCONF protocol specification allows to use the protocol on top of
|
||||
several transport protocols. **libnetconf2** provides support for SSH and
|
||||
TLS transport. By default, both SSH and TLS transport is enabled. Disabling
|
||||
and enabling both the transport protocols can be made
|
||||
in the same way. The following command has actually the same effect as
|
||||
specifying no option since it specifies the default settings.
|
||||
```
|
||||
$ cmake -DENABLE_TLS=ON -DENABLE_SSH=ON ..
|
||||
```
|
||||
|
||||
### DNSSEC SSHFP Retrieval
|
||||
|
||||
In SSH connections, if the remote NETCONF server supports it and it is
|
||||
enabled, it is possible to safely retrieve server host key fingerprints
|
||||
using DNSSEC and automatically consider them to be trusted without any
|
||||
interaction. Enable it with the following command.
|
||||
```
|
||||
$ cmake -DENABLE_DNSSEC=ON ..
|
||||
```
|
||||
|
||||
### Build Modes
|
||||
|
||||
There are two build modes:
|
||||
* Release.
|
||||
This generates library for the production use without any debug information.
|
||||
* Debug.
|
||||
This generates library with the debug information and disables optimization
|
||||
of the code.
|
||||
|
||||
The `Debug` mode is currently used as the default one. to switch to the
|
||||
`Release` mode, enter at the command line:
|
||||
```
|
||||
$ cmake -D CMAKE_BUILD_TYPE:String="Release" ..
|
||||
```
|
||||
|
||||
### Inactive Read Timeout
|
||||
|
||||
It is possible to adjust inactive read timeout. It is used when a new message is
|
||||
being read and no new data had arrived for this amount of seconds. 20 is the default value.
|
||||
|
||||
```
|
||||
$ cmake -D READ_INACTIVE_TIMEOUT:String="20" ..
|
||||
```
|
||||
|
||||
### Active Read Timeout
|
||||
|
||||
Active read timeout is used to limit the maximum number of seconds a message is given
|
||||
to arrive in its entirety once a beginning is read. The default is 300 (5 minutes).
|
||||
|
||||
```
|
||||
$ cmake -D READ_ACTIVE_TIMEOUT:String="300" ..
|
||||
```
|
||||
|
||||
### PSPoll Thread Count
|
||||
|
||||
This value limits the maximum number of threads that can concurrently access
|
||||
(wait for access) a single pspoll structure. To simplify, how many threads could
|
||||
simultaneously call a function whose parameter is one and the same pspoll structure.
|
||||
If using **netopeer2-server**, it will warn that this value needs to be adjusted if
|
||||
too small.
|
||||
|
||||
```
|
||||
$ cmake -D MAX_PSPOLL_THREAD_COUNT:String="6" ..
|
||||
```
|
||||
|
||||
### Code Coverage
|
||||
|
||||
Based on the tests run, it is possible to generate code coverage report. But
|
||||
it must be enabled and these commands are needed to generate the report:
|
||||
```
|
||||
$ cmake -DENABLE_COVERAGE=ON ..
|
||||
$ make
|
||||
$ make coverage
|
||||
```
|
||||
|
||||
Note that `gcc` compiler is required for this option and additional tools are required:
|
||||
* gcov
|
||||
* lcov
|
||||
* genhtml
|
||||
|
||||
### CMake Notes
|
||||
|
||||
Note that, with CMake, if you want to change the compiler or its options after
|
||||
you already ran CMake, you need to clear its cache first - the most simple way
|
||||
to do it is to remove all content from the 'build' directory.
|
||||
|
||||
## Usage
|
||||
|
||||
All public functions are available via 2 headers:
|
||||
```
|
||||
#include <nc_server.h>
|
||||
#include <nc_client.h>
|
||||
```
|
||||
|
||||
You need to include either one if imeplementing a NETCONF server or a NETCONF client,
|
||||
respectively.
|
||||
|
||||
To compile your program with libnetconf2, it is necessary to link it with it using the
|
||||
following linker parameters:
|
||||
```
|
||||
-lnetconf2
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
The repository includes several tests built with [cmocka](https://cmocka.org/).
|
||||
The tests can be found in `tests` subdirectory and they are designed for
|
||||
checking library functionality after code changes.
|
||||
|
||||
The tests are by default built in the `Debug` build mode by running
|
||||
```
|
||||
$ make
|
||||
```
|
||||
|
||||
In case of the `Release` mode, the tests are not built by default (it requires
|
||||
additional dependency), but it can be enabled via cmake option:
|
||||
```
|
||||
$ cmake -DENABLE_TESTS=ON ..
|
||||
```
|
||||
|
||||
Note that if the necessary [cmocka](https://cmocka.org/) headers are not present
|
||||
in the system include paths, tests are not available despite the build mode or
|
||||
cmake's options.
|
||||
|
||||
Tests can be run by the make's `test` target:
|
||||
```
|
||||
$ make test
|
||||
```
|
||||
|
32
codecov.yml
Normal file
32
codecov.yml
Normal file
|
@ -0,0 +1,32 @@
|
|||
comment:
|
||||
layout: header, changes, diff
|
||||
|
||||
coverage:
|
||||
precision: 2
|
||||
round: nearest
|
||||
|
||||
ignore:
|
||||
- compat/.*
|
||||
- tests/.*
|
||||
- examples/.*
|
||||
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: auto
|
||||
if_no_uploads: error
|
||||
|
||||
patch:
|
||||
default:
|
||||
if_no_uploads: error
|
||||
|
||||
changes: true
|
||||
|
||||
parsers:
|
||||
gcov:
|
||||
branch_detection:
|
||||
macro: no
|
||||
loop: no
|
||||
conditional: no
|
||||
method: no
|
||||
|
44
compat/check_includes.sh
Executable file
44
compat/check_includes.sh
Executable file
|
@ -0,0 +1,44 @@
|
|||
#!/bin/sh
|
||||
|
||||
RETVAL=0
|
||||
|
||||
# params - paths to the source files to search
|
||||
SRC="$*"
|
||||
|
||||
# param FUNC - name of the function in compat to check
|
||||
check_compat_func () {
|
||||
FILES=`grep -rE "([^[:alnum:]]|^)$1\([^\)]+\)" --include=\*.{c,h} $SRC | cut -d: -f1 | uniq`
|
||||
for f in $FILES; do
|
||||
grep -q "#include \"compat.h\"" $f
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Missing #include \"compat.h\" in file $f for function $1()"
|
||||
RETVAL=$((RETVAL+1))
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
check_compat_macro () {
|
||||
FILES=`grep -rE "([^[:alnum:]]|^)$1([^[:alnum:]]|$)" --include=\*.{c,h} $SRC | cut -d: -f1 | uniq`
|
||||
for f in $FILES; do
|
||||
grep -q "#include \"compat.h\"" $f
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Missing #include \"compat.h\" in file $f for macro $1"
|
||||
RETVAL=$((RETVAL+1))
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
check_compat_func vdprintf
|
||||
check_compat_func asprintf
|
||||
check_compat_func vasprintf
|
||||
check_compat_func getline
|
||||
check_compat_func strndup
|
||||
check_compat_func strnstr
|
||||
check_compat_func strdupa
|
||||
check_compat_func strchrnul
|
||||
check_compat_func get_current_dir_name
|
||||
check_compat_func pthread_mutex_timedlock
|
||||
check_compat_func UNUSED
|
||||
check_compat_macro _PACKED
|
||||
|
||||
exit $RETVAL
|
250
compat/compat.c
Normal file
250
compat/compat.c
Normal file
|
@ -0,0 +1,250 @@
|
|||
/**
|
||||
* @file compat.c
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief compatibility functions
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#define _POSIX_C_SOURCE 200809L /* fdopen, _POSIX_PATH_MAX, strdup */
|
||||
#define _ISOC99_SOURCE /* vsnprintf */
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef HAVE_VDPRINTF
|
||||
int
|
||||
vdprintf(int fd, const char *format, va_list ap)
|
||||
{
|
||||
FILE *stream;
|
||||
int count = 0;
|
||||
|
||||
stream = fdopen(dup(fd), "a+");
|
||||
if (stream) {
|
||||
count = vfprintf(stream, format, ap);
|
||||
fclose(stream);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
int
|
||||
asprintf(char **strp, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vasprintf(strp, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_VASPRINTF
|
||||
int
|
||||
vasprintf(char **strp, const char *fmt, va_list ap)
|
||||
{
|
||||
va_list ap2;
|
||||
|
||||
va_copy(ap2, ap);
|
||||
int l = vsnprintf(0, 0, fmt, ap2);
|
||||
|
||||
va_end(ap2);
|
||||
|
||||
if ((l < 0) || !(*strp = malloc(l + 1U))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return vsnprintf(*strp, l + 1U, fmt, ap);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETLINE
|
||||
ssize_t
|
||||
getline(char **lineptr, size_t *n, FILE *stream)
|
||||
{
|
||||
static char line[256];
|
||||
char *ptr;
|
||||
ssize_t len;
|
||||
|
||||
if (!lineptr || !n) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ferror(stream) || feof(stream)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!fgets(line, 256, stream)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr = strchr(line, '\n');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
len = strlen(line);
|
||||
|
||||
if (len + 1 < 256) {
|
||||
ptr = realloc(*lineptr, 256);
|
||||
if (!ptr) {
|
||||
return -1;
|
||||
}
|
||||
*lineptr = ptr;
|
||||
*n = 256;
|
||||
}
|
||||
|
||||
strcpy(*lineptr, line);
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRNDUP
|
||||
char *
|
||||
strndup(const char *s, size_t n)
|
||||
{
|
||||
char *buf;
|
||||
size_t len = 0;
|
||||
|
||||
/* strnlen */
|
||||
for ( ; (len < n) && (s[len] != '\0'); ++len) {}
|
||||
|
||||
if (!(buf = malloc(len + 1U))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(buf, s, len);
|
||||
buf[len] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRNSTR
|
||||
char *
|
||||
strnstr(const char *s, const char *find, size_t slen)
|
||||
{
|
||||
char c, sc;
|
||||
size_t len;
|
||||
|
||||
if ((c = *find++) != '\0') {
|
||||
len = strlen(find);
|
||||
do {
|
||||
do {
|
||||
if ((slen-- < 1) || ((sc = *s++) == '\0')) {
|
||||
return NULL;
|
||||
}
|
||||
} while (sc != c);
|
||||
if (len > slen) {
|
||||
return NULL;
|
||||
}
|
||||
} while (strncmp(s, find, len));
|
||||
s--;
|
||||
}
|
||||
return (char *)s;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRCHRNUL
|
||||
char *
|
||||
strchrnul(const char *s, int c)
|
||||
{
|
||||
char *p = strchr(s, c);
|
||||
|
||||
return p ? p : (char *)s + strlen(s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GET_CURRENT_DIR_NAME
|
||||
char *
|
||||
get_current_dir_name(void)
|
||||
{
|
||||
char tmp[_POSIX_PATH_MAX];
|
||||
char *retval = NULL;
|
||||
|
||||
if (getcwd(tmp, sizeof(tmp))) {
|
||||
retval = strdup(tmp);
|
||||
if (!retval) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||||
int
|
||||
pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime)
|
||||
{
|
||||
int64_t nsec_diff;
|
||||
int32_t diff;
|
||||
struct timespec cur, dur;
|
||||
int rc;
|
||||
|
||||
/* try to acquire the lock and, if we fail, sleep for 5ms. */
|
||||
while ((rc = pthread_mutex_trylock(mutex)) == EBUSY) {
|
||||
/* get real time */
|
||||
#ifdef CLOCK_REALTIME
|
||||
clock_gettime(CLOCK_REALTIME, &cur);
|
||||
#else
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
cur.tv_sec = (time_t)tv.tv_sec;
|
||||
cur.tv_nsec = 1000L * (long)tv.tv_usec;
|
||||
#endif
|
||||
|
||||
/* get time diff */
|
||||
nsec_diff = 0;
|
||||
nsec_diff += (((int64_t)abstime->tv_sec) - ((int64_t)cur.tv_sec)) * 1000000000L;
|
||||
nsec_diff += ((int64_t)abstime->tv_nsec) - ((int64_t)cur.tv_nsec);
|
||||
diff = (nsec_diff ? nsec_diff / 1000000L : 0);
|
||||
|
||||
if (diff < 1) {
|
||||
/* timeout */
|
||||
break;
|
||||
} else if (diff < 5) {
|
||||
/* sleep until timeout */
|
||||
dur.tv_sec = 0;
|
||||
dur.tv_nsec = (long)diff * 1000000;
|
||||
} else {
|
||||
/* sleep 5 ms */
|
||||
dur.tv_sec = 0;
|
||||
dur.tv_nsec = 5000000;
|
||||
}
|
||||
|
||||
nanosleep(&dur, NULL);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
158
compat/compat.h.in
Normal file
158
compat/compat.h.in
Normal file
|
@ -0,0 +1,158 @@
|
|||
/**
|
||||
* @file compat.h
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief compatibility functions header
|
||||
*
|
||||
* 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 _COMPAT_H_
|
||||
#define _COMPAT_H_
|
||||
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef __WORDSIZE
|
||||
# if defined __x86_64__ && !defined __ILP32__
|
||||
# define __WORDSIZE 64
|
||||
# else
|
||||
# define __WORDSIZE 32
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef __INT64_C
|
||||
# if __WORDSIZE == 64
|
||||
# define __INT64_C(c) c ## L
|
||||
# define __UINT64_C(c) c ## UL
|
||||
# else
|
||||
# define __INT64_C(c) c ## LL
|
||||
# define __UINT64_C(c) c ## ULL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (@CMAKE_C_COMPILER_ID@ == GNU) || (@CMAKE_C_COMPILER_ID@ == Clang)
|
||||
# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
|
||||
# define _PACKED __attribute__((__packed__))
|
||||
#else
|
||||
# define UNUSED(x) UNUSED_ ## x
|
||||
# define _PACKED
|
||||
#endif
|
||||
|
||||
#cmakedefine HAVE_VDPRINTF
|
||||
#cmakedefine HAVE_ASPRINTF
|
||||
#cmakedefine HAVE_VASPRINTF
|
||||
#cmakedefine HAVE_GETLINE
|
||||
#cmakedefine HAVE_STRNDUP
|
||||
#cmakedefine HAVE_STRNSTR
|
||||
#cmakedefine HAVE_STRDUPA
|
||||
#cmakedefine HAVE_STRCHRNUL
|
||||
#cmakedefine HAVE_GET_CURRENT_DIR_NAME
|
||||
#cmakedefine HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||||
|
||||
#ifndef bswap64
|
||||
#define bswap64(val) \
|
||||
( (((val) >> 56) & 0x00000000000000FF) | (((val) >> 40) & 0x000000000000FF00) | \
|
||||
(((val) >> 24) & 0x0000000000FF0000) | (((val) >> 8) & 0x00000000FF000000) | \
|
||||
(((val) << 8) & 0x000000FF00000000) | (((val) << 24) & 0x0000FF0000000000) | \
|
||||
(((val) << 40) & 0x00FF000000000000) | (((val) << 56) & 0xFF00000000000000) )
|
||||
#endif
|
||||
|
||||
#undef le64toh
|
||||
#undef htole64
|
||||
|
||||
#cmakedefine IS_BIG_ENDIAN
|
||||
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
# define le64toh(x) bswap64(x)
|
||||
# define htole64(x) bswap64(x)
|
||||
#else
|
||||
# define le64toh(x) (x)
|
||||
# define htole64(x) (x)
|
||||
#endif
|
||||
|
||||
#cmakedefine HAVE_STDATOMIC
|
||||
|
||||
#ifdef HAVE_STDATOMIC
|
||||
# include <stdatomic.h>
|
||||
|
||||
# define ATOMIC_T atomic_uint_fast32_t
|
||||
# define ATOMIC_T_MAX UINT_FAST32_MAX
|
||||
|
||||
# define ATOMIC_STORE_RELAXED(var, x) atomic_store_explicit(&(var), x, memory_order_relaxed)
|
||||
# define ATOMIC_LOAD_RELAXED(var) atomic_load_explicit(&(var), memory_order_relaxed)
|
||||
# define ATOMIC_INC_RELAXED(var) atomic_fetch_add_explicit(&(var), 1, memory_order_relaxed)
|
||||
# define ATOMIC_ADD_RELAXED(var, x) atomic_fetch_add_explicit(&(var), x, memory_order_relaxed)
|
||||
# define ATOMIC_DEC_RELAXED(var) atomic_fetch_sub_explicit(&(var), 1, memory_order_relaxed)
|
||||
# define ATOMIC_SUB_RELAXED(var, x) atomic_fetch_sub_explicit(&(var), x, memory_order_relaxed)
|
||||
#else
|
||||
# include <stdint.h>
|
||||
|
||||
# define ATOMIC_T uint32_t
|
||||
# define ATOMIC_T_MAX UINT32_MAX
|
||||
|
||||
# define ATOMIC_STORE_RELAXED(var, x) ((var) = (x))
|
||||
# define ATOMIC_LOAD_RELAXED(var) (var)
|
||||
# define ATOMIC_INC_RELAXED(var) __sync_fetch_and_add(&(var), 1)
|
||||
# define ATOMIC_ADD_RELAXED(var, x) __sync_fetch_and_add(&(var), x)
|
||||
# define ATOMIC_DEC_RELAXED(var) __sync_fetch_and_sub(&(var), 1)
|
||||
# define ATOMIC_SUB_RELAXED(var, x) __sync_fetch_and_sub(&(var), x)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_VDPRINTF
|
||||
int vdprintf(int fd, const char *format, va_list ap);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
int asprintf(char **strp, const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_VASPRINTF
|
||||
int vasprintf(char **strp, const char *fmt, va_list ap);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETLINE
|
||||
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRNDUP
|
||||
char *strndup(const char *s, size_t n);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRNSTR
|
||||
char *strnstr(const char *s, const char *find, size_t slen);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRDUPA
|
||||
#define strdupa(s) ( \
|
||||
{ \
|
||||
char *buf; \
|
||||
size_t len = strlen(s); \
|
||||
buf = alloca(len + 1); \
|
||||
buf[len] = '\0'; \
|
||||
(char *)memcpy(buf, s, len); \
|
||||
})
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRCHRNUL
|
||||
char *strchrnul(const char *s, int c);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GET_CURRENT_DIR_NAME
|
||||
char *get_current_dir_name(void);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||||
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime);
|
||||
#endif
|
||||
|
||||
#endif /* _COMPAT_H_ */
|
10
distro/config/apkg.toml
Normal file
10
distro/config/apkg.toml
Normal file
|
@ -0,0 +1,10 @@
|
|||
[project]
|
||||
name = "libnetconf2"
|
||||
make_archive_script = "distro/scripts/make-archive.sh"
|
||||
|
||||
[upstream]
|
||||
archive_url = "https://github.com/CESNET/libnetconf2/archive/refs/tags/v{{ version }}.tar.gz"
|
||||
version_script = "distro/scripts/upstream-version.sh"
|
||||
|
||||
[apkg]
|
||||
compat = 1
|
5
distro/pkg/deb/changelog
Normal file
5
distro/pkg/deb/changelog
Normal file
|
@ -0,0 +1,5 @@
|
|||
libnetconf2 ({{ version }}-{{ release }}) unstable; urgency=medium
|
||||
|
||||
* upstream packaging
|
||||
|
||||
-- Michal Vaško <mvasko@cesnet.cz> Fri, 01 Oct 2021 14:29:03 +0200
|
1
distro/pkg/deb/compat
Normal file
1
distro/pkg/deb/compat
Normal file
|
@ -0,0 +1 @@
|
|||
10
|
44
distro/pkg/deb/control
Normal file
44
distro/pkg/deb/control
Normal file
|
@ -0,0 +1,44 @@
|
|||
Source: libnetconf2
|
||||
Section: libs
|
||||
Homepage: https://github.com/CESNET/libnetconf2/
|
||||
Maintainer: CESNET <mvasko@cesnet.cz>
|
||||
Priority: optional
|
||||
Standards-Version: 4.5.0
|
||||
Build-Depends: cmake,
|
||||
debhelper (>= 10),
|
||||
libyang2-dev,
|
||||
libssl-dev,
|
||||
libssh-dev (>= 0.7.1),
|
||||
pkg-config
|
||||
Vcs-Browser: https://github.com/CESNET/libnetconf2/tree/master
|
||||
Vcs-Git: https://github.com/CESNET/libnetconf2.git
|
||||
|
||||
Package: libnetconf2-2
|
||||
Depends: ${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Architecture: any
|
||||
Description: library implementing NETCONF protocol - runtime
|
||||
Libnetconf2 implements network communication using NETCONF
|
||||
protocol specified in IETF RFC 6241. It is based on libnetconf
|
||||
(which it replaces and makes obsolete) but written from scratch.
|
||||
.
|
||||
Both server and client-side functionality is provided.
|
||||
.
|
||||
It is implemented in C.
|
||||
|
||||
Package: libnetconf2-dev
|
||||
Depends: libyang2-dev,
|
||||
libnetconf2-2 (= ${binary:Version}),
|
||||
${misc:Depends}
|
||||
Section: libdevel
|
||||
Architecture: any
|
||||
Description: library implementing NETCONF protocol - development files
|
||||
Libnetconf2 implements network communication using NETCONF
|
||||
protocol specified in IETF RFC 6241. It is based on libnetconf
|
||||
(which it replaces and makes obsolete) but written from scratch.
|
||||
.
|
||||
Both server and client-side functionality is provided.
|
||||
.
|
||||
This package contains the C headers, a pkgconfig file, and .so entry
|
||||
point for libnetconf2.
|
||||
|
46
distro/pkg/deb/copyright
Normal file
46
distro/pkg/deb/copyright
Normal file
|
@ -0,0 +1,46 @@
|
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: libnetconf2
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: *
|
||||
Copyright: 2015-2021 by CESNET, z.s.p.o.
|
||||
License: BSD-3-clause
|
||||
|
||||
Files: */ietf-*.yang */ietf-*.h
|
||||
Copyright: 2011-2018 by the IETF Trust and the persons identified as authors
|
||||
License: IETF-BSD-3-clause
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD
|
||||
License set forth in Section 4.c of the IETF Trust's
|
||||
Legal Provisions Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
.
|
||||
This version of this YANG module is part of RFC 6536; see
|
||||
the RFC itself for full legal notices.
|
||||
|
||||
License: BSD-3-clause
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
.
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
.
|
||||
* 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.
|
||||
.
|
||||
* Neither the name of libyang nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
4
distro/pkg/deb/gbp.conf
Normal file
4
distro/pkg/deb/gbp.conf
Normal file
|
@ -0,0 +1,4 @@
|
|||
[DEFAULT]
|
||||
pristine-tar = False
|
||||
debian-branch = master
|
||||
upstream-tree = SLOPPY
|
1
distro/pkg/deb/libnetconf2-2.install
Normal file
1
distro/pkg/deb/libnetconf2-2.install
Normal file
|
@ -0,0 +1 @@
|
|||
usr/lib/*/libnetconf2.so.*
|
5
distro/pkg/deb/libnetconf2-dev.install
Normal file
5
distro/pkg/deb/libnetconf2-dev.install
Normal file
|
@ -0,0 +1,5 @@
|
|||
usr/lib/*/libnetconf2.so
|
||||
usr/lib/*/pkgconfig/libnetconf2.pc
|
||||
usr/include/libnetconf2/*
|
||||
usr/include/nc_client.h
|
||||
usr/include/nc_server.h
|
12
distro/pkg/deb/rules
Executable file
12
distro/pkg/deb/rules
Executable file
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/make -f
|
||||
#export DH_VERBOSE=1
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
include /usr/share/dpkg/default.mk
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_BUILD_TYPE:String="Release"
|
1
distro/pkg/deb/source/format
Normal file
1
distro/pkg/deb/source/format
Normal file
|
@ -0,0 +1 @@
|
|||
3.0 (quilt)
|
4
distro/pkg/deb/watch
Normal file
4
distro/pkg/deb/watch
Normal file
|
@ -0,0 +1,4 @@
|
|||
version=4
|
||||
opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnetconf2-$1.tar.gz%" \
|
||||
https://github.com/CESNET/libnetconf2/releases \
|
||||
(?:.*?/)?v?(\d[\d.]*)(?:-r\d+)?\.tar\.gz debian uupdate
|
61
distro/pkg/rpm/libnetconf2.spec
Normal file
61
distro/pkg/rpm/libnetconf2.spec
Normal file
|
@ -0,0 +1,61 @@
|
|||
Name: libnetconf2
|
||||
Version: {{ version }}
|
||||
Release: {{ release }}%{?dist}
|
||||
Summary: NETCONF protocol library
|
||||
Url: https://github.com/CESNET/libnetconf2
|
||||
Source: libnetconf2-%{version}.tar.gz
|
||||
License: BSD
|
||||
|
||||
BuildRequires: cmake
|
||||
BuildRequires: make
|
||||
BuildRequires: gcc
|
||||
BuildRequires: libssh-devel
|
||||
BuildRequires: openssl-devel
|
||||
BuildRequires: pkgconfig(libyang) >= 2
|
||||
|
||||
%package devel
|
||||
Summary: Headers of libnetconf2 library
|
||||
Conflicts: libnetconf-devel
|
||||
Requires: %{name}%{?_isa} = %{version}-%{release}
|
||||
|
||||
%description devel
|
||||
Headers of libnetconf library.
|
||||
|
||||
%description
|
||||
libnetconf2 is a NETCONF library in C intended for building NETCONF clients and
|
||||
servers. NETCONF is the NETwork CONFiguration protocol introduced by IETF.
|
||||
|
||||
|
||||
%prep
|
||||
%autosetup -p1
|
||||
mkdir build
|
||||
|
||||
%build
|
||||
cd build
|
||||
cmake \
|
||||
-DCMAKE_INSTALL_PREFIX:PATH=%{_prefix} \
|
||||
-DCMAKE_BUILD_TYPE:String="Release" \
|
||||
-DCMAKE_C_FLAGS="${RPM_OPT_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${RPM_OPT_FLAGS}" \
|
||||
..
|
||||
make
|
||||
|
||||
%install
|
||||
cd build
|
||||
make DESTDIR=%{buildroot} install
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
%{_libdir}/libnetconf2.so.2*
|
||||
|
||||
%files devel
|
||||
%{_libdir}/libnetconf2.so
|
||||
%{_libdir}/pkgconfig/libnetconf2.pc
|
||||
%{_includedir}/*.h
|
||||
%{_includedir}/libnetconf2/*.h
|
||||
%dir %{_includedir}/libnetconf2/
|
||||
|
||||
|
||||
%changelog
|
||||
* Tue Oct 12 2021 Jakub Ružička <jakub.ruzicka@nic.cz> - {{ version }}-{{ release }}
|
||||
- upstream package
|
17
distro/scripts/make-archive.sh
Executable file
17
distro/scripts/make-archive.sh
Executable file
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
# create archive from current source using git
|
||||
|
||||
VERSION=$(git describe --tags --always)
|
||||
# skip "v" from start of version number (if it exists) and replace - with .
|
||||
VERSION=${VERSION#v}
|
||||
VERSION=${VERSION//[-]/.}
|
||||
|
||||
NAMEVER=libnetconf2-$VERSION
|
||||
ARCHIVE=$NAMEVER.tar.gz
|
||||
|
||||
git archive --format tgz --output $ARCHIVE --prefix $NAMEVER/ HEAD
|
||||
mkdir -p pkg/archives/dev/
|
||||
mv $ARCHIVE pkg/archives/dev/
|
||||
|
||||
# apkg expects stdout to list archive files
|
||||
echo pkg/archives/dev/$ARCHIVE
|
7
distro/scripts/upstream-version.sh
Executable file
7
distro/scripts/upstream-version.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
# get latest upstream libnetconf2 version from github
|
||||
|
||||
RLS_URL=https://api.github.com/repos/CESNET/libnetconf2/releases
|
||||
VERSION=$(curl -s $RLS_URL | grep tag_name | cut -d '"' -f 4 | sort --version-sort | tail -n 1)
|
||||
VERSION=${VERSION#v}
|
||||
echo $VERSION
|
106
doc/cesnet-style.css
Normal file
106
doc/cesnet-style.css
Normal file
|
@ -0,0 +1,106 @@
|
|||
/* CESNET blue: #0068a2 */
|
||||
|
||||
body {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
div.header {
|
||||
background-image: none;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
div.contents {
|
||||
background-color: #fff;
|
||||
padding: 1.618em 3.236em;
|
||||
max-width: 60em;
|
||||
margin: auto;
|
||||
margin-left: 0;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.sm-dox {
|
||||
background-image: none;
|
||||
background-color: #0068a2;
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
|
||||
.sm-dox a {
|
||||
background-image: none;
|
||||
border-right: 1px solid white;
|
||||
color: white;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.sm-dox a:hover {
|
||||
background-image: none;
|
||||
background-color: rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.sm-dox ul a:hover {
|
||||
background-image: none;
|
||||
background-color: #ddd;
|
||||
text-shadow: none;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.navpath ul {
|
||||
background-image: none;
|
||||
background-color: #0068a2;
|
||||
}
|
||||
|
||||
.navpath li.footer {
|
||||
color: white;
|
||||
}
|
||||
img.footer {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.navpath li.navelem a {
|
||||
color: white;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
#side-nav {
|
||||
background-color: #343131;
|
||||
}
|
||||
|
||||
#nav-tree::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
#nav-tree::-webkit-scrollbar-track {
|
||||
background: #333;
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
||||
#nav-tree::-webkit-scrollbar-thumb {
|
||||
background: #ccc;
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
||||
#nav-tree {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#nav-tree .item {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
#nav-tree .item:hover {
|
||||
background-color: rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
#nav-tree a {
|
||||
color: #fff;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
#nav-tree .selected {
|
||||
background-image: none;
|
||||
background-color: #0068a2;
|
||||
}
|
||||
|
||||
#nav-tree-contents {
|
||||
margin: 0;
|
||||
}
|
12
libnetconf2.pc.in
Normal file
12
libnetconf2.pc.in
Normal file
|
@ -0,0 +1,12 @@
|
|||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||
|
||||
Name: @PROJECT_NAME@
|
||||
Description: @LIBNETCONF2_DESCRIPTION@
|
||||
Version: @LIBNETCONF2_VERSION@
|
||||
Libs: -L${libdir} -lnetconf2
|
||||
Cflags: -I${includedir}
|
||||
|
||||
LNC2_MAX_THREAD_COUNT=@MAX_PSPOLL_THREAD_COUNT@
|
||||
LNC2_SCHEMAS_DIR=@SCHEMAS_DIR@
|
464
modules/ietf-netconf-acm@2018-02-14.yang
Normal file
464
modules/ietf-netconf-acm@2018-02-14.yang
Normal file
|
@ -0,0 +1,464 @@
|
|||
module ietf-netconf-acm {
|
||||
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm";
|
||||
|
||||
prefix nacm;
|
||||
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <https://datatracker.ietf.org/wg/netconf/>
|
||||
WG List: <mailto:netconf@ietf.org>
|
||||
|
||||
Author: Andy Bierman
|
||||
<mailto:andy@yumaworks.com>
|
||||
|
||||
Author: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com>";
|
||||
|
||||
description
|
||||
"Network Configuration Access Control Model.
|
||||
|
||||
Copyright (c) 2012 - 2018 IETF Trust and the persons
|
||||
identified as authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD
|
||||
License set forth in Section 4.c of the IETF Trust's
|
||||
Legal Provisions Relating to IETF Documents
|
||||
(https://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 8341; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision "2018-02-14" {
|
||||
description
|
||||
"Added support for YANG 1.1 actions and notifications tied to
|
||||
data nodes. Clarified how NACM extensions can be used by
|
||||
other data models.";
|
||||
reference
|
||||
"RFC 8341: Network Configuration Access Control Model";
|
||||
}
|
||||
|
||||
revision "2012-02-22" {
|
||||
description
|
||||
"Initial version.";
|
||||
reference
|
||||
"RFC 6536: Network Configuration Protocol (NETCONF)
|
||||
Access Control Model";
|
||||
}
|
||||
|
||||
/*
|
||||
* Extension statements
|
||||
*/
|
||||
|
||||
extension default-deny-write {
|
||||
description
|
||||
"Used to indicate that the data model node
|
||||
represents a sensitive security system parameter.
|
||||
|
||||
If present, the NETCONF server will only allow the designated
|
||||
'recovery session' to have write access to the node. An
|
||||
explicit access control rule is required for all other users.
|
||||
|
||||
If the NACM module is used, then it must be enabled (i.e.,
|
||||
/nacm/enable-nacm object equals 'true'), or this extension
|
||||
is ignored.
|
||||
|
||||
The 'default-deny-write' extension MAY appear within a data
|
||||
definition statement. It is ignored otherwise.";
|
||||
}
|
||||
|
||||
extension default-deny-all {
|
||||
description
|
||||
"Used to indicate that the data model node
|
||||
controls a very sensitive security system parameter.
|
||||
|
||||
If present, the NETCONF server will only allow the designated
|
||||
'recovery session' to have read, write, or execute access to
|
||||
the node. An explicit access control rule is required for all
|
||||
other users.
|
||||
|
||||
If the NACM module is used, then it must be enabled (i.e.,
|
||||
/nacm/enable-nacm object equals 'true'), or this extension
|
||||
is ignored.
|
||||
|
||||
The 'default-deny-all' extension MAY appear within a data
|
||||
definition statement, 'rpc' statement, or 'notification'
|
||||
statement. It is ignored otherwise.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Derived types
|
||||
*/
|
||||
|
||||
typedef user-name-type {
|
||||
type string {
|
||||
length "1..max";
|
||||
}
|
||||
description
|
||||
"General-purpose username string.";
|
||||
}
|
||||
|
||||
typedef matchall-string-type {
|
||||
type string {
|
||||
pattern '\*';
|
||||
}
|
||||
description
|
||||
"The string containing a single asterisk '*' is used
|
||||
to conceptually represent all possible values
|
||||
for the particular leaf using this data type.";
|
||||
}
|
||||
|
||||
typedef access-operations-type {
|
||||
type bits {
|
||||
bit create {
|
||||
description
|
||||
"Any protocol operation that creates a
|
||||
new data node.";
|
||||
}
|
||||
bit read {
|
||||
description
|
||||
"Any protocol operation or notification that
|
||||
returns the value of a data node.";
|
||||
}
|
||||
bit update {
|
||||
description
|
||||
"Any protocol operation that alters an existing
|
||||
data node.";
|
||||
}
|
||||
bit delete {
|
||||
description
|
||||
"Any protocol operation that removes a data node.";
|
||||
}
|
||||
bit exec {
|
||||
description
|
||||
"Execution access to the specified protocol operation.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Access operation.";
|
||||
}
|
||||
|
||||
typedef group-name-type {
|
||||
type string {
|
||||
length "1..max";
|
||||
pattern '[^\*].*';
|
||||
}
|
||||
description
|
||||
"Name of administrative group to which
|
||||
users can be assigned.";
|
||||
}
|
||||
|
||||
typedef action-type {
|
||||
type enumeration {
|
||||
enum permit {
|
||||
description
|
||||
"Requested action is permitted.";
|
||||
}
|
||||
enum deny {
|
||||
description
|
||||
"Requested action is denied.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Action taken by the server when a particular
|
||||
rule matches.";
|
||||
}
|
||||
|
||||
typedef node-instance-identifier {
|
||||
type yang:xpath1.0;
|
||||
description
|
||||
"Path expression used to represent a special
|
||||
data node, action, or notification instance-identifier
|
||||
string.
|
||||
|
||||
A node-instance-identifier value is an
|
||||
unrestricted YANG instance-identifier expression.
|
||||
All the same rules as an instance-identifier apply,
|
||||
except that predicates for keys are optional. If a key
|
||||
predicate is missing, then the node-instance-identifier
|
||||
represents all possible server instances for that key.
|
||||
|
||||
This XML Path Language (XPath) expression is evaluated in the
|
||||
following context:
|
||||
|
||||
o The set of namespace declarations are those in scope on
|
||||
the leaf element where this type is used.
|
||||
|
||||
o The set of variable bindings contains one variable,
|
||||
'USER', which contains the name of the user of the
|
||||
current session.
|
||||
|
||||
o The function library is the core function library, but
|
||||
note that due to the syntax restrictions of an
|
||||
instance-identifier, no functions are allowed.
|
||||
|
||||
o The context node is the root node in the data tree.
|
||||
|
||||
The accessible tree includes actions and notifications tied
|
||||
to data nodes.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Data definition statements
|
||||
*/
|
||||
|
||||
container nacm {
|
||||
nacm:default-deny-all;
|
||||
|
||||
description
|
||||
"Parameters for NETCONF access control model.";
|
||||
|
||||
leaf enable-nacm {
|
||||
type boolean;
|
||||
default "true";
|
||||
description
|
||||
"Enables or disables all NETCONF access control
|
||||
enforcement. If 'true', then enforcement
|
||||
is enabled. If 'false', then enforcement
|
||||
is disabled.";
|
||||
}
|
||||
|
||||
leaf read-default {
|
||||
type action-type;
|
||||
default "permit";
|
||||
description
|
||||
"Controls whether read access is granted if
|
||||
no appropriate rule is found for a
|
||||
particular read request.";
|
||||
}
|
||||
|
||||
leaf write-default {
|
||||
type action-type;
|
||||
default "deny";
|
||||
description
|
||||
"Controls whether create, update, or delete access
|
||||
is granted if no appropriate rule is found for a
|
||||
particular write request.";
|
||||
}
|
||||
|
||||
leaf exec-default {
|
||||
type action-type;
|
||||
default "permit";
|
||||
description
|
||||
"Controls whether exec access is granted if no appropriate
|
||||
rule is found for a particular protocol operation request.";
|
||||
}
|
||||
|
||||
leaf enable-external-groups {
|
||||
type boolean;
|
||||
default "true";
|
||||
description
|
||||
"Controls whether the server uses the groups reported by the
|
||||
NETCONF transport layer when it assigns the user to a set of
|
||||
NACM groups. If this leaf has the value 'false', any group
|
||||
names reported by the transport layer are ignored by the
|
||||
server.";
|
||||
}
|
||||
|
||||
leaf denied-operations {
|
||||
type yang:zero-based-counter32;
|
||||
config false;
|
||||
mandatory true;
|
||||
description
|
||||
"Number of times since the server last restarted that a
|
||||
protocol operation request was denied.";
|
||||
}
|
||||
|
||||
leaf denied-data-writes {
|
||||
type yang:zero-based-counter32;
|
||||
config false;
|
||||
mandatory true;
|
||||
description
|
||||
"Number of times since the server last restarted that a
|
||||
protocol operation request to alter
|
||||
a configuration datastore was denied.";
|
||||
}
|
||||
|
||||
leaf denied-notifications {
|
||||
type yang:zero-based-counter32;
|
||||
config false;
|
||||
mandatory true;
|
||||
description
|
||||
"Number of times since the server last restarted that
|
||||
a notification was dropped for a subscription because
|
||||
access to the event type was denied.";
|
||||
}
|
||||
|
||||
container groups {
|
||||
description
|
||||
"NETCONF access control groups.";
|
||||
|
||||
list group {
|
||||
key name;
|
||||
|
||||
description
|
||||
"One NACM group entry. This list will only contain
|
||||
configured entries, not any entries learned from
|
||||
any transport protocols.";
|
||||
|
||||
leaf name {
|
||||
type group-name-type;
|
||||
description
|
||||
"Group name associated with this entry.";
|
||||
}
|
||||
|
||||
leaf-list user-name {
|
||||
type user-name-type;
|
||||
description
|
||||
"Each entry identifies the username of
|
||||
a member of the group associated with
|
||||
this entry.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list rule-list {
|
||||
key name;
|
||||
ordered-by user;
|
||||
description
|
||||
"An ordered collection of access control rules.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length "1..max";
|
||||
}
|
||||
description
|
||||
"Arbitrary name assigned to the rule-list.";
|
||||
}
|
||||
leaf-list group {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type group-name-type;
|
||||
}
|
||||
description
|
||||
"List of administrative groups that will be
|
||||
assigned the associated access rights
|
||||
defined by the 'rule' list.
|
||||
|
||||
The string '*' indicates that all groups apply to the
|
||||
entry.";
|
||||
}
|
||||
|
||||
list rule {
|
||||
key name;
|
||||
ordered-by user;
|
||||
description
|
||||
"One access control rule.
|
||||
|
||||
Rules are processed in user-defined order until a match is
|
||||
found. A rule matches if 'module-name', 'rule-type', and
|
||||
'access-operations' match the request. If a rule
|
||||
matches, the 'action' leaf determines whether or not
|
||||
access is granted.";
|
||||
|
||||
leaf name {
|
||||
type string {
|
||||
length "1..max";
|
||||
}
|
||||
description
|
||||
"Arbitrary name assigned to the rule.";
|
||||
}
|
||||
|
||||
leaf module-name {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type string;
|
||||
}
|
||||
default "*";
|
||||
description
|
||||
"Name of the module associated with this rule.
|
||||
|
||||
This leaf matches if it has the value '*' or if the
|
||||
object being accessed is defined in the module with the
|
||||
specified module name.";
|
||||
}
|
||||
choice rule-type {
|
||||
description
|
||||
"This choice matches if all leafs present in the rule
|
||||
match the request. If no leafs are present, the
|
||||
choice matches all requests.";
|
||||
case protocol-operation {
|
||||
leaf rpc-name {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type string;
|
||||
}
|
||||
description
|
||||
"This leaf matches if it has the value '*' or if
|
||||
its value equals the requested protocol operation
|
||||
name.";
|
||||
}
|
||||
}
|
||||
case notification {
|
||||
leaf notification-name {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type string;
|
||||
}
|
||||
description
|
||||
"This leaf matches if it has the value '*' or if its
|
||||
value equals the requested notification name.";
|
||||
}
|
||||
}
|
||||
|
||||
case data-node {
|
||||
leaf path {
|
||||
type node-instance-identifier;
|
||||
mandatory true;
|
||||
description
|
||||
"Data node instance-identifier associated with the
|
||||
data node, action, or notification controlled by
|
||||
this rule.
|
||||
|
||||
Configuration data or state data
|
||||
instance-identifiers start with a top-level
|
||||
data node. A complete instance-identifier is
|
||||
required for this type of path value.
|
||||
|
||||
The special value '/' refers to all possible
|
||||
datastore contents.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leaf access-operations {
|
||||
type union {
|
||||
type matchall-string-type;
|
||||
type access-operations-type;
|
||||
}
|
||||
default "*";
|
||||
description
|
||||
"Access operations associated with this rule.
|
||||
|
||||
This leaf matches if it has the value '*' or if the
|
||||
bit corresponding to the requested operation is set.";
|
||||
}
|
||||
|
||||
leaf action {
|
||||
type action-type;
|
||||
mandatory true;
|
||||
description
|
||||
"The access control action associated with the
|
||||
rule. If a rule has been determined to match a
|
||||
particular request, then this object is used
|
||||
to determine whether to permit or deny the
|
||||
request.";
|
||||
}
|
||||
|
||||
leaf comment {
|
||||
type string;
|
||||
description
|
||||
"A textual description of the access rule.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
558
modules/ietf-netconf-monitoring@2010-10-04.yang
Normal file
558
modules/ietf-netconf-monitoring@2010-10-04.yang
Normal file
|
@ -0,0 +1,558 @@
|
|||
module ietf-netconf-monitoring {
|
||||
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring";
|
||||
prefix "ncm";
|
||||
|
||||
import ietf-yang-types { prefix yang; }
|
||||
import ietf-inet-types { prefix inet; }
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <http://tools.ietf.org/wg/netconf/>
|
||||
WG List: <mailto:netconf@ietf.org>
|
||||
|
||||
WG Chair: Mehmet Ersue
|
||||
<mailto:mehmet.ersue@nsn.com>
|
||||
|
||||
WG Chair: Bert Wijnen
|
||||
<mailto:bertietf@bwijnen.net>
|
||||
|
||||
Editor: Mark Scott
|
||||
<mailto:mark.scott@ericsson.com>
|
||||
|
||||
Editor: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com>";
|
||||
|
||||
description
|
||||
"NETCONF Monitoring Module.
|
||||
All elements in this module are read-only.
|
||||
|
||||
Copyright (c) 2010 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD
|
||||
License set forth in Section 4.c of the IETF Trust's
|
||||
Legal Provisions Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 6022; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision 2010-10-04 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 6022: YANG Module for NETCONF Monitoring";
|
||||
}
|
||||
|
||||
typedef netconf-datastore-type {
|
||||
type enumeration {
|
||||
enum running;
|
||||
enum candidate;
|
||||
enum startup;
|
||||
}
|
||||
description
|
||||
"Enumeration of possible NETCONF datastore types.";
|
||||
reference
|
||||
"RFC 4741: NETCONF Configuration Protocol";
|
||||
}
|
||||
|
||||
identity transport {
|
||||
description
|
||||
"Base identity for NETCONF transport types.";
|
||||
}
|
||||
|
||||
identity netconf-ssh {
|
||||
base transport;
|
||||
description
|
||||
"NETCONF over Secure Shell (SSH).";
|
||||
reference
|
||||
"RFC 4742: Using the NETCONF Configuration Protocol
|
||||
over Secure SHell (SSH)";
|
||||
}
|
||||
|
||||
identity netconf-soap-over-beep {
|
||||
base transport;
|
||||
description
|
||||
"NETCONF over Simple Object Access Protocol (SOAP) over
|
||||
Blocks Extensible Exchange Protocol (BEEP).";
|
||||
reference
|
||||
"RFC 4743: Using NETCONF over the Simple Object
|
||||
Access Protocol (SOAP)";
|
||||
}
|
||||
|
||||
identity netconf-soap-over-https {
|
||||
base transport;
|
||||
description
|
||||
"NETCONF over Simple Object Access Protocol (SOAP)
|
||||
over Hypertext Transfer Protocol Secure (HTTPS).";
|
||||
reference
|
||||
"RFC 4743: Using NETCONF over the Simple Object
|
||||
Access Protocol (SOAP)";
|
||||
}
|
||||
|
||||
identity netconf-beep {
|
||||
base transport;
|
||||
description
|
||||
"NETCONF over Blocks Extensible Exchange Protocol (BEEP).";
|
||||
reference
|
||||
"RFC 4744: Using the NETCONF Protocol over the
|
||||
Blocks Extensible Exchange Protocol (BEEP)";
|
||||
}
|
||||
|
||||
identity netconf-tls {
|
||||
base transport;
|
||||
description
|
||||
"NETCONF over Transport Layer Security (TLS).";
|
||||
reference
|
||||
"RFC 5539: NETCONF over Transport Layer Security (TLS)";
|
||||
}
|
||||
|
||||
identity schema-format {
|
||||
description
|
||||
"Base identity for data model schema languages.";
|
||||
}
|
||||
|
||||
identity xsd {
|
||||
base schema-format;
|
||||
description
|
||||
"W3C XML Schema Definition.";
|
||||
reference
|
||||
"W3C REC REC-xmlschema-1-20041028:
|
||||
XML Schema Part 1: Structures";
|
||||
}
|
||||
|
||||
identity yang {
|
||||
base schema-format;
|
||||
description
|
||||
"The YANG data modeling language for NETCONF.";
|
||||
reference
|
||||
"RFC 6020: YANG - A Data Modeling Language for the
|
||||
Network Configuration Protocol (NETCONF)";
|
||||
}
|
||||
|
||||
identity yin {
|
||||
base schema-format;
|
||||
description
|
||||
"The YIN syntax for YANG.";
|
||||
reference
|
||||
"RFC 6020: YANG - A Data Modeling Language for the
|
||||
Network Configuration Protocol (NETCONF)";
|
||||
}
|
||||
|
||||
identity rng {
|
||||
base schema-format;
|
||||
description
|
||||
"Regular Language for XML Next Generation (RELAX NG).";
|
||||
reference
|
||||
"ISO/IEC 19757-2:2008: RELAX NG";
|
||||
}
|
||||
|
||||
identity rnc {
|
||||
base schema-format;
|
||||
description
|
||||
"Relax NG Compact Syntax";
|
||||
reference
|
||||
"ISO/IEC 19757-2:2008: RELAX NG";
|
||||
}
|
||||
|
||||
grouping common-counters {
|
||||
description
|
||||
"Counters that exist both per session, and also globally,
|
||||
accumulated from all sessions.";
|
||||
|
||||
leaf in-rpcs {
|
||||
type yang:zero-based-counter32;
|
||||
description
|
||||
"Number of correct <rpc> messages received.";
|
||||
}
|
||||
leaf in-bad-rpcs {
|
||||
type yang:zero-based-counter32;
|
||||
description
|
||||
"Number of messages received when an <rpc> message was expected,
|
||||
that were not correct <rpc> messages. This includes XML parse
|
||||
errors and errors on the rpc layer.";
|
||||
}
|
||||
leaf out-rpc-errors {
|
||||
type yang:zero-based-counter32;
|
||||
description
|
||||
"Number of <rpc-reply> messages sent that contained an
|
||||
<rpc-error> element.";
|
||||
}
|
||||
leaf out-notifications {
|
||||
type yang:zero-based-counter32;
|
||||
description
|
||||
"Number of <notification> messages sent.";
|
||||
}
|
||||
}
|
||||
|
||||
container netconf-state {
|
||||
config false;
|
||||
description
|
||||
"The netconf-state container is the root of the monitoring
|
||||
data model.";
|
||||
|
||||
container capabilities {
|
||||
description
|
||||
"Contains the list of NETCONF capabilities supported by the
|
||||
server.";
|
||||
|
||||
leaf-list capability {
|
||||
type inet:uri;
|
||||
description
|
||||
"List of NETCONF capabilities supported by the server.";
|
||||
}
|
||||
}
|
||||
|
||||
container datastores {
|
||||
description
|
||||
"Contains the list of NETCONF configuration datastores.";
|
||||
|
||||
list datastore {
|
||||
key name;
|
||||
description
|
||||
"List of NETCONF configuration datastores supported by
|
||||
the NETCONF server and related information.";
|
||||
|
||||
leaf name {
|
||||
type netconf-datastore-type;
|
||||
description
|
||||
"Name of the datastore associated with this list entry.";
|
||||
}
|
||||
container locks {
|
||||
presence
|
||||
"This container is present only if the datastore
|
||||
is locked.";
|
||||
description
|
||||
"The NETCONF <lock> and <partial-lock> operations allow
|
||||
a client to lock specific resources in a datastore. The
|
||||
NETCONF server will prevent changes to the locked
|
||||
resources by all sessions except the one that acquired
|
||||
the lock(s).
|
||||
|
||||
Monitoring information is provided for each datastore
|
||||
entry including details such as the session that acquired
|
||||
the lock, the type of lock (global or partial) and the
|
||||
list of locked resources. Multiple locks per datastore
|
||||
are supported.";
|
||||
|
||||
grouping lock-info {
|
||||
description
|
||||
"Lock related parameters, common to both global and
|
||||
partial locks.";
|
||||
|
||||
leaf locked-by-session {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description
|
||||
"The session ID of the session that has locked
|
||||
this resource. Both a global lock and a partial
|
||||
lock MUST contain the NETCONF session-id.
|
||||
|
||||
If the lock is held by a session that is not managed
|
||||
by the NETCONF server (e.g., a CLI session), a session
|
||||
id of 0 (zero) is reported.";
|
||||
reference
|
||||
"RFC 4741: NETCONF Configuration Protocol";
|
||||
}
|
||||
leaf locked-time {
|
||||
type yang:date-and-time;
|
||||
mandatory true;
|
||||
description
|
||||
"The date and time of when the resource was
|
||||
locked.";
|
||||
}
|
||||
}
|
||||
|
||||
choice lock-type {
|
||||
description
|
||||
"Indicates if a global lock or a set of partial locks
|
||||
are set.";
|
||||
|
||||
container global-lock {
|
||||
description
|
||||
"Present if the global lock is set.";
|
||||
uses lock-info;
|
||||
}
|
||||
|
||||
list partial-lock {
|
||||
key lock-id;
|
||||
description
|
||||
"List of partial locks.";
|
||||
reference
|
||||
"RFC 5717: Partial Lock Remote Procedure Call (RPC) for
|
||||
NETCONF";
|
||||
|
||||
leaf lock-id {
|
||||
type uint32;
|
||||
description
|
||||
"This is the lock id returned in the <partial-lock>
|
||||
response.";
|
||||
}
|
||||
uses lock-info;
|
||||
leaf-list select {
|
||||
type yang:xpath1.0;
|
||||
min-elements 1;
|
||||
description
|
||||
"The xpath expression that was used to request
|
||||
the lock. The select expression indicates the
|
||||
original intended scope of the lock.";
|
||||
}
|
||||
leaf-list locked-node {
|
||||
type instance-identifier;
|
||||
description
|
||||
"The list of instance-identifiers (i.e., the
|
||||
locked nodes).
|
||||
|
||||
The scope of the partial lock is defined by the list
|
||||
of locked nodes.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container schemas {
|
||||
description
|
||||
"Contains the list of data model schemas supported by the
|
||||
server.";
|
||||
|
||||
list schema {
|
||||
key "identifier version format";
|
||||
|
||||
description
|
||||
"List of data model schemas supported by the server.";
|
||||
|
||||
leaf identifier {
|
||||
type string;
|
||||
description
|
||||
"Identifier to uniquely reference the schema. The
|
||||
identifier is used in the <get-schema> operation and may
|
||||
be used for other purposes such as file retrieval.
|
||||
|
||||
For modeling languages that support or require a data
|
||||
model name (e.g., YANG module name) the identifier MUST
|
||||
match that name. For YANG data models, the identifier is
|
||||
the name of the module or submodule. In other cases, an
|
||||
identifier such as a filename MAY be used instead.";
|
||||
}
|
||||
leaf version {
|
||||
type string;
|
||||
description
|
||||
"Version of the schema supported. Multiple versions MAY be
|
||||
supported simultaneously by a NETCONF server. Each
|
||||
version MUST be reported individually in the schema list,
|
||||
i.e., with same identifier, possibly different location,
|
||||
but different version.
|
||||
|
||||
For YANG data models, version is the value of the most
|
||||
recent YANG 'revision' statement in the module or
|
||||
submodule, or the empty string if no 'revision' statement
|
||||
is present.";
|
||||
}
|
||||
leaf format {
|
||||
type identityref {
|
||||
base schema-format;
|
||||
}
|
||||
description
|
||||
"The data modeling language the schema is written
|
||||
in (currently xsd, yang, yin, rng, or rnc).
|
||||
For YANG data models, 'yang' format MUST be supported and
|
||||
'yin' format MAY also be provided.";
|
||||
}
|
||||
leaf namespace {
|
||||
type inet:uri;
|
||||
mandatory true;
|
||||
description
|
||||
"The XML namespace defined by the data model.
|
||||
|
||||
For YANG data models, this is the module's namespace.
|
||||
If the list entry describes a submodule, this field
|
||||
contains the namespace of the module to which the
|
||||
submodule belongs.";
|
||||
}
|
||||
leaf-list location {
|
||||
type union {
|
||||
type enumeration {
|
||||
enum "NETCONF";
|
||||
}
|
||||
type inet:uri;
|
||||
}
|
||||
description
|
||||
"One or more locations from which the schema can be
|
||||
retrieved. This list SHOULD contain at least one
|
||||
entry per schema.
|
||||
|
||||
A schema entry may be located on a remote file system
|
||||
(e.g., reference to file system for ftp retrieval) or
|
||||
retrieved directly from a server supporting the
|
||||
<get-schema> operation (denoted by the value 'NETCONF').";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container sessions {
|
||||
description
|
||||
"The sessions container includes session-specific data for
|
||||
NETCONF management sessions. The session list MUST include
|
||||
all currently active NETCONF sessions.";
|
||||
|
||||
list session {
|
||||
key session-id;
|
||||
description
|
||||
"All NETCONF sessions managed by the NETCONF server
|
||||
MUST be reported in this list.";
|
||||
|
||||
leaf session-id {
|
||||
type uint32 {
|
||||
range "1..max";
|
||||
}
|
||||
description
|
||||
"Unique identifier for the session. This value is the
|
||||
NETCONF session identifier, as defined in RFC 4741.";
|
||||
reference
|
||||
"RFC 4741: NETCONF Configuration Protocol";
|
||||
}
|
||||
leaf transport {
|
||||
type identityref {
|
||||
base transport;
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"Identifies the transport for each session, e.g.,
|
||||
'netconf-ssh', 'netconf-soap', etc.";
|
||||
}
|
||||
leaf username {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"The username is the client identity that was authenticated
|
||||
by the NETCONF transport protocol. The algorithm used to
|
||||
derive the username is NETCONF transport protocol specific
|
||||
and in addition specific to the authentication mechanism
|
||||
used by the NETCONF transport protocol.";
|
||||
}
|
||||
leaf source-host {
|
||||
type inet:host;
|
||||
description
|
||||
"Host identifier of the NETCONF client. The value
|
||||
returned is implementation specific (e.g., hostname,
|
||||
IPv4 address, IPv6 address)";
|
||||
}
|
||||
leaf login-time {
|
||||
type yang:date-and-time;
|
||||
mandatory true;
|
||||
description
|
||||
"Time at the server at which the session was established.";
|
||||
}
|
||||
uses common-counters {
|
||||
description
|
||||
"Per-session counters. Zero based with following reset
|
||||
behaviour:
|
||||
- at start of a session
|
||||
- when max value is reached";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container statistics {
|
||||
description
|
||||
"Statistical data pertaining to the NETCONF server.";
|
||||
|
||||
leaf netconf-start-time {
|
||||
type yang:date-and-time;
|
||||
description
|
||||
"Date and time at which the management subsystem was
|
||||
started.";
|
||||
}
|
||||
leaf in-bad-hellos {
|
||||
type yang:zero-based-counter32;
|
||||
description
|
||||
"Number of sessions silently dropped because an
|
||||
invalid <hello> message was received. This includes <hello>
|
||||
messages with a 'session-id' attribute, bad namespace, and
|
||||
bad capability declarations.";
|
||||
}
|
||||
leaf in-sessions {
|
||||
type yang:zero-based-counter32;
|
||||
description
|
||||
"Number of sessions started. This counter is incremented
|
||||
when a <hello> message with a <session-id> is sent.
|
||||
|
||||
'in-sessions' - 'in-bad-hellos' =
|
||||
'number of correctly started netconf sessions'";
|
||||
}
|
||||
leaf dropped-sessions {
|
||||
type yang:zero-based-counter32;
|
||||
description
|
||||
"Number of sessions that were abnormally terminated, e.g.,
|
||||
due to idle timeout or transport close. This counter is not
|
||||
incremented when a session is properly closed by a
|
||||
<close-session> operation, or killed by a <kill-session>
|
||||
operation.";
|
||||
}
|
||||
uses common-counters {
|
||||
description
|
||||
"Global counters, accumulated from all sessions.
|
||||
Zero based with following reset behaviour:
|
||||
- re-initialization of NETCONF server
|
||||
- when max value is reached";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc get-schema {
|
||||
description
|
||||
"This operation is used to retrieve a schema from the
|
||||
NETCONF server.
|
||||
|
||||
Positive Response:
|
||||
The NETCONF server returns the requested schema.
|
||||
|
||||
Negative Response:
|
||||
If requested schema does not exist, the <error-tag> is
|
||||
'invalid-value'.
|
||||
|
||||
If more than one schema matches the requested parameters, the
|
||||
<error-tag> is 'operation-failed', and <error-app-tag> is
|
||||
'data-not-unique'.";
|
||||
|
||||
input {
|
||||
leaf identifier {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"Identifier for the schema list entry.";
|
||||
}
|
||||
leaf version {
|
||||
type string;
|
||||
description
|
||||
"Version of the schema requested. If this parameter is not
|
||||
present, and more than one version of the schema exists on
|
||||
the server, a 'data-not-unique' error is returned, as
|
||||
described above.";
|
||||
}
|
||||
leaf format {
|
||||
type identityref {
|
||||
base schema-format;
|
||||
}
|
||||
description
|
||||
"The data modeling language of the schema. If this
|
||||
parameter is not present, and more than one formats of
|
||||
the schema exists on the server, a 'data-not-unique' error
|
||||
is returned, as described above.";
|
||||
}
|
||||
}
|
||||
output {
|
||||
anyxml data {
|
||||
description
|
||||
"Contains the schema content.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
939
modules/ietf-netconf@2013-09-29.yang
Normal file
939
modules/ietf-netconf@2013-09-29.yang
Normal file
|
@ -0,0 +1,939 @@
|
|||
module ietf-netconf {
|
||||
|
||||
// the namespace for NETCONF XML definitions is unchanged
|
||||
// from RFC 4741, which this document replaces
|
||||
namespace "urn:ietf:params:xml:ns:netconf:base:1.0";
|
||||
|
||||
prefix nc;
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
|
||||
import ietf-netconf-acm { prefix nacm; }
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <http://tools.ietf.org/wg/netconf/>
|
||||
WG List: <netconf@ietf.org>
|
||||
|
||||
WG Chair: Bert Wijnen
|
||||
<bertietf@bwijnen.net>
|
||||
|
||||
WG Chair: Mehmet Ersue
|
||||
<mehmet.ersue@nsn.com>
|
||||
|
||||
Editor: Martin Bjorklund
|
||||
<mbj@tail-f.com>
|
||||
|
||||
Editor: Juergen Schoenwaelder
|
||||
<j.schoenwaelder@jacobs-university.de>
|
||||
|
||||
Editor: Andy Bierman
|
||||
<andy.bierman@brocade.com>";
|
||||
description
|
||||
"NETCONF Protocol Data Types and Protocol Operations.
|
||||
|
||||
Copyright (c) 2011 IETF Trust and the persons identified as
|
||||
the document authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 6241; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision 2013-09-29 {
|
||||
description
|
||||
"Updated to include NACM attributes";
|
||||
reference
|
||||
"RFC 6536: sec 3.2.5 and 3.2.8";
|
||||
}
|
||||
|
||||
revision 2011-06-01 {
|
||||
description
|
||||
"Initial revision";
|
||||
reference
|
||||
"RFC 6241: Network Configuration Protocol";
|
||||
}
|
||||
|
||||
extension get-filter-element-attributes {
|
||||
description
|
||||
"If this extension is present within an 'anyxml'
|
||||
statement named 'filter', which must be conceptually
|
||||
defined within the RPC input section for the <get>
|
||||
and <get-config> protocol operations, then the
|
||||
following unqualified XML attribute is supported
|
||||
within the <filter> element, within a <get> or
|
||||
<get-config> protocol operation:
|
||||
|
||||
type : optional attribute with allowed
|
||||
value strings 'subtree' and 'xpath'.
|
||||
If missing, the default value is 'subtree'.
|
||||
|
||||
If the 'xpath' feature is supported, then the
|
||||
following unqualified XML attribute is
|
||||
also supported:
|
||||
|
||||
select: optional attribute containing a
|
||||
string representing an XPath expression.
|
||||
The 'type' attribute must be equal to 'xpath'
|
||||
if this attribute is present.";
|
||||
}
|
||||
|
||||
// NETCONF capabilities defined as features
|
||||
feature writable-running {
|
||||
description
|
||||
"NETCONF :writable-running capability;
|
||||
If the server advertises the :writable-running
|
||||
capability for a session, then this feature must
|
||||
also be enabled for that session. Otherwise,
|
||||
this feature must not be enabled.";
|
||||
reference "RFC 6241, Section 8.2";
|
||||
}
|
||||
|
||||
feature candidate {
|
||||
description
|
||||
"NETCONF :candidate capability;
|
||||
If the server advertises the :candidate
|
||||
capability for a session, then this feature must
|
||||
also be enabled for that session. Otherwise,
|
||||
this feature must not be enabled.";
|
||||
reference "RFC 6241, Section 8.3";
|
||||
}
|
||||
|
||||
feature confirmed-commit {
|
||||
if-feature candidate;
|
||||
description
|
||||
"NETCONF :confirmed-commit:1.1 capability;
|
||||
If the server advertises the :confirmed-commit:1.1
|
||||
capability for a session, then this feature must
|
||||
also be enabled for that session. Otherwise,
|
||||
this feature must not be enabled.";
|
||||
|
||||
reference "RFC 6241, Section 8.4";
|
||||
}
|
||||
|
||||
feature rollback-on-error {
|
||||
description
|
||||
"NETCONF :rollback-on-error capability;
|
||||
If the server advertises the :rollback-on-error
|
||||
capability for a session, then this feature must
|
||||
also be enabled for that session. Otherwise,
|
||||
this feature must not be enabled.";
|
||||
reference "RFC 6241, Section 8.5";
|
||||
}
|
||||
|
||||
feature validate {
|
||||
description
|
||||
"NETCONF :validate:1.1 capability;
|
||||
If the server advertises the :validate:1.1
|
||||
capability for a session, then this feature must
|
||||
also be enabled for that session. Otherwise,
|
||||
this feature must not be enabled.";
|
||||
reference "RFC 6241, Section 8.6";
|
||||
}
|
||||
|
||||
feature startup {
|
||||
description
|
||||
"NETCONF :startup capability;
|
||||
If the server advertises the :startup
|
||||
capability for a session, then this feature must
|
||||
also be enabled for that session. Otherwise,
|
||||
this feature must not be enabled.";
|
||||
reference "RFC 6241, Section 8.7";
|
||||
}
|
||||
|
||||
feature url {
|
||||
description
|
||||
"NETCONF :url capability;
|
||||
If the server advertises the :url
|
||||
capability for a session, then this feature must
|
||||
also be enabled for that session. Otherwise,
|
||||
this feature must not be enabled.";
|
||||
reference "RFC 6241, Section 8.8";
|
||||
}
|
||||
|
||||
feature xpath {
|
||||
description
|
||||
"NETCONF :xpath capability;
|
||||
If the server advertises the :xpath
|
||||
capability for a session, then this feature must
|
||||
also be enabled for that session. Otherwise,
|
||||
this feature must not be enabled.";
|
||||
reference "RFC 6241, Section 8.9";
|
||||
}
|
||||
|
||||
// NETCONF Simple Types
|
||||
|
||||
typedef session-id-type {
|
||||
type uint32 {
|
||||
range "1..max";
|
||||
}
|
||||
description
|
||||
"NETCONF Session Id";
|
||||
}
|
||||
|
||||
typedef session-id-or-zero-type {
|
||||
type uint32;
|
||||
description
|
||||
"NETCONF Session Id or Zero to indicate none";
|
||||
}
|
||||
typedef error-tag-type {
|
||||
type enumeration {
|
||||
enum in-use {
|
||||
description
|
||||
"The request requires a resource that
|
||||
already is in use.";
|
||||
}
|
||||
enum invalid-value {
|
||||
description
|
||||
"The request specifies an unacceptable value for one
|
||||
or more parameters.";
|
||||
}
|
||||
enum too-big {
|
||||
description
|
||||
"The request or response (that would be generated) is
|
||||
too large for the implementation to handle.";
|
||||
}
|
||||
enum missing-attribute {
|
||||
description
|
||||
"An expected attribute is missing.";
|
||||
}
|
||||
enum bad-attribute {
|
||||
description
|
||||
"An attribute value is not correct; e.g., wrong type,
|
||||
out of range, pattern mismatch.";
|
||||
}
|
||||
enum unknown-attribute {
|
||||
description
|
||||
"An unexpected attribute is present.";
|
||||
}
|
||||
enum missing-element {
|
||||
description
|
||||
"An expected element is missing.";
|
||||
}
|
||||
enum bad-element {
|
||||
description
|
||||
"An element value is not correct; e.g., wrong type,
|
||||
out of range, pattern mismatch.";
|
||||
}
|
||||
enum unknown-element {
|
||||
description
|
||||
"An unexpected element is present.";
|
||||
}
|
||||
enum unknown-namespace {
|
||||
description
|
||||
"An unexpected namespace is present.";
|
||||
}
|
||||
enum access-denied {
|
||||
description
|
||||
"Access to the requested protocol operation or
|
||||
data model is denied because authorization failed.";
|
||||
}
|
||||
enum lock-denied {
|
||||
description
|
||||
"Access to the requested lock is denied because the
|
||||
lock is currently held by another entity.";
|
||||
}
|
||||
enum resource-denied {
|
||||
description
|
||||
"Request could not be completed because of
|
||||
insufficient resources.";
|
||||
}
|
||||
enum rollback-failed {
|
||||
description
|
||||
"Request to roll back some configuration change (via
|
||||
rollback-on-error or <discard-changes> operations)
|
||||
was not completed for some reason.";
|
||||
|
||||
}
|
||||
enum data-exists {
|
||||
description
|
||||
"Request could not be completed because the relevant
|
||||
data model content already exists. For example,
|
||||
a 'create' operation was attempted on data that
|
||||
already exists.";
|
||||
}
|
||||
enum data-missing {
|
||||
description
|
||||
"Request could not be completed because the relevant
|
||||
data model content does not exist. For example,
|
||||
a 'delete' operation was attempted on
|
||||
data that does not exist.";
|
||||
}
|
||||
enum operation-not-supported {
|
||||
description
|
||||
"Request could not be completed because the requested
|
||||
operation is not supported by this implementation.";
|
||||
}
|
||||
enum operation-failed {
|
||||
description
|
||||
"Request could not be completed because the requested
|
||||
operation failed for some reason not covered by
|
||||
any other error condition.";
|
||||
}
|
||||
enum partial-operation {
|
||||
description
|
||||
"This error-tag is obsolete, and SHOULD NOT be sent
|
||||
by servers conforming to this document.";
|
||||
}
|
||||
enum malformed-message {
|
||||
description
|
||||
"A message could not be handled because it failed to
|
||||
be parsed correctly. For example, the message is not
|
||||
well-formed XML or it uses an invalid character set.";
|
||||
}
|
||||
}
|
||||
description "NETCONF Error Tag";
|
||||
reference "RFC 6241, Appendix A";
|
||||
}
|
||||
|
||||
typedef error-severity-type {
|
||||
type enumeration {
|
||||
enum error {
|
||||
description "Error severity";
|
||||
}
|
||||
enum warning {
|
||||
description "Warning severity";
|
||||
}
|
||||
}
|
||||
description "NETCONF Error Severity";
|
||||
reference "RFC 6241, Section 4.3";
|
||||
}
|
||||
|
||||
typedef edit-operation-type {
|
||||
type enumeration {
|
||||
enum merge {
|
||||
description
|
||||
"The configuration data identified by the
|
||||
element containing this attribute is merged
|
||||
with the configuration at the corresponding
|
||||
level in the configuration datastore identified
|
||||
by the target parameter.";
|
||||
}
|
||||
enum replace {
|
||||
description
|
||||
"The configuration data identified by the element
|
||||
containing this attribute replaces any related
|
||||
configuration in the configuration datastore
|
||||
identified by the target parameter. If no such
|
||||
configuration data exists in the configuration
|
||||
datastore, it is created. Unlike a
|
||||
<copy-config> operation, which replaces the
|
||||
entire target configuration, only the configuration
|
||||
actually present in the config parameter is affected.";
|
||||
}
|
||||
enum create {
|
||||
description
|
||||
"The configuration data identified by the element
|
||||
containing this attribute is added to the
|
||||
configuration if and only if the configuration
|
||||
data does not already exist in the configuration
|
||||
datastore. If the configuration data exists, an
|
||||
<rpc-error> element is returned with an
|
||||
<error-tag> value of 'data-exists'.";
|
||||
}
|
||||
enum delete {
|
||||
description
|
||||
"The configuration data identified by the element
|
||||
containing this attribute is deleted from the
|
||||
configuration if and only if the configuration
|
||||
data currently exists in the configuration
|
||||
datastore. If the configuration data does not
|
||||
exist, an <rpc-error> element is returned with
|
||||
an <error-tag> value of 'data-missing'.";
|
||||
}
|
||||
enum remove {
|
||||
description
|
||||
"The configuration data identified by the element
|
||||
containing this attribute is deleted from the
|
||||
configuration if the configuration
|
||||
data currently exists in the configuration
|
||||
datastore. If the configuration data does not
|
||||
exist, the 'remove' operation is silently ignored
|
||||
by the server.";
|
||||
}
|
||||
}
|
||||
default "merge";
|
||||
description "NETCONF 'operation' attribute values";
|
||||
reference "RFC 6241, Section 7.2";
|
||||
}
|
||||
|
||||
// NETCONF Standard Protocol Operations
|
||||
|
||||
rpc get-config {
|
||||
description
|
||||
"Retrieve all or part of a specified configuration.";
|
||||
|
||||
reference "RFC 6241, Section 7.1";
|
||||
|
||||
input {
|
||||
container source {
|
||||
description
|
||||
"Particular configuration to retrieve.";
|
||||
|
||||
choice config-source {
|
||||
mandatory true;
|
||||
description
|
||||
"The configuration to retrieve.";
|
||||
leaf candidate {
|
||||
if-feature candidate;
|
||||
type empty;
|
||||
description
|
||||
"The candidate configuration is the config source.";
|
||||
}
|
||||
leaf running {
|
||||
type empty;
|
||||
description
|
||||
"The running configuration is the config source.";
|
||||
}
|
||||
leaf startup {
|
||||
if-feature startup;
|
||||
type empty;
|
||||
description
|
||||
"The startup configuration is the config source.
|
||||
This is optional-to-implement on the server because
|
||||
not all servers will support filtering for this
|
||||
datastore.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anyxml filter {
|
||||
description
|
||||
"Subtree or XPath filter to use.";
|
||||
nc:get-filter-element-attributes;
|
||||
}
|
||||
}
|
||||
|
||||
output {
|
||||
anyxml data {
|
||||
description
|
||||
"Copy of the source datastore subset that matched
|
||||
the filter criteria (if any). An empty data container
|
||||
indicates that the request did not produce any results.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc edit-config {
|
||||
description
|
||||
"The <edit-config> operation loads all or part of a specified
|
||||
configuration to the specified target configuration.";
|
||||
|
||||
reference "RFC 6241, Section 7.2";
|
||||
|
||||
input {
|
||||
container target {
|
||||
description
|
||||
"Particular configuration to edit.";
|
||||
|
||||
choice config-target {
|
||||
mandatory true;
|
||||
description
|
||||
"The configuration target.";
|
||||
|
||||
leaf candidate {
|
||||
if-feature candidate;
|
||||
type empty;
|
||||
description
|
||||
"The candidate configuration is the config target.";
|
||||
}
|
||||
leaf running {
|
||||
if-feature writable-running;
|
||||
type empty;
|
||||
description
|
||||
"The running configuration is the config source.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leaf default-operation {
|
||||
type enumeration {
|
||||
enum merge {
|
||||
description
|
||||
"The default operation is merge.";
|
||||
}
|
||||
enum replace {
|
||||
description
|
||||
"The default operation is replace.";
|
||||
}
|
||||
enum none {
|
||||
description
|
||||
"There is no default operation.";
|
||||
}
|
||||
}
|
||||
default "merge";
|
||||
description
|
||||
"The default operation to use.";
|
||||
}
|
||||
|
||||
leaf test-option {
|
||||
if-feature validate;
|
||||
type enumeration {
|
||||
enum test-then-set {
|
||||
description
|
||||
"The server will test and then set if no errors.";
|
||||
}
|
||||
enum set {
|
||||
description
|
||||
"The server will set without a test first.";
|
||||
}
|
||||
|
||||
enum test-only {
|
||||
description
|
||||
"The server will only test and not set, even
|
||||
if there are no errors.";
|
||||
}
|
||||
}
|
||||
default "test-then-set";
|
||||
description
|
||||
"The test option to use.";
|
||||
}
|
||||
|
||||
leaf error-option {
|
||||
type enumeration {
|
||||
enum stop-on-error {
|
||||
description
|
||||
"The server will stop on errors.";
|
||||
}
|
||||
enum continue-on-error {
|
||||
description
|
||||
"The server may continue on errors.";
|
||||
}
|
||||
enum rollback-on-error {
|
||||
description
|
||||
"The server will roll back on errors.
|
||||
This value can only be used if the 'rollback-on-error'
|
||||
feature is supported.";
|
||||
}
|
||||
}
|
||||
default "stop-on-error";
|
||||
description
|
||||
"The error option to use.";
|
||||
}
|
||||
|
||||
choice edit-content {
|
||||
mandatory true;
|
||||
description
|
||||
"The content for the edit operation.";
|
||||
|
||||
anyxml config {
|
||||
description
|
||||
"Inline Config content.";
|
||||
}
|
||||
leaf url {
|
||||
if-feature url;
|
||||
type inet:uri;
|
||||
description
|
||||
"URL-based config content.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc copy-config {
|
||||
description
|
||||
"Create or replace an entire configuration datastore with the
|
||||
contents of another complete configuration datastore.";
|
||||
|
||||
reference "RFC 6241, Section 7.3";
|
||||
|
||||
input {
|
||||
container target {
|
||||
description
|
||||
"Particular configuration to copy to.";
|
||||
|
||||
choice config-target {
|
||||
mandatory true;
|
||||
description
|
||||
"The configuration target of the copy operation.";
|
||||
|
||||
leaf candidate {
|
||||
if-feature candidate;
|
||||
type empty;
|
||||
description
|
||||
"The candidate configuration is the config target.";
|
||||
}
|
||||
leaf running {
|
||||
if-feature writable-running;
|
||||
type empty;
|
||||
description
|
||||
"The running configuration is the config target.
|
||||
This is optional-to-implement on the server.";
|
||||
}
|
||||
leaf startup {
|
||||
if-feature startup;
|
||||
type empty;
|
||||
description
|
||||
"The startup configuration is the config target.";
|
||||
}
|
||||
leaf url {
|
||||
if-feature url;
|
||||
type inet:uri;
|
||||
description
|
||||
"The URL-based configuration is the config target.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container source {
|
||||
description
|
||||
"Particular configuration to copy from.";
|
||||
|
||||
choice config-source {
|
||||
mandatory true;
|
||||
description
|
||||
"The configuration source for the copy operation.";
|
||||
|
||||
leaf candidate {
|
||||
if-feature candidate;
|
||||
type empty;
|
||||
description
|
||||
"The candidate configuration is the config source.";
|
||||
}
|
||||
leaf running {
|
||||
type empty;
|
||||
description
|
||||
"The running configuration is the config source.";
|
||||
}
|
||||
leaf startup {
|
||||
if-feature startup;
|
||||
type empty;
|
||||
description
|
||||
"The startup configuration is the config source.";
|
||||
}
|
||||
leaf url {
|
||||
if-feature url;
|
||||
type inet:uri;
|
||||
description
|
||||
"The URL-based configuration is the config source.";
|
||||
}
|
||||
anyxml config {
|
||||
description
|
||||
"Inline Config content: <config> element. Represents
|
||||
an entire configuration datastore, not
|
||||
a subset of the running datastore.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc delete-config {
|
||||
nacm:default-deny-all;
|
||||
description
|
||||
"Delete a configuration datastore.";
|
||||
|
||||
reference "RFC 6241, Section 7.4";
|
||||
|
||||
input {
|
||||
container target {
|
||||
description
|
||||
"Particular configuration to delete.";
|
||||
|
||||
choice config-target {
|
||||
mandatory true;
|
||||
description
|
||||
"The configuration target to delete.";
|
||||
|
||||
leaf startup {
|
||||
if-feature startup;
|
||||
type empty;
|
||||
description
|
||||
"The startup configuration is the config target.";
|
||||
}
|
||||
leaf url {
|
||||
if-feature url;
|
||||
type inet:uri;
|
||||
description
|
||||
"The URL-based configuration is the config target.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc lock {
|
||||
description
|
||||
"The lock operation allows the client to lock the configuration
|
||||
system of a device.";
|
||||
|
||||
reference "RFC 6241, Section 7.5";
|
||||
|
||||
input {
|
||||
container target {
|
||||
description
|
||||
"Particular configuration to lock.";
|
||||
|
||||
choice config-target {
|
||||
mandatory true;
|
||||
description
|
||||
"The configuration target to lock.";
|
||||
|
||||
leaf candidate {
|
||||
if-feature candidate;
|
||||
type empty;
|
||||
description
|
||||
"The candidate configuration is the config target.";
|
||||
}
|
||||
leaf running {
|
||||
type empty;
|
||||
description
|
||||
"The running configuration is the config target.";
|
||||
}
|
||||
leaf startup {
|
||||
if-feature startup;
|
||||
type empty;
|
||||
description
|
||||
"The startup configuration is the config target.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc unlock {
|
||||
description
|
||||
"The unlock operation is used to release a configuration lock,
|
||||
previously obtained with the 'lock' operation.";
|
||||
|
||||
reference "RFC 6241, Section 7.6";
|
||||
|
||||
input {
|
||||
container target {
|
||||
description
|
||||
"Particular configuration to unlock.";
|
||||
|
||||
choice config-target {
|
||||
mandatory true;
|
||||
description
|
||||
"The configuration target to unlock.";
|
||||
|
||||
leaf candidate {
|
||||
if-feature candidate;
|
||||
type empty;
|
||||
description
|
||||
"The candidate configuration is the config target.";
|
||||
}
|
||||
leaf running {
|
||||
type empty;
|
||||
description
|
||||
"The running configuration is the config target.";
|
||||
}
|
||||
leaf startup {
|
||||
if-feature startup;
|
||||
type empty;
|
||||
description
|
||||
"The startup configuration is the config target.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc get {
|
||||
description
|
||||
"Retrieve running configuration and device state information.";
|
||||
|
||||
reference "RFC 6241, Section 7.7";
|
||||
|
||||
input {
|
||||
anyxml filter {
|
||||
description
|
||||
"This parameter specifies the portion of the system
|
||||
configuration and state data to retrieve.";
|
||||
nc:get-filter-element-attributes;
|
||||
}
|
||||
}
|
||||
|
||||
output {
|
||||
anyxml data {
|
||||
description
|
||||
"Copy of the running datastore subset and/or state
|
||||
data that matched the filter criteria (if any).
|
||||
An empty data container indicates that the request did not
|
||||
produce any results.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc close-session {
|
||||
description
|
||||
"Request graceful termination of a NETCONF session.";
|
||||
|
||||
reference "RFC 6241, Section 7.8";
|
||||
}
|
||||
|
||||
rpc kill-session {
|
||||
nacm:default-deny-all;
|
||||
description
|
||||
"Force the termination of a NETCONF session.";
|
||||
|
||||
reference "RFC 6241, Section 7.9";
|
||||
|
||||
input {
|
||||
leaf session-id {
|
||||
type session-id-type;
|
||||
mandatory true;
|
||||
description
|
||||
"Particular session to kill.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc commit {
|
||||
if-feature candidate;
|
||||
|
||||
description
|
||||
"Commit the candidate configuration as the device's new
|
||||
current configuration.";
|
||||
|
||||
reference "RFC 6241, Section 8.3.4.1";
|
||||
|
||||
input {
|
||||
leaf confirmed {
|
||||
if-feature confirmed-commit;
|
||||
type empty;
|
||||
description
|
||||
"Requests a confirmed commit.";
|
||||
reference "RFC 6241, Section 8.3.4.1";
|
||||
}
|
||||
|
||||
leaf confirm-timeout {
|
||||
if-feature confirmed-commit;
|
||||
type uint32 {
|
||||
range "1..max";
|
||||
}
|
||||
units "seconds";
|
||||
default "600"; // 10 minutes
|
||||
description
|
||||
"The timeout interval for a confirmed commit.";
|
||||
reference "RFC 6241, Section 8.3.4.1";
|
||||
}
|
||||
|
||||
leaf persist {
|
||||
if-feature confirmed-commit;
|
||||
type string;
|
||||
description
|
||||
"This parameter is used to make a confirmed commit
|
||||
persistent. A persistent confirmed commit is not aborted
|
||||
if the NETCONF session terminates. The only way to abort
|
||||
a persistent confirmed commit is to let the timer expire,
|
||||
or to use the <cancel-commit> operation.
|
||||
|
||||
The value of this parameter is a token that must be given
|
||||
in the 'persist-id' parameter of <commit> or
|
||||
<cancel-commit> operations in order to confirm or cancel
|
||||
the persistent confirmed commit.
|
||||
|
||||
The token should be a random string.";
|
||||
reference "RFC 6241, Section 8.3.4.1";
|
||||
}
|
||||
|
||||
leaf persist-id {
|
||||
if-feature confirmed-commit;
|
||||
type string;
|
||||
description
|
||||
"This parameter is given in order to commit a persistent
|
||||
confirmed commit. The value must be equal to the value
|
||||
given in the 'persist' parameter to the <commit> operation.
|
||||
If it does not match, the operation fails with an
|
||||
'invalid-value' error.";
|
||||
reference "RFC 6241, Section 8.3.4.1";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
rpc discard-changes {
|
||||
if-feature candidate;
|
||||
|
||||
description
|
||||
"Revert the candidate configuration to the current
|
||||
running configuration.";
|
||||
reference "RFC 6241, Section 8.3.4.2";
|
||||
}
|
||||
|
||||
rpc cancel-commit {
|
||||
if-feature confirmed-commit;
|
||||
description
|
||||
"This operation is used to cancel an ongoing confirmed commit.
|
||||
If the confirmed commit is persistent, the parameter
|
||||
'persist-id' must be given, and it must match the value of the
|
||||
'persist' parameter.";
|
||||
reference "RFC 6241, Section 8.4.4.1";
|
||||
|
||||
input {
|
||||
leaf persist-id {
|
||||
type string;
|
||||
description
|
||||
"This parameter is given in order to cancel a persistent
|
||||
confirmed commit. The value must be equal to the value
|
||||
given in the 'persist' parameter to the <commit> operation.
|
||||
If it does not match, the operation fails with an
|
||||
'invalid-value' error.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc validate {
|
||||
if-feature validate;
|
||||
|
||||
description
|
||||
"Validates the contents of the specified configuration.";
|
||||
|
||||
reference "RFC 6241, Section 8.6.4.1";
|
||||
|
||||
input {
|
||||
container source {
|
||||
description
|
||||
"Particular configuration to validate.";
|
||||
|
||||
choice config-source {
|
||||
mandatory true;
|
||||
description
|
||||
"The configuration source to validate.";
|
||||
|
||||
leaf candidate {
|
||||
if-feature candidate;
|
||||
type empty;
|
||||
description
|
||||
"The candidate configuration is the config source.";
|
||||
}
|
||||
leaf running {
|
||||
type empty;
|
||||
description
|
||||
"The running configuration is the config source.";
|
||||
}
|
||||
leaf startup {
|
||||
if-feature startup;
|
||||
type empty;
|
||||
description
|
||||
"The startup configuration is the config source.";
|
||||
}
|
||||
leaf url {
|
||||
if-feature url;
|
||||
type inet:uri;
|
||||
description
|
||||
"The URL-based configuration is the config source.";
|
||||
}
|
||||
anyxml config {
|
||||
description
|
||||
"Inline Config content: <config> element. Represents
|
||||
an entire configuration datastore, not
|
||||
a subset of the running datastore.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
2251
modules/ietf_netconf@2013-09-29_yang.h
Normal file
2251
modules/ietf_netconf@2013-09-29_yang.h
Normal file
File diff suppressed because it is too large
Load diff
1454
modules/ietf_netconf_monitoring@2010-10-04_yang.h
Normal file
1454
modules/ietf_netconf_monitoring@2010-10-04_yang.h
Normal file
File diff suppressed because it is too large
Load diff
35
nc_client.h.in
Normal file
35
nc_client.h.in
Normal file
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* \file nc_client.h
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2's main public header for NETCONF clients.
|
||||
*
|
||||
* 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_CLIENT_H_
|
||||
#define NC_CLIENT_H_
|
||||
|
||||
@SSH_MACRO@
|
||||
@TLS_MACRO@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libnetconf2/netconf.h>
|
||||
#include <libnetconf2/log.h>
|
||||
#include <libnetconf2/messages_client.h>
|
||||
#include <libnetconf2/session_client.h>
|
||||
#include <libnetconf2/session_client_ch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NC_CLIENT_H_ */
|
35
nc_server.h.in
Normal file
35
nc_server.h.in
Normal file
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* \file nc_server.h
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2's main public header for NETCONF servers.
|
||||
*
|
||||
* 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_SERVER_H_
|
||||
#define NC_SERVER_H_
|
||||
|
||||
@SSH_MACRO@
|
||||
@TLS_MACRO@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libnetconf2/netconf.h>
|
||||
#include <libnetconf2/log.h>
|
||||
#include <libnetconf2/messages_server.h>
|
||||
#include <libnetconf2/session_server.h>
|
||||
#include <libnetconf2/session_server_ch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NC_SERVER_H_ */
|
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
78
tests/CMakeLists.txt
Normal file
78
tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,78 @@
|
|||
# headers test for including compat.h
|
||||
add_test(NAME headers
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/compat/check_includes.sh ${CMAKE_SOURCE_DIR}/src/)
|
||||
|
||||
# format
|
||||
if (${SOURCE_FORMAT_ENABLED})
|
||||
add_test(NAME format WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND make format-check)
|
||||
endif()
|
||||
|
||||
# list of all the tests in each directory
|
||||
set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages)
|
||||
set(client_tests test_client test_client_messages)
|
||||
|
||||
# add -Wl,--wrap flags
|
||||
set(test test_client_ssh)
|
||||
set(${test}_mock_funcs connect ssh_connect ssh_userauth_none ssh_userauth_kbdint ssh_is_connected
|
||||
ssh_channel_open_session ssh_channel_request_subsystem ssh_channel_is_close ssh_channel_write
|
||||
ssh_channel_poll_timeout ssh_userauth_password nc_handshake_io nc_ctx_check_and_fill
|
||||
ssh_userauth_try_publickey ssh_userauth_publickey nc_sock_listen_inet nc_sock_accept_binds nc_accept_callhome_ssh_sock)
|
||||
set(${test}_wrap_link_flags "-Wl")
|
||||
foreach(mock_func IN LISTS ${test}_mock_funcs)
|
||||
set(${test}_wrap_link_flags "${${test}_wrap_link_flags},--wrap=${mock_func}")
|
||||
endforeach()
|
||||
|
||||
set(test test_client_tls)
|
||||
set(${test}_mock_funcs connect SSL_connect nc_send_hello_io nc_handshake_io nc_ctx_check_and_fill)
|
||||
set(${test}_wrap_link_flags "-Wl")
|
||||
foreach(mock_func IN LISTS ${test}_mock_funcs)
|
||||
set(${test}_wrap_link_flags "${${test}_wrap_link_flags},--wrap=${mock_func}")
|
||||
endforeach()
|
||||
|
||||
#append tests depending on SSH/TLS
|
||||
if(ENABLE_SSH OR ENABLE_TLS)
|
||||
list(APPEND tests test_server_thread)
|
||||
if(ENABLE_SSH)
|
||||
list(APPEND client_tests test_client_ssh)
|
||||
endif()
|
||||
|
||||
if(ENABLE_TLS)
|
||||
list(APPEND client_tests test_client_tls)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
foreach(src IN LISTS libsrc)
|
||||
list(APPEND test_srcs "../${src}")
|
||||
endforeach()
|
||||
add_library(testobj OBJECT ${test_srcs})
|
||||
|
||||
foreach(test_name IN LISTS tests)
|
||||
add_executable(${test_name} $<TARGET_OBJECTS:testobj> ${test_name}.c)
|
||||
target_link_libraries(${test_name} ${CMOCKA_LIBRARIES} ${LIBYANG_LIBRARIES} netconf2)
|
||||
target_include_directories(${test_name} PRIVATE ${CMOCKA_INCLUDE_DIR})
|
||||
set_target_properties(${test_name} PROPERTIES LINK_FLAGS "${${test_name}_wrap_link_flags}")
|
||||
add_test(NAME ${test_name} COMMAND $<TARGET_FILE:${test_name}>)
|
||||
endforeach()
|
||||
|
||||
foreach(test_name IN LISTS client_tests)
|
||||
add_executable(${test_name} $<TARGET_OBJECTS:testobj> ./client/${test_name}.c)
|
||||
target_link_libraries(${test_name} ${CMOCKA_LIBRARIES} ${LIBYANG_LIBRARIES} netconf2)
|
||||
target_include_directories(${test_name} PRIVATE ${CMOCKA_INCLUDE_DIR})
|
||||
set_target_properties(${test_name} PROPERTIES LINK_FLAGS "${${test_name}_wrap_link_flags}")
|
||||
add_test(NAME ${test_name} COMMAND $<TARGET_FILE:${test_name}>)
|
||||
endforeach()
|
||||
|
||||
if(ENABLE_VALGRIND_TESTS)
|
||||
foreach(test_name IN LISTS tests)
|
||||
add_test(${test_name}_valgrind valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1
|
||||
--suppressions=${PROJECT_SOURCE_DIR}/tests/ld.supp ${CMAKE_BINARY_DIR}/tests/${test_name})
|
||||
endforeach()
|
||||
|
||||
foreach(test_name IN LISTS client_tests)
|
||||
add_test(${test_name}_valgrind valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1
|
||||
--suppressions=${PROJECT_SOURCE_DIR}/tests/ld.supp ${CMAKE_BINARY_DIR}/tests/${test_name})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src ${PROJECT_BINARY_DIR})
|
||||
configure_file("${PROJECT_SOURCE_DIR}/tests/config.h.in" "${PROJECT_BINARY_DIR}/tests/config.h" ESCAPE_QUOTES @ONLY)
|
125
tests/client/test_client.c
Normal file
125
tests/client/test_client.c
Normal file
|
@ -0,0 +1,125 @@
|
|||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
#include <libyang/libyang.h>
|
||||
#include <log.h>
|
||||
#include <session_client.h>
|
||||
#include "tests/config.h"
|
||||
|
||||
static int
|
||||
setup_f(void **state)
|
||||
{
|
||||
(void)state;
|
||||
|
||||
nc_verbosity(NC_VERB_VERBOSE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
teardown_f(void **state)
|
||||
{
|
||||
(void)state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_setting_schema_searchpath(void **state)
|
||||
{
|
||||
(void)state;
|
||||
const char *path;
|
||||
int ret;
|
||||
|
||||
/* initiate client */
|
||||
nc_client_init();
|
||||
|
||||
path = nc_client_get_schema_searchpath();
|
||||
assert_null(path);
|
||||
|
||||
ret = nc_client_set_schema_searchpath("path");
|
||||
assert_int_equal(ret, 0);
|
||||
path = nc_client_get_schema_searchpath();
|
||||
assert_string_equal(path, "path");
|
||||
|
||||
ret = nc_client_set_schema_searchpath("path1");
|
||||
assert_int_equal(ret, 0);
|
||||
path = nc_client_get_schema_searchpath();
|
||||
assert_string_equal(path, "path1");
|
||||
}
|
||||
|
||||
LY_ERR
|
||||
test_clb(const char *mod_name, const char *mod_rev, const char *submod_name, const char *sub_rev, void *user_data,
|
||||
LYS_INFORMAT *format, const char **model_data, void (**free_module_data)(void *model_data, void *user_data))
|
||||
{
|
||||
(void)mod_name;
|
||||
(void)mod_rev;
|
||||
(void)submod_name;
|
||||
(void)sub_rev;
|
||||
(void)user_data;
|
||||
(void)format;
|
||||
(void)model_data;
|
||||
(void)free_module_data;
|
||||
|
||||
return LY_SUCCESS;
|
||||
}
|
||||
|
||||
LY_ERR
|
||||
test_clb1(const char *mod_name, const char *mod_rev, const char *submod_name, const char *sub_rev, void *user_data,
|
||||
LYS_INFORMAT *format, const char **model_data, void (**free_module_data)(void *model_data, void *user_data))
|
||||
{
|
||||
(void)mod_name;
|
||||
(void)mod_rev;
|
||||
(void)submod_name;
|
||||
(void)sub_rev;
|
||||
(void)user_data;
|
||||
(void)format;
|
||||
(void)model_data;
|
||||
(void)free_module_data;
|
||||
|
||||
return LY_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_setting_schema_callback(void **state)
|
||||
{
|
||||
(void)state;
|
||||
ly_module_imp_clb ret_f;
|
||||
char *data_ret;
|
||||
int ret;
|
||||
|
||||
ret_f = nc_client_get_schema_callback((void **)&data_ret);
|
||||
assert_null(ret_f);
|
||||
assert_null(data_ret);
|
||||
|
||||
ret = nc_client_set_schema_callback(test_clb, "DATA");
|
||||
assert_int_equal(ret, 0);
|
||||
ret_f = nc_client_get_schema_callback((void **)&data_ret);
|
||||
assert_ptr_equal(test_clb, ret_f);
|
||||
assert_string_equal("DATA", data_ret);
|
||||
|
||||
ret = nc_client_set_schema_callback(test_clb1, "DATA1");
|
||||
assert_int_equal(ret, 0);
|
||||
ret_f = nc_client_get_schema_callback((void **)&data_ret);
|
||||
assert_ptr_equal(test_clb1, ret_f);
|
||||
assert_string_equal("DATA1", data_ret);
|
||||
|
||||
/* destroy client */
|
||||
nc_client_destroy();
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_setting_schema_searchpath, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_setting_schema_callback, setup_f, teardown_f),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
709
tests/client/test_client_messages.c
Normal file
709
tests/client/test_client_messages.c
Normal file
|
@ -0,0 +1,709 @@
|
|||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
#include <config.h>
|
||||
#include <libyang/libyang.h>
|
||||
#include <log.h>
|
||||
#include <messages_p.h>
|
||||
#include <session_client.h>
|
||||
#include "tests/config.h"
|
||||
|
||||
static int
|
||||
setup_f(void **state)
|
||||
{
|
||||
(void)state;
|
||||
|
||||
nc_verbosity(NC_VERB_VERBOSE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
teardown_f(void **state)
|
||||
{
|
||||
(void)state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_act_generic_xml(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
struct nc_rpc_act_generic *generic_rpc = NULL;
|
||||
|
||||
/* create generic rpc with NC_PARAMTYPE_CONST */
|
||||
rpc = nc_rpc_act_generic_xml("xml", NC_PARAMTYPE_CONST);
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_ACT_GENERIC);
|
||||
generic_rpc = (struct nc_rpc_act_generic *)rpc;
|
||||
assert_int_equal(generic_rpc->type, NC_RPC_ACT_GENERIC);
|
||||
assert_int_equal(generic_rpc->has_data, 0);
|
||||
assert_string_equal(generic_rpc->content.xml_str, "xml");
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create generic rpc with NC_PARAMTYPE_FREE */
|
||||
char *str = strdup("str");
|
||||
|
||||
rpc = nc_rpc_act_generic_xml(str, NC_PARAMTYPE_FREE);
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_ACT_GENERIC);
|
||||
generic_rpc = (struct nc_rpc_act_generic *)rpc;
|
||||
assert_int_equal(generic_rpc->type, NC_RPC_ACT_GENERIC);
|
||||
assert_int_equal(generic_rpc->has_data, 0);
|
||||
assert_string_equal(generic_rpc->content.xml_str, str);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create generic rpc with NC_PARAMTYPE_DUP_AND_FREE */
|
||||
rpc = nc_rpc_act_generic_xml("xml", NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_ACT_GENERIC);
|
||||
generic_rpc = (struct nc_rpc_act_generic *)rpc;
|
||||
assert_int_equal(generic_rpc->type, NC_RPC_ACT_GENERIC);
|
||||
assert_int_equal(generic_rpc->has_data, 0);
|
||||
assert_string_equal(generic_rpc->content.xml_str, "xml");
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_act_generic(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
struct nc_rpc_act_generic *generic_rpc = NULL;
|
||||
struct lyd_node node;
|
||||
|
||||
node.next = NULL;
|
||||
node.prev = &node;
|
||||
|
||||
rpc = nc_rpc_act_generic(&node, NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_ACT_GENERIC);
|
||||
generic_rpc = (struct nc_rpc_act_generic *)rpc;
|
||||
assert_int_equal(generic_rpc->type, NC_RPC_ACT_GENERIC);
|
||||
assert_int_equal(generic_rpc->has_data, 1);
|
||||
assert_ptr_equal(generic_rpc->content.data, &node);
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
/* function to check if values of getconfig rpc are set correctly */
|
||||
void
|
||||
check_getconfig(struct nc_rpc *rpc, enum NC_DATASTORE_TYPE source, char *filter, NC_WD_MODE wd_mode)
|
||||
{
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_GETCONFIG);
|
||||
struct nc_rpc_getconfig *getconfig_rpc = (struct nc_rpc_getconfig *)rpc;
|
||||
|
||||
assert_int_equal(getconfig_rpc->type, NC_RPC_GETCONFIG);
|
||||
assert_int_equal(getconfig_rpc->source, source);
|
||||
assert_string_equal(getconfig_rpc->filter, filter);
|
||||
assert_int_equal(getconfig_rpc->wd_mode, wd_mode);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_getconfig(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* create getconfig rpc with NC_PARAMTYPE_CONST */
|
||||
rpc = nc_rpc_getconfig(NC_DATASTORE_CANDIDATE, "filter-string", NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
check_getconfig(rpc, NC_DATASTORE_CANDIDATE, "filter-string", NC_WD_UNKNOWN);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create getconfig rpc with NC_PARAMTYPE_FREE */
|
||||
char *filter = strdup("string");
|
||||
|
||||
rpc = nc_rpc_getconfig(NC_DATASTORE_CONFIG, filter, NC_WD_EXPLICIT, NC_PARAMTYPE_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_getconfig(rpc, NC_DATASTORE_CONFIG, filter, NC_WD_EXPLICIT);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create getconfig rpc with NC_PARAMTYPE_DUP_AND_FREE */
|
||||
rpc = nc_rpc_getconfig(NC_DATASTORE_RUNNING, "filter", NC_WD_ALL, NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_getconfig(rpc, NC_DATASTORE_RUNNING, "filter", NC_WD_ALL);
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
/* function to check if values of edit rpc are set correctly */
|
||||
void
|
||||
check_edit(struct nc_rpc *rpc, 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)
|
||||
{
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_EDIT);
|
||||
struct nc_rpc_edit *edit_rpc = (struct nc_rpc_edit *)rpc;
|
||||
|
||||
assert_int_equal(edit_rpc->type, NC_RPC_EDIT);
|
||||
assert_int_equal(edit_rpc->target, target);
|
||||
assert_int_equal(edit_rpc->default_op, default_op);
|
||||
assert_int_equal(edit_rpc->test_opt, test_opt);
|
||||
assert_int_equal(edit_rpc->error_opt, error_opt);
|
||||
assert_string_equal(edit_rpc->edit_cont, edit_content);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_edit(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* create edit rpc with NC_PARAMTYPE_CONST */
|
||||
rpc = nc_rpc_edit(NC_DATASTORE_RUNNING, NC_RPC_EDIT_DFLTOP_REPLACE, NC_RPC_EDIT_TESTOPT_TESTSET,
|
||||
NC_RPC_EDIT_ERROPT_STOP, "url", NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
check_edit(rpc, NC_DATASTORE_RUNNING, NC_RPC_EDIT_DFLTOP_REPLACE,
|
||||
NC_RPC_EDIT_TESTOPT_TESTSET, NC_RPC_EDIT_ERROPT_STOP, "url");
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create edit rpc with NC_PARAMTYPE_FREE */
|
||||
char *str = strdup("string");
|
||||
|
||||
rpc = nc_rpc_edit(NC_DATASTORE_CANDIDATE, NC_RPC_EDIT_DFLTOP_MERGE, NC_RPC_EDIT_TESTOPT_SET,
|
||||
NC_RPC_EDIT_ERROPT_ROLLBACK, str, NC_PARAMTYPE_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_edit(rpc, NC_DATASTORE_CANDIDATE, NC_RPC_EDIT_DFLTOP_MERGE,
|
||||
NC_RPC_EDIT_TESTOPT_SET, NC_RPC_EDIT_ERROPT_ROLLBACK, str);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create edit rpc with NC_PARAMTYPE_DUP_AND_FREE */
|
||||
rpc = nc_rpc_edit(NC_DATASTORE_CONFIG, NC_RPC_EDIT_DFLTOP_NONE, NC_RPC_EDIT_TESTOPT_TEST,
|
||||
NC_RPC_EDIT_ERROPT_CONTINUE, "url1", NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_edit(rpc, NC_DATASTORE_CONFIG, NC_RPC_EDIT_DFLTOP_NONE,
|
||||
NC_RPC_EDIT_TESTOPT_TEST, NC_RPC_EDIT_ERROPT_CONTINUE, "url1");
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
/* function to check if values of copy rpc are set correctly */
|
||||
void
|
||||
check_copy(struct nc_rpc *rpc, NC_DATASTORE target, const char *url_trg, NC_DATASTORE source,
|
||||
const char *url_or_config_src, NC_WD_MODE wd_mode)
|
||||
{
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_COPY);
|
||||
struct nc_rpc_copy *copy_rpc = (struct nc_rpc_copy *)rpc;
|
||||
|
||||
assert_int_equal(copy_rpc->type, NC_RPC_COPY);
|
||||
assert_int_equal(copy_rpc->target, target);
|
||||
assert_string_equal(copy_rpc->url_trg, url_trg);
|
||||
assert_int_equal(copy_rpc->source, source);
|
||||
assert_string_equal(copy_rpc->url_config_src, url_or_config_src);
|
||||
assert_int_equal(copy_rpc->wd_mode, wd_mode);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_copy(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* create copy rpc with NC_PARAMTYPE_CONST */
|
||||
rpc = nc_rpc_copy(NC_DATASTORE_RUNNING, "target-url", NC_DATASTORE_RUNNING, "src-url",
|
||||
NC_WD_ALL, NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
check_copy(rpc, NC_DATASTORE_RUNNING, "target-url", NC_DATASTORE_RUNNING, "src-url", NC_WD_ALL);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create copy rpc with NC_PARAMTYPE_FREE */
|
||||
char *target = strdup("target");
|
||||
char *src = strdup("src");
|
||||
|
||||
rpc = nc_rpc_copy(NC_DATASTORE_STARTUP, target, NC_DATASTORE_RUNNING, src,
|
||||
NC_WD_ALL_TAG, NC_PARAMTYPE_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_copy(rpc, NC_DATASTORE_STARTUP, target, NC_DATASTORE_RUNNING, src, NC_WD_ALL_TAG);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create copy rpc with NC_PARAMTYPE_DUP_AND_FREE */
|
||||
rpc = nc_rpc_copy(NC_DATASTORE_STARTUP, "url", NC_DATASTORE_CANDIDATE, "url",
|
||||
NC_WD_TRIM, NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_copy(rpc, NC_DATASTORE_STARTUP, "url", NC_DATASTORE_CANDIDATE, "url", NC_WD_TRIM);
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
/* function to check if values of delete rpc are set correctly */
|
||||
void
|
||||
check_delete(struct nc_rpc *rpc, NC_DATASTORE target, const char *url)
|
||||
{
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_DELETE);
|
||||
struct nc_rpc_delete *delete_rpc = (struct nc_rpc_delete *)rpc;
|
||||
|
||||
assert_int_equal(delete_rpc->type, NC_RPC_DELETE);
|
||||
assert_int_equal(delete_rpc->target, target);
|
||||
assert_string_equal(delete_rpc->url, url);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_delete(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* create delete rpc with NC_PARAMTYPE_CONST */
|
||||
rpc = nc_rpc_delete(NC_DATASTORE_RUNNING, "target-url", NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
check_delete(rpc, NC_DATASTORE_RUNNING, "target-url");
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create delete rpc with NC_PARAMTYPE_FREE */
|
||||
char *url = strdup("url");
|
||||
|
||||
rpc = nc_rpc_delete(NC_DATASTORE_CANDIDATE, url, NC_PARAMTYPE_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_delete(rpc, NC_DATASTORE_CANDIDATE, url);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create delete rpc with NC_PARAMTYPE_DUP_AND_FREE */
|
||||
rpc = nc_rpc_delete(NC_DATASTORE_CONFIG, "target", NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_delete(rpc, NC_DATASTORE_CONFIG, "target");
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_lock(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
struct nc_rpc_lock *lock_rpc = NULL;
|
||||
|
||||
rpc = nc_rpc_lock(NC_DATASTORE_RUNNING);
|
||||
assert_non_null(rpc);
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_LOCK);
|
||||
|
||||
lock_rpc = (struct nc_rpc_lock *)rpc;
|
||||
assert_int_equal(lock_rpc->type, NC_RPC_LOCK);
|
||||
assert_int_equal(lock_rpc->target, NC_DATASTORE_RUNNING);
|
||||
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_unlock(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
struct nc_rpc_lock *unlock_rpc = NULL;
|
||||
|
||||
rpc = nc_rpc_unlock(NC_DATASTORE_RUNNING);
|
||||
assert_non_null(rpc);
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_UNLOCK);
|
||||
|
||||
unlock_rpc = (struct nc_rpc_lock *)rpc;
|
||||
assert_int_equal(unlock_rpc->type, NC_RPC_UNLOCK);
|
||||
assert_int_equal(unlock_rpc->target, NC_DATASTORE_RUNNING);
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
/* function to check if values of get rpc are set correctly */
|
||||
void
|
||||
check_get_rpc(struct nc_rpc *rpc, const char *filter, NC_WD_MODE wd_mode)
|
||||
{
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_GET);
|
||||
struct nc_rpc_get *get_rpc = (struct nc_rpc_get *)rpc;
|
||||
|
||||
assert_int_equal(get_rpc->type, NC_RPC_GET);
|
||||
assert_string_equal(get_rpc->filter, filter);
|
||||
assert_int_equal(get_rpc->wd_mode, wd_mode);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_get(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* create get rpc with NC_PARAMTYPE_CONST */
|
||||
rpc = nc_rpc_get("filter", NC_WD_ALL, NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
check_get_rpc(rpc, "filter", NC_WD_ALL);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create get rpc with NC_PARAMTYPE_FREE */
|
||||
char *str = strdup("string");
|
||||
|
||||
rpc = nc_rpc_get(str, NC_WD_EXPLICIT, NC_PARAMTYPE_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_get_rpc(rpc, str, NC_WD_EXPLICIT);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create get rpc with NC_PARAMTYPE_DUP_AND_FREE */
|
||||
rpc = nc_rpc_get("filter-string", NC_WD_UNKNOWN, NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_get_rpc(rpc, "filter-string", NC_WD_UNKNOWN);
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_kill(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
struct nc_rpc_kill *kill_rpc = NULL;
|
||||
|
||||
rpc = nc_rpc_kill(10);
|
||||
assert_non_null(rpc);
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_KILL);
|
||||
|
||||
kill_rpc = (struct nc_rpc_kill *)rpc;
|
||||
assert_int_equal(kill_rpc->type, NC_RPC_KILL);
|
||||
assert_int_equal(kill_rpc->sid, 10);
|
||||
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
/* function to check if values of commit rpc are set correctly */
|
||||
void
|
||||
check_commit_rpc(struct nc_rpc *rpc, int confirmed, uint32_t confirm_timeout, const char *persist, const char *persist_id)
|
||||
{
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_COMMIT);
|
||||
struct nc_rpc_commit *commit_rpc = (struct nc_rpc_commit *)rpc;
|
||||
|
||||
assert_int_equal(commit_rpc->type, NC_RPC_COMMIT);
|
||||
assert_int_equal(commit_rpc->confirmed, confirmed);
|
||||
assert_int_equal(commit_rpc->confirm_timeout, confirm_timeout);
|
||||
assert_string_equal(commit_rpc->persist, persist);
|
||||
assert_string_equal(commit_rpc->persist_id, persist_id);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_commit(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* create commit rpc with NC_PARAMTYPE_CONST*/
|
||||
rpc = nc_rpc_commit(1, 100, "persist", "persist-id", NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
check_commit_rpc(rpc, 1, 100, "persist", "persist-id");
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create commit rpc with NC_PARAMTYPE_FREE*/
|
||||
char *str1 = strdup("str1");
|
||||
char *str2 = strdup("str2");
|
||||
|
||||
rpc = nc_rpc_commit(2, 5, str1, str2, NC_PARAMTYPE_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_commit_rpc(rpc, 2, 5, str1, str2);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create commit rpc with NC_PARAMTYPE_DUP_AND_FREE*/
|
||||
rpc = nc_rpc_commit(10, 200, "persistent", "persistent-id", NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_commit_rpc(rpc, 10, 200, "persistent", "persistent-id");
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_discard(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
rpc = nc_rpc_discard();
|
||||
assert_non_null(rpc);
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_DISCARD);
|
||||
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
/* function to check if values of cancel rpc are set correctly */
|
||||
void
|
||||
check_cancel_rpc(struct nc_rpc *rpc, const char *persist_id)
|
||||
{
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_CANCEL);
|
||||
struct nc_rpc_cancel *cancel_rpc = (struct nc_rpc_cancel *)rpc;
|
||||
|
||||
assert_int_equal(cancel_rpc->type, NC_RPC_CANCEL);
|
||||
assert_string_equal(cancel_rpc->persist_id, persist_id);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_cancel(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* create cancel rpc with NC_PARAMTYPE_CONST*/
|
||||
rpc = nc_rpc_cancel("persist-id", NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
check_cancel_rpc(rpc, "persist-id");
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create cancel rpc with NC_PARAMTYPE_FREE*/
|
||||
char *str = strdup("string");
|
||||
|
||||
rpc = nc_rpc_cancel(str, NC_PARAMTYPE_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_cancel_rpc(rpc, str);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create cancel rpc with NC_PARAMTYPE_DUP_AND_FREE*/
|
||||
rpc = nc_rpc_cancel("id", NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_cancel_rpc(rpc, "id");
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
/* function to check if values of validate rpc are set correctly */
|
||||
void
|
||||
check_validate_rpc(struct nc_rpc *rpc, NC_DATASTORE source, const char *url_or_config)
|
||||
{
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_VALIDATE);
|
||||
struct nc_rpc_validate *validate_rpc = (struct nc_rpc_validate *)rpc;
|
||||
|
||||
assert_int_equal(validate_rpc->type, NC_RPC_VALIDATE);
|
||||
assert_int_equal(validate_rpc->source, source);
|
||||
assert_string_equal(validate_rpc->url_config_src, url_or_config);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_validate(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* create validate rpc with NC_PARAMTYPE_CONST */
|
||||
rpc = nc_rpc_validate(NC_DATASTORE_RUNNING, "url", NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
check_validate_rpc(rpc, NC_DATASTORE_RUNNING, "url");
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create validate rpc with NC_PARAMTYPE_FREE */
|
||||
char *str = strdup("string");
|
||||
|
||||
rpc = nc_rpc_validate(NC_DATASTORE_CANDIDATE, str, NC_PARAMTYPE_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_validate_rpc(rpc, NC_DATASTORE_CANDIDATE, str);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create validate rpc with NC_PARAMTYPE_DUP_AND_FREE */
|
||||
rpc = nc_rpc_validate(NC_DATASTORE_CONFIG, "url1", NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_validate_rpc(rpc, NC_DATASTORE_CONFIG, "url1");
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
/* function to check if values of getschema rpc are set correctly */
|
||||
void
|
||||
check_getschema_rpc(struct nc_rpc *rpc, const char *identifier, const char *version, const char *format)
|
||||
{
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_GETSCHEMA);
|
||||
struct nc_rpc_getschema *getchema_rpc = (struct nc_rpc_getschema *)rpc;
|
||||
|
||||
assert_int_equal(getchema_rpc->type, NC_RPC_GETSCHEMA);
|
||||
assert_string_equal(getchema_rpc->identifier, identifier);
|
||||
assert_string_equal(getchema_rpc->version, version);
|
||||
assert_string_equal(getchema_rpc->format, format);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_getschema(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* create getchema with NC_PARAMTYPE_CONST*/
|
||||
rpc = nc_rpc_getschema("id", "version", "format", NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
check_getschema_rpc(rpc, "id", "version", "format");
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create getchema with NC_PARAMTYPE_FREE*/
|
||||
char *str1 = strdup("str1");
|
||||
char *str2 = strdup("str2");
|
||||
char *str3 = strdup("str3");
|
||||
|
||||
rpc = nc_rpc_getschema(str1, str2, str3, NC_PARAMTYPE_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_getschema_rpc(rpc, str1, str2, str3);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create getchema with NC_PARAMTYPE_DUP_AND_FREE*/
|
||||
rpc = nc_rpc_getschema("id1", "version1", "format1", NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_getschema_rpc(rpc, "id1", "version1", "format1");
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
/* function to check if values of subscribe rpc are set correctly */
|
||||
void
|
||||
check_subscribe_rpc(struct nc_rpc *rpc, const char *stream_name, const char *filter,
|
||||
const char *start_time, const char *stop_time)
|
||||
{
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_SUBSCRIBE);
|
||||
struct nc_rpc_subscribe *subscribe_rpc = (struct nc_rpc_subscribe *)rpc;
|
||||
|
||||
assert_int_equal(subscribe_rpc->type, NC_RPC_SUBSCRIBE);
|
||||
assert_string_equal(subscribe_rpc->stream, stream_name);
|
||||
assert_string_equal(subscribe_rpc->filter, filter);
|
||||
assert_string_equal(subscribe_rpc->start, start_time);
|
||||
assert_string_equal(subscribe_rpc->stop, stop_time);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_subscribe(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* create subscribe rpc with NC_PARAMTYPE_CONST*/
|
||||
rpc = nc_rpc_subscribe("stream-name", "filter", "start-time", "stop-time", NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
check_subscribe_rpc(rpc, "stream-name", "filter", "start-time", "stop-time");
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create subscribe rpc with NC_PARAMTYPE_FREE*/
|
||||
char *str1 = strdup("str1");
|
||||
char *str2 = strdup("str2");
|
||||
char *str3 = strdup("str3");
|
||||
char *str4 = strdup("str4");
|
||||
|
||||
rpc = nc_rpc_subscribe(str1, str2, str3, str4, NC_PARAMTYPE_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_subscribe_rpc(rpc, str1, str2, str3, str4);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create subscribe rpc with NC_PARAMTYPE_DUP_AND_FREE*/
|
||||
rpc = nc_rpc_subscribe("name", "filter-str", "start", "stop", NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_subscribe_rpc(rpc, "name", "filter-str", "start", "stop");
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
/* function to check if values of getdata rpc are set correctly */
|
||||
void
|
||||
check_getdata(struct nc_rpc *rpc, char *datastore, const char *filter, const char *config_filter,
|
||||
char **origin_filter, int origin_filter_count, int negated_origin_filter, uint16_t max_depth,
|
||||
int with_origin, NC_WD_MODE wd_mode)
|
||||
{
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_GETDATA);
|
||||
struct nc_rpc_getdata *rpc_getdata = (struct nc_rpc_getdata *)rpc;
|
||||
|
||||
assert_int_equal(rpc_getdata->type, NC_RPC_GETDATA);
|
||||
assert_string_equal(rpc_getdata->datastore, datastore);
|
||||
assert_string_equal(rpc_getdata->filter, filter);
|
||||
assert_string_equal(rpc_getdata->config_filter, config_filter);
|
||||
assert_string_equal(*rpc_getdata->origin_filter, *origin_filter);
|
||||
assert_int_equal(rpc_getdata->origin_filter_count, origin_filter_count);
|
||||
assert_int_equal(rpc_getdata->negated_origin_filter, negated_origin_filter);
|
||||
assert_int_equal(rpc_getdata->max_depth, max_depth);
|
||||
assert_int_equal(rpc_getdata->with_origin, with_origin);
|
||||
assert_int_equal(rpc_getdata->wd_mode, wd_mode);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_getdata(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* create getdata rpc with NC_PARAMTYPE_CONST */
|
||||
char *origin_filters = "origin_filter";
|
||||
|
||||
rpc = nc_rpc_getdata("candidate", "filter", "true", &origin_filters, 1, 1, 3, 1, NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
check_getdata(rpc, "candidate", "filter", "true", &origin_filters, 1, 1, 3, 1, NC_WD_UNKNOWN);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create getdata rpc with NC_PARAMTYPE_FREE */
|
||||
char *datastore = strdup("running");
|
||||
char *filter = strdup("filter");
|
||||
char *config_filter = strdup("true");
|
||||
char buf[20] = {0};
|
||||
char **origin_filter;
|
||||
int origin_filter_count = 2;
|
||||
|
||||
origin_filter = calloc(origin_filter_count, sizeof *origin_filter);
|
||||
assert_non_null(origin_filter);
|
||||
for (int i = 0; i < origin_filter_count; i++) {
|
||||
snprintf(buf, sizeof(buf) - 1, "origin_filter%d", i + 1);
|
||||
origin_filter[i] = strdup(buf);
|
||||
}
|
||||
|
||||
rpc = nc_rpc_getdata(datastore, filter, config_filter, origin_filter, origin_filter_count, 2, 3, 1, NC_WD_EXPLICIT, NC_PARAMTYPE_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_getdata(rpc, datastore, filter, config_filter, origin_filter, origin_filter_count, 2, 3, 1, NC_WD_EXPLICIT);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create getdata rpc with NC_PARAMTYPE_DUP_AND_FREE */
|
||||
char *origin_filter1 = "origin_filter1";
|
||||
|
||||
rpc = nc_rpc_getdata("startup", "filter1", "false", &origin_filter1, 1, 0, 3, 1, NC_WD_ALL, NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_getdata(rpc, "startup", "filter1", "false", &origin_filter1, 1, 0, 3, 1, NC_WD_ALL);
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
/* function to check if values of editdata rpc are set correctly */
|
||||
void
|
||||
check_editdata(struct nc_rpc *rpc, char *datastore, NC_RPC_EDIT_DFLTOP default_op, const char *edit_content)
|
||||
{
|
||||
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_EDITDATA);
|
||||
struct nc_rpc_editdata *rpc_editdata = (struct nc_rpc_editdata *)rpc;
|
||||
|
||||
assert_int_equal(rpc_editdata->type, NC_RPC_EDITDATA);
|
||||
assert_string_equal(rpc_editdata->datastore, datastore);
|
||||
assert_int_equal(rpc_editdata->default_op, default_op);
|
||||
assert_string_equal(rpc_editdata->edit_cont, edit_content);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_rpc_editdata(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* create editdata rpc with NC_PARAMTYPE_CONST */
|
||||
rpc = nc_rpc_editdata("candidate", NC_RPC_EDIT_DFLTOP_UNKNOWN, "edit", NC_PARAMTYPE_CONST);
|
||||
assert_non_null(rpc);
|
||||
check_editdata(rpc, "candidate", NC_RPC_EDIT_DFLTOP_UNKNOWN, "edit");
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create editdata rpc with NC_PARAMTYPE_FREE */
|
||||
char *datastore = strdup("running");
|
||||
char *edit_cont = strdup("edit_data");
|
||||
|
||||
rpc = nc_rpc_editdata(datastore, NC_RPC_EDIT_DFLTOP_MERGE, edit_cont, NC_PARAMTYPE_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_editdata(rpc, datastore, NC_RPC_EDIT_DFLTOP_MERGE, edit_cont);
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
/* create editdata rpc with NC_PARAMTYPE_DUP_AND_FREE */
|
||||
rpc = nc_rpc_editdata("startup", NC_RPC_EDIT_DFLTOP_REPLACE, "edit_cont", NC_PARAMTYPE_DUP_AND_FREE);
|
||||
assert_non_null(rpc);
|
||||
check_editdata(rpc, "startup", NC_RPC_EDIT_DFLTOP_REPLACE, "edit_cont");
|
||||
nc_rpc_free(rpc);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_act_generic_xml, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_act_generic, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_getconfig, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_edit, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_copy, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_delete, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_lock, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_unlock, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_get, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_kill, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_commit, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_discard, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_cancel, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_validate, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_getschema, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_subscribe, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_getdata, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_rpc_editdata, setup_f, teardown_f),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
813
tests/client/test_client_ssh.c
Normal file
813
tests/client/test_client_ssh.c
Normal file
|
@ -0,0 +1,813 @@
|
|||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
#include <config.h>
|
||||
#include <libyang/libyang.h>
|
||||
#include <log.h>
|
||||
#include <session_client.h>
|
||||
#include <session_client_ch.h>
|
||||
#include <session_p.h>
|
||||
#include "tests/config.h"
|
||||
|
||||
#include <libssh/callbacks.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/server.h>
|
||||
|
||||
static int
|
||||
ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv)
|
||||
{
|
||||
(void)hostname;
|
||||
(void)session;
|
||||
(void)priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
setup_f(void **state)
|
||||
{
|
||||
(void)state;
|
||||
int ret;
|
||||
|
||||
nc_verbosity(NC_VERB_VERBOSE);
|
||||
|
||||
ret = nc_client_ssh_set_username("username");
|
||||
assert_int_equal(ret, 0);
|
||||
ret = nc_client_ssh_ch_set_username("ch_username");
|
||||
assert_int_equal(ret, 0);
|
||||
nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
teardown_f(void **state)
|
||||
{
|
||||
(void)state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
(void)sockfd;
|
||||
(void)addr;
|
||||
(void)addrlen;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_ssh_connect(ssh_session session)
|
||||
{
|
||||
(void)session;
|
||||
|
||||
/* set support of all authentication methods by fake server */
|
||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_INTERACTIVE);
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_ssh_userauth_none(ssh_session session, const char *username)
|
||||
{
|
||||
(void)session;
|
||||
(void)username;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_ssh_userauth_kbdint(ssh_session session, const char *user, const char *submethods)
|
||||
{
|
||||
(void)session;
|
||||
(void)user;
|
||||
(void)submethods;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_ssh_is_connected(ssh_session session)
|
||||
{
|
||||
(void)session;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_ssh_channel_open_session(ssh_channel channel)
|
||||
{
|
||||
(void)channel;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_ssh_channel_request_subsystem(ssh_channel channel, const char *subsystem)
|
||||
{
|
||||
(void)channel;
|
||||
(void)subsystem;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_ssh_channel_is_closed(ssh_channel channel)
|
||||
{
|
||||
(void)channel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_ssh_channel_write(ssh_channel channel, const void *data, uint32_t len)
|
||||
{
|
||||
(void)channel;
|
||||
(void)data;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr)
|
||||
{
|
||||
(void)channel;
|
||||
(void)timeout;
|
||||
(void)is_stderr;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_ssh_userauth_password(ssh_session session, const char *username, const char *password)
|
||||
{
|
||||
(void)session;
|
||||
check_expected(password);
|
||||
check_expected(username);
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_nc_handshake_io(struct nc_session *session)
|
||||
{
|
||||
(void)session;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_nc_ctx_check_and_fill(struct nc_session *session)
|
||||
{
|
||||
(void)session;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_ssh_userauth_try_publickey(ssh_session session, const char *username, const ssh_key pubkey)
|
||||
{
|
||||
(void)session;
|
||||
(void)username;
|
||||
(void)pubkey;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_ssh_userauth_publickey(ssh_session session, const char *username, const ssh_key privkey)
|
||||
{
|
||||
(void)session;
|
||||
(void)username;
|
||||
(void)privkey;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_nc_sock_listen_inet(const char *address, uint16_t port, struct nc_keepalives *ka)
|
||||
{
|
||||
(void)address;
|
||||
(void)port;
|
||||
(void)ka;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, char **host, uint16_t *port, uint16_t *idx)
|
||||
{
|
||||
(void)binds;
|
||||
(void)bind_count;
|
||||
(void)timeout;
|
||||
(void)host;
|
||||
(void)port;
|
||||
|
||||
*idx = 0;
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK struct nc_session *
|
||||
__wrap_nc_accept_callhome_ssh_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx, int timeout)
|
||||
{
|
||||
(void)sock;
|
||||
(void)host;
|
||||
(void)port;
|
||||
(void)ctx;
|
||||
(void)timeout;
|
||||
|
||||
return mock_ptr_type(struct nc_session *);
|
||||
}
|
||||
|
||||
static int
|
||||
test_hostkey_clb(const char *hostname, ssh_session session, void *priv)
|
||||
{
|
||||
(void)hostname;
|
||||
(void)session;
|
||||
(void)priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_ssh_setting_auth_hostkey_check_clb(void **state)
|
||||
{
|
||||
(void)state;
|
||||
int (*ret_f)(const char *hostname, ssh_session session, void *priv);
|
||||
char *priv_data_ret;
|
||||
|
||||
/* ssh_hostkey_check_clb is set in setup_f */
|
||||
nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret);
|
||||
assert_ptr_equal(ret_f, ssh_hostkey_check_clb);
|
||||
assert_null(priv_data_ret);
|
||||
|
||||
/* set different callback and private data */
|
||||
nc_client_ssh_set_auth_hostkey_check_clb(test_hostkey_clb, "DATA");
|
||||
nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret);
|
||||
assert_ptr_equal(ret_f, test_hostkey_clb);
|
||||
assert_string_equal(priv_data_ret, "DATA");
|
||||
}
|
||||
|
||||
char *
|
||||
test_pwd_clb1(const char *username, const char *hostname, void *priv)
|
||||
{
|
||||
char *pass, *pass_to_return;
|
||||
|
||||
check_expected(username);
|
||||
check_expected(hostname);
|
||||
check_expected(priv);
|
||||
|
||||
pass = (char *)mock();
|
||||
pass_to_return = malloc(sizeof *pass * (strlen(pass) + 1));
|
||||
strcpy(pass_to_return, pass);
|
||||
|
||||
return pass_to_return;
|
||||
}
|
||||
|
||||
char *
|
||||
test_pwd_clb2(const char *username, const char *hostname, void *priv)
|
||||
{
|
||||
(void)username;
|
||||
(void)hostname;
|
||||
(void)priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_ssh_setting_auth_password_clb(void **state)
|
||||
{
|
||||
(void)state;
|
||||
char *(*ret_f)(const char *username, const char *hostname, void *priv);
|
||||
char *priv_data_ret;
|
||||
|
||||
/* set callback */
|
||||
nc_client_ssh_set_auth_password_clb(test_pwd_clb1, "DATA");
|
||||
nc_client_ssh_get_auth_password_clb(&ret_f, (void **)&priv_data_ret);
|
||||
assert_ptr_equal(test_pwd_clb1, ret_f);
|
||||
assert_string_equal("DATA", priv_data_ret);
|
||||
|
||||
/* set different callback */
|
||||
nc_client_ssh_set_auth_password_clb(test_pwd_clb2, "NEW DATA");
|
||||
nc_client_ssh_get_auth_password_clb(&ret_f, (void **)&priv_data_ret);
|
||||
assert_ptr_equal(test_pwd_clb2, ret_f);
|
||||
assert_string_equal("NEW DATA", priv_data_ret);
|
||||
}
|
||||
|
||||
char *
|
||||
test_inter_clb1(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv)
|
||||
{
|
||||
(void)auth_name;
|
||||
(void)instruction;
|
||||
(void)prompt;
|
||||
(void)echo;
|
||||
(void)priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
test_inter_clb2(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv)
|
||||
{
|
||||
(void)auth_name;
|
||||
(void)instruction;
|
||||
(void)prompt;
|
||||
(void)echo;
|
||||
(void)priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_ssh_setting_auth_interactive_clb(void **state)
|
||||
{
|
||||
(void)state;
|
||||
char *(*ret_f)(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv);
|
||||
char *priv_data_ret;
|
||||
|
||||
/* set callback */
|
||||
nc_client_ssh_set_auth_interactive_clb(test_inter_clb1, "DATA");
|
||||
nc_client_ssh_get_auth_interactive_clb(&ret_f, (void **)&priv_data_ret);
|
||||
assert_ptr_equal(test_inter_clb1, ret_f);
|
||||
assert_string_equal("DATA", priv_data_ret);
|
||||
|
||||
/* set diferent callback */
|
||||
nc_client_ssh_set_auth_interactive_clb(test_inter_clb2, "NEW DATA");
|
||||
nc_client_ssh_get_auth_interactive_clb(&ret_f, (void **)&priv_data_ret);
|
||||
assert_ptr_equal(test_inter_clb2, ret_f);
|
||||
assert_string_equal("NEW DATA", priv_data_ret);
|
||||
}
|
||||
|
||||
char *
|
||||
test_passphrase_clb1(const char *privkey_path, void *priv)
|
||||
{
|
||||
(void)privkey_path;
|
||||
(void)priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
test_passphrase_clb2(const char *privkey_path, void *priv)
|
||||
{
|
||||
(void)privkey_path;
|
||||
(void)priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_ssh_setting_auth_privkey_passphrase_clb(void **state)
|
||||
{
|
||||
(void)state;
|
||||
char *(*ret_f)(const char *privkey_path, void *priv);
|
||||
char *priv_data_ret;
|
||||
|
||||
/* set first callback */
|
||||
nc_client_ssh_set_auth_privkey_passphrase_clb(test_passphrase_clb1, "DATA");
|
||||
nc_client_ssh_get_auth_privkey_passphrase_clb(&ret_f, (void **)&priv_data_ret);
|
||||
assert_ptr_equal(ret_f, test_passphrase_clb1);
|
||||
assert_string_equal("DATA", priv_data_ret);
|
||||
|
||||
/* set different callback */
|
||||
nc_client_ssh_set_auth_privkey_passphrase_clb(test_passphrase_clb2, "NEW DATA");
|
||||
nc_client_ssh_get_auth_privkey_passphrase_clb(&ret_f, (void **)&priv_data_ret);
|
||||
assert_ptr_equal(ret_f, test_passphrase_clb2);
|
||||
assert_string_equal("NEW DATA", priv_data_ret);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_ssh_adding_keypair(void **state)
|
||||
{
|
||||
(void)state;
|
||||
int ret;
|
||||
const char *pubkey1, *pubkey2;
|
||||
|
||||
/* at the beginning keypair count should be 0 */
|
||||
ret = nc_client_ssh_get_keypair_count();
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
/* add first key pair */
|
||||
ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_dsa.pub", TESTS_DIR "/data/key_dsa");
|
||||
assert_int_equal(ret, 0);
|
||||
ret = nc_client_ssh_get_keypair_count();
|
||||
assert_int_equal(ret, 1);
|
||||
|
||||
/* add second keypair */
|
||||
ret = nc_client_ssh_add_keypair("key_pub", "key_priv");
|
||||
assert_int_equal(ret, 0);
|
||||
ret = nc_client_ssh_get_keypair_count();
|
||||
assert_int_equal(ret, 2);
|
||||
ret = nc_client_ssh_get_keypair(1, &pubkey1, &pubkey2);
|
||||
assert_int_equal(ret, 0);
|
||||
assert_string_equal(pubkey1, "key_pub");
|
||||
assert_string_equal(pubkey2, "key_priv");
|
||||
|
||||
/* delete first keypair */
|
||||
ret = nc_client_ssh_del_keypair(0);
|
||||
assert_int_equal(ret, 0);
|
||||
ret = nc_client_ssh_get_keypair_count();
|
||||
assert_int_equal(ret, 1);
|
||||
/* try to get deleted keypair */
|
||||
ret = nc_client_ssh_get_keypair(5, &pubkey1, &pubkey2);
|
||||
assert_int_equal(ret, -1);
|
||||
|
||||
/* try to add keypair that is already set */
|
||||
ret = nc_client_ssh_add_keypair("key_pub", "key_priv");
|
||||
assert_int_equal(ret, -1);
|
||||
ret = nc_client_ssh_get_keypair_count();
|
||||
assert_int_equal(ret, 1);
|
||||
|
||||
/* try to delete keypair with id that is not used */
|
||||
ret = nc_client_ssh_del_keypair(42);
|
||||
assert_int_equal(ret, -1);
|
||||
ret = nc_client_ssh_get_keypair_count();
|
||||
assert_int_equal(ret, 1);
|
||||
|
||||
/* remove remaining keypairs */
|
||||
ret = nc_client_ssh_del_keypair(0);
|
||||
assert_int_equal(ret, 0);
|
||||
ret = nc_client_ssh_get_keypair_count();
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_ssh_setting_auth_pref(void **state)
|
||||
{
|
||||
(void)state;
|
||||
int ret;
|
||||
|
||||
/* initiate client, must be called in first test */
|
||||
nc_client_init();
|
||||
|
||||
/* check default prefference settings according to documentation */
|
||||
ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_INTERACTIVE);
|
||||
assert_int_equal(ret, 3);
|
||||
ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PASSWORD);
|
||||
assert_int_equal(ret, 2);
|
||||
ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PUBLICKEY);
|
||||
assert_int_equal(ret, 1);
|
||||
|
||||
/* try to set prefetence of non existing method */
|
||||
nc_client_ssh_set_auth_pref(42, 22);
|
||||
|
||||
/* try to get preference of non existing method */
|
||||
ret = nc_client_ssh_get_auth_pref(42);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
/* change values of all methods and check if they actually changed */
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 9);
|
||||
ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_INTERACTIVE);
|
||||
assert_int_equal(ret, 9);
|
||||
|
||||
/* negative value should be set as -1 */
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -5);
|
||||
ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PASSWORD);
|
||||
assert_int_equal(ret, -1);
|
||||
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 11);
|
||||
ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PUBLICKEY);
|
||||
assert_int_equal(ret, 11);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_ssh_setting_username(void **state)
|
||||
{
|
||||
(void)state;
|
||||
int ret;
|
||||
const char *username_ret;
|
||||
|
||||
username_ret = nc_client_ssh_get_username();
|
||||
/* username is set to "username" in setup_f */
|
||||
assert_string_equal(username_ret, "username");
|
||||
|
||||
/* set new username and check if it changes */
|
||||
ret = nc_client_ssh_set_username("new_username");
|
||||
assert_int_equal(ret, 0);
|
||||
username_ret = nc_client_ssh_get_username();
|
||||
assert_string_equal(username_ret, "new_username");
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_connect_ssh_interactive_succesfull(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_session *session;
|
||||
|
||||
/* set authentication method to use interactive authentication */
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 1);
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1);
|
||||
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 20);
|
||||
|
||||
/* prepare return values for functions used by nc_connect_ssh */
|
||||
will_return(__wrap_connect, 0);
|
||||
will_return(__wrap_ssh_connect, 0);
|
||||
will_return(__wrap_ssh_userauth_none, 1);
|
||||
|
||||
will_return(__wrap_ssh_userauth_kbdint, 0);
|
||||
will_return(__wrap_ssh_is_connected, 1);
|
||||
will_return(__wrap_ssh_is_connected, 1);
|
||||
|
||||
will_return(__wrap_ssh_channel_open_session, 0);
|
||||
will_return(__wrap_ssh_channel_request_subsystem, 0);
|
||||
|
||||
will_return(__wrap_nc_handshake_io, 3);
|
||||
will_return(__wrap_nc_ctx_check_and_fill, 0);
|
||||
|
||||
session = nc_connect_ssh("127.0.0.1", 8080, NULL);
|
||||
assert_non_null(session);
|
||||
|
||||
will_return(__wrap_ssh_channel_poll_timeout, 0);
|
||||
nc_session_free(session, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_connect_ssh_password_succesfull(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_session *session;
|
||||
|
||||
/* set authentication method to use password authentication */
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, 1);
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1);
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
|
||||
|
||||
/* set authentication callback */
|
||||
nc_client_ssh_set_auth_password_clb(test_pwd_clb1, "private_data");
|
||||
will_return(test_pwd_clb1, "secret password");
|
||||
/* set values that are expected as parameters for authentication callback */
|
||||
expect_string(test_pwd_clb1, username, "username");
|
||||
expect_string(test_pwd_clb1, hostname, "127.0.0.1");
|
||||
expect_string(test_pwd_clb1, priv, "private_data");
|
||||
|
||||
/* fake succesfull connection */
|
||||
will_return(__wrap_connect, 0);
|
||||
will_return(__wrap_ssh_connect, 0);
|
||||
/* do not authenticate using no authentication method */
|
||||
will_return(__wrap_ssh_userauth_none, 1);
|
||||
|
||||
/* succesfully authenticate via password authentication */
|
||||
expect_string(__wrap_ssh_userauth_password, password, "secret password");
|
||||
expect_string(__wrap_ssh_userauth_password, username, "username");
|
||||
will_return(__wrap_ssh_userauth_password, 0);
|
||||
|
||||
/* fake ssh functions that are used to open netconf channel */
|
||||
will_return(__wrap_ssh_channel_open_session, 0);
|
||||
will_return(__wrap_ssh_channel_request_subsystem, 0);
|
||||
|
||||
/* fake that connection is still alive*/
|
||||
will_return(__wrap_ssh_is_connected, 1);
|
||||
|
||||
/* fake ssh function for recieving hello message */
|
||||
will_return(__wrap_ssh_is_connected, 1);
|
||||
|
||||
will_return(__wrap_nc_handshake_io, 3);
|
||||
will_return(__wrap_nc_ctx_check_and_fill, 0);
|
||||
|
||||
session = nc_connect_ssh("127.0.0.1", 8080, NULL);
|
||||
assert_non_null(session);
|
||||
|
||||
/* disconnect */
|
||||
will_return(__wrap_ssh_channel_poll_timeout, 0);
|
||||
nc_session_free(session, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_connect_ssh_pubkey_succesfull(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_session *session;
|
||||
int ret = 0;
|
||||
|
||||
/* set authentication method to use password authentication */
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1);
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
|
||||
|
||||
/* add keypair for authentication */
|
||||
ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_dsa.pub", TESTS_DIR "/data/key_dsa");
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
/* fake succesfull connection */
|
||||
will_return(__wrap_connect, 0);
|
||||
will_return(__wrap_ssh_connect, 0);
|
||||
/* do not authenticate using no authentication method */
|
||||
will_return(__wrap_ssh_userauth_none, 1);
|
||||
will_return(__wrap_ssh_userauth_try_publickey, 0);
|
||||
will_return(__wrap_ssh_userauth_publickey, 0);
|
||||
will_return(__wrap_ssh_is_connected, 1);
|
||||
will_return(__wrap_ssh_channel_open_session, 0);
|
||||
will_return(__wrap_ssh_channel_request_subsystem, 0);
|
||||
|
||||
/* fake ssh function for recieving hello message */
|
||||
will_return(__wrap_ssh_is_connected, 1);
|
||||
|
||||
will_return(__wrap_nc_handshake_io, 3);
|
||||
will_return(__wrap_nc_ctx_check_and_fill, 0);
|
||||
session = nc_connect_ssh("127.0.0.1", 8080, NULL);
|
||||
assert_non_null(session);
|
||||
|
||||
/* disconnect */
|
||||
will_return(__wrap_ssh_channel_poll_timeout, 0);
|
||||
nc_session_free(session, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_connect_connection_failed(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_session *session;
|
||||
|
||||
errno = ECONNREFUSED;
|
||||
will_return(__wrap_connect, -1);
|
||||
will_return(__wrap_ssh_is_connected, 0);
|
||||
|
||||
session = nc_connect_ssh("127.0.0.1", 8080, NULL);
|
||||
assert_null(session);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_connect_ssh_bad_hello(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_session *session;
|
||||
|
||||
/* set authentication method to use interactive authentication */
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 1);
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1);
|
||||
|
||||
nc_client_ssh_set_auth_password_clb(test_pwd_clb2, NULL);
|
||||
|
||||
will_return(__wrap_connect, 0);
|
||||
will_return(__wrap_ssh_connect, 0);
|
||||
will_return(__wrap_ssh_userauth_none, 1);
|
||||
|
||||
will_return(__wrap_ssh_userauth_kbdint, 0);
|
||||
will_return(__wrap_ssh_is_connected, 1);
|
||||
will_return(__wrap_ssh_is_connected, 1);
|
||||
|
||||
will_return(__wrap_ssh_channel_open_session, 0);
|
||||
will_return(__wrap_ssh_channel_request_subsystem, 0);
|
||||
will_return(__wrap_nc_handshake_io, 4);
|
||||
|
||||
session = nc_connect_ssh("127.0.0.1", 8080, NULL);
|
||||
assert_null(session);
|
||||
|
||||
/* destroy client, must be called in last test */
|
||||
nc_client_destroy();
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_ssh_ch_setting_username(void **state)
|
||||
{
|
||||
(void)state;
|
||||
const char *username_ret;
|
||||
int ret;
|
||||
|
||||
/* username is set to "ch_username" in setup_f */
|
||||
username_ret = nc_client_ssh_ch_get_username();
|
||||
assert_string_equal(username_ret, "ch_username");
|
||||
/* set new username and check if it changes */
|
||||
ret = nc_client_ssh_ch_set_username("new_ch_username");
|
||||
assert_int_equal(ret, 0);
|
||||
username_ret = nc_client_ssh_ch_get_username();
|
||||
assert_string_equal(username_ret, "new_ch_username");
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_ssh_ch_add_bind_listen(void **state)
|
||||
{
|
||||
(void)state;
|
||||
int ret;
|
||||
|
||||
/* invalid parameters, address NULL or port 0 */
|
||||
ret = nc_client_ssh_ch_add_bind_listen(NULL, 4334);
|
||||
assert_int_equal(ret, -1);
|
||||
ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 0);
|
||||
assert_int_equal(ret, -1);
|
||||
|
||||
/* failed to create an ssh listening socket */
|
||||
will_return(__wrap_nc_sock_listen_inet, -1);
|
||||
ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334);
|
||||
assert_int_equal(ret, -1);
|
||||
|
||||
/* fake a successful CH ssh listening socket */
|
||||
will_return(__wrap_nc_sock_listen_inet, 1);
|
||||
ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
/* remove ssh listening client binds */
|
||||
ret = nc_client_ssh_ch_del_bind("127.0.0.1", 4334);
|
||||
assert_int_equal(ret, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_accept_callhome(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_session *session = NULL;
|
||||
int timeout = 10;
|
||||
int ret;
|
||||
|
||||
/* invalid parameter session */
|
||||
ret = nc_accept_callhome(timeout, NULL, NULL);
|
||||
assert_int_equal(ret, -1);
|
||||
|
||||
/* no client bind */
|
||||
ret = nc_accept_callhome(timeout, NULL, &session);
|
||||
assert_int_equal(ret, -1);
|
||||
|
||||
/* successfully add a client Call Home bind */
|
||||
will_return(__wrap_nc_sock_listen_inet, 1);
|
||||
ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
/* failed to accept a client bind */
|
||||
will_return(__wrap_nc_sock_accept_binds, -1);
|
||||
ret = nc_accept_callhome(timeout, NULL, &session);
|
||||
assert_int_equal(ret, -1);
|
||||
|
||||
/* failed to accept a server Call Home connection */
|
||||
will_return(__wrap_nc_accept_callhome_ssh_sock, NULL);
|
||||
will_return(__wrap_nc_sock_accept_binds, 2);
|
||||
ret = nc_accept_callhome(timeout, NULL, &session);
|
||||
assert_int_equal(ret, -1);
|
||||
|
||||
/* create session structure to fake a successful server call home connection */
|
||||
session = nc_new_session(NC_CLIENT, 0);
|
||||
assert_non_null(session);
|
||||
will_return(__wrap_nc_sock_accept_binds, 2);
|
||||
will_return(__wrap_nc_accept_callhome_ssh_sock, session);
|
||||
ret = nc_accept_callhome(timeout, NULL, &session);
|
||||
assert_int_equal(ret, 1);
|
||||
|
||||
/* remove ssh listening client binds */
|
||||
ret = nc_client_ssh_ch_del_bind("127.0.0.1", 4334);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
/* free session */
|
||||
nc_session_free(session, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_ssh_callhome_successful(void **state)
|
||||
{
|
||||
(void)state;
|
||||
struct nc_session *session = NULL;
|
||||
int timeout = 10;
|
||||
int ret;
|
||||
|
||||
/* create session structure */
|
||||
session = nc_new_session(NC_CLIENT, 0);
|
||||
assert_non_null(session);
|
||||
|
||||
/* prepare to fake return values for functions used by nc_accept_callhome */
|
||||
will_return(__wrap_nc_sock_listen_inet, 1);
|
||||
will_return(__wrap_nc_sock_accept_binds, 2);
|
||||
will_return(__wrap_nc_accept_callhome_ssh_sock, session);
|
||||
|
||||
ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334);
|
||||
assert_int_equal(ret, 0);
|
||||
ret = nc_accept_callhome(timeout, NULL, &session);
|
||||
assert_int_equal(ret, 1);
|
||||
|
||||
/* remove ssh listening client binds */
|
||||
ret = nc_client_ssh_ch_del_bind("127.0.0.1", 4334);
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
/* free session */
|
||||
nc_session_free(session, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_pref, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_hostkey_check_clb, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_password_clb, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_interactive_clb, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_privkey_passphrase_clb, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_ssh_adding_keypair, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_username, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_connect_ssh_interactive_succesfull, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_connect_ssh_password_succesfull, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_connect_ssh_pubkey_succesfull, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_connect_connection_failed, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_connect_ssh_bad_hello, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_ssh_ch_setting_username, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_ssh_ch_add_bind_listen, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_accept_callhome, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_ssh_callhome_successful, setup_f, teardown_f),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
200
tests/client/test_client_tls.c
Normal file
200
tests/client/test_client_tls.c
Normal file
|
@ -0,0 +1,200 @@
|
|||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
#include <config.h>
|
||||
#include <libyang/libyang.h>
|
||||
#include <log.h>
|
||||
#include <session_client.h>
|
||||
#include "tests/config.h"
|
||||
|
||||
static int
|
||||
setup_f(void **state)
|
||||
{
|
||||
(void)state;
|
||||
|
||||
nc_verbosity(NC_VERB_VERBOSE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
teardown_f(void **state)
|
||||
{
|
||||
(void)state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
(void)sockfd;
|
||||
(void)addr;
|
||||
(void)addrlen;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_SSL_connect(SSL *ssl)
|
||||
{
|
||||
(void)ssl;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_nc_handshake_io(struct nc_session *session)
|
||||
{
|
||||
(void)session;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
MOCK int
|
||||
__wrap_nc_ctx_check_and_fill(struct nc_session *session)
|
||||
{
|
||||
(void)session;
|
||||
|
||||
return (int)mock();
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_tls_setting_cert_key_paths(void **state)
|
||||
{
|
||||
(void)state;
|
||||
const char *cert, *key;
|
||||
int ret;
|
||||
|
||||
nc_client_init();
|
||||
|
||||
/* no certificats are set, nc_client_tls_get_cert_key_paths should output NULL */
|
||||
nc_client_tls_get_cert_key_paths(&cert, &key);
|
||||
assert_null(cert);
|
||||
assert_null(key);
|
||||
|
||||
/* set certificate path */
|
||||
ret = nc_client_tls_set_cert_key_paths("cert_path", "key_path");
|
||||
assert_int_equal(ret, 0);
|
||||
nc_client_tls_get_cert_key_paths(&cert, &key);
|
||||
assert_string_equal(cert, "cert_path");
|
||||
assert_string_equal(key, "key_path");
|
||||
|
||||
/* override certificate path */
|
||||
ret = nc_client_tls_set_cert_key_paths("cert_path1", "key_path1");
|
||||
assert_int_equal(ret, 0);
|
||||
nc_client_tls_get_cert_key_paths(&cert, &key);
|
||||
assert_string_equal(cert, "cert_path1");
|
||||
assert_string_equal(key, "key_path1");
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_tls_setting_trusted_ca_paths(void **state)
|
||||
{
|
||||
(void)state;
|
||||
const char *file, *dir;
|
||||
int ret;
|
||||
|
||||
ret = nc_client_tls_set_trusted_ca_paths("ca_file", "ca_dir");
|
||||
assert_int_equal(ret, 0);
|
||||
nc_client_tls_get_trusted_ca_paths(&file, &dir);
|
||||
assert_string_equal("ca_file", file);
|
||||
assert_string_equal("ca_dir", dir);
|
||||
|
||||
ret = nc_client_tls_set_trusted_ca_paths("ca_file1", "ca_dir1");
|
||||
assert_int_equal(ret, 0);
|
||||
nc_client_tls_get_trusted_ca_paths(&file, &dir);
|
||||
assert_string_equal("ca_file1", file);
|
||||
assert_string_equal("ca_dir1", dir);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_connect_tls_succesfull(void **state)
|
||||
{
|
||||
(void)state;
|
||||
int ret;
|
||||
struct nc_session *session;
|
||||
|
||||
ret = nc_client_tls_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key");
|
||||
assert_int_equal(ret, 0);
|
||||
ret = nc_client_tls_set_trusted_ca_paths(NULL, TESTS_DIR "/data");
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
will_return(__wrap_connect, 0);
|
||||
will_return(__wrap_SSL_connect, 1);
|
||||
|
||||
/* fake succesfull handshake */
|
||||
will_return(__wrap_nc_handshake_io, 3);
|
||||
will_return(__wrap_nc_ctx_check_and_fill, 0);
|
||||
session = nc_connect_tls("0.0.0.0", 6001, NULL);
|
||||
assert_non_null(session);
|
||||
|
||||
nc_session_free(session, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_client_tls_setting_crl_paths(void **state)
|
||||
{
|
||||
(void)state;
|
||||
const char *file, *dir;
|
||||
int ret;
|
||||
|
||||
nc_client_tls_get_crl_paths(&file, &dir);
|
||||
assert_null(file);
|
||||
assert_null(dir);
|
||||
|
||||
ret = nc_client_tls_set_crl_paths("file", "dir");
|
||||
assert_int_equal(ret, 0);
|
||||
nc_client_tls_get_crl_paths(&file, &dir);
|
||||
assert_string_equal(file, "file");
|
||||
assert_string_equal(dir, "dir");
|
||||
|
||||
ret = nc_client_tls_set_crl_paths("file1", "dir1");
|
||||
assert_int_equal(ret, 0);
|
||||
nc_client_tls_get_crl_paths(&file, &dir);
|
||||
assert_string_equal(file, "file1");
|
||||
assert_string_equal(dir, "dir1");
|
||||
|
||||
/* destroy client */
|
||||
nc_client_destroy();
|
||||
}
|
||||
|
||||
static void
|
||||
test_nc_connect_tls_handshake_failed(void **state)
|
||||
{
|
||||
(void)state;
|
||||
int ret;
|
||||
struct nc_session *session;
|
||||
|
||||
ret = nc_client_tls_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key");
|
||||
assert_int_equal(ret, 0);
|
||||
ret = nc_client_tls_set_trusted_ca_paths(NULL, TESTS_DIR "/data");
|
||||
assert_int_equal(ret, 0);
|
||||
|
||||
will_return(__wrap_connect, 0);
|
||||
will_return(__wrap_SSL_connect, 1);
|
||||
|
||||
/* fake failed handshake */
|
||||
will_return(__wrap_nc_handshake_io, 0);
|
||||
session = nc_connect_tls("0.0.0.0", 6001, NULL);
|
||||
assert_null(session);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_tls_setting_cert_key_paths, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_connect_tls_handshake_failed, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_connect_tls_succesfull, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_tls_setting_trusted_ca_paths, setup_f, teardown_f),
|
||||
cmocka_unit_test_setup_teardown(test_nc_client_tls_setting_crl_paths, setup_f, teardown_f),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
24
tests/config.h.in
Normal file
24
tests/config.h.in
Normal file
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* @file config.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @brief cmocka tests configuration header.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
|
||||
#else
|
||||
# define UNUSED(x) UNUSED_ ## x
|
||||
#endif
|
||||
|
||||
#define TESTS_DIR "@CMAKE_SOURCE_DIR@/tests"
|
||||
|
||||
@SSH_MACRO@
|
||||
@TLS_MACRO@
|
1
tests/data/042686bb.0
Symbolic link
1
tests/data/042686bb.0
Symbolic link
|
@ -0,0 +1 @@
|
|||
serverca.pem
|
1
tests/data/5412ca73.0
Symbolic link
1
tests/data/5412ca73.0
Symbolic link
|
@ -0,0 +1 @@
|
|||
server.crt
|
1
tests/data/62436b04.0
Symbolic link
1
tests/data/62436b04.0
Symbolic link
|
@ -0,0 +1 @@
|
|||
client.crt
|
25
tests/data/client.crt
Normal file
25
tests/data/client.crt
Normal file
|
@ -0,0 +1,25 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIEQDCCAygCCQCV65JgDvfWkDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJD
|
||||
WjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwG
|
||||
Q0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMB4XDTE4MTEw
|
||||
NTA3MzAzOVoXDTI4MTEwMjA3MzAzOVowYTELMAkGA1UEBhMCQ1oxEzARBgNVBAgM
|
||||
ClNvbWUtU3RhdGUxDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoG
|
||||
A1UECwwDVE1DMQ8wDQYDVQQDDAZjbGllbnQwggIiMA0GCSqGSIb3DQEBAQUAA4IC
|
||||
DwAwggIKAoICAQC+kqPqDL9GbWmqVQhp4qla4vYo4kFuh2HG48b7RLp/4l/guik4
|
||||
Hvq2aDVFD9sBcs3FeQbjoLH1Q4doUr8jG6VwJsfovE5SD3T8dVLs2dtpW0OyXTcc
|
||||
b0I9lOVDMz6f6IUBe/m5vk8XNbdUII0NJ8y1dQ51VH3e784Bzu7PSdaMaFac4fkw
|
||||
8kJA9LxkWkv2FDFC7IBcVjRgtb/15EwODH849O6+VPEgX5gdozNj5bL45rKDBvvx
|
||||
0KjD7dFBGAIHbSjmjp7HHadfYKqvtQnMb83fRcK6wohxNP3vy13wBTtSOlvOg16G
|
||||
b+2ZB0Or7wgOw19ZvEIcNgswPwhHfZQNcYMNVLCu02BSzwdY00IEqNM0J5B/W//K
|
||||
JF3uFF/ZqP7D2wO7w8j5UL2lpuxF7YrGecNT1Kr7ggHdkzcLlekkNu7wNWKAZlJ6
|
||||
+Kbun8PqZbamGXLG2Ur1aZDkyKyD9nyMzsRneAlxO+HbQhLojimUbsMm+wgL89zc
|
||||
hLYkL/DSmsJlryA4qhvzHaaONBw4DV5UhSbLDpZtXVfrn+MAm8hLpqf+gUCThsFN
|
||||
8kDp9h9Tg9v01ai9jGb941HkFtGYUWHS5drSz3ZLnSI6i1/wKdbs9ns9YqDMqq2c
|
||||
305v5h7taMN0b40KuGSIME4K4cOsdfCprFYGZQgKjaadQwrsm4k1Jl7kMwIDAQAB
|
||||
MA0GCSqGSIb3DQEBCwUAA4IBAQAtwH2u1o16jkABlqEGDIvAJSMwBmZzNTNHgOXt
|
||||
WDlkzWGsj+L1wc/DNjDRBkE31h4h7ASthhqi1nzzHYQ1hhPVhUUqI532AS/V7EPs
|
||||
Bg3f+BI8gxqQ31TUBEQ4Ll6FtW36nqpJOe6Uui2rH2FonuUg2Av5BvDRil42Tu7f
|
||||
YW4WpSU3e00HiGJ0J0t+QjoKRnnoLJJqlmzk8Y4aIlQim7Azvrlo1WEtOhI3L9UE
|
||||
1GEqxLjRB45P36FSe1wfkgt7xmD0Xjy33Wh6Ae2Fvx7OfJ0K1zy0LHr4rDDJ3tLT
|
||||
qjPqHIFhaa73jGXwXk8sZnbAk542Oa6C6AjzNFyqV7T5Q5lg
|
||||
-----END CERTIFICATE-----
|
51
tests/data/client.key
Normal file
51
tests/data/client.key
Normal file
|
@ -0,0 +1,51 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIJKQIBAAKCAgEAvpKj6gy/Rm1pqlUIaeKpWuL2KOJBbodhxuPG+0S6f+Jf4Lop
|
||||
OB76tmg1RQ/bAXLNxXkG46Cx9UOHaFK/IxulcCbH6LxOUg90/HVS7NnbaVtDsl03
|
||||
HG9CPZTlQzM+n+iFAXv5ub5PFzW3VCCNDSfMtXUOdVR93u/OAc7uz0nWjGhWnOH5
|
||||
MPJCQPS8ZFpL9hQxQuyAXFY0YLW/9eRMDgx/OPTuvlTxIF+YHaMzY+Wy+Oaygwb7
|
||||
8dCow+3RQRgCB20o5o6exx2nX2Cqr7UJzG/N30XCusKIcTT978td8AU7UjpbzoNe
|
||||
hm/tmQdDq+8IDsNfWbxCHDYLMD8IR32UDXGDDVSwrtNgUs8HWNNCBKjTNCeQf1v/
|
||||
yiRd7hRf2aj+w9sDu8PI+VC9pabsRe2KxnnDU9Sq+4IB3ZM3C5XpJDbu8DVigGZS
|
||||
evim7p/D6mW2phlyxtlK9WmQ5Misg/Z8jM7EZ3gJcTvh20IS6I4plG7DJvsIC/Pc
|
||||
3IS2JC/w0prCZa8gOKob8x2mjjQcOA1eVIUmyw6WbV1X65/jAJvIS6an/oFAk4bB
|
||||
TfJA6fYfU4Pb9NWovYxm/eNR5BbRmFFh0uXa0s92S50iOotf8CnW7PZ7PWKgzKqt
|
||||
nN9Ob+Ye7WjDdG+NCrhkiDBOCuHDrHXwqaxWBmUICo2mnUMK7JuJNSZe5DMCAwEA
|
||||
AQKCAgA3X963LHsL2NECSHEIa28wVJCYcp32oun7Y8Y2ztKuRDX907oUb5QEGqWX
|
||||
6rKFajl2buNckx4CmVuoKZsWdXsN6obeDpFncMxaazDsV6VUqMsz8bgI0B9cS36O
|
||||
lz5UMrkrJD39BdpvcRFTJZ42u2DVPS01VJa6h83BYsKrgtYPuGWqclL5MPulajev
|
||||
pTk7SMTDoHrv2bCghU9BANREpMb24tzYe1ARSxWlTv2owl7NyiMGxanBqxLO07Sh
|
||||
CHvWcpaW38wtKWWv5iPSqHUvbTFR9jBOGiaRVoeO/PXPv4VsMD7q8+ssfyt38s9s
|
||||
Dym1OHnlVjmTfvSjUT1zoH67pUchv/RUsUT8SR2zvK2Cm9xwEG+Nn2izuUZwCjxp
|
||||
Pouan6ZZrCnJut0PKWbEpeEzwKWgEx3r+tYeoV+svkePKKU3oQEUgzACAA5PHRZT
|
||||
GiaFBHznb57HZaw5xXCmm1g3k31wP0MEnLebEeFtFvqcc0LWQ6uN5UZtpZNM393n
|
||||
w87CVIZqX0miuB7GsDsZwg8ODWy7nEsAppeoudFg81Gy0jrVluI72le2sYGU4SRe
|
||||
TBjAf/9H6GF+rYWYgWFfkDeQp31Vx3gkJC6V+lSdMh6OMa8A+vk47alwQbX5kbLJ
|
||||
AqtSFjOCWLDhUB650huOnk9PyhoK85D+hd9Tx924TByeegXO2QKCAQEA/QptsVKV
|
||||
fUlfKN2HVntPP6+y/fnR2nSGRWP91KP1I1/PyG+FSXGxR1ngXFpn5TByD5CFBEhv
|
||||
0PX8pUjbC1cgNC7WJuy2B0g4Cn4m25yiMPz7g1Ngt+JkWH3E57AeSYCqUUm41Qb0
|
||||
PUA1zZDE4izvEzweTp04ZFk/1+oPQDeol0oIFhrlrxDSYRjpgDcwPWrQvRnmqfQL
|
||||
C1aB9+ulHqLIzvhpsWBg4+mYsMfFGX6P+f0NxWFH2hVZoax2STcupAXiRcUbzTO9
|
||||
z6Yan6DydHv0dS3XcReOFhgB1fRC4hbnJPRZxH1rJ6H0PzmN6vfKeWzZ60Uflyti
|
||||
r100P+Mh2rUobwKCAQEAwM0w282zqmn71pqmCUrC153uRY1eXRtGmDkuLvpPO0N9
|
||||
LPLo1AblboIdxXw4pUBzmxtO+J8L+rYzi+sorNhL0GuOHulgVSe27WMfEXeGOhay
|
||||
m0qGiEEs1s2Ctgj7MdzHzW2moiMOJUgnBIQraJ9JF7KGwMoblUsFE3EeIF2sy8qk
|
||||
tHugxfx/HUouCx5m8Fsh0HMkvsJMZvmJPMihsVYL57UxGTuKMPsNGpNfdyKgHo3G
|
||||
0t+0yR81EPsfnhxoLbGlvgA9Bcn5I2tU9WyYI+e5LdbsXg2EAltXY4YHyg+GRFnL
|
||||
2ZrPNfm5Wrh2P5w0xepGflwW0QfL1CVPJz9+0c86fQKCAQB4FgDkzGqBYNa2UBuw
|
||||
YSjE8p8hhPOglvg56jBGP+FQfmHfn31D057sW6zsZ0MzM4CN/moCFFZsdrEFx8Oc
|
||||
aCayXR/orSHd5tohsKjERFt8oDLEqkcWPWydymIuChj1jQhHN5NuFbTHdLeT7QZi
|
||||
yCxVloxThq2CghCYaU3/jeqGke2wf+dM49DTn70AyjAslYqmk6oyMc0j/lQD0mM0
|
||||
XNCr2JxgP3r77po2Gzhg1v2BCCUG7RnqV4OIBI7GRFfwI5K0xcxh4BJOf2fXJcyq
|
||||
l0D2c2DxHNqjhZUpcphjL7dWhFgttc+qqWN+tdOyFRKT+aKZ0t4hIcfdrX/kaehh
|
||||
IOQlAoIBAQCCEmyh/db2Y2Yp1E+r+SoWOVAk0EkXW213CSylOO33N4Ldrktxr+1d
|
||||
bp8TOskkg6T6waO3i+WTERUZkl7wrUQIqmdJZ308Nfztjm/JYu/FhMaeidrVVdMg
|
||||
X6mNkeWWMDMD3rQKsse6U0EvhNOcU8oGGMVcj32obOJRyYDfqRMIsgAIW1eN+tjv
|
||||
M7p4edxMz86ySNxDbeYJmtQBlAGyGDET82PaeBa1EMo4YbCIOW347wFyBsZ64Xj1
|
||||
qdYc32FRYoZE9vg0TZytTp4UrVy+7Hg7+sGgelHTHTiJxkS/B1Y4CrTCa/Tbn0xz
|
||||
bfso0wOvemxwl0Q1ZaMXzsvl2KqAdeQpAoIBAQC9tvBTKaBxcaijwLqa+lKOQZnO
|
||||
4MxQsCX5hcXyBJPPhEjP8J3MoyEOGQZK1gu6fRnDuOhgEFqBHJAGIEvLYId2qP3f
|
||||
4/wZp4as4BYrEPBplwehrh9ufG8NrY4v9vSFzWkNCvuiOgGxmmzo9CPDRvMHSjnx
|
||||
R1FqAc4PfMqU7LYEX9MKgu5KwCzp8Ot6Y5ifm1hXr2x7ARxe/S3zdvIpaB/aY9TC
|
||||
D/gWkXVplQDGrLwcguleMy4ZUKuD6L9QLbBBjN18ua5yHfCfw3flSgC9hBxazqce
|
||||
WChZob9ttZIXX/W0sefNjQjo0etQFakkGYAZihK34fUnCSuMVQDWWxdl1wJA
|
||||
-----END RSA PRIVATE KEY-----
|
12
tests/data/key_dsa
Normal file
12
tests/data/key_dsa
Normal file
|
@ -0,0 +1,12 @@
|
|||
-----BEGIN DSA PRIVATE KEY-----
|
||||
MIIBugIBAAKBgQC5UysgLVJXTBaY4hPuLBBmxsOkC9VzFKbH581ufLqKxBZlQhcn
|
||||
OZ4DaQWXUvMXOmDTnG+ROpjbXBMxaYRmCwrUL9Gz0JeTYuqE413D1XYpQYZH5oJH
|
||||
7SyIe4R+mlCdORekeSKdY2oJ9dREVVe0WXiAzrBV+Eg5Ve3uWQkYw3HAMwIVAMOo
|
||||
rc88si96YqcYSPf//761FJtVAoGANwUJNODSvguHU6x55+UTGHLyWnbIqd/nbUn1
|
||||
cnCRa4xeHSHq0rBayoHh3hJiqqpcdRpb0lVoYNe51HmFJHJUGLHtYcxgnqdvIF5K
|
||||
QiP5h1ESxYqb4v4AXHl5+CVyC0Yp/hkowqaNfVqyOgol/IhNlJknZDCMxWUD9NUJ
|
||||
iiV5oc0CgYACU3qrETmgEHbwx5kCKN1/Ly4pWzS5rNg764aYsU0wE714TfYs5nOf
|
||||
yEvQYkfBDb+rEpGyKot6ZvDsHvL0WVVVx7mIDSKnzHAYwYGl1wKNHlLenOMZIDRT
|
||||
43AKfTz03wRkCrzBl2fAmLLq7wFaXcDDxaBg4zN2CDbuHjmJgRuwzAIUBRb7QH4c
|
||||
p2gVuWcmRuuI9Qexmzc=
|
||||
-----END DSA PRIVATE KEY-----
|
1
tests/data/key_dsa.pub
Normal file
1
tests/data/key_dsa.pub
Normal file
|
@ -0,0 +1 @@
|
|||
ssh-dss AAAAB3NzaC1kc3MAAACBALlTKyAtUldMFpjiE+4sEGbGw6QL1XMUpsfnzW58uorEFmVCFyc5ngNpBZdS8xc6YNOcb5E6mNtcEzFphGYLCtQv0bPQl5Ni6oTjXcPVdilBhkfmgkftLIh7hH6aUJ05F6R5Ip1jagn11ERVV7RZeIDOsFX4SDlV7e5ZCRjDccAzAAAAFQDDqK3PPLIvemKnGEj3//++tRSbVQAAAIA3BQk04NK+C4dTrHnn5RMYcvJadsip3+dtSfVycJFrjF4dIerSsFrKgeHeEmKqqlx1GlvSVWhg17nUeYUkclQYse1hzGCep28gXkpCI/mHURLFipvi/gBceXn4JXILRin+GSjCpo19WrI6CiX8iE2UmSdkMIzFZQP01QmKJXmhzQAAAIACU3qrETmgEHbwx5kCKN1/Ly4pWzS5rNg764aYsU0wE714TfYs5nOfyEvQYkfBDb+rEpGyKot6ZvDsHvL0WVVVx7mIDSKnzHAYwYGl1wKNHlLenOMZIDRT43AKfTz03wRkCrzBl2fAmLLq7wFaXcDDxaBg4zN2CDbuHjmJgRuwzA== vasko@pcvasko
|
5
tests/data/key_ecdsa
Normal file
5
tests/data/key_ecdsa
Normal file
|
@ -0,0 +1,5 @@
|
|||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEICQ2fr9Jt2xluom0YQQ7HseE8YTo5reZRVcQENKUWOrooAoGCCqGSM49
|
||||
AwEHoUQDQgAENEgHZ41JFZT4c1ZFQYqvvqCEIuDxFoyVQKmz2UGOdzqCBomXZD5M
|
||||
4ufyx7bAB0reVgEzPd1ypH5KVTt4HzAkBw==
|
||||
-----END EC PRIVATE KEY-----
|
1
tests/data/key_ecdsa.pub
Normal file
1
tests/data/key_ecdsa.pub
Normal file
|
@ -0,0 +1 @@
|
|||
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDRIB2eNSRWU+HNWRUGKr76ghCLg8RaMlUCps9lBjnc6ggaJl2Q+TOLn8se2wAdK3lYBMz3dcqR+SlU7eB8wJAc= vasko@pcvasko
|
27
tests/data/key_rsa
Normal file
27
tests/data/key_rsa
Normal file
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAz2r1QC4jO0MEyFAJ3TvBPRjpEg0Fo7hMJM2yd5DgT2u5JKu9
|
||||
VDmRXnnA4xW/XoqZJY3xcrPyWBxkGmFRfP7L09CleYex5brUXResr6khG46W0zkW
|
||||
9u6XR194hRMgwsAiKKvbzHl/sMl57Xsp9NRqSC9IoNFgJ75Kl/0j47qZV+WSLVEq
|
||||
9DIVzO3zUl+dAQ+hvCDtP3Y1HHTFHI04xr+90sQfWcy78Z4V7lCW8xCSSS4+qmo8
|
||||
hCFWiUmu97wN9yQg/Ks2q67LiE6I1SzwxZnh8EgKAeXT/OsqKenusqbl8yscXn+s
|
||||
jV3BPKE4/FBWASF7ICD9pwb1pONRGitFZN2BZQIDAQABAoIBAQC1jeTQYdI67EXC
|
||||
ZLTNrqFNroFMaJOYJBiaWmat2+VL/3nWzHDzyVQiQyaAXyfcRCsbQSyn/zTQxUEm
|
||||
Cis+4vRdGpPNVeZ0tN1wAuoH9F3jdiM1DhK44E0Qj1O5/+08Ktt7iDrjtzH699A+
|
||||
/ADUqh3Bw4mqIrss7pbyhQSmME5LLTbaWikZ8LgtUiF9f5JWzsqjPb6Yd8JEg0O+
|
||||
5lDngLfgEYevKCJxxBMtQQQ6gZCjQQWmir+/0NBezSHsoltPlw1m8Vs8Y5zz684y
|
||||
v33J/qxDM7+rbGbte2fSQ06OuK7abCZMyfXyWdp4cQpG1JZRxGp4Y8vQKvsU5ZOQ
|
||||
UT/v7ur9AoGBAO+Li/vUzU3GlL7mxBlPTg5LavItWq6C7Rnwftjql7yPxrQ/+m5R
|
||||
Za0YujnqvZq5SpdpljCZbF9KYrFr92wgFqlt5uYptI4eD0/6xALEUcJJIlllTjiK
|
||||
tJmuyFkkD45WEn1IlDGAURQiDn6aqd40odlPsv4L5EdnQEQQz6Kfv6JLAoGBAN2q
|
||||
chHTKv1PBXfqRm0ABYSPyFhki2RqI4DWsbwykFXn3qP7tDDnmR/VMsAbApgTVW77
|
||||
LGffJ7DZXsqgzujwcqvLBKf8Wl5MRJg2jTe0GkKEBYqhGWNzBhuIwnIcKu/6HsEd
|
||||
FfCD93hwUPaVTBE+2ckXQVb9RSUCpGarXKk9cZ0PAoGBAJ/Hku29OdwA80KKpo7D
|
||||
SStbvtAe1HfGuOQueE2z3NZXiJC+hAqFnK5i6gSrwSCtK0XnldiA3bqJ4V66x2SF
|
||||
2tfUiMlJVDffcRNGDuxRir9vDMxYOF6alnBUFyruVLn6S4bpnH+QOYSWWtizzU58
|
||||
CODsulWeFPxTsJg2Jmkw6SAVAoGANWBGqX4k2uw9T9vM65BWw83vm0FSw3I/bFXG
|
||||
ZJ/0W4tC9E+22xPZrm2jE9ktLbtyFhBLaBO3NgGRrs88I6FKq41uaJj+lbhdyB1S
|
||||
sfgfXqb1wqT6PRVEgjrTP7ECsdiTsUK0tr7AR3McO9RFhd2Ribec1zqTfM7/EW3w
|
||||
GRyfkAcCgYAtw6KO+5fXHE79v9pUdZAJ4PAc/KdHjv0zE9s5snwUrh7TO5fIB62d
|
||||
i6nPBWLwD5InDZ9sNgxzTBt+0o2N6PsvKQFtfEBemKimmZShMytFkx9/KTRNR9se
|
||||
2qcBMiJsdAaz6hHUliYVWV3Ui+Uy+vYh5reuEhcvEjEzT6ySaCrZfg==
|
||||
-----END RSA PRIVATE KEY-----
|
1
tests/data/key_rsa.pub
Normal file
1
tests/data/key_rsa.pub
Normal file
|
@ -0,0 +1 @@
|
|||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl vasko@pcvasko
|
464
tests/data/modules/ietf-netconf-acm.yin
Normal file
464
tests/data/modules/ietf-netconf-acm.yin
Normal file
|
@ -0,0 +1,464 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module name="ietf-netconf-acm"
|
||||
xmlns="urn:ietf:params:xml:ns:yang:yin:1"
|
||||
xmlns:nacm="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"
|
||||
xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types">
|
||||
<namespace uri="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"/>
|
||||
<prefix value="nacm"/>
|
||||
<import module="ietf-yang-types">
|
||||
<prefix value="yang"/>
|
||||
</import>
|
||||
<organization>
|
||||
<text>IETF NETCONF (Network Configuration) Working Group</text>
|
||||
</organization>
|
||||
<contact>
|
||||
<text>WG Web: <https://datatracker.ietf.org/wg/netconf/>
|
||||
WG List: <mailto:netconf@ietf.org>
|
||||
|
||||
Author: Andy Bierman
|
||||
<mailto:andy@yumaworks.com>
|
||||
|
||||
Author: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com></text>
|
||||
</contact>
|
||||
<description>
|
||||
<text>Network Configuration Access Control Model.
|
||||
|
||||
Copyright (c) 2012 - 2018 IETF Trust and the persons
|
||||
identified as authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD
|
||||
License set forth in Section 4.c of the IETF Trust's
|
||||
Legal Provisions Relating to IETF Documents
|
||||
(https://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 8341; see
|
||||
the RFC itself for full legal notices.</text>
|
||||
</description>
|
||||
<revision date="2018-02-14">
|
||||
<description>
|
||||
<text>Added support for YANG 1.1 actions and notifications tied to
|
||||
data nodes. Clarified how NACM extensions can be used by
|
||||
other data models.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 8341: Network Configuration Access Control Model</text>
|
||||
</reference>
|
||||
</revision>
|
||||
<revision date="2012-02-22">
|
||||
<description>
|
||||
<text>Initial version.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6536: Network Configuration Protocol (NETCONF)
|
||||
Access Control Model</text>
|
||||
</reference>
|
||||
</revision>
|
||||
<extension name="default-deny-write">
|
||||
<description>
|
||||
<text>Used to indicate that the data model node
|
||||
represents a sensitive security system parameter.
|
||||
|
||||
If present, the NETCONF server will only allow the designated
|
||||
'recovery session' to have write access to the node. An
|
||||
explicit access control rule is required for all other users.
|
||||
|
||||
If the NACM module is used, then it must be enabled (i.e.,
|
||||
/nacm/enable-nacm object equals 'true'), or this extension
|
||||
is ignored.
|
||||
|
||||
The 'default-deny-write' extension MAY appear within a data
|
||||
definition statement. It is ignored otherwise.</text>
|
||||
</description>
|
||||
</extension>
|
||||
<extension name="default-deny-all">
|
||||
<description>
|
||||
<text>Used to indicate that the data model node
|
||||
controls a very sensitive security system parameter.
|
||||
|
||||
If present, the NETCONF server will only allow the designated
|
||||
'recovery session' to have read, write, or execute access to
|
||||
the node. An explicit access control rule is required for all
|
||||
other users.
|
||||
|
||||
If the NACM module is used, then it must be enabled (i.e.,
|
||||
/nacm/enable-nacm object equals 'true'), or this extension
|
||||
is ignored.
|
||||
|
||||
The 'default-deny-all' extension MAY appear within a data
|
||||
definition statement, 'rpc' statement, or 'notification'
|
||||
statement. It is ignored otherwise.</text>
|
||||
</description>
|
||||
</extension>
|
||||
<typedef name="user-name-type">
|
||||
<type name="string">
|
||||
<length value="1..max"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>General-purpose username string.</text>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="matchall-string-type">
|
||||
<type name="string">
|
||||
<pattern value="\*"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>The string containing a single asterisk '*' is used
|
||||
to conceptually represent all possible values
|
||||
for the particular leaf using this data type.</text>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="access-operations-type">
|
||||
<type name="bits">
|
||||
<bit name="create">
|
||||
<description>
|
||||
<text>Any protocol operation that creates a
|
||||
new data node.</text>
|
||||
</description>
|
||||
</bit>
|
||||
<bit name="read">
|
||||
<description>
|
||||
<text>Any protocol operation or notification that
|
||||
returns the value of a data node.</text>
|
||||
</description>
|
||||
</bit>
|
||||
<bit name="update">
|
||||
<description>
|
||||
<text>Any protocol operation that alters an existing
|
||||
data node.</text>
|
||||
</description>
|
||||
</bit>
|
||||
<bit name="delete">
|
||||
<description>
|
||||
<text>Any protocol operation that removes a data node.</text>
|
||||
</description>
|
||||
</bit>
|
||||
<bit name="exec">
|
||||
<description>
|
||||
<text>Execution access to the specified protocol operation.</text>
|
||||
</description>
|
||||
</bit>
|
||||
</type>
|
||||
<description>
|
||||
<text>Access operation.</text>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="group-name-type">
|
||||
<type name="string">
|
||||
<length value="1..max"/>
|
||||
<pattern value="[^\*].*"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>Name of administrative group to which
|
||||
users can be assigned.</text>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="action-type">
|
||||
<type name="enumeration">
|
||||
<enum name="permit">
|
||||
<description>
|
||||
<text>Requested action is permitted.</text>
|
||||
</description>
|
||||
</enum>
|
||||
<enum name="deny">
|
||||
<description>
|
||||
<text>Requested action is denied.</text>
|
||||
</description>
|
||||
</enum>
|
||||
</type>
|
||||
<description>
|
||||
<text>Action taken by the server when a particular
|
||||
rule matches.</text>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="node-instance-identifier">
|
||||
<type name="yang:xpath1.0"/>
|
||||
<description>
|
||||
<text>Path expression used to represent a special
|
||||
data node, action, or notification instance-identifier
|
||||
string.
|
||||
|
||||
A node-instance-identifier value is an
|
||||
unrestricted YANG instance-identifier expression.
|
||||
All the same rules as an instance-identifier apply,
|
||||
except that predicates for keys are optional. If a key
|
||||
predicate is missing, then the node-instance-identifier
|
||||
represents all possible server instances for that key.
|
||||
|
||||
This XML Path Language (XPath) expression is evaluated in the
|
||||
following context:
|
||||
|
||||
o The set of namespace declarations are those in scope on
|
||||
the leaf element where this type is used.
|
||||
|
||||
o The set of variable bindings contains one variable,
|
||||
'USER', which contains the name of the user of the
|
||||
current session.
|
||||
|
||||
o The function library is the core function library, but
|
||||
note that due to the syntax restrictions of an
|
||||
instance-identifier, no functions are allowed.
|
||||
|
||||
o The context node is the root node in the data tree.
|
||||
|
||||
The accessible tree includes actions and notifications tied
|
||||
to data nodes.</text>
|
||||
</description>
|
||||
</typedef>
|
||||
<container name="nacm">
|
||||
<nacm:default-deny-all/>
|
||||
<description>
|
||||
<text>Parameters for NETCONF access control model.</text>
|
||||
</description>
|
||||
<leaf name="enable-nacm">
|
||||
<type name="boolean"/>
|
||||
<default value="true"/>
|
||||
<description>
|
||||
<text>Enables or disables all NETCONF access control
|
||||
enforcement. If 'true', then enforcement
|
||||
is enabled. If 'false', then enforcement
|
||||
is disabled.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="read-default">
|
||||
<type name="action-type"/>
|
||||
<default value="permit"/>
|
||||
<description>
|
||||
<text>Controls whether read access is granted if
|
||||
no appropriate rule is found for a
|
||||
particular read request.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="write-default">
|
||||
<type name="action-type"/>
|
||||
<default value="deny"/>
|
||||
<description>
|
||||
<text>Controls whether create, update, or delete access
|
||||
is granted if no appropriate rule is found for a
|
||||
particular write request.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="exec-default">
|
||||
<type name="action-type"/>
|
||||
<default value="permit"/>
|
||||
<description>
|
||||
<text>Controls whether exec access is granted if no appropriate
|
||||
rule is found for a particular protocol operation request.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="enable-external-groups">
|
||||
<type name="boolean"/>
|
||||
<default value="true"/>
|
||||
<description>
|
||||
<text>Controls whether the server uses the groups reported by the
|
||||
NETCONF transport layer when it assigns the user to a set of
|
||||
NACM groups. If this leaf has the value 'false', any group
|
||||
names reported by the transport layer are ignored by the
|
||||
server.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="denied-operations">
|
||||
<type name="yang:zero-based-counter32"/>
|
||||
<config value="false"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>Number of times since the server last restarted that a
|
||||
protocol operation request was denied.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="denied-data-writes">
|
||||
<type name="yang:zero-based-counter32"/>
|
||||
<config value="false"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>Number of times since the server last restarted that a
|
||||
protocol operation request to alter
|
||||
a configuration datastore was denied.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="denied-notifications">
|
||||
<type name="yang:zero-based-counter32"/>
|
||||
<config value="false"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>Number of times since the server last restarted that
|
||||
a notification was dropped for a subscription because
|
||||
access to the event type was denied.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<container name="groups">
|
||||
<description>
|
||||
<text>NETCONF access control groups.</text>
|
||||
</description>
|
||||
<list name="group">
|
||||
<key value="name"/>
|
||||
<description>
|
||||
<text>One NACM group entry. This list will only contain
|
||||
configured entries, not any entries learned from
|
||||
any transport protocols.</text>
|
||||
</description>
|
||||
<leaf name="name">
|
||||
<type name="group-name-type"/>
|
||||
<description>
|
||||
<text>Group name associated with this entry.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf-list name="user-name">
|
||||
<type name="user-name-type"/>
|
||||
<description>
|
||||
<text>Each entry identifies the username of
|
||||
a member of the group associated with
|
||||
this entry.</text>
|
||||
</description>
|
||||
</leaf-list>
|
||||
</list>
|
||||
</container>
|
||||
<list name="rule-list">
|
||||
<key value="name"/>
|
||||
<ordered-by value="user"/>
|
||||
<description>
|
||||
<text>An ordered collection of access control rules.</text>
|
||||
</description>
|
||||
<leaf name="name">
|
||||
<type name="string">
|
||||
<length value="1..max"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>Arbitrary name assigned to the rule-list.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf-list name="group">
|
||||
<type name="union">
|
||||
<type name="matchall-string-type"/>
|
||||
<type name="group-name-type"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>List of administrative groups that will be
|
||||
assigned the associated access rights
|
||||
defined by the 'rule' list.
|
||||
|
||||
The string '*' indicates that all groups apply to the
|
||||
entry.</text>
|
||||
</description>
|
||||
</leaf-list>
|
||||
<list name="rule">
|
||||
<key value="name"/>
|
||||
<ordered-by value="user"/>
|
||||
<description>
|
||||
<text>One access control rule.
|
||||
|
||||
Rules are processed in user-defined order until a match is
|
||||
found. A rule matches if 'module-name', 'rule-type', and
|
||||
'access-operations' match the request. If a rule
|
||||
matches, the 'action' leaf determines whether or not
|
||||
access is granted.</text>
|
||||
</description>
|
||||
<leaf name="name">
|
||||
<type name="string">
|
||||
<length value="1..max"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>Arbitrary name assigned to the rule.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="module-name">
|
||||
<type name="union">
|
||||
<type name="matchall-string-type"/>
|
||||
<type name="string"/>
|
||||
</type>
|
||||
<default value="*"/>
|
||||
<description>
|
||||
<text>Name of the module associated with this rule.
|
||||
|
||||
This leaf matches if it has the value '*' or if the
|
||||
object being accessed is defined in the module with the
|
||||
specified module name.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<choice name="rule-type">
|
||||
<description>
|
||||
<text>This choice matches if all leafs present in the rule
|
||||
match the request. If no leafs are present, the
|
||||
choice matches all requests.</text>
|
||||
</description>
|
||||
<case name="protocol-operation">
|
||||
<leaf name="rpc-name">
|
||||
<type name="union">
|
||||
<type name="matchall-string-type"/>
|
||||
<type name="string"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>This leaf matches if it has the value '*' or if
|
||||
its value equals the requested protocol operation
|
||||
name.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
</case>
|
||||
<case name="notification">
|
||||
<leaf name="notification-name">
|
||||
<type name="union">
|
||||
<type name="matchall-string-type"/>
|
||||
<type name="string"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>This leaf matches if it has the value '*' or if its
|
||||
value equals the requested notification name.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
</case>
|
||||
<case name="data-node">
|
||||
<leaf name="path">
|
||||
<type name="node-instance-identifier"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>Data node instance-identifier associated with the
|
||||
data node, action, or notification controlled by
|
||||
this rule.
|
||||
|
||||
Configuration data or state data
|
||||
instance-identifiers start with a top-level
|
||||
data node. A complete instance-identifier is
|
||||
required for this type of path value.
|
||||
|
||||
The special value '/' refers to all possible
|
||||
datastore contents.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
</case>
|
||||
</choice>
|
||||
<leaf name="access-operations">
|
||||
<type name="union">
|
||||
<type name="matchall-string-type"/>
|
||||
<type name="access-operations-type"/>
|
||||
</type>
|
||||
<default value="*"/>
|
||||
<description>
|
||||
<text>Access operations associated with this rule.
|
||||
|
||||
This leaf matches if it has the value '*' or if the
|
||||
bit corresponding to the requested operation is set.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="action">
|
||||
<type name="action-type"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>The access control action associated with the
|
||||
rule. If a rule has been determined to match a
|
||||
particular request, then this object is used
|
||||
to determine whether to permit or deny the
|
||||
request.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="comment">
|
||||
<type name="string"/>
|
||||
<description>
|
||||
<text>A textual description of the access rule.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
</list>
|
||||
</list>
|
||||
</container>
|
||||
</module>
|
600
tests/data/modules/ietf-netconf-monitoring.yin
Normal file
600
tests/data/modules/ietf-netconf-monitoring.yin
Normal file
|
@ -0,0 +1,600 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module name="ietf-netconf-monitoring"
|
||||
xmlns="urn:ietf:params:xml:ns:yang:yin:1"
|
||||
xmlns:ncm="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"
|
||||
xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types"
|
||||
xmlns:inet="urn:ietf:params:xml:ns:yang:ietf-inet-types">
|
||||
<namespace uri="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"/>
|
||||
<prefix value="ncm"/>
|
||||
<import module="ietf-yang-types">
|
||||
<prefix value="yang"/>
|
||||
</import>
|
||||
<import module="ietf-inet-types">
|
||||
<prefix value="inet"/>
|
||||
</import>
|
||||
<organization>
|
||||
<text>IETF NETCONF (Network Configuration) Working Group</text>
|
||||
</organization>
|
||||
<contact>
|
||||
<text>WG Web: <http://tools.ietf.org/wg/netconf/>
|
||||
WG List: <mailto:netconf@ietf.org>
|
||||
|
||||
WG Chair: Mehmet Ersue
|
||||
<mailto:mehmet.ersue@nsn.com>
|
||||
|
||||
WG Chair: Bert Wijnen
|
||||
<mailto:bertietf@bwijnen.net>
|
||||
|
||||
Editor: Mark Scott
|
||||
<mailto:mark.scott@ericsson.com>
|
||||
|
||||
Editor: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com></text>
|
||||
</contact>
|
||||
<description>
|
||||
<text>NETCONF Monitoring Module.
|
||||
All elements in this module are read-only.
|
||||
|
||||
Copyright (c) 2010 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD
|
||||
License set forth in Section 4.c of the IETF Trust's
|
||||
Legal Provisions Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 6022; see
|
||||
the RFC itself for full legal notices.</text>
|
||||
</description>
|
||||
<revision date="2010-10-04">
|
||||
<description>
|
||||
<text>Initial revision.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6022: YANG Module for NETCONF Monitoring</text>
|
||||
</reference>
|
||||
</revision>
|
||||
<typedef name="netconf-datastore-type">
|
||||
<type name="enumeration">
|
||||
<enum name="running"/>
|
||||
<enum name="candidate"/>
|
||||
<enum name="startup"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>Enumeration of possible NETCONF datastore types.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 4741: NETCONF Configuration Protocol</text>
|
||||
</reference>
|
||||
</typedef>
|
||||
<identity name="transport">
|
||||
<description>
|
||||
<text>Base identity for NETCONF transport types.</text>
|
||||
</description>
|
||||
</identity>
|
||||
<identity name="netconf-ssh">
|
||||
<base name="transport"/>
|
||||
<description>
|
||||
<text>NETCONF over Secure Shell (SSH).</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 4742: Using the NETCONF Configuration Protocol
|
||||
over Secure SHell (SSH)</text>
|
||||
</reference>
|
||||
</identity>
|
||||
<identity name="netconf-soap-over-beep">
|
||||
<base name="transport"/>
|
||||
<description>
|
||||
<text>NETCONF over Simple Object Access Protocol (SOAP) over
|
||||
Blocks Extensible Exchange Protocol (BEEP).</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 4743: Using NETCONF over the Simple Object
|
||||
Access Protocol (SOAP)</text>
|
||||
</reference>
|
||||
</identity>
|
||||
<identity name="netconf-soap-over-https">
|
||||
<base name="transport"/>
|
||||
<description>
|
||||
<text>NETCONF over Simple Object Access Protocol (SOAP)
|
||||
over Hypertext Transfer Protocol Secure (HTTPS).</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 4743: Using NETCONF over the Simple Object
|
||||
Access Protocol (SOAP)</text>
|
||||
</reference>
|
||||
</identity>
|
||||
<identity name="netconf-beep">
|
||||
<base name="transport"/>
|
||||
<description>
|
||||
<text>NETCONF over Blocks Extensible Exchange Protocol (BEEP).</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 4744: Using the NETCONF Protocol over the
|
||||
Blocks Extensible Exchange Protocol (BEEP)</text>
|
||||
</reference>
|
||||
</identity>
|
||||
<identity name="netconf-tls">
|
||||
<base name="transport"/>
|
||||
<description>
|
||||
<text>NETCONF over Transport Layer Security (TLS).</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 5539: NETCONF over Transport Layer Security (TLS)</text>
|
||||
</reference>
|
||||
</identity>
|
||||
<identity name="schema-format">
|
||||
<description>
|
||||
<text>Base identity for data model schema languages.</text>
|
||||
</description>
|
||||
</identity>
|
||||
<identity name="xsd">
|
||||
<base name="schema-format"/>
|
||||
<description>
|
||||
<text>W3C XML Schema Definition.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>W3C REC REC-xmlschema-1-20041028:
|
||||
XML Schema Part 1: Structures</text>
|
||||
</reference>
|
||||
</identity>
|
||||
<identity name="yang">
|
||||
<base name="schema-format"/>
|
||||
<description>
|
||||
<text>The YANG data modeling language for NETCONF.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6020: YANG - A Data Modeling Language for the
|
||||
Network Configuration Protocol (NETCONF)</text>
|
||||
</reference>
|
||||
</identity>
|
||||
<identity name="yin">
|
||||
<base name="schema-format"/>
|
||||
<description>
|
||||
<text>The YIN syntax for YANG.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6020: YANG - A Data Modeling Language for the
|
||||
Network Configuration Protocol (NETCONF)</text>
|
||||
</reference>
|
||||
</identity>
|
||||
<identity name="rng">
|
||||
<base name="schema-format"/>
|
||||
<description>
|
||||
<text>Regular Language for XML Next Generation (RELAX NG).</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>ISO/IEC 19757-2:2008: RELAX NG</text>
|
||||
</reference>
|
||||
</identity>
|
||||
<identity name="rnc">
|
||||
<base name="schema-format"/>
|
||||
<description>
|
||||
<text>Relax NG Compact Syntax</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>ISO/IEC 19757-2:2008: RELAX NG</text>
|
||||
</reference>
|
||||
</identity>
|
||||
<grouping name="common-counters">
|
||||
<description>
|
||||
<text>Counters that exist both per session, and also globally,
|
||||
accumulated from all sessions.</text>
|
||||
</description>
|
||||
<leaf name="in-rpcs">
|
||||
<type name="yang:zero-based-counter32"/>
|
||||
<description>
|
||||
<text>Number of correct <rpc> messages received.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="in-bad-rpcs">
|
||||
<type name="yang:zero-based-counter32"/>
|
||||
<description>
|
||||
<text>Number of messages received when an <rpc> message was expected,
|
||||
that were not correct <rpc> messages. This includes XML parse
|
||||
errors and errors on the rpc layer.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="out-rpc-errors">
|
||||
<type name="yang:zero-based-counter32"/>
|
||||
<description>
|
||||
<text>Number of <rpc-reply> messages sent that contained an
|
||||
<rpc-error> element.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="out-notifications">
|
||||
<type name="yang:zero-based-counter32"/>
|
||||
<description>
|
||||
<text>Number of <notification> messages sent.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
</grouping>
|
||||
<container name="netconf-state">
|
||||
<config value="false"/>
|
||||
<description>
|
||||
<text>The netconf-state container is the root of the monitoring
|
||||
data model.</text>
|
||||
</description>
|
||||
<container name="capabilities">
|
||||
<description>
|
||||
<text>Contains the list of NETCONF capabilities supported by the
|
||||
server.</text>
|
||||
</description>
|
||||
<leaf-list name="capability">
|
||||
<type name="inet:uri"/>
|
||||
<description>
|
||||
<text>List of NETCONF capabilities supported by the server.</text>
|
||||
</description>
|
||||
</leaf-list>
|
||||
</container>
|
||||
<container name="datastores">
|
||||
<description>
|
||||
<text>Contains the list of NETCONF configuration datastores.</text>
|
||||
</description>
|
||||
<list name="datastore">
|
||||
<key value="name"/>
|
||||
<description>
|
||||
<text>List of NETCONF configuration datastores supported by
|
||||
the NETCONF server and related information.</text>
|
||||
</description>
|
||||
<leaf name="name">
|
||||
<type name="netconf-datastore-type"/>
|
||||
<description>
|
||||
<text>Name of the datastore associated with this list entry.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<container name="locks">
|
||||
<presence value="This container is present only if the datastore is locked."/>
|
||||
<description>
|
||||
<text>The NETCONF <lock> and <partial-lock> operations allow
|
||||
a client to lock specific resources in a datastore. The
|
||||
NETCONF server will prevent changes to the locked
|
||||
resources by all sessions except the one that acquired
|
||||
the lock(s).
|
||||
|
||||
Monitoring information is provided for each datastore
|
||||
entry including details such as the session that acquired
|
||||
the lock, the type of lock (global or partial) and the
|
||||
list of locked resources. Multiple locks per datastore
|
||||
are supported.</text>
|
||||
</description>
|
||||
<grouping name="lock-info">
|
||||
<description>
|
||||
<text>Lock related parameters, common to both global and
|
||||
partial locks.</text>
|
||||
</description>
|
||||
<leaf name="locked-by-session">
|
||||
<type name="uint32"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>The session ID of the session that has locked
|
||||
this resource. Both a global lock and a partial
|
||||
lock MUST contain the NETCONF session-id.
|
||||
|
||||
If the lock is held by a session that is not managed
|
||||
by the NETCONF server (e.g., a CLI session), a session
|
||||
id of 0 (zero) is reported.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 4741: NETCONF Configuration Protocol</text>
|
||||
</reference>
|
||||
</leaf>
|
||||
<leaf name="locked-time">
|
||||
<type name="yang:date-and-time"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>The date and time of when the resource was
|
||||
locked.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
</grouping>
|
||||
<choice name="lock-type">
|
||||
<description>
|
||||
<text>Indicates if a global lock or a set of partial locks
|
||||
are set.</text>
|
||||
</description>
|
||||
<container name="global-lock">
|
||||
<description>
|
||||
<text>Present if the global lock is set.</text>
|
||||
</description>
|
||||
<uses name="lock-info"/>
|
||||
</container>
|
||||
<list name="partial-lock">
|
||||
<key value="lock-id"/>
|
||||
<description>
|
||||
<text>List of partial locks.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 5717: Partial Lock Remote Procedure Call (RPC) for
|
||||
NETCONF</text>
|
||||
</reference>
|
||||
<leaf name="lock-id">
|
||||
<type name="uint32"/>
|
||||
<description>
|
||||
<text>This is the lock id returned in the <partial-lock>
|
||||
response.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<uses name="lock-info"/>
|
||||
<leaf-list name="select">
|
||||
<type name="yang:xpath1.0"/>
|
||||
<min-elements value="1"/>
|
||||
<description>
|
||||
<text>The xpath expression that was used to request
|
||||
the lock. The select expression indicates the
|
||||
original intended scope of the lock.</text>
|
||||
</description>
|
||||
</leaf-list>
|
||||
<leaf-list name="locked-node">
|
||||
<type name="instance-identifier"/>
|
||||
<description>
|
||||
<text>The list of instance-identifiers (i.e., the
|
||||
locked nodes).
|
||||
|
||||
The scope of the partial lock is defined by the list
|
||||
of locked nodes.</text>
|
||||
</description>
|
||||
</leaf-list>
|
||||
</list>
|
||||
</choice>
|
||||
</container>
|
||||
</list>
|
||||
</container>
|
||||
<container name="schemas">
|
||||
<description>
|
||||
<text>Contains the list of data model schemas supported by the
|
||||
server.</text>
|
||||
</description>
|
||||
<list name="schema">
|
||||
<key value="identifier version format"/>
|
||||
<description>
|
||||
<text>List of data model schemas supported by the server.</text>
|
||||
</description>
|
||||
<leaf name="identifier">
|
||||
<type name="string"/>
|
||||
<description>
|
||||
<text>Identifier to uniquely reference the schema. The
|
||||
identifier is used in the <get-schema> operation and may
|
||||
be used for other purposes such as file retrieval.
|
||||
|
||||
For modeling languages that support or require a data
|
||||
model name (e.g., YANG module name) the identifier MUST
|
||||
match that name. For YANG data models, the identifier is
|
||||
the name of the module or submodule. In other cases, an
|
||||
identifier such as a filename MAY be used instead.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="version">
|
||||
<type name="string"/>
|
||||
<description>
|
||||
<text>Version of the schema supported. Multiple versions MAY be
|
||||
supported simultaneously by a NETCONF server. Each
|
||||
version MUST be reported individually in the schema list,
|
||||
i.e., with same identifier, possibly different location,
|
||||
but different version.
|
||||
|
||||
For YANG data models, version is the value of the most
|
||||
recent YANG 'revision' statement in the module or
|
||||
submodule, or the empty string if no 'revision' statement
|
||||
is present.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="format">
|
||||
<type name="identityref">
|
||||
<base name="schema-format"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>The data modeling language the schema is written
|
||||
in (currently xsd, yang, yin, rng, or rnc).
|
||||
For YANG data models, 'yang' format MUST be supported and
|
||||
'yin' format MAY also be provided.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="namespace">
|
||||
<type name="inet:uri"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>The XML namespace defined by the data model.
|
||||
|
||||
For YANG data models, this is the module's namespace.
|
||||
If the list entry describes a submodule, this field
|
||||
contains the namespace of the module to which the
|
||||
submodule belongs.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf-list name="location">
|
||||
<type name="union">
|
||||
<type name="enumeration">
|
||||
<enum name="NETCONF"/>
|
||||
</type>
|
||||
<type name="inet:uri"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>One or more locations from which the schema can be
|
||||
retrieved. This list SHOULD contain at least one
|
||||
entry per schema.
|
||||
|
||||
A schema entry may be located on a remote file system
|
||||
(e.g., reference to file system for ftp retrieval) or
|
||||
retrieved directly from a server supporting the
|
||||
<get-schema> operation (denoted by the value 'NETCONF').</text>
|
||||
</description>
|
||||
</leaf-list>
|
||||
</list>
|
||||
</container>
|
||||
<container name="sessions">
|
||||
<description>
|
||||
<text>The sessions container includes session-specific data for
|
||||
NETCONF management sessions. The session list MUST include
|
||||
all currently active NETCONF sessions.</text>
|
||||
</description>
|
||||
<list name="session">
|
||||
<key value="session-id"/>
|
||||
<description>
|
||||
<text>All NETCONF sessions managed by the NETCONF server
|
||||
MUST be reported in this list.</text>
|
||||
</description>
|
||||
<leaf name="session-id">
|
||||
<type name="uint32">
|
||||
<range value="1..max"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>Unique identifier for the session. This value is the
|
||||
NETCONF session identifier, as defined in RFC 4741.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 4741: NETCONF Configuration Protocol</text>
|
||||
</reference>
|
||||
</leaf>
|
||||
<leaf name="transport">
|
||||
<type name="identityref">
|
||||
<base name="transport"/>
|
||||
</type>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>Identifies the transport for each session, e.g.,
|
||||
'netconf-ssh', 'netconf-soap', etc.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="username">
|
||||
<type name="string"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>The username is the client identity that was authenticated
|
||||
by the NETCONF transport protocol. The algorithm used to
|
||||
derive the username is NETCONF transport protocol specific
|
||||
and in addition specific to the authentication mechanism
|
||||
used by the NETCONF transport protocol.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="source-host">
|
||||
<type name="inet:host"/>
|
||||
<description>
|
||||
<text>Host identifier of the NETCONF client. The value
|
||||
returned is implementation specific (e.g., hostname,
|
||||
IPv4 address, IPv6 address)</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="login-time">
|
||||
<type name="yang:date-and-time"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>Time at the server at which the session was established.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<uses name="common-counters">
|
||||
<description>
|
||||
<text>Per-session counters. Zero based with following reset
|
||||
behaviour:
|
||||
- at start of a session
|
||||
- when max value is reached</text>
|
||||
</description>
|
||||
</uses>
|
||||
</list>
|
||||
</container>
|
||||
<container name="statistics">
|
||||
<description>
|
||||
<text>Statistical data pertaining to the NETCONF server.</text>
|
||||
</description>
|
||||
<leaf name="netconf-start-time">
|
||||
<type name="yang:date-and-time"/>
|
||||
<description>
|
||||
<text>Date and time at which the management subsystem was
|
||||
started.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="in-bad-hellos">
|
||||
<type name="yang:zero-based-counter32"/>
|
||||
<description>
|
||||
<text>Number of sessions silently dropped because an
|
||||
invalid <hello> message was received. This includes <hello>
|
||||
messages with a 'session-id' attribute, bad namespace, and
|
||||
bad capability declarations.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="in-sessions">
|
||||
<type name="yang:zero-based-counter32"/>
|
||||
<description>
|
||||
<text>Number of sessions started. This counter is incremented
|
||||
when a <hello> message with a <session-id> is sent.
|
||||
|
||||
'in-sessions' - 'in-bad-hellos' =
|
||||
'number of correctly started netconf sessions'</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="dropped-sessions">
|
||||
<type name="yang:zero-based-counter32"/>
|
||||
<description>
|
||||
<text>Number of sessions that were abnormally terminated, e.g.,
|
||||
due to idle timeout or transport close. This counter is not
|
||||
incremented when a session is properly closed by a
|
||||
<close-session> operation, or killed by a <kill-session>
|
||||
operation.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<uses name="common-counters">
|
||||
<description>
|
||||
<text>Global counters, accumulated from all sessions.
|
||||
Zero based with following reset behaviour:
|
||||
- re-initialization of NETCONF server
|
||||
- when max value is reached</text>
|
||||
</description>
|
||||
</uses>
|
||||
</container>
|
||||
</container>
|
||||
<rpc name="get-schema">
|
||||
<description>
|
||||
<text>This operation is used to retrieve a schema from the
|
||||
NETCONF server.
|
||||
|
||||
Positive Response:
|
||||
The NETCONF server returns the requested schema.
|
||||
|
||||
Negative Response:
|
||||
If requested schema does not exist, the <error-tag> is
|
||||
'invalid-value'.
|
||||
|
||||
If more than one schema matches the requested parameters, the
|
||||
<error-tag> is 'operation-failed', and <error-app-tag> is
|
||||
'data-not-unique'.</text>
|
||||
</description>
|
||||
<input>
|
||||
<leaf name="identifier">
|
||||
<type name="string"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>Identifier for the schema list entry.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="version">
|
||||
<type name="string"/>
|
||||
<description>
|
||||
<text>Version of the schema requested. If this parameter is not
|
||||
present, and more than one version of the schema exists on
|
||||
the server, a 'data-not-unique' error is returned, as
|
||||
described above.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="format">
|
||||
<type name="identityref">
|
||||
<base name="schema-format"/>
|
||||
</type>
|
||||
<description>
|
||||
<text>The data modeling language of the schema. If this
|
||||
parameter is not present, and more than one formats of
|
||||
the schema exists on the server, a 'data-not-unique' error
|
||||
is returned, as described above.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
</input>
|
||||
<output>
|
||||
<anyxml name="data">
|
||||
<description>
|
||||
<text>Contains the schema content.</text>
|
||||
</description>
|
||||
</anyxml>
|
||||
</output>
|
||||
</rpc>
|
||||
</module>
|
353
tests/data/modules/ietf-netconf-notifications.yin
Normal file
353
tests/data/modules/ietf-netconf-notifications.yin
Normal file
|
@ -0,0 +1,353 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module name="ietf-netconf-notifications"
|
||||
xmlns="urn:ietf:params:xml:ns:yang:yin:1"
|
||||
xmlns:ncn="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications"
|
||||
xmlns:inet="urn:ietf:params:xml:ns:yang:ietf-inet-types"
|
||||
xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
|
||||
<namespace uri="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications"/>
|
||||
<prefix value="ncn"/>
|
||||
<import module="ietf-inet-types">
|
||||
<prefix value="inet"/>
|
||||
</import>
|
||||
<import module="ietf-netconf">
|
||||
<prefix value="nc"/>
|
||||
</import>
|
||||
<organization>
|
||||
<text>IETF NETCONF (Network Configuration Protocol) Working Group</text>
|
||||
</organization>
|
||||
<contact>
|
||||
<text>WG Web: <http://tools.ietf.org/wg/netconf/>
|
||||
WG List: <mailto:netconf@ietf.org>
|
||||
|
||||
WG Chair: Bert Wijnen
|
||||
<mailto:bertietf@bwijnen.net>
|
||||
|
||||
WG Chair: Mehmet Ersue
|
||||
<mailto:mehmet.ersue@nsn.com>
|
||||
|
||||
Editor: Andy Bierman
|
||||
<mailto:andy@netconfcentral.org></text>
|
||||
</contact>
|
||||
<description>
|
||||
<text>This module defines a YANG data model for use with the
|
||||
NETCONF protocol that allows the NETCONF client to
|
||||
receive common NETCONF base event notifications.
|
||||
|
||||
Copyright (c) 2012 IETF Trust and the persons identified as
|
||||
the document authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
|
||||
|
||||
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 6470; see
|
||||
the RFC itself for full legal notices.</text>
|
||||
</description>
|
||||
<revision date="2012-02-06">
|
||||
<description>
|
||||
<text>Initial version.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6470: NETCONF Base Notifications</text>
|
||||
</reference>
|
||||
</revision>
|
||||
<grouping name="common-session-parms">
|
||||
<description>
|
||||
<text>Common session parameters to identify a
|
||||
management session.</text>
|
||||
</description>
|
||||
<leaf name="username">
|
||||
<type name="string"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>Name of the user for the session.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="session-id">
|
||||
<type name="nc:session-id-or-zero-type"/>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>Identifier of the session.
|
||||
A NETCONF session MUST be identified by a non-zero value.
|
||||
A non-NETCONF session MAY be identified by the value zero.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="source-host">
|
||||
<type name="inet:ip-address"/>
|
||||
<description>
|
||||
<text>Address of the remote host for the session.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
</grouping>
|
||||
<grouping name="changed-by-parms">
|
||||
<description>
|
||||
<text>Common parameters to identify the source
|
||||
of a change event, such as a configuration
|
||||
or capability change.</text>
|
||||
</description>
|
||||
<container name="changed-by">
|
||||
<description>
|
||||
<text>Indicates the source of the change.
|
||||
If caused by internal action, then the
|
||||
empty leaf 'server' will be present.
|
||||
If caused by a management session, then
|
||||
the name, remote host address, and session ID
|
||||
of the session that made the change will be reported.</text>
|
||||
</description>
|
||||
<choice name="server-or-user">
|
||||
<mandatory value="true"/>
|
||||
<leaf name="server">
|
||||
<type name="empty"/>
|
||||
<description>
|
||||
<text>If present, the change was caused
|
||||
by the server.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<case name="by-user">
|
||||
<uses name="common-session-parms"/>
|
||||
</case>
|
||||
</choice>
|
||||
</container>
|
||||
</grouping>
|
||||
<notification name="netconf-config-change">
|
||||
<description>
|
||||
<text>Generated when the NETCONF server detects that the
|
||||
<running> or <startup> configuration datastore
|
||||
has been changed by a management session.
|
||||
The notification summarizes the edits that
|
||||
have been detected.
|
||||
|
||||
The server MAY choose to also generate this
|
||||
notification while loading a datastore during the
|
||||
boot process for the device.</text>
|
||||
</description>
|
||||
<uses name="changed-by-parms"/>
|
||||
<leaf name="datastore">
|
||||
<type name="enumeration">
|
||||
<enum name="running">
|
||||
<description>
|
||||
<text>The <running> datastore has changed.</text>
|
||||
</description>
|
||||
</enum>
|
||||
<enum name="startup">
|
||||
<description>
|
||||
<text>The <startup> datastore has changed</text>
|
||||
</description>
|
||||
</enum>
|
||||
</type>
|
||||
<default value="running"/>
|
||||
<description>
|
||||
<text>Indicates which configuration datastore has changed.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<list name="edit">
|
||||
<description>
|
||||
<text>An edit record SHOULD be present for each distinct
|
||||
edit operation that the server has detected on
|
||||
the target datastore. This list MAY be omitted
|
||||
if the detailed edit operations are not known.
|
||||
The server MAY report entries in this list for
|
||||
changes not made by a NETCONF session (e.g., CLI).</text>
|
||||
</description>
|
||||
<leaf name="target">
|
||||
<type name="instance-identifier"/>
|
||||
<description>
|
||||
<text>Topmost node associated with the configuration change.
|
||||
A server SHOULD set this object to the node within
|
||||
the datastore that is being altered. A server MAY
|
||||
set this object to one of the ancestors of the actual
|
||||
node that was changed, or omit this object, if the
|
||||
exact node is not known.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="operation">
|
||||
<type name="nc:edit-operation-type"/>
|
||||
<description>
|
||||
<text>Type of edit operation performed.
|
||||
A server MUST set this object to the NETCONF edit
|
||||
operation performed on the target datastore.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
</list>
|
||||
</notification>
|
||||
<notification name="netconf-capability-change">
|
||||
<description>
|
||||
<text>Generated when the NETCONF server detects that
|
||||
the server capabilities have changed.
|
||||
Indicates which capabilities have been added, deleted,
|
||||
and/or modified. The manner in which a server
|
||||
capability is changed is outside the scope of this
|
||||
document.</text>
|
||||
</description>
|
||||
<uses name="changed-by-parms"/>
|
||||
<leaf-list name="added-capability">
|
||||
<type name="inet:uri"/>
|
||||
<description>
|
||||
<text>List of capabilities that have just been added.</text>
|
||||
</description>
|
||||
</leaf-list>
|
||||
<leaf-list name="deleted-capability">
|
||||
<type name="inet:uri"/>
|
||||
<description>
|
||||
<text>List of capabilities that have just been deleted.</text>
|
||||
</description>
|
||||
</leaf-list>
|
||||
<leaf-list name="modified-capability">
|
||||
<type name="inet:uri"/>
|
||||
<description>
|
||||
<text>List of capabilities that have just been modified.
|
||||
A capability is considered to be modified if the
|
||||
base URI for the capability has not changed, but
|
||||
one or more of the parameters encoded at the end of
|
||||
the capability URI have changed.
|
||||
The new modified value of the complete URI is returned.</text>
|
||||
</description>
|
||||
</leaf-list>
|
||||
</notification>
|
||||
<notification name="netconf-session-start">
|
||||
<description>
|
||||
<text>Generated when a NETCONF server detects that a
|
||||
NETCONF session has started. A server MAY generate
|
||||
this event for non-NETCONF management sessions.
|
||||
Indicates the identity of the user that started
|
||||
the session.</text>
|
||||
</description>
|
||||
<uses name="common-session-parms"/>
|
||||
</notification>
|
||||
<notification name="netconf-session-end">
|
||||
<description>
|
||||
<text>Generated when a NETCONF server detects that a
|
||||
NETCONF session has terminated.
|
||||
A server MAY optionally generate this event for
|
||||
non-NETCONF management sessions. Indicates the
|
||||
identity of the user that owned the session,
|
||||
and why the session was terminated.</text>
|
||||
</description>
|
||||
<uses name="common-session-parms"/>
|
||||
<leaf name="killed-by">
|
||||
<when condition="../termination-reason = 'killed'"/>
|
||||
<type name="nc:session-id-type"/>
|
||||
<description>
|
||||
<text>The ID of the session that directly caused this session
|
||||
to be abnormally terminated. If this session was abnormally
|
||||
terminated by a non-NETCONF session unknown to the server,
|
||||
then this leaf will not be present.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="termination-reason">
|
||||
<type name="enumeration">
|
||||
<enum name="closed">
|
||||
<description>
|
||||
<text>The session was terminated by the client in normal
|
||||
fashion, e.g., by the NETCONF <close-session>
|
||||
protocol operation.</text>
|
||||
</description>
|
||||
</enum>
|
||||
<enum name="killed">
|
||||
<description>
|
||||
<text>The session was terminated in abnormal
|
||||
fashion, e.g., by the NETCONF <kill-session>
|
||||
protocol operation.</text>
|
||||
</description>
|
||||
</enum>
|
||||
<enum name="dropped">
|
||||
<description>
|
||||
<text>The session was terminated because the transport layer
|
||||
connection was unexpectedly closed.</text>
|
||||
</description>
|
||||
</enum>
|
||||
<enum name="timeout">
|
||||
<description>
|
||||
<text>The session was terminated because of inactivity,
|
||||
e.g., waiting for the <hello> message or <rpc>
|
||||
messages.</text>
|
||||
</description>
|
||||
</enum>
|
||||
<enum name="bad-hello">
|
||||
<description>
|
||||
<text>The client's <hello> message was invalid.</text>
|
||||
</description>
|
||||
</enum>
|
||||
<enum name="other">
|
||||
<description>
|
||||
<text>The session was terminated for some other reason.</text>
|
||||
</description>
|
||||
</enum>
|
||||
</type>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>Reason the session was terminated.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
</notification>
|
||||
<notification name="netconf-confirmed-commit">
|
||||
<description>
|
||||
<text>Generated when a NETCONF server detects that a
|
||||
confirmed-commit event has occurred. Indicates the event
|
||||
and the current state of the confirmed-commit procedure
|
||||
in progress.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6241, Section 8.4</text>
|
||||
</reference>
|
||||
<uses name="common-session-parms">
|
||||
<when condition="confirm-event != 'timeout'"/>
|
||||
</uses>
|
||||
<leaf name="confirm-event">
|
||||
<type name="enumeration">
|
||||
<enum name="start">
|
||||
<description>
|
||||
<text>The confirmed-commit procedure has started.</text>
|
||||
</description>
|
||||
</enum>
|
||||
<enum name="cancel">
|
||||
<description>
|
||||
<text>The confirmed-commit procedure has been canceled,
|
||||
e.g., due to the session being terminated, or an
|
||||
explicit <cancel-commit> operation.</text>
|
||||
</description>
|
||||
</enum>
|
||||
<enum name="timeout">
|
||||
<description>
|
||||
<text>The confirmed-commit procedure has been canceled
|
||||
due to the confirm-timeout interval expiring.
|
||||
The common session parameters will not be present
|
||||
in this sub-mode.</text>
|
||||
</description>
|
||||
</enum>
|
||||
<enum name="extend">
|
||||
<description>
|
||||
<text>The confirmed-commit timeout has been extended,
|
||||
e.g., by a new <confirmed-commit> operation.</text>
|
||||
</description>
|
||||
</enum>
|
||||
<enum name="complete">
|
||||
<description>
|
||||
<text>The confirmed-commit procedure has been completed.</text>
|
||||
</description>
|
||||
</enum>
|
||||
</type>
|
||||
<mandatory value="true"/>
|
||||
<description>
|
||||
<text>Indicates the event that caused the notification.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
<leaf name="timeout">
|
||||
<when condition="../confirm-event = 'start' or ../confirm-event = 'extend'"/>
|
||||
<type name="uint32"/>
|
||||
<units name="seconds"/>
|
||||
<description>
|
||||
<text>The configured timeout value if the event type
|
||||
is 'start' or 'extend'. This value represents
|
||||
the approximate number of seconds from the event
|
||||
time when the 'timeout' event might occur.</text>
|
||||
</description>
|
||||
</leaf>
|
||||
</notification>
|
||||
</module>
|
149
tests/data/modules/ietf-netconf-with-defaults.yin
Normal file
149
tests/data/modules/ietf-netconf-with-defaults.yin
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module name="ietf-netconf-with-defaults"
|
||||
xmlns="urn:ietf:params:xml:ns:yang:yin:1"
|
||||
xmlns:ncwd="urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults"
|
||||
xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
|
||||
<namespace uri="urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults"/>
|
||||
<prefix value="ncwd"/>
|
||||
<import module="ietf-netconf">
|
||||
<prefix value="nc"/>
|
||||
</import>
|
||||
<organization>
|
||||
<text>IETF NETCONF (Network Configuration Protocol) Working Group</text>
|
||||
</organization>
|
||||
<contact>
|
||||
<text>WG Web: <http://tools.ietf.org/wg/netconf/>
|
||||
|
||||
WG List: <netconf@ietf.org>
|
||||
|
||||
WG Chair: Bert Wijnen
|
||||
<bertietf@bwijnen.net>
|
||||
|
||||
WG Chair: Mehmet Ersue
|
||||
<mehmet.ersue@nsn.com>
|
||||
|
||||
Editor: Andy Bierman
|
||||
<andy.bierman@brocade.com>
|
||||
|
||||
Editor: Balazs Lengyel
|
||||
<balazs.lengyel@ericsson.com></text>
|
||||
</contact>
|
||||
<description>
|
||||
<text>This module defines an extension to the NETCONF protocol
|
||||
that allows the NETCONF client to control how default
|
||||
values are handled by the server in particular NETCONF
|
||||
operations.
|
||||
|
||||
Copyright (c) 2011 IETF Trust and the persons identified as
|
||||
the document authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 6243; see
|
||||
the RFC itself for full legal notices.</text>
|
||||
</description>
|
||||
<revision date="2011-06-01">
|
||||
<description>
|
||||
<text>Initial version.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6243: With-defaults Capability for NETCONF</text>
|
||||
</reference>
|
||||
</revision>
|
||||
<typedef name="with-defaults-mode">
|
||||
<description>
|
||||
<text>Possible modes to report default data.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6243; Section 3.</text>
|
||||
</reference>
|
||||
<type name="enumeration">
|
||||
<enum name="report-all">
|
||||
<description>
|
||||
<text>All default data is reported.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6243; Section 3.1</text>
|
||||
</reference>
|
||||
</enum>
|
||||
<enum name="report-all-tagged">
|
||||
<description>
|
||||
<text>All default data is reported.
|
||||
Any nodes considered to be default data
|
||||
will contain a 'default' XML attribute,
|
||||
set to 'true' or '1'.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6243; Section 3.4</text>
|
||||
</reference>
|
||||
</enum>
|
||||
<enum name="trim">
|
||||
<description>
|
||||
<text>Values are not reported if they contain the default.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6243; Section 3.2</text>
|
||||
</reference>
|
||||
</enum>
|
||||
<enum name="explicit">
|
||||
<description>
|
||||
<text>Report values that contain the definition of
|
||||
explicitly set data.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6243; Section 3.3</text>
|
||||
</reference>
|
||||
</enum>
|
||||
</type>
|
||||
</typedef>
|
||||
<grouping name="with-defaults-parameters">
|
||||
<description>
|
||||
<text>Contains the <with-defaults> parameter for control
|
||||
of defaults in NETCONF retrieval operations.</text>
|
||||
</description>
|
||||
<leaf name="with-defaults">
|
||||
<description>
|
||||
<text>The explicit defaults processing mode requested.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6243; Section 4.5.1</text>
|
||||
</reference>
|
||||
<type name="with-defaults-mode"/>
|
||||
</leaf>
|
||||
</grouping>
|
||||
<augment target-node="/nc:get-config/nc:input">
|
||||
<description>
|
||||
<text>Adds the <with-defaults> parameter to the
|
||||
input of the NETCONF <get-config> operation.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6243; Section 4.5.1</text>
|
||||
</reference>
|
||||
<uses name="with-defaults-parameters"/>
|
||||
</augment>
|
||||
<augment target-node="/nc:get/nc:input">
|
||||
<description>
|
||||
<text>Adds the <with-defaults> parameter to
|
||||
the input of the NETCONF <get> operation.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6243; Section 4.5.1</text>
|
||||
</reference>
|
||||
<uses name="with-defaults-parameters"/>
|
||||
</augment>
|
||||
<augment target-node="/nc:copy-config/nc:input">
|
||||
<description>
|
||||
<text>Adds the <with-defaults> parameter to
|
||||
the input of the NETCONF <copy-config> operation.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 6243; Section 4.5.1</text>
|
||||
</reference>
|
||||
<uses name="with-defaults-parameters"/>
|
||||
</augment>
|
||||
</module>
|
1032
tests/data/modules/ietf-netconf.yin
Normal file
1032
tests/data/modules/ietf-netconf.yin
Normal file
File diff suppressed because it is too large
Load diff
16
tests/data/modules/module-a-dv.yang
Normal file
16
tests/data/modules/module-a-dv.yang
Normal file
|
@ -0,0 +1,16 @@
|
|||
module module-a-dv {
|
||||
|
||||
namespace "urn:jmu:params:xml:ns:yang:module-a-dv";
|
||||
prefix dv;
|
||||
|
||||
import module-a {
|
||||
prefix a;
|
||||
}
|
||||
|
||||
description
|
||||
"Contains some deviations to module-a";
|
||||
|
||||
deviation "/a:top/a:hidden" {
|
||||
deviate not-supported;
|
||||
}
|
||||
}
|
21
tests/data/modules/module-a-dv2.yang
Normal file
21
tests/data/modules/module-a-dv2.yang
Normal file
|
@ -0,0 +1,21 @@
|
|||
module module-a-dv2 {
|
||||
|
||||
namespace "urn:jmu:params:xml:ns:yang:module-a-dv2";
|
||||
prefix dv2;
|
||||
|
||||
import module-a {
|
||||
prefix a;
|
||||
}
|
||||
|
||||
description
|
||||
"Contains some deviations to module-a";
|
||||
|
||||
deviation "/a:top/a:type" {
|
||||
deviate add {
|
||||
default "admin";
|
||||
must "count(.) = 1";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
23
tests/data/modules/module-a.yang
Normal file
23
tests/data/modules/module-a.yang
Normal file
|
@ -0,0 +1,23 @@
|
|||
module module-a {
|
||||
|
||||
namespace "urn:jmu:params:xml:ns:yang:module-a";
|
||||
prefix a;
|
||||
|
||||
description "This is a simple user module";
|
||||
|
||||
container top {
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
}
|
||||
|
||||
leaf type {
|
||||
type string;
|
||||
}
|
||||
|
||||
leaf hidden {
|
||||
type boolean;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
102
tests/data/modules/nc-notifications.yin
Normal file
102
tests/data/modules/nc-notifications.yin
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module name="nc-notifications"
|
||||
xmlns="urn:ietf:params:xml:ns:yang:yin:1"
|
||||
xmlns:manageEvent="urn:ietf:params:xml:ns:netmod:notification"
|
||||
xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types"
|
||||
xmlns:ncEvent="urn:ietf:params:xml:ns:netconf:notification:1.0">
|
||||
<namespace uri="urn:ietf:params:xml:ns:netmod:notification"/>
|
||||
<prefix value="manageEvent"/>
|
||||
<import module="ietf-yang-types">
|
||||
<prefix value="yang"/>
|
||||
</import>
|
||||
<import module="notifications">
|
||||
<prefix value="ncEvent"/>
|
||||
</import>
|
||||
<organization>
|
||||
<text>IETF NETCONF WG</text>
|
||||
</organization>
|
||||
<contact>
|
||||
<text>netconf@ietf.org</text>
|
||||
</contact>
|
||||
<description>
|
||||
<text>Conversion of the 'manageEvent' XSD in the NETCONF
|
||||
Notifications RFC.</text>
|
||||
</description>
|
||||
<reference>
|
||||
<text>RFC 5277</text>
|
||||
</reference>
|
||||
<revision date="2008-07-14">
|
||||
<description>
|
||||
<text>RFC 5277 version.</text>
|
||||
</description>
|
||||
</revision>
|
||||
<container name="netconf">
|
||||
<description>
|
||||
<text>Top-level element in the notification namespace</text>
|
||||
</description>
|
||||
<config value="false"/>
|
||||
<container name="streams">
|
||||
<description>
|
||||
<text>The list of event streams supported by the system. When
|
||||
a query is issued, the returned set of streams is
|
||||
determined based on user privileges.</text>
|
||||
</description>
|
||||
<list name="stream">
|
||||
<description>
|
||||
<text>Stream name, description and other information.</text>
|
||||
</description>
|
||||
<key value="name"/>
|
||||
<min-elements value="1"/>
|
||||
<leaf name="name">
|
||||
<description>
|
||||
<text>The name of the event stream. If this is the default
|
||||
NETCONF stream, this must have the value 'NETCONF'.</text>
|
||||
</description>
|
||||
<type name="ncEvent:streamNameType"/>
|
||||
</leaf>
|
||||
<leaf name="description">
|
||||
<description>
|
||||
<text>A description of the event stream, including such
|
||||
information as the type of events that are sent over
|
||||
this stream.</text>
|
||||
</description>
|
||||
<type name="string"/>
|
||||
<mandatory value="true"/>
|
||||
</leaf>
|
||||
<leaf name="replaySupport">
|
||||
<description>
|
||||
<text>A description of the event stream, including such
|
||||
information as the type of events that are sent over
|
||||
this stream.</text>
|
||||
</description>
|
||||
<type name="boolean"/>
|
||||
<mandatory value="true"/>
|
||||
</leaf>
|
||||
<leaf name="replayLogCreationTime">
|
||||
<description>
|
||||
<text>The timestamp of the creation of the log used to support
|
||||
the replay function on this stream. Note that this might
|
||||
be earlier then the earliest available notification in
|
||||
the log. This object is updated if the log resets for
|
||||
some reason. This object MUST be present if replay is
|
||||
supported.</text>
|
||||
</description>
|
||||
<type name="yang:date-and-time"/>
|
||||
</leaf>
|
||||
</list>
|
||||
</container>
|
||||
</container>
|
||||
<notification name="replayComplete">
|
||||
<description>
|
||||
<text>This notification is sent to signal the end of a replay
|
||||
portion of a subscription.</text>
|
||||
</description>
|
||||
</notification>
|
||||
<notification name="notificationComplete">
|
||||
<description>
|
||||
<text>This notification is sent to signal the end of a notification
|
||||
subscription. It is sent in the case that stopTime was
|
||||
specified during the creation of the subscription..</text>
|
||||
</description>
|
||||
</notification>
|
||||
</module>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue