Merging upstream version 3.5.5 (Closes: #1098233).
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
c86ae7dcba
commit
6af28b7e8e
144 changed files with 43534 additions and 11497 deletions
178
.github/workflows/ci.yml
vendored
178
.github/workflows/ci.yml
vendored
|
@ -10,12 +10,12 @@ on:
|
|||
- devel
|
||||
|
||||
env:
|
||||
DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev
|
||||
DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev libpam0g-dev libcurl4-openssl-dev
|
||||
|
||||
jobs:
|
||||
git-branch:
|
||||
name: Get git branch
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
branch-name: ${{ steps.get-git-branch.outputs.branch-name }}
|
||||
steps:
|
||||
|
@ -26,7 +26,7 @@ jobs:
|
|||
else
|
||||
export GIT_BRANCH=${{ github.base_ref }}
|
||||
fi
|
||||
echo "::set-output name=branch-name::$GIT_BRANCH"
|
||||
echo "branch-name=$GIT_BRANCH" >> $GITHUB_OUTPUT
|
||||
|
||||
build:
|
||||
name: ${{ matrix.config.name }}
|
||||
|
@ -37,96 +37,118 @@ jobs:
|
|||
matrix:
|
||||
config:
|
||||
- {
|
||||
name: "Release, Ubuntu 18.04, gcc",
|
||||
os: "ubuntu-18.04",
|
||||
name: "Release, gcc, OpenSSL",
|
||||
os: "ubuntu-22.04",
|
||||
build-type: "Release",
|
||||
dep-build-type: "Release",
|
||||
cc: "gcc",
|
||||
options: "-DENABLE_TESTS=ON -DENABLE_DNSSEC=ON",
|
||||
tls-lib: "OpenSSL",
|
||||
packages: "",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "Release, Ubuntu 18.04, clang",
|
||||
os: "ubuntu-18.04",
|
||||
name: "Release, gcc, MbedTLS",
|
||||
os: "ubuntu-22.04",
|
||||
build-type: "Release",
|
||||
dep-build-type: "Release",
|
||||
cc: "clang",
|
||||
cc: "gcc",
|
||||
options: "-DENABLE_TESTS=ON -DENABLE_DNSSEC=ON",
|
||||
tls-lib: "MbedTLS",
|
||||
packages: "",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "Debug, Ubuntu 18.04, gcc",
|
||||
os: "ubuntu-18.04",
|
||||
name: "Release, clang",
|
||||
os: "ubuntu-22.04",
|
||||
build-type: "Release",
|
||||
dep-build-type: "Release",
|
||||
cc: "clang",
|
||||
options: "-DENABLE_TESTS=ON -DENABLE_DNSSEC=ON",
|
||||
tls-lib: "OpenSSL",
|
||||
packages: "",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "Debug, gcc, OpenSSL",
|
||||
os: "ubuntu-22.04",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Release",
|
||||
cc: "gcc",
|
||||
options: "-DENABLE_DNSSEC=ON",
|
||||
tls-lib: "OpenSSL",
|
||||
packages: "valgrind",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "Debug, Ubuntu 18.04, clang",
|
||||
os: "ubuntu-18.04",
|
||||
name: "Debug, gcc, MbedTLS",
|
||||
os: "ubuntu-22.04",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Release",
|
||||
cc: "gcc",
|
||||
options: "-DENABLE_DNSSEC=ON",
|
||||
tls-lib: "MbedTLS",
|
||||
packages: "valgrind",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "Debug, clang",
|
||||
os: "ubuntu-22.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",
|
||||
tls-lib: "OpenSSL",
|
||||
# no valgrind because it does not support DWARF5 yet generated by clang 14
|
||||
packages: "",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "No SSH nor TLS",
|
||||
os: "ubuntu-18.04",
|
||||
os: "ubuntu-22.04",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Release",
|
||||
cc: "gcc",
|
||||
options: "-DENABLE_TLS=OFF -DENABLE_SSH=OFF",
|
||||
options: "-DENABLE_SSH_TLS=OFF",
|
||||
tls-lib: "",
|
||||
packages: "valgrind",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "ASAN and UBSAN",
|
||||
os: "ubuntu-18.04",
|
||||
name: "ASAN and UBSAN, OpenSSL",
|
||||
os: "ubuntu-22.04",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Release",
|
||||
cc: "clang",
|
||||
options: "-DCMAKE_C_FLAGS=-fsanitize=address,undefined -DENABLE_VALGRIND_TESTS=OFF",
|
||||
tls-lib: "OpenSSL",
|
||||
packages: "",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
- {
|
||||
name: "ASAN and UBSAN, MbedTLS",
|
||||
os: "ubuntu-22.04",
|
||||
build-type: "Debug",
|
||||
dep-build-type: "Release",
|
||||
cc: "clang",
|
||||
options: "-DCMAKE_C_FLAGS=-fsanitize=address,undefined -DENABLE_VALGRIND_TESTS=OFF",
|
||||
tls-lib: "MbedTLS",
|
||||
packages: "",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
|
@ -134,53 +156,85 @@ jobs:
|
|||
}
|
||||
- {
|
||||
name: "ABI Check",
|
||||
os: "ubuntu-latest",
|
||||
os: "ubuntu-22.04",
|
||||
build-type: "ABICheck",
|
||||
dep-build-type: "Debug",
|
||||
cc: "gcc",
|
||||
options: "",
|
||||
tls-lib: "OpenSSL",
|
||||
packages: "abi-dumper abi-compliance-checker snap",
|
||||
snaps: "core universal-ctags",
|
||||
make-prepend: "",
|
||||
make-target: "abi-check"
|
||||
}
|
||||
- {
|
||||
name: "DEB Package",
|
||||
os: "ubuntu-22.04",
|
||||
build-type: "Release",
|
||||
dep-build-type: "Release",
|
||||
cc: "gcc",
|
||||
options: "",
|
||||
tls-lib: "OpenSSL",
|
||||
packages: "cmake debhelper valgrind python3-pip",
|
||||
snaps: "",
|
||||
make-prepend: "",
|
||||
make-target: ""
|
||||
}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@main
|
||||
with:
|
||||
fetch-depth: 100
|
||||
|
||||
- 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
|
||||
if ${{ matrix.config.name == 'DEB Package' }}; then
|
||||
pip install apkg
|
||||
apkg system-setup
|
||||
fi
|
||||
|
||||
- name: Deps-uncrustify
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
git clone --branch uncrustify-0.71.0 https://github.com/uncrustify/uncrustify
|
||||
git clone --branch uncrustify-0.77.1 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' }}
|
||||
if: ${{ matrix.config.name == 'Debug, gcc, OpenSSL' || matrix.config.name == 'Debug, gcc, MbedTLS' }}
|
||||
|
||||
- name: Deps-libyang
|
||||
shell: bash
|
||||
run: |
|
||||
git clone -b ${{needs.git-branch.outputs.branch-name}} https://github.com/CESNET/libyang.git
|
||||
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
|
||||
if ${{ matrix.config.name == 'DEB Package' }}; then
|
||||
apkg build
|
||||
apkg install
|
||||
else
|
||||
mkdir build
|
||||
cd build
|
||||
CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.dep-build-type }} -DENABLE_TESTS=OFF ..
|
||||
make -j2
|
||||
sudo make install
|
||||
fi
|
||||
|
||||
- name: Build-and-install-package
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
apkg build
|
||||
apkg install
|
||||
if: ${{ matrix.config.name == 'DEB Package' }}
|
||||
|
||||
- name: Deps-libval
|
||||
shell: bash
|
||||
|
@ -190,6 +244,19 @@ jobs:
|
|||
./configure
|
||||
make -j2
|
||||
sudo make install
|
||||
if: ${{ matrix.config.name != 'DEB Package' }}
|
||||
|
||||
- name: Deps-MbedTLS
|
||||
shell: bash
|
||||
run: |
|
||||
git clone -b mbedtls-3.5.2 https://github.com/Mbed-TLS/mbedtls.git
|
||||
cd mbedtls
|
||||
mkdir build
|
||||
cd build
|
||||
CC=${{ matrix.config.cc }} cmake -DUSE_SHARED_MBEDTLS_LIBRARY=On -DENABLE_TESTING=Off ..
|
||||
make -j2
|
||||
sudo make install
|
||||
if: ${{ matrix.config.tls-lib == 'MbedTLS' }}
|
||||
|
||||
- name: Configure
|
||||
shell: bash
|
||||
|
@ -198,6 +265,7 @@ jobs:
|
|||
mkdir build
|
||||
cd build
|
||||
CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.build-type }} ${{ matrix.config.options }} ..
|
||||
if: ${{ matrix.config.name != 'DEB Package' }}
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
|
@ -206,8 +274,12 @@ jobs:
|
|||
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 }}
|
||||
if: ${{ matrix.config.name != 'DEB Package' }}
|
||||
|
||||
- name: Test
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/build
|
||||
run: ctest --output-on-failure
|
||||
run: |
|
||||
export LSAN_OPTIONS=suppressions=${{ github.workspace }}/tests/library_lsan.supp
|
||||
ctest -j4 --output-on-failure
|
||||
if: ${{ matrix.config.name != 'DEB Package' }}
|
||||
|
|
12
.github/workflows/devel-push.yml
vendored
12
.github/workflows/devel-push.yml
vendored
|
@ -5,13 +5,13 @@ on:
|
|||
- devel
|
||||
|
||||
env:
|
||||
DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev
|
||||
DEFAULT_PACKAGES: libcmocka-dev zlib1g-dev libssh-dev libssl-dev libpam0g-dev libcurl4-openssl-dev
|
||||
COVERITY_PROJECT: CESNET%2Flibnetconf2
|
||||
|
||||
jobs:
|
||||
git-branch:
|
||||
name: Get git branch
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
branch-name: ${{ steps.get-git-branch.outputs.branch-name }}
|
||||
steps:
|
||||
|
@ -22,7 +22,7 @@ jobs:
|
|||
else
|
||||
export GIT_BRANCH=${{ github.base_ref }}
|
||||
fi
|
||||
echo "::set-output name=branch-name::$GIT_BRANCH"
|
||||
echo "branch-name=$GIT_BRANCH" >> $GITHUB_OUTPUT
|
||||
|
||||
build:
|
||||
name: ${{ matrix.config.name }}
|
||||
|
@ -58,7 +58,7 @@ jobs:
|
|||
}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@main
|
||||
|
||||
- name: Deps-packages
|
||||
shell: bash
|
||||
|
@ -84,11 +84,11 @@ jobs:
|
|||
- name: Deps-libyang
|
||||
shell: bash
|
||||
run: |
|
||||
git clone -b ${{needs.git-branch.outputs.branch-name}} https://github.com/CESNET/libyang.git
|
||||
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 ..
|
||||
CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.dep-build-type }} -DENABLE_TESTS=OFF ..
|
||||
make -j2
|
||||
sudo make install
|
||||
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1,3 @@
|
|||
/pkg
|
||||
/build
|
||||
/doc/html
|
||||
|
|
19
.lgtm.yml
19
.lgtm.yml
|
@ -1,19 +0,0 @@
|
|||
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
|
250
CMakeLists.txt
250
CMakeLists.txt
|
@ -1,9 +1,9 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
cmake_minimum_required(VERSION 3.5...3.28.1)
|
||||
|
||||
project(libnetconf2 C)
|
||||
|
||||
# include custom Modules
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeModules/")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/")
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(CheckFunctionExists)
|
||||
|
@ -19,16 +19,6 @@ 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)
|
||||
|
@ -53,28 +43,40 @@ elseif("${BUILD_TYPE_UPPER}" STREQUAL "DOCONLY")
|
|||
set(CMAKE_BUILD_TYPE "DocOnly" CACHE STRING "Build Type" FORCE)
|
||||
endif()
|
||||
|
||||
#
|
||||
# variables
|
||||
#
|
||||
|
||||
set(LIBNETCONF2_DESCRIPTION "NETCONF server and client library in C.")
|
||||
|
||||
# osx specific
|
||||
set(CMAKE_MACOSX_RPATH TRUE)
|
||||
|
||||
# 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_MAJOR_VERSION 3)
|
||||
set(LIBNETCONF2_MINOR_VERSION 5)
|
||||
set(LIBNETCONF2_MICRO_VERSION 5)
|
||||
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
|
||||
# Major version is changed with every backward non-compatible API/ABI change in the library, 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_MAJOR_SOVERSION 4)
|
||||
set(LIBNETCONF2_MINOR_SOVERSION 4)
|
||||
set(LIBNETCONF2_MICRO_SOVERSION 5)
|
||||
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)
|
||||
# Version of libyang library that this project depends on
|
||||
set(LIBYANG_DEP_VERSION 2.0.0)
|
||||
set(LIBYANG_DEP_SOVERSION 3.0.0)
|
||||
set(LIBYANG_DEP_SOVERSION_MAJOR 3)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fvisibility=hidden -std=gnu99")
|
||||
# global C flags
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fvisibility=hidden -std=c99")
|
||||
|
||||
#
|
||||
# options
|
||||
|
@ -86,15 +88,18 @@ else()
|
|||
option(ENABLE_TESTS "Build tests" OFF)
|
||||
option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" OFF)
|
||||
endif()
|
||||
option(ENABLE_EXAMPLES "Build examples" ON)
|
||||
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_SSH_TLS "Enable NETCONF over SSH and TLS support (via libssh and OpenSSL)" ON)
|
||||
option(ENABLE_DNSSEC "Enable support for SSHFP retrieval using DNSSEC for SSH (requires OpenSSL and libval)" OFF)
|
||||
option(ENABLE_COMMON_TARGETS "Define common custom target names such as 'doc' or 'uninstall', may cause conflicts when using add_subdirectory() to build this project" ON)
|
||||
option(BUILD_SHARED_LIBS "By default, shared libs are enabled. Turn off for a static build." ON)
|
||||
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")
|
||||
set(YANG_MODULE_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/yang/modules/libnetconf2" CACHE STRING "Directory where to copy the YANG modules to")
|
||||
set(CLIENT_SEARCH_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/yang/modules" CACHE STRING "Default NC client YANG module search directory")
|
||||
|
||||
#
|
||||
# sources
|
||||
|
@ -106,20 +111,21 @@ set(libsrc
|
|||
src/messages_server.c
|
||||
src/session.c
|
||||
src/session_client.c
|
||||
src/session_server.c)
|
||||
src/session_server.c
|
||||
src/server_config.c
|
||||
src/server_config_util.c)
|
||||
|
||||
if(ENABLE_SSH)
|
||||
if(ENABLE_SSH_TLS)
|
||||
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_server_ssh.c
|
||||
src/server_config_util_ssh.c
|
||||
src/session_client_tls.c
|
||||
src/session_server_tls.c)
|
||||
set(TLS_MACRO "#ifndef NC_ENABLED_TLS\n#define NC_ENABLED_TLS\n#endif")
|
||||
src/session_server_tls.c
|
||||
src/server_config_util_tls.c
|
||||
src/server_config_ks.c
|
||||
src/server_config_ts.c)
|
||||
set(SSH_TLS_MACRO "#ifndef NC_ENABLED_SSH_TLS\n#define NC_ENABLED_SSH_TLS\n#endif")
|
||||
endif()
|
||||
|
||||
set(headers
|
||||
|
@ -131,11 +137,12 @@ set(headers
|
|||
src/session_client.h
|
||||
src/session_client_ch.h
|
||||
src/session_server.h
|
||||
src/session_server_ch.h)
|
||||
src/session_server_ch.h
|
||||
src/server_config.h)
|
||||
|
||||
# files to generate doxygen from
|
||||
set(doxy_files
|
||||
src/libnetconf.h
|
||||
doc/libnetconf.doc
|
||||
src/log.h
|
||||
src/netconf.h
|
||||
src/session.h
|
||||
|
@ -144,21 +151,23 @@ set(doxy_files
|
|||
src/session_client.h
|
||||
src/session_client_ch.h
|
||||
src/session_server.h
|
||||
src/session_server_ch.h)
|
||||
src/session_server_ch.h
|
||||
src/server_config.h)
|
||||
|
||||
# source files to be covered by the 'format' target
|
||||
set(format_sources
|
||||
compat/*.c
|
||||
compat/*.h*
|
||||
examples/*.c
|
||||
examples/*.h*
|
||||
src/*.c
|
||||
src/*.h
|
||||
tests/*.c
|
||||
tests/client/*.c)
|
||||
tests/*.c)
|
||||
|
||||
#
|
||||
# checks
|
||||
#
|
||||
if(ENABLE_DNSSEC AND NOT ENABLE_SSH)
|
||||
if(ENABLE_DNSSEC AND NOT ENABLE_SSH_TLS)
|
||||
message(WARNING "DNSSEC SSHFP retrieval cannot be used without SSH support.")
|
||||
set(ENABLE_DNSSEC OFF)
|
||||
endif()
|
||||
|
@ -186,7 +195,7 @@ if(ENABLE_COVERAGE)
|
|||
endif()
|
||||
|
||||
if ("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG")
|
||||
source_format_enable()
|
||||
source_format_enable(0.77)
|
||||
endif()
|
||||
|
||||
if("${BUILD_TYPE_UPPER}" STREQUAL "DOCONLY")
|
||||
|
@ -201,12 +210,15 @@ endif()
|
|||
# use compat
|
||||
use_compat()
|
||||
|
||||
# netconf2 target
|
||||
add_library(netconf2 SHARED ${libsrc} ${compatsrc})
|
||||
# netconf2 sourceless target - need it for linking libs, but the required sources will be added later
|
||||
add_library(netconf2)
|
||||
|
||||
# set the shared library version
|
||||
set_target_properties(netconf2 PROPERTIES VERSION ${LIBNETCONF2_SOVERSION_FULL} SOVERSION ${LIBNETCONF2_SOVERSION})
|
||||
|
||||
# include repository files with highest priority
|
||||
include_directories(${PROJECT_BINARY_DIR}/src)
|
||||
include_directories(${PROJECT_BINARY_DIR}/include)
|
||||
|
||||
# dependencies - pthread
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
|
@ -217,41 +229,75 @@ target_link_libraries(netconf2 ${CMAKE_THREAD_LIBS_INIT})
|
|||
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")
|
||||
# header file compatibility
|
||||
check_include_file("shadow.h" HAVE_SHADOW)
|
||||
check_include_file("termios.h" HAVE_TERMIOS)
|
||||
|
||||
if(ENABLE_SSH_TLS)
|
||||
# dependencies - mbedTLS (higher preference) or OpenSSL
|
||||
find_package(MbedTLS 3.5.0)
|
||||
if (MBEDTLS_FOUND)
|
||||
# dependencies - mbedtls
|
||||
set(HAVE_MBEDTLS TRUE)
|
||||
list(APPEND libsrc src/session_mbedtls.c)
|
||||
include_directories(${MBEDTLS_INCLUDE_DIRS})
|
||||
target_link_libraries(netconf2 ${MBEDTLS_LIBRARIES})
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES ${MBEDTLS_LIBRARIES})
|
||||
else()
|
||||
# dependencies - openssl
|
||||
find_package(OpenSSL 3.0.0 REQUIRED)
|
||||
list(APPEND libsrc src/session_openssl.c)
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
target_link_libraries(netconf2 ${OPENSSL_LIBRARIES})
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# dependencies - libssh
|
||||
find_package(LibSSH 0.9.5 REQUIRED)
|
||||
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)
|
||||
# dependencies - libcurl
|
||||
find_package(CURL 7.30.0 REQUIRED)
|
||||
if(TARGET CURL::libcurl)
|
||||
target_link_libraries(netconf2 CURL::libcurl)
|
||||
else()
|
||||
target_link_libraries(netconf2 -llogin)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES login)
|
||||
target_link_libraries(netconf2 ${CURL_LIBRARIES})
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES ${CURL_LIBRARY})
|
||||
include_directories(${CURL_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
# crypt (if not found, assume no library needs to be linked)
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "QNX")
|
||||
set(LIBCRYPT login)
|
||||
else()
|
||||
set(LIBCRYPT crypt)
|
||||
endif()
|
||||
check_library_exists(${LIBCRYPT} crypt "" HAVE_CRYPT)
|
||||
if(HAVE_CRYPT)
|
||||
target_link_libraries(netconf2 ${LIBCRYPT})
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBCRYPT})
|
||||
endif()
|
||||
|
||||
# libpam
|
||||
find_package(LibPAM)
|
||||
if(LibPAM_FOUND)
|
||||
set(HAVE_LIBPAM TRUE)
|
||||
|
||||
target_link_libraries(netconf2 ${LIBPAM_LIBRARIES})
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBPAM_LIBRARIES})
|
||||
include_directories(${LIBPAM_INCLUDE_DIRS})
|
||||
|
||||
message(STATUS "SSH Keyboard Interactive system method: Linux PAM")
|
||||
elseif(HAVE_SHADOW)
|
||||
message(STATUS "SSH Keyboard Interactive system method: local users")
|
||||
else()
|
||||
message(WARNING "SSH Keyboard Interactive system method: disabled")
|
||||
endif()
|
||||
|
||||
# set compiler flag
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_ENABLED_SSH_TLS")
|
||||
endif()
|
||||
|
||||
# dependencies - libval
|
||||
|
@ -263,14 +309,10 @@ if(ENABLE_DNSSEC)
|
|||
endif()
|
||||
|
||||
# dependencies - libyang
|
||||
find_package(LibYANG ${LIBYANG_DEP_SOVERSION_MAJOR} REQUIRED)
|
||||
find_package(LibYANG ${LIBYANG_DEP_SOVERSION} 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)
|
||||
|
@ -281,24 +323,35 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "QNX")
|
|||
list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_QNX_SOURCE)
|
||||
endif()
|
||||
|
||||
# generate files
|
||||
# set sources
|
||||
target_sources(netconf2 PRIVATE ${libsrc} ${compatsrc})
|
||||
|
||||
# generate config file
|
||||
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)
|
||||
|
||||
# generate and copy public header files
|
||||
configure_file("${PROJECT_SOURCE_DIR}/nc_client.h.in" "${PROJECT_BINARY_DIR}/include/nc_client.h")
|
||||
configure_file("${PROJECT_SOURCE_DIR}/nc_server.h.in" "${PROJECT_BINARY_DIR}/include/nc_server.h")
|
||||
configure_file("${PROJECT_SOURCE_DIR}/nc_version.h.in" "${PROJECT_BINARY_DIR}/include/nc_version.h")
|
||||
file(COPY ${headers} DESTINATION "${PROJECT_BINARY_DIR}/include/libnetconf2")
|
||||
|
||||
# install YANG modules
|
||||
install(DIRECTORY "${PROJECT_SOURCE_DIR}/modules/" DESTINATION ${YANG_MODULE_DIR} FILES_MATCHING PATTERN "*.yang")
|
||||
|
||||
# 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(FILES ${PROJECT_BINARY_DIR}/include/nc_client.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(FILES ${PROJECT_BINARY_DIR}/include/nc_server.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(FILES ${PROJECT_BINARY_DIR}/include/nc_version.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(DIRECTORY ${PROJECT_BINARY_DIR}/include/libnetconf2 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
# 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")
|
||||
install(FILES "${PROJECT_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)
|
||||
|
@ -310,6 +363,15 @@ if(PKG_CONFIG_FOUND)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
# examples
|
||||
if(ENABLE_EXAMPLES)
|
||||
if(NOT ENABLE_SSH_TLS)
|
||||
message(WARNING "Examples will not be compiled because SSH and TLS are disabled.")
|
||||
else()
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# tests
|
||||
if(ENABLE_TESTS)
|
||||
enable_testing()
|
||||
|
@ -320,22 +382,28 @@ endif()
|
|||
gen_coverage("test_.*" "test_.*_valgrind")
|
||||
|
||||
# generate doxygen documentation for libnetconf2 API
|
||||
gen_doc("${doxy_files}" ${LIBNETCONF2_VERSION} ${LIBNETCONF2_DESCRIPTION} "")
|
||||
if(ENABLE_COMMON_TARGETS)
|
||||
gen_doc("${doxy_files}" ${LIBNETCONF2_VERSION} ${LIBNETCONF2_DESCRIPTION} "")
|
||||
endif()
|
||||
|
||||
# generate API/ABI report
|
||||
if ("${BUILD_TYPE_UPPER}" STREQUAL "ABICHECK")
|
||||
lib_abi_check(netconf2 "${headers}" ${LIBNETCONF2_SOVERSION_FULL} e7402149e5b36de7acab2e38970a3a9d6a8165d5)
|
||||
lib_abi_check(netconf2 "${headers}" ${LIBNETCONF2_SOVERSION_FULL} 15fbc59efa5e6f1f7bea19ab561d03f8852caabb)
|
||||
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})
|
||||
if(ENABLE_COMMON_TARGETS)
|
||||
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})
|
||||
endif()
|
||||
|
||||
# uninstall
|
||||
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_MODULE_PATH}/uninstall.cmake")
|
||||
if(ENABLE_COMMON_TARGETS)
|
||||
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_MODULE_PATH}/uninstall.cmake")
|
||||
endif()
|
||||
|
|
86
CMakeModules/FindLibPAM.cmake
Normal file
86
CMakeModules/FindLibPAM.cmake
Normal file
|
@ -0,0 +1,86 @@
|
|||
# - Try to find LibPAM
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBPAM_FOUND - system has LibPAM
|
||||
# LIBPAM_INCLUDE_DIRS - the LibPAM include directory
|
||||
# LIBPAM_LIBRARIES - link these to use LibPAM
|
||||
#
|
||||
# Author Roman Janota <xjanot04@fit.vutbr.cz>
|
||||
# Copyright (c) 2022 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(LIBPAM_LIBRARIES AND LIBPAM_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(LIBPAM_FOUND TRUE)
|
||||
else()
|
||||
|
||||
find_path(LIBPAM_INCLUDE_DIR
|
||||
NAMES
|
||||
security/pam_appl.h
|
||||
security/pam_modules.h
|
||||
PATHS
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
${CMAKE_INCLUDE_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
)
|
||||
|
||||
find_library(LIBPAM_LIBRARY
|
||||
NAMES
|
||||
pam
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
if(LIBPAM_INCLUDE_DIR AND LIBPAM_LIBRARY)
|
||||
set(LIBPAM_FOUND TRUE)
|
||||
|
||||
# check if the function pam_start_confdir is in pam_appl.h header (added in PAM 1.4)
|
||||
file(STRINGS ${LIBPAM_INCLUDE_DIR}/security/pam_appl.h PAM_CONFDIR REGEX "pam_start_confdir")
|
||||
if ("${PAM_CONFDIR}" STREQUAL "")
|
||||
set(LIBPAM_HAVE_CONFDIR FALSE)
|
||||
else()
|
||||
set(LIBPAM_HAVE_CONFDIR TRUE)
|
||||
endif()
|
||||
else()
|
||||
set(LIBPAM_FOUND FALSE)
|
||||
endif()
|
||||
|
||||
set(LIBPAM_INCLUDE_DIRS ${LIBPAM_INCLUDE_DIR})
|
||||
set(LIBPAM_LIBRARIES ${LIBPAM_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LibPAM DEFAULT_MSG LIBPAM_LIBRARIES LIBPAM_INCLUDE_DIRS)
|
||||
|
||||
# show the LIBPAM_INCLUDE_DIRS and LIBPAM_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(LIBPAM_INCLUDE_DIRS LIBPAM_LIBRARIES)
|
||||
|
||||
endif()
|
110
CMakeModules/FindMbedTLS.cmake
Normal file
110
CMakeModules/FindMbedTLS.cmake
Normal file
|
@ -0,0 +1,110 @@
|
|||
# - Try to find MbedTLS
|
||||
# Once done this will define
|
||||
#
|
||||
# MBEDTLS_FOUND - MbedTLS was found
|
||||
# MBEDTLS_INCLUDE_DIRS - MbedTLS include directories
|
||||
# MBEDTLS_LIBRARIES - link these to use MbedTLS
|
||||
# MBEDTLS_VERSION - version of MbedTLS
|
||||
#
|
||||
# Author Roman Janota <janota@cesnet.cz>
|
||||
# Copyright (c) 2024 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(MBEDTLS_LIBRARIES AND MBEDTLS_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(MBEDTLS_FOUND TRUE)
|
||||
else()
|
||||
find_path(MBEDTLS_INCLUDE_DIR
|
||||
NAMES
|
||||
mbedtls/ssl.h
|
||||
PATHS
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
${CMAKE_INCLUDE_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
)
|
||||
|
||||
find_library(MBEDTLS_LIBRARY
|
||||
NAMES
|
||||
libmbedtls.so
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
find_library(MBEDX509_LIBRARY
|
||||
NAMES
|
||||
libmbedx509.so
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
find_library(MBEDCRYPTO_LIBRARY
|
||||
NAMES
|
||||
libmbedcrypto.so
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
if(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARY AND MBEDX509_LIBRARY AND MBEDCRYPTO_LIBRARY)
|
||||
# learn MbedTLS version
|
||||
if(EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")
|
||||
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h" MBEDTLS_VERSION
|
||||
REGEX "#define[ \t]+MBEDTLS_VERSION_STRING[ \t]+\"([0-9]+\.[0-9]+\.[0-9]+)\"")
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" MBEDTLS_VERSION ${MBEDTLS_VERSION})
|
||||
endif()
|
||||
if(NOT MBEDTLS_VERSION)
|
||||
message(STATUS "MBEDTLS_VERSION not found, assuming MbedTLS is too old and cannot be used!")
|
||||
set(MBEDTLS_INCLUDE_DIR "MBEDTLS_INCLUDE_DIR-NOTFOUND")
|
||||
set(MBEDTLS_LIBRARY "MBEDTLS_LIBRARY-NOTFOUND")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(MBEDTLS_INCLUDE_DIRS ${MBEDTLS_INCLUDE_DIR})
|
||||
set(MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY})
|
||||
|
||||
find_package_handle_standard_args(MbedTLS FOUND_VAR MBEDTLS_FOUND
|
||||
REQUIRED_VARS MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARIES
|
||||
VERSION_VAR MBEDTLS_VERSION)
|
||||
|
||||
# show the MBEDTLS_INCLUDE_DIR and MBEDTLS_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARIES)
|
||||
endif()
|
|
@ -2,7 +2,11 @@
|
|||
|
||||
# check that format checking is available - always use before SOURCE_FORMAT
|
||||
macro(SOURCE_FORMAT_ENABLE)
|
||||
find_package(Uncrustify 0.71)
|
||||
if(NOT ${ARGC} EQUAL 1)
|
||||
message(FATAL_ERROR "source_format_enable() needs the required Uncrustify version!")
|
||||
endif()
|
||||
|
||||
find_package(Uncrustify ${ARGV0})
|
||||
if(UNCRUSTIFY_FOUND)
|
||||
set(SOURCE_FORMAT_ENABLED TRUE)
|
||||
else()
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# 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.
|
||||
# Copyright (c) 2021 - 2023 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.
|
||||
|
@ -15,7 +15,6 @@
|
|||
# https://opensource.org/licenses/BSD-3-Clause
|
||||
#
|
||||
include(CheckSymbolExists)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFile)
|
||||
include(TestBigEndian)
|
||||
if(POLICY CMP0075)
|
||||
|
@ -24,10 +23,35 @@ endif()
|
|||
|
||||
macro(USE_COMPAT)
|
||||
# compatibility checks
|
||||
set(CMAKE_REQUIRED_DEFINITIONS -D_POSIX_C_SOURCE=200809L)
|
||||
list(APPEND 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(_POSIX_TIMERS "unistd.h" HAVE_CLOCK)
|
||||
if(NOT HAVE_CLOCK)
|
||||
message(FATAL_ERROR "Missing support for clock_gettime() and similar functions!")
|
||||
endif()
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
find_package(Threads)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
check_symbol_exists(pthread_mutex_timedlock "pthread.h" HAVE_PTHREAD_MUTEX_TIMEDLOCK)
|
||||
check_symbol_exists(pthread_mutex_clocklock "pthread.h" HAVE_PTHREAD_MUTEX_CLOCKLOCK)
|
||||
check_symbol_exists(pthread_rwlock_timedrdlock "pthread.h" HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK)
|
||||
check_symbol_exists(pthread_rwlock_clockrdlock "pthread.h" HAVE_PTHREAD_RWLOCK_CLOCKRDLOCK)
|
||||
check_symbol_exists(pthread_rwlock_timedwrlock "pthread.h" HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK)
|
||||
check_symbol_exists(pthread_rwlock_clockwrlock "pthread.h" HAVE_PTHREAD_RWLOCK_CLOCKWRLOCK)
|
||||
check_symbol_exists(pthread_cond_clockwait "pthread.h" HAVE_PTHREAD_COND_CLOCKWAIT)
|
||||
if(HAVE_PTHREAD_MUTEX_CLOCKLOCK)
|
||||
# can use CLOCK_MONOTONIC only if we have pthread_mutex_clocklock()
|
||||
check_symbol_exists(_POSIX_MONOTONIC_CLOCK "unistd.h" HAVE_CLOCK_MONOTONIC)
|
||||
endif()
|
||||
if(HAVE_CLOCK_MONOTONIC)
|
||||
set(COMPAT_CLOCK_ID "CLOCK_MONOTONIC")
|
||||
else()
|
||||
set(COMPAT_CLOCK_ID "CLOCK_REALTIME")
|
||||
endif()
|
||||
|
||||
check_symbol_exists(vdprintf "stdio.h;stdarg.h" HAVE_VDPRINTF)
|
||||
check_symbol_exists(asprintf "stdio.h" HAVE_ASPRINTF)
|
||||
|
@ -41,14 +65,26 @@ macro(USE_COMPAT)
|
|||
|
||||
check_symbol_exists(get_current_dir_name "unistd.h" HAVE_GET_CURRENT_DIR_NAME)
|
||||
|
||||
check_function_exists(pthread_mutex_timedlock HAVE_PTHREAD_MUTEX_TIMEDLOCK)
|
||||
check_function_exists(timegm HAVE_TIMEGM)
|
||||
|
||||
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
|
||||
# crypt
|
||||
check_include_file("crypt.h" HAVE_CRYPT_H)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "QNX")
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES -llogin)
|
||||
elseif(NOT APPLE)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES -lcrypt)
|
||||
endif()
|
||||
check_symbol_exists(crypt_r "crypt.h" HAVE_CRYPT_R)
|
||||
|
||||
test_big_endian(IS_BIG_ENDIAN)
|
||||
|
||||
check_include_file("stdatomic.h" HAVE_STDATOMIC)
|
||||
|
||||
unset(CMAKE_REQUIRED_DEFINITIONS)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_POSIX_C_SOURCE=200809L)
|
||||
list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
|
||||
list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D__BSD_VISIBLE=1)
|
||||
list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
# 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)
|
||||
|
|
|
@ -561,7 +561,7 @@ INLINE_INFO = YES
|
|||
# name. If set to NO, the members will appear in declaration order.
|
||||
# The default value is: YES.
|
||||
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_MEMBER_DOCS = NO
|
||||
|
||||
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
|
||||
# descriptions of file, namespace and class members alphabetically by member
|
||||
|
@ -2069,7 +2069,7 @@ INCLUDE_FILE_PATTERNS =
|
|||
# recursively expanded use the := operator instead of the = operator.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
PREDEFINED = NC_ENABLED_SSH NC_ENABLED_TLS
|
||||
PREDEFINED = NC_ENABLED_SSH_TLS
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||
# tag can be used to specify a list of macro names that should be expanded. The
|
||||
|
@ -2184,7 +2184,7 @@ HIDE_UNDOC_RELATIONS = YES
|
|||
# set to NO
|
||||
# The default value is: NO.
|
||||
|
||||
HAVE_DOT = @HAVE_DOT@
|
||||
HAVE_DOT = YES
|
||||
|
||||
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
|
||||
# to run in parallel. When set to 0 doxygen will base this on the number of
|
||||
|
|
45
FAQ.md
45
FAQ.md
|
@ -7,7 +7,7 @@ __Q: Having a fresh installation of *netopeer2-server*, when I connect to it I s
|
|||
|
||||
__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
|
||||
during *netopeer2-server* installation. To fix, disable support 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:__
|
||||
|
@ -17,8 +17,9 @@ 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)`).
|
||||
your system. The supported algorithms can be configured but if not, they
|
||||
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:__
|
||||
|
||||
|
@ -36,3 +37,41 @@ __A:__ There are 2 most common reasons for this error. Either you are not using
|
|||
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.
|
||||
|
||||
__Q: When I try to enter authentication tokens, they always echo back even though I set echo off:__
|
||||
|
||||
__A:__ You are most likely using an older version of *libssh* which contains a bug.
|
||||
The bug was fixed in *libssh* 0.9.0, so you must use at least that version.
|
||||
|
||||
__Q: When connecting over SSH and using publickey authentication, can I use a certificate:__
|
||||
|
||||
__A:__ No, it is not possible. There are currently 2 main types of certificates - *X.509v3* and *OpenSSH*.
|
||||
*X.509v3* certificates for Secure Shell Authentication are a part of *NETCONF* specification
|
||||
according to [RFC 6187](https://datatracker.ietf.org/doc/html/rfc6187), however using them
|
||||
is currently not supported by *libssh* (version 0.9.6 as of writing this), which *libnetconf2* depends on.
|
||||
As per the RFC mentioned before there are currently these `publickey` algorithms for *X.509v3*
|
||||
supported by *NETCONF*: `x509v3-ssh-dss`, `x509v3-ssh-rsa`, `x509v3-rsa2048-sha256` and the family of
|
||||
Elliptic Curve Digital Signature Algorithms `x509v3-ecdsa-sha2-*`. *libssh* 0.9.6 supports
|
||||
these certificate publickey algorithms: `ssh-ed25519-cert-v01@openssh.com`,
|
||||
`ecdsa-sha2-nistp521-cert-v01@openssh.com`, `ecdsa-sha2-nistp384-cert-v01@openssh.com`,
|
||||
`ecdsa-sha2-nistp256-cert-v01@openssh.com`, `rsa-sha2-512-cert-v01@openssh.com`,
|
||||
`rsa-sha2-256-cert-v01@openssh.com`, `ssh-rsa-cert-v01@openssh.com` and `ssh-dss-cert-v01@openssh.com`.
|
||||
|
||||
|
||||
On the other hand there is a basic support for *OpenSSH* certificates in *libssh*.
|
||||
The problem is that they are very minimalistic compared to *X.509v3* certificates
|
||||
as per this [document](https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD).
|
||||
So when `publickey` authentication happens only the client's `publickey`,
|
||||
which is extracted from the certificate, is sent to the server instead of the whole certificate.
|
||||
This means that the `cert-to-name` process required by *NETCONF* can not take place. Specifically,
|
||||
OpenSSH certificates are missing important fields such as `Common Name`, `Subject Alternative Name` and so on.
|
||||
|
||||
__Q: I have client-side keepalives and monitoring enabled, but it takes a long time for the client to detect that the connection was terminated:__
|
||||
__A:__ Assuming that the network connection is fine or is loopback, then this is the standard TCP behavior.
|
||||
The client will not immediately detect that the connection was terminated unless
|
||||
it tries to send some data or unless a specific timeout occurs.
|
||||
|
||||
Even though the server was terminated, its socket remains in a lingering state for some time and continues to reply to incoming
|
||||
TCP keepalive packets. In particular, this timeout you're encountering is most likely affected by the `tcp_fin_timeout` kernel parameter,
|
||||
which controls how long the TCP stack waits before timing out a half-closed connection after receiving a FIN packet.
|
||||
The default value is typically 60 seconds, but it can be configured based on your needs.
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
# LIBNETCONF2_FOUND - system has LibNETCONF2
|
||||
# LIBNETCONF2_INCLUDE_DIRS - the LibNETCONF2 include directory
|
||||
# LIBNETCONF2_LIBRARIES - Link these to use LibNETCONF2
|
||||
# LIBNETCONF2_VERSION - SO version of the found libNETCONF2 library
|
||||
# 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.
|
||||
# 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
|
||||
|
@ -34,7 +35,6 @@
|
|||
# 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
|
||||
|
@ -68,13 +68,28 @@ else()
|
|||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
if(LIBNETCONF2_INCLUDE_DIR)
|
||||
find_path(NC_VERSION_PATH "nc_version.h" HINTS ${LIBNETCONF2_INCLUDE_DIR})
|
||||
if(NOT NC_VERSION_PATH)
|
||||
message(STATUS "libnetconf2 version header not found, assuming libnetconf2 is too old and cannot be used!")
|
||||
set(LIBNETCONF2_INCLUDE_DIR "LIBNETCONF2_INCLUDE_DIR-NOTFOUND")
|
||||
set(LIBNETCONF2_LIBRARY "LIBNETCONF2_LIBRARY-NOTFOUND")
|
||||
else()
|
||||
file(READ "${NC_VERSION_PATH}/nc_version.h" NC_VERSION_FILE)
|
||||
string(REGEX MATCH "#define NC_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]+\"" NC_VERSION_MACRO "${NC_VERSION_FILE}")
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" LIBNETCONF2_VERSION "${NC_VERSION_MACRO}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
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)
|
||||
find_package_handle_standard_args(LibNETCONF2 FOUND_VAR LIBNETCONF2_FOUND
|
||||
REQUIRED_VARS LIBNETCONF2_LIBRARY LIBNETCONF2_INCLUDE_DIR
|
||||
VERSION_VAR LIBNETCONF2_VERSION)
|
||||
|
||||
# check the configured options and make them available through cmake
|
||||
list(INSERT CMAKE_REQUIRED_INCLUDES 0 "${LIBNETCONF2_INCLUDE_DIR}")
|
||||
|
|
144
README.md
144
README.md
|
@ -22,13 +22,14 @@ NETCONF 1.0 ([RFC 4741](https://tools.ietf.org/html/rfc4741)) as well as NETCONF
|
|||
* 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)),
|
||||
* NETCONF Event Notifications ([RFC 5277](https://tools.ietf.org/html/rfc5277)).
|
||||
* Compatibility with the [ietf-netconf-server](https://datatracker.ietf.org/doc/html/draft-ietf-netconf-netconf-client-server-29#name-the-ietf-netconf-server-mod) YANG module.
|
||||
|
||||
**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).
|
||||
via the [issue tracker](https://github.com/CESNET/libnetconf2/issues).
|
||||
|
||||
Besides the [**libyang**](https://github.com/CESNET/libyang), **libnetconf2** is
|
||||
another basic building block for the [**Netopeer2** toolset](https://github.com/CESNET/Netopeer2).
|
||||
|
@ -51,79 +52,41 @@ and it occurs on the `master` branch, the **first response will likely be** to u
|
|||
of the [**libnetconf**](https://github.com/CESNET/libnetconf) library, which
|
||||
is now obsolete and should not be used.
|
||||
|
||||
# Installation
|
||||
## Packages
|
||||
|
||||
## Required Dependencies
|
||||
Binary RPM or DEB packages of the latest release can be built locally using `apkg`, look into `README` in
|
||||
the `distro` directory.
|
||||
|
||||
Install the following libraries and tools the libnetconf2 depends on.
|
||||
## Requirements
|
||||
|
||||
### 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
|
||||
```
|
||||
* C compiler (gcc >= 4.8.4, clang >= 3.0, ...)
|
||||
* cmake >= 3.5.0
|
||||
* crypt(3)
|
||||
* [libyang](https://github.com/CESNET/libyang)
|
||||
* libssh >= 0.9.5 (for SSH support)
|
||||
* OpenSSL >= 3.0.0 or MbedTLS >= 3.5.0 (for TLS support)
|
||||
* curl >= 7.30.0
|
||||
|
||||
### 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
|
||||
```
|
||||
#### Optional
|
||||
|
||||
### 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).
|
||||
* libpam (for PAM-based SSH `keyboard-interactive` authentication method)
|
||||
* libval (only for DNSSEC SSHFP retrieval)
|
||||
* [DNSSEC-Tools/dnssec-tools/validator](https://github.com/DNSSEC-Tools/DNSSEC-Tools/tree/master/dnssec-tools/validator)
|
||||
part of the DNSSEC-Tools suite
|
||||
* doxygen (for generating documentation)
|
||||
* cmocka >= 1.0.1 (for tests only, see [Tests](#Tests))
|
||||
* valgrind (for enhanced testing)
|
||||
* gcov (for code coverage)
|
||||
* lcov (for code coverage)
|
||||
* genhtml (for code coverage)
|
||||
|
||||
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
|
||||
## Building
|
||||
|
||||
```
|
||||
$ mkdir build; cd build
|
||||
$ cmake ..
|
||||
$ make
|
||||
# install
|
||||
# make install
|
||||
```
|
||||
|
||||
The library documentation can be generated directly from the source codes using
|
||||
|
@ -161,7 +124,7 @@ 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 ..
|
||||
$ cmake -DENABLE_SSH_TLS=ON ..
|
||||
```
|
||||
|
||||
### DNSSEC SSHFP Retrieval
|
||||
|
@ -229,10 +192,7 @@ $ make
|
|||
$ make coverage
|
||||
```
|
||||
|
||||
Note that `gcc` compiler is required for this option and additional tools are required:
|
||||
* gcov
|
||||
* lcov
|
||||
* genhtml
|
||||
Note that `gcc` compiler is required for this option.
|
||||
|
||||
### CMake Notes
|
||||
|
||||
|
@ -248,7 +208,7 @@ All public functions are available via 2 headers:
|
|||
#include <nc_client.h>
|
||||
```
|
||||
|
||||
You need to include either one if imeplementing a NETCONF server or a NETCONF client,
|
||||
You need to include either one if implementing a NETCONF server or a NETCONF client,
|
||||
respectively.
|
||||
|
||||
To compile your program with libnetconf2, it is necessary to link it with it using the
|
||||
|
@ -257,6 +217,10 @@ following linker parameters:
|
|||
-lnetconf2
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
See [examples](examples) directory for an example client and server.
|
||||
|
||||
## Tests
|
||||
|
||||
The repository includes several tests built with [cmocka](https://cmocka.org/).
|
||||
|
@ -283,3 +247,43 @@ Tests can be run by the make's `test` target:
|
|||
$ make test
|
||||
```
|
||||
|
||||
## Supported YANG modules
|
||||
|
||||
### Server
|
||||
|
||||
The *libnetconf2* NETCONF server has two APIs that load YANG modules into the context. The first API is [nc_server_init_ctx](https://netopeer.liberouter.org/doc/libnetconf2/master/html/group__server__functions.html#ga35cccf2dbe9204abe01ccb4b93db7438), which loads the following YANG modules with their features:
|
||||
|
||||
- **ietf-netconf**: writable-running, candidate, rollback-on-error, validate, startup, url, xpath, confirmed-commit,
|
||||
- **ietf-netconf-monitoring**: no features.
|
||||
|
||||
The second API is [nc_server_config_load_modules](https://netopeer.liberouter.org/doc/libnetconf2/master/html/group__server__config__functions.html#ga3760b87e3ab4309514e9ad82c4c09cdb). Supported features (marked by ✔) are loaded into the context by this API.
|
||||
|
||||
- **iana-crypt-hash**: crypt-hash-md5 ✔, crypt-hash-sha-256 ✔, crypt-hash-sha-512 ✔,
|
||||
- **ietf-netconf-server**: ssh-listen ✔, tls-listen ✔, ssh-call-home ✔, tls-call-home ✔, central-netconf-server-supported ✔,
|
||||
- **iana-ssh-encryption-algs**: no features,
|
||||
- **iana-ssh-key-exchange-algs**: no features,
|
||||
- **iana-ssh-mac-algs**: no features,
|
||||
- **iana-ssh-public-key-algs**: no features,
|
||||
- **iana-tls-cipher-suite-algs**: no features,
|
||||
- **ietf-crypto-types**: cleartext-passwords ✔, cleartext-private-keys ✔, private-key-encryption ✘, csr-generation ✘, p10-csr-format ✘, certificate-expiration-notification **?**, encrypted-passwords ✘, hidden-symmetric-keys ✘, encrypted-symmetric-keys ✘, hidden-private-keys ✘, encrypted-private-keys ✘, one-symmetric-key-format ✘, one-asymmetric-key-format ✘, symmetrically-encrypted-value-format ✘, asymmetrically-encrypted-value-format ✘, cms-enveloped-data-format ✘, cms-encrypted-data-format ✘, cleartext-symmetric-keys ✘,
|
||||
- **ietf-keystore**: central-keystore-supported ✔, inline-definitions-supported ✔, asymmetric-keys ✔, symmetric-keys ✘,
|
||||
- **ietf-netconf-server**: ssh-listen ✔, tls-listen ✔, ssh-call-home ✔, tls-call-home ✔, central-netconf-server-supported ✔,
|
||||
- **ietf-ssh-common**: transport-params ✔, ssh-x509-certs ✘, public-key-generation ✘,
|
||||
- **ietf-ssh-server**: local-users-supported **?**, local-user-auth-publickey ✔, local-user-auth-password ✔, local-user-auth-none ✔, ssh-server-keepalives ✘, local-user-auth-hostbased ✘,
|
||||
- **ietf-tcp-client**: tcp-client-keepalives ✔, proxy-connect ✘, socks5-gss-api ✘, socks5-username-password ✘, local-binding-supported ✔,
|
||||
- **ietf-tcp-common**: transport-params ✔, ssh-x509-certs ✘, public-key-generation ✘,
|
||||
- **ietf-tcp-server**: tcp-server-keepalives ✔,
|
||||
- **ietf-tls-common**: tls10 ✔, tls11 ✔, tls12 ✔, tls13 ✔, hello-params ✔, public-key-generation ✘,
|
||||
- **ietf-tls-server**: server-ident-x509-cert ✔, client-auth-supported ✔, client-auth-x509-cert ✔, tls-server-keepalives ✘, server-ident-raw-public-key ✘, server-ident-tls12-psk ✘, server-ident-tls13-epsk ✘, client-auth-raw-public-key ✘, client-auth-tls12-psk ✘, client-auth-tls13-epsk ✘,
|
||||
- **ietf-truststore**: central-truststore-supported ✔, inline-definitions-supported ✔, certificates ✔, public-keys ✔,
|
||||
- **ietf-x509-cert-to-name**: no features,
|
||||
- **libnetconf2-netconf-server**: no features.
|
||||
|
||||
The following features can be enabled/disabled to influence the behaviour of the `libnetconf2` NETCONF server:
|
||||
|
||||
- `local-users-supported` - enabled by default, disable to change the behaviour of the SSH authentication (see the *libnetconf2* [documentation](https://netopeer.liberouter.org/doc/libnetconf2/master/html/howtoserver.html)).
|
||||
- `certificate-expiration-notification` - disabled by default, but certificate expiration notifications are supported and you can enable this feature to create such YANG data (see the *libnetconf2* documentation).
|
||||
|
||||
### Client
|
||||
|
||||
Currently no client specific YANG modules are supported.
|
||||
|
|
30
SECURITY.md
Normal file
30
SECURITY.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Security Policy
|
||||
|
||||
If you discover a security-related issue, please report it based on the instructions below.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please **DO NOT** file a public issue, instead report the vulnerability on the relevant
|
||||
[GitHub security](https://github.com/CESNET/libnetconf2/security) page. If you do not receive any reaction within 48 hours,
|
||||
please also send an email to [mvasko@cesnet.cz].
|
||||
|
||||
## Review Process
|
||||
|
||||
After receiving the report, an initial triage and technical analysis is performed to confirm the report and determine
|
||||
its scope. We may request additional information in this stage of the process.
|
||||
|
||||
Once a reviewer has confirmed the relevance of the report, a draft security advisory will be created on GitHub. The
|
||||
draft advisory will be used to discuss the issue with maintainers, the reporter(s), and where applicable, other affected
|
||||
parties under embargo.
|
||||
|
||||
If the vulnerability is accepted, a timeline for developing a patch, public disclosure, and patch release will be
|
||||
determined. If there is an embargo period on public disclosure before the patch release, the reporter(s) are expected to
|
||||
participate in the discussion of the timeline and abide by agreed upon dates for public disclosure.
|
||||
|
||||
Usually, the reasonably complex issues are fixed within hours of being reported.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
After an issue is fixed, it **WILL NOT** be backported to any released version. Instead, it is kept in the public `devel`
|
||||
branch, which is periodically merged into the main branch when a new release is due. So, the issue will be fixed in the
|
||||
next release after it is fixed.
|
261
compat/compat.c
261
compat/compat.c
|
@ -3,7 +3,7 @@
|
|||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief compatibility functions
|
||||
*
|
||||
* Copyright (c) 2021 CESNET, z.s.p.o.
|
||||
* Copyright (c) 2021 - 2023 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.
|
||||
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "compat.h"
|
||||
|
||||
#include <crypt.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
|
@ -28,6 +29,179 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||||
int
|
||||
pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime)
|
||||
{
|
||||
int64_t nsec_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 time */
|
||||
clock_gettime(COMPAT_CLOCK_ID, &cur);
|
||||
|
||||
/* 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);
|
||||
|
||||
if (nsec_diff <= 0) {
|
||||
/* timeout */
|
||||
rc = ETIMEDOUT;
|
||||
break;
|
||||
} else if (nsec_diff < 5000000) {
|
||||
/* sleep until timeout */
|
||||
dur.tv_sec = 0;
|
||||
dur.tv_nsec = nsec_diff;
|
||||
} else {
|
||||
/* sleep 5 ms */
|
||||
dur.tv_sec = 0;
|
||||
dur.tv_nsec = 5000000;
|
||||
}
|
||||
|
||||
nanosleep(&dur, NULL);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_MUTEX_CLOCKLOCK
|
||||
int
|
||||
pthread_mutex_clocklock(pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abstime)
|
||||
{
|
||||
/* only real time supported without this function */
|
||||
if (clockid != CLOCK_REALTIME) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return pthread_mutex_timedlock(mutex, abstime);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK
|
||||
int
|
||||
pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, const struct timespec *abstime)
|
||||
{
|
||||
int64_t nsec_diff;
|
||||
struct timespec cur, dur;
|
||||
int rc;
|
||||
|
||||
/* try to acquire the lock and, if we fail, sleep for 5ms. */
|
||||
while ((rc = pthread_rwlock_tryrdlock(rwlock)) == EBUSY) {
|
||||
/* get time */
|
||||
clock_gettime(COMPAT_CLOCK_ID, &cur);
|
||||
|
||||
/* 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);
|
||||
|
||||
if (nsec_diff <= 0) {
|
||||
/* timeout */
|
||||
rc = ETIMEDOUT;
|
||||
break;
|
||||
} else if (nsec_diff < 5000000) {
|
||||
/* sleep until timeout */
|
||||
dur.tv_sec = 0;
|
||||
dur.tv_nsec = nsec_diff;
|
||||
} else {
|
||||
/* sleep 5 ms */
|
||||
dur.tv_sec = 0;
|
||||
dur.tv_nsec = 5000000;
|
||||
}
|
||||
|
||||
nanosleep(&dur, NULL);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_RWLOCK_CLOCKRDLOCK
|
||||
int
|
||||
pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clockid, const struct timespec *abstime)
|
||||
{
|
||||
/* only real time supported without this function */
|
||||
if (clockid != CLOCK_REALTIME) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return pthread_rwlock_timedrdlock(rwlock, abstime);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
|
||||
int
|
||||
pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *abstime)
|
||||
{
|
||||
int64_t nsec_diff;
|
||||
struct timespec cur, dur;
|
||||
int rc;
|
||||
|
||||
/* try to acquire the lock and, if we fail, sleep for 5ms. */
|
||||
while ((rc = pthread_rwlock_trywrlock(rwlock)) == EBUSY) {
|
||||
/* get time */
|
||||
clock_gettime(COMPAT_CLOCK_ID, &cur);
|
||||
|
||||
/* 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);
|
||||
|
||||
if (nsec_diff <= 0) {
|
||||
/* timeout */
|
||||
rc = ETIMEDOUT;
|
||||
break;
|
||||
} else if (nsec_diff < 5000000) {
|
||||
/* sleep until timeout */
|
||||
dur.tv_sec = 0;
|
||||
dur.tv_nsec = nsec_diff;
|
||||
} else {
|
||||
/* sleep 5 ms */
|
||||
dur.tv_sec = 0;
|
||||
dur.tv_nsec = 5000000;
|
||||
}
|
||||
|
||||
nanosleep(&dur, NULL);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_RWLOCK_CLOCKWRLOCK
|
||||
int
|
||||
pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clockid, const struct timespec *abstime)
|
||||
{
|
||||
/* only real time supported without this function */
|
||||
if (clockid != CLOCK_REALTIME) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return pthread_rwlock_timedwrlock(rwlock, abstime);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_COND_CLOCKWAIT
|
||||
int
|
||||
pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex, clockid_t UNUSED(clockid),
|
||||
const struct timespec *abstime)
|
||||
{
|
||||
/* assume the correct clock is set during cond init */
|
||||
return pthread_cond_timedwait(cond, mutex, abstime);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_VDPRINTF
|
||||
int
|
||||
vdprintf(int fd, const char *format, va_list ap)
|
||||
|
@ -200,51 +374,54 @@ get_current_dir_name(void)
|
|||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||||
int
|
||||
pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime)
|
||||
#ifndef HAVE_CRYPT_R
|
||||
char *
|
||||
crypt_r(const char *phrase, const char *setting, struct crypt_data *data)
|
||||
{
|
||||
int64_t nsec_diff;
|
||||
int32_t diff;
|
||||
struct timespec cur, dur;
|
||||
int rc;
|
||||
static pthread_mutex_t crypt_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
char *hash;
|
||||
|
||||
/* 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;
|
||||
(void) data;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
cur.tv_sec = (time_t)tv.tv_sec;
|
||||
cur.tv_nsec = 1000L * (long)tv.tv_usec;
|
||||
#endif
|
||||
pthread_mutex_lock(&crypt_lock);
|
||||
hash = crypt(phrase, setting);
|
||||
pthread_mutex_unlock(&crypt_lock);
|
||||
|
||||
/* 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;
|
||||
return hash;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_TIMEGM
|
||||
time_t
|
||||
timegm(struct tm *tm)
|
||||
{
|
||||
pthread_mutex_t tz_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
time_t ret;
|
||||
char *tz;
|
||||
|
||||
pthread_mutex_lock(&tz_lock);
|
||||
|
||||
tz = getenv("TZ");
|
||||
if (tz) {
|
||||
tz = strdup(tz);
|
||||
}
|
||||
setenv("TZ", "", 1);
|
||||
tzset();
|
||||
|
||||
ret = mktime(tm);
|
||||
|
||||
if (tz) {
|
||||
setenv("TZ", tz, 1);
|
||||
free(tz);
|
||||
} else {
|
||||
unsetenv("TZ");
|
||||
}
|
||||
tzset();
|
||||
|
||||
pthread_mutex_unlock(&tz_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief compatibility functions header
|
||||
*
|
||||
* Copyright (c) 2021 CESNET, z.s.p.o.
|
||||
* Copyright (c) 2021 - 2023 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.
|
||||
|
@ -15,12 +15,22 @@
|
|||
#ifndef _COMPAT_H_
|
||||
#define _COMPAT_H_
|
||||
|
||||
#define _GNU_SOURCE /* pthread_rwlock_t */
|
||||
|
||||
#cmakedefine HAVE_CRYPT_H
|
||||
|
||||
#ifdef HAVE_CRYPT_H
|
||||
# include <crypt.h>
|
||||
#endif
|
||||
|
||||
#include <alloca.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef __WORDSIZE
|
||||
# if defined __x86_64__ && !defined __ILP32__
|
||||
|
@ -48,6 +58,15 @@
|
|||
# define _PACKED
|
||||
#endif
|
||||
|
||||
#define COMPAT_CLOCK_ID @COMPAT_CLOCK_ID@
|
||||
#cmakedefine HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||||
#cmakedefine HAVE_PTHREAD_MUTEX_CLOCKLOCK
|
||||
#cmakedefine HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK
|
||||
#cmakedefine HAVE_PTHREAD_RWLOCK_CLOCKRDLOCK
|
||||
#cmakedefine HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
|
||||
#cmakedefine HAVE_PTHREAD_RWLOCK_CLOCKWRLOCK
|
||||
#cmakedefine HAVE_PTHREAD_COND_CLOCKWAIT
|
||||
|
||||
#cmakedefine HAVE_VDPRINTF
|
||||
#cmakedefine HAVE_ASPRINTF
|
||||
#cmakedefine HAVE_VASPRINTF
|
||||
|
@ -57,7 +76,8 @@
|
|||
#cmakedefine HAVE_STRDUPA
|
||||
#cmakedefine HAVE_STRCHRNUL
|
||||
#cmakedefine HAVE_GET_CURRENT_DIR_NAME
|
||||
#cmakedefine HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||||
#cmakedefine HAVE_CRYPT_R
|
||||
#cmakedefine HAVE_TIMEGM
|
||||
|
||||
#ifndef bswap64
|
||||
#define bswap64(val) \
|
||||
|
@ -87,6 +107,10 @@
|
|||
|
||||
# define ATOMIC_T atomic_uint_fast32_t
|
||||
# define ATOMIC_T_MAX UINT_FAST32_MAX
|
||||
# define ATOMIC64_T atomic_uint_fast64_t
|
||||
# define ATOMIC64_T_MAX UINT_FAST64_MAX
|
||||
|
||||
# define ATOMIC_PTR_T atomic_uintptr_t
|
||||
|
||||
# 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)
|
||||
|
@ -94,11 +118,20 @@
|
|||
# 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)
|
||||
# define ATOMIC_COMPARE_EXCHANGE_RELAXED(var, exp, des, result) \
|
||||
result = atomic_compare_exchange_strong_explicit(&(var), &(exp), des, memory_order_relaxed, memory_order_relaxed)
|
||||
|
||||
# define ATOMIC_PTR_STORE_RELAXED(var, x) atomic_store_explicit(&(var), (uintptr_t)(x), memory_order_relaxed)
|
||||
# define ATOMIC_PTR_LOAD_RELAXED(var) ((void *)atomic_load_explicit(&(var), memory_order_relaxed))
|
||||
#else
|
||||
# include <stdint.h>
|
||||
|
||||
# define ATOMIC_T uint32_t
|
||||
# define ATOMIC_T_MAX UINT32_MAX
|
||||
# define ATOMIC64_T uint64_t
|
||||
# define ATOMIC64_T_MAX UINT64_MAX
|
||||
|
||||
# define ATOMIC_PTR_T void *
|
||||
|
||||
# define ATOMIC_STORE_RELAXED(var, x) ((var) = (x))
|
||||
# define ATOMIC_LOAD_RELAXED(var) (var)
|
||||
|
@ -106,6 +139,35 @@
|
|||
# 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)
|
||||
# define ATOMIC_COMPARE_EXCHANGE_RELAXED(var, exp, des, result) \
|
||||
{ \
|
||||
ATOMIC_T __old = __sync_val_compare_and_swap(&(var), exp, des); \
|
||||
result = ATOMIC_LOAD_RELAXED(__old) == ATOMIC_LOAD_RELAXED(exp) ? 1 : 0; \
|
||||
ATOMIC_STORE_RELAXED(exp, ATOMIC_LOAD_RELAXED(__old)); \
|
||||
}
|
||||
|
||||
# define ATOMIC_PTR_STORE_RELAXED(var, x) ((var) = (x))
|
||||
# define ATOMIC_PTR_LOAD_RELAXED(var) (var)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||||
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_MUTEX_CLOCKLOCK
|
||||
int pthread_mutex_clocklock(pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abstime);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_RWLOCK_CLOCKRDLOCK
|
||||
int pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clockid, const struct timespec *abstime);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_RWLOCK_CLOCKWRLOCK
|
||||
int pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clockid, const struct timespec *abstime);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_COND_CLOCKWAIT
|
||||
int pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex, clockid_t clockid, const struct timespec *abstime);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_VDPRINTF
|
||||
|
@ -151,8 +213,18 @@ char *strchrnul(const char *s, int c);
|
|||
char *get_current_dir_name(void);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||||
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime);
|
||||
#ifndef HAVE_CRYPT_R
|
||||
|
||||
/* unused anyway */
|
||||
struct crypt_data {
|
||||
char a;
|
||||
};
|
||||
|
||||
char *crypt_r(const char *phrase, const char *setting, struct crypt_data *data);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_TIMEGM
|
||||
time_t timegm(struct tm *tm);
|
||||
#endif
|
||||
|
||||
#endif /* _COMPAT_H_ */
|
||||
|
|
17
distro/README.md
Normal file
17
distro/README.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
# upstream packaging
|
||||
|
||||
This directory contains upstream packaging sources in apkg format.
|
||||
|
||||
apkg tool can be used to build packages directly from this source repo.
|
||||
|
||||
See apkg docs: https://pkg.labs.nic.cz/pages/apkg/
|
||||
|
||||
|
||||
## RPM-based system (Fedora, CentOS, SUSE, ...) quickstart
|
||||
|
||||
```
|
||||
sudo dnf install -y git rpm-build python3-pip
|
||||
pip3 install apkg
|
||||
|
||||
apkg build -b
|
||||
```
|
|
@ -3,8 +3,8 @@ 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"
|
||||
archive_url = "https://github.com/CESNET/libnetconf2/archive/v{{ version }}/libnetconf2-{{ version }}.tar.gz"
|
||||
version_script = "distro/scripts/upstream-version.sh"
|
||||
|
||||
[apkg]
|
||||
compat = 1
|
||||
compat = 2
|
||||
|
|
|
@ -6,14 +6,16 @@ Priority: optional
|
|||
Standards-Version: 4.5.0
|
||||
Build-Depends: cmake,
|
||||
debhelper (>= 10),
|
||||
libyang2-dev,
|
||||
libssl-dev,
|
||||
libssh-dev (>= 0.7.1),
|
||||
pkg-config
|
||||
libyang-dev,
|
||||
libssl-dev (>= 3.0.0),
|
||||
libssh-dev (>= 0.9.5),
|
||||
libpam0g-dev,
|
||||
pkg-config,
|
||||
libcurl4-openssl-dev (>= 7.30.0)
|
||||
Vcs-Browser: https://github.com/CESNET/libnetconf2/tree/master
|
||||
Vcs-Git: https://github.com/CESNET/libnetconf2.git
|
||||
|
||||
Package: libnetconf2-2
|
||||
Package: libnetconf4
|
||||
Depends: ${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Architecture: any
|
||||
|
@ -27,8 +29,8 @@ Description: library implementing NETCONF protocol - runtime
|
|||
It is implemented in C.
|
||||
|
||||
Package: libnetconf2-dev
|
||||
Depends: libyang2-dev,
|
||||
libnetconf2-2 (= ${binary:Version}),
|
||||
Depends: libyang-dev,
|
||||
libnetconf4 (= ${binary:Version}),
|
||||
${misc:Depends}
|
||||
Section: libdevel
|
||||
Architecture: any
|
||||
|
@ -41,4 +43,3 @@ Description: library implementing NETCONF protocol - development files
|
|||
.
|
||||
This package contains the C headers, a pkgconfig file, and .so entry
|
||||
point for libnetconf2.
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
usr/lib/*/libnetconf2.so.*
|
|
@ -3,3 +3,4 @@ usr/lib/*/pkgconfig/libnetconf2.pc
|
|||
usr/include/libnetconf2/*
|
||||
usr/include/nc_client.h
|
||||
usr/include/nc_server.h
|
||||
usr/include/nc_version.h
|
||||
|
|
2
distro/pkg/deb/libnetconf4.install
Normal file
2
distro/pkg/deb/libnetconf4.install
Normal file
|
@ -0,0 +1,2 @@
|
|||
usr/lib/*/libnetconf2.so.*
|
||||
usr/share/yang/modules/libnetconf2
|
|
@ -3,20 +3,22 @@ Version: {{ version }}
|
|||
Release: {{ release }}%{?dist}
|
||||
Summary: NETCONF protocol library
|
||||
Url: https://github.com/CESNET/libnetconf2
|
||||
Source: libnetconf2-%{version}.tar.gz
|
||||
Source: %{url}/archive/v%{version}/%{name}-%{version}.tar.gz
|
||||
License: BSD
|
||||
|
||||
BuildRequires: cmake
|
||||
BuildRequires: make
|
||||
BuildRequires: gcc
|
||||
BuildRequires: libssh-devel
|
||||
BuildRequires: openssl-devel
|
||||
BuildRequires: pam-devel
|
||||
BuildRequires: pkgconfig(libyang) >= 2
|
||||
BuildRequires: libcurl-devel
|
||||
|
||||
%package devel
|
||||
Summary: Headers of libnetconf2 library
|
||||
Conflicts: libnetconf-devel
|
||||
Requires: %{name}%{?_isa} = %{version}-%{release}
|
||||
Requires: pkgconfig
|
||||
|
||||
%description devel
|
||||
Headers of libnetconf library.
|
||||
|
@ -28,27 +30,24 @@ 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
|
||||
%cmake -DCMAKE_BUILD_TYPE=RELWITHDEBINFO -DENABLE_TESTS=OFF
|
||||
%cmake_build
|
||||
|
||||
%install
|
||||
cd build
|
||||
make DESTDIR=%{buildroot} install
|
||||
%cmake_install
|
||||
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
%{_libdir}/libnetconf2.so.2*
|
||||
%doc README.md FAQ.md
|
||||
%{_libdir}/libnetconf2.so.*
|
||||
%{_datadir}/yang/modules/libnetconf2/*.yang
|
||||
%dir %{_datadir}/yang/modules/libnetconf2/
|
||||
|
||||
%files devel
|
||||
%doc CODINGSTYLE.md
|
||||
%{_libdir}/libnetconf2.so
|
||||
%{_libdir}/pkgconfig/libnetconf2.pc
|
||||
%{_includedir}/*.h
|
||||
|
@ -57,5 +56,5 @@ make DESTDIR=%{buildroot} install
|
|||
|
||||
|
||||
%changelog
|
||||
* Tue Oct 12 2021 Jakub Ružička <jakub.ruzicka@nic.cz> - {{ version }}-{{ release }}
|
||||
* {{ now }} Jakub Ružička <jakub.ruzicka@nic.cz> - {{ version }}-{{ release }}
|
||||
- upstream package
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
#!/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//[-]/.}
|
||||
VERSION=$(git log --oneline -n1 --grep="^VERSION" | rev | cut -d' ' -f1 | rev)
|
||||
|
||||
NAMEVER=libnetconf2-$VERSION
|
||||
ARCHIVE=$NAMEVER.tar.gz
|
||||
|
|
1
distro/tests/control
Normal file
1
distro/tests/control
Normal file
|
@ -0,0 +1 @@
|
|||
Tests: test-pkg-config.sh
|
5
distro/tests/test-pkg-config.sh
Executable file
5
distro/tests/test-pkg-config.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
version=`pkg-config --modversion libnetconf2`
|
||||
echo "$version" | grep '2\.[0-9.]\+'
|
|
@ -1,31 +1,3 @@
|
|||
/**
|
||||
* @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
|
||||
*
|
||||
|
@ -45,7 +17,8 @@
|
|||
* - 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)),
|
||||
* - Creating, sending and receiving NETCONF Event Notifications ([RFC 5277](https://tools.ietf.org/html/rfc5277)).
|
||||
* - Configuring the NETCONF server based on the [ietf-netconf-server](https://datatracker.ietf.org/doc/html/draft-ietf-netconf-netconf-client-server-29) YANG module
|
||||
*
|
||||
* @section about-license License
|
||||
*
|
||||
|
@ -82,13 +55,11 @@
|
|||
* @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
|
||||
* and/or ::nc_server_init(). 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.
|
||||
* after all the other threads have ended.
|
||||
*
|
||||
* 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
|
||||
|
@ -103,7 +74,7 @@
|
|||
* 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
|
||||
* locally 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.
|
||||
*
|
||||
|
@ -115,8 +86,9 @@
|
|||
* 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.
|
||||
* In the client, it is always thread-safe to work with a NETCONF session in a single thread since the client
|
||||
* settings are thread-specific as described above. Generally, one can access a session in several threads
|
||||
* as well but there is little incentive to do so.
|
||||
*
|
||||
* Server
|
||||
* ------
|
||||
|
@ -148,10 +120,6 @@
|
|||
*
|
||||
* - ::nc_server_init()
|
||||
* - ::nc_server_destroy()
|
||||
*
|
||||
* Available in both __nc_client.h__ and __nc_server.h__.
|
||||
*
|
||||
* - ::nc_thread_destroy()
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -196,8 +164,6 @@
|
|||
*
|
||||
* 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()
|
||||
|
@ -240,8 +206,6 @@
|
|||
* - ::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()
|
||||
|
@ -279,7 +243,6 @@
|
|||
*
|
||||
* 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()
|
||||
|
@ -300,8 +263,6 @@
|
|||
* - ::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()
|
||||
*
|
||||
|
@ -319,14 +280,10 @@
|
|||
* 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
|
||||
* Server must start with [initialization](@ref howtoinit). Its capabilities are
|
||||
* determined by the context used when accepting new NETCONF sessions. 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,
|
||||
|
@ -337,13 +294,7 @@
|
|||
* 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.
|
||||
* To be able to accept any connections, the server must first be configured.
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
|
@ -352,46 +303,141 @@
|
|||
*
|
||||
* - ::nc_server_set_capab_withdefaults()
|
||||
* - ::nc_server_set_capability()
|
||||
* - ::nc_server_set_hello_timeout()
|
||||
* - ::nc_server_set_idle_timeout()
|
||||
* - ::nc_server_endpt_count()
|
||||
* - ::nc_server_add_endpt_unix_socket_listen()
|
||||
* - ::nc_server_del_endpt_unix_socket()
|
||||
*
|
||||
* - ::nc_server_add_endpt()
|
||||
* - ::nc_server_del_endpt()
|
||||
* - ::nc_server_endpt_set_address()
|
||||
* - ::nc_server_endpt_set_port()
|
||||
* - ::nc_server_endpt_set_perms()
|
||||
*
|
||||
*
|
||||
* SSH
|
||||
* Server Configuration
|
||||
* ===
|
||||
*
|
||||
* 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().
|
||||
* To successfully accept connections on a server, you first need to configure it.
|
||||
* The *libnetconf2* server natively supports the *ietf-netconf-server YANG* module.
|
||||
* This allows for a bigger scaling and flexibility of the *NETCONF* server.
|
||||
* By using *ietf-netconf-server YANG* data you can express network configurations
|
||||
* in a standardized and hierarchical format, enabling you to define complex network
|
||||
* structures with greater ease.
|
||||
*
|
||||
* There are also some other optional settings. Note that authorized
|
||||
* public keys are set for the server as a whole, not endpoint-specifically.
|
||||
* The process of configuring a server is comprised of two steps. The first step is creating the
|
||||
* configuration data and the second is applying it. The server supports two forms of the configuration
|
||||
* data - *YANG data* and *YANG diff*.
|
||||
*
|
||||
* YANG data
|
||||
* ---
|
||||
* Configuring the server using YANG data simplifies the management of network services.
|
||||
* With YANG data, you build a structured configuration tree and apply it as a whole.
|
||||
* This approach is user-friendly, allowing you to modify the configuration by adding or deleting nodes,
|
||||
* and then deploying the updated configuration tree in its entirety, providing a way to manage your server's settings.
|
||||
* The *libnetconf2* library exports API functions that can help you with creation or deletion of the *YANG* data.
|
||||
*
|
||||
* YANG diff
|
||||
* ---
|
||||
* YANG diff, enriched with operation attributes, offers advanced configuration control.
|
||||
* It empowers the user to make precise changes within the configuration tree,
|
||||
* enabling operations like specific node deletions, additions, and modifications.
|
||||
* On the other hand, unlike YANG data, YANG diff represents only a subtree of the
|
||||
* changes expecting the whole configuration to be managed externally.
|
||||
* For example this is done by the tool [sysrepo](https://www.sysrepo.org/).
|
||||
*
|
||||
* Usage
|
||||
* ---
|
||||
* To be able to configure the server, the required models first need to be implemented.
|
||||
* To do this, see ::nc_server_config_load_modules().
|
||||
* Not all of the *ietf-netconf-server* (and all of its associated modules) features are enabled.
|
||||
* If you wish to see which features are enabled, extract them from the context after calling the mentioned function.
|
||||
*
|
||||
* If you wish not to create the __YANG data__ yourself, you may use the library's functions to do this for you.
|
||||
* For example ::nc_server_config_add_address_port() creates __YANG data__ corresponding to an SSH/TLS endpoint.
|
||||
* You can then apply this data by calling ::nc_server_config_setup_data() (or ::nc_server_config_setup_diff() for diff).
|
||||
* See *examples/server.c* for a simple example.
|
||||
*
|
||||
* You may also create entries in the keystore or truststore. For example the asymmetric key and certificate entries
|
||||
* in the keystore can be then referenced as the SSH hostkeys or TLS server certificates, respectively.
|
||||
* As for the truststore, you may create public key and certificate entries, which can then be used
|
||||
* as SSH user's public keys or TLS server's end-entity/trust-anchor certificates, respectively.
|
||||
*
|
||||
* 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_config_load_modules()
|
||||
* - ::nc_server_config_setup_diff()
|
||||
* - ::nc_server_config_setup_data()
|
||||
* - ::nc_server_config_setup_path()
|
||||
*
|
||||
* - ::nc_server_ssh_set_hostkey_clb()
|
||||
* - ::nc_server_config_add_address_port()
|
||||
* - ::nc_server_config_del_endpt()
|
||||
* - ::nc_server_config_add_keystore_asym_key()
|
||||
* - ::nc_server_config_del_keystore_asym_key()
|
||||
* - ::nc_server_config_add_keystore_cert()
|
||||
* - ::nc_server_config_del_keystore_cert()
|
||||
* - ::nc_server_config_add_truststore_pubkey()
|
||||
* - ::nc_server_config_del_truststore_pubkey()
|
||||
* - ::nc_server_config_add_truststore_cert()
|
||||
* - ::nc_server_config_del_truststore_cert()
|
||||
*
|
||||
* - ::nc_server_ssh_add_authkey()
|
||||
* - ::nc_server_ssh_add_authkey_path()
|
||||
* - ::nc_server_ssh_del_authkey()
|
||||
* SSH
|
||||
* ===
|
||||
*
|
||||
* To successfully accept an SSH session you must configure at least one host key.
|
||||
* You may create this data yourself or by using ::nc_server_config_add_ssh_hostkey().
|
||||
*
|
||||
* It is important to decide whether the users that can connect to the SSH server should be obtained from the configuration or from the system.
|
||||
* If the YANG feature *local-users-supported* is enabled (the default), then the authorized users are derived from the configuration.
|
||||
* When a client connects to the server, he must be found in the configuration and he must authenticate to **all** of his configured authentication methods.
|
||||
* If the feature is disabled, then the system will be used to try to authenticate the client via one of the three
|
||||
* methods - publickey, keyboard-interactive or password (only one of them has to succeed).
|
||||
*
|
||||
* If the local users are supported then each SSH endpoint can define it's own authorized clients and their authentication methods.
|
||||
* For example if you wish to create an SSH user that can authenticate using a password, use ::nc_server_config_add_ssh_user_password().
|
||||
* Another option for authorized clients is to reference another endpoint's clients, however be careful not to create a cyclic reference
|
||||
* (see ::nc_server_config_add_ssh_endpoint_client_ref()).
|
||||
*
|
||||
* \anchor ln2doc_pubkey
|
||||
* The Public Key authentication method is supported. If you wish to use this method, you need to specify the given user's
|
||||
* public keys, which will be compared with the key(s) presented by the SSH client when authenticating. One option is to configure
|
||||
* the public keys directly in the ietf-netconf-server YANG data (inline-definition). Other option is to configure the keys' data
|
||||
* in the ietf-trustore module's YANG data and then reference them (truststore-reference). The final option is to set the global
|
||||
* path to file with public keys. This path may contain special tokens, see ::nc_server_ssh_set_authkey_path_format().
|
||||
* If the path is set and the use-system-keys container is present in the data for the client wishing to authenticate,
|
||||
* then the keys from the file will be used for authentication. If the YANG feature *local-users-supported* is disabled,
|
||||
* then it's neccessary to set the path format using ::nc_server_ssh_set_authkey_path_format().
|
||||
*
|
||||
* \anchor ln2doc_kbdint
|
||||
* The Keyboard Interactive authentication method is also supported. It can be done in three ways.
|
||||
* If libpam is found, Linux PAM is used to handle the authentication. You need to specify the service name using ::nc_server_ssh_set_pam_conf_filename().
|
||||
* Else if the standard functions for accessing local users are found on the system, they are used. The only Keyboard Interactive challenge will be the given
|
||||
* user's password (that is if he's found on the system).
|
||||
* Either way, you can always define your own callback to perform the authentication, see ::nc_server_ssh_set_interactive_auth_clb().
|
||||
* The callback has a higher priority than the other two methods.
|
||||
*
|
||||
* There are also some other optional settings.
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
* Available in __nc_server.h__.
|
||||
*
|
||||
* - ::nc_server_config_add_ssh_hostkey()
|
||||
* - ::nc_server_config_del_ssh_hostkey()
|
||||
* - ::nc_server_config_add_ssh_keystore_ref()
|
||||
* - ::nc_server_config_del_ssh_keystore_ref()
|
||||
*
|
||||
* - ::nc_server_config_add_ssh_user_pubkey()
|
||||
* - ::nc_server_config_del_ssh_user_pubkey()
|
||||
* - ::nc_server_config_add_ssh_user_password()
|
||||
* - ::nc_server_config_del_ssh_user_password()
|
||||
* - ::nc_server_config_add_ssh_user_interactive()
|
||||
* - ::nc_server_config_del_ssh_user_interactive()
|
||||
* - ::nc_server_config_del_ssh_user()
|
||||
* - ::nc_server_config_add_ssh_truststore_ref()
|
||||
* - ::nc_server_config_del_ssh_truststore_ref()
|
||||
* - ::nc_server_config_add_ssh_endpoint_client_ref()
|
||||
* - ::nc_server_config_del_ssh_endpoint_client_ref()
|
||||
*
|
||||
* - ::nc_server_ssh_set_authkey_path_format()
|
||||
* - ::nc_server_ssh_set_pam_conf_filename()
|
||||
* - ::nc_server_ssh_set_interactive_auth_clb()
|
||||
*
|
||||
* TLS
|
||||
* ===
|
||||
|
@ -399,47 +445,53 @@
|
|||
* 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.
|
||||
* If you wish to listen on a TLS endpoint, you need to configure the endpoint's
|
||||
* server certificate (see ::nc_server_config_add_tls_server_cert()).
|
||||
*
|
||||
* To accept client certificates, they must first be considered trusted.
|
||||
* For each TLS endpoint you may configure two types of client certificates.
|
||||
* The first type are end-entity (client) certificates. These are certificates that belong
|
||||
* to given clients. These certificates need to be trusted.
|
||||
* The second type are trust-anchor (certificate authority) certificates,
|
||||
* which carry over the trust (a chain of trust).
|
||||
* Another option is to reference another TLS endpoint's end-entity certificates, however be careful not to create a cyclic reference
|
||||
* (see ::nc_server_config_add_tls_endpoint_client_ref()).
|
||||
*
|
||||
* 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().
|
||||
* _cert-to-name_ entry.
|
||||
*
|
||||
* 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().
|
||||
* There are some further options. For example you can configure the TLS
|
||||
* version and ciphers to be used.
|
||||
*
|
||||
* You may also choose to use a Certificate Revocation List. These lists
|
||||
* are downloaded from the URIs specified in the x509 CRLDistributionPoints extensions.
|
||||
* Be mindful that if any CRL is successfully downloaded and set, then at least one of them has to belong
|
||||
* to the peer (e.g. the client) certificate (in other words it has to be issued by peer's CA).
|
||||
*
|
||||
* 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_config_add_tls_server_cert()
|
||||
* - ::nc_server_config_del_tls_server_cert()
|
||||
* - ::nc_server_config_add_tls_keystore_ref()
|
||||
* - ::nc_server_config_del_tls_keystore_ref()
|
||||
*
|
||||
* - ::nc_server_tls_set_server_cert_clb()
|
||||
* - ::nc_server_tls_set_server_cert_chain_clb()
|
||||
* - ::nc_server_tls_set_trusted_cert_list_clb()
|
||||
* - ::nc_server_config_add_tls_client_cert()
|
||||
* - ::nc_server_config_del_tls_client_cert()
|
||||
* - ::nc_server_config_add_tls_client_cert_truststore_ref()
|
||||
* - ::nc_server_config_del_tls_client_cert_truststore_ref()
|
||||
* - ::nc_server_config_add_tls_ca_cert()
|
||||
* - ::nc_server_config_del_tls_ca_cert()
|
||||
* - ::nc_server_config_add_tls_ca_cert_truststore_ref()
|
||||
* - ::nc_server_config_del_tls_ca_cert_truststore_ref()
|
||||
* - ::nc_server_config_add_tls_endpoint_client_ref()
|
||||
* - ::nc_server_config_del_tls_endpoint_client_ref()
|
||||
* - ::nc_server_config_add_tls_ctn()
|
||||
* - ::nc_server_config_del_tls_ctn()
|
||||
*
|
||||
* FD
|
||||
* ==
|
||||
|
@ -461,54 +513,64 @@
|
|||
*
|
||||
* _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.
|
||||
* for CH clients.
|
||||
* You may choose one of two approaches for creating a new Call Home
|
||||
* session (or in other words making a server connect to a client).
|
||||
* The first is to set all the required callbacks
|
||||
* by calling ::nc_server_ch_set_dispatch_data(). By setting the callbacks,
|
||||
* the server will automatically start connecting to a client, whenever
|
||||
* a new Call Home client is created.
|
||||
* The second approach is to create the Call Home thread manually.
|
||||
* To do this, you need to call ::nc_connect_ch_client_dispatch(),
|
||||
* which then creates a new thread and the server will start to connect.
|
||||
* Unix socket _Call Home_ sessions are not supported.
|
||||
*
|
||||
* 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_config_add_ch_address_port()
|
||||
* - ::nc_server_config_del_ch_client()
|
||||
* - ::nc_server_config_del_ch_endpt()
|
||||
* - ::nc_server_config_add_ch_persistent()
|
||||
* - ::nc_server_config_add_ch_period()
|
||||
* - ::nc_server_config_del_ch_period()
|
||||
* - ::nc_server_config_add_ch_anchor_time()
|
||||
* - ::nc_server_config_del_ch_anchor_time()
|
||||
* - ::nc_server_config_add_ch_idle_timeout()
|
||||
* - ::nc_server_config_del_ch_idle_timeout()
|
||||
* - ::nc_server_config_add_ch_reconnect_strategy()
|
||||
* - ::nc_server_config_del_ch_reconnect_strategy()
|
||||
*
|
||||
* - ::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()
|
||||
* - ::nc_server_config_add_ch_ssh_hostkey()
|
||||
* - ::nc_server_config_del_ch_ssh_hostkey()
|
||||
* - ::nc_server_config_add_ch_ssh_keystore_ref()
|
||||
* - ::nc_server_config_del_ch_ssh_keystore_ref()
|
||||
* - ::nc_server_config_add_ch_ssh_user_pubkey()
|
||||
* - ::nc_server_config_del_ch_ssh_user_pubkey()
|
||||
* - ::nc_server_config_add_ch_ssh_user_password()
|
||||
* - ::nc_server_config_del_ch_ssh_user_password()
|
||||
* - ::nc_server_config_add_ch_ssh_user_interactive()
|
||||
* - ::nc_server_config_del_ch_ssh_user_interactive()
|
||||
* - ::nc_server_config_del_ch_ssh_user()
|
||||
* - ::nc_server_config_add_ch_ssh_truststore_ref()
|
||||
* - ::nc_server_config_del_ch_ssh_truststore_ref()
|
||||
*
|
||||
* - ::nc_server_config_add_ch_tls_server_cert()
|
||||
* - ::nc_server_config_del_ch_tls_server_cert()
|
||||
* - ::nc_server_config_add_ch_tls_keystore_ref()
|
||||
* - ::nc_server_config_del_ch_tls_keystore_ref()
|
||||
* - ::nc_server_config_add_ch_tls_client_cert()
|
||||
* - ::nc_server_config_del_ch_tls_client_cert()
|
||||
* - ::nc_server_config_add_ch_tls_client_cert_truststore_ref()
|
||||
* - ::nc_server_config_del_ch_tls_client_cert_truststore_ref()
|
||||
* - ::nc_server_config_add_ch_tls_ca_cert()
|
||||
* - ::nc_server_config_del_ch_tls_ca_cert()
|
||||
* - ::nc_server_config_add_ch_tls_ca_cert_truststore_ref()
|
||||
* - ::nc_server_config_del_ch_tls_ca_cert_truststore_ref()
|
||||
* - ::nc_server_config_add_ch_tls_ctn()
|
||||
* - ::nc_server_config_del_ch_tls_ctn()
|
||||
*
|
||||
* Connecting And Cleanup
|
||||
* ======================
|
||||
|
@ -588,6 +650,13 @@
|
|||
* 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.
|
||||
*
|
||||
* The server-side notifications are also supported. You can create a new notification
|
||||
* with ::nc_server_notif_new() and send it via ::nc_server_notif_send() to subscribed clients.
|
||||
* Keep in mind that the session you wish to send a notification on has to have at least one
|
||||
* subscriber, see ::nc_session_inc_notif_status().
|
||||
* Currently, only notifications about certificate expiration are implemented,
|
||||
* see ::nc_server_notif_cert_expiration_thread_start().
|
||||
*
|
||||
* Functions List
|
||||
* --------------
|
||||
*
|
||||
|
@ -603,6 +672,18 @@
|
|||
* - ::nc_ps_clear()
|
||||
* - ::nc_ps_accept_ssh_channel()
|
||||
* - ::nc_session_accept_ssh_channel()
|
||||
*
|
||||
* - ::nc_server_notif_new()
|
||||
* - ::nc_server_notif_send()
|
||||
* - ::nc_server_notif_free()
|
||||
* - ::nc_server_notif_get_time()
|
||||
|
||||
* - ::nc_session_inc_notif_status()
|
||||
* - ::nc_session_dec_notif_status()
|
||||
* - ::nc_session_get_notif_status()
|
||||
|
||||
* - ::nc_server_notif_cert_expiration_thread_start()
|
||||
* - ::nc_server_notif_cert_expiration_thread_stop()
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -610,7 +691,7 @@
|
|||
*
|
||||
* 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
|
||||
* you should not need to worry about them much because 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.
|
||||
|
@ -621,8 +702,8 @@
|
|||
* You can adjust active and inactive read timeout using `cmake` variables.
|
||||
* For details look into `README.md`.
|
||||
*
|
||||
* API Functions
|
||||
* -------------
|
||||
* Configurable timeouts
|
||||
* ---------------------
|
||||
*
|
||||
* Once a new connection is established including transport protocol negotiations,
|
||||
* _hello_ message is exchanged. You can set how long will the server wait for
|
||||
|
@ -632,23 +713,10 @@
|
|||
* 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
|
||||
* client. 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()
|
||||
* These timeouts can be toggled by applying corresponding configuration data.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -664,6 +732,6 @@
|
|||
/**
|
||||
* @defgroup server Server
|
||||
* @brief NETCONF server functionality.
|
||||
* @{
|
||||
* @} Server
|
||||
*/
|
||||
|
||||
#endif /* NC_LIBNETCONF_H_ */
|
21
examples/CMakeLists.txt
Normal file
21
examples/CMakeLists.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
if(NOT LIBNETCONF2_VERSION)
|
||||
message(FATAL_ERROR "Please use the root CMakeLists file instead.")
|
||||
endif()
|
||||
|
||||
# correct RPATH usage on OS X
|
||||
set(CMAKE_MACOSX_RPATH TRUE)
|
||||
|
||||
# include all the library headers
|
||||
include_directories(BEFORE "${CMAKE_SOURCE_DIR}/src")
|
||||
|
||||
# generate example header
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
configure_file(example.h.in example.h)
|
||||
|
||||
# list of all the examples
|
||||
set(examples server client)
|
||||
|
||||
foreach(app_name IN LISTS examples)
|
||||
add_executable(${app_name} ${app_name}.c)
|
||||
target_link_libraries(${app_name} netconf2)
|
||||
endforeach(app_name)
|
134
examples/README.md
Normal file
134
examples/README.md
Normal file
|
@ -0,0 +1,134 @@
|
|||
# libnetconf2 - examples
|
||||
There are two examples `server` and `client` demonstrating a simple NETCONF server and client using libnetconf2 C library. This is an extensively documented example, which is trying to showcase the key parts of the libnetconf2 library in a simple way. The library configuration is kept to the minimum just to achieve basic functionality. Two types of transport are supported in this example: _UNIX Socket_ and _SSH_. Both examples have the `-h` option that displays their usage.
|
||||
|
||||
## Server
|
||||
The example server provides `ietf-yang-library` state data that are returned as a reply to `get` RPC. In case an XPath filter is used it is properly applied on these data. If some unsupported parameters are specified, the server replies with a NETCONF error.
|
||||
|
||||
### Server Configuration
|
||||
The server's default configuration can be found in the `config.json` file. The YANG data stored in this file define two SSH endpoints - they differ in port and in how clients get authenticated.
|
||||
You can modify this configuration in any way you want, however, configuring the server may fail if the configuration is not valid.
|
||||
|
||||
## Example usage
|
||||
### Server
|
||||
First start the server:
|
||||
```
|
||||
$ server -u ./example-socket
|
||||
```
|
||||
The server will be started and configured per YANG data stored in the file `config.json`.
|
||||
Two SSH endpoints with the addresses `127.0.0.1:10000` and `127.0.0.1:10001` will start listening for new connections.
|
||||
This first endpoint has a single user that can authenticate with a password (which is set to `admin` by default).
|
||||
The second endpoint has a single user that can authenticate with a publickey (the asymmetric key pair used is stored in `admin_key` and `admin_key.pub`).
|
||||
The `-u` option specifies that a UNIX socket endpoint will be created and `./example-socket` is the path to where the socket will be listening.
|
||||
|
||||
### Client
|
||||
#### UNIX socket
|
||||
After the server has been run, in another terminal instance, with the default configuration:
|
||||
```
|
||||
$ client -u ./example-socket get "/ietf-yang-library:yang-library/module-set/module[name='ietf-netconf']"
|
||||
```
|
||||
In this case, `-u` means that a connection to an UNIX socket will be attempted and a path to the socket needs to be specified.
|
||||
The `get` parameter is the name of the RPC and `/ietf-yang-library:yang-library/module-set/module[name='ietf-netconf']` is the RPC's optional XPath filter.
|
||||
|
||||
##### Server output
|
||||
```
|
||||
Listening for new connections! <-- server created
|
||||
Connection established <-- client joined
|
||||
Received RPC:
|
||||
get-schema <-- name of the RPC
|
||||
identifier = "ietf-datastores" <-- name of the requested YANG module
|
||||
format = "ietf-netconf-monitoring:yang" <-- format of the requested YANG module
|
||||
Received RPC:
|
||||
get-schema
|
||||
identifier = "ietf-netconf-nmda"
|
||||
format = "ietf-netconf-monitoring:yang"
|
||||
Received RPC:
|
||||
get
|
||||
filter = "(null)" <-- XPath filter has no value in the anyxml
|
||||
type = "xpath" <-- defines XPath filter type (which may also be subtree)
|
||||
select = "/ietf-yang-library:*" <-- contains a string representing the XPath filter
|
||||
Received RPC:
|
||||
get
|
||||
filter = "(null)"
|
||||
type = "xpath"
|
||||
select = "/ietf-yang-library:yang-library/module-set/module[name='ietf-netconf']"
|
||||
Received RPC:
|
||||
close-session <-- communication with client terminated
|
||||
```
|
||||
The server received five supported RPCs. First, the client attempts to obtain basic YANG modules using `get-schema`. Then, it retrieves all the `ietf-yang-library` data to be used for creating its context, which should ideally be the same as that of the server. Next the example `get` RPC is received and lastly `close-session` RPC terminates the connection.
|
||||
|
||||
##### Client output
|
||||
```
|
||||
<get xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
|
||||
<data>
|
||||
<yang-library xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
|
||||
<module-set>
|
||||
<name>complete</name>
|
||||
<module>
|
||||
<name>ietf-netconf</name> <-- requested name of a module
|
||||
<revision>2013-09-29</revision>
|
||||
<namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace>
|
||||
<location>file:///home/roman/libnetconf2/modules/ietf-netconf@2013-09-29.yang</location>
|
||||
<feature>writable-running</feature>
|
||||
<feature>candidate</feature>
|
||||
<feature>confirmed-commit</feature>
|
||||
<feature>rollback-on-error</feature>
|
||||
<feature>validate</feature>
|
||||
<feature>startup</feature>
|
||||
<feature>url</feature>
|
||||
<feature>xpath</feature>
|
||||
</module>
|
||||
</module-set>
|
||||
</yang-library>
|
||||
</data>
|
||||
</get>
|
||||
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="4"/>
|
||||
```
|
||||
The client received a single `ietf-yang-library` module based on the used filter.
|
||||
|
||||
#### SSH
|
||||
After the server has been run, in another terminal instance, with the default configuration:
|
||||
```
|
||||
$ client -p 10000 get-config startup
|
||||
```
|
||||
In this case, `-p 10000` is the port to connect to. By default the endpoint with this port has a single authorized client that needs to authenticate with a password.
|
||||
The parameter `get-config` is the name of the RPC and `startup` is the source datastore for the retrieved data of the get-config RPC.
|
||||
|
||||
##### Server output
|
||||
```
|
||||
Using SSH!
|
||||
Connection established
|
||||
Received RPC:
|
||||
get-schema
|
||||
identifier = "ietf-datastores"
|
||||
format = "ietf-netconf-monitoring:yang"
|
||||
Received RPC:
|
||||
get-schema
|
||||
identifier = "ietf-netconf-nmda"
|
||||
format = "ietf-netconf-monitoring:yang"
|
||||
Received RPC:
|
||||
get
|
||||
filter = "(null)"
|
||||
type = "xpath"
|
||||
select = "/ietf-yang-library:*"
|
||||
Received RPC:
|
||||
get-config <-- name of the RPC
|
||||
candidate = "" <-- source datastore, which is of type empty
|
||||
Received RPC:
|
||||
close-session
|
||||
```
|
||||
|
||||
##### Client output
|
||||
```
|
||||
admin@127.0.0.1 password: <-- prompts for password, type in 'admin'
|
||||
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="4">
|
||||
<ok/>
|
||||
</rpc-reply>
|
||||
```
|
||||
No `startup` configuration is returned, because the example server lacks this functionality.
|
||||
The _username_ in the `example.h` header file. The _password_ is located in `config.json`.
|
||||
|
||||
If you wish to connect to the SSH public key endpoint, you need to specify its port and the asymmetric key pair to use.
|
||||
By default the command to connect would look like so:
|
||||
```
|
||||
$ client -p 10001 -P ~/libnetconf2/examples/admin_key.pub -i ~/libnetconf2/examples/admin_key get
|
||||
```
|
7
examples/admin_key
Normal file
7
examples/admin_key
Normal file
|
@ -0,0 +1,7 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACDq+Oq6bYOgbFoTtSTKJrod3LgmJnrjuiXzlD7P2Dt+cAAAAJC1rL1gtay9
|
||||
YAAAAAtzc2gtZWQyNTUxOQAAACDq+Oq6bYOgbFoTtSTKJrod3LgmJnrjuiXzlD7P2Dt+cA
|
||||
AAAEAQm84SEphEUZEbuCRmXrMcYyv70wNEVziE/SbBC6+trOr46rptg6BsWhO1JMomuh3c
|
||||
uCYmeuO6JfOUPs/YO35wAAAADXJvbWFuQHBjdmFza28=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
1
examples/admin_key.pub
Normal file
1
examples/admin_key.pub
Normal file
|
@ -0,0 +1 @@
|
|||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOr46rptg6BsWhO1JMomuh3cuCYmeuO6JfOUPs/YO35w test@libnetconf2
|
266
examples/client.c
Normal file
266
examples/client.c
Normal file
|
@ -0,0 +1,266 @@
|
|||
/**
|
||||
* @file client.c
|
||||
* @author Roman Janota <xjanot04@fit.vutbr.cz>
|
||||
* @brief libnetconf2 client example
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2022 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 "example.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "messages_client.h"
|
||||
#include "netconf.h"
|
||||
#include "session_client.h"
|
||||
#include "session_client_ch.h"
|
||||
|
||||
static void
|
||||
help_print()
|
||||
{
|
||||
printf("Example usage:\n"
|
||||
" client get\n"
|
||||
"\n"
|
||||
" Available options:\n"
|
||||
" -h, --help\t \tPrint usage help.\n"
|
||||
" -p, --port\t\t<port>\tSpecify the port to connect to.\n"
|
||||
" -u, --unix-path\t<path>\tConnect to a UNIX socket located at <path>.\n"
|
||||
" -P, --ssh-pubkey\t<path>\tSet the path to an SSH Public key.\n"
|
||||
" -i, --ssh-privkey\t<path>\tSet the path to an SSH Private key.\n\n"
|
||||
" Available RPCs:\n"
|
||||
" get [xpath-filter]\t\t\t\t\t send a <get> RPC with optional XPath filter\n"
|
||||
" get-config [datastore] [xpath-filter]\t\t send a <get-config> RPC with optional XPath filter and datastore, the default datastore is \"running\" \n\n");
|
||||
}
|
||||
|
||||
static enum NC_DATASTORE_TYPE
|
||||
string2datastore(const char *str)
|
||||
{
|
||||
if (!str) {
|
||||
return NC_DATASTORE_RUNNING;
|
||||
}
|
||||
|
||||
if (!strcmp(str, "candidate")) {
|
||||
return NC_DATASTORE_CANDIDATE;
|
||||
} else if (!strcmp(str, "running")) {
|
||||
return NC_DATASTORE_RUNNING;
|
||||
} else if (!strcmp(str, "startup")) {
|
||||
return NC_DATASTORE_STARTUP;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
send_rpc(struct nc_session *session, NC_RPC_TYPE rpc_type, const char *param1, const char *param2)
|
||||
{
|
||||
enum NC_DATASTORE_TYPE datastore;
|
||||
int r = 0, rc = 0;
|
||||
uint64_t msg_id = 0;
|
||||
struct lyd_node *envp = NULL, *op = NULL;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* decide which type of RPC to send */
|
||||
switch (rpc_type) {
|
||||
case NC_RPC_GET:
|
||||
/* create get RPC with an optional filter */
|
||||
rpc = nc_rpc_get(param1, NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
|
||||
break;
|
||||
|
||||
case NC_RPC_GETCONFIG:
|
||||
/* create get-config RPC with a source datastore and an optional filter */
|
||||
datastore = string2datastore(param1);
|
||||
if (!datastore) {
|
||||
ERR_MSG_CLEANUP("Invalid name of a datastore. Use candidate, running, startup or neither.\n");
|
||||
}
|
||||
rpc = nc_rpc_getconfig(datastore, param2, NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!rpc) {
|
||||
ERR_MSG_CLEANUP("Error while creating a RPC\n");
|
||||
}
|
||||
|
||||
/* send the RPC on the session and remember NETCONF message ID */
|
||||
r = nc_send_rpc(session, rpc, 100, &msg_id);
|
||||
if (r != NC_MSG_RPC) {
|
||||
ERR_MSG_CLEANUP("Couldn't send a RPC\n");
|
||||
}
|
||||
|
||||
/* receive the server's reply with the expected message ID
|
||||
* as separate rpc-reply NETCONF envelopes and the parsed YANG output itself, if any */
|
||||
r = nc_recv_reply(session, rpc, msg_id, 100, &envp, &op);
|
||||
if (r != NC_MSG_REPLY) {
|
||||
ERR_MSG_CLEANUP("Couldn't receive a reply from the server\n");
|
||||
}
|
||||
|
||||
/* print the whole reply */
|
||||
if (!op) {
|
||||
r = lyd_print_file(stdout, envp, LYD_XML, 0);
|
||||
} else {
|
||||
r = lyd_print_file(stdout, op, LYD_XML, 0);
|
||||
if (r) {
|
||||
ERR_MSG_CLEANUP("Couldn't print the RPC to stdout\n");
|
||||
}
|
||||
r = lyd_print_file(stdout, envp, LYD_XML, 0);
|
||||
}
|
||||
if (r) {
|
||||
ERR_MSG_CLEANUP("Couldn't print the RPC to stdout\n");
|
||||
}
|
||||
|
||||
cleanup:
|
||||
lyd_free_all(envp);
|
||||
lyd_free_all(op);
|
||||
nc_rpc_free(rpc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int rc = 0, opt, port = 0;
|
||||
struct nc_session *session = NULL;
|
||||
const char *unix_socket_path = NULL, *rpc_parameter_1 = NULL, *rpc_parameter_2 = NULL;
|
||||
const char *ssh_pubkey_path = NULL, *ssh_privkey_path = NULL;
|
||||
|
||||
struct option options[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"port", required_argument, NULL, 'p'},
|
||||
{"unix-path", required_argument, NULL, 'u'},
|
||||
{"ssh-pubkey", required_argument, NULL, 'P'},
|
||||
{"ssh-privkey", required_argument, NULL, 'i'},
|
||||
{"debug", no_argument, NULL, 'd'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
if (argc == 1) {
|
||||
help_print();
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* set the path to search for schemas */
|
||||
nc_client_set_schema_searchpath(MODULES_DIR);
|
||||
|
||||
opterr = 0;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "hp:u:P:i:d", options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
help_print();
|
||||
goto cleanup;
|
||||
|
||||
case 'p':
|
||||
port = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
unix_socket_path = optarg;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
ssh_pubkey_path = optarg;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
ssh_privkey_path = optarg;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
nc_verbosity(NC_VERB_DEBUG);
|
||||
nc_libssh_thread_verbosity(2);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERR_MSG_CLEANUP("Invalid option or missing argument\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc) {
|
||||
ERR_MSG_CLEANUP("Expected the name of RPC after options\n");
|
||||
}
|
||||
|
||||
/* check invalid args combinations */
|
||||
if (unix_socket_path && port) {
|
||||
ERR_MSG_CLEANUP("Both UNIX socket path and port specified. Please choose either SSH or UNIX.\n");
|
||||
} else if (unix_socket_path && (ssh_pubkey_path || ssh_privkey_path)) {
|
||||
ERR_MSG_CLEANUP("Both UNIX socket path and a path to key(s) specified. Please choose either SSH or UNIX.\n");
|
||||
} else if ((port == 10001) && (!ssh_pubkey_path || !ssh_privkey_path)) {
|
||||
ERR_MSG_CLEANUP("You need to specify both paths to private and public keys, if you want to connect to a publickey endpoint.\n");
|
||||
} else if ((port == 10000) && (ssh_pubkey_path || ssh_privkey_path)) {
|
||||
ERR_MSG_CLEANUP("Public or private key specified, when connecting to the password endpoint.\n");
|
||||
} else if (!unix_socket_path && !port) {
|
||||
ERR_MSG_CLEANUP("Neither UNIX socket or SSH specified.\n");
|
||||
}
|
||||
|
||||
/* connect to the server using the specified transport protocol */
|
||||
if (unix_socket_path) {
|
||||
/* it's UNIX socket */
|
||||
session = nc_connect_unix(unix_socket_path, NULL);
|
||||
} else {
|
||||
/* it must be SSH, so set the client SSH username to always be used when connecting to the server */
|
||||
if (nc_client_ssh_set_username(SSH_USERNAME)) {
|
||||
ERR_MSG_CLEANUP("Couldn't set the SSH username\n");
|
||||
}
|
||||
|
||||
if (ssh_pubkey_path && ssh_privkey_path) {
|
||||
/* set the client's SSH keypair to be used for authentication if necessary */
|
||||
if (nc_client_ssh_add_keypair(ssh_pubkey_path, ssh_privkey_path)) {
|
||||
ERR_MSG_CLEANUP("Couldn't set client's SSH keypair.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* try to connect via SSH */
|
||||
session = nc_connect_ssh(SSH_ADDRESS, port, NULL);
|
||||
}
|
||||
if (!session) {
|
||||
ERR_MSG_CLEANUP("Couldn't connect to the server\n");
|
||||
}
|
||||
|
||||
/* sending a get RPC */
|
||||
if (!strcmp(argv[optind], "get")) {
|
||||
if (optind + 1 < argc) {
|
||||
/* use the specified XPath filter */
|
||||
rpc_parameter_1 = argv[optind + 1];
|
||||
}
|
||||
if (send_rpc(session, NC_RPC_GET, rpc_parameter_1, rpc_parameter_2)) {
|
||||
rc = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
/* sending a get-config RPC */
|
||||
} else if (!strcmp(argv[optind], "get-config")) {
|
||||
/* use the specified datastore and optional XPath filter */
|
||||
if (optind + 2 < argc) {
|
||||
rpc_parameter_1 = argv[optind + 1];
|
||||
rpc_parameter_2 = argv[optind + 2];
|
||||
} else if (optind + 1 < argc) {
|
||||
rpc_parameter_1 = argv[optind + 1];
|
||||
}
|
||||
if (send_rpc(session, NC_RPC_GETCONFIG, rpc_parameter_1, rpc_parameter_2)) {
|
||||
rc = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
ERR_MSG_CLEANUP("Invalid name of a RPC\n");
|
||||
}
|
||||
|
||||
cleanup:
|
||||
nc_session_free(session, NULL);
|
||||
nc_client_destroy();
|
||||
return rc;
|
||||
}
|
93
examples/config.json
Normal file
93
examples/config.json
Normal file
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"ietf-netconf-server:netconf-server": {
|
||||
"listen": {
|
||||
"idle-timeout": 10,
|
||||
"endpoints": {
|
||||
"endpoint": [
|
||||
{
|
||||
"name": "ssh-password-auth-endpt",
|
||||
"ssh": {
|
||||
"tcp-server-parameters": {
|
||||
"local-address": "127.0.0.1",
|
||||
"local-port": 10000
|
||||
},
|
||||
"ssh-server-parameters": {
|
||||
"server-identity": {
|
||||
"host-key": [
|
||||
{
|
||||
"name": "key",
|
||||
"public-key": {
|
||||
"inline-definition": {
|
||||
"public-key-format": "ietf-crypto-types:ssh-public-key-format",
|
||||
"public-key": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDRIB2eNSRWU+HNWRUGKr76ghCLg8RaMlUCps9lBjnc6ggaJl2Q+TOLn8se2wAdK3lYBMz3dcqR+SlU7eB8wJAc=",
|
||||
"private-key-format": "ietf-crypto-types:ec-private-key-format",
|
||||
"cleartext-private-key": "MHcCAQEEICQ2fr9Jt2xluom0YQQ7HseE8YTo5reZRVcQENKUWOrooAoGCCqGSM49AwEHoUQDQgAENEgHZ41JFZT4c1ZFQYqvvqCEIuDxFoyVQKmz2UGOdzqCBomXZD5M4ufyx7bAB0reVgEzPd1ypH5KVTt4HzAkBw=="
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"client-authentication": {
|
||||
"users": {
|
||||
"user": [
|
||||
{
|
||||
"name": "admin",
|
||||
"password": "$0$admin"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ssh-pubkey-auth-endpt",
|
||||
"ssh": {
|
||||
"tcp-server-parameters": {
|
||||
"local-address": "127.0.0.1",
|
||||
"local-port": 10001
|
||||
},
|
||||
"ssh-server-parameters": {
|
||||
"server-identity": {
|
||||
"host-key": [
|
||||
{
|
||||
"name": "key",
|
||||
"public-key": {
|
||||
"inline-definition": {
|
||||
"public-key-format": "ietf-crypto-types:ssh-public-key-format",
|
||||
"public-key": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDRIB2eNSRWU+HNWRUGKr76ghCLg8RaMlUCps9lBjnc6ggaJl2Q+TOLn8se2wAdK3lYBMz3dcqR+SlU7eB8wJAc=",
|
||||
"private-key-format": "ietf-crypto-types:ec-private-key-format",
|
||||
"cleartext-private-key": "MHcCAQEEICQ2fr9Jt2xluom0YQQ7HseE8YTo5reZRVcQENKUWOrooAoGCCqGSM49AwEHoUQDQgAENEgHZ41JFZT4c1ZFQYqvvqCEIuDxFoyVQKmz2UGOdzqCBomXZD5M4ufyx7bAB0reVgEzPd1ypH5KVTt4HzAkBw=="
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"client-authentication": {
|
||||
"users": {
|
||||
"user": [
|
||||
{
|
||||
"name": "admin",
|
||||
"public-keys": {
|
||||
"inline-definition": {
|
||||
"public-key": [
|
||||
{
|
||||
"name": "admin_key.pub",
|
||||
"public-key-format": "ietf-crypto-types:ssh-public-key-format",
|
||||
"public-key": "AAAAC3NzaC1lZDI1NTE5AAAAIOr46rptg6BsWhO1JMomuh3cuCYmeuO6JfOUPs/YO35w"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
examples/example.h.in
Normal file
41
examples/example.h.in
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* @file example.h
|
||||
* @author Roman Janota <xjanot04@fit.vutbr.cz>
|
||||
* @brief libnetconf2 example header
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2022 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 _EXAMPLE_H_
|
||||
#define _EXAMPLE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* directory with library YANG modules */
|
||||
#define MODULES_DIR "@CMAKE_SOURCE_DIR@/modules"
|
||||
|
||||
/* directory with examples source code and this header */
|
||||
#define EXAMPLES_DIR "@CMAKE_SOURCE_DIR@/examples"
|
||||
|
||||
/* SSH listening IP address */
|
||||
#define SSH_ADDRESS "127.0.0.1"
|
||||
|
||||
/* SSH 'password' authentication exptected username and password */
|
||||
#define SSH_USERNAME "admin"
|
||||
|
||||
/* time in microseconds to sleep for if there are no new RPCs and no new sessions */
|
||||
#define BACKOFF_TIMEOUT_USECS 100
|
||||
|
||||
#define ERR_MSG_CLEANUP(msg) \
|
||||
rc = 1; \
|
||||
fprintf(stderr, "%s", msg); \
|
||||
goto cleanup
|
||||
|
||||
#endif
|
380
examples/server.c
Normal file
380
examples/server.c
Normal file
|
@ -0,0 +1,380 @@
|
|||
/**
|
||||
* @file server.c
|
||||
* @author Roman Janota <xjanot04@fit.vutbr.cz>
|
||||
* @brief libnetconf2 server example
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2022 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 _GNU_SOURCE
|
||||
#include "example.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "messages_server.h"
|
||||
#include "netconf.h"
|
||||
#include "server_config.h"
|
||||
#include "session_server.h"
|
||||
#include "session_server_ch.h"
|
||||
|
||||
volatile int exit_application = 0;
|
||||
struct lyd_node *tree;
|
||||
|
||||
static void
|
||||
sigint_handler(int signum)
|
||||
{
|
||||
(void) signum;
|
||||
/* notify the main loop if we should exit */
|
||||
exit_application = 1;
|
||||
}
|
||||
|
||||
static struct nc_server_reply *
|
||||
get_rpc(struct lyd_node *rpc, struct nc_session *session)
|
||||
{
|
||||
const struct ly_ctx *ctx;
|
||||
const char *xpath;
|
||||
struct lyd_node *root = NULL, *root2 = NULL, *duplicate = NULL;
|
||||
struct lyd_node *filter, *err;
|
||||
struct lyd_meta *m, *type = NULL, *select = NULL;
|
||||
struct ly_set *set = NULL;
|
||||
LY_ERR ret;
|
||||
|
||||
ctx = nc_session_get_ctx(session);
|
||||
|
||||
/* load the ietf-yang-library data of the session, which represent this server's state data */
|
||||
if (ly_ctx_get_yanglib_data(ctx, &root, "%u", ly_ctx_get_change_count(ctx))) {
|
||||
err = nc_err(ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* search for the optional filter in the RPC */
|
||||
ret = lyd_find_path(rpc, "filter", 0, &filter);
|
||||
if (ret && (ret != LY_ENOTFOUND)) {
|
||||
err = nc_err(ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (filter) {
|
||||
/* look for the expected filter attributes type and select */
|
||||
LY_LIST_FOR(filter->meta, m) {
|
||||
if (!strcmp(m->name, "type")) {
|
||||
type = m;
|
||||
}
|
||||
if (!strcmp(m->name, "select")) {
|
||||
select = m;
|
||||
}
|
||||
}
|
||||
|
||||
/* only XPath filter is supported */
|
||||
if (!type || strcmp(lyd_get_meta_value(type), "xpath") || !select) {
|
||||
err = nc_err(ctx, NC_ERR_OP_NOT_SUPPORTED, NC_ERR_TYPE_APP);
|
||||
goto error;
|
||||
}
|
||||
xpath = lyd_get_meta_value(select);
|
||||
|
||||
/* find all the subtrees matching the filter */
|
||||
if (lyd_find_xpath(root, xpath, &set)) {
|
||||
err = nc_err(ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
|
||||
goto error;
|
||||
}
|
||||
|
||||
root2 = NULL;
|
||||
for (uint32_t i = 0; i < set->count; i++) {
|
||||
/* create a copy of the subtree with its parent nodes */
|
||||
if (lyd_dup_single(set->dnodes[i], NULL, LYD_DUP_RECURSIVE | LYD_DUP_WITH_PARENTS, &duplicate)) {
|
||||
err = nc_err(ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* merge another top-level filtered subtree into the result */
|
||||
while (duplicate->parent) {
|
||||
duplicate = lyd_parent(duplicate);
|
||||
}
|
||||
if (lyd_merge_tree(&root2, duplicate, LYD_MERGE_DESTRUCT)) {
|
||||
err = nc_err(ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
|
||||
goto error;
|
||||
}
|
||||
duplicate = NULL;
|
||||
}
|
||||
|
||||
/* replace the original full data with only the filtered data */
|
||||
lyd_free_siblings(root);
|
||||
root = root2;
|
||||
root2 = NULL;
|
||||
}
|
||||
|
||||
/* duplicate the rpc node without its input nodes so the output nodes can be appended */
|
||||
if (lyd_dup_single(rpc, NULL, 0, &duplicate)) {
|
||||
err = nc_err(ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* create the get RPC anyxml "data" output node with the requested data */
|
||||
if (lyd_new_any(duplicate, NULL, "data", root, LYD_ANYDATA_DATATREE, LYD_NEW_ANY_USE_VALUE | LYD_NEW_VAL_OUTPUT, NULL)) {
|
||||
err = nc_err(ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ly_set_free(set, NULL);
|
||||
|
||||
/* send data reply with the RPC output data */
|
||||
return nc_server_reply_data(duplicate, NC_WD_UNKNOWN, NC_PARAMTYPE_FREE);
|
||||
|
||||
error:
|
||||
ly_set_free(set, NULL);
|
||||
lyd_free_siblings(root);
|
||||
lyd_free_siblings(duplicate);
|
||||
lyd_free_siblings(root2);
|
||||
|
||||
/* send error reply with the specific NETCONF error */
|
||||
return nc_server_reply_err(err);
|
||||
}
|
||||
|
||||
static struct nc_server_reply *
|
||||
glob_rpc(struct lyd_node *rpc, struct nc_session *session)
|
||||
{
|
||||
struct lyd_node *iter;
|
||||
struct lyd_meta *m;
|
||||
|
||||
printf("Received RPC:\n");
|
||||
|
||||
/* iterate over all the nodes in the RPC */
|
||||
LYD_TREE_DFS_BEGIN(rpc, iter) {
|
||||
/* if the node has a value, then print its name and value */
|
||||
if (iter->schema->nodetype & (LYD_NODE_TERM | LYD_NODE_ANY)) {
|
||||
printf(" %s = \"%s\"\n", LYD_NAME(iter), lyd_get_value(iter));
|
||||
/* then iterate through all the metadata, which may include the XPath filter */
|
||||
LY_LIST_FOR(iter->meta, m) {
|
||||
printf(" %s = \"%s\"\n", m->name, lyd_get_meta_value(m));
|
||||
}
|
||||
/* else print just the name */
|
||||
} else if (iter->schema->nodetype == LYS_RPC) {
|
||||
printf(" %s\n", LYD_NAME(iter));
|
||||
}
|
||||
|
||||
LYD_TREE_DFS_END(rpc, iter);
|
||||
}
|
||||
|
||||
/* if close-session RPC is received, then call library's default function to properly close the session */
|
||||
if (!strcmp(LYD_NAME(rpc), "close-session") && !strcmp(lyd_owner_module(rpc)->name, "ietf-netconf")) {
|
||||
return nc_clb_default_close_session(rpc, session);
|
||||
}
|
||||
|
||||
/* if get-schema RPC is received, then use the library implementation of this RPC */
|
||||
if (!strcmp(LYD_NAME(rpc), "get-schema") && !strcmp(lyd_owner_module(rpc)->name, "ietf-netconf-monitoring")) {
|
||||
return nc_clb_default_get_schema(rpc, session);
|
||||
}
|
||||
|
||||
if (!strcmp(LYD_NAME(rpc), "get") && !strcmp(lyd_owner_module(rpc)->name, "ietf-netconf")) {
|
||||
return get_rpc(rpc, session);
|
||||
}
|
||||
|
||||
/* return an okay reply to every other RPC */
|
||||
return nc_server_reply_ok();
|
||||
}
|
||||
|
||||
static void
|
||||
help_print()
|
||||
{
|
||||
printf("Example usage:\n"
|
||||
" server -u ./unix_socket\n"
|
||||
"\n"
|
||||
" Available options:\n"
|
||||
" -h, --help\t \tPrint usage help.\n"
|
||||
" -u, --unix\t<path>\tCreate a UNIX socket endpoint at the place specified by <path>.\n\n");
|
||||
}
|
||||
|
||||
static int
|
||||
init(const char *unix_socket_path, struct ly_ctx **context, struct nc_pollsession **ps)
|
||||
{
|
||||
int rc = 0;
|
||||
struct lyd_node *config = NULL;
|
||||
|
||||
/* create a libyang context that will determine which YANG modules will be supported by the server */
|
||||
rc = ly_ctx_new(MODULES_DIR, 0, context);
|
||||
if (rc) {
|
||||
ERR_MSG_CLEANUP("Error while creating a new context.\n");
|
||||
}
|
||||
|
||||
/* implement the base NETCONF modules */
|
||||
rc = nc_server_init_ctx(context);
|
||||
if (rc) {
|
||||
ERR_MSG_CLEANUP("Error while initializing context.\n");
|
||||
}
|
||||
|
||||
/* load all required modules for configuration, so the configuration of the server can be done */
|
||||
rc = nc_server_config_load_modules(context);
|
||||
if (rc) {
|
||||
ERR_MSG_CLEANUP("Error loading modules required for configuration of the server.\n");
|
||||
}
|
||||
|
||||
/* apply the YANG data stored in config.json */
|
||||
rc = nc_server_config_setup_path(*context, EXAMPLES_DIR "/config.json");
|
||||
if (rc) {
|
||||
ERR_MSG_CLEANUP("Application of configuration data failed.\n");
|
||||
}
|
||||
|
||||
/* initialize the server */
|
||||
if (nc_server_init()) {
|
||||
ERR_MSG_CLEANUP("Error occurred while initializing the server.\n");
|
||||
}
|
||||
|
||||
/* create unix socket endpoint if path was set */
|
||||
if (unix_socket_path) {
|
||||
rc = nc_server_add_endpt_unix_socket_listen("unix-socket-endpt", unix_socket_path, -1, -1, -1);
|
||||
if (rc) {
|
||||
ERR_MSG_CLEANUP("Creating UNIX socket endpoint failed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* create a new poll session structure, which is used for polling RPCs sent by clients */
|
||||
*ps = nc_ps_new();
|
||||
if (!*ps) {
|
||||
ERR_MSG_CLEANUP("Couldn't create a poll session\n");
|
||||
}
|
||||
|
||||
/* set the global RPC callback, which is called every time a new RPC is received */
|
||||
nc_set_global_rpc_clb(glob_rpc);
|
||||
|
||||
/* upon receiving SIGINT the handler will notify the program that is should terminate */
|
||||
signal(SIGINT, sigint_handler);
|
||||
|
||||
cleanup:
|
||||
lyd_free_all(config);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int r, opt, no_new_sessions, rc = 0;
|
||||
struct ly_ctx *context = NULL;
|
||||
struct nc_session *session, *new_session;
|
||||
struct nc_pollsession *ps = NULL;
|
||||
const char *unix_socket_path = NULL;
|
||||
|
||||
struct option options[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"debug", no_argument, NULL, 'd'},
|
||||
{"unix", required_argument, NULL, 'u'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
opterr = 0;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "hdu:", options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
help_print();
|
||||
goto cleanup;
|
||||
|
||||
case 'd':
|
||||
nc_verbosity(NC_VERB_DEBUG);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
unix_socket_path = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
ERR_MSG_CLEANUP("Invalid option or missing argument\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize the server */
|
||||
r = init(unix_socket_path, &context, &ps);
|
||||
if (r) {
|
||||
ERR_MSG_CLEANUP("Initializing the server failed.");
|
||||
}
|
||||
|
||||
printf("Listening for new connections!\n");
|
||||
|
||||
while (!exit_application) {
|
||||
no_new_sessions = 0;
|
||||
|
||||
/* try to accept new NETCONF sessions on all configured endpoints */
|
||||
r = nc_accept(0, context, &session);
|
||||
|
||||
switch (r) {
|
||||
|
||||
/* session accepted and its hello message received */
|
||||
case NC_MSG_HELLO:
|
||||
printf("Connection established\n");
|
||||
|
||||
/* add the new session to the poll structure */
|
||||
if (nc_ps_add_session(ps, session)) {
|
||||
ERR_MSG_CLEANUP("Couldn't add session to poll\n");
|
||||
}
|
||||
break;
|
||||
|
||||
/* there were no new sessions */
|
||||
case NC_MSG_WOULDBLOCK:
|
||||
no_new_sessions = 1;
|
||||
break;
|
||||
|
||||
/* session accepted, but its hello message was invalid */
|
||||
case NC_MSG_BAD_HELLO:
|
||||
printf("Parsing client hello message error.\n");
|
||||
break;
|
||||
|
||||
/* something else went wrong */
|
||||
case NC_MSG_ERROR:
|
||||
/* accepting a session failed, but the server should continue handling RPCs on established sessions */
|
||||
printf("Error while accepting a hello message.\n");
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* poll all the sessions in the structure and process a single event on a session which is then returned,
|
||||
* in case it is a new RPC then the global RPC callback is also called */
|
||||
r = nc_ps_poll(ps, 0, &new_session);
|
||||
|
||||
/* a fatal error occurred */
|
||||
if (r & NC_PSPOLL_ERROR) {
|
||||
ERR_MSG_CLEANUP("Error polling RPCs\n");
|
||||
}
|
||||
|
||||
/* a session was terminated, so remove it from the ps structure and free it */
|
||||
if (r & NC_PSPOLL_SESSION_TERM) {
|
||||
r = nc_ps_del_session(ps, new_session);
|
||||
assert(!r);
|
||||
nc_session_free(new_session, NULL);
|
||||
}
|
||||
|
||||
/* there were no new sessions and no new events on any established sessions,
|
||||
* prevent active waiting by sleeping for a short period of time */
|
||||
if (no_new_sessions && (r & (NC_PSPOLL_TIMEOUT | NC_PSPOLL_NOSESSIONS))) {
|
||||
usleep(BACKOFF_TIMEOUT_USECS);
|
||||
}
|
||||
|
||||
/* other set bits of the return value of nc_ps_poll() are not interesting in this example */
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* free all the remaining sessions in the ps structure before destroying the context */
|
||||
if (ps) {
|
||||
nc_ps_clear(ps, 1, NULL);
|
||||
}
|
||||
nc_ps_free(ps);
|
||||
nc_server_destroy();
|
||||
lyd_free_all(tree);
|
||||
ly_ctx_destroy(context);
|
||||
return rc;
|
||||
}
|
|
@ -8,5 +8,5 @@ Version: @LIBNETCONF2_VERSION@
|
|||
Libs: -L${libdir} -lnetconf2
|
||||
Cflags: -I${includedir}
|
||||
|
||||
LNC2_MAX_THREAD_COUNT=@MAX_PSPOLL_THREAD_COUNT@
|
||||
LNC2_SCHEMAS_DIR=@SCHEMAS_DIR@
|
||||
LN2_MAX_THREAD_COUNT=@MAX_PSPOLL_THREAD_COUNT@
|
||||
LN2_SCHEMAS_DIR=@YANG_MODULE_DIR@
|
||||
|
|
124
modules/iana-crypt-hash@2014-04-04.yang
Normal file
124
modules/iana-crypt-hash@2014-04-04.yang
Normal file
|
@ -0,0 +1,124 @@
|
|||
module iana-crypt-hash {
|
||||
namespace "urn:ietf:params:xml:ns:yang:iana-crypt-hash";
|
||||
prefix ianach;
|
||||
|
||||
organization "IANA";
|
||||
contact
|
||||
" Internet Assigned Numbers Authority
|
||||
|
||||
Postal: ICANN
|
||||
4676 Admiralty Way, Suite 330
|
||||
Marina del Rey, CA 90292
|
||||
|
||||
Tel: +1 310 823 9358
|
||||
E-Mail: iana&iana.org";
|
||||
description
|
||||
"This YANG module defines a typedef for storing passwords
|
||||
using a hash function, and features to indicate which hash
|
||||
functions are supported by an implementation.
|
||||
|
||||
The latest revision of this YANG module can be obtained from
|
||||
the IANA web site.
|
||||
|
||||
Requests for new values should be made to IANA via
|
||||
email (iana&iana.org).
|
||||
|
||||
Copyright (c) 2014 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).
|
||||
|
||||
The initial version of this YANG module is part of RFC XXXX;
|
||||
see the RFC itself for full legal notices.";
|
||||
// RFC Ed.: replace XXXX with actual RFC number and remove this
|
||||
// note.
|
||||
|
||||
// RFC Ed.: update the date below with the date of RFC publication
|
||||
// and remove this note.
|
||||
revision 2014-04-04 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC XXXX: A YANG Data Model for System Management";
|
||||
}
|
||||
|
||||
typedef crypt-hash {
|
||||
type string {
|
||||
pattern
|
||||
'$0$.*'
|
||||
+ '|$1$[a-zA-Z0-9./]{1,8}$[a-zA-Z0-9./]{22}'
|
||||
+ '|$5$(rounds=\d+$)?[a-zA-Z0-9./]{1,16}$[a-zA-Z0-9./]{43}'
|
||||
+ '|$6$(rounds=\d+$)?[a-zA-Z0-9./]{1,16}$[a-zA-Z0-9./]{86}';
|
||||
}
|
||||
description
|
||||
"The crypt-hash type is used to store passwords using
|
||||
a hash function. The algorithms for applying the hash
|
||||
function and encoding the result are implemented in
|
||||
various UNIX systems as the function crypt(3).
|
||||
|
||||
A value of this type matches one of the forms:
|
||||
|
||||
$0$<clear text password>
|
||||
$<id>$<salt>$<password hash>
|
||||
$<id>$<parameter>$<salt>$<password hash>
|
||||
|
||||
The '$0$' prefix signals that the value is clear text. When
|
||||
such a value is received by the server, a hash value is
|
||||
calculated, and the string '$<id>$<salt>$' or
|
||||
$<id>$<parameter>$<salt>$ is prepended to the result. This
|
||||
value is stored in the configuration data store.
|
||||
|
||||
If a value starting with '$<id>$', where <id> is not '0', is
|
||||
received, the server knows that the value already represents a
|
||||
hashed value, and stores it as is in the data store.
|
||||
|
||||
When a server needs to verify a password given by a user, it
|
||||
finds the stored password hash string for that user, extracts
|
||||
the salt, and calculates the hash with the salt and given
|
||||
password as input. If the calculated hash value is the same
|
||||
as the stored value, the password given by the client is
|
||||
accepted.
|
||||
|
||||
This type defines the following hash functions:
|
||||
|
||||
id | hash function | feature
|
||||
---+---------------+-------------------
|
||||
1 | MD5 | crypt-hash-md5
|
||||
5 | SHA-256 | crypt-hash-sha-256
|
||||
6 | SHA-512 | crypt-hash-sha-512
|
||||
|
||||
The server indicates support for the different hash functions
|
||||
by advertising the corresponding feature.";
|
||||
reference
|
||||
"IEEE Std 1003.1-2008 - crypt() function
|
||||
RFC 1321: The MD5 Message-Digest Algorithm
|
||||
FIPS.180-3.2008: Secure Hash Standard";
|
||||
}
|
||||
|
||||
feature crypt-hash-md5 {
|
||||
description
|
||||
"Indicates that the device supports the MD5
|
||||
hash function in 'crypt-hash' values";
|
||||
reference "RFC 1321: The MD5 Message-Digest Algorithm";
|
||||
}
|
||||
|
||||
feature crypt-hash-sha-256 {
|
||||
description
|
||||
"Indicates that the device supports the SHA-256
|
||||
hash function in 'crypt-hash' values";
|
||||
reference "FIPS.180-3.2008: Secure Hash Standard";
|
||||
}
|
||||
|
||||
feature crypt-hash-sha-512 {
|
||||
description
|
||||
"Indicates that the device supports the SHA-512
|
||||
hash function in 'crypt-hash' values";
|
||||
reference "FIPS.180-3.2008: Secure Hash Standard";
|
||||
}
|
||||
|
||||
}
|
389
modules/iana-ssh-encryption-algs@2022-06-16.yang
Normal file
389
modules/iana-ssh-encryption-algs@2022-06-16.yang
Normal file
|
@ -0,0 +1,389 @@
|
|||
module iana-ssh-encryption-algs {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:iana-ssh-encryption-algs";
|
||||
prefix sshea;
|
||||
|
||||
organization
|
||||
"Internet Assigned Numbers Authority (IANA)";
|
||||
|
||||
contact
|
||||
"Postal: ICANN
|
||||
12025 Waterfront Drive, Suite 300
|
||||
Los Angeles, CA 90094-2536
|
||||
United States of America
|
||||
Tel: +1 310 301 5800
|
||||
Email: iana@iana.org";
|
||||
|
||||
description
|
||||
"This module defines identities for the encryption algorithms
|
||||
defined in the 'Encryption Algorithm Names' sub-registry of the
|
||||
'Secure Shell (SSH) Protocol Parameters' registry maintained
|
||||
by IANA.
|
||||
|
||||
Copyright (c) 2022 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 Revised
|
||||
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).
|
||||
|
||||
The initial version of this YANG module is part of RFC EEEE
|
||||
(https://www.rfc-editor.org/info/rfcEEEE); see the RFC
|
||||
itself for full legal notices.";
|
||||
|
||||
revision 2022-06-16 {
|
||||
description
|
||||
"Reflects contents of the encryption algorithms registry
|
||||
on June 16, 2022.";
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
|
||||
// Typedefs
|
||||
|
||||
typedef encryption-algorithm-ref {
|
||||
type identityref {
|
||||
base "encryption-alg-base";
|
||||
}
|
||||
description
|
||||
"A reference to a SSH encryption algorithm identifier.";
|
||||
}
|
||||
|
||||
// Identities
|
||||
|
||||
identity encryption-alg-base {
|
||||
description
|
||||
"Base identity used to identify encryption algorithms.";
|
||||
}
|
||||
|
||||
identity triple-des-cbc { // YANG IDs cannot begin with a number
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"3DES-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity blowfish-cbc {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"BLOWFISH-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity twofish256-cbc {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"TWOFISH256-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity twofish-cbc {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"TWOFISH-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity twofish192-cbc {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"TWOFISH192-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
identity twofish128-cbc {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"TWOFISH128-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity aes256-cbc {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"AES256-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity aes192-cbc {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"AES192-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity aes128-cbc {
|
||||
base encryption-alg-base;
|
||||
status deprecated;
|
||||
description
|
||||
"AES128-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity serpent256-cbc {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"SERPENT256-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity serpent192-cbc {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"SERPENT192-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity serpent128-cbc {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"SERPENT128-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity arcfour {
|
||||
base encryption-alg-base;
|
||||
status obsolete;
|
||||
description
|
||||
"ARCFOUR";
|
||||
reference
|
||||
"RFC 8758:
|
||||
Deprecating RC4 in Secure Shell (SSH)";
|
||||
}
|
||||
|
||||
identity idea-cbc {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"IDEA-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity cast128-cbc {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"CAST128-CBC";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity none {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"NONE";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity des-cbc {
|
||||
base encryption-alg-base;
|
||||
status obsolete;
|
||||
description
|
||||
"DES-CBC";
|
||||
reference
|
||||
"FIPS 46-3:
|
||||
Data Encryption Standard (DES)";
|
||||
}
|
||||
|
||||
identity arcfour128 {
|
||||
base encryption-alg-base;
|
||||
status obsolete;
|
||||
description
|
||||
"ARCFOUR128";
|
||||
reference
|
||||
"RFC 8758:
|
||||
Deprecating RC4 in Secure Shell (SSH)";
|
||||
}
|
||||
|
||||
identity arcfour256 {
|
||||
base encryption-alg-base;
|
||||
status obsolete;
|
||||
description
|
||||
"ARCFOUR256";
|
||||
reference
|
||||
"RFC 8758:
|
||||
Deprecating RC4 in Secure Shell (SSH)";
|
||||
}
|
||||
|
||||
identity aes128-ctr {
|
||||
base encryption-alg-base;
|
||||
status deprecated;
|
||||
description
|
||||
"AES128-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity aes192-ctr {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"AES192-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity aes256-ctr {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"AES256-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity triple-des-ctr { // YANG IDs cannot begin with a number
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"3DES-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity blowfish-ctr {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"BLOWFISH-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity twofish128-ctr {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"TWOFISH128-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity twofish192-ctr {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"TWOFISH192-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity twofish256-ctr {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"TWOFISH256-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity serpent128-ctr {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"SERPENT128-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity serpent192-ctr {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"SERPENT192-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity serpent256-ctr {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"SERPENT256-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity idea-ctr {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"IDEA-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity cast128-ctr {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"CAST128-CTR";
|
||||
reference
|
||||
"RFC 4344:
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes";
|
||||
}
|
||||
|
||||
identity aead-aes-128-gcm {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"AEAD_AES_128_GCM";
|
||||
reference
|
||||
"RFC 5647:
|
||||
AES Galois Counter Mode for the
|
||||
Secure Shell Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity aead-aes-256-gcm {
|
||||
base encryption-alg-base;
|
||||
description
|
||||
"AEAD_AES_256_GCM";
|
||||
reference
|
||||
"RFC 5647:
|
||||
AES Galois Counter Mode for the
|
||||
Secure Shell Transport Layer Protocol";
|
||||
}
|
||||
|
||||
// Protocol-accessible Nodes
|
||||
|
||||
container supported-algorithms {
|
||||
config false;
|
||||
description
|
||||
"A container for a list of encryption algorithms
|
||||
supported by the server.";
|
||||
leaf-list supported-algorithm {
|
||||
type encryption-algorithm-ref;
|
||||
description
|
||||
"A encryption algorithm supported by the server.";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
2217
modules/iana-ssh-key-exchange-algs@2022-06-16.yang
Normal file
2217
modules/iana-ssh-key-exchange-algs@2022-06-16.yang
Normal file
File diff suppressed because it is too large
Load diff
162
modules/iana-ssh-mac-algs@2022-06-16.yang
Normal file
162
modules/iana-ssh-mac-algs@2022-06-16.yang
Normal file
|
@ -0,0 +1,162 @@
|
|||
module iana-ssh-mac-algs {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:iana-ssh-mac-algs";
|
||||
prefix sshma;
|
||||
|
||||
organization
|
||||
"Internet Assigned Numbers Authority (IANA)";
|
||||
|
||||
contact
|
||||
"Postal: ICANN
|
||||
12025 Waterfront Drive, Suite 300
|
||||
Los Angeles, CA 90094-2536
|
||||
United States of America
|
||||
Tel: +1 310 301 5800
|
||||
Email: iana@iana.org";
|
||||
|
||||
description
|
||||
"This module defines identities for the MAC algorithms
|
||||
defined in the 'MAC Algorithm Names' sub-registry of the
|
||||
'Secure Shell (SSH) Protocol Parameters' registry maintained
|
||||
by IANA.
|
||||
|
||||
Copyright (c) 2022 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 Revised
|
||||
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).
|
||||
|
||||
The initial version of this YANG module is part of RFC EEEE
|
||||
(https://www.rfc-editor.org/info/rfcEEEE); see the RFC
|
||||
itself for full legal notices.";
|
||||
|
||||
revision 2022-06-16 {
|
||||
description
|
||||
"Reflects contents of the MAC algorithms registry on
|
||||
June 16, 2022.";
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
|
||||
// Typedefs
|
||||
|
||||
typedef mac-algorithm-ref {
|
||||
type identityref {
|
||||
base "mac-alg-base";
|
||||
}
|
||||
description
|
||||
"A reference to a SSH mac algorithm identifier.";
|
||||
}
|
||||
|
||||
// Identities
|
||||
|
||||
identity mac-alg-base {
|
||||
description
|
||||
"Base identity used to identify message authentication
|
||||
code (MAC) algorithms.";
|
||||
}
|
||||
|
||||
identity hmac-sha1 {
|
||||
base mac-alg-base;
|
||||
description
|
||||
"HMAC-SHA1";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity hmac-sha1-96 {
|
||||
base mac-alg-base;
|
||||
description
|
||||
"HMAC-SHA1-96";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity hmac-md5 {
|
||||
base mac-alg-base;
|
||||
description
|
||||
"HMAC-MD5";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity hmac-md5-96 {
|
||||
base mac-alg-base;
|
||||
description
|
||||
"HMAC-MD5-96";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity none {
|
||||
base mac-alg-base;
|
||||
description
|
||||
"NONE";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity aead-aes-128-gcm {
|
||||
base mac-alg-base;
|
||||
description
|
||||
"AEAD_AES_128_GCM";
|
||||
reference
|
||||
"RFC 5647:
|
||||
AES Galois Counter Mode for the
|
||||
Secure Shell Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity aead-aes-256-gcm {
|
||||
base mac-alg-base;
|
||||
description
|
||||
"AEAD_AES_256_GCM";
|
||||
reference
|
||||
"RFC 5647:
|
||||
AES Galois Counter Mode for the
|
||||
Secure Shell Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity hmac-sha2-256 {
|
||||
base mac-alg-base;
|
||||
description
|
||||
"HMAC-SHA2-256";
|
||||
reference
|
||||
"RFC 6668:
|
||||
SHA-2 Data Integrity Verification for the
|
||||
Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity hmac-sha2-512 {
|
||||
base mac-alg-base;
|
||||
description
|
||||
"HMAC-SHA2-512";
|
||||
reference
|
||||
"RFC 6668:
|
||||
SHA-2 Data Integrity Verification for the
|
||||
Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
// Protocol-accessible Nodes
|
||||
|
||||
container supported-algorithms {
|
||||
config false;
|
||||
description
|
||||
"A container for a list of MAC algorithms
|
||||
supported by the server.";
|
||||
leaf-list supported-algorithm {
|
||||
type mac-algorithm-ref;
|
||||
description
|
||||
"A MAC algorithm supported by the server.";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
436
modules/iana-ssh-public-key-algs@2022-06-16.yang
Normal file
436
modules/iana-ssh-public-key-algs@2022-06-16.yang
Normal file
|
@ -0,0 +1,436 @@
|
|||
module iana-ssh-public-key-algs {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:iana-ssh-public-key-algs";
|
||||
prefix sshpka;
|
||||
|
||||
organization
|
||||
"Internet Assigned Numbers Authority (IANA)";
|
||||
contact
|
||||
"Postal: ICANN
|
||||
12025 Waterfront Drive, Suite 300
|
||||
Los Angeles, CA 90094-2536
|
||||
United States of America
|
||||
Tel: +1 310 301 5800
|
||||
Email: iana@iana.org";
|
||||
|
||||
description
|
||||
"This module defines identities for the public key algorithms
|
||||
defined in the 'Public Key Algorithm Names' sub-registry of the
|
||||
'Secure Shell (SSH) Protocol Parameters' registry maintained
|
||||
by IANA.
|
||||
|
||||
Copyright (c) 2022 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 Revised
|
||||
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).
|
||||
|
||||
The initial version of this YANG module is part of RFC EEEE
|
||||
(https://www.rfc-editor.org/info/rfcEEEE); see the RFC
|
||||
itself for full legal notices.";
|
||||
|
||||
revision 2022-06-16 {
|
||||
description
|
||||
"Reflects contents of the public key algorithms registry
|
||||
on June 16, 2022.";
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
|
||||
// Typedefs
|
||||
|
||||
typedef public-key-algorithm-ref {
|
||||
type identityref {
|
||||
base "public-key-alg-base";
|
||||
}
|
||||
description
|
||||
"A reference to a SSH public key algorithm identifier.";
|
||||
}
|
||||
|
||||
// Identities
|
||||
identity public-key-alg-base {
|
||||
description
|
||||
"Base identity used to identify public key algorithms.";
|
||||
}
|
||||
|
||||
identity ssh-dss {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"SSH-DSS";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity ssh-rsa {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"SSH-RSA";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity rsa-sha2-256 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"RSA-SHA2-256";
|
||||
reference
|
||||
"RFC 8332:
|
||||
Use of RSA Keys with SHA-256 and SHA-512
|
||||
in the Secure Shell (SSH) Protocol";
|
||||
}
|
||||
|
||||
identity rsa-sha2-512 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"RSA-SHA2-512";
|
||||
reference
|
||||
"RFC 8332:
|
||||
Use of RSA Keys with SHA-256 and SHA-512
|
||||
in the Secure Shell (SSH) Protocol";
|
||||
}
|
||||
|
||||
identity spki-sign-rsa {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"SPKI-SIGN-RSA";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity spki-sign-dss {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"SPKI-SIGN-DSS";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity pgp-sign-rsa {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"PGP-SIGN-RSA";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity pgp-sign-dss {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"PGP-SIGN-DSS";
|
||||
reference
|
||||
"RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity null {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"NULL";
|
||||
reference
|
||||
"RFC 4462:
|
||||
Generic Security Service Application Program Interface
|
||||
(GSS-API) Authentication and Key Exchange for the
|
||||
Secure Shell (SSH) Protocol";
|
||||
}
|
||||
|
||||
identity ecdsa-sha2-nistp256 {
|
||||
base public-key-alg-base;
|
||||
status deprecated;
|
||||
description
|
||||
"ECDSA-SHA2-NISTP256 (secp256r1)";
|
||||
reference
|
||||
"RFC 5656:
|
||||
Elliptic Curve Algorithm Integration in the
|
||||
Secure Shell Transport Layer";
|
||||
}
|
||||
|
||||
identity ecdsa-sha2-nistp384 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-NISTP384 (secp384r1)";
|
||||
reference
|
||||
"RFC 5656:
|
||||
Elliptic Curve Algorithm Integration in the
|
||||
Secure Shell Transport Layer";
|
||||
}
|
||||
|
||||
identity ecdsa-sha2-nistp521 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-NISTP521 (secp521r1)";
|
||||
reference
|
||||
"RFC 5656:
|
||||
Elliptic Curve Algorithm Integration in the
|
||||
Secure Shell Transport Layer";
|
||||
}
|
||||
|
||||
identity ecdsa-sha2-1.3.132.0.1 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-1.3.132.0.1 (nistk163, sect163k1)";
|
||||
reference
|
||||
"RFC 5656:
|
||||
Elliptic Curve Algorithm Integration in the
|
||||
Secure Shell Transport Layer";
|
||||
}
|
||||
|
||||
identity ecdsa-sha2-1.2.840.10045.3.1.1 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-1.2.840.10045.3.1.1 (nistp192, secp192r1)";
|
||||
reference
|
||||
"RFC 5656:
|
||||
Elliptic Curve Algorithm Integration in the
|
||||
Secure Shell Transport Layer";
|
||||
}
|
||||
|
||||
identity ecdsa-sha2-1.3.132.0.33 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-1.3.132.0.33 (nistp224, secp224r1)";
|
||||
reference
|
||||
"RFC 5656:
|
||||
Elliptic Curve Algorithm Integration in the
|
||||
Secure Shell Transport Layer";
|
||||
}
|
||||
|
||||
identity ecdsa-sha2-1.3.132.0.26 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-1.3.132.0.26 (nistk233, sect233k1)";
|
||||
reference
|
||||
"RFC 5656:
|
||||
Elliptic Curve Algorithm Integration in the
|
||||
Secure Shell Transport Layer";
|
||||
}
|
||||
|
||||
identity ecdsa-sha2-1.3.132.0.27 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-1.3.132.0.27 (nistb233, sect233r1)";
|
||||
reference
|
||||
"RFC 5656:
|
||||
Elliptic Curve Algorithm Integration in the
|
||||
Secure Shell Transport Layer";
|
||||
}
|
||||
|
||||
identity ecdsa-sha2-1.3.132.0.16 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-1.3.132.0.16 (nistk283, sect283k1)";
|
||||
reference
|
||||
"RFC 5656:
|
||||
Elliptic Curve Algorithm Integration in the
|
||||
Secure Shell Transport Layer";
|
||||
}
|
||||
|
||||
identity ecdsa-sha2-1.3.132.0.36 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-1.3.132.0.36 (nistk409, sect409k1)";
|
||||
reference
|
||||
"RFC 5656:
|
||||
Elliptic Curve Algorithm Integration in the
|
||||
Secure Shell Transport Layer";
|
||||
}
|
||||
|
||||
identity ecdsa-sha2-1.3.132.0.37 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-1.3.132.0.37 (nistb409, sect409r1)";
|
||||
reference
|
||||
"RFC 5656:
|
||||
Elliptic Curve Algorithm Integration in the
|
||||
Secure Shell Transport Layer";
|
||||
}
|
||||
|
||||
identity ecdsa-sha2-1.3.132.0.38 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-1.3.132.0.38 (nistt571, sect571k1)";
|
||||
reference
|
||||
"RFC 5656:
|
||||
Elliptic Curve Algorithm Integration in the
|
||||
Secure Shell Transport Layer";
|
||||
}
|
||||
|
||||
identity x509v3-ssh-dss {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-SSH-DSS";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ssh-rsa {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-SSH-RSA";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-rsa2048-sha256 {
|
||||
base public-key-alg-base;
|
||||
status deprecated;
|
||||
description
|
||||
"X509V3-RSA2048-SHA256";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ecdsa-sha2-nistp256 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-ECDSA-SHA2-NISTP256 (secp256r1)";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ecdsa-sha2-nistp384 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-ECDSA-SHA2-NISTP384 (secp384r1)";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ecdsa-sha2-nistp521 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-ECDSA-SHA2-NISTP521 (secp521r1)";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ecdsa-sha2-1.3.132.0.1 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-ECDSA-SHA2-1.3.132.0.1 (nistk163, sect163k1)";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ecdsa-sha2-1.2.840.10045.3.1.1 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-ECDSA-SHA2-1.2.840.10045.3.1.1 (nistp192, secp192r1)";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ecdsa-sha2-1.3.132.0.33 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-ECDSA-SHA2-1.3.132.0.33 (nistp224, secp224r1)";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ecdsa-sha2-1.3.132.0.26 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-ECDSA-SHA2-1.3.132.0.26 (nistk233, sect233k1)";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ecdsa-sha2-1.3.132.0.27 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-ECDSA-SHA2-1.3.132.0.27 (nistb233, sect233r1)";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ecdsa-sha2-1.3.132.0.16 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-ECDSA-SHA2-1.3.132.0.16 (nistk283, sect283k1)";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ecdsa-sha2-1.3.132.0.36 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-ECDSA-SHA2-1.3.132.0.36 (nistk409, sect409k1)";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ecdsa-sha2-1.3.132.0.37 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-ECDSA-SHA2-1.3.132.0.37 (nistb409, sect409r1)";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity x509v3-ecdsa-sha2-1.3.132.0.38 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"X509V3-ECDSA-SHA2-1.3.132.0.38 (nistt571, sect571k1)";
|
||||
reference
|
||||
"RFC 6187:
|
||||
X.509v3 Certificates for Secure Shell Authentication";
|
||||
}
|
||||
|
||||
identity ssh-ed25519 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"SSH-ED25519";
|
||||
reference
|
||||
"RFC 8709:
|
||||
Ed25519 and Ed448 Public Key Algorithms for the
|
||||
Secure Shell (SSH) Protocol";
|
||||
}
|
||||
|
||||
identity ssh-ed448 {
|
||||
base public-key-alg-base;
|
||||
description
|
||||
"SSH-ED448";
|
||||
reference
|
||||
"RFC 8709:
|
||||
Ed25519 and Ed448 Public Key Algorithms for the
|
||||
Secure Shell (SSH) Protocol";
|
||||
}
|
||||
|
||||
// Protocol-accessible Nodes
|
||||
|
||||
container supported-algorithms {
|
||||
config false;
|
||||
description
|
||||
"A container for a list of public key algorithms
|
||||
supported by the server.";
|
||||
leaf-list supported-algorithm {
|
||||
type public-key-algorithm-ref;
|
||||
description
|
||||
"A public key algorithm supported by the server.";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
3777
modules/iana-tls-cipher-suite-algs@2022-06-16.yang
Normal file
3777
modules/iana-tls-cipher-suite-algs@2022-06-16.yang
Normal file
File diff suppressed because it is too large
Load diff
1091
modules/ietf-crypto-types@2023-12-28.yang
Normal file
1091
modules/ietf-crypto-types@2023-12-28.yang
Normal file
File diff suppressed because it is too large
Load diff
407
modules/ietf-keystore@2023-12-28.yang
Normal file
407
modules/ietf-keystore@2023-12-28.yang
Normal file
|
@ -0,0 +1,407 @@
|
|||
module ietf-keystore {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-keystore";
|
||||
prefix ks;
|
||||
|
||||
import ietf-netconf-acm {
|
||||
prefix nacm;
|
||||
reference
|
||||
"RFC 8341: Network Configuration Access Control Model";
|
||||
}
|
||||
|
||||
import ietf-crypto-types {
|
||||
prefix ct;
|
||||
reference
|
||||
"RFC AAAA: YANG Data Types and Groupings for Cryptography";
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: https://datatracker.ietf.org/wg/netconf
|
||||
WG List: NETCONF WG list <mailto:netconf@ietf.org>
|
||||
Author: Kent Watsen <mailto:kent+ietf@watsen.net>";
|
||||
|
||||
description
|
||||
"This module defines a 'keystore' to centralize management
|
||||
of security credentials.
|
||||
|
||||
Copyright (c) 2023 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 Revised
|
||||
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 CCCC
|
||||
(https://www.rfc-editor.org/info/rfcCCCC); see the RFC
|
||||
itself for full legal notices.
|
||||
|
||||
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL',
|
||||
'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED',
|
||||
'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document
|
||||
are to be interpreted as described in BCP 14 (RFC 2119)
|
||||
(RFC 8174) when, and only when, they appear in all
|
||||
capitals, as shown here.";
|
||||
|
||||
revision 2023-12-28 {
|
||||
description
|
||||
"Initial version";
|
||||
reference
|
||||
"RFC CCCC: A YANG Data Model for a Keystore";
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Features */
|
||||
/****************/
|
||||
|
||||
feature central-keystore-supported {
|
||||
description
|
||||
"The 'central-keystore-supported' feature indicates that
|
||||
the server supports the central keystore (i.e., fully
|
||||
implements the 'ietf-keystore' module).";
|
||||
}
|
||||
|
||||
feature inline-definitions-supported {
|
||||
description
|
||||
"The 'inline-definitions-supported' feature indicates that
|
||||
the server supports locally-defined keys.";
|
||||
}
|
||||
|
||||
feature asymmetric-keys {
|
||||
description
|
||||
"The 'asymmetric-keys' feature indicates that the server
|
||||
implements the /keystore/asymmetric-keys subtree.";
|
||||
|
||||
}
|
||||
|
||||
feature symmetric-keys {
|
||||
description
|
||||
"The 'symmetric-keys' feature indicates that the server
|
||||
implements the /keystore/symmetric-keys subtree.";
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Typedefs */
|
||||
/****************/
|
||||
|
||||
typedef symmetric-key-ref {
|
||||
type leafref {
|
||||
path "/ks:keystore/ks:symmetric-keys/ks:symmetric-key"
|
||||
+ "/ks:name";
|
||||
}
|
||||
description
|
||||
"This typedef enables modules to easily define a reference
|
||||
to a symmetric key stored in the central keystore.";
|
||||
}
|
||||
|
||||
typedef asymmetric-key-ref {
|
||||
type leafref {
|
||||
path "/ks:keystore/ks:asymmetric-keys/ks:asymmetric-key"
|
||||
+ "/ks:name";
|
||||
}
|
||||
description
|
||||
"This typedef enables modules to easily define a reference
|
||||
to an asymmetric key stored in the central keystore.";
|
||||
}
|
||||
|
||||
/*****************/
|
||||
/* Groupings */
|
||||
/*****************/
|
||||
|
||||
grouping encrypted-by-grouping {
|
||||
description
|
||||
"A grouping that defines a 'choice' statement that can be
|
||||
augmented into the 'encrypted-by' node, present in the
|
||||
'symmetric-key-grouping' and 'asymmetric-key-pair-grouping'
|
||||
groupings defined in RFC AAAA, enabling references to keys
|
||||
in the central keystore.";
|
||||
choice encrypted-by {
|
||||
nacm:default-deny-write;
|
||||
mandatory true;
|
||||
description
|
||||
"A choice amongst other symmetric or asymmetric keys.";
|
||||
case symmetric-key-ref {
|
||||
if-feature "central-keystore-supported";
|
||||
if-feature "symmetric-keys";
|
||||
leaf symmetric-key-ref {
|
||||
type ks:symmetric-key-ref;
|
||||
description
|
||||
"Identifies the symmetric key used to encrypt the
|
||||
associated key.";
|
||||
}
|
||||
}
|
||||
case asymmetric-key-ref {
|
||||
if-feature "central-keystore-supported";
|
||||
if-feature "asymmetric-keys";
|
||||
leaf asymmetric-key-ref {
|
||||
type ks:asymmetric-key-ref;
|
||||
description
|
||||
"Identifies the asymmetric key whose public key
|
||||
encrypted the associated key.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *-ref groupings
|
||||
|
||||
grouping asymmetric-key-certificate-ref-grouping {
|
||||
description
|
||||
"Grouping for the reference to a certificate associated
|
||||
with an asymmetric key stored in the central keystore.";
|
||||
leaf asymmetric-key {
|
||||
nacm:default-deny-write;
|
||||
if-feature "central-keystore-supported";
|
||||
if-feature "asymmetric-keys";
|
||||
type ks:asymmetric-key-ref;
|
||||
must '../certificate';
|
||||
description
|
||||
"A reference to an asymmetric key in the keystore.";
|
||||
}
|
||||
leaf certificate {
|
||||
nacm:default-deny-write;
|
||||
type leafref {
|
||||
path "/ks:keystore/ks:asymmetric-keys/ks:asymmetric-key"
|
||||
+ "[ks:name = current()/../asymmetric-key]/"
|
||||
+ "ks:certificates/ks:certificate/ks:name";
|
||||
}
|
||||
must '../asymmetric-key';
|
||||
description
|
||||
"A reference to a specific certificate of the
|
||||
asymmetric key in the keystore.";
|
||||
}
|
||||
}
|
||||
|
||||
// inline-or-keystore-* groupings
|
||||
|
||||
grouping inline-or-keystore-symmetric-key-grouping {
|
||||
description
|
||||
"A grouping for the configuration of a symmetric key. The
|
||||
symmetric key may be defined inline or as a reference to
|
||||
a symmetric key stored in the central keystore.
|
||||
|
||||
Servers that do not define the 'central-keystore-supported'
|
||||
feature SHOULD augment in custom 'case' statements enabling
|
||||
references to alternate keystore locations.";
|
||||
choice inline-or-keystore {
|
||||
nacm:default-deny-write;
|
||||
mandatory true;
|
||||
description
|
||||
"A choice between an inlined definition and a definition
|
||||
that exists in the keystore.";
|
||||
case inline {
|
||||
if-feature "inline-definitions-supported";
|
||||
container inline-definition {
|
||||
description
|
||||
"Container to hold the local key definition.";
|
||||
uses ct:symmetric-key-grouping;
|
||||
}
|
||||
}
|
||||
case central-keystore {
|
||||
if-feature "central-keystore-supported";
|
||||
if-feature "symmetric-keys";
|
||||
leaf central-keystore-reference {
|
||||
type ks:symmetric-key-ref;
|
||||
description
|
||||
"A reference to an symmetric key that exists in
|
||||
the central keystore.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping inline-or-keystore-asymmetric-key-grouping {
|
||||
description
|
||||
"A grouping for the configuration of an asymmetric key. The
|
||||
asymmetric key may be defined inline or as a reference to
|
||||
an asymmetric key stored in the central keystore.
|
||||
|
||||
Servers that do not define the 'central-keystore-supported'
|
||||
feature SHOULD augment in custom 'case' statements enabling
|
||||
references to alternate keystore locations.";
|
||||
choice inline-or-keystore {
|
||||
nacm:default-deny-write;
|
||||
mandatory true;
|
||||
description
|
||||
"A choice between an inlined definition and a definition
|
||||
that exists in the keystore.";
|
||||
case inline {
|
||||
if-feature "inline-definitions-supported";
|
||||
container inline-definition {
|
||||
description
|
||||
"Container to hold the local key definition.";
|
||||
uses ct:asymmetric-key-pair-grouping;
|
||||
}
|
||||
}
|
||||
case central-keystore {
|
||||
if-feature "central-keystore-supported";
|
||||
if-feature "asymmetric-keys";
|
||||
leaf central-keystore-reference {
|
||||
type ks:asymmetric-key-ref;
|
||||
description
|
||||
"A reference to an asymmetric key that exists in
|
||||
the central keystore. The intent is to reference
|
||||
just the asymmetric key without any regard for
|
||||
any certificates that may be associated with it.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping inline-or-keystore-asymmetric-key-with-certs-grouping {
|
||||
description
|
||||
"A grouping for the configuration of an asymmetric key and
|
||||
its associated certificates. The asymmetric key and its
|
||||
associated certificates may be defined inline or as a
|
||||
reference to an asymmetric key (and its associated
|
||||
certificates) in the central keystore.
|
||||
|
||||
Servers that do not define the 'central-keystore-supported'
|
||||
feature SHOULD augment in custom 'case' statements enabling
|
||||
references to alternate keystore locations.";
|
||||
choice inline-or-keystore {
|
||||
nacm:default-deny-write;
|
||||
mandatory true;
|
||||
description
|
||||
"A choice between an inlined definition and a definition
|
||||
that exists in the keystore.";
|
||||
case inline {
|
||||
if-feature "inline-definitions-supported";
|
||||
container inline-definition {
|
||||
description
|
||||
"Container to hold the local key definition.";
|
||||
uses ct:asymmetric-key-pair-with-certs-grouping;
|
||||
}
|
||||
}
|
||||
case central-keystore {
|
||||
if-feature "central-keystore-supported";
|
||||
if-feature "asymmetric-keys";
|
||||
leaf central-keystore-reference {
|
||||
type ks:asymmetric-key-ref;
|
||||
description
|
||||
"A reference to an asymmetric-key (and all of its
|
||||
associated certificates) in the keystore, when
|
||||
this module is implemented.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping inline-or-keystore-end-entity-cert-with-key-grouping {
|
||||
description
|
||||
"A grouping for the configuration of an asymmetric key and
|
||||
its associated end-entity certificate. The asymmetric key
|
||||
and its associated end-entity certificate may be defined
|
||||
inline or as a reference to an asymmetric key (and its
|
||||
associated end-entity certificate) in the central keystore.
|
||||
|
||||
Servers that do not define the 'central-keystore-supported'
|
||||
feature SHOULD augment in custom 'case' statements enabling
|
||||
references to alternate keystore locations.";
|
||||
choice inline-or-keystore {
|
||||
nacm:default-deny-write;
|
||||
mandatory true;
|
||||
description
|
||||
"A choice between an inlined definition and a definition
|
||||
that exists in the keystore.";
|
||||
case inline {
|
||||
if-feature "inline-definitions-supported";
|
||||
container inline-definition {
|
||||
description
|
||||
"Container to hold the local key definition.";
|
||||
uses ct:asymmetric-key-pair-with-cert-grouping;
|
||||
}
|
||||
}
|
||||
case central-keystore {
|
||||
if-feature "central-keystore-supported";
|
||||
if-feature "asymmetric-keys";
|
||||
container central-keystore-reference {
|
||||
uses asymmetric-key-certificate-ref-grouping;
|
||||
description
|
||||
"A reference to a specific certificate associated with
|
||||
an asymmetric key stored in the central keystore.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the keystore grouping
|
||||
|
||||
grouping keystore-grouping {
|
||||
description
|
||||
"Grouping definition enables use in other contexts. If ever
|
||||
done, implementations MUST augment new 'case' statements
|
||||
into the various inline-or-keystore 'choice' statements to
|
||||
supply leafrefs to the model-specific location(s).";
|
||||
container asymmetric-keys {
|
||||
nacm:default-deny-write;
|
||||
if-feature "asymmetric-keys";
|
||||
description
|
||||
"A list of asymmetric keys.";
|
||||
list asymmetric-key {
|
||||
key "name";
|
||||
description
|
||||
"An asymmetric key.";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for the asymmetric key.";
|
||||
}
|
||||
uses ct:asymmetric-key-pair-with-certs-grouping;
|
||||
}
|
||||
}
|
||||
container symmetric-keys {
|
||||
nacm:default-deny-write;
|
||||
if-feature "symmetric-keys";
|
||||
description
|
||||
"A list of symmetric keys.";
|
||||
list symmetric-key {
|
||||
key "name";
|
||||
description
|
||||
"A symmetric key.";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for the symmetric key.";
|
||||
}
|
||||
uses ct:symmetric-key-grouping;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************/
|
||||
/* Protocol accessible nodes */
|
||||
/*********************************/
|
||||
|
||||
container keystore {
|
||||
if-feature central-keystore-supported;
|
||||
description
|
||||
"A central keystore containing a list of symmetric keys and
|
||||
a list of asymmetric keys.";
|
||||
nacm:default-deny-write;
|
||||
uses keystore-grouping {
|
||||
augment "symmetric-keys/symmetric-key/key-type/encrypted-key/"
|
||||
+ "encrypted-key/encrypted-by" {
|
||||
description
|
||||
"Augments in a choice statement enabling the encrypting
|
||||
key to be any other symmetric or asymmetric key in the
|
||||
central keystore.";
|
||||
uses encrypted-by-grouping;
|
||||
}
|
||||
augment "asymmetric-keys/asymmetric-key/private-key-type/"
|
||||
+ "encrypted-private-key/encrypted-private-key/"
|
||||
+ "encrypted-by" {
|
||||
description
|
||||
"Augments in a choice statement enabling the encrypting
|
||||
key to be any other symmetric or asymmetric key in the
|
||||
central keystore.";
|
||||
uses encrypted-by-grouping;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
685
modules/ietf-netconf-server@2023-12-28.yang
Normal file
685
modules/ietf-netconf-server@2023-12-28.yang
Normal file
|
@ -0,0 +1,685 @@
|
|||
module ietf-netconf-server {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-server";
|
||||
prefix ncs;
|
||||
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
reference
|
||||
"RFC 6991: Common YANG Data Types";
|
||||
}
|
||||
|
||||
import ietf-x509-cert-to-name {
|
||||
prefix x509c2n;
|
||||
reference
|
||||
"RFC 7407: A YANG Data Model for SNMP Configuration";
|
||||
}
|
||||
|
||||
import ietf-tcp-client {
|
||||
prefix tcpc;
|
||||
reference
|
||||
"RFC DDDD: YANG Groupings for TCP Clients and TCP Servers";
|
||||
}
|
||||
|
||||
import ietf-tcp-server {
|
||||
prefix tcps;
|
||||
reference
|
||||
"RFC DDDD: YANG Groupings for TCP Clients and TCP Servers";
|
||||
}
|
||||
|
||||
import ietf-ssh-common {
|
||||
prefix sshcmn;
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
|
||||
import ietf-ssh-server {
|
||||
prefix sshs;
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
|
||||
import ietf-tls-server {
|
||||
prefix tlss;
|
||||
reference
|
||||
"RFC FFFF: YANG Groupings for TLS Clients and TLS Servers";
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: https://datatracker.ietf.org/wg/netconf
|
||||
WG List: NETCONF WG list <mailto:netconf@ietf.org>
|
||||
Author: Kent Watsen <mailto:kent+ietf@watsen.net>";
|
||||
|
||||
description
|
||||
"This module contains a collection of YANG definitions
|
||||
for configuring NETCONF servers.
|
||||
|
||||
Copyright (c) 2023 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 Revised
|
||||
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 HHHH
|
||||
(https://www.rfc-editor.org/info/rfcHHHH); see the RFC
|
||||
itself for full legal notices.
|
||||
|
||||
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL',
|
||||
'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED',
|
||||
'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document
|
||||
are to be interpreted as described in BCP 14 (RFC 2119)
|
||||
(RFC 8174) when, and only when, they appear in all
|
||||
capitals, as shown here.";
|
||||
|
||||
revision 2023-12-28 {
|
||||
description
|
||||
"Initial version";
|
||||
reference
|
||||
"RFC HHHH: NETCONF Client and Server Models";
|
||||
}
|
||||
|
||||
// Features
|
||||
|
||||
feature ssh-listen {
|
||||
description
|
||||
"The 'ssh-listen' feature indicates that the NETCONF server
|
||||
supports opening a port to accept NETCONF over SSH
|
||||
client connections.";
|
||||
reference
|
||||
"RFC 6242:
|
||||
Using the NETCONF Protocol over Secure Shell (SSH)";
|
||||
}
|
||||
|
||||
feature tls-listen {
|
||||
description
|
||||
"The 'tls-listen' feature indicates that the NETCONF server
|
||||
supports opening a port to accept NETCONF over TLS
|
||||
client connections.";
|
||||
reference
|
||||
"RFC 7589: Using the NETCONF Protocol over Transport
|
||||
Layer Security (TLS) with Mutual X.509
|
||||
Authentication";
|
||||
}
|
||||
|
||||
feature ssh-call-home {
|
||||
description
|
||||
"The 'ssh-call-home' feature indicates that the NETCONF
|
||||
server supports initiating a NETCONF over SSH call
|
||||
home connection to NETCONF clients.";
|
||||
reference
|
||||
"RFC 8071: NETCONF Call Home and RESTCONF Call Home";
|
||||
}
|
||||
|
||||
feature tls-call-home {
|
||||
description
|
||||
"The 'tls-call-home' feature indicates that the NETCONF
|
||||
server supports initiating a NETCONF over TLS call
|
||||
home connection to NETCONF clients.";
|
||||
reference
|
||||
"RFC 8071: NETCONF Call Home and RESTCONF Call Home";
|
||||
}
|
||||
|
||||
feature central-netconf-server-supported {
|
||||
description
|
||||
"The 'central-netconf-server-supported' feature indicates
|
||||
that the server supports the top-level 'netconf-server'
|
||||
node.
|
||||
|
||||
This feature is needed as some servers may want to use
|
||||
features defined in this module, which requires this
|
||||
module to be implemented, without having to support
|
||||
the top-level 'netconf-server' node.";
|
||||
}
|
||||
|
||||
// Groupings
|
||||
|
||||
grouping netconf-server-grouping {
|
||||
description
|
||||
"A reusable grouping for configuring a NETCONF server
|
||||
without any consideration for how underlying transport
|
||||
sessions are established.
|
||||
|
||||
Note that this grouping uses a fairly typical descendant
|
||||
node name such that a stack of 'uses' statements will
|
||||
have name conflicts. It is intended that the consuming
|
||||
data model will resolve the issue by wrapping the 'uses'
|
||||
statement in a container called, e.g.,
|
||||
'netconf-server-parameters'. This model purposely does
|
||||
not do this itself so as to provide maximum flexibility
|
||||
to consuming models.";
|
||||
|
||||
container client-identity-mappings {
|
||||
description
|
||||
"Specifies mappings through which NETCONF client X.509
|
||||
certificates are used to determine a NETCONF username,
|
||||
per RFC 7407.
|
||||
|
||||
For TLS-based transports, if no matching and valid
|
||||
cert-to-name list entry can be found, then the NETCONF
|
||||
server MUST close the connection, and MUST NOT accept
|
||||
NETCONF messages over it, per Section 7 in RFC 7589.
|
||||
|
||||
For SSH-based transports, a matching cert-to-name
|
||||
entry overrides the username provided by the SSH
|
||||
implementation, consistent with the second paragraph
|
||||
of Section 3 in RFC 6242.";
|
||||
reference
|
||||
"RFC 6242:
|
||||
Using the NETCONF Protocol over Secure Shell (SSH)
|
||||
RFC 7589:
|
||||
Using the NETCONF Protocol over Transport Layer
|
||||
Security (TLS) with Mutual X.509 Authentication";
|
||||
uses x509c2n:cert-to-name {
|
||||
refine "cert-to-name/fingerprint" {
|
||||
mandatory false;
|
||||
description
|
||||
"A 'fingerprint' value does not need to be specified
|
||||
when the 'cert-to-name' mapping is independent of
|
||||
fingerprint matching. A 'cert-to-name' having no
|
||||
fingerprint value will match any client certificate
|
||||
and therefore should only be present at the end of
|
||||
the user-ordered 'cert-to-name' list.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping netconf-server-listen-stack-grouping {
|
||||
description
|
||||
"A reusable grouping for configuring a NETCONF server
|
||||
'listen' protocol stack for listening on a single port.";
|
||||
choice transport {
|
||||
mandatory true;
|
||||
description
|
||||
"Selects between available transports.";
|
||||
case ssh {
|
||||
if-feature "ssh-listen";
|
||||
container ssh {
|
||||
description
|
||||
"TCP, SSH, and NETCONF configuration to listen
|
||||
for NETCONF over SSH connections.";
|
||||
container tcp-server-parameters {
|
||||
description
|
||||
"TCP-level server parameters to listen
|
||||
for NETCONF over SSH connections.";
|
||||
uses tcps:tcp-server-grouping {
|
||||
refine "local-port" {
|
||||
default "830";
|
||||
description
|
||||
"The NETCONF server will listen on the
|
||||
IANA-assigned well-known port value
|
||||
for 'netconf-ssh' (830) if no value
|
||||
is specified.";
|
||||
}
|
||||
}
|
||||
}
|
||||
container ssh-server-parameters {
|
||||
description
|
||||
"SSH-level server parameters to listen
|
||||
for NETCONF over SSH connections.";
|
||||
uses sshs:ssh-server-grouping;
|
||||
}
|
||||
container netconf-server-parameters {
|
||||
description
|
||||
"NETCONF-level server parameters to listen
|
||||
for NETCONF over SSH connections.";
|
||||
uses ncs:netconf-server-grouping {
|
||||
refine "client-identity-mappings" {
|
||||
if-feature "sshcmn:ssh-x509-certs";
|
||||
description
|
||||
"Adds in an 'if-feature' statement
|
||||
ensuring the 'client-identity-mappings'
|
||||
descendant is enabled only when SSH
|
||||
supports X.509 certificates.";
|
||||
}
|
||||
augment "client-identity-mappings" {
|
||||
description
|
||||
"Adds a flag indicating if a cert-to-name
|
||||
is required.";
|
||||
leaf mapping-required {
|
||||
type boolean;
|
||||
description
|
||||
"Indicates that the cert-to-name mapping
|
||||
is required (i.e., the SSH-level username
|
||||
is ignored).";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case tls {
|
||||
if-feature "tls-listen";
|
||||
container tls {
|
||||
description
|
||||
"TCP, TLS, and NETCONF configuration to listen
|
||||
for NETCONF over TLS connections.";
|
||||
container tcp-server-parameters {
|
||||
description
|
||||
"TCP-level server parameters to listen
|
||||
for NETCONF over TLS connections.";
|
||||
uses tcps:tcp-server-grouping {
|
||||
refine "local-port" {
|
||||
default "6513";
|
||||
description
|
||||
"The NETCONF server will listen on the
|
||||
IANA-assigned well-known port value
|
||||
for 'netconf-tls' (6513) if no value
|
||||
is specified.";
|
||||
}
|
||||
}
|
||||
}
|
||||
container tls-server-parameters {
|
||||
description
|
||||
"TLS-level server parameters to listen
|
||||
for NETCONF over TLS connections.";
|
||||
uses tlss:tls-server-grouping {
|
||||
refine "client-authentication" {
|
||||
must 'ca-certs or ee-certs';
|
||||
description
|
||||
"NETCONF/TLS servers MUST validate client
|
||||
certificates. This configures certificates
|
||||
at the socket-level (i.e. bags). More
|
||||
discriminating client-certificate checks
|
||||
SHOULD be implemented by the application.";
|
||||
reference
|
||||
"RFC 7589:
|
||||
Using the NETCONF Protocol over Transport Layer
|
||||
Security (TLS) with Mutual X.509 Authentication";
|
||||
}
|
||||
}
|
||||
}
|
||||
container netconf-server-parameters {
|
||||
description
|
||||
"NETCONF-level server parameters to listen
|
||||
for NETCONF over TLS connections.";
|
||||
uses ncs:netconf-server-grouping {
|
||||
refine "client-identity-mappings/cert-to-name" {
|
||||
min-elements 1;
|
||||
description
|
||||
"The TLS transport requires a mapping.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping netconf-server-callhome-stack-grouping {
|
||||
description
|
||||
"A reusable grouping for configuring a NETCONF server
|
||||
'call-home' protocol stack, for a single outbound
|
||||
connection.";
|
||||
choice transport {
|
||||
mandatory true;
|
||||
description
|
||||
"Selects between available transports.";
|
||||
case ssh {
|
||||
if-feature "ssh-call-home";
|
||||
container ssh {
|
||||
description
|
||||
"TCP, SSH, and NETCONF configuration to initiate
|
||||
a NETCONF over SSH Call Home connection.";
|
||||
container tcp-client-parameters {
|
||||
description
|
||||
"TCP-level client parameters to initiate a
|
||||
NETCONF over SSH Call Home connection.";
|
||||
uses tcpc:tcp-client-grouping {
|
||||
refine "remote-port" {
|
||||
default "4334";
|
||||
description
|
||||
"The NETCONF server will attempt to connect
|
||||
to the IANA-assigned well-known port for
|
||||
'netconf-ch-ssh' (4334) if no value is
|
||||
specified.";
|
||||
}
|
||||
}
|
||||
}
|
||||
container ssh-server-parameters {
|
||||
description
|
||||
"SSH-level server parameters to initiate a
|
||||
NETCONF over SSH Call Home connection.";
|
||||
uses sshs:ssh-server-grouping;
|
||||
}
|
||||
container netconf-server-parameters {
|
||||
description
|
||||
"NETCONF-level server parameters to initiate a
|
||||
NETCONF over SSH Call Home connection.";
|
||||
uses ncs:netconf-server-grouping {
|
||||
refine "client-identity-mappings" {
|
||||
if-feature "sshcmn:ssh-x509-certs";
|
||||
description
|
||||
"Adds in an 'if-feature' statement
|
||||
ensuring the 'client-identity-mappings'
|
||||
descendant is enabled only when SSH
|
||||
supports X.509 certificates.";
|
||||
}
|
||||
augment "client-identity-mappings" {
|
||||
description
|
||||
"Adds a flag indicating if a cert-to-name
|
||||
is required.";
|
||||
leaf mapping-required {
|
||||
type boolean;
|
||||
description
|
||||
"Indicates that the cert-to-name mapping
|
||||
is required (i.e., the SSH-level username
|
||||
is ignored).";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case tls {
|
||||
if-feature "tls-call-home";
|
||||
container tls {
|
||||
description
|
||||
"TCP, TLS, and NETCONF configuration to initiate
|
||||
a NETCONF over TLS Call Home connection.";
|
||||
container tcp-client-parameters {
|
||||
description
|
||||
"TCP-level client parameters to initiate a
|
||||
NETCONF over TLS Call Home connection.";
|
||||
uses tcpc:tcp-client-grouping {
|
||||
refine "remote-port" {
|
||||
default "4335";
|
||||
description
|
||||
"The NETCONF server will attempt to connect
|
||||
to the IANA-assigned well-known port for
|
||||
'netconf-ch-tls' (4335) if no value is
|
||||
specified.";
|
||||
}
|
||||
}
|
||||
}
|
||||
container tls-server-parameters {
|
||||
description
|
||||
"TLS-level server parameters to initiate a
|
||||
NETCONF over TLS Call Home connection.";
|
||||
uses tlss:tls-server-grouping {
|
||||
refine "client-authentication" {
|
||||
must 'ca-certs or ee-certs';
|
||||
description
|
||||
"NETCONF/TLS servers MUST validate client
|
||||
certificates. This configures certificates
|
||||
at the socket-level (i.e. bags). More
|
||||
discriminating client-certificate checks
|
||||
SHOULD be implemented by the application.";
|
||||
reference
|
||||
"RFC 7589:
|
||||
Using the NETCONF Protocol over Transport Layer
|
||||
Security (TLS) with Mutual X.509 Authentication";
|
||||
}
|
||||
}
|
||||
}
|
||||
container netconf-server-parameters {
|
||||
description
|
||||
"NETCONF-level server parameters to initiate a
|
||||
NETCONF over TLS Call Home connection.";
|
||||
uses ncs:netconf-server-grouping {
|
||||
refine "client-identity-mappings/cert-to-name" {
|
||||
min-elements 1;
|
||||
description
|
||||
"The TLS transport requires a mapping.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping netconf-server-app-grouping {
|
||||
description
|
||||
"A reusable grouping for configuring a NETCONF server
|
||||
application that supports both 'listen' and 'call-home'
|
||||
protocol stacks for a multiplicity of connections.";
|
||||
container listen {
|
||||
if-feature "ssh-listen or tls-listen";
|
||||
presence
|
||||
"Indicates that server-listening ports have been configured.
|
||||
This statement is present so the mandatory descendant
|
||||
nodes do not imply that this node must be configured.";
|
||||
description
|
||||
"Configures listen behavior";
|
||||
leaf idle-timeout {
|
||||
type uint16;
|
||||
units "seconds";
|
||||
default "180"; // three minutes
|
||||
description
|
||||
"Specifies the maximum number of seconds that a NETCONF
|
||||
session may remain idle. A NETCONF session will be
|
||||
dropped if it is idle for an interval longer than this
|
||||
number of seconds. If set to zero, then the server
|
||||
will never drop a session because it is idle.";
|
||||
}
|
||||
container endpoints {
|
||||
description
|
||||
"Container for a list of endpoints.";
|
||||
list endpoint {
|
||||
key "name";
|
||||
min-elements 1;
|
||||
description
|
||||
"List of endpoints to listen for NETCONF connections.";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for the NETCONF listen endpoint.";
|
||||
}
|
||||
uses netconf-server-listen-stack-grouping;
|
||||
}
|
||||
}
|
||||
}
|
||||
container call-home {
|
||||
if-feature "ssh-call-home or tls-call-home";
|
||||
presence
|
||||
"Indicates that server-initiated call home connections have
|
||||
been configured. This statement is present so the mandatory
|
||||
descendant nodes do not imply that this node must be
|
||||
configured.";
|
||||
description
|
||||
"Configures the NETCONF server to initiate the underlying
|
||||
transport connection to NETCONF clients.";
|
||||
list netconf-client {
|
||||
key "name";
|
||||
min-elements 1;
|
||||
description
|
||||
"List of NETCONF clients the NETCONF server is to
|
||||
maintain simultaneous call-home connections with.";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for the remote NETCONF client.";
|
||||
}
|
||||
container endpoints {
|
||||
description
|
||||
"Container for the list of endpoints.";
|
||||
list endpoint {
|
||||
key "name";
|
||||
min-elements 1;
|
||||
ordered-by user;
|
||||
description
|
||||
"A non-empty user-ordered list of endpoints for this
|
||||
NETCONF server to try to connect to in sequence.
|
||||
Defining more than one enables high-availability.";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for this endpoint.";
|
||||
}
|
||||
uses netconf-server-callhome-stack-grouping;
|
||||
}
|
||||
}
|
||||
container connection-type {
|
||||
description
|
||||
"Indicates the NETCONF server's preference for how the
|
||||
NETCONF connection is maintained.";
|
||||
choice connection-type {
|
||||
mandatory true;
|
||||
description
|
||||
"Selects between available connection types.";
|
||||
case persistent-connection {
|
||||
container persistent {
|
||||
presence
|
||||
"Indicates that a persistent connection is to be
|
||||
maintained.";
|
||||
description
|
||||
"Maintain a persistent connection to the NETCONF
|
||||
client. If the connection goes down, immediately
|
||||
start trying to reconnect to the NETCONF client,
|
||||
using the reconnection strategy.
|
||||
|
||||
This connection type minimizes any NETCONF client
|
||||
to NETCONF server data-transfer delay, albeit at
|
||||
the expense of holding resources longer.";
|
||||
}
|
||||
}
|
||||
case periodic-connection {
|
||||
container periodic {
|
||||
presence "Indicates that a periodic connection is
|
||||
to be maintained.";
|
||||
description
|
||||
"Periodically connect to the NETCONF client.
|
||||
|
||||
This connection type decreases resource
|
||||
utilization, albeit with increased delay in
|
||||
NETCONF client to NETCONF server interactions.
|
||||
|
||||
The NETCONF client SHOULD gracefully close the
|
||||
connection using <close-session> upon completing
|
||||
planned activities. If the NETCONF session is
|
||||
not closed gracefully, the NETCONF server MUST
|
||||
immediately attempt to reestablish the connection.
|
||||
|
||||
Connections are established at the same start
|
||||
time regardless how long the previous connection
|
||||
stayed open.
|
||||
|
||||
In the case that the previous connection is still
|
||||
active (i.e., the NETCONF client has not closed
|
||||
it yet), establishing a new connection is NOT
|
||||
RECOMMENDED.";
|
||||
leaf period {
|
||||
type uint16;
|
||||
units "minutes";
|
||||
default "60";
|
||||
description
|
||||
"Duration of time between periodic connections.";
|
||||
}
|
||||
leaf anchor-time {
|
||||
type yang:date-and-time {
|
||||
// constrained to minute-level granularity
|
||||
pattern '[0-9]{4}-(1[0-2]|0[1-9])-(0[1-9]|[1-2]'
|
||||
+ '[0-9]|3[0-1])T(0[0-9]|1[0-9]|2[0-3]):['
|
||||
+ '0-5][0-9]:00(Z|[\+\-]((1[0-3]|0[0-9]):'
|
||||
+ '([0-5][0-9])|14:00))?';
|
||||
}
|
||||
description
|
||||
"Designates a timestamp before or after which a
|
||||
series of periodic connections are determined.
|
||||
The periodic connections occur at a whole
|
||||
multiple interval from the anchor time.
|
||||
|
||||
If an 'anchor-time' is not provided, then the
|
||||
server may implicitly set it to the time when
|
||||
this configuraton is applied (e.g., on boot).
|
||||
|
||||
For example, for an anchor time is 15 minutes
|
||||
past midnight and a period interval of 24 hours,
|
||||
then a periodic connection will occur 15 minutes
|
||||
past midnight everyday.";
|
||||
}
|
||||
leaf idle-timeout {
|
||||
type uint16;
|
||||
units "seconds";
|
||||
default "180"; // three minutes
|
||||
description
|
||||
"Specifies the maximum number of seconds that
|
||||
a NETCONF session may remain idle. A NETCONF
|
||||
session will be dropped if it is idle for an
|
||||
interval longer than this number of seconds.
|
||||
If set to zero, then the server will never
|
||||
drop a session because it is idle.";
|
||||
}
|
||||
}
|
||||
} // case periodic-connection
|
||||
} // choice connection-type
|
||||
} // container connection-type
|
||||
container reconnect-strategy {
|
||||
description
|
||||
"The reconnection strategy directs how a NETCONF server
|
||||
reconnects to a NETCONF client, after discovering its
|
||||
connection to the client has dropped, even if due to a
|
||||
reboot. The NETCONF server starts with the specified
|
||||
endpoint and tries to connect to it max-attempts times
|
||||
before trying the next endpoint in the list (round
|
||||
robin).";
|
||||
leaf start-with {
|
||||
type enumeration {
|
||||
enum first-listed {
|
||||
description
|
||||
"Indicates that reconnections should start with
|
||||
the first endpoint listed.";
|
||||
}
|
||||
enum last-connected {
|
||||
description
|
||||
"Indicates that reconnections should start with
|
||||
the endpoint last connected to. If no previous
|
||||
connection has ever been established, then the
|
||||
first endpoint configured is used. NETCONF
|
||||
servers SHOULD be able to remember the last
|
||||
endpoint connected to across reboots.";
|
||||
}
|
||||
enum random-selection {
|
||||
description
|
||||
"Indicates that reconnections should start with
|
||||
a random endpoint.";
|
||||
}
|
||||
}
|
||||
default "first-listed";
|
||||
description
|
||||
"Specifies which of the NETCONF client's endpoints
|
||||
the NETCONF server should start with when trying
|
||||
to connect to the NETCONF client.";
|
||||
}
|
||||
leaf max-wait {
|
||||
type uint16 {
|
||||
range "1..max";
|
||||
}
|
||||
units "seconds";
|
||||
default "5";
|
||||
description
|
||||
"Specifies the amount of time in seconds after which,
|
||||
if the connection is not established, an endpoint
|
||||
connection attempt is considered unsuccessful.";
|
||||
}
|
||||
leaf max-attempts {
|
||||
type uint8 {
|
||||
range "1..max";
|
||||
}
|
||||
default "3";
|
||||
description
|
||||
"Specifies the number times the NETCONF server tries
|
||||
to connect to a specific endpoint before moving on
|
||||
to the next endpoint in the list (round robin).";
|
||||
}
|
||||
} // container reconnect-strategy
|
||||
} // list netconf-client
|
||||
} // container call-home
|
||||
} // grouping netconf-server-app-grouping
|
||||
|
||||
// Protocol accessible node for servers that implement this module.
|
||||
container netconf-server {
|
||||
if-feature central-netconf-server-supported;
|
||||
uses netconf-server-app-grouping;
|
||||
description
|
||||
"Top-level container for NETCONF server configuration.";
|
||||
}
|
||||
}
|
261
modules/ietf-ssh-common@2023-12-28.yang
Normal file
261
modules/ietf-ssh-common@2023-12-28.yang
Normal file
|
@ -0,0 +1,261 @@
|
|||
module ietf-ssh-common {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-ssh-common";
|
||||
prefix sshcmn;
|
||||
|
||||
import iana-ssh-encryption-algs {
|
||||
prefix sshea;
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
|
||||
import iana-ssh-key-exchange-algs {
|
||||
prefix sshkea;
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
|
||||
import iana-ssh-mac-algs {
|
||||
prefix sshma;
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
|
||||
import iana-ssh-public-key-algs {
|
||||
prefix sshpka;
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
|
||||
import ietf-crypto-types {
|
||||
prefix ct;
|
||||
reference
|
||||
"RFC AAAA: YANG Data Types and Groupings for Cryptography";
|
||||
}
|
||||
|
||||
import ietf-keystore {
|
||||
prefix ks;
|
||||
reference
|
||||
"RFC CCCC: A YANG Data Model for a Keystore";
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: https://datatracker.ietf.org/wg/netconf
|
||||
WG List: NETCONF WG list <mailto:netconf@ietf.org>
|
||||
Author: Kent Watsen <mailto:kent+ietf@watsen.net>
|
||||
Author: Gary Wu <mailto:garywu@cisco.com>";
|
||||
|
||||
description
|
||||
"This module defines a common features and groupings for
|
||||
Secure Shell (SSH).
|
||||
|
||||
Copyright (c) 2023 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 Revised
|
||||
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 EEEE
|
||||
(https://www.rfc-editor.org/info/rfcEEEE); see the RFC
|
||||
itself for full legal notices.
|
||||
|
||||
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL',
|
||||
'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED',
|
||||
'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document
|
||||
are to be interpreted as described in BCP 14 (RFC 2119)
|
||||
(RFC 8174) when, and only when, they appear in all
|
||||
capitals, as shown here.";
|
||||
|
||||
revision 2023-12-28 {
|
||||
description
|
||||
"Initial version";
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
|
||||
// Features
|
||||
|
||||
feature ssh-x509-certs {
|
||||
description
|
||||
"X.509v3 certificates are supported for SSH.";
|
||||
reference
|
||||
"RFC 6187: X.509v3 Certificates for Secure Shell
|
||||
Authentication";
|
||||
}
|
||||
|
||||
feature transport-params {
|
||||
description
|
||||
"SSH transport layer parameters are configurable.";
|
||||
}
|
||||
|
||||
feature public-key-generation {
|
||||
description
|
||||
"Indicates that the server implements the
|
||||
'generate-public-key' RPC.";
|
||||
}
|
||||
|
||||
// Groupings
|
||||
|
||||
grouping transport-params-grouping {
|
||||
description
|
||||
"A reusable grouping for SSH transport parameters.";
|
||||
reference
|
||||
"RFC 4253: The Secure Shell (SSH) Transport Layer Protocol";
|
||||
container host-key {
|
||||
description
|
||||
"Parameters regarding host key.";
|
||||
leaf-list host-key-alg {
|
||||
type identityref {
|
||||
base sshpka:public-key-alg-base;
|
||||
}
|
||||
ordered-by user;
|
||||
description
|
||||
"Acceptable host key algorithms in order of decreasing
|
||||
preference.
|
||||
|
||||
If this leaf-list is not configured (has zero elements)
|
||||
the acceptable host key algorithms are implementation-
|
||||
defined.";
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
}
|
||||
container key-exchange {
|
||||
description
|
||||
"Parameters regarding key exchange.";
|
||||
leaf-list key-exchange-alg {
|
||||
type identityref {
|
||||
base sshkea:key-exchange-alg-base;
|
||||
}
|
||||
ordered-by user;
|
||||
description
|
||||
"Acceptable key exchange algorithms in order of decreasing
|
||||
preference.
|
||||
|
||||
If this leaf-list is not configured (has zero elements)
|
||||
the acceptable key exchange algorithms are implementation
|
||||
defined.";
|
||||
}
|
||||
}
|
||||
container encryption {
|
||||
description
|
||||
"Parameters regarding encryption.";
|
||||
leaf-list encryption-alg {
|
||||
type identityref {
|
||||
base sshea:encryption-alg-base;
|
||||
}
|
||||
ordered-by user;
|
||||
description
|
||||
"Acceptable encryption algorithms in order of decreasing
|
||||
preference.
|
||||
|
||||
If this leaf-list is not configured (has zero elements)
|
||||
the acceptable encryption algorithms are implementation
|
||||
defined.";
|
||||
}
|
||||
}
|
||||
container mac {
|
||||
description
|
||||
"Parameters regarding message authentication code (MAC).";
|
||||
leaf-list mac-alg {
|
||||
type identityref {
|
||||
base sshma:mac-alg-base;
|
||||
}
|
||||
ordered-by user;
|
||||
description
|
||||
"Acceptable MAC algorithms in order of decreasing
|
||||
preference.
|
||||
|
||||
If this leaf-list is not configured (has zero elements)
|
||||
the acceptable MAC algorithms are implementation-
|
||||
defined.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Protocol-accessible Nodes
|
||||
|
||||
rpc generate-public-key {
|
||||
if-feature "public-key-generation";
|
||||
description
|
||||
"Requests the device to generate an public key using
|
||||
the specified key algorithm.";
|
||||
input {
|
||||
leaf algorithm {
|
||||
type sshpka:public-key-algorithm-ref;
|
||||
mandatory true;
|
||||
description
|
||||
"The algorithm to be used when generating the key.";
|
||||
}
|
||||
leaf num-bits {
|
||||
type uint16;
|
||||
description
|
||||
"Specifies the number of bits in the key to create.
|
||||
For RSA keys, the minimum size is 1024 bits and
|
||||
the default is 3072 bits. Generally, 3072 bits is
|
||||
considered sufficient. DSA keys must be exactly 1024
|
||||
bits as specified by FIPS 186-6. For ECDSA keys, the
|
||||
'num-bits' value determines the key length by selecting
|
||||
from one of three elliptic curve sizes: 256, 384 or
|
||||
521 bits. Attempting to use bit lengths other than
|
||||
these three values for ECDSA keys will fail. ECDSA-SK,
|
||||
Ed25519 and Ed25519-SK keys have a fixed length and
|
||||
thus the 'num-bits' value is not specified.";
|
||||
reference
|
||||
"FIPS 186-6: Digital Signature Standard (DSS)";
|
||||
}
|
||||
container private-key-encoding {
|
||||
description
|
||||
"Indicates how the private key is to be encoded.";
|
||||
choice private-key-encoding {
|
||||
mandatory true;
|
||||
description
|
||||
"A choice amongst optional private key handling.";
|
||||
case cleartext {
|
||||
if-feature "ct:cleartext-private-keys";
|
||||
leaf cleartext {
|
||||
type empty;
|
||||
description
|
||||
"Indicates that the private key is to be returned
|
||||
as a cleartext value.";
|
||||
}
|
||||
}
|
||||
case encrypted {
|
||||
if-feature "ct:encrypted-private-keys";
|
||||
container encrypted {
|
||||
description
|
||||
"Indicates that the private key is to be encrypted
|
||||
using the specified symmetric or asymmetric key.";
|
||||
uses ks:encrypted-by-grouping;
|
||||
}
|
||||
}
|
||||
case hidden {
|
||||
if-feature "ct:hidden-private-keys";
|
||||
leaf hidden {
|
||||
type empty;
|
||||
description
|
||||
"Indicates that the private key is to be hidden.
|
||||
|
||||
Unlike the 'cleartext' and 'encrypt' options, the
|
||||
key returned is a placeholder for an internally
|
||||
stored key. See the 'Support for Built-in Keys'
|
||||
section in RFC CCCC for information about hidden
|
||||
keys.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
output {
|
||||
uses ct:asymmetric-key-pair-grouping;
|
||||
}
|
||||
} // end generate-public-key
|
||||
|
||||
}
|
425
modules/ietf-ssh-server@2023-12-28.yang
Normal file
425
modules/ietf-ssh-server@2023-12-28.yang
Normal file
|
@ -0,0 +1,425 @@
|
|||
module ietf-ssh-server {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-ssh-server";
|
||||
prefix sshs;
|
||||
|
||||
import iana-crypt-hash {
|
||||
prefix ianach;
|
||||
reference
|
||||
"RFC 7317: A YANG Data Model for System Management";
|
||||
}
|
||||
|
||||
import ietf-netconf-acm {
|
||||
prefix nacm;
|
||||
reference
|
||||
"RFC 8341: Network Configuration Access Control Model";
|
||||
}
|
||||
|
||||
import ietf-crypto-types {
|
||||
prefix ct;
|
||||
reference
|
||||
"RFC AAAA: YANG Data Types and Groupings for Cryptography";
|
||||
}
|
||||
|
||||
import ietf-truststore {
|
||||
prefix ts;
|
||||
reference
|
||||
"RFC BBBB: A YANG Data Model for a Truststore";
|
||||
}
|
||||
|
||||
import ietf-keystore {
|
||||
prefix ks;
|
||||
reference
|
||||
"RFC CCCC: A YANG Data Model for a Keystore";
|
||||
}
|
||||
|
||||
import ietf-ssh-common {
|
||||
prefix sshcmn;
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: https://datatracker.ietf.org/wg/netconf
|
||||
WG List: NETCONF WG list <mailto:netconf@ietf.org>
|
||||
Author: Kent Watsen <mailto:kent+ietf@watsen.net>";
|
||||
|
||||
description
|
||||
"This module defines a reusable grouping for SSH servers that
|
||||
can be used as a basis for specific SSH server instances.
|
||||
|
||||
Copyright (c) 2023 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 Revised
|
||||
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 EEEE
|
||||
(https://www.rfc-editor.org/info/rfcEEEE); see the RFC
|
||||
itself for full legal notices.
|
||||
|
||||
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL',
|
||||
'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED',
|
||||
'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document
|
||||
are to be interpreted as described in BCP 14 (RFC 2119)
|
||||
(RFC 8174) when, and only when, they appear in all
|
||||
capitals, as shown here.";
|
||||
|
||||
revision 2023-12-28 {
|
||||
description
|
||||
"Initial version";
|
||||
reference
|
||||
"RFC EEEE: YANG Groupings for SSH Clients and SSH Servers";
|
||||
}
|
||||
|
||||
// Features
|
||||
|
||||
feature ssh-server-keepalives {
|
||||
description
|
||||
"Per socket SSH keepalive parameters are configurable for
|
||||
SSH servers on the server implementing this feature.";
|
||||
}
|
||||
|
||||
feature local-users-supported {
|
||||
description
|
||||
"Indicates that the configuration for users can be
|
||||
configured herein, as opposed to in an application
|
||||
specific location.";
|
||||
}
|
||||
|
||||
feature local-user-auth-publickey {
|
||||
if-feature "local-users-supported";
|
||||
description
|
||||
"Indicates that the 'publickey' authentication type,
|
||||
per RFC 4252, is supported for locally-defined users.
|
||||
The 'publickey' authentication type is required by
|
||||
RFC 4252, but common implementations allow it to
|
||||
be disabled.";
|
||||
reference
|
||||
"RFC 4252:
|
||||
The Secure Shell (SSH) Authentication Protocol";
|
||||
}
|
||||
|
||||
feature local-user-auth-password {
|
||||
if-feature "local-users-supported";
|
||||
description
|
||||
"Indicates that the 'password' authentication type,
|
||||
per RFC 4252, is supported for locally-defined users.";
|
||||
reference
|
||||
"RFC 4252:
|
||||
The Secure Shell (SSH) Authentication Protocol";
|
||||
}
|
||||
|
||||
feature local-user-auth-hostbased {
|
||||
if-feature "local-users-supported";
|
||||
description
|
||||
"Indicates that the 'hostbased' authentication type,
|
||||
per RFC 4252, is supported for locally-defined users.";
|
||||
reference
|
||||
"RFC 4252:
|
||||
The Secure Shell (SSH) Authentication Protocol";
|
||||
}
|
||||
|
||||
feature local-user-auth-none {
|
||||
if-feature "local-users-supported";
|
||||
description
|
||||
"Indicates that the 'none' authentication type, per
|
||||
RFC 4252, is supported. It is NOT RECOMMENDED to
|
||||
enable this feature.";
|
||||
reference
|
||||
"RFC 4252:
|
||||
The Secure Shell (SSH) Authentication Protocol";
|
||||
}
|
||||
|
||||
// Groupings
|
||||
|
||||
grouping ssh-server-grouping {
|
||||
description
|
||||
"A reusable grouping for configuring a SSH server without
|
||||
any consideration for how underlying TCP sessions are
|
||||
established.
|
||||
|
||||
Note that this grouping uses fairly typical descendant
|
||||
node names such that a nesting of 'uses' statements will
|
||||
have name conflicts. It is intended that the consuming
|
||||
data model will resolve the issue (e.g., by wrapping
|
||||
the 'uses' statement in a container called
|
||||
'ssh-server-parameters'). This model purposely does
|
||||
not do this itself so as to provide maximum flexibility
|
||||
to consuming models.";
|
||||
|
||||
container server-identity {
|
||||
nacm:default-deny-write;
|
||||
description
|
||||
"The list of host keys the SSH server will present when
|
||||
establishing a SSH connection.";
|
||||
list host-key {
|
||||
key "name";
|
||||
min-elements 1;
|
||||
ordered-by user;
|
||||
description
|
||||
"An ordered list of host keys (see RFC 4251) the SSH
|
||||
server will use to construct its ordered list of
|
||||
algorithms, when sending its SSH_MSG_KEXINIT message,
|
||||
as defined in Section 7.1 of RFC 4253.";
|
||||
reference
|
||||
"RFC 4251: The Secure Shell (SSH) Protocol Architecture
|
||||
RFC 4253: The Secure Shell (SSH) Transport Layer
|
||||
Protocol";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for this host key";
|
||||
}
|
||||
choice host-key-type {
|
||||
mandatory true;
|
||||
description
|
||||
"The type of host key being specified";
|
||||
container public-key {
|
||||
description
|
||||
"A locally-defined or referenced asymmetric key pair
|
||||
to be used for the SSH server's host key.";
|
||||
reference
|
||||
"RFC CCCC: A YANG Data Model for a Keystore";
|
||||
uses ks:inline-or-keystore-asymmetric-key-grouping {
|
||||
refine "inline-or-keystore/inline/inline-definition" {
|
||||
must 'not(public-key-format) or derived-from-or-self'
|
||||
+ '(public-key-format, "ct:ssh-public-key-format")';
|
||||
|
||||
}
|
||||
refine "inline-or-keystore/central-keystore/"
|
||||
+ "central-keystore-reference" {
|
||||
must 'not(deref(.)/../ks:public-key-format) or '
|
||||
+ 'derived-from-or-self(deref(.)/../ks:public-'
|
||||
+ 'key-format, "ct:ssh-public-key-format")';
|
||||
}
|
||||
}
|
||||
}
|
||||
container certificate {
|
||||
if-feature "sshcmn:ssh-x509-certs";
|
||||
description
|
||||
"A locally-defined or referenced end-entity
|
||||
certificate to be used for the SSH server's
|
||||
host key.";
|
||||
reference
|
||||
"RFC CCCC: A YANG Data Model for a Keystore";
|
||||
uses
|
||||
ks:inline-or-keystore-end-entity-cert-with-key-grouping{
|
||||
refine "inline-or-keystore/inline/inline-definition" {
|
||||
must 'not(public-key-format) or derived-from-or-self'
|
||||
+ '(public-key-format, "ct:subject-public-key-'
|
||||
+ 'info-format")';
|
||||
}
|
||||
refine "inline-or-keystore/central-keystore/"
|
||||
+ "central-keystore-reference/asymmetric-key" {
|
||||
must 'not(deref(.)/../ks:public-key-format) or '
|
||||
+ 'derived-from-or-self(deref(.)/../ks:public-key'
|
||||
+ '-format, "ct:subject-public-key-info-format")';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // container server-identity
|
||||
|
||||
container client-authentication {
|
||||
nacm:default-deny-write;
|
||||
description
|
||||
"Specifies how the SSH server can be configured to
|
||||
authenticate SSH clients. See RFC 4252 for a general
|
||||
discussion about SSH authentication.";
|
||||
reference
|
||||
"RFC 4252: The Secure Shell (SSH) Transport Layer";
|
||||
container users {
|
||||
if-feature "local-users-supported";
|
||||
description
|
||||
"A list of locally configured users.";
|
||||
list user {
|
||||
key "name";
|
||||
description
|
||||
"A locally configured user.
|
||||
|
||||
The server SHOULD derive the list of authentication
|
||||
'method names' returned to the SSH client from the
|
||||
descendant nodes configured herein, per Sections
|
||||
5.1 and 5.2 in RFC 4252.
|
||||
|
||||
The authentication methods are unordered. Clients
|
||||
must authenticate to all configured methods.
|
||||
Whenever a choice amongst methods arises,
|
||||
implementations SHOULD use a default ordering
|
||||
that prioritizes automation over human-interaction.";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"The 'user name' for the SSH client, as defined in
|
||||
the SSH_MSG_USERAUTH_REQUEST message in RFC 4253.";
|
||||
reference
|
||||
"RFC 4253: The Secure Shell (SSH) Transport Layer
|
||||
Protocol";
|
||||
}
|
||||
container public-keys {
|
||||
if-feature "local-user-auth-publickey";
|
||||
presence
|
||||
"Indicates that public keys have been configured.
|
||||
This statement is present so the mandatory descendant
|
||||
nodes do not imply that this node must be
|
||||
configured.";
|
||||
description
|
||||
"A set of SSH public keys may be used by the SSH
|
||||
server to authenticate this user. A user is
|
||||
authenticated if its public key is an exact
|
||||
match to a configured public key.";
|
||||
reference
|
||||
"RFC BBBB: A YANG Data Model for a Truststore";
|
||||
uses ts:inline-or-truststore-public-keys-grouping {
|
||||
refine "inline-or-truststore/inline/inline-definition/"
|
||||
+ "public-key" {
|
||||
must 'derived-from-or-self(public-key-format,'
|
||||
+ ' "ct:ssh-public-key-format")';
|
||||
}
|
||||
refine "inline-or-truststore/central-truststore/"
|
||||
+ "central-truststore-reference" {
|
||||
must 'not(deref(.)/../ts:public-key/ts:public-key-'
|
||||
+ 'format[not(derived-from-or-self(., "ct:ssh-'
|
||||
+ 'public-key-format"))])';
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf password {
|
||||
if-feature "local-user-auth-password";
|
||||
type ianach:crypt-hash;
|
||||
description
|
||||
"The password for this user.";
|
||||
}
|
||||
container hostbased {
|
||||
if-feature "local-user-auth-hostbased";
|
||||
presence
|
||||
"Indicates that hostbased [RFC4252] keys have been
|
||||
configured. This statement is present so the
|
||||
mandatory descendant nodes do not imply that this
|
||||
node must be configured.";
|
||||
description
|
||||
"A set of SSH host keys used by the SSH server to
|
||||
authenticate this user's host. A user's host is
|
||||
authenticated if its host key is an exact match
|
||||
to a configured host key.";
|
||||
reference
|
||||
"RFC 4252: The Secure Shell (SSH) Transport Layer
|
||||
RFC BBBB: A YANG Data Model for a Truststore";
|
||||
uses ts:inline-or-truststore-public-keys-grouping {
|
||||
refine "inline-or-truststore/inline/inline-definition/"
|
||||
+ "public-key" {
|
||||
must 'derived-from-or-self(public-key-format,'
|
||||
+ ' "ct:ssh-public-key-format")';
|
||||
}
|
||||
refine "inline-or-truststore/central-truststore/"
|
||||
+ "central-truststore-reference" {
|
||||
must 'not(deref(.)/../ts:public-key/ts:public-key-'
|
||||
+ 'format[not(derived-from-or-self(., "ct:ssh-'
|
||||
+ 'public-key-format"))])';
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf none {
|
||||
if-feature "local-user-auth-none";
|
||||
type empty;
|
||||
description
|
||||
"Indicates that the 'none' method is configured
|
||||
for this user.";
|
||||
reference
|
||||
"RFC 4252: The Secure Shell (SSH) Authentication
|
||||
Protocol.";
|
||||
}
|
||||
}
|
||||
} // users
|
||||
container ca-certs {
|
||||
if-feature "sshcmn:ssh-x509-certs";
|
||||
presence
|
||||
"Indicates that CA certificates have been configured.
|
||||
This statement is present so the mandatory descendant
|
||||
nodes do not imply this node must be configured.";
|
||||
description
|
||||
"A set of certificate authority (CA) certificates used by
|
||||
the SSH server to authenticate SSH client certificates.
|
||||
A client certificate is authenticated if it has a valid
|
||||
chain of trust to a configured CA certificate.";
|
||||
reference
|
||||
"RFC BBBB: A YANG Data Model for a Truststore";
|
||||
uses ts:inline-or-truststore-certs-grouping;
|
||||
}
|
||||
container ee-certs {
|
||||
if-feature "sshcmn:ssh-x509-certs";
|
||||
presence
|
||||
"Indicates that EE certificates have been configured.
|
||||
This statement is present so the mandatory descendant
|
||||
nodes do not imply this node must be configured.";
|
||||
description
|
||||
"A set of client certificates (i.e., end entity
|
||||
certificates) used by the SSH server to authenticate
|
||||
the certificates presented by SSH clients. A client
|
||||
certificate is authenticated if it is an exact match
|
||||
to a configured end-entity certificate.";
|
||||
reference
|
||||
"RFC BBBB: A YANG Data Model for a Truststore";
|
||||
uses ts:inline-or-truststore-certs-grouping;
|
||||
}
|
||||
} // container client-authentication
|
||||
|
||||
container transport-params {
|
||||
nacm:default-deny-write;
|
||||
if-feature "sshcmn:transport-params";
|
||||
description
|
||||
"Configurable parameters of the SSH transport layer.";
|
||||
uses sshcmn:transport-params-grouping;
|
||||
} // container transport-params
|
||||
|
||||
container keepalives {
|
||||
nacm:default-deny-write;
|
||||
if-feature "ssh-server-keepalives";
|
||||
presence
|
||||
"Indicates that the SSH server proactively tests the
|
||||
aliveness of the remote SSH client.";
|
||||
description
|
||||
"Configures the keep-alive policy, to proactively test
|
||||
the aliveness of the SSH client. An unresponsive SSH
|
||||
client is dropped after approximately max-wait *
|
||||
max-attempts seconds. Per Section 4 of RFC 4254,
|
||||
the SSH server SHOULD send an SSH_MSG_GLOBAL_REQUEST
|
||||
message with a purposely nonexistent 'request name'
|
||||
value (e.g., keepalive@ietf.org) and the 'want reply'
|
||||
value set to '1'.";
|
||||
reference
|
||||
"RFC 4254: The Secure Shell (SSH) Connection Protocol";
|
||||
leaf max-wait {
|
||||
type uint16 {
|
||||
range "1..max";
|
||||
}
|
||||
units "seconds";
|
||||
default "30";
|
||||
description
|
||||
"Sets the amount of time in seconds after which
|
||||
if no data has been received from the SSH client,
|
||||
a SSH-level message will be sent to test the
|
||||
aliveness of the SSH client.";
|
||||
}
|
||||
leaf max-attempts {
|
||||
type uint8;
|
||||
default "3";
|
||||
description
|
||||
"Sets the maximum number of sequential keep-alive
|
||||
messages that can fail to obtain a response from
|
||||
the SSH client before assuming the SSH client is
|
||||
no longer alive.";
|
||||
}
|
||||
}
|
||||
} // grouping ssh-server-grouping
|
||||
|
||||
}
|
326
modules/ietf-tcp-client@2023-12-28.yang
Normal file
326
modules/ietf-tcp-client@2023-12-28.yang
Normal file
|
@ -0,0 +1,326 @@
|
|||
module ietf-tcp-client {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-tcp-client";
|
||||
prefix tcpc;
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
reference
|
||||
"RFC 6991: Common YANG Data Types";
|
||||
}
|
||||
|
||||
import ietf-crypto-types {
|
||||
prefix ct;
|
||||
reference
|
||||
"RFC AAAA: YANG Data Types and Groupings for Cryptography";
|
||||
}
|
||||
|
||||
import ietf-tcp-common {
|
||||
prefix tcpcmn;
|
||||
reference
|
||||
"RFC DDDD: YANG Groupings for TCP Clients and TCP Servers";
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group and the
|
||||
IETF TCP Maintenance and Minor Extensions (TCPM) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: https://datatracker.ietf.org/wg/netconf
|
||||
https://datatracker.ietf.org/wg/tcpm
|
||||
WG List: NETCONF WG list <mailto:netconf@ietf.org>
|
||||
TCPM WG list <mailto:tcpm@ietf.org>
|
||||
Authors: Kent Watsen <mailto:kent+ietf@watsen.net>
|
||||
Michael Scharf
|
||||
<mailto:michael.scharf@hs-esslingen.de>";
|
||||
|
||||
description
|
||||
"This module defines reusable groupings for TCP clients that
|
||||
can be used as a basis for specific TCP client instances.
|
||||
|
||||
Copyright (c) 2023 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 Revised
|
||||
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 DDDD
|
||||
(https://www.rfc-editor.org/info/rfcDDDD); see the RFC
|
||||
itself for full legal notices.
|
||||
|
||||
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL',
|
||||
'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED',
|
||||
'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document
|
||||
are to be interpreted as described in BCP 14 (RFC 2119)
|
||||
(RFC 8174) when, and only when, they appear in all
|
||||
capitals, as shown here.";
|
||||
|
||||
revision 2023-12-28 {
|
||||
description
|
||||
"Initial version";
|
||||
reference
|
||||
"RFC DDDD: YANG Groupings for TCP Clients and TCP Servers";
|
||||
}
|
||||
|
||||
// Features
|
||||
|
||||
feature local-binding-supported {
|
||||
description
|
||||
"Indicates that the server supports configuring local
|
||||
bindings (i.e., the local address and local port) for
|
||||
TCP clients.";
|
||||
}
|
||||
|
||||
feature tcp-client-keepalives {
|
||||
description
|
||||
"Per socket TCP keepalive parameters are configurable for
|
||||
TCP clients on the server implementing this feature.";
|
||||
reference
|
||||
"RFC 9293: Transmission Control Protocol (TCP)";
|
||||
}
|
||||
|
||||
feature proxy-connect {
|
||||
description
|
||||
"Proxy connection configuration is configurable for
|
||||
TCP clients on the server implementing this feature.
|
||||
Currently supports SOCKS 4, SOCKS 4a, and SOCKS 5.";
|
||||
reference
|
||||
"SOCKS Proceedings:
|
||||
1992 Usenix Security Symposium.
|
||||
OpenSSH message:
|
||||
SOCKS 4A: A Simple Extension to SOCKS 4 Protocol
|
||||
https://www.openssh.com/txt/socks4a.protocol
|
||||
RFC 1928:
|
||||
SOCKS Protocol Version 5";
|
||||
}
|
||||
|
||||
feature socks5-gss-api {
|
||||
description
|
||||
"Indicates that the server, when acting as a TCP-client,
|
||||
supports authenticating to a SOCKS Version 5 proxy server
|
||||
using GSSAPI credentials.";
|
||||
reference
|
||||
"RFC 1928: SOCKS Protocol Version 5";
|
||||
}
|
||||
|
||||
feature socks5-username-password {
|
||||
description
|
||||
"Indicates that the server, when acting as a TCP-client,
|
||||
supports authenticating to a SOCKS Version 5 proxy server
|
||||
using 'username' and 'password' credentials.";
|
||||
reference
|
||||
"RFC 1928: SOCKS Protocol Version 5";
|
||||
}
|
||||
|
||||
// Groupings
|
||||
|
||||
grouping tcp-client-grouping {
|
||||
description
|
||||
"A reusable grouping for configuring a TCP client.
|
||||
|
||||
Note that this grouping uses fairly typical descendant
|
||||
node names such that a stack of 'uses' statements will
|
||||
have name conflicts. It is intended that the consuming
|
||||
data model will resolve the issue (e.g., by wrapping
|
||||
the 'uses' statement in a container called
|
||||
'tcp-client-parameters'). This model purposely does
|
||||
not do this itself so as to provide maximum flexibility
|
||||
to consuming models.";
|
||||
|
||||
leaf remote-address {
|
||||
type inet:host;
|
||||
mandatory true;
|
||||
description
|
||||
"The IP address or hostname of the remote peer to
|
||||
establish a connection with. If a domain name is
|
||||
configured, then the DNS resolution should happen on
|
||||
each connection attempt. If the DNS resolution
|
||||
results in multiple IP addresses, the IP addresses
|
||||
are tried according to local preference order until
|
||||
a connection has been established or until all IP
|
||||
addresses have failed.";
|
||||
}
|
||||
leaf remote-port {
|
||||
type inet:port-number;
|
||||
default "0";
|
||||
description
|
||||
"The IP port number for the remote peer to establish a
|
||||
connection with. An invalid default value is used
|
||||
so that importing modules may 'refine' it with the
|
||||
appropriate default port number value.";
|
||||
}
|
||||
leaf local-address {
|
||||
if-feature "local-binding-supported";
|
||||
type inet:ip-address;
|
||||
description
|
||||
"The local IP address/interface to bind to for when
|
||||
connecting to the remote peer. INADDR_ANY ('0.0.0.0') or
|
||||
INADDR6_ANY ('0:0:0:0:0:0:0:0' a.k.a. '::') MAY be used to
|
||||
explicitly indicate the implicit default, that the server
|
||||
can bind to any IPv4 or IPv6 addresses, respectively.";
|
||||
}
|
||||
leaf local-port {
|
||||
if-feature "local-binding-supported";
|
||||
type inet:port-number;
|
||||
default "0";
|
||||
description
|
||||
"The local IP port number to bind to for when connecting
|
||||
to the remote peer. The port number '0', which is the
|
||||
default value, indicates that any available local port
|
||||
number may be used.";
|
||||
}
|
||||
container proxy-server {
|
||||
if-feature "proxy-connect";
|
||||
presence
|
||||
"Indicates that a proxy connection has been configured.
|
||||
Present so that the mandatory descendant nodes do not
|
||||
imply that this node must be configured.";
|
||||
choice proxy-type {
|
||||
mandatory true;
|
||||
description
|
||||
"Selects a proxy connection protocol.";
|
||||
case socks4 {
|
||||
container socks4-parameters {
|
||||
leaf remote-address {
|
||||
type inet:ip-address;
|
||||
mandatory true;
|
||||
description
|
||||
"The IP address of the proxy server.";
|
||||
}
|
||||
leaf remote-port {
|
||||
type inet:port-number;
|
||||
default "1080";
|
||||
description
|
||||
"The IP port number for the proxy server.";
|
||||
}
|
||||
description
|
||||
"Parameters for connecting to a TCP-based proxy
|
||||
server using the SOCKS4 protocol.";
|
||||
reference
|
||||
"SOCKS, Proceedings: 1992 Usenix Security Symposium.";
|
||||
}
|
||||
}
|
||||
case socks4a {
|
||||
container socks4a-parameters {
|
||||
leaf remote-address {
|
||||
type inet:host;
|
||||
mandatory true;
|
||||
description
|
||||
"The IP address or hostname of the proxy server.";
|
||||
}
|
||||
leaf remote-port {
|
||||
type inet:port-number;
|
||||
default "1080";
|
||||
description
|
||||
"The IP port number for the proxy server.";
|
||||
}
|
||||
description
|
||||
"Parameters for connecting to a TCP-based proxy
|
||||
server using the SOCKS4a protocol.";
|
||||
reference
|
||||
"SOCKS Proceedings:
|
||||
1992 Usenix Security Symposium.
|
||||
OpenSSH message:
|
||||
SOCKS 4A: A Simple Extension to SOCKS 4 Protocol
|
||||
https://www.openssh.com/txt/socks4a.protocol";
|
||||
}
|
||||
}
|
||||
case socks5 {
|
||||
container socks5-parameters {
|
||||
leaf remote-address {
|
||||
type inet:host;
|
||||
mandatory true;
|
||||
description
|
||||
"The IP address or hostname of the proxy server.";
|
||||
}
|
||||
leaf remote-port {
|
||||
type inet:port-number;
|
||||
default "1080";
|
||||
description
|
||||
"The IP port number for the proxy server.";
|
||||
}
|
||||
container authentication-parameters {
|
||||
presence
|
||||
"Indicates that an authentication mechanism
|
||||
has been configured. Present so that the
|
||||
mandatory descendant nodes do not imply that
|
||||
this node must be configured.";
|
||||
description
|
||||
"A container for SOCKS Version 5 authentication
|
||||
mechanisms.
|
||||
|
||||
A complete list of methods is defined at:
|
||||
https://www.iana.org/assignments/socks-methods
|
||||
/socks-methods.xhtml.";
|
||||
reference
|
||||
"RFC 1928: SOCKS Protocol Version 5";
|
||||
choice auth-type {
|
||||
mandatory true;
|
||||
description
|
||||
"A choice amongst supported SOCKS Version 5
|
||||
authentication mechanisms.";
|
||||
case gss-api {
|
||||
if-feature "socks5-gss-api";
|
||||
container gss-api {
|
||||
description
|
||||
"Contains GSS-API configuration. Defines
|
||||
as an empty container to enable specific
|
||||
GSS-API configuration to be augmented in
|
||||
by future modules.";
|
||||
reference
|
||||
"RFC 1928: SOCKS Protocol Version 5
|
||||
RFC 2743: Generic Security Service
|
||||
Application Program Interface
|
||||
Version 2, Update 1";
|
||||
}
|
||||
}
|
||||
case username-password {
|
||||
if-feature "socks5-username-password";
|
||||
container username-password {
|
||||
leaf username {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"The 'username' value to use for client
|
||||
identification.";
|
||||
}
|
||||
uses ct:password-grouping {
|
||||
description
|
||||
"The password to be used for client
|
||||
authentication.";
|
||||
}
|
||||
description
|
||||
"Contains Username/Password configuration.";
|
||||
reference
|
||||
"RFC 1929: Username/Password Authentication
|
||||
for SOCKS V5";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
description
|
||||
"Parameters for connecting to a TCP-based proxy server
|
||||
using the SOCKS5 protocol.";
|
||||
reference
|
||||
"RFC 1928: SOCKS Protocol Version 5";
|
||||
}
|
||||
}
|
||||
}
|
||||
description
|
||||
"Proxy server settings.";
|
||||
}
|
||||
|
||||
uses tcpcmn:tcp-common-grouping {
|
||||
refine "keepalives" {
|
||||
if-feature "tcp-client-keepalives";
|
||||
description
|
||||
"Add an if-feature statement so that implementations
|
||||
can choose to support TCP client keepalives.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
117
modules/ietf-tcp-common@2023-12-28.yang
Normal file
117
modules/ietf-tcp-common@2023-12-28.yang
Normal file
|
@ -0,0 +1,117 @@
|
|||
module ietf-tcp-common {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-tcp-common";
|
||||
prefix tcpcmn;
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group and the
|
||||
IETF TCP Maintenance and Minor Extensions (TCPM) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: https://datatracker.ietf.org/wg/netconf
|
||||
https://datatracker.ietf.org/wg/tcpm
|
||||
WG List: NETCONF WG list <mailto:netconf@ietf.org>
|
||||
TCPM WG list <mailto:tcpm@ietf.org>
|
||||
Authors: Kent Watsen <mailto:kent+ietf@watsen.net>
|
||||
Michael Scharf
|
||||
<mailto:michael.scharf@hs-esslingen.de>";
|
||||
|
||||
description
|
||||
"This module define a reusable 'grouping' that is common
|
||||
to both TCP-clients and TCP-servers. This grouping statement
|
||||
is used by both the 'ietf-tcp-client' and 'ietf-tcp-server'
|
||||
modules.
|
||||
|
||||
Copyright (c) 2023 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 Revised
|
||||
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 DDDD
|
||||
(https://www.rfc-editor.org/info/rfcDDDD); see the RFC
|
||||
itself for full legal notices.
|
||||
|
||||
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL',
|
||||
'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED',
|
||||
'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document
|
||||
are to be interpreted as described in BCP 14 (RFC 2119)
|
||||
(RFC 8174) when, and only when, they appear in all
|
||||
capitals, as shown here.";
|
||||
|
||||
revision 2023-12-28 {
|
||||
description
|
||||
"Initial version";
|
||||
reference
|
||||
"RFC DDDD: YANG Groupings for TCP Clients and TCP Servers";
|
||||
}
|
||||
|
||||
// Features
|
||||
|
||||
feature keepalives-supported {
|
||||
description
|
||||
"Indicates that keepalives are supported.";
|
||||
}
|
||||
|
||||
// Groupings
|
||||
|
||||
grouping tcp-common-grouping {
|
||||
description
|
||||
"A reusable grouping for configuring TCP parameters common
|
||||
to TCP connections as well as the operating system as a
|
||||
whole.";
|
||||
container keepalives {
|
||||
if-feature "keepalives-supported";
|
||||
description
|
||||
"Configures the keep-alive policy, to proactively test the
|
||||
aliveness of the TCP peer. An unresponsive TCP peer is
|
||||
dropped after approximately (idle-time + max-probes *
|
||||
probe-interval) seconds. Further guidance can be found
|
||||
in Section 2.1.5 of RFC DDDD.";
|
||||
reference
|
||||
"RFC 9293:
|
||||
Transmission Control Protocol (TCP), Section 3.8.4..";
|
||||
leaf idle-time {
|
||||
type uint16 {
|
||||
range "1..max";
|
||||
}
|
||||
units "seconds";
|
||||
default 7200;
|
||||
description
|
||||
"Sets the amount of time after which if no data has been
|
||||
received from the TCP peer, a TCP-level probe message
|
||||
will be sent to test the aliveness of the TCP peer.
|
||||
Two hours (7200 seconds) is safe value, per RFC 1122.";
|
||||
reference
|
||||
"RFC 1122:
|
||||
Requirements for Internet Hosts -- Communication Layers";
|
||||
}
|
||||
leaf max-probes {
|
||||
type uint16 {
|
||||
range "1..max";
|
||||
}
|
||||
default 9;
|
||||
description
|
||||
"Sets the maximum number of sequential keep-alive probes
|
||||
that can fail to obtain a response from the TCP peer
|
||||
before assuming the TCP peer is no longer alive.";
|
||||
}
|
||||
leaf probe-interval {
|
||||
type uint16 {
|
||||
range "1..max";
|
||||
}
|
||||
units "seconds";
|
||||
default 75;
|
||||
description
|
||||
"Sets the time interval between failed probes. The interval
|
||||
SHOULD be significantly longer than one second in order to
|
||||
avoid harm on a congested link.";
|
||||
}
|
||||
} // container keepalives
|
||||
} // grouping tcp-common-grouping
|
||||
|
||||
}
|
116
modules/ietf-tcp-server@2023-12-28.yang
Normal file
116
modules/ietf-tcp-server@2023-12-28.yang
Normal file
|
@ -0,0 +1,116 @@
|
|||
module ietf-tcp-server {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-tcp-server";
|
||||
prefix tcps;
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
reference
|
||||
"RFC 6991: Common YANG Data Types";
|
||||
}
|
||||
|
||||
import ietf-tcp-common {
|
||||
prefix tcpcmn;
|
||||
reference
|
||||
"RFC DDDD: YANG Groupings for TCP Clients and TCP Servers";
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group and the
|
||||
IETF TCP Maintenance and Minor Extensions (TCPM) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: https://datatracker.ietf.org/wg/netconf
|
||||
https://datatracker.ietf.org/wg/tcpm
|
||||
WG List: NETCONF WG list <mailto:netconf@ietf.org>
|
||||
TCPM WG list <mailto:tcpm@ietf.org>
|
||||
Authors: Kent Watsen <mailto:kent+ietf@watsen.net>
|
||||
Michael Scharf
|
||||
<mailto:michael.scharf@hs-esslingen.de>";
|
||||
|
||||
description
|
||||
"This module defines reusable groupings for TCP servers that
|
||||
can be used as a basis for specific TCP server instances.
|
||||
|
||||
Copyright (c) 2023 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 Revised
|
||||
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 DDDD
|
||||
(https://www.rfc-editor.org/info/rfcDDDD); see the RFC
|
||||
itself for full legal notices.
|
||||
|
||||
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL',
|
||||
'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED',
|
||||
'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document
|
||||
are to be interpreted as described in BCP 14 (RFC 2119)
|
||||
(RFC 8174) when, and only when, they appear in all
|
||||
capitals, as shown here.";
|
||||
|
||||
revision 2023-12-28 {
|
||||
description
|
||||
"Initial version";
|
||||
reference
|
||||
"RFC DDDD: YANG Groupings for TCP Clients and TCP Servers";
|
||||
}
|
||||
|
||||
// Features
|
||||
|
||||
feature tcp-server-keepalives {
|
||||
description
|
||||
"Per socket TCP keepalive parameters are configurable for
|
||||
TCP servers on the server implementing this feature.";
|
||||
reference
|
||||
"RFC 9293: Transmission Control Protocol (TCP)";
|
||||
}
|
||||
|
||||
// Groupings
|
||||
|
||||
grouping tcp-server-grouping {
|
||||
description
|
||||
"A reusable grouping for configuring a TCP server.
|
||||
|
||||
Note that this grouping uses fairly typical descendant
|
||||
node names such that a stack of 'uses' statements will
|
||||
have name conflicts. It is intended that the consuming
|
||||
data model will resolve the issue (e.g., by wrapping
|
||||
the 'uses' statement in a container called
|
||||
'tcp-server-parameters'). This model purposely does
|
||||
not do this itself so as to provide maximum flexibility
|
||||
to consuming models.";
|
||||
leaf local-address {
|
||||
type inet:ip-address;
|
||||
mandatory true;
|
||||
description
|
||||
"The local IP address to listen on for incoming
|
||||
TCP client connections. INADDR_ANY (0.0.0.0) or
|
||||
INADDR6_ANY (0:0:0:0:0:0:0:0 a.k.a. ::) MUST be
|
||||
used when the server is to listen on all IPv4 or
|
||||
IPv6 addresses, respectively.";
|
||||
}
|
||||
leaf local-port {
|
||||
type inet:port-number;
|
||||
default "0";
|
||||
description
|
||||
"The local port number to listen on for incoming TCP
|
||||
client connections. An invalid default value (0)
|
||||
is used (instead of 'mandatory true') so that an
|
||||
application level data model may 'refine' it with
|
||||
an application specific default port number value.";
|
||||
}
|
||||
uses tcpcmn:tcp-common-grouping {
|
||||
refine "keepalives" {
|
||||
if-feature "tcp-server-keepalives";
|
||||
description
|
||||
"Add an if-feature statement so that implementations
|
||||
can choose to support TCP server keepalives.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
316
modules/ietf-tls-common@2023-12-28.yang
Normal file
316
modules/ietf-tls-common@2023-12-28.yang
Normal file
|
@ -0,0 +1,316 @@
|
|||
module ietf-tls-common {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-tls-common";
|
||||
prefix tlscmn;
|
||||
|
||||
import iana-tls-cipher-suite-algs {
|
||||
prefix tlscsa;
|
||||
reference
|
||||
"RFC FFFF: YANG Groupings for TLS Clients and SSH Servers";
|
||||
}
|
||||
|
||||
import ietf-crypto-types {
|
||||
prefix ct;
|
||||
reference
|
||||
"RFC AAAA: YANG Data Types and Groupings for Cryptography";
|
||||
}
|
||||
|
||||
import ietf-keystore {
|
||||
prefix ks;
|
||||
reference
|
||||
"RFC CCCC: A YANG Data Model for a Keystore";
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG List: NETCONF WG list <mailto:netconf@ietf.org>
|
||||
WG Web: https://datatracker.ietf.org/wg/netconf
|
||||
Author: Kent Watsen <mailto:kent+ietf@watsen.net>
|
||||
Author: Jeff Hartley <mailto:jeff.hartley@commscope.com>
|
||||
Author: Gary Wu <mailto:garywu@cisco.com>";
|
||||
|
||||
description
|
||||
"This module defines a common features and groupings for
|
||||
Transport Layer Security (TLS).
|
||||
|
||||
Copyright (c) 2023 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 Revised
|
||||
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 FFFF
|
||||
(https://www.rfc-editor.org/info/rfcFFFF); see the RFC
|
||||
itself for full legal notices.
|
||||
|
||||
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL',
|
||||
'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED',
|
||||
'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document
|
||||
are to be interpreted as described in BCP 14 (RFC 2119)
|
||||
(RFC 8174) when, and only when, they appear in all
|
||||
capitals, as shown here.";
|
||||
|
||||
revision 2023-12-28 {
|
||||
description
|
||||
"Initial version";
|
||||
reference
|
||||
"RFC FFFF: YANG Groupings for TLS Clients and TLS Servers";
|
||||
}
|
||||
|
||||
// Features
|
||||
|
||||
feature tls10 {
|
||||
status "obsolete";
|
||||
description
|
||||
"TLS Protocol Version 1.0 is supported. TLS 1.0 is obsolete
|
||||
and thus it is NOT RECOMMENDED to enable this feature.";
|
||||
reference
|
||||
"RFC 2246: The TLS Protocol Version 1.0";
|
||||
}
|
||||
|
||||
feature tls11 {
|
||||
status "obsolete";
|
||||
description
|
||||
"TLS Protocol Version 1.1 is supported. TLS 1.1 is obsolete
|
||||
and thus it is NOT RECOMMENDED to enable this feature.";
|
||||
reference
|
||||
"RFC 4346: The Transport Layer Security (TLS) Protocol
|
||||
Version 1.1";
|
||||
}
|
||||
|
||||
feature tls12 {
|
||||
status "deprecated";
|
||||
description
|
||||
"TLS Protocol Version 1.2 is supported. TLS 1.2 is obsolete
|
||||
and thus it is NOT RECOMMENDED to enable this feature.";
|
||||
reference
|
||||
"RFC 5246: The Transport Layer Security (TLS) Protocol
|
||||
Version 1.2";
|
||||
}
|
||||
|
||||
feature tls13 {
|
||||
description
|
||||
"TLS Protocol Version 1.3 is supported.";
|
||||
reference
|
||||
"RFC 8446: The Transport Layer Security (TLS)
|
||||
Protocol Version 1.3";
|
||||
}
|
||||
|
||||
feature hello-params {
|
||||
description
|
||||
"TLS hello message parameters are configurable.";
|
||||
}
|
||||
|
||||
feature public-key-generation {
|
||||
description
|
||||
"Indicates that the server implements the
|
||||
'generate-public-key' RPC.";
|
||||
}
|
||||
|
||||
// Identities
|
||||
|
||||
identity tls-version-base {
|
||||
description
|
||||
"Base identity used to identify TLS protocol versions.";
|
||||
}
|
||||
|
||||
identity tls10 {
|
||||
if-feature "tls10";
|
||||
base tls-version-base;
|
||||
status "obsolete";
|
||||
description
|
||||
"TLS Protocol Version 1.0.";
|
||||
reference
|
||||
"RFC 2246: The TLS Protocol Version 1.0";
|
||||
}
|
||||
|
||||
identity tls11 {
|
||||
if-feature "tls11";
|
||||
base tls-version-base;
|
||||
status "obsolete";
|
||||
description
|
||||
"TLS Protocol Version 1.1.";
|
||||
reference
|
||||
"RFC 4346: The Transport Layer Security (TLS) Protocol
|
||||
Version 1.1";
|
||||
}
|
||||
|
||||
identity tls12 {
|
||||
if-feature "tls12";
|
||||
base tls-version-base;
|
||||
status "deprecated";
|
||||
description
|
||||
"TLS Protocol Version 1.2.";
|
||||
reference
|
||||
"RFC 5246: The Transport Layer Security (TLS) Protocol
|
||||
Version 1.2";
|
||||
}
|
||||
|
||||
identity tls13 {
|
||||
if-feature "tls13";
|
||||
base tls-version-base;
|
||||
description
|
||||
"TLS Protocol Version 1.3.";
|
||||
reference
|
||||
"RFC 8446: The Transport Layer Security (TLS)
|
||||
Protocol Version 1.3";
|
||||
}
|
||||
|
||||
// Typedefs
|
||||
|
||||
typedef epsk-supported-hash {
|
||||
type enumeration {
|
||||
enum sha-256 {
|
||||
description
|
||||
"The SHA-256 Hash.";
|
||||
}
|
||||
enum sha-384 {
|
||||
description
|
||||
"The SHA-384 Hash.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"As per Section 4.2.11 of RFC 8446, the hash algorithm
|
||||
supported by an instance of an External Pre-Shared
|
||||
Key (EPSK).";
|
||||
reference
|
||||
"RFC 8446: The Transport Layer Security (TLS)
|
||||
Protocol Version 1.3";
|
||||
}
|
||||
|
||||
|
||||
// Groupings
|
||||
|
||||
grouping hello-params-grouping {
|
||||
description
|
||||
"A reusable grouping for TLS hello message parameters.";
|
||||
reference
|
||||
"RFC 5246: The Transport Layer Security (TLS) Protocol
|
||||
Version 1.2
|
||||
RFC 8446: The Transport Layer Security (TLS) Protocol
|
||||
Version 1.3";
|
||||
container tls-versions {
|
||||
description
|
||||
"Parameters regarding TLS versions.";
|
||||
leaf-list tls-version {
|
||||
type identityref {
|
||||
base tls-version-base;
|
||||
}
|
||||
ordered-by user;
|
||||
description
|
||||
"Acceptable TLS protocol versions.
|
||||
|
||||
If this leaf-list is not configured (has zero elements)
|
||||
the acceptable TLS protocol versions are implementation-
|
||||
defined.";
|
||||
}
|
||||
}
|
||||
container cipher-suites {
|
||||
description
|
||||
"Parameters regarding cipher suites.";
|
||||
leaf-list cipher-suite {
|
||||
type identityref {
|
||||
base tlscsa:cipher-suite-alg-base;
|
||||
}
|
||||
ordered-by user;
|
||||
description
|
||||
"Acceptable cipher suites in order of descending
|
||||
preference. The configured host key algorithms should
|
||||
be compatible with the algorithm used by the configured
|
||||
private key. Please see Section 5 of RFC FFFF for
|
||||
valid combinations.
|
||||
|
||||
If this leaf-list is not configured (has zero elements)
|
||||
the acceptable cipher suites are implementation-
|
||||
defined.";
|
||||
reference
|
||||
"RFC FFFF: YANG Groupings for TLS Clients and TLS Servers";
|
||||
}
|
||||
}
|
||||
} // hello-params-grouping
|
||||
|
||||
rpc generate-public-key {
|
||||
if-feature "public-key-generation";
|
||||
description
|
||||
"Requests the device to generate an public key using
|
||||
the specified key algorithm.";
|
||||
input {
|
||||
leaf algorithm {
|
||||
type tlscsa:cipher-suite-algorithm-ref;
|
||||
mandatory true;
|
||||
description
|
||||
"The cipher suite algorithm that the generated key is
|
||||
to work with. Implementations derive the public key
|
||||
algorithm from the cipher suite algorithm. Example:
|
||||
cipher suite 'tls-rsa-with-aes-256-cbc-sha256' maps
|
||||
to the RSA public key.";
|
||||
}
|
||||
leaf num-bits {
|
||||
type uint16;
|
||||
description
|
||||
"Specifies the number of bits in the key to create.
|
||||
For RSA keys, the minimum size is 1024 bits and
|
||||
the default is 3072 bits. Generally, 3072 bits is
|
||||
considered sufficient. DSA keys must be exactly 1024
|
||||
bits as specified by FIPS 186-2. For elliptical
|
||||
keys, the 'num-bits' value determines the key length
|
||||
of the curve (e.g., 256, 384 or 521), where valid
|
||||
values supported by the server are conveyed via an
|
||||
unspecified mechanism. For some public algorithms,
|
||||
the keys have a fixed length and thus the 'num-bits'
|
||||
value is not specified.";
|
||||
}
|
||||
container private-key-encoding {
|
||||
description
|
||||
"Indicates how the private key is to be encoded.";
|
||||
choice private-key-encoding {
|
||||
mandatory true;
|
||||
description
|
||||
"A choice amongst optional private key handling.";
|
||||
case cleartext {
|
||||
if-feature "ct:cleartext-private-keys";
|
||||
leaf cleartext {
|
||||
type empty;
|
||||
description
|
||||
"Indicates that the private key is to be returned
|
||||
as a cleartext value.";
|
||||
}
|
||||
}
|
||||
case encrypted {
|
||||
if-feature "ct:encrypted-private-keys";
|
||||
container encrypted {
|
||||
description
|
||||
"Indicates that the key is to be encrypted using
|
||||
the specified symmetric or asymmetric key.";
|
||||
uses ks:encrypted-by-grouping;
|
||||
}
|
||||
}
|
||||
case hidden {
|
||||
if-feature "ct:hidden-private-keys";
|
||||
leaf hidden {
|
||||
type empty;
|
||||
description
|
||||
"Indicates that the private key is to be hidden.
|
||||
|
||||
Unlike the 'cleartext' and 'encrypt' options, the
|
||||
key returned is a placeholder for an internally
|
||||
stored key. See the 'Support for Built-in Keys'
|
||||
section in RFC CCCC for information about hidden
|
||||
keys.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
output {
|
||||
uses ct:asymmetric-key-pair-grouping;
|
||||
}
|
||||
} // end generate-public-key
|
||||
|
||||
}
|
527
modules/ietf-tls-server@2023-12-28.yang
Normal file
527
modules/ietf-tls-server@2023-12-28.yang
Normal file
|
@ -0,0 +1,527 @@
|
|||
module ietf-tls-server {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-tls-server";
|
||||
prefix tlss;
|
||||
|
||||
import ietf-netconf-acm {
|
||||
prefix nacm;
|
||||
reference
|
||||
"RFC 8341: Network Configuration Access Control Model";
|
||||
}
|
||||
|
||||
import ietf-crypto-types {
|
||||
prefix ct;
|
||||
reference
|
||||
"RFC AAAA: YANG Data Types and Groupings for Cryptography";
|
||||
}
|
||||
|
||||
import ietf-truststore {
|
||||
prefix ts;
|
||||
reference
|
||||
"RFC BBBB: A YANG Data Model for a Truststore";
|
||||
}
|
||||
|
||||
import ietf-keystore {
|
||||
prefix ks;
|
||||
reference
|
||||
"RFC CCCC: A YANG Data Model for a Keystore";
|
||||
}
|
||||
|
||||
import ietf-tls-common {
|
||||
prefix tlscmn;
|
||||
reference
|
||||
"RFC FFFF: YANG Groupings for TLS Clients and TLS Servers";
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG List: NETCONF WG list <mailto:netconf@ietf.org>
|
||||
WG Web: https://datatracker.ietf.org/wg/netconf
|
||||
Author: Kent Watsen <mailto:kent+ietf@watsen.net>
|
||||
Author: Jeff Hartley <mailto:jeff.hartley@commscope.com>";
|
||||
|
||||
description
|
||||
"This module defines reusable groupings for TLS servers that
|
||||
can be used as a basis for specific TLS server instances.
|
||||
|
||||
Copyright (c) 2023 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 Revised
|
||||
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 FFFF
|
||||
(https://www.rfc-editor.org/info/rfcFFFF); see the RFC
|
||||
itself for full legal notices.
|
||||
|
||||
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL',
|
||||
'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED',
|
||||
'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document
|
||||
are to be interpreted as described in BCP 14 (RFC 2119)
|
||||
(RFC 8174) when, and only when, they appear in all
|
||||
capitals, as shown here.";
|
||||
|
||||
revision 2023-12-28 {
|
||||
description
|
||||
"Initial version";
|
||||
reference
|
||||
"RFC FFFF: YANG Groupings for TLS Clients and TLS Servers";
|
||||
}
|
||||
|
||||
// Features
|
||||
|
||||
feature tls-server-keepalives {
|
||||
description
|
||||
"Per socket TLS keepalive parameters are configurable for
|
||||
TLS servers on the server implementing this feature.";
|
||||
}
|
||||
|
||||
feature server-ident-x509-cert {
|
||||
description
|
||||
"Indicates that the server supports identifying itself
|
||||
using X.509 certificates.";
|
||||
reference
|
||||
"RFC 5280:
|
||||
Internet X.509 Public Key Infrastructure Certificate
|
||||
and Certificate Revocation List (CRL) Profile";
|
||||
}
|
||||
|
||||
feature server-ident-raw-public-key {
|
||||
description
|
||||
"Indicates that the server supports identifying itself
|
||||
using raw public keys.";
|
||||
reference
|
||||
"RFC 7250:
|
||||
Using Raw Public Keys in Transport Layer Security (TLS)
|
||||
and Datagram Transport Layer Security (DTLS)";
|
||||
}
|
||||
|
||||
feature server-ident-tls12-psk {
|
||||
if-feature "tlscmn:tls12";
|
||||
description
|
||||
"Indicates that the server supports identifying itself
|
||||
using TLS-1.2 PSKs (pre-shared or pairwise-symmetric keys).";
|
||||
reference
|
||||
"RFC 4279:
|
||||
Pre-Shared Key Ciphersuites for Transport Layer Security
|
||||
(TLS)";
|
||||
}
|
||||
|
||||
feature server-ident-tls13-epsk {
|
||||
if-feature "tlscmn:tls13";
|
||||
description
|
||||
"Indicates that the server supports identifying itself
|
||||
using TLS-1.3 External PSKs (pre-shared keys).";
|
||||
reference
|
||||
"RFC 8446:
|
||||
The Transport Layer Security (TLS) Protocol Version 1.3";
|
||||
}
|
||||
|
||||
feature client-auth-supported {
|
||||
description
|
||||
"Indicates that the configuration for how to authenticate
|
||||
clients can be configured herein. TLS-level client
|
||||
authentication may not be needed when client authentication
|
||||
is expected to occur only at another protocol layer.";
|
||||
}
|
||||
|
||||
feature client-auth-x509-cert {
|
||||
description
|
||||
"Indicates that the server supports authenticating clients
|
||||
using X.509 certificates.";
|
||||
reference
|
||||
"RFC 5280:
|
||||
Internet X.509 Public Key Infrastructure Certificate
|
||||
and Certificate Revocation List (CRL) Profile";
|
||||
}
|
||||
|
||||
feature client-auth-raw-public-key {
|
||||
description
|
||||
"Indicates that the server supports authenticating clients
|
||||
using raw public keys.";
|
||||
reference
|
||||
"RFC 7250:
|
||||
Using Raw Public Keys in Transport Layer Security (TLS)
|
||||
and Datagram Transport Layer Security (DTLS)";
|
||||
}
|
||||
|
||||
feature client-auth-tls12-psk {
|
||||
description
|
||||
"Indicates that the server supports authenticating clients
|
||||
using PSKs (pre-shared or pairwise-symmetric keys).";
|
||||
reference
|
||||
"RFC 4279:
|
||||
Pre-Shared Key Ciphersuites for Transport Layer Security
|
||||
(TLS)";
|
||||
}
|
||||
|
||||
feature client-auth-tls13-epsk {
|
||||
description
|
||||
"Indicates that the server supports authenticating clients
|
||||
using TLS-1.3 External PSKs (pre-shared keys).";
|
||||
reference
|
||||
"RFC 8446:
|
||||
The Transport Layer Security (TLS) Protocol Version 1.3";
|
||||
}
|
||||
|
||||
// Groupings
|
||||
|
||||
grouping tls-server-grouping {
|
||||
description
|
||||
"A reusable grouping for configuring a TLS server without
|
||||
any consideration for how underlying TCP sessions are
|
||||
established.
|
||||
|
||||
Note that this grouping uses fairly typical descendant
|
||||
node names such that a stack of 'uses' statements will
|
||||
have name conflicts. It is intended that the consuming
|
||||
data model will resolve the issue (e.g., by wrapping
|
||||
the 'uses' statement in a container called
|
||||
'tls-server-parameters'). This model purposely does
|
||||
not do this itself so as to provide maximum flexibility
|
||||
to consuming models.";
|
||||
|
||||
container server-identity {
|
||||
nacm:default-deny-write;
|
||||
description
|
||||
"A locally-defined or referenced end-entity certificate,
|
||||
including any configured intermediate certificates, the
|
||||
TLS server will present when establishing a TLS connection
|
||||
in its Certificate message, as defined in Section 7.4.2
|
||||
in RFC 5246 and Section 4.4.2 in RFC 8446.";
|
||||
reference
|
||||
"RFC 5246: The Transport Layer Security (TLS) Protocol
|
||||
Version 1.2
|
||||
RFC 8446: The Transport Layer Security (TLS) Protocol
|
||||
Version 1.3
|
||||
RFC CCCC: A YANG Data Model for a Keystore";
|
||||
choice auth-type {
|
||||
mandatory true;
|
||||
description
|
||||
"A choice amongst authentication types, of which one must
|
||||
be enabled (via its associated 'feature') and selected.";
|
||||
case certificate {
|
||||
if-feature "server-ident-x509-cert";
|
||||
container certificate {
|
||||
description
|
||||
"Specifies the server identity using a certificate.";
|
||||
uses
|
||||
"ks:inline-or-keystore-end-entity-cert-with-key-"
|
||||
+ "grouping" {
|
||||
refine "inline-or-keystore/inline/inline-definition" {
|
||||
must 'not(public-key-format) or derived-from-or-self'
|
||||
+ '(public-key-format,' + ' "ct:subject-public-'
|
||||
+ 'key-info-format")';
|
||||
}
|
||||
refine "inline-or-keystore/central-keystore/"
|
||||
+ "central-keystore-reference/asymmetric-key" {
|
||||
must 'not(deref(.)/../ks:public-key-format) or '
|
||||
+ 'derived-from-or-self(deref(.)/../ks:public-key'
|
||||
+ '-format, "ct:subject-public-key-info-format")';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case raw-private-key {
|
||||
if-feature "server-ident-raw-public-key";
|
||||
container raw-private-key {
|
||||
description
|
||||
"Specifies the server identity using a raw
|
||||
private key.";
|
||||
uses ks:inline-or-keystore-asymmetric-key-grouping {
|
||||
refine "inline-or-keystore/inline/inline-definition" {
|
||||
must 'not(public-key-format) or derived-from-or-self'
|
||||
+ '(public-key-format,' + ' "ct:subject-public-'
|
||||
+ 'key-info-format")';
|
||||
}
|
||||
refine "inline-or-keystore/central-keystore/"
|
||||
+ "central-keystore-reference" {
|
||||
must 'not(deref(.)/../ks:public-key-format) or '
|
||||
+ 'derived-from-or-self(deref(.)/../ks:public-key'
|
||||
+ '-format, "ct:subject-public-key-info-format")';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case tls12-psk {
|
||||
if-feature "server-ident-tls12-psk";
|
||||
container tls12-psk {
|
||||
description
|
||||
"Specifies the server identity using a PSK (pre-shared
|
||||
or pairwise-symmetric key).";
|
||||
uses ks:inline-or-keystore-symmetric-key-grouping;
|
||||
leaf id-hint {
|
||||
type string;
|
||||
description
|
||||
"The key 'psk_identity_hint' value used in the TLS
|
||||
'ServerKeyExchange' message.";
|
||||
reference
|
||||
"RFC 4279: Pre-Shared Key Ciphersuites for
|
||||
Transport Layer Security (TLS)";
|
||||
}
|
||||
}
|
||||
}
|
||||
case tls13-epsk {
|
||||
if-feature "server-ident-tls13-epsk";
|
||||
container tls13-epsk {
|
||||
description
|
||||
"An External Pre-Shared Key (EPSK) is established
|
||||
or provisioned out-of-band, i.e., not from a TLS
|
||||
connection. An EPSK is a tuple of (Base Key,
|
||||
External Identity, Hash). External PSKs MUST
|
||||
NOT be imported for (D)TLS 1.2 or prior versions.
|
||||
When PSKs are provisioned out of band, the PSK
|
||||
identity and the KDF hash algorithm to be used
|
||||
with the PSK MUST also be provisioned.
|
||||
|
||||
The structure of this container is designed to
|
||||
satisfy the requirements of RFC 8446 Section
|
||||
4.2.11, the recommendations from Section 6 in
|
||||
RFC 9257, and the EPSK input fields detailed in
|
||||
Section 5.1 in RFC 9258. The base-key is based
|
||||
upon ks:inline-or-keystore-symmetric-key-grouping
|
||||
in order to provide users with flexible and
|
||||
secure storage options.";
|
||||
reference
|
||||
"RFC 8446: The Transport Layer Security (TLS)
|
||||
Protocol Version 1.3
|
||||
RFC 9257: Guidance for External Pre-Shared Key
|
||||
(PSK) Usage in TLS
|
||||
RFC 9258: Importing External Pre-Shared Keys
|
||||
(PSKs) for TLS 1.3";
|
||||
uses ks:inline-or-keystore-symmetric-key-grouping;
|
||||
leaf external-identity {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"As per Section 4.2.11 of RFC 8446, and Section 4.1
|
||||
of RFC 9257, a sequence of bytes used to identify
|
||||
an EPSK. A label for a pre-shared key established
|
||||
externally.";
|
||||
reference
|
||||
"RFC 8446: The Transport Layer Security (TLS)
|
||||
Protocol Version 1.3
|
||||
RFC 9257: Guidance for External Pre-Shared Key
|
||||
(PSK) Usage in TLS";
|
||||
}
|
||||
leaf hash {
|
||||
type tlscmn:epsk-supported-hash;
|
||||
default sha-256;
|
||||
description
|
||||
"As per Section 4.2.11 of RFC 8446, for externally
|
||||
established PSKs, the Hash algorithm MUST be set
|
||||
when the PSK is established or default to SHA-256
|
||||
if no such algorithm is defined. The server MUST
|
||||
ensure that it selects a compatible PSK (if any)
|
||||
and cipher suite. Each PSK MUST only be used
|
||||
with a single hash function.";
|
||||
reference
|
||||
"RFC 8446: The Transport Layer Security (TLS)
|
||||
Protocol Version 1.3";
|
||||
}
|
||||
leaf context {
|
||||
type string;
|
||||
description
|
||||
"Per Section 5.1 of RFC 9258, context MUST include
|
||||
the context used to determine the EPSK, if
|
||||
any exists. For example, context may include
|
||||
information about peer roles or identities
|
||||
to mitigate Selfie-style reflection attacks.
|
||||
Since the EPSK is a key derived from an external
|
||||
protocol or sequence of protocols, context MUST
|
||||
include a channel binding for the deriving
|
||||
protocols [RFC5056]. The details of this
|
||||
binding are protocol specfic and out of scope
|
||||
for this document.";
|
||||
reference
|
||||
"RFC 9258: Importing External Pre-Shared Keys
|
||||
(PSKs) for TLS 1.3";
|
||||
}
|
||||
leaf target-protocol {
|
||||
type uint16;
|
||||
description
|
||||
"As per Section 3.1 of RFC 9258, the protocol
|
||||
for which a PSK is imported for use.";
|
||||
reference
|
||||
"RFC 9258: Importing External Pre-Shared Keys
|
||||
(PSKs) for TLS 1.3";
|
||||
}
|
||||
leaf target-kdf {
|
||||
type uint16;
|
||||
description
|
||||
"As per Section 3 of RFC 9258, the KDF for
|
||||
which a PSK is imported for use.";
|
||||
reference
|
||||
"RFC 9258: Importing External Pre-Shared Keys
|
||||
(PSKs) for TLS 1.3";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // container server-identity
|
||||
|
||||
container client-authentication {
|
||||
if-feature "client-auth-supported";
|
||||
nacm:default-deny-write;
|
||||
must 'ca-certs or ee-certs or raw-public-keys or tls12-psks
|
||||
or tls13-epsks';
|
||||
presence
|
||||
"Indicates that client authentication is supported (i.e.,
|
||||
that the server will request clients send certificates).
|
||||
If not configured, the TLS server SHOULD NOT request the
|
||||
TLS clients provide authentication credentials.";
|
||||
description
|
||||
"Specifies how the TLS server can authenticate TLS clients.
|
||||
Any combination of credentials is additive and unordered.
|
||||
|
||||
Note that no configuration is required for PSK (pre-shared
|
||||
or pairwise-symmetric key) based authentication as the key
|
||||
is necessarily the same as configured in the '../server-
|
||||
identity' node.";
|
||||
container ca-certs {
|
||||
if-feature "client-auth-x509-cert";
|
||||
presence
|
||||
"Indicates that CA certificates have been configured.
|
||||
This statement is present so the mandatory descendant
|
||||
nodes do not imply that this node must be configured.";
|
||||
description
|
||||
"A set of certificate authority (CA) certificates used by
|
||||
the TLS server to authenticate TLS client certificates.
|
||||
A client certificate is authenticated if it has a valid
|
||||
chain of trust to a configured CA certificate.";
|
||||
reference
|
||||
"RFC BBBB: A YANG Data Model for a Truststore";
|
||||
uses ts:inline-or-truststore-certs-grouping;
|
||||
}
|
||||
container ee-certs {
|
||||
if-feature "client-auth-x509-cert";
|
||||
presence
|
||||
"Indicates that EE certificates have been configured.
|
||||
This statement is present so the mandatory descendant
|
||||
nodes do not imply that this node must be configured.";
|
||||
description
|
||||
"A set of client certificates (i.e., end entity
|
||||
certificates) used by the TLS server to authenticate
|
||||
certificates presented by TLS clients. A client
|
||||
certificate is authenticated if it is an exact
|
||||
match to a configured client certificate.";
|
||||
reference
|
||||
"RFC BBBB: A YANG Data Model for a Truststore";
|
||||
uses ts:inline-or-truststore-certs-grouping;
|
||||
}
|
||||
container raw-public-keys {
|
||||
if-feature "client-auth-raw-public-key";
|
||||
presence
|
||||
"Indicates that raw public keys have been configured.
|
||||
This statement is present so the mandatory descendant
|
||||
nodes do not imply that this node must be configured.";
|
||||
description
|
||||
"A set of raw public keys used by the TLS server to
|
||||
authenticate raw public keys presented by the TLS
|
||||
client. A raw public key is authenticated if it
|
||||
is an exact match to a configured raw public key.";
|
||||
reference
|
||||
"RFC BBBB: A YANG Data Model for a Truststore";
|
||||
uses ts:inline-or-truststore-public-keys-grouping {
|
||||
refine "inline-or-truststore/inline/inline-definition/"
|
||||
+ "public-key" {
|
||||
must 'derived-from-or-self(public-key-format,'
|
||||
+ ' "ct:subject-public-key-info-format")';
|
||||
}
|
||||
refine "inline-or-truststore/central-truststore/"
|
||||
+ "central-truststore-reference" {
|
||||
must 'not(deref(.)/../ts:public-key/ts:public-key-'
|
||||
+ 'format[not(derived-from-or-self(., "ct:subject-'
|
||||
+ 'public-key-info-format"))])';
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf tls12-psks {
|
||||
if-feature "client-auth-tls12-psk";
|
||||
type empty;
|
||||
description
|
||||
"Indicates that the TLS server can authenticate TLS clients
|
||||
using configured PSKs (pre-shared or pairwise-symmetric
|
||||
keys).
|
||||
|
||||
No configuration is required since the PSK value is the
|
||||
same as PSK value configured in the 'server-identity'
|
||||
node.";
|
||||
}
|
||||
leaf tls13-epsks {
|
||||
if-feature "client-auth-tls13-epsk";
|
||||
type empty;
|
||||
description
|
||||
"Indicates that the TLS 1.3 server can authenticate TLS
|
||||
clients using configured external PSKs (pre-shared keys).
|
||||
|
||||
No configuration is required since the PSK value is the
|
||||
same as PSK value configured in the 'server-identity'
|
||||
node.";
|
||||
}
|
||||
} // container client-authentication
|
||||
|
||||
container hello-params {
|
||||
nacm:default-deny-write;
|
||||
if-feature "tlscmn:hello-params";
|
||||
uses tlscmn:hello-params-grouping;
|
||||
description
|
||||
"Configurable parameters for the TLS hello message.";
|
||||
} // container hello-params
|
||||
|
||||
container keepalives {
|
||||
nacm:default-deny-write;
|
||||
if-feature "tls-server-keepalives";
|
||||
description
|
||||
"Configures the keepalive policy for the TLS server.";
|
||||
leaf peer-allowed-to-send {
|
||||
type empty;
|
||||
description
|
||||
"Indicates that the remote TLS client is allowed to send
|
||||
HeartbeatRequest messages, as defined by RFC 6520
|
||||
to this TLS server.";
|
||||
reference
|
||||
"RFC 6520: Transport Layer Security (TLS) and Datagram
|
||||
Transport Layer Security (DTLS) Heartbeat Extension";
|
||||
}
|
||||
container test-peer-aliveness {
|
||||
presence
|
||||
"Indicates that the TLS server proactively tests the
|
||||
aliveness of the remote TLS client.";
|
||||
description
|
||||
"Configures the keep-alive policy to proactively test
|
||||
the aliveness of the TLS client. An unresponsive
|
||||
TLS client is dropped after approximately max-wait
|
||||
* max-attempts seconds.";
|
||||
leaf max-wait {
|
||||
type uint16 {
|
||||
range "1..max";
|
||||
}
|
||||
units "seconds";
|
||||
default "30";
|
||||
description
|
||||
"Sets the amount of time in seconds after which if
|
||||
no data has been received from the TLS client, a
|
||||
TLS-level message will be sent to test the
|
||||
aliveness of the TLS client.";
|
||||
}
|
||||
leaf max-attempts {
|
||||
type uint8;
|
||||
default "3";
|
||||
description
|
||||
"Sets the maximum number of sequential keep-alive
|
||||
messages that can fail to obtain a response from
|
||||
the TLS client before assuming the TLS client is
|
||||
no longer alive.";
|
||||
}
|
||||
}
|
||||
} // container keepalives
|
||||
} // grouping tls-server-grouping
|
||||
|
||||
}
|
391
modules/ietf-truststore@2023-12-28.yang
Normal file
391
modules/ietf-truststore@2023-12-28.yang
Normal file
|
@ -0,0 +1,391 @@
|
|||
module ietf-truststore {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-truststore";
|
||||
prefix ts;
|
||||
|
||||
import ietf-netconf-acm {
|
||||
prefix nacm;
|
||||
reference
|
||||
"RFC 8341: Network Configuration Access Control Model";
|
||||
}
|
||||
|
||||
import ietf-crypto-types {
|
||||
prefix ct;
|
||||
reference
|
||||
"RFC AAAA: YANG Data Types and Groupings for Cryptography";
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web : https://datatracker.ietf.org/wg/netconf
|
||||
WG List : NETCONF WG list <mailto:netconf@ietf.org>
|
||||
Author : Kent Watsen <kent+ietf@watsen.net>";
|
||||
|
||||
description
|
||||
"This module defines a 'truststore' to centralize management
|
||||
of trust anchors including certificates and public keys.
|
||||
|
||||
Copyright (c) 2023 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 Revised
|
||||
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 BBBB
|
||||
(https://www.rfc-editor.org/info/rfcBBBB); see the RFC
|
||||
itself for full legal notices.
|
||||
|
||||
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL',
|
||||
'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED',
|
||||
'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document
|
||||
are to be interpreted as described in BCP 14 (RFC 2119)
|
||||
(RFC 8174) when, and only when, they appear in all
|
||||
capitals, as shown here.";
|
||||
|
||||
revision 2023-12-28 {
|
||||
description
|
||||
"Initial version";
|
||||
reference
|
||||
"RFC BBBB: A YANG Data Model for a Truststore";
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Features */
|
||||
/****************/
|
||||
|
||||
feature central-truststore-supported {
|
||||
description
|
||||
"The 'central-truststore-supported' feature indicates that
|
||||
the server supports the truststore (i.e., implements the
|
||||
'ietf-truststore' module).";
|
||||
}
|
||||
|
||||
feature inline-definitions-supported {
|
||||
description
|
||||
"The 'inline-definitions-supported' feature indicates that
|
||||
the server supports locally-defined trust anchors.";
|
||||
}
|
||||
|
||||
feature certificates {
|
||||
description
|
||||
"The 'certificates' feature indicates that the server
|
||||
implements the /truststore/certificate-bags subtree.";
|
||||
}
|
||||
|
||||
feature public-keys {
|
||||
description
|
||||
"The 'public-keys' feature indicates that the server
|
||||
implements the /truststore/public-key-bags subtree.";
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Typedefs */
|
||||
/****************/
|
||||
|
||||
typedef certificate-bag-ref {
|
||||
type leafref {
|
||||
path "/ts:truststore/ts:certificate-bags/"
|
||||
+ "ts:certificate-bag/ts:name";
|
||||
}
|
||||
description
|
||||
"This typedef defines a reference to a certificate bag
|
||||
in the central truststore.";
|
||||
}
|
||||
|
||||
typedef certificate-ref {
|
||||
type leafref {
|
||||
path "/ts:truststore/ts:certificate-bags/ts:certificate-bag"
|
||||
+ "[ts:name = current()/../certificate-bag]/"
|
||||
+ "ts:certificate/ts:name";
|
||||
}
|
||||
description
|
||||
"This typedef defines a reference to a specific certificate
|
||||
in a certificate bag in the central truststore. This typedef
|
||||
requires that there exist a sibling 'leaf' node called
|
||||
'certificate-bag' that SHOULD have the typedef
|
||||
'certificate-bag-ref'.";
|
||||
}
|
||||
|
||||
typedef public-key-bag-ref {
|
||||
type leafref {
|
||||
path "/ts:truststore/ts:public-key-bags/"
|
||||
+ "ts:public-key-bag/ts:name";
|
||||
}
|
||||
description
|
||||
"This typedef defines a reference to a public key bag
|
||||
in the central truststore.";
|
||||
}
|
||||
|
||||
typedef public-key-ref {
|
||||
type leafref {
|
||||
path "/ts:truststore/ts:public-key-bags/ts:public-key-bag"
|
||||
+ "[ts:name = current()/../public-key-bag]/"
|
||||
+ "ts:public-key/ts:name";
|
||||
}
|
||||
description
|
||||
"This typedef defines a reference to a specific public key
|
||||
in a public key bag in the truststore. This typedef
|
||||
requires that there exist a sibling 'leaf' node called
|
||||
'public-key-bag' that SHOULD have the typedef
|
||||
'public-key-bag-ref'.";
|
||||
}
|
||||
|
||||
/*****************/
|
||||
/* Groupings */
|
||||
/*****************/
|
||||
|
||||
// *-ref groupings
|
||||
|
||||
grouping certificate-ref-grouping {
|
||||
description
|
||||
"Grouping for the reference to a certificate in a
|
||||
certificate-bag in the central truststore.";
|
||||
leaf certificate-bag {
|
||||
nacm:default-deny-write;
|
||||
if-feature "central-truststore-supported";
|
||||
if-feature "certificates";
|
||||
type ts:certificate-bag-ref;
|
||||
must "../certificate";
|
||||
description
|
||||
"Reference to a certificate-bag in the truststore.";
|
||||
}
|
||||
leaf certificate {
|
||||
nacm:default-deny-write;
|
||||
type ts:certificate-ref;
|
||||
must "../certificate-bag";
|
||||
description
|
||||
"Reference to a specific certificate in the
|
||||
referenced certificate-bag.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping public-key-ref-grouping {
|
||||
description
|
||||
"Grouping for the reference to a public key in a
|
||||
public-key-bag in the central truststore.";
|
||||
leaf public-key-bag {
|
||||
nacm:default-deny-write;
|
||||
if-feature "central-truststore-supported";
|
||||
if-feature "public-keys";
|
||||
type ts:public-key-bag-ref;
|
||||
description
|
||||
"Reference of a public key bag in the truststore inlucding
|
||||
the certificate to authenticate the TLS client.";
|
||||
}
|
||||
leaf public-key {
|
||||
nacm:default-deny-write;
|
||||
type ts:public-key-ref;
|
||||
description
|
||||
"Reference to a specific public key in the
|
||||
referenced public-key-bag.";
|
||||
}
|
||||
}
|
||||
|
||||
// inline-or-truststore-* groupings
|
||||
|
||||
grouping inline-or-truststore-certs-grouping {
|
||||
description
|
||||
"A grouping for the configuration of a list of certificates.
|
||||
The list of certificate may be defined inline or as a
|
||||
reference to a certificate bag in the central truststore.
|
||||
|
||||
Servers that do not define the 'central-truststore-supported'
|
||||
feature SHOULD augment in custom 'case' statements enabling
|
||||
references to alternate truststore locations.";
|
||||
choice inline-or-truststore {
|
||||
nacm:default-deny-write;
|
||||
mandatory true;
|
||||
description
|
||||
"A choice between an inlined definition and a definition
|
||||
that exists in the truststore.";
|
||||
case inline {
|
||||
if-feature "inline-definitions-supported";
|
||||
container inline-definition {
|
||||
description
|
||||
"A container for locally configured trust anchor
|
||||
certificates.";
|
||||
list certificate {
|
||||
key "name";
|
||||
min-elements 1;
|
||||
description
|
||||
"A trust anchor certificate.";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for this certificate.";
|
||||
}
|
||||
uses ct:trust-anchor-cert-grouping {
|
||||
refine "cert-data" {
|
||||
mandatory true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case central-truststore {
|
||||
if-feature "central-truststore-supported";
|
||||
if-feature "certificates";
|
||||
leaf central-truststore-reference {
|
||||
type ts:certificate-bag-ref;
|
||||
description
|
||||
"A reference to a certificate bag that exists in the
|
||||
central truststore.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping inline-or-truststore-public-keys-grouping {
|
||||
description
|
||||
"A grouping that allows the public keys to be either
|
||||
configured locally, within the using data model, or be a
|
||||
reference to a public key bag stored in the truststore.
|
||||
|
||||
Servers that do not define the 'central-truststore-supported'
|
||||
feature SHOULD augment in custom 'case' statements enabling
|
||||
references to alternate truststore locations.";
|
||||
choice inline-or-truststore {
|
||||
nacm:default-deny-write;
|
||||
mandatory true;
|
||||
description
|
||||
"A choice between an inlined definition and a definition
|
||||
that exists in the truststore.";
|
||||
case inline {
|
||||
if-feature "inline-definitions-supported";
|
||||
container inline-definition {
|
||||
description
|
||||
"A container to hold local public key definitions.";
|
||||
list public-key {
|
||||
key "name";
|
||||
description
|
||||
"A public key definition.";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for this public key.";
|
||||
}
|
||||
uses ct:public-key-grouping;
|
||||
}
|
||||
}
|
||||
}
|
||||
case central-truststore {
|
||||
if-feature "central-truststore-supported";
|
||||
if-feature "public-keys";
|
||||
leaf central-truststore-reference {
|
||||
type ts:public-key-bag-ref;
|
||||
description
|
||||
"A reference to a bag of public keys that exists
|
||||
in the central truststore.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// the truststore grouping
|
||||
|
||||
grouping truststore-grouping {
|
||||
description
|
||||
"A grouping definition that enables use in other contexts.
|
||||
Where used, implementations MUST augment new 'case'
|
||||
statements into the various inline-or-truststore 'choice'
|
||||
statements to supply leafrefs to the model-specific
|
||||
location(s).";
|
||||
container certificate-bags {
|
||||
nacm:default-deny-write;
|
||||
if-feature "certificates";
|
||||
description
|
||||
"A collection of certificate bags.";
|
||||
list certificate-bag {
|
||||
key "name";
|
||||
description
|
||||
"A bag of certificates. Each bag of certificates SHOULD
|
||||
be for a specific purpose. For instance, one bag could
|
||||
be used to authenticate a specific set of servers, while
|
||||
another could be used to authenticate a specific set of
|
||||
clients.";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for this bag of certificates.";
|
||||
}
|
||||
leaf description {
|
||||
type string;
|
||||
description
|
||||
"A description for this bag of certificates. The
|
||||
intended purpose for the bag SHOULD be described.";
|
||||
}
|
||||
list certificate {
|
||||
key "name";
|
||||
description
|
||||
"A trust anchor certificate.";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for this certificate.";
|
||||
}
|
||||
uses ct:trust-anchor-cert-grouping {
|
||||
refine "cert-data" {
|
||||
mandatory true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
container public-key-bags {
|
||||
nacm:default-deny-write;
|
||||
if-feature "public-keys";
|
||||
description
|
||||
"A collection of public key bags.";
|
||||
list public-key-bag {
|
||||
key "name";
|
||||
description
|
||||
"A bag of public keys. Each bag of keys SHOULD be for
|
||||
a specific purpose. For instance, one bag could be used
|
||||
authenticate a specific set of servers, while another
|
||||
could be used to authenticate a specific set of clients.";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for this bag of public keys.";
|
||||
}
|
||||
leaf description {
|
||||
type string;
|
||||
description
|
||||
"A description for this bag public keys. The
|
||||
intended purpose for the bag SHOULD be described.";
|
||||
}
|
||||
list public-key {
|
||||
key "name";
|
||||
description
|
||||
"A public key.";
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary name for this public key.";
|
||||
}
|
||||
uses ct:public-key-grouping;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************/
|
||||
/* Protocol accessible nodes */
|
||||
/*********************************/
|
||||
|
||||
container truststore {
|
||||
if-feature central-truststore-supported;
|
||||
nacm:default-deny-write;
|
||||
description
|
||||
"The truststore contains bags of certificates and
|
||||
public keys.";
|
||||
uses truststore-grouping;
|
||||
}
|
||||
}
|
314
modules/ietf-x509-cert-to-name@2014-12-10.yang
Normal file
314
modules/ietf-x509-cert-to-name@2014-12-10.yang
Normal file
|
@ -0,0 +1,314 @@
|
|||
module ietf-x509-cert-to-name {
|
||||
|
||||
yang-version 1;
|
||||
|
||||
namespace
|
||||
"urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name";
|
||||
|
||||
prefix x509c2n;
|
||||
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <http://tools.ietf.org/wg/netmod/>
|
||||
WG List: <mailto:netmod@ietf.org>
|
||||
|
||||
WG Chair: Thomas Nadeau
|
||||
<mailto:tnadeau@lucidvision.com>
|
||||
|
||||
WG Chair: Juergen Schoenwaelder
|
||||
<mailto:j.schoenwaelder@jacobs-university.de>
|
||||
|
||||
Editor: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com>
|
||||
|
||||
Editor: Juergen Schoenwaelder
|
||||
<mailto:j.schoenwaelder@jacobs-university.de>";
|
||||
|
||||
description
|
||||
"This module contains a collection of YANG definitions for
|
||||
extracting a name from an X.509 certificate.
|
||||
The algorithm used to extract a name from an X.509 certificate
|
||||
was first defined in RFC 6353.
|
||||
|
||||
Copyright (c) 2014 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 7407; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model for
|
||||
the Simple Network Management Protocol (SNMP)";
|
||||
|
||||
|
||||
revision "2014-12-10" {
|
||||
description "Initial revision.";
|
||||
reference
|
||||
"RFC 7407: A YANG Data Model for SNMP Configuration";
|
||||
|
||||
}
|
||||
|
||||
|
||||
typedef tls-fingerprint {
|
||||
type yang:hex-string {
|
||||
pattern
|
||||
'([0-9a-fA-F]){2}(:([0-9a-fA-F]){2}){0,254}';
|
||||
}
|
||||
description
|
||||
"A fingerprint value that can be used to uniquely reference
|
||||
other data of potentially arbitrary length.
|
||||
|
||||
A tls-fingerprint value is composed of a 1-octet hashing
|
||||
algorithm identifier followed by the fingerprint value. The
|
||||
first octet value identifying the hashing algorithm is taken
|
||||
from the IANA 'TLS HashAlgorithm Registry' (RFC 5246). The
|
||||
remaining octets are filled using the results of the hashing
|
||||
algorithm.";
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model
|
||||
for the Simple Network Management Protocol (SNMP).
|
||||
SNMP-TLS-TM-MIB.SnmpTLSFingerprint";
|
||||
|
||||
}
|
||||
|
||||
identity cert-to-name {
|
||||
description
|
||||
"Base identity for algorithms to derive a name from a
|
||||
certificate.";
|
||||
}
|
||||
|
||||
identity specified {
|
||||
base cert-to-name;
|
||||
description
|
||||
"Directly specifies the name to be used for the certificate.
|
||||
The value of the leaf 'name' in the cert-to-name list is
|
||||
used.";
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model
|
||||
for the Simple Network Management Protocol (SNMP).
|
||||
SNMP-TLS-TM-MIB.snmpTlstmCertSpecified";
|
||||
|
||||
}
|
||||
|
||||
identity san-rfc822-name {
|
||||
base cert-to-name;
|
||||
description
|
||||
"Maps a subjectAltName's rfc822Name to a name. The local part
|
||||
of the rfc822Name is passed unaltered, but the host-part of
|
||||
the name must be passed in lowercase. For example, the
|
||||
rfc822Name field FooBar@Example.COM is mapped to name
|
||||
FooBar@example.com.";
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model
|
||||
for the Simple Network Management Protocol (SNMP).
|
||||
SNMP-TLS-TM-MIB.snmpTlstmCertSANRFC822Name";
|
||||
|
||||
}
|
||||
|
||||
identity san-dns-name {
|
||||
base cert-to-name;
|
||||
description
|
||||
"Maps a subjectAltName's dNSName to a name after first
|
||||
converting it to all lowercase (RFC 5280 does not specify
|
||||
converting to lowercase, so this involves an extra step).
|
||||
This mapping results in a 1:1 correspondence between
|
||||
subjectAltName dNSName values and the name values.";
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model
|
||||
for the Simple Network Management Protocol (SNMP).
|
||||
SNMP-TLS-TM-MIB.snmpTlstmCertSANDNSName";
|
||||
|
||||
}
|
||||
|
||||
identity san-ip-address {
|
||||
base cert-to-name;
|
||||
description
|
||||
"Maps a subjectAltName's iPAddress to a name by
|
||||
transforming the binary-encoded address as follows:
|
||||
|
||||
1) for IPv4, the value is converted into a
|
||||
decimal-dotted quad address (e.g., '192.0.2.1').
|
||||
|
||||
2) for IPv6 addresses, the value is converted into a
|
||||
32-character, all-lowercase hexadecimal string
|
||||
without any colon separators.
|
||||
|
||||
This mapping results in a 1:1 correspondence between
|
||||
subjectAltName iPAddress values and the name values.";
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model
|
||||
for the Simple Network Management Protocol (SNMP).
|
||||
SNMP-TLS-TM-MIB.snmpTlstmCertSANIpAddress";
|
||||
|
||||
}
|
||||
|
||||
identity san-any {
|
||||
base cert-to-name;
|
||||
description
|
||||
"Maps any of the following fields using the corresponding
|
||||
mapping algorithms:
|
||||
|
||||
+------------+-----------------+
|
||||
| Type | Algorithm |
|
||||
|------------+-----------------|
|
||||
| rfc822Name | san-rfc822-name |
|
||||
| dNSName | san-dns-name |
|
||||
| iPAddress | san-ip-address |
|
||||
+------------+-----------------+
|
||||
|
||||
The first matching subjectAltName value found in the
|
||||
certificate of the above types MUST be used when deriving
|
||||
the name. The mapping algorithm specified in the
|
||||
'Algorithm' column MUST be used to derive the name.
|
||||
|
||||
This mapping results in a 1:1 correspondence between
|
||||
subjectAltName values and name values. The three sub-mapping
|
||||
algorithms produced by this combined algorithm cannot produce
|
||||
conflicting results between themselves.";
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model
|
||||
for the Simple Network Management Protocol (SNMP).
|
||||
SNMP-TLS-TM-MIB.snmpTlstmCertSANAny";
|
||||
|
||||
}
|
||||
|
||||
identity common-name {
|
||||
base cert-to-name;
|
||||
description
|
||||
"Maps a certificate's CommonName to a name after converting
|
||||
it to a UTF-8 encoding. The usage of CommonNames is
|
||||
deprecated, and users are encouraged to use subjectAltName
|
||||
mapping methods instead. This mapping results in a 1:1
|
||||
correspondence between certificate CommonName values and name
|
||||
values.";
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model
|
||||
for the Simple Network Management Protocol (SNMP).
|
||||
SNMP-TLS-TM-MIB.snmpTlstmCertCommonName";
|
||||
|
||||
}
|
||||
|
||||
grouping cert-to-name {
|
||||
description
|
||||
"Defines nodes for mapping certificates to names. Modules
|
||||
that use this grouping should describe how the resulting
|
||||
name is used.";
|
||||
list cert-to-name {
|
||||
key "id";
|
||||
description
|
||||
"This list defines how certificates are mapped to names.
|
||||
The name is derived by considering each cert-to-name
|
||||
list entry in order. The cert-to-name entry's fingerprint
|
||||
determines whether the list entry is a match:
|
||||
|
||||
1) If the cert-to-name list entry's fingerprint value
|
||||
matches that of the presented certificate, then consider
|
||||
the list entry a successful match.
|
||||
|
||||
2) If the cert-to-name list entry's fingerprint value
|
||||
matches that of a locally held copy of a trusted CA
|
||||
certificate, and that CA certificate was part of the CA
|
||||
certificate chain to the presented certificate, then
|
||||
consider the list entry a successful match.
|
||||
|
||||
Once a matching cert-to-name list entry has been found, the
|
||||
map-type is used to determine how the name associated with
|
||||
the certificate should be determined. See the map-type
|
||||
leaf's description for details on determining the name value.
|
||||
If it is impossible to determine a name from the cert-to-name
|
||||
list entry's data combined with the data presented in the
|
||||
certificate, then additional cert-to-name list entries MUST
|
||||
be searched to look for another potential match.
|
||||
|
||||
Security administrators are encouraged to make use of
|
||||
certificates with subjectAltName fields that can be mapped to
|
||||
names so that a single root CA certificate can allow all
|
||||
child certificates' subjectAltName fields to map directly to
|
||||
a name via a 1:1 transformation.";
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model
|
||||
for the Simple Network Management Protocol (SNMP).
|
||||
SNMP-TLS-TM-MIB.snmpTlstmCertToTSNEntry";
|
||||
|
||||
leaf id {
|
||||
type uint32;
|
||||
description
|
||||
"The id specifies the order in which the entries in the
|
||||
cert-to-name list are searched. Entries with lower
|
||||
numbers are searched first.";
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model
|
||||
for the Simple Network Management Protocol
|
||||
(SNMP).
|
||||
SNMP-TLS-TM-MIB.snmpTlstmCertToTSNID";
|
||||
|
||||
}
|
||||
|
||||
leaf fingerprint {
|
||||
type tls-fingerprint;
|
||||
mandatory true;
|
||||
description
|
||||
"Specifies a value with which the fingerprint of the
|
||||
full certificate presented by the peer is compared. If
|
||||
the fingerprint of the full certificate presented by the
|
||||
peer does not match the fingerprint configured, then the
|
||||
entry is skipped, and the search for a match continues.";
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model
|
||||
for the Simple Network Management Protocol
|
||||
(SNMP).
|
||||
SNMP-TLS-TM-MIB.snmpTlstmCertToTSNFingerprint";
|
||||
|
||||
}
|
||||
|
||||
leaf map-type {
|
||||
type identityref {
|
||||
base cert-to-name;
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"Specifies the algorithm used to map the certificate
|
||||
presented by the peer to a name.
|
||||
|
||||
Mappings that need additional configuration objects should
|
||||
use the 'when' statement to make them conditional based on
|
||||
the map-type.";
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model
|
||||
for the Simple Network Management Protocol
|
||||
(SNMP).
|
||||
SNMP-TLS-TM-MIB.snmpTlstmCertToTSNMapType";
|
||||
|
||||
}
|
||||
|
||||
leaf name {
|
||||
when
|
||||
"../map-type = 'x509c2n:specified'";
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"Directly specifies the NETCONF username when the
|
||||
map-type is 'specified'.";
|
||||
reference
|
||||
"RFC 6353: Transport Layer Security (TLS) Transport Model
|
||||
for the Simple Network Management Protocol
|
||||
(SNMP).
|
||||
SNMP-TLS-TM-MIB.snmpTlstmCertToTSNData";
|
||||
|
||||
}
|
||||
} // list cert-to-name
|
||||
} // grouping cert-to-name
|
||||
} // module ietf-x509-cert-to-name
|
475
modules/libnetconf2-netconf-server@2024-07-09.yang
Normal file
475
modules/libnetconf2-netconf-server@2024-07-09.yang
Normal file
|
@ -0,0 +1,475 @@
|
|||
module libnetconf2-netconf-server {
|
||||
yang-version 1.1;
|
||||
namespace "urn:cesnet:libnetconf2-netconf-server";
|
||||
prefix np2;
|
||||
|
||||
import ietf-netconf-server {
|
||||
prefix ncs;
|
||||
}
|
||||
|
||||
import ietf-crypto-types {
|
||||
prefix ct;
|
||||
}
|
||||
|
||||
import iana-ssh-public-key-algs {
|
||||
prefix sshpka;
|
||||
}
|
||||
|
||||
import iana-ssh-key-exchange-algs {
|
||||
prefix sshkea;
|
||||
}
|
||||
|
||||
import iana-ssh-encryption-algs {
|
||||
prefix sshea;
|
||||
}
|
||||
|
||||
import iana-ssh-mac-algs {
|
||||
prefix sshma;
|
||||
}
|
||||
|
||||
import ietf-tls-server {
|
||||
prefix tlss;
|
||||
}
|
||||
|
||||
revision "2024-07-09" {
|
||||
description "Second revision.";
|
||||
}
|
||||
|
||||
// Identities
|
||||
|
||||
/*
|
||||
identity ed25519-private-key-format {
|
||||
base ct:private-key-format;
|
||||
description
|
||||
"This identity would indicate that the
|
||||
private key is encoded in a ED25519PrivateKey
|
||||
format. However no such format is currently
|
||||
standardized or even exists.
|
||||
|
||||
If you wish to use a private key that uses
|
||||
an ED25519 algorithm, you need to pick either
|
||||
the private-key-info-format or
|
||||
openssh-private-key-format identity.";
|
||||
}
|
||||
*/
|
||||
|
||||
identity private-key-info-format {
|
||||
base ct:private-key-format;
|
||||
description
|
||||
"Indicates that the private key is encoded
|
||||
as a PrivateKeyInfo structure (from RFC 5208).
|
||||
|
||||
The expected header of the private key:
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
The expected footer of the private key:
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
Supported private key algorithms to use with
|
||||
this format are: RSA, EC and ED25519.
|
||||
|
||||
Commonly used public key format for this
|
||||
type of private key is represented by the
|
||||
SubjectPublicKeyInfo identity.";
|
||||
|
||||
reference
|
||||
"RFC 5208: PKCS #8: Private-Key Information
|
||||
Syntax Specification Version 1.2";
|
||||
}
|
||||
|
||||
identity openssh-private-key-format {
|
||||
base ct:private-key-format;
|
||||
description
|
||||
"Indicates that the private key is encoded
|
||||
in the OpenSSH format.
|
||||
|
||||
The expected header of the private key:
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
The expected footer of the private key:
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
|
||||
Supported private key algorithms to use with
|
||||
this format are: RSA, EC and ED25519.
|
||||
|
||||
Commonly used public key format for this
|
||||
type of private key is either the
|
||||
SSH2 public key format (from RFC 4716)
|
||||
or the Public key format defined in RFC 4253,
|
||||
Section 6.6.";
|
||||
|
||||
reference
|
||||
"The OpenSSH Private Key Format:
|
||||
https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
|
||||
|
||||
RFC 4716:
|
||||
The Secure Shell (SSH) Public Key File Format
|
||||
|
||||
RFC 4253:
|
||||
The Secure Shell (SSH) Transport Layer Protocol";
|
||||
}
|
||||
|
||||
identity openssh-ssh-ed25519-cert-v01 {
|
||||
base sshpka:public-key-alg-base;
|
||||
description
|
||||
"SSH-ED25519-CERT-V01@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL.certkeys:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity openssh-ecdsa-sha2-nistp521-cert-v01 {
|
||||
base sshpka:public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-NISTP521-CERT-V01@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL.certkeys:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity openssh-ecdsa-sha2-nistp384-cert-v01 {
|
||||
base sshpka:public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-NISTP384-CERT-V01@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL.certkeys:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity openssh-ecdsa-sha2-nistp256-cert-v01 {
|
||||
base sshpka:public-key-alg-base;
|
||||
description
|
||||
"ECDSA-SHA2-NISTP256-CERT-V01@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL.certkeys:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity openssh-rsa-sha2-512-cert-v01 {
|
||||
base sshpka:public-key-alg-base;
|
||||
description
|
||||
"RSA-SHA2-512-CERT-V01@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL.certkeys:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity openssh-rsa-sha2-256-cert-v01 {
|
||||
base sshpka:public-key-alg-base;
|
||||
description
|
||||
"RSA-SHA2-256-CERT-V01@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL.certkeys:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity openssh-ssh-rsa-cert-v01 {
|
||||
base sshpka:public-key-alg-base;
|
||||
description
|
||||
"SSH-RSA-CERT-V01@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL.certkeys:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity openssh-ssh-dss-cert-v01 {
|
||||
base sshpka:public-key-alg-base;
|
||||
description
|
||||
"SSH-DSS-CERT-V01@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL.certkeys:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity libssh-curve25519-sha256 {
|
||||
base sshkea:key-exchange-alg-base;
|
||||
description
|
||||
"CURVE25519-SHA256@LIBSSH.ORG";
|
||||
reference
|
||||
"curve25519-sha256@libssh.org specification:
|
||||
https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt";
|
||||
}
|
||||
|
||||
identity openssh-chacha20-poly1305 {
|
||||
base sshea:encryption-alg-base;
|
||||
description
|
||||
"CHACHA20-POLY1305@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL.chacha20poly1305:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.chacha20poly1305?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity openssh-aes256-gcm {
|
||||
base sshea:encryption-alg-base;
|
||||
description
|
||||
"AES256-GCM@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL, Section 1.6:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity openssh-aes128-gcm {
|
||||
base sshea:encryption-alg-base;
|
||||
description
|
||||
"AES128-GCM@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL, Section 1.6:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity openssh-hmac-sha2-256-etm {
|
||||
base sshma:mac-alg-base;
|
||||
description
|
||||
"HMAC-SHA2-256-ETM@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity openssh-hmac-sha2-512-etm {
|
||||
base sshma:mac-alg-base;
|
||||
description
|
||||
"HMAC-SHA2-512-ETM@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD";
|
||||
}
|
||||
|
||||
identity openssh-hmac-sha1-etm {
|
||||
base sshma:mac-alg-base;
|
||||
description
|
||||
"HMAC-SHA1-ETM@OPENSSH.COM";
|
||||
reference
|
||||
"OpenSSH PROTOCOL:
|
||||
https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL?annotate=HEAD";
|
||||
}
|
||||
|
||||
// Typedefs
|
||||
|
||||
typedef time-period {
|
||||
type string {
|
||||
pattern '(1[0-2]|[1-9])m|[1-4]w|[1-7]d|(2[0-4]|1[0-9]|[1-9])h';
|
||||
}
|
||||
|
||||
description
|
||||
"The time-period type allows to specify time in either months, weeks, days, or hours.
|
||||
Its purpose is to create time intervals for the certificate expiration notifications.";
|
||||
}
|
||||
|
||||
// Groupings
|
||||
|
||||
grouping ssh-authentication-params-grouping {
|
||||
description
|
||||
"Grouping for SSH authentication parameters.";
|
||||
|
||||
leaf auth-timeout {
|
||||
type uint16;
|
||||
default 30;
|
||||
units "seconds";
|
||||
description
|
||||
"Represents the maximum amount of seconds an authentication can go on for.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping ssh-server-banner-grouping {
|
||||
description
|
||||
"Grouping for the SSH server banner.";
|
||||
|
||||
leaf banner {
|
||||
type string {
|
||||
length "1..247";
|
||||
}
|
||||
description
|
||||
"The banner that will be sent to the client when connecting to the server.
|
||||
If not set, the libnetconf2 default with its version will be used.";
|
||||
|
||||
reference
|
||||
"RFC 4253: The Secure Shell (SSH) Transport Layer Protocol, section 4.2.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping system-auth-public-keys-grouping {
|
||||
description
|
||||
"Grouping for using the system configured keys in the SSH public key authentication method.";
|
||||
|
||||
container use-system-keys {
|
||||
presence
|
||||
"Indicates that the given user will be authenticated using the system's configured public keys.";
|
||||
|
||||
description
|
||||
"Authentication is done using the system's mechanisms.";
|
||||
|
||||
reference
|
||||
"libnetconf2 documentation:
|
||||
Section SSH";
|
||||
}
|
||||
}
|
||||
|
||||
grouping keyboard-interactive-grouping {
|
||||
description
|
||||
"Grouping for the SSH Keyboard interactive authentication method.";
|
||||
|
||||
container keyboard-interactive {
|
||||
presence "Indicates that the given client supports the SSH Keyboard Interactive authentication method.";
|
||||
description
|
||||
"Keyboard interactive SSH authentication method.";
|
||||
|
||||
reference
|
||||
"RFC 4256:
|
||||
Generic Message Exchange Authentication for
|
||||
the Secure Shell Protocol (SSH)";
|
||||
|
||||
choice method {
|
||||
mandatory true;
|
||||
description
|
||||
"Method to perform the authentication with.";
|
||||
|
||||
container use-system-auth {
|
||||
presence
|
||||
"Indicates that the system will handle the authentication.";
|
||||
|
||||
description
|
||||
"Authentication is done using the system's mechanisms.";
|
||||
|
||||
reference
|
||||
"libnetconf2 documentation:
|
||||
Section SSH";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping endpoint-reference-grouping {
|
||||
description
|
||||
"Grouping for the endpoint reference.";
|
||||
|
||||
leaf endpoint-reference {
|
||||
type leafref {
|
||||
path "/ncs:netconf-server/ncs:listen/ncs:endpoints/ncs:endpoint/ncs:name";
|
||||
}
|
||||
description
|
||||
"Reference to another endpoint. The purpose is to use the referenced endpoint's authentication mechanisms.
|
||||
If a connection occurs on an endpoint, the connecting user will be tried to be authenticated
|
||||
using the given endpoint's defined methods. If the user wasn't authenticated and the endpoint
|
||||
references another endpoint, the authentication will be tried again. However, this time
|
||||
using the referenced endpoint's mechanisms. The references can be
|
||||
multiple, however there must not be a cycle.";
|
||||
}
|
||||
}
|
||||
|
||||
// Augments
|
||||
|
||||
augment "/ncs:netconf-server/ncs:listen/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh" +
|
||||
"/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" {
|
||||
uses ssh-authentication-params-grouping;
|
||||
}
|
||||
|
||||
augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints" +
|
||||
"/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" {
|
||||
uses ssh-authentication-params-grouping;
|
||||
}
|
||||
|
||||
augment "/ncs:netconf-server/ncs:listen/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh" +
|
||||
"/ncs:ssh/ncs:ssh-server-parameters/ncs:server-identity" {
|
||||
uses ssh-server-banner-grouping;
|
||||
}
|
||||
|
||||
augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints" +
|
||||
"/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:server-identity" {
|
||||
uses ssh-authentication-params-grouping;
|
||||
}
|
||||
|
||||
augment "/ncs:netconf-server/ncs:listen/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters" +
|
||||
"/ncs:client-authentication/ncs:users/ncs:user/ncs:public-keys/ncs:inline-or-truststore" {
|
||||
case system-auth-public-keys {
|
||||
uses system-auth-public-keys-grouping;
|
||||
}
|
||||
}
|
||||
|
||||
augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh" +
|
||||
"/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user/ncs:public-keys/ncs:inline-or-truststore" {
|
||||
case system-auth-public-keys {
|
||||
uses system-auth-public-keys-grouping;
|
||||
}
|
||||
}
|
||||
|
||||
augment "/ncs:netconf-server/ncs:listen/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh" +
|
||||
"/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" {
|
||||
uses keyboard-interactive-grouping;
|
||||
}
|
||||
|
||||
augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints" +
|
||||
"/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication/ncs:users/ncs:user" {
|
||||
uses keyboard-interactive-grouping;
|
||||
}
|
||||
|
||||
augment "/ncs:netconf-server/ncs:listen/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh" +
|
||||
"/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" {
|
||||
uses endpoint-reference-grouping;
|
||||
}
|
||||
|
||||
augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints" +
|
||||
"/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" {
|
||||
uses endpoint-reference-grouping;
|
||||
}
|
||||
|
||||
augment "/ncs:netconf-server/ncs:listen/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:tls" +
|
||||
"/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" {
|
||||
uses endpoint-reference-grouping;
|
||||
}
|
||||
|
||||
augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints" +
|
||||
"/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" {
|
||||
uses endpoint-reference-grouping;
|
||||
}
|
||||
|
||||
// Protocol-accessible Nodes
|
||||
|
||||
container ln2-netconf-server {
|
||||
container certificate-expiration-notif-intervals {
|
||||
if-feature "ct:certificate-expiration-notification";
|
||||
|
||||
description
|
||||
"Container for the certificate expiration notification intervals.
|
||||
Its child nodes describe the ability to set the time intervals for the certificate
|
||||
expiration notifications. These intervals are given in the form of an anchor and a period.
|
||||
By default, these notifications are generated 3, 2, and 1 month; 2 weeks; 7, 6, 5, 4, 3, 2 and 1 day before a certificate expires.
|
||||
Additionally, notifications are generated on the day of expiration and every day thereafter.
|
||||
|
||||
Simplified example of YANG data that describe the default intervals:
|
||||
|
||||
Anchor Period
|
||||
3m ... 1m
|
||||
2w ... 1w
|
||||
7d ... 1d
|
||||
";
|
||||
|
||||
list interval {
|
||||
key "anchor period";
|
||||
|
||||
leaf anchor {
|
||||
type time-period;
|
||||
|
||||
description
|
||||
"The time anchor for the notification. The anchor is the time
|
||||
before the certificate expiration when a notification will be sent.
|
||||
It is essentially the lower bound of the given interval.";
|
||||
}
|
||||
leaf period {
|
||||
type time-period;
|
||||
|
||||
// Require the period to be smaller than the anchor (only units are checked for simplicity)
|
||||
must "(contains(., 'm') and contains(../anchor, 'm')) or
|
||||
(contains(., 'w') and (contains(../anchor, 'm') or contains(../anchor, 'w'))) or
|
||||
(contains(., 'd') and (contains(../anchor, 'm') or contains(../anchor, 'w') or contains(../anchor, 'd'))) or
|
||||
contains(., 'h')" {
|
||||
error-message
|
||||
"Certificate expiration notification period must be smaller than the anchor.";
|
||||
}
|
||||
|
||||
description
|
||||
"The period of the notification. The period is the time
|
||||
between two notifications within the given time interval.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
/**
|
||||
* \file nc_client.h
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2's main public header for NETCONF clients.
|
||||
* @file nc_client.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @brief libnetconf2's main public header for NETCONF clients.
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
@ -15,13 +16,12 @@
|
|||
#ifndef NC_CLIENT_H_
|
||||
#define NC_CLIENT_H_
|
||||
|
||||
@SSH_MACRO@
|
||||
@TLS_MACRO@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@SSH_TLS_MACRO@
|
||||
|
||||
#include <libnetconf2/netconf.h>
|
||||
#include <libnetconf2/log.h>
|
||||
#include <libnetconf2/messages_client.h>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/**
|
||||
* \file nc_server.h
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2's main public header for NETCONF servers.
|
||||
* @file nc_server.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @brief libnetconf2's main public header for NETCONF servers.
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
@ -15,16 +16,16 @@
|
|||
#ifndef NC_SERVER_H_
|
||||
#define NC_SERVER_H_
|
||||
|
||||
@SSH_MACRO@
|
||||
@TLS_MACRO@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@SSH_TLS_MACRO@
|
||||
|
||||
#include <libnetconf2/netconf.h>
|
||||
#include <libnetconf2/log.h>
|
||||
#include <libnetconf2/messages_server.h>
|
||||
#include <libnetconf2/server_config.h>
|
||||
#include <libnetconf2/session_server.h>
|
||||
#include <libnetconf2/session_server_ch.h>
|
||||
|
||||
|
|
32
nc_version.h.in
Normal file
32
nc_version.h.in
Normal file
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* @file nc_version.h
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 version information
|
||||
*
|
||||
* @copyright
|
||||
* 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_VERSION_H_
|
||||
#define NC_VERSION_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NC_VERSION_MAJOR @LIBNETCONF2_MAJOR_SOVERSION@ /**< libnetconf2 major version number */
|
||||
#define NC_VERSION_MINOR @LIBNETCONF2_MINOR_SOVERSION@ /**< libnetconf2 minor version number */
|
||||
#define NC_VERSION_MICRO @LIBNETCONF2_MICRO_SOVERSION@ /**< libnetconf2 micro version number */
|
||||
#define NC_VERSION "@LIBNETCONF2_SOVERSION_FULL@" /**< libnetconf2 version string */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NC_VERSION_H_ */
|
|
@ -1,9 +1,11 @@
|
|||
/**
|
||||
* \file config.h
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2 various configuration settings.
|
||||
* @file config.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 various configuration settings.
|
||||
*
|
||||
* Copyright (c) 2015 - 2017 CESNET, z.s.p.o.
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2024 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.
|
||||
|
@ -33,14 +35,29 @@
|
|||
#cmakedefine HAVE_SHADOW
|
||||
|
||||
/*
|
||||
* Support for crypt.h
|
||||
* Support for terminal in/out
|
||||
*/
|
||||
#cmakedefine HAVE_CRYPT
|
||||
#cmakedefine HAVE_TERMIOS
|
||||
|
||||
/*
|
||||
* Location of installed basic YANG modules on the system
|
||||
* Support for keyboard-interactive SSH authentication method
|
||||
*/
|
||||
#define NC_YANG_DIR "@YANG_MODULE_DIR@"
|
||||
#cmakedefine HAVE_LIBPAM
|
||||
|
||||
/*
|
||||
* Use MbedTLS as TLS back-end
|
||||
*/
|
||||
#cmakedefine HAVE_MBEDTLS
|
||||
|
||||
/*
|
||||
* Location of installed YANG modules on the system
|
||||
*/
|
||||
#define NC_SERVER_SEARCH_DIR "@YANG_MODULE_DIR@"
|
||||
|
||||
/*
|
||||
* Location of installed YANG modules on the system
|
||||
*/
|
||||
#define NC_CLIENT_SEARCH_DIR "@CLIENT_SEARCH_DIR@"
|
||||
|
||||
/*
|
||||
* Inactive read timeout
|
||||
|
|
403
src/io.c
403
src/io.c
|
@ -1,9 +1,11 @@
|
|||
/**
|
||||
* \file io.c
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2 - input/output functions
|
||||
* @file io.c
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 - input/output functions
|
||||
*
|
||||
* Copyright (c) 2015 CESNET, z.s.p.o.
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2024 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.
|
||||
|
@ -13,27 +15,30 @@
|
|||
*/
|
||||
|
||||
#define _GNU_SOURCE /* asprintf, signals */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <poll.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
# include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "libnetconf.h"
|
||||
#include "config.h"
|
||||
#include "log_p.h"
|
||||
#include "messages_p.h"
|
||||
#include "netconf.h"
|
||||
#include "session.h"
|
||||
#include "session_p.h"
|
||||
#include "session_wrapper.h"
|
||||
|
||||
const char *nc_msgtype2str[] = {
|
||||
"error",
|
||||
|
@ -49,49 +54,13 @@ const char *nc_msgtype2str[] = {
|
|||
|
||||
#define BUFFERSIZE 512
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
|
||||
static char *
|
||||
nc_ssl_error_get_reasons(void)
|
||||
{
|
||||
unsigned int e;
|
||||
int reason_size, reason_len;
|
||||
char *reasons = NULL;
|
||||
|
||||
reason_size = 1;
|
||||
reason_len = 0;
|
||||
while ((e = ERR_get_error())) {
|
||||
if (reason_len) {
|
||||
/* add "; " */
|
||||
reason_size += 2;
|
||||
reasons = nc_realloc(reasons, reason_size);
|
||||
if (!reasons) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
reason_len += sprintf(reasons + reason_len, "; ");
|
||||
}
|
||||
reason_size += strlen(ERR_reason_error_string(e));
|
||||
reasons = nc_realloc(reasons, reason_size);
|
||||
if (!reasons) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
reason_len += sprintf(reasons + reason_len, "%s", ERR_reason_error_string(e));
|
||||
}
|
||||
|
||||
return reasons;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static ssize_t
|
||||
nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_timeout, struct timespec *ts_act_timeout)
|
||||
nc_read(struct nc_session *session, char *buf, uint32_t count, uint32_t inact_timeout, struct timespec *ts_act_timeout)
|
||||
{
|
||||
size_t readd = 0;
|
||||
uint32_t readd = 0;
|
||||
ssize_t r = -1;
|
||||
int fd, interrupted;
|
||||
struct timespec ts_cur, ts_inact_timeout;
|
||||
struct timespec ts_inact_timeout;
|
||||
|
||||
assert(session);
|
||||
assert(buf);
|
||||
|
@ -104,8 +73,7 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
|
|||
return 0;
|
||||
}
|
||||
|
||||
nc_gettimespec_mono(&ts_inact_timeout);
|
||||
nc_addtimespec(&ts_inact_timeout, inact_timeout);
|
||||
nc_timeouttime_get(&ts_inact_timeout, inact_timeout);
|
||||
do {
|
||||
interrupted = 0;
|
||||
switch (session->ti_type) {
|
||||
|
@ -139,8 +107,8 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
|
|||
}
|
||||
break;
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
case NC_TI_LIBSSH:
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
case NC_TI_SSH:
|
||||
/* read via libssh */
|
||||
r = ssh_channel_read(session->ti.libssh.channel, buf + readd, count - readd, 0);
|
||||
if (r == SSH_AGAIN) {
|
||||
|
@ -161,48 +129,15 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
|
|||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
case NC_TI_OPENSSL:
|
||||
/* read via OpenSSL */
|
||||
ERR_clear_error();
|
||||
r = SSL_read(session->ti.tls, buf + readd, count - readd);
|
||||
if (r <= 0) {
|
||||
int e;
|
||||
char *reasons;
|
||||
|
||||
switch (e = SSL_get_error(session->ti.tls, r)) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
r = 0;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
ERR(session, "Communication socket unexpectedly closed (OpenSSL).");
|
||||
session->status = NC_STATUS_INVALID;
|
||||
session->term_reason = NC_SESSION_TERM_DROPPED;
|
||||
return -1;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
ERR(session, "SSL socket error (%s).", errno ? strerror(errno) : "unexpected EOF");
|
||||
session->status = NC_STATUS_INVALID;
|
||||
session->term_reason = NC_SESSION_TERM_OTHER;
|
||||
return -1;
|
||||
case SSL_ERROR_SSL:
|
||||
reasons = nc_ssl_error_get_reasons();
|
||||
ERR(session, "SSL error (%s).", reasons);
|
||||
free(reasons);
|
||||
session->status = NC_STATUS_INVALID;
|
||||
session->term_reason = NC_SESSION_TERM_OTHER;
|
||||
return -1;
|
||||
default:
|
||||
ERR(session, "Unknown SSL error occured (err code %d).", e);
|
||||
session->status = NC_STATUS_INVALID;
|
||||
session->term_reason = NC_SESSION_TERM_OTHER;
|
||||
return -1;
|
||||
}
|
||||
case NC_TI_TLS:
|
||||
r = nc_tls_read_wrap(session, (unsigned char *)buf + readd, count - readd);
|
||||
if (r < 0) {
|
||||
/* non-recoverable error */
|
||||
return r;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
|
@ -210,9 +145,8 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
|
|||
if (!interrupted) {
|
||||
usleep(NC_TIMEOUT_STEP);
|
||||
}
|
||||
nc_gettimespec_mono(&ts_cur);
|
||||
if ((nc_difftimespec(&ts_cur, &ts_inact_timeout) < 1) || (nc_difftimespec(&ts_cur, ts_act_timeout) < 1)) {
|
||||
if (nc_difftimespec(&ts_cur, &ts_inact_timeout) < 1) {
|
||||
if ((nc_timeouttime_cur_diff(&ts_inact_timeout) < 1) || (nc_timeouttime_cur_diff(ts_act_timeout) < 1)) {
|
||||
if (nc_timeouttime_cur_diff(&ts_inact_timeout) < 1) {
|
||||
ERR(session, "Inactive read timeout elapsed.");
|
||||
} else {
|
||||
ERR(session, "Active read timeout elapsed.");
|
||||
|
@ -226,8 +160,7 @@ nc_read(struct nc_session *session, char *buf, size_t count, uint32_t inact_time
|
|||
readd += r;
|
||||
|
||||
/* reset inactive timeout */
|
||||
nc_gettimespec_mono(&ts_inact_timeout);
|
||||
nc_addtimespec(&ts_inact_timeout, inact_timeout);
|
||||
nc_timeouttime_get(&ts_inact_timeout, inact_timeout);
|
||||
}
|
||||
|
||||
} while (readd < count);
|
||||
|
@ -249,10 +182,7 @@ nc_read_chunk(struct nc_session *session, size_t len, uint32_t inact_timeout, st
|
|||
}
|
||||
|
||||
*chunk = malloc((len + 1) * sizeof **chunk);
|
||||
if (!*chunk) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!*chunk, -1);
|
||||
|
||||
r = nc_read(session, *chunk, len, inact_timeout, ts_act_timeout);
|
||||
if (r <= 0) {
|
||||
|
@ -282,10 +212,7 @@ nc_read_until(struct nc_session *session, const char *endtag, size_t limit, uint
|
|||
size = BUFFERSIZE;
|
||||
}
|
||||
chunk = malloc((size + 1) * sizeof *chunk);
|
||||
if (!chunk) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!chunk, -1);
|
||||
|
||||
len = strlen(endtag);
|
||||
while (1) {
|
||||
|
@ -301,10 +228,7 @@ nc_read_until(struct nc_session *session, const char *endtag, size_t limit, uint
|
|||
/* get more memory */
|
||||
size = size + BUFFERSIZE;
|
||||
chunk = nc_realloc(chunk, (size + 1) * sizeof *chunk);
|
||||
if (!chunk) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!chunk, -1);
|
||||
}
|
||||
|
||||
/* get another character */
|
||||
|
@ -362,8 +286,7 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
nc_gettimespec_mono(&ts_act_timeout);
|
||||
nc_addtimespec(&ts_act_timeout, NC_READ_ACT_TIMEOUT * 1000);
|
||||
nc_timeouttime_get(&ts_act_timeout, NC_READ_ACT_TIMEOUT * 1000);
|
||||
|
||||
if (!io_locked) {
|
||||
/* SESSION IO LOCK */
|
||||
|
@ -428,11 +351,7 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
|
|||
|
||||
/* realloc message buffer, remember to count terminating null byte */
|
||||
data = nc_realloc(data, len + chunk_len + 1);
|
||||
if (!data) {
|
||||
ERRMEM;
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
NC_CHECK_ERRMEM_GOTO(!data, ret = -1, cleanup);
|
||||
memcpy(data + len, chunk, chunk_len);
|
||||
len += chunk_len;
|
||||
data[len] = '\0';
|
||||
|
@ -469,7 +388,6 @@ cleanup:
|
|||
static int
|
||||
nc_read_poll(struct nc_session *session, int io_timeout)
|
||||
{
|
||||
sigset_t sigmask, origmask;
|
||||
int ret = -2;
|
||||
struct pollfd fds;
|
||||
|
||||
|
@ -479,8 +397,13 @@ nc_read_poll(struct nc_session *session, int io_timeout)
|
|||
}
|
||||
|
||||
switch (session->ti_type) {
|
||||
#ifdef NC_ENABLED_SSH
|
||||
case NC_TI_LIBSSH:
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
case NC_TI_SSH:
|
||||
if (io_timeout == -1) {
|
||||
/* BUG libssh 0.11.0 replaces timeout -1 with 0 for non-blocking sessions */
|
||||
io_timeout = INT_MAX;
|
||||
}
|
||||
|
||||
/* EINTR is handled, it resumes waiting */
|
||||
ret = ssh_channel_poll_timeout(session->ti.libssh.channel, io_timeout, 0);
|
||||
if (ret == SSH_ERROR) {
|
||||
|
@ -501,10 +424,8 @@ nc_read_poll(struct nc_session *session, int io_timeout)
|
|||
fds.revents = 0;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef NC_ENABLED_TLS
|
||||
case NC_TI_OPENSSL:
|
||||
ret = SSL_pending(session->ti.tls);
|
||||
case NC_TI_TLS:
|
||||
ret = nc_tls_get_num_pending_bytes_wrap(session->ti.tls.session);
|
||||
if (ret) {
|
||||
/* some buffered TLS data available */
|
||||
ret = 1;
|
||||
|
@ -512,8 +433,8 @@ nc_read_poll(struct nc_session *session, int io_timeout)
|
|||
break;
|
||||
}
|
||||
|
||||
fds.fd = SSL_get_fd(session->ti.tls);
|
||||
#endif
|
||||
fds.fd = nc_tls_get_fd_wrap(session);
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
/* fallthrough */
|
||||
case NC_TI_FD:
|
||||
case NC_TI_UNIX:
|
||||
|
@ -526,11 +447,7 @@ nc_read_poll(struct nc_session *session, int io_timeout)
|
|||
fds.events = POLLIN;
|
||||
fds.revents = 0;
|
||||
|
||||
sigfillset(&sigmask);
|
||||
pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
|
||||
ret = poll(&fds, 1, io_timeout);
|
||||
pthread_sigmask(SIG_SETMASK, &origmask, NULL);
|
||||
|
||||
ret = nc_poll(&fds, 1, io_timeout);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -600,7 +517,7 @@ nc_read_msg_poll_io(struct nc_session *session, int io_timeout, struct ly_in **m
|
|||
|
||||
/* does not really log, only fatal errors */
|
||||
int
|
||||
nc_session_is_connected(struct nc_session *session)
|
||||
nc_session_is_connected(const struct nc_session *session)
|
||||
{
|
||||
int ret;
|
||||
struct pollfd fds;
|
||||
|
@ -612,15 +529,13 @@ nc_session_is_connected(struct nc_session *session)
|
|||
case NC_TI_UNIX:
|
||||
fds.fd = session->ti.unixsock.sock;
|
||||
break;
|
||||
#ifdef NC_ENABLED_SSH
|
||||
case NC_TI_LIBSSH:
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
case NC_TI_SSH:
|
||||
return ssh_is_connected(session->ti.libssh.session);
|
||||
#endif
|
||||
#ifdef NC_ENABLED_TLS
|
||||
case NC_TI_OPENSSL:
|
||||
fds.fd = SSL_get_fd(session->ti.tls);
|
||||
case NC_TI_TLS:
|
||||
fds.fd = nc_tls_get_fd_wrap(session);
|
||||
break;
|
||||
#endif
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -632,11 +547,8 @@ nc_session_is_connected(struct nc_session *session)
|
|||
fds.events = POLLIN;
|
||||
fds.revents = 0;
|
||||
|
||||
errno = 0;
|
||||
while (((ret = poll(&fds, 1, 0)) == -1) && (errno == EINTR)) {}
|
||||
|
||||
ret = nc_poll(&fds, 1, 0);
|
||||
if (ret == -1) {
|
||||
ERR(session, "poll failed (%s).", strerror(errno));
|
||||
return 0;
|
||||
} else if ((ret > 0) && (fds.revents & (POLLHUP | POLLERR))) {
|
||||
return 0;
|
||||
|
@ -646,21 +558,26 @@ nc_session_is_connected(struct nc_session *session)
|
|||
}
|
||||
|
||||
#define WRITE_BUFSIZE (2 * BUFFERSIZE)
|
||||
struct wclb_arg {
|
||||
struct nc_wclb_arg {
|
||||
struct nc_session *session;
|
||||
char buf[WRITE_BUFSIZE];
|
||||
size_t len;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Write to a NETCONF session.
|
||||
*
|
||||
* @param[in] session Session to write to.
|
||||
* @param[in] buf Buffer to write.
|
||||
* @param[in] count Count of bytes from @p buf to write.
|
||||
* @return Number of bytes written.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_write(struct nc_session *session, const void *buf, size_t count)
|
||||
nc_write(struct nc_session *session, const void *buf, uint32_t count)
|
||||
{
|
||||
int c, fd, interrupted;
|
||||
size_t written = 0;
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
unsigned long e;
|
||||
#endif
|
||||
uint32_t written = 0;
|
||||
|
||||
if ((session->status != NC_STATUS_RUNNING) && (session->status != NC_STATUS_STARTING)) {
|
||||
return -1;
|
||||
|
@ -674,7 +591,7 @@ nc_write(struct nc_session *session, const void *buf, size_t count)
|
|||
return -1;
|
||||
}
|
||||
|
||||
DBG(session, "Sending message:\n%.*s\n", count, buf);
|
||||
DBG(session, "Sending message:\n%.*s\n", (int)count, buf);
|
||||
|
||||
do {
|
||||
interrupted = 0;
|
||||
|
@ -689,13 +606,13 @@ nc_write(struct nc_session *session, const void *buf, size_t count)
|
|||
c = 0;
|
||||
interrupted = 1;
|
||||
} else if (c < 0) {
|
||||
ERR(session, "socket error (%s).", strerror(errno));
|
||||
ERR(session, "Socket error (%s).", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
case NC_TI_LIBSSH:
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
case NC_TI_SSH:
|
||||
if (ssh_channel_is_closed(session->ti.libssh.channel) || ssh_channel_is_eof(session->ti.libssh.channel)) {
|
||||
if (ssh_channel_is_closed(session->ti.libssh.channel)) {
|
||||
ERR(session, "SSH channel unexpectedly closed.");
|
||||
|
@ -712,36 +629,14 @@ nc_write(struct nc_session *session, const void *buf, size_t count)
|
|||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef NC_ENABLED_TLS
|
||||
case NC_TI_OPENSSL:
|
||||
c = SSL_write(session->ti.tls, (char *)(buf + written), count - written);
|
||||
if (c < 1) {
|
||||
char *reasons;
|
||||
|
||||
switch ((e = SSL_get_error(session->ti.tls, c))) {
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
ERR(session, "SSL connection was properly closed.");
|
||||
return -1;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
case SSL_ERROR_WANT_READ:
|
||||
c = 0;
|
||||
break;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
ERR(session, "SSL socket error (%s).", strerror(errno));
|
||||
return -1;
|
||||
case SSL_ERROR_SSL:
|
||||
reasons = nc_ssl_error_get_reasons();
|
||||
ERR(session, "SSL error (%s).", reasons);
|
||||
free(reasons);
|
||||
return -1;
|
||||
default:
|
||||
ERR(session, "Unknown SSL error occured (err code %d).", e);
|
||||
return -1;
|
||||
}
|
||||
case NC_TI_TLS:
|
||||
c = nc_tls_write_wrap(session, (const unsigned char *)(buf + written), count - written);
|
||||
if (c < 0) {
|
||||
/* possible client dc, or some socket/TLS communication error */
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
default:
|
||||
ERRINT;
|
||||
return -1;
|
||||
|
@ -758,30 +653,47 @@ nc_write(struct nc_session *session, const void *buf, size_t count)
|
|||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the start tag and the message part of a chunked-framing NETCONF message.
|
||||
*
|
||||
* @param[in] session Session to write to.
|
||||
* @param[in] buf Message buffer to write.
|
||||
* @param[in] count Count of bytes from @p buf to write.
|
||||
* @return Number of bytes written.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_write_starttag_and_msg(struct nc_session *session, const void *buf, size_t count)
|
||||
nc_write_starttag_and_msg(struct nc_session *session, const void *buf, uint32_t count)
|
||||
{
|
||||
int ret = 0, c;
|
||||
int ret = 0, r;
|
||||
char chunksize[24];
|
||||
|
||||
// warning: ‘%zu’ directive writing between 4 and 20 bytes into a region of size 18 [-Wformat-overflow=]
|
||||
if (session->version == NC_VERSION_11) {
|
||||
sprintf(chunksize, "\n#%zu\n", count);
|
||||
ret = nc_write(session, chunksize, strlen(chunksize));
|
||||
if (ret == -1) {
|
||||
r = sprintf(chunksize, "\n#%" PRIu32 "\n", count);
|
||||
|
||||
r = nc_write(session, chunksize, r);
|
||||
if (r == -1) {
|
||||
return -1;
|
||||
}
|
||||
ret += r;
|
||||
}
|
||||
|
||||
c = nc_write(session, buf, count);
|
||||
if (c == -1) {
|
||||
r = nc_write(session, buf, count);
|
||||
if (r == -1) {
|
||||
return -1;
|
||||
}
|
||||
ret += c;
|
||||
ret += r;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the end tag part of a chunked-framing NETCONF message.
|
||||
*
|
||||
* @param[in] session Session to write to.
|
||||
* @return Number of bytes written.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_write_endtag(struct nc_session *session)
|
||||
{
|
||||
|
@ -796,8 +708,15 @@ nc_write_endtag(struct nc_session *session)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Flush all the data buffered for writing.
|
||||
*
|
||||
* @param[in] warg Write callback structure to flush.
|
||||
* @return Number of written bytes.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_write_clb_flush(struct wclb_arg *warg)
|
||||
nc_write_clb_flush(struct nc_wclb_arg *warg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
@ -810,12 +729,22 @@ nc_write_clb_flush(struct wclb_arg *warg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write callback buffering the data in a write structure.
|
||||
*
|
||||
* @param[in] arg Write structure used for buffering.
|
||||
* @param[in] buf Buffer to write.
|
||||
* @param[in] count Count of bytes to write from @p buf.
|
||||
* @param[in] xmlcontent Whether the data are actually printed as part of an XML in which case they need to be encoded.
|
||||
* @return Number of written bytes.
|
||||
* @return -1 on error.
|
||||
*/
|
||||
static ssize_t
|
||||
nc_write_clb(void *arg, const void *buf, size_t count, int xmlcontent)
|
||||
nc_write_clb(void *arg, const void *buf, uint32_t count, int xmlcontent)
|
||||
{
|
||||
int ret = 0, c;
|
||||
size_t l;
|
||||
struct wclb_arg *warg = (struct wclb_arg *)arg;
|
||||
ssize_t ret = 0, c;
|
||||
uint32_t l;
|
||||
struct nc_wclb_arg *warg = arg;
|
||||
|
||||
if (!buf) {
|
||||
c = nc_write_clb_flush(warg);
|
||||
|
@ -895,6 +824,9 @@ nc_write_clb(void *arg, const void *buf, size_t count, int xmlcontent)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write print callback used by libyang.
|
||||
*/
|
||||
static ssize_t
|
||||
nc_write_xmlclb(void *arg, const void *buf, size_t count)
|
||||
{
|
||||
|
@ -921,7 +853,7 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
struct nc_server_notif *notif;
|
||||
struct nc_server_reply *reply;
|
||||
char *buf;
|
||||
struct wclb_arg arg;
|
||||
struct nc_wclb_arg arg;
|
||||
const char **capabilities;
|
||||
uint32_t *sid = NULL, i, wd = 0;
|
||||
LY_ERR lyrc;
|
||||
|
@ -954,11 +886,7 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
/* <rpc> open */
|
||||
count = asprintf(&buf, "<rpc xmlns=\"%s\" message-id=\"%" PRIu64 "\"%s>",
|
||||
NC_NS_BASE, session->opts.client.msgid + 1, attrs ? attrs : "");
|
||||
if (count == -1) {
|
||||
ERRMEM;
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
NC_CHECK_ERRMEM_GOTO(count == -1, ret = NC_MSG_ERROR, cleanup);
|
||||
nc_write_clb((void *)&arg, buf, count, 0);
|
||||
free(buf);
|
||||
|
||||
|
@ -969,7 +897,7 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
}
|
||||
|
||||
/* rpc data */
|
||||
if (lyd_print_clb(nc_write_xmlclb, (void *)&arg, op, LYD_XML, LYD_PRINT_SHRINK)) {
|
||||
if (lyd_print_clb(nc_write_xmlclb, (void *)&arg, op, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_KEEPEMPTYCONT)) {
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -991,27 +919,21 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
rpc_envp = va_arg(ap, struct lyd_node_opaq *);
|
||||
reply = va_arg(ap, struct nc_server_reply *);
|
||||
|
||||
if (!rpc_envp) {
|
||||
/* can be NULL if replying with a malformed-message error */
|
||||
nc_write_clb((void *)&arg, "<rpc-reply xmlns=\"" NC_NS_BASE "\">", 18 + strlen(NC_NS_BASE) + 2, 0);
|
||||
|
||||
assert(reply->type == NC_RPL_ERROR);
|
||||
if (lyd_print_clb(nc_write_xmlclb, (void *)&arg, ((struct nc_server_reply_error *)reply)->err, LYD_XML,
|
||||
LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS)) {
|
||||
/* build a rpc-reply opaque node that can be simply printed */
|
||||
if (rpc_envp) {
|
||||
if (lyd_new_opaq2(NULL, session->ctx, "rpc-reply", NULL, rpc_envp->name.prefix, rpc_envp->name.module_ns,
|
||||
&reply_envp)) {
|
||||
ERRINT;
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
if (lyd_new_opaq2(NULL, session->ctx, "rpc-reply", NULL, NULL, NC_NS_BASE,
|
||||
&reply_envp)) {
|
||||
ERRINT;
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
nc_write_clb((void *)&arg, "</rpc-reply>", 12, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* build a rpc-reply opaque node that can be simply printed */
|
||||
if (lyd_new_opaq2(NULL, session->ctx, "rpc-reply", NULL, rpc_envp->name.prefix, rpc_envp->name.module_ns,
|
||||
&reply_envp)) {
|
||||
ERRINT;
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
switch (reply->type) {
|
||||
|
@ -1060,7 +982,9 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
}
|
||||
|
||||
/* temporary */
|
||||
((struct lyd_node_opaq *)reply_envp)->attr = rpc_envp->attr;
|
||||
if (rpc_envp) {
|
||||
((struct lyd_node_opaq *)reply_envp)->attr = rpc_envp->attr;
|
||||
}
|
||||
|
||||
/* print */
|
||||
lyrc = lyd_print_clb(nc_write_xmlclb, (void *)&arg, reply_envp, LYD_XML, LYD_PRINT_SHRINK | wd);
|
||||
|
@ -1117,11 +1041,7 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
sid = va_arg(ap, uint32_t *);
|
||||
|
||||
count = asprintf(&buf, "<hello xmlns=\"%s\"><capabilities>", NC_NS_BASE);
|
||||
if (count == -1) {
|
||||
ERRMEM;
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
NC_CHECK_ERRMEM_GOTO(count == -1, ret = NC_MSG_ERROR, cleanup);
|
||||
nc_write_clb((void *)&arg, buf, count, 0);
|
||||
free(buf);
|
||||
for (i = 0; capabilities[i]; i++) {
|
||||
|
@ -1130,12 +1050,8 @@ nc_write_msg_io(struct nc_session *session, int io_timeout, int type, ...)
|
|||
nc_write_clb((void *)&arg, "</capability>", 13, 0);
|
||||
}
|
||||
if (sid) {
|
||||
count = asprintf(&buf, "</capabilities><session-id>%u</session-id></hello>", *sid);
|
||||
if (count == -1) {
|
||||
ERRMEM;
|
||||
ret = NC_MSG_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
count = asprintf(&buf, "</capabilities><session-id>%" PRIu32 "</session-id></hello>", *sid);
|
||||
NC_CHECK_ERRMEM_GOTO(count == -1, ret = NC_MSG_ERROR, cleanup);
|
||||
nc_write_clb((void *)&arg, buf, count, 0);
|
||||
free(buf);
|
||||
} else {
|
||||
|
@ -1179,7 +1095,7 @@ 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_getpw(uid_t uid, const char *username, struct passwd *pwd_buf, char **buf, size_t *buf_size)
|
||||
{
|
||||
struct passwd *pwd = NULL;
|
||||
long sys_size;
|
||||
|
@ -1197,16 +1113,21 @@ nc_getpwuid(uid_t uid, struct passwd *pwd_buf, char **buf, size_t *buf_size)
|
|||
|
||||
/* allocate some buffer */
|
||||
*buf = nc_realloc(*buf, *buf_size);
|
||||
if (!*buf) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!*buf, NULL);
|
||||
|
||||
ret = getpwuid_r(uid, pwd_buf, *buf, *buf_size, &pwd);
|
||||
if (username) {
|
||||
ret = getpwnam_r(username, pwd_buf, *buf, *buf_size, &pwd);
|
||||
} else {
|
||||
ret = getpwuid_r(uid, pwd_buf, *buf, *buf_size, &pwd);
|
||||
}
|
||||
} while (ret && (ret == ERANGE));
|
||||
|
||||
if (ret) {
|
||||
ERR(NULL, "Retrieving UID \"%lu\" passwd entry failed (%s).", (unsigned long int)uid, strerror(ret));
|
||||
if (username) {
|
||||
ERR(NULL, "Retrieving username \"%s\" passwd entry failed (%s).", username, strerror(ret));
|
||||
} else {
|
||||
ERR(NULL, "Retrieving UID \"%lu\" passwd entry failed (%s).", (unsigned long)uid, strerror(ret));
|
||||
}
|
||||
}
|
||||
return pwd;
|
||||
}
|
||||
|
|
113
src/log.c
113
src/log.c
|
@ -1,9 +1,11 @@
|
|||
/**
|
||||
* \file log.c
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2 - log functions
|
||||
* @file log.c
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 - log functions
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2024 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.
|
||||
|
@ -12,31 +14,38 @@
|
|||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* pthread_rwlock_t */
|
||||
|
||||
#include "log_p.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
#include <libssh/libssh.h>
|
||||
#endif
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
#include "compat.h"
|
||||
#include "libnetconf.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "session_p.h"
|
||||
|
||||
#define NC_MSG_SIZE 256
|
||||
|
||||
/**
|
||||
* @brief libnetconf verbose level variable
|
||||
*/
|
||||
volatile uint8_t verbose_level = 0;
|
||||
ATOMIC_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;
|
||||
ATOMIC_STORE_RELAXED(verbose_level, level);
|
||||
ly_log_level((LY_LOG_LEVEL)level);
|
||||
}
|
||||
|
||||
|
@ -51,98 +60,100 @@ struct {
|
|||
{NC_VERB_DEBUG_LOWLVL, "[DBL]"}
|
||||
};
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
static void
|
||||
nc_libssh_log_cb(int priority, const char *UNUSED(function), const char *buffer, void *UNUSED(userdata))
|
||||
{
|
||||
static char last_msg[NC_MSG_SIZE] = {0};
|
||||
static struct timespec last_print = {0}, cur_time;
|
||||
|
||||
/* check for repeated messages and do not print them */
|
||||
if (!strncmp(last_msg, buffer, NC_MSG_SIZE - 1)) {
|
||||
nc_realtime_get(&cur_time);
|
||||
if (last_print.tv_sec && (nc_time_diff(&cur_time, &last_print) < 1000)) {
|
||||
/* print another repeated message only after 1s */
|
||||
return;
|
||||
}
|
||||
|
||||
last_print = cur_time;
|
||||
} else {
|
||||
/* store the last message */
|
||||
strncpy(last_msg, buffer, NC_MSG_SIZE - 1);
|
||||
memset(&last_print, 0, sizeof last_print);
|
||||
}
|
||||
|
||||
/* print the message */
|
||||
nc_log_printf(NULL, priority, "SSH: %s", buffer);
|
||||
}
|
||||
|
||||
API void
|
||||
nc_libssh_thread_verbosity(int level)
|
||||
{
|
||||
ssh_set_log_callback(nc_libssh_log_cb);
|
||||
ssh_set_log_level(level);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
static void
|
||||
prv_vprintf(const struct nc_session *session, NC_VERB_LEVEL level, const char *format, va_list args)
|
||||
nc_log_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;
|
||||
char *msg;
|
||||
void *mem;
|
||||
int req_len;
|
||||
|
||||
prv_msg = malloc(PRV_MSG_INIT_SIZE);
|
||||
if (!prv_msg) {
|
||||
msg = malloc(NC_MSG_SIZE);
|
||||
if (!msg) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_copy(args2, args);
|
||||
|
||||
req_len = vsnprintf(prv_msg, PRV_MSG_INIT_SIZE - 1, format, args);
|
||||
req_len = vsnprintf(msg, NC_MSG_SIZE - 1, format, args);
|
||||
if (req_len == -1) {
|
||||
goto cleanup;
|
||||
} else if (req_len >= PRV_MSG_INIT_SIZE - 1) {
|
||||
} else if (req_len >= NC_MSG_SIZE - 1) {
|
||||
/* the length is not enough */
|
||||
++req_len;
|
||||
mem = realloc(prv_msg, req_len);
|
||||
mem = realloc(msg, req_len);
|
||||
if (!mem) {
|
||||
goto cleanup;
|
||||
}
|
||||
prv_msg = mem;
|
||||
msg = mem;
|
||||
|
||||
/* now print the full message */
|
||||
req_len = vsnprintf(prv_msg, req_len, format, args2);
|
||||
req_len = vsnprintf(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);
|
||||
print_clb(session, level, msg);
|
||||
} else if (session && session->id) {
|
||||
fprintf(stderr, "Session %u %s: %s\n", session->id, verb[level].label, prv_msg);
|
||||
fprintf(stderr, "Session %" PRIu32 " %s: %s\n", session->id, verb[level].label, msg);
|
||||
} else {
|
||||
fprintf(stderr, "%s: %s\n", verb[level].label, prv_msg);
|
||||
fprintf(stderr, "%s: %s\n", verb[level].label, msg);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(prv_msg);
|
||||
#undef PRV_MSG_INIT_SIZE
|
||||
free(msg);
|
||||
}
|
||||
|
||||
void
|
||||
prv_printf(const struct nc_session *session, NC_VERB_LEVEL level, const char *format, ...)
|
||||
nc_log_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);
|
||||
nc_log_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);
|
||||
}
|
||||
|
|
16
src/log.h
16
src/log.h
|
@ -3,6 +3,7 @@
|
|||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @brief libnetconf2 logger
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
@ -49,7 +50,7 @@ typedef enum NC_VERB_LEVEL {
|
|||
*/
|
||||
void nc_verbosity(NC_VERB_LEVEL level);
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/**
|
||||
* @brief Set libssh verbosity level.
|
||||
|
@ -68,20 +69,13 @@ void nc_verbosity(NC_VERB_LEVEL 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 *));
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* The callback is not set per-session, it is a global resource. It might be called with
|
||||
* a NULL session parameter.
|
||||
*
|
||||
* @param[in] clb Callback that is called for every message.
|
||||
*/
|
||||
|
|
69
src/log_p.h
69
src/log_p.h
|
@ -1,9 +1,11 @@
|
|||
/**
|
||||
* @file log.h
|
||||
* @file log_p.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 logger
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2024 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.
|
||||
|
@ -15,8 +17,9 @@
|
|||
#ifndef NC_LOG_PRIVATE_H_
|
||||
#define NC_LOG_PRIVATE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "log.h"
|
||||
|
||||
/*
|
||||
|
@ -30,25 +33,67 @@
|
|||
* @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, ...);
|
||||
void nc_log_printf(const struct nc_session *session, NC_VERB_LEVEL level, const char *format, ...);
|
||||
|
||||
/**
|
||||
* @brief Verbose level variable
|
||||
*/
|
||||
extern volatile uint8_t verbose_level;
|
||||
extern ATOMIC_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 ERR(session, ...) nc_log_printf(session, NC_VERB_ERROR, __VA_ARGS__)
|
||||
#define WRN(session, ...) if(ATOMIC_LOAD_RELAXED(verbose_level)>=NC_VERB_WARNING){nc_log_printf(session, NC_VERB_WARNING, __VA_ARGS__);}
|
||||
#define VRB(session, ...) if(ATOMIC_LOAD_RELAXED(verbose_level)>=NC_VERB_VERBOSE){nc_log_printf(session, NC_VERB_VERBOSE, __VA_ARGS__);}
|
||||
#define DBG(session, ...) if(ATOMIC_LOAD_RELAXED(verbose_level)>=NC_VERB_DEBUG){nc_log_printf(session, NC_VERB_DEBUG, __VA_ARGS__);}
|
||||
#define DBL(session, ...) if(ATOMIC_LOAD_RELAXED(verbose_level)>=NC_VERB_DEBUG_LOWLVL){nc_log_printf(session, NC_VERB_DEBUG_LOWLVL, __VA_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 ERRINITSRV ERR(NULL, "%s: server not initialized.", __func__)
|
||||
#define ERRINT ERR(NULL, "%s: internal error (%s:%d).", __func__, __FILE__, __LINE__)
|
||||
#define ERRARG(session, ARG) ERR(session, "Invalid argument %s (%s()).", #ARG, __func__)
|
||||
|
||||
#define NC_CHECK_SRV_INIT_RET(RET) if (!ATOMIC_LOAD_RELAXED(server_opts.new_session_id)) {ERRINITSRV; return (RET);}
|
||||
#define NC_CHECK_ERRMEM_RET(COND, RET) if ((COND)) {ERRMEM; return (RET);}
|
||||
#define NC_CHECK_ERRMEM_GOTO(COND, RET, GOTO) if ((COND)) {ERRMEM; RET; goto GOTO;}
|
||||
|
||||
#define GETMACRO1(_1, NAME, ...) NAME
|
||||
#define GETMACRO2(_1, _2, NAME, ...) NAME
|
||||
#define GETMACRO3(_1, _2, _3, NAME, ...) NAME
|
||||
#define GETMACRO4(_1, _2, _3, _4, NAME, ...) NAME
|
||||
#define GETMACRO5(_1, _2, _3, _4, _5, NAME, ...) NAME
|
||||
#define GETMACRO6(_1, _2, _3, _4, _5, _6, NAME, ...) NAME
|
||||
#define GETMACRO7(_1, _2, _3, _4, _5, _6, _7, NAME, ...) NAME
|
||||
#define GETMACRO8(_1, _2, _3, _4, _5, _6, _7, _8, NAME, ...) NAME
|
||||
|
||||
#define NC_CHECK_ARG_RET1(session, ARG, RETVAL) if (!(ARG)) {ERRARG(session, ARG);return RETVAL;}
|
||||
#define NC_CHECK_ARG_RET2(session, ARG1, ARG2, RETVAL)\
|
||||
NC_CHECK_ARG_RET1(session, ARG1, RETVAL);\
|
||||
NC_CHECK_ARG_RET1(session, ARG2, RETVAL)
|
||||
#define NC_CHECK_ARG_RET3(session, ARG1, ARG2, ARG3, RETVAL)\
|
||||
NC_CHECK_ARG_RET2(session, ARG1, ARG2, RETVAL);\
|
||||
NC_CHECK_ARG_RET1(session, ARG3, RETVAL)
|
||||
#define NC_CHECK_ARG_RET4(session, ARG1, ARG2, ARG3, ARG4, RETVAL)\
|
||||
NC_CHECK_ARG_RET3(session, ARG1, ARG2, ARG3, RETVAL);\
|
||||
NC_CHECK_ARG_RET1(session, ARG4, RETVAL)
|
||||
#define NC_CHECK_ARG_RET5(session, ARG1, ARG2, ARG3, ARG4, ARG5, RETVAL)\
|
||||
NC_CHECK_ARG_RET4(session, ARG1, ARG2, ARG3, ARG4, RETVAL);\
|
||||
NC_CHECK_ARG_RET1(session, ARG5, RETVAL)
|
||||
#define NC_CHECK_ARG_RET6(session, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, RETVAL)\
|
||||
NC_CHECK_ARG_RET5(session, ARG1, ARG2, ARG3, ARG4, ARG5, RETVAL);\
|
||||
NC_CHECK_ARG_RET1(session, ARG6, RETVAL)
|
||||
#define NC_CHECK_ARG_RET7(session, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, RETVAL)\
|
||||
NC_CHECK_ARG_RET6(session, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, RETVAL);\
|
||||
NC_CHECK_ARG_RET1(session, ARG7, RETVAL)
|
||||
|
||||
/**
|
||||
* @brief Function's parameters checking macro
|
||||
*
|
||||
* @param session Session that is logged.
|
||||
* @param ... Parameters of the function to check. The last parameter is the value that is returned on error.
|
||||
*/
|
||||
#define NC_CHECK_ARG_RET(session, ...) GETMACRO8(__VA_ARGS__, NC_CHECK_ARG_RET7, NC_CHECK_ARG_RET6, NC_CHECK_ARG_RET5,\
|
||||
NC_CHECK_ARG_RET4, NC_CHECK_ARG_RET3, NC_CHECK_ARG_RET2, NC_CHECK_ARG_RET1, DUMMY) (session, __VA_ARGS__)
|
||||
|
||||
#endif /* NC_LOG_PRIVATE_H_ */
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/**
|
||||
* \file messages.c
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2 - NETCONF messages functions
|
||||
* @file messages.c
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @brief libnetconf2 - NETCONF messages functions
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
@ -12,15 +13,21 @@
|
|||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* pthread_rwlock_t, strdup */
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "libnetconf.h"
|
||||
#include "compat.h"
|
||||
#include "config.h"
|
||||
#include "log_p.h"
|
||||
#include "messages_client.h"
|
||||
#include "messages_p.h"
|
||||
#include "netconf.h"
|
||||
|
||||
const char *rpcedit_dfltop2str[] = {NULL, "merge", "replace", "none"};
|
||||
const char *rpcedit_testopt2str[] = {NULL, "test-then-set", "set", "test-only"};
|
||||
|
@ -29,10 +36,7 @@ const char *rpcedit_erropt2str[] = {NULL, "stop-on-error", "continue-on-error",
|
|||
API NC_RPC_TYPE
|
||||
nc_rpc_get_type(const struct nc_rpc *rpc)
|
||||
{
|
||||
if (!rpc) {
|
||||
ERRARG("rpc");
|
||||
return 0;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, rpc, 0);
|
||||
|
||||
return rpc->type;
|
||||
}
|
||||
|
@ -42,16 +46,14 @@ nc_rpc_act_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype)
|
|||
{
|
||||
struct nc_rpc_act_generic *rpc;
|
||||
|
||||
if (!data || data->next || (data->prev != data)) {
|
||||
ERRARG("data");
|
||||
NC_CHECK_ARG_RET(NULL, data, NULL);
|
||||
if (data->next || (data->prev != data)) {
|
||||
ERR(NULL, "nc_rpc_act_generic missing data");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_ACT_GENERIC;
|
||||
rpc->has_data = 1;
|
||||
|
@ -73,16 +75,10 @@ nc_rpc_act_generic_xml(const char *xml_str, NC_PARAMTYPE paramtype)
|
|||
{
|
||||
struct nc_rpc_act_generic *rpc;
|
||||
|
||||
if (!xml_str) {
|
||||
ERRARG("xml_str");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, xml_str, NULL);
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_ACT_GENERIC;
|
||||
rpc->has_data = 0;
|
||||
|
@ -101,10 +97,7 @@ nc_rpc_getconfig(NC_DATASTORE source, const char *filter, NC_WD_MODE wd_mode, NC
|
|||
{
|
||||
struct nc_rpc_getconfig *rpc;
|
||||
|
||||
if (!source) {
|
||||
ERRARG("source");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, source, NULL);
|
||||
|
||||
if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
|
||||
ERR(NULL, "Filter is neither an XML subtree nor an XPath expression (invalid first char '%c').", filter[0]);
|
||||
|
@ -112,10 +105,7 @@ nc_rpc_getconfig(NC_DATASTORE source, const char *filter, NC_WD_MODE wd_mode, NC
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_GETCONFIG;
|
||||
rpc->source = source;
|
||||
|
@ -136,13 +126,7 @@ nc_rpc_edit(NC_DATASTORE target, NC_RPC_EDIT_DFLTOP default_op, NC_RPC_EDIT_TEST
|
|||
{
|
||||
struct nc_rpc_edit *rpc;
|
||||
|
||||
if (!target) {
|
||||
ERRARG("target");
|
||||
return NULL;
|
||||
} else if (!edit_content) {
|
||||
ERRARG("edit_content");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, target, edit_content, NULL);
|
||||
|
||||
if (edit_content[0] && (edit_content[0] != '<') && !isalpha(edit_content[0])) {
|
||||
ERR(NULL, "<edit-config> content is neither a URL nor an XML config (invalid first char '%c').", edit_content[0]);
|
||||
|
@ -150,10 +134,7 @@ nc_rpc_edit(NC_DATASTORE target, NC_RPC_EDIT_DFLTOP default_op, NC_RPC_EDIT_TEST
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_EDIT;
|
||||
rpc->target = target;
|
||||
|
@ -176,13 +157,7 @@ nc_rpc_copy(NC_DATASTORE target, const char *url_trg, NC_DATASTORE source, const
|
|||
{
|
||||
struct nc_rpc_copy *rpc;
|
||||
|
||||
if (!target) {
|
||||
ERRARG("target");
|
||||
return NULL;
|
||||
} else if (!source) {
|
||||
ERRARG("source");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, target, source, NULL);
|
||||
|
||||
if (url_or_config_src && url_or_config_src[0] && (url_or_config_src[0] != '<') && !isalpha(url_or_config_src[0])) {
|
||||
ERR(NULL, "<copy-config> source is neither a URL nor an XML config (invalid first char '%c').", url_or_config_src[0]);
|
||||
|
@ -190,10 +165,7 @@ nc_rpc_copy(NC_DATASTORE target, const char *url_trg, NC_DATASTORE source, const
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_COPY;
|
||||
rpc->target = target;
|
||||
|
@ -219,16 +191,10 @@ nc_rpc_delete(NC_DATASTORE target, const char *url, NC_PARAMTYPE paramtype)
|
|||
{
|
||||
struct nc_rpc_delete *rpc;
|
||||
|
||||
if (!target) {
|
||||
ERRARG("target");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, target, NULL);
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_DELETE;
|
||||
rpc->target = target;
|
||||
|
@ -247,16 +213,10 @@ nc_rpc_lock(NC_DATASTORE target)
|
|||
{
|
||||
struct nc_rpc_lock *rpc;
|
||||
|
||||
if (!target) {
|
||||
ERRARG("target");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, target, NULL);
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_LOCK;
|
||||
rpc->target = target;
|
||||
|
@ -269,16 +229,10 @@ nc_rpc_unlock(NC_DATASTORE target)
|
|||
{
|
||||
struct nc_rpc_lock *rpc;
|
||||
|
||||
if (!target) {
|
||||
ERRARG("target");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, target, NULL);
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_UNLOCK;
|
||||
rpc->target = target;
|
||||
|
@ -297,10 +251,7 @@ nc_rpc_get(const char *filter, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype)
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_GET;
|
||||
if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
|
||||
|
@ -319,16 +270,10 @@ nc_rpc_kill(uint32_t session_id)
|
|||
{
|
||||
struct nc_rpc_kill *rpc;
|
||||
|
||||
if (!session_id) {
|
||||
ERRARG("session_id");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, session_id, NULL);
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_KILL;
|
||||
rpc->sid = session_id;
|
||||
|
@ -343,10 +288,7 @@ nc_rpc_commit(int confirmed, uint32_t confirm_timeout, const char *persist, cons
|
|||
struct nc_rpc_commit *rpc;
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_COMMIT;
|
||||
rpc->confirmed = confirmed;
|
||||
|
@ -372,10 +314,7 @@ nc_rpc_discard(void)
|
|||
struct nc_rpc *rpc;
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_DISCARD;
|
||||
|
||||
|
@ -388,10 +327,7 @@ nc_rpc_cancel(const char *persist_id, NC_PARAMTYPE paramtype)
|
|||
struct nc_rpc_cancel *rpc;
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_CANCEL;
|
||||
if (persist_id && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
|
||||
|
@ -409,10 +345,7 @@ nc_rpc_validate(NC_DATASTORE source, const char *url_or_config, NC_PARAMTYPE par
|
|||
{
|
||||
struct nc_rpc_validate *rpc;
|
||||
|
||||
if (!source) {
|
||||
ERRARG("source");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, source, NULL);
|
||||
|
||||
if (url_or_config && url_or_config[0] && (url_or_config[0] != '<') && !isalpha(url_or_config[0])) {
|
||||
ERR(NULL, "<validate> source is neither a URL nor an XML config (invalid first char '%c').", url_or_config[0]);
|
||||
|
@ -420,10 +353,7 @@ nc_rpc_validate(NC_DATASTORE source, const char *url_or_config, NC_PARAMTYPE par
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_VALIDATE;
|
||||
rpc->source = source;
|
||||
|
@ -442,16 +372,10 @@ nc_rpc_getschema(const char *identifier, const char *version, const char *format
|
|||
{
|
||||
struct nc_rpc_getschema *rpc;
|
||||
|
||||
if (!identifier) {
|
||||
ERRARG("identifier");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, identifier, NULL);
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_GETSCHEMA;
|
||||
if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
|
||||
|
@ -486,10 +410,7 @@ nc_rpc_subscribe(const char *stream_name, const char *filter, const char *start_
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_SUBSCRIBE;
|
||||
if (stream_name && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
|
||||
|
@ -525,19 +446,15 @@ nc_rpc_getdata(const char *datastore, const char *filter, const char *config_fil
|
|||
struct nc_rpc_getdata *rpc = NULL;
|
||||
int i;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, datastore, NULL);
|
||||
|
||||
if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
|
||||
ERR(NULL, "Filter is neither an XML subtree nor an XPath expression (invalid first char '%c').", filter[0]);
|
||||
return NULL;
|
||||
} else if (!datastore) {
|
||||
ERRARG("datastore");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rpc = calloc(1, sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
|
||||
|
||||
rpc->type = NC_RPC_GETDATA;
|
||||
|
@ -558,16 +475,10 @@ nc_rpc_getdata(const char *datastore, const char *filter, const char *config_fil
|
|||
}
|
||||
if (origin_filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
|
||||
rpc->origin_filter = malloc(origin_filter_count * sizeof *rpc->origin_filter);
|
||||
if (!rpc->origin_filter) {
|
||||
ERRMEM;
|
||||
goto error;
|
||||
}
|
||||
NC_CHECK_ERRMEM_GOTO(!rpc->origin_filter, , error);
|
||||
for (i = 0; i < origin_filter_count; ++i) {
|
||||
rpc->origin_filter[i] = strdup(origin_filter[i]);
|
||||
if (!rpc->origin_filter[i]) {
|
||||
ERRMEM;
|
||||
goto error;
|
||||
}
|
||||
NC_CHECK_ERRMEM_GOTO(!rpc->origin_filter[i], , error);
|
||||
++rpc->origin_filter_count;
|
||||
}
|
||||
} else {
|
||||
|
@ -591,13 +502,7 @@ nc_rpc_editdata(const char *datastore, NC_RPC_EDIT_DFLTOP default_op, const char
|
|||
{
|
||||
struct nc_rpc_editdata *rpc;
|
||||
|
||||
if (!datastore) {
|
||||
ERRARG("datastore");
|
||||
return NULL;
|
||||
} else if (!edit_content) {
|
||||
ERRARG("edit_content");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, datastore, edit_content, NULL);
|
||||
|
||||
if (edit_content[0] && (edit_content[0] != '<') && !isalpha(edit_content[0])) {
|
||||
ERR(NULL, "<edit-data> content is neither a URL nor an XML config (invalid first char '%c').", edit_content[0]);
|
||||
|
@ -605,10 +510,7 @@ nc_rpc_editdata(const char *datastore, NC_RPC_EDIT_DFLTOP default_op, const char
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_EDITDATA;
|
||||
if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
|
||||
|
@ -633,10 +535,7 @@ nc_rpc_establishsub(const char *filter, const char *stream_name, const char *sta
|
|||
{
|
||||
struct nc_rpc_establishsub *rpc;
|
||||
|
||||
if (!stream_name) {
|
||||
ERRARG("stream_name");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, stream_name, NULL);
|
||||
|
||||
if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
|
||||
ERR(NULL, "Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').",
|
||||
|
@ -645,10 +544,7 @@ nc_rpc_establishsub(const char *filter, const char *stream_name, const char *sta
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_ESTABLISHSUB;
|
||||
if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
|
||||
|
@ -686,10 +582,7 @@ nc_rpc_modifysub(uint32_t id, const char *filter, const char *stop_time, NC_PARA
|
|||
{
|
||||
struct nc_rpc_modifysub *rpc;
|
||||
|
||||
if (!id) {
|
||||
ERRARG("id");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, id, NULL);
|
||||
|
||||
if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
|
||||
ERR(NULL, "Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').",
|
||||
|
@ -698,10 +591,7 @@ nc_rpc_modifysub(uint32_t id, const char *filter, const char *stop_time, NC_PARA
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_MODIFYSUB;
|
||||
rpc->id = id;
|
||||
|
@ -725,16 +615,10 @@ nc_rpc_deletesub(uint32_t id)
|
|||
{
|
||||
struct nc_rpc_deletesub *rpc;
|
||||
|
||||
if (!id) {
|
||||
ERRARG("id");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, id, NULL);
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_DELETESUB;
|
||||
rpc->id = id;
|
||||
|
@ -747,16 +631,10 @@ nc_rpc_killsub(uint32_t id)
|
|||
{
|
||||
struct nc_rpc_killsub *rpc;
|
||||
|
||||
if (!id) {
|
||||
ERRARG("id");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, id, NULL);
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_KILLSUB;
|
||||
rpc->id = id;
|
||||
|
@ -770,13 +648,7 @@ nc_rpc_establishpush_periodic(const char *datastore, const char *filter, const c
|
|||
{
|
||||
struct nc_rpc_establishpush *rpc;
|
||||
|
||||
if (!datastore) {
|
||||
ERRARG("datastore");
|
||||
return NULL;
|
||||
} else if (!period) {
|
||||
ERRARG("period");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, datastore, period, NULL);
|
||||
|
||||
if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
|
||||
ERR(NULL, "Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').",
|
||||
|
@ -785,10 +657,7 @@ nc_rpc_establishpush_periodic(const char *datastore, const char *filter, const c
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_ESTABLISHPUSH;
|
||||
if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
|
||||
|
@ -829,11 +698,9 @@ nc_rpc_establishpush_onchange(const char *datastore, const char *filter, const c
|
|||
{
|
||||
struct nc_rpc_establishpush *rpc;
|
||||
uint32_t i;
|
||||
void *tmp;
|
||||
|
||||
if (!datastore) {
|
||||
ERRARG("datastore");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, datastore, NULL);
|
||||
|
||||
if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
|
||||
ERR(NULL, "Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').",
|
||||
|
@ -842,10 +709,7 @@ nc_rpc_establishpush_onchange(const char *datastore, const char *filter, const c
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_ESTABLISHPUSH;
|
||||
if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
|
||||
|
@ -874,7 +738,15 @@ nc_rpc_establishpush_onchange(const char *datastore, const char *filter, const c
|
|||
if (excluded_change && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
|
||||
rpc->excluded_change = NULL;
|
||||
for (i = 0; excluded_change[i]; ++i) {
|
||||
rpc->excluded_change = realloc(rpc->excluded_change, (i + 2) * sizeof *rpc->excluded_change);
|
||||
tmp = realloc(rpc->excluded_change, (i + 2) * sizeof *rpc->excluded_change);
|
||||
if (!tmp) {
|
||||
/* in case we fail to alloc, just free all the excluded changes, but return the rpc anyways */
|
||||
ERRMEM;
|
||||
free(rpc->excluded_change);
|
||||
rpc->excluded_change = NULL;
|
||||
break;
|
||||
}
|
||||
rpc->excluded_change = tmp;
|
||||
rpc->excluded_change[i] = strdup(excluded_change[i]);
|
||||
rpc->excluded_change[i + 1] = NULL;
|
||||
}
|
||||
|
@ -892,13 +764,7 @@ nc_rpc_modifypush_periodic(uint32_t id, const char *datastore, const char *filte
|
|||
{
|
||||
struct nc_rpc_modifypush *rpc;
|
||||
|
||||
if (!id) {
|
||||
ERRARG("id");
|
||||
return NULL;
|
||||
} else if (!datastore) {
|
||||
ERRARG("datastore");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, id, datastore, NULL);
|
||||
|
||||
if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
|
||||
ERR(NULL, "Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').",
|
||||
|
@ -907,10 +773,7 @@ nc_rpc_modifypush_periodic(uint32_t id, const char *datastore, const char *filte
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_MODIFYPUSH;
|
||||
rpc->id = id;
|
||||
|
@ -947,13 +810,7 @@ nc_rpc_modifypush_onchange(uint32_t id, const char *datastore, const char *filte
|
|||
{
|
||||
struct nc_rpc_modifypush *rpc;
|
||||
|
||||
if (!id) {
|
||||
ERRARG("id");
|
||||
return NULL;
|
||||
} else if (!datastore) {
|
||||
ERRARG("datastore");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, id, datastore, NULL);
|
||||
|
||||
if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
|
||||
ERR(NULL, "Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').",
|
||||
|
@ -962,10 +819,7 @@ nc_rpc_modifypush_onchange(uint32_t id, const char *datastore, const char *filte
|
|||
}
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_MODIFYPUSH;
|
||||
rpc->id = id;
|
||||
|
@ -996,16 +850,10 @@ nc_rpc_resyncsub(uint32_t id)
|
|||
{
|
||||
struct nc_rpc_resyncsub *rpc;
|
||||
|
||||
if (!id) {
|
||||
ERRARG("id");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, id, NULL);
|
||||
|
||||
rpc = malloc(sizeof *rpc);
|
||||
if (!rpc) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!rpc, NULL);
|
||||
|
||||
rpc->type = NC_RPC_RESYNCSUB;
|
||||
rpc->id = id;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2's public functions and structures of NETCONF client messages.
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @brief libnetconf2's private functions and structures of NETCONF messages.
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
@ -15,10 +16,13 @@
|
|||
#ifndef NC_MESSAGES_P_H_
|
||||
#define NC_MESSAGES_P_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "messages_client.h"
|
||||
#include "messages_server.h"
|
||||
#include "netconf.h"
|
||||
|
||||
extern const char *rpcedit_dfltop2str[];
|
||||
extern const char *rpcedit_testopt2str[];
|
||||
|
@ -65,6 +69,7 @@ struct nc_rpc {
|
|||
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 */
|
||||
|
@ -220,6 +225,7 @@ struct nc_rpc_establishpush {
|
|||
char *stop;
|
||||
char *encoding;
|
||||
int periodic;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t period;
|
||||
|
@ -241,6 +247,7 @@ struct nc_rpc_modifypush {
|
|||
char *filter; /**< XML subtree (starts with '<'), an XPath (starts with '/'), or reference (start with alpha) */
|
||||
char *stop;
|
||||
int periodic;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t period;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/**
|
||||
* \file messages_server.c
|
||||
* \author Michal Vasko <mvasko@cesnet.cz>
|
||||
* \brief libnetconf2 - server NETCONF messages functions
|
||||
* @file messages_server.c
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 - server NETCONF messages functions
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2015 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
@ -12,6 +13,8 @@
|
|||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* pthread_rwlock_t, strdup */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -21,10 +24,11 @@
|
|||
#include <libyang/libyang.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "libnetconf.h"
|
||||
#include "session_server.h"
|
||||
|
||||
extern struct nc_server_opts server_opts;
|
||||
#include "config.h"
|
||||
#include "log_p.h"
|
||||
#include "messages_p.h"
|
||||
#include "messages_server.h"
|
||||
#include "netconf.h"
|
||||
|
||||
API struct nc_server_reply *
|
||||
nc_server_reply_ok(void)
|
||||
|
@ -32,10 +36,7 @@ nc_server_reply_ok(void)
|
|||
struct nc_server_reply *ret;
|
||||
|
||||
ret = malloc(sizeof *ret);
|
||||
if (!ret) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!ret, NULL);
|
||||
|
||||
ret->type = NC_RPL_OK;
|
||||
return ret;
|
||||
|
@ -46,16 +47,15 @@ nc_server_reply_data(struct lyd_node *data, NC_WD_MODE wd, NC_PARAMTYPE paramtyp
|
|||
{
|
||||
struct nc_server_reply_data *ret;
|
||||
|
||||
if (!data) {
|
||||
ERRARG("data");
|
||||
NC_CHECK_ARG_RET(NULL, data, NULL);
|
||||
|
||||
if (!(data->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
|
||||
ERR(NULL, "nc_server_reply_data bad data");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = malloc(sizeof *ret);
|
||||
if (!ret) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!ret, NULL);
|
||||
|
||||
ret->type = NC_RPL_DATA;
|
||||
ret->wd = wd;
|
||||
|
@ -80,16 +80,10 @@ nc_server_reply_err(struct lyd_node *err)
|
|||
{
|
||||
struct nc_server_reply_error *ret;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, NULL);
|
||||
|
||||
ret = malloc(sizeof *ret);
|
||||
if (!ret) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!ret, NULL);
|
||||
|
||||
ret->type = NC_RPL_ERROR;
|
||||
ret->err = err;
|
||||
|
@ -101,11 +95,10 @@ 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");
|
||||
NC_CHECK_ARG_RET(NULL, reply, err, -1);
|
||||
|
||||
if (reply->type != NC_RPL_ERROR) {
|
||||
ERR(NULL, "nc_server_reply_add_err() bad reply type");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -119,8 +112,10 @@ 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");
|
||||
NC_CHECK_ARG_RET(NULL, reply, NULL);
|
||||
|
||||
if (reply->type != NC_RPL_ERROR) {
|
||||
ERR(NULL, "nc_server_reply_get_last_err() bad reply type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -270,10 +265,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
|
|||
const char *arg1, *arg2;
|
||||
uint32_t sid;
|
||||
|
||||
if (!tag) {
|
||||
ERRARG("tag");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, tag, NULL);
|
||||
|
||||
/* rpc-error */
|
||||
if (lyd_new_opaq2(NULL, ctx, "rpc-error", NULL, NULL, NC_NS_BASE, &err)) {
|
||||
|
@ -291,7 +283,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
|
|||
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");
|
||||
ERRARG(NULL, "type");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
@ -304,7 +296,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
|
|||
case NC_ERR_UNKNOWN_ATTR:
|
||||
type = (NC_ERR_TYPE)va_arg(ap, int);
|
||||
if (type == NC_ERR_TYPE_TRAN) {
|
||||
ERRARG("type");
|
||||
ERRARG(NULL, "type");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
@ -313,14 +305,14 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
|
|||
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");
|
||||
ERRARG(NULL, "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");
|
||||
ERRARG(NULL, "type");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
@ -334,7 +326,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
|
|||
case NC_ERR_OP_FAILED:
|
||||
type = (NC_ERR_TYPE)va_arg(ap, int);
|
||||
if (type == NC_ERR_TYPE_TRAN) {
|
||||
ERRARG("type");
|
||||
ERRARG(NULL, "type");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
@ -342,7 +334,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
|
|||
type = NC_ERR_TYPE_RPC;
|
||||
break;
|
||||
default:
|
||||
ERRARG("tag");
|
||||
ERRARG(NULL, "tag");
|
||||
goto fail;
|
||||
}
|
||||
if (lyd_new_opaq2(err, NULL, "error-type", nc_err_type2str(type), NULL, NC_NS_BASE, NULL)) {
|
||||
|
@ -419,7 +411,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
|
|||
nc_err_set_msg(err, "A message could not be handled because it failed to be parsed correctly.", "en");
|
||||
break;
|
||||
default:
|
||||
ERRARG("tag");
|
||||
ERRARG(NULL, "tag");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -466,7 +458,7 @@ nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
|
|||
nc_err_set_sid(err, sid);
|
||||
break;
|
||||
default:
|
||||
ERRARG("tag");
|
||||
ERRARG(NULL, "tag");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -484,10 +476,7 @@ nc_err_get_type(const struct lyd_node *err)
|
|||
{
|
||||
struct lyd_node *match;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return 0;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, 0);
|
||||
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-type", &match);
|
||||
if (match) {
|
||||
|
@ -502,10 +491,7 @@ nc_err_get_tag(const struct lyd_node *err)
|
|||
{
|
||||
struct lyd_node *match;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return 0;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, 0);
|
||||
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-tag", &match);
|
||||
if (match) {
|
||||
|
@ -520,13 +506,7 @@ 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;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, error_app_tag, -1);
|
||||
|
||||
/* remove previous node */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
|
||||
|
@ -546,10 +526,7 @@ nc_err_get_app_tag(const struct lyd_node *err)
|
|||
{
|
||||
struct lyd_node *match;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, NULL);
|
||||
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
|
||||
if (match) {
|
||||
|
@ -564,13 +541,7 @@ 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;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, error_path, -1);
|
||||
|
||||
/* remove previous node */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
|
||||
|
@ -590,10 +561,7 @@ nc_err_get_path(const struct lyd_node *err)
|
|||
{
|
||||
struct lyd_node *match;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return 0;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, NULL);
|
||||
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
|
||||
if (match) {
|
||||
|
@ -609,20 +577,15 @@ 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;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, error_message, -1);
|
||||
|
||||
/* remove previous message */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
|
||||
if (match) {
|
||||
lyd_free_tree(match);
|
||||
/* Change the value of error-message and keep order of elements to comply with appendix-B in RFC 6241. */
|
||||
lydict_remove(LYD_CTX(err), ((struct lyd_node_opaq *)match)->value);
|
||||
lydict_insert(LYD_CTX(err), error_message, 0, &(((struct lyd_node_opaq *)match)->value));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lyd_new_opaq2(err, NULL, "error-message", error_message, NULL, NC_NS_BASE, &match)) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -639,10 +602,7 @@ nc_err_get_msg(const struct lyd_node *err)
|
|||
{
|
||||
struct lyd_node *match;
|
||||
|
||||
if (!err) {
|
||||
ERRARG("err");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, NULL);
|
||||
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
|
||||
if (match) {
|
||||
|
@ -658,10 +618,7 @@ 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;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, -1);
|
||||
|
||||
/* find error-info */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
|
||||
|
@ -688,13 +645,7 @@ 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;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, attr_name, -1);
|
||||
|
||||
/* find error-info */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
|
||||
|
@ -714,13 +665,7 @@ 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;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, elem_name, -1);
|
||||
|
||||
/* find error-info */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
|
||||
|
@ -740,13 +685,7 @@ 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;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, ns_name, -1);
|
||||
|
||||
/* find error-info */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
|
||||
|
@ -766,13 +705,7 @@ 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;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, err, other, -1);
|
||||
|
||||
/* find error-info */
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
|
||||
|
@ -837,13 +770,7 @@ nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramt
|
|||
struct lyd_node *elem;
|
||||
int found;
|
||||
|
||||
if (!event) {
|
||||
ERRARG("event");
|
||||
return NULL;
|
||||
} else if (!eventtime) {
|
||||
ERRARG("eventtime");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, event, eventtime, NULL);
|
||||
|
||||
/* check that there is a notification */
|
||||
found = 0;
|
||||
|
@ -855,11 +782,13 @@ nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramt
|
|||
LYD_TREE_DFS_END(event, elem);
|
||||
}
|
||||
if (!found) {
|
||||
ERRARG("event");
|
||||
ERRARG(NULL, "event");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ntf = malloc(sizeof *ntf);
|
||||
NC_CHECK_ERRMEM_RET(!ntf, NULL);
|
||||
|
||||
if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
|
||||
ntf->eventtime = strdup(eventtime);
|
||||
if (lyd_dup_single(event, NULL, LYD_DUP_RECURSIVE, &ntf->ntf)) {
|
||||
|
@ -892,10 +821,7 @@ nc_server_notif_free(struct nc_server_notif *notif)
|
|||
API const char *
|
||||
nc_server_notif_get_time(const struct nc_server_notif *notif)
|
||||
{
|
||||
if (!notif) {
|
||||
ERRARG("notif");
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, notif, NULL);
|
||||
|
||||
return notif->eventtime;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2's functions and structures of server NETCONF messages.
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2015-2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
@ -19,9 +20,11 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "netconf.h"
|
||||
#include "session.h"
|
||||
|
||||
|
@ -95,7 +98,7 @@ 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
|
||||
* @param[in] data Reply data tree pointing to the RPC/action itself. 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.
|
||||
|
@ -106,7 +109,7 @@ struct nc_server_reply *nc_server_reply_data(struct lyd_node *data, NC_WD_MODE w
|
|||
/**
|
||||
* @brief Create an ERROR rpc-reply object.
|
||||
*
|
||||
* @param[in] err Errors as opaque data node tree. It will be freed with the returned object.
|
||||
* @param[in] err Errors created by nc_err(). 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);
|
||||
|
@ -115,7 +118,7 @@ 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.
|
||||
* @param[in] err Error created by nc_err(). 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);
|
||||
|
@ -165,6 +168,7 @@ const struct lyd_node *nc_server_reply_get_last_err(const struct nc_server_reply
|
|||
* - #NC_ERR_DATA_MISSING
|
||||
* - #NC_ERR_MALFORMED_MSG
|
||||
* - no additional arguments
|
||||
* @param[in] ... Additional arguments depending on the @p tag used.
|
||||
* @return Opaque data node tree representing the error.
|
||||
*/
|
||||
struct lyd_node *nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...);
|
||||
|
@ -293,11 +297,11 @@ 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.
|
||||
* object, so the caller is supposed to not free the tree on its own, but only via freeing 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()
|
||||
* @return Newly created structure of the Event Notification object to be sent to the clients via nc_server_notif_send()
|
||||
* and freed using nc_server_notif_free().
|
||||
*/
|
||||
struct nc_server_notif *nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramtype);
|
||||
|
@ -306,8 +310,8 @@ struct nc_server_notif *nc_server_notif_new(struct lyd_node *event, char *eventt
|
|||
* @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] notif NETCONF Notification object to send via specified session. Object can be created by
|
||||
* nc_server_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,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @brief libnetconf2's general public functions and structures definitions.
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
@ -19,8 +20,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/**
|
||||
* @addtogroup misc
|
||||
* @{
|
||||
|
|
4707
src/server_config.c
Normal file
4707
src/server_config.c
Normal file
File diff suppressed because it is too large
Load diff
1442
src/server_config.h
Normal file
1442
src/server_config.h
Normal file
File diff suppressed because it is too large
Load diff
445
src/server_config_ks.c
Normal file
445
src/server_config_ks.c
Normal file
|
@ -0,0 +1,445 @@
|
|||
/**
|
||||
* @file server_config_ks.c
|
||||
* @author Roman Janota <janota@cesnet.cz>
|
||||
* @brief libnetconf2 keystore configuration functions
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2023 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 _GNU_SOURCE
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "log_p.h"
|
||||
#include "server_config_p.h"
|
||||
#include "session_p.h"
|
||||
|
||||
/**
|
||||
* @brief Get the pointer to an asymmetric key structure based on node's location in the YANG data.
|
||||
*
|
||||
* @param[in] node Node from which the asymmetric key containing this node is derived.
|
||||
* @param[out] askey Asymmetric key containing the node.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_server_config_get_asymmetric_key(const struct lyd_node *node, struct nc_asymmetric_key **askey)
|
||||
{
|
||||
uint16_t i;
|
||||
const char *askey_name;
|
||||
struct nc_keystore *ks;
|
||||
const char *node_name = LYD_NAME(node);
|
||||
|
||||
assert(node && askey);
|
||||
|
||||
while (node) {
|
||||
if (!strcmp(LYD_NAME(node), "asymmetric-key")) {
|
||||
break;
|
||||
}
|
||||
node = lyd_parent(node);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
ERR(NULL, "Node \"%s\" is not contained in an asymmetric-key subtree.", node_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
node = lyd_child(node);
|
||||
assert(!strcmp(LYD_NAME(node), "name"));
|
||||
askey_name = lyd_get_value(node);
|
||||
|
||||
ks = &server_opts.keystore;
|
||||
for (i = 0; i < ks->asym_key_count; i++) {
|
||||
if (!strcmp(ks->asym_keys[i].name, askey_name)) {
|
||||
*askey = &ks->asym_keys[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ERR(NULL, "Asymmetric key \"%s\" was not found.", askey_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the pointer to a certificate structure based on node's location in the YANG data.
|
||||
*
|
||||
* @param[in] node Node from which the certificate containing this node is derived.
|
||||
* @param[out] cert Certificate containing the node.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_server_config_get_certificate(const struct lyd_node *node, struct nc_certificate **cert)
|
||||
{
|
||||
uint16_t i;
|
||||
const char *cert_name;
|
||||
struct nc_asymmetric_key *askey;
|
||||
const char *node_name = LYD_NAME(node);
|
||||
|
||||
assert(node && cert);
|
||||
|
||||
if (nc_server_config_get_asymmetric_key(node, &askey)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (node) {
|
||||
if (!strcmp(LYD_NAME(node), "certificate")) {
|
||||
break;
|
||||
}
|
||||
node = lyd_parent(node);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", node_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
node = lyd_child(node);
|
||||
assert(!strcmp(LYD_NAME(node), "name"));
|
||||
cert_name = lyd_get_value(node);
|
||||
|
||||
for (i = 0; i < askey->cert_count; i++) {
|
||||
if (!strcmp(askey->certs[i].name, cert_name)) {
|
||||
*cert = &askey->certs[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ERR(NULL, "Certificate \"%s\" was not found.", cert_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
nc_server_config_ks_del_asymmetric_key_cert(struct nc_asymmetric_key *key, struct nc_certificate *cert)
|
||||
{
|
||||
free(cert->name);
|
||||
free(cert->data);
|
||||
|
||||
key->cert_count--;
|
||||
if (!key->cert_count) {
|
||||
free(key->certs);
|
||||
key->certs = NULL;
|
||||
} else if (cert != &key->certs[key->cert_count]) {
|
||||
memcpy(cert, &key->certs[key->cert_count], sizeof *key->certs);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nc_server_config_ks_del_asymmetric_key(struct nc_asymmetric_key *key)
|
||||
{
|
||||
uint16_t i, cert_count;
|
||||
struct nc_keystore *ks = &server_opts.keystore;
|
||||
|
||||
free(key->name);
|
||||
free(key->pubkey_data);
|
||||
free(key->privkey_data);
|
||||
|
||||
cert_count = key->cert_count;
|
||||
for (i = 0; i < cert_count; i++) {
|
||||
nc_server_config_ks_del_asymmetric_key_cert(key, &key->certs[i]);
|
||||
}
|
||||
|
||||
ks->asym_key_count--;
|
||||
if (!ks->asym_key_count) {
|
||||
free(ks->asym_keys);
|
||||
ks->asym_keys = NULL;
|
||||
} else if (key != &ks->asym_keys[ks->asym_key_count]) {
|
||||
memcpy(key, &ks->asym_keys[ks->asym_key_count], sizeof *ks->asym_keys);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ks_asymmetric_keys(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
struct nc_keystore *ks = &server_opts.keystore;
|
||||
uint16_t i, asym_key_count;
|
||||
|
||||
(void) node;
|
||||
|
||||
if (op == NC_OP_DELETE) {
|
||||
asym_key_count = ks->asym_key_count;
|
||||
for (i = 0; i < asym_key_count; i++) {
|
||||
nc_server_config_ks_del_asymmetric_key(&ks->asym_keys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nc_server_config_ks_keystore(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
(void) node;
|
||||
|
||||
if (op == NC_OP_DELETE) {
|
||||
nc_server_config_ks_asymmetric_keys(NULL, NC_OP_DELETE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ks_create_asymmetric_key(const struct lyd_node *node)
|
||||
{
|
||||
struct nc_keystore *ks = &server_opts.keystore;
|
||||
|
||||
node = lyd_child(node);
|
||||
assert(!strcmp(LYD_NAME(node), "name"));
|
||||
|
||||
return nc_server_config_realloc(lyd_get_value(node), (void **)&ks->asym_keys, sizeof *ks->asym_keys, &ks->asym_key_count);
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ks_asymmetric_key(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
int ret = 0;
|
||||
struct nc_asymmetric_key *key;
|
||||
|
||||
assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
|
||||
|
||||
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
|
||||
ret = nc_server_config_ks_create_asymmetric_key(node);
|
||||
} else {
|
||||
if (nc_server_config_get_asymmetric_key(node, &key)) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
nc_server_config_ks_del_asymmetric_key(key);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ks_public_key_format(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
struct nc_asymmetric_key *key;
|
||||
const char *format;
|
||||
|
||||
(void) op;
|
||||
|
||||
assert(!strcmp(LYD_NAME(node), "public-key-format"));
|
||||
|
||||
if (nc_server_config_get_asymmetric_key(node, &key)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
format = ((struct lyd_node_term *)node)->value.ident->name;
|
||||
if (!strcmp(format, "ssh-public-key-format")) {
|
||||
key->pubkey_type = NC_PUBKEY_FORMAT_SSH;
|
||||
} else if (!strcmp(format, "subject-public-key-info-format")) {
|
||||
key->pubkey_type = NC_PUBKEY_FORMAT_X509;
|
||||
} else {
|
||||
ERR(NULL, "Public key format (%s) not supported.", format);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ks_public_key(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
struct nc_asymmetric_key *key;
|
||||
|
||||
(void) op;
|
||||
|
||||
assert(!strcmp(LYD_NAME(node), "public-key"));
|
||||
|
||||
if (nc_server_config_get_asymmetric_key(node, &key)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* replace the pubkey */
|
||||
free(key->pubkey_data);
|
||||
key->pubkey_data = strdup(lyd_get_value(node));
|
||||
NC_CHECK_ERRMEM_RET(!key->pubkey_data, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ks_private_key_format(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
struct nc_asymmetric_key *key;
|
||||
const char *format;
|
||||
enum nc_privkey_format privkey_type;
|
||||
|
||||
(void) op;
|
||||
|
||||
assert(!strcmp(LYD_NAME(node), "private-key-format"));
|
||||
|
||||
if (nc_server_config_get_asymmetric_key(node, &key)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
format = ((struct lyd_node_term *)node)->value.ident->name;
|
||||
if (!format) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
privkey_type = nc_server_config_get_private_key_type(format);
|
||||
if (privkey_type == NC_PRIVKEY_FORMAT_UNKNOWN) {
|
||||
return 1;
|
||||
}
|
||||
key->privkey_type = privkey_type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ks_cleartext_private_key(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
struct nc_asymmetric_key *key;
|
||||
|
||||
assert(!strcmp(LYD_NAME(node), "cleartext-private-key"));
|
||||
|
||||
if (nc_server_config_get_asymmetric_key(node, &key)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
|
||||
/* replace the privkey */
|
||||
free(key->privkey_data);
|
||||
key->privkey_data = strdup(lyd_get_value(node));
|
||||
NC_CHECK_ERRMEM_RET(!key->privkey_data, 1);
|
||||
} else if (op == NC_OP_DELETE) {
|
||||
free(key->privkey_data);
|
||||
key->privkey_data = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ks_create_certificate(const struct lyd_node *node, struct nc_asymmetric_key *key)
|
||||
{
|
||||
node = lyd_child(node);
|
||||
assert(!strcmp(LYD_NAME(node), "name"));
|
||||
|
||||
return nc_server_config_realloc(lyd_get_value(node), (void **)&key->certs, sizeof *key->certs, &key->cert_count);
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ks_certificate(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
int ret = 0;
|
||||
struct nc_asymmetric_key *key;
|
||||
struct nc_certificate *cert;
|
||||
|
||||
assert(!strcmp(LYD_NAME(node), "certificate"));
|
||||
|
||||
if (nc_server_config_get_asymmetric_key(node, &key)) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
|
||||
ret = nc_server_config_ks_create_certificate(node, key);
|
||||
} else {
|
||||
if (nc_server_config_get_certificate(node, &cert)) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
nc_server_config_ks_del_asymmetric_key_cert(key, cert);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ks_cert_data(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
struct nc_certificate *cert;
|
||||
|
||||
assert(!strcmp(LYD_NAME(node), "cert-data"));
|
||||
|
||||
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
|
||||
if (nc_server_config_get_certificate(node, &cert)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* replace the cert data */
|
||||
free(cert->data);
|
||||
cert->data = strdup(lyd_get_value(node));
|
||||
NC_CHECK_ERRMEM_RET(!cert->data, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nc_server_config_parse_keystore(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
const char *name = LYD_NAME(node);
|
||||
int ret = 0;
|
||||
|
||||
if (!strcmp(name, "keystore")) {
|
||||
ret = nc_server_config_ks_keystore(node, op);
|
||||
} else if (!strcmp(name, "asymmetric-keys")) {
|
||||
ret = nc_server_config_ks_asymmetric_keys(node, op);
|
||||
} else if (!strcmp(name, "asymmetric-key")) {
|
||||
ret = nc_server_config_ks_asymmetric_key(node, op);
|
||||
} else if (!strcmp(name, "public-key-format")) {
|
||||
ret = nc_server_config_ks_public_key_format(node, op);
|
||||
} else if (!strcmp(name, "public-key")) {
|
||||
ret = nc_server_config_ks_public_key(node, op);
|
||||
} else if (!strcmp(name, "private-key-format")) {
|
||||
ret = nc_server_config_ks_private_key_format(node, op);
|
||||
} else if (!strcmp(name, "cleartext-private-key")) {
|
||||
ret = nc_server_config_ks_cleartext_private_key(node, op);
|
||||
} else if (!strcmp(name, "certificate")) {
|
||||
ret = nc_server_config_ks_certificate(node, op);
|
||||
} else if (!strcmp(name, "cert-data")) {
|
||||
ret = nc_server_config_ks_cert_data(node, op);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
ERR(NULL, "Configuring (%s) failed.", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nc_server_config_fill_keystore(const struct lyd_node *data, enum nc_operation op)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t prev_lo;
|
||||
struct lyd_node *tree;
|
||||
|
||||
/* silently search for nodes, some of them may not be present */
|
||||
prev_lo = ly_log_options(0);
|
||||
|
||||
ret = lyd_find_path(data, "/ietf-keystore:keystore", 0, &tree);
|
||||
if (ret || (tree->flags & LYD_DEFAULT)) {
|
||||
/* not found */
|
||||
ret = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (nc_server_config_parse_tree(tree, op, NC_MODULE_KEYSTORE)) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* reset the logging options back to what they were */
|
||||
ly_log_options(prev_lo);
|
||||
return ret;
|
||||
}
|
169
src/server_config_p.h
Normal file
169
src/server_config_p.h
Normal file
|
@ -0,0 +1,169 @@
|
|||
/**
|
||||
* @file server_config_p.h
|
||||
* @author Roman Janota <janota@cesnet.cz>
|
||||
* @brief libnetconf2 server configuration
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2023 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_SERVER_P_H_
|
||||
#define NC_CONFIG_SERVER_P_H_
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "session_p.h"
|
||||
|
||||
/**
|
||||
* Enumeration of ietf-netconf-server's modules/trees (top-level containers)
|
||||
*/
|
||||
typedef enum {
|
||||
NC_MODULE_NETCONF_SERVER,
|
||||
NC_MODULE_KEYSTORE,
|
||||
NC_MODULE_TRUSTSTORE,
|
||||
NC_MODULE_LIBNETCONF2_NETCONF_SERVER
|
||||
} NC_MODULE;
|
||||
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/**
|
||||
* @brief Get private key type from YANG identity stored in a string.
|
||||
*
|
||||
* @param[in] format Value of the YANG identityref.
|
||||
* @return Private key format on success, NC_PRIVKEY_FORMAT_UNKNOWN otherwise.
|
||||
*/
|
||||
enum nc_privkey_format nc_server_config_get_private_key_type(const char *format);
|
||||
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
/**
|
||||
* @brief Compares the nth-parent name.
|
||||
*
|
||||
* @param[in] node Node of which nth-parent to compare.
|
||||
* @param[in] parent_count Count of parents.
|
||||
* @param[in] parent_name Expected name of the parent.
|
||||
* @return 1 if the name matches, 0 otherwise.
|
||||
*/
|
||||
int equal_parent_name(const struct lyd_node *node, uint16_t parent_count, const char *parent_name);
|
||||
|
||||
/**
|
||||
* @brief Generic realloc function for arrays of structures representing YANG lists whose first member is the key (char *)
|
||||
*
|
||||
* @param[in] key_value Value of the key, which will be assigned to the first member of the given struct.
|
||||
* @param[in] size Size of a member of the array.
|
||||
* @param[in,out] ptr Pointer to the beginning of the given array, which will be reallocated.
|
||||
* @param[in,out] count Count of members in the array, incremented at the end.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
int nc_server_config_realloc(const char *key_value, void **ptr, size_t size, uint16_t *count);
|
||||
|
||||
/**
|
||||
* @brief Recursively parse the given tree and apply it's data to the server's configuration.
|
||||
*
|
||||
* @param[in] node YANG data tree.
|
||||
* @param[in] parent_op Operation of the parent.
|
||||
* @param[in] module Module for which to parse the data - either ietf-netconf-server, ietf-keystore or ietf-truststore
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
int nc_server_config_parse_tree(const struct lyd_node *node, enum nc_operation parent_op, NC_MODULE module);
|
||||
|
||||
/**
|
||||
* @brief Configures the listen subtree in the ietf-netconf-server module.
|
||||
*
|
||||
* @param[in] node Listen YANG data node.
|
||||
* @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
int nc_server_config_listen(const struct lyd_node *node, enum nc_operation op);
|
||||
|
||||
/**
|
||||
* @brief Configures the Call Home subtree in the ietf-netconf-server module.
|
||||
*
|
||||
* @param[in] node call-home YANG data node.
|
||||
* @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
int nc_server_config_ch(const struct lyd_node *node, enum nc_operation op);
|
||||
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/** KEYSTORE **/
|
||||
|
||||
/**
|
||||
* @brief Checks if keystore tree is present in the data and if yes, tries to apply it's data.
|
||||
*
|
||||
* @param[in] data YANG data tree.
|
||||
* @param[in] op Operation saying what to do with the top-level node.
|
||||
* @return 0 either if keystore is not present or if it is and application was successful, 1 on error.
|
||||
*/
|
||||
int nc_server_config_fill_keystore(const struct lyd_node *data, enum nc_operation op);
|
||||
|
||||
/**
|
||||
* @brief Parse the given node, which belongs to the ietf-keystore subtree, and apply it's data to the server's configuration.
|
||||
*
|
||||
* @param[in] node YANG data node.
|
||||
* @param[in] op Operation saying what to do with the node.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
int nc_server_config_parse_keystore(const struct lyd_node *node, enum nc_operation op);
|
||||
|
||||
/**
|
||||
* @brief Configures the keystore subtree in the ietf-keystore module.
|
||||
*
|
||||
* @param[in] node Keystore YANG data node.
|
||||
* @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE.
|
||||
* @return 0.
|
||||
*/
|
||||
int nc_server_config_ks_keystore(const struct lyd_node *node, enum nc_operation op);
|
||||
|
||||
/** TRUSTSTORE **/
|
||||
|
||||
/**
|
||||
* @brief Checks if truststore tree is present in the data and if yes, tries to apply it's data.
|
||||
*
|
||||
* @param[in] data YANG data tree.
|
||||
* @param[in] op Operation saying what to do with the top-level node.
|
||||
* @return 0 either if truststore is not present or if it is and application was successful, 1 on error.
|
||||
*/
|
||||
int nc_server_config_fill_truststore(const struct lyd_node *data, enum nc_operation op);
|
||||
|
||||
/**
|
||||
* @brief Parse the given node, which belongs to the ietf-truststore subtree, and apply it's data to the server's configuration.
|
||||
*
|
||||
* @param[in] node YANG data node.
|
||||
* @param[in] op Operation saying what to do with the node.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
int nc_server_config_parse_truststore(const struct lyd_node *node, enum nc_operation op);
|
||||
|
||||
/**
|
||||
* @brief Configures the truststore subtree in the ietf-truststore module.
|
||||
*
|
||||
* @param[in] node Truststore YANG data node.
|
||||
* @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE.
|
||||
* @return 0.
|
||||
*/
|
||||
int nc_server_config_ts_truststore(const struct lyd_node *node, enum nc_operation op);
|
||||
|
||||
/** LIBNETCONF2-NETCONF-SERVER **/
|
||||
|
||||
/**
|
||||
* @brief Configures the ln2-netconf-server subtree in the libnetconf2-netconf-server module.
|
||||
*
|
||||
* @param[in] node Optional ln2-netconf-server YANG data node.
|
||||
* @param[in] op Operation to be done on the subtree. Only does something if the operation is NC_OP_DELETE.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
int nc_server_config_ln2_netconf_server(const struct lyd_node *node, enum nc_operation op);
|
||||
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
#endif /* NC_CONFIG_SERVER_P_H_ */
|
600
src/server_config_ts.c
Normal file
600
src/server_config_ts.c
Normal file
|
@ -0,0 +1,600 @@
|
|||
/**
|
||||
* @file server_config_ts.c
|
||||
* @author Roman Janota <janota@cesnet.cz>
|
||||
* @brief libnetconf2 truststore configuration functions
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2023 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 _GNU_SOURCE
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "log_p.h"
|
||||
#include "server_config_p.h"
|
||||
#include "session_p.h"
|
||||
|
||||
/**
|
||||
* @brief Get the pointer to a certificate bag structure based on node's location in the YANG data.
|
||||
*
|
||||
* @param[in] node Node from which the certificate bag containing this node is derived.
|
||||
* @param[out] cbag Certificate bag containing the node.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_server_config_get_certificate_bag(const struct lyd_node *node, struct nc_certificate_bag **cbag)
|
||||
{
|
||||
uint16_t i;
|
||||
const char *cbag_name;
|
||||
struct nc_truststore *ts;
|
||||
const char *node_name = LYD_NAME(node);
|
||||
|
||||
assert(node && cbag);
|
||||
|
||||
while (node) {
|
||||
if (!strcmp(LYD_NAME(node), "certificate-bag")) {
|
||||
break;
|
||||
}
|
||||
node = lyd_parent(node);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
ERR(NULL, "Node \"%s\" is not contained in a certificate-bag subtree.", node_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
node = lyd_child(node);
|
||||
assert(!strcmp(LYD_NAME(node), "name"));
|
||||
cbag_name = lyd_get_value(node);
|
||||
|
||||
ts = &server_opts.truststore;
|
||||
for (i = 0; i < ts->cert_bag_count; i++) {
|
||||
if (!strcmp(ts->cert_bags[i].name, cbag_name)) {
|
||||
*cbag = &ts->cert_bags[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ERR(NULL, "Certificate bag \"%s\" was not found.", cbag_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the pointer to a certificate structure based on node's location in the YANG data.
|
||||
*
|
||||
* @param[in] node Node from which the certificate containing this node is derived.
|
||||
* @param[out] cert Certificate containing the node.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_server_config_get_certificate(const struct lyd_node *node, struct nc_certificate **cert)
|
||||
{
|
||||
uint16_t i;
|
||||
const char *cert_name;
|
||||
struct nc_certificate_bag *cbag;
|
||||
const char *node_name = LYD_NAME(node);
|
||||
|
||||
assert(node && cert);
|
||||
|
||||
if (nc_server_config_get_certificate_bag(node, &cbag)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (node) {
|
||||
if (!strcmp(LYD_NAME(node), "certificate")) {
|
||||
break;
|
||||
}
|
||||
node = lyd_parent(node);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
ERR(NULL, "Node \"%s\" is not contained in a certificate subtree.", node_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
node = lyd_child(node);
|
||||
assert(!strcmp(LYD_NAME(node), "name"));
|
||||
cert_name = lyd_get_value(node);
|
||||
|
||||
for (i = 0; i < cbag->cert_count; i++) {
|
||||
if (!strcmp(cbag->certs[i].name, cert_name)) {
|
||||
*cert = &cbag->certs[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ERR(NULL, "Certificate \"%s\" was not found.", cert_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the pointer to a public key bag structure based on node's location in the YANG data.
|
||||
*
|
||||
* @param[in] node Node from which the public key bag containing this node is derived.
|
||||
* @param[out] pbag Public key bag containing the node.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_server_config_get_public_key_bag(const struct lyd_node *node, struct nc_public_key_bag **pbag)
|
||||
{
|
||||
uint16_t i;
|
||||
const char *pbag_name;
|
||||
struct nc_truststore *ts;
|
||||
const char *node_name = LYD_NAME(node);
|
||||
|
||||
assert(node && pbag);
|
||||
|
||||
while (node) {
|
||||
if (!strcmp(LYD_NAME(node), "public-key-bag")) {
|
||||
break;
|
||||
}
|
||||
node = lyd_parent(node);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
ERR(NULL, "Node \"%s\" is not contained in a public-key-bag subtree.", node_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
node = lyd_child(node);
|
||||
assert(!strcmp(LYD_NAME(node), "name"));
|
||||
pbag_name = lyd_get_value(node);
|
||||
|
||||
ts = &server_opts.truststore;
|
||||
for (i = 0; i < ts->pub_bag_count; i++) {
|
||||
if (!strcmp(ts->pub_bags[i].name, pbag_name)) {
|
||||
*pbag = &ts->pub_bags[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ERR(NULL, "Public key bag \"%s\" was not found.", pbag_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the pointer to a public key structure based on node's location in the YANG data.
|
||||
*
|
||||
* @param[in] node Node from which the public key containing this node is derived.
|
||||
* @param[out] pkey Public key containing the node.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
static int
|
||||
nc_server_config_get_public_key(const struct lyd_node *node, struct nc_public_key **pkey)
|
||||
{
|
||||
uint16_t i;
|
||||
const char *pkey_name;
|
||||
struct nc_public_key_bag *pbag;
|
||||
const char *node_name = LYD_NAME(node);
|
||||
|
||||
assert(node && pkey);
|
||||
|
||||
if (nc_server_config_get_public_key_bag(node, &pbag)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (node) {
|
||||
if (!strcmp(LYD_NAME(node), "public-key")) {
|
||||
if (lyd_child(node)) {
|
||||
/* check if it's not the leaf public-key, only case about the list */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
node = lyd_parent(node);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
ERR(NULL, "Node \"%s\" is not contained in a public-key subtree.", node_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
node = lyd_child(node);
|
||||
assert(!strcmp(LYD_NAME(node), "name"));
|
||||
pkey_name = lyd_get_value(node);
|
||||
|
||||
for (i = 0; i < pbag->pubkey_count; i++) {
|
||||
if (!strcmp(pbag->pubkeys[i].name, pkey_name)) {
|
||||
*pkey = &pbag->pubkeys[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ERR(NULL, "Public key \"%s\" was not found.", pkey_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
nc_server_config_ts_del_certificate(struct nc_certificate_bag *cbag, struct nc_certificate *cert)
|
||||
{
|
||||
free(cert->name);
|
||||
free(cert->data);
|
||||
|
||||
cbag->cert_count--;
|
||||
if (!cbag->cert_count) {
|
||||
free(cbag->certs);
|
||||
cbag->certs = NULL;
|
||||
} else if (cert != &cbag->certs[cbag->cert_count]) {
|
||||
memcpy(cert, &cbag->certs[cbag->cert_count], sizeof *cbag->certs);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nc_server_config_ts_del_public_key(struct nc_public_key_bag *pbag, struct nc_public_key *pkey)
|
||||
{
|
||||
free(pkey->name);
|
||||
free(pkey->data);
|
||||
|
||||
pbag->pubkey_count--;
|
||||
if (!pbag->pubkey_count) {
|
||||
free(pbag->pubkeys);
|
||||
pbag->pubkeys = NULL;
|
||||
} else if (pkey != &pbag->pubkeys[pbag->pubkey_count]) {
|
||||
memcpy(pkey, &pbag->pubkeys[pbag->pubkey_count], sizeof *pbag->pubkeys);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nc_server_config_ts_del_certificate_bag(struct nc_certificate_bag *cbag)
|
||||
{
|
||||
uint16_t i, cert_count;
|
||||
struct nc_truststore *ts = &server_opts.truststore;
|
||||
|
||||
free(cbag->name);
|
||||
|
||||
cert_count = cbag->cert_count;
|
||||
for (i = 0; i < cert_count; i++) {
|
||||
nc_server_config_ts_del_certificate(cbag, &cbag->certs[i]);
|
||||
}
|
||||
|
||||
ts->cert_bag_count--;
|
||||
if (!ts->cert_bag_count) {
|
||||
free(ts->cert_bags);
|
||||
ts->cert_bags = NULL;
|
||||
} else if (cbag != &ts->cert_bags[ts->cert_bag_count]) {
|
||||
memcpy(cbag, &ts->cert_bags[ts->cert_bag_count], sizeof *ts->cert_bags);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nc_server_config_ts_del_public_key_bag(struct nc_public_key_bag *pbag)
|
||||
{
|
||||
uint16_t i, pubkey_count;
|
||||
struct nc_truststore *ts = &server_opts.truststore;
|
||||
|
||||
free(pbag->name);
|
||||
|
||||
pubkey_count = pbag->pubkey_count;
|
||||
for (i = 0; i < pubkey_count; i++) {
|
||||
nc_server_config_ts_del_public_key(pbag, &pbag->pubkeys[i]);
|
||||
}
|
||||
|
||||
ts->pub_bag_count--;
|
||||
if (!ts->pub_bag_count) {
|
||||
free(ts->pub_bags);
|
||||
ts->pub_bags = NULL;
|
||||
} else if (pbag != &ts->pub_bags[ts->pub_bag_count]) {
|
||||
memcpy(pbag, &ts->pub_bags[ts->pub_bag_count], sizeof *ts->pub_bags);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ts_certificate_bags(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
uint16_t i, cert_bag_count;
|
||||
struct nc_truststore *ts = &server_opts.truststore;
|
||||
|
||||
(void) node;
|
||||
|
||||
if (op == NC_OP_DELETE) {
|
||||
cert_bag_count = ts->cert_bag_count;
|
||||
for (i = 0; i < cert_bag_count; i++) {
|
||||
nc_server_config_ts_del_certificate_bag(&ts->cert_bags[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ts_public_key_bags(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
uint16_t i, pub_bag_count;
|
||||
struct nc_truststore *ts = &server_opts.truststore;
|
||||
|
||||
(void) node;
|
||||
|
||||
if (op == NC_OP_DELETE) {
|
||||
pub_bag_count = ts->pub_bag_count;
|
||||
for (i = 0; i < pub_bag_count; i++) {
|
||||
nc_server_config_ts_del_public_key_bag(&ts->pub_bags[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nc_server_config_ts_truststore(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
(void) node;
|
||||
|
||||
if (op == NC_OP_DELETE) {
|
||||
nc_server_config_ts_certificate_bags(NULL, NC_OP_DELETE);
|
||||
nc_server_config_ts_public_key_bags(NULL, NC_OP_DELETE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ts_create_certificate_bag(const struct lyd_node *node)
|
||||
{
|
||||
struct nc_truststore *ts = &server_opts.truststore;
|
||||
|
||||
node = lyd_child(node);
|
||||
assert(!strcmp(LYD_NAME(node), "name"));
|
||||
|
||||
return nc_server_config_realloc(lyd_get_value(node), (void **)&ts->cert_bags, sizeof *ts->cert_bags, &ts->cert_bag_count);
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ts_certificate_bag(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
struct nc_certificate_bag *bag;
|
||||
|
||||
assert(!strcmp(LYD_NAME(node), "certificate-bag"));
|
||||
|
||||
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
|
||||
if (nc_server_config_ts_create_certificate_bag(node)) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (nc_server_config_get_certificate_bag(node, &bag)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
nc_server_config_ts_del_certificate_bag(bag);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ts_create_certificate(const struct lyd_node *node, struct nc_certificate_bag *bag)
|
||||
{
|
||||
node = lyd_child(node);
|
||||
assert(!strcmp(LYD_NAME(node), "name"));
|
||||
|
||||
return nc_server_config_realloc(lyd_get_value(node), (void **)&bag->certs, sizeof *bag->certs, &bag->cert_count);
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ts_certificate(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
struct nc_certificate_bag *bag;
|
||||
struct nc_certificate *cert;
|
||||
|
||||
assert(!strcmp(LYD_NAME(node), "certificate"));
|
||||
|
||||
if (nc_server_config_get_certificate_bag(node, &bag)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
|
||||
if (nc_server_config_ts_create_certificate(node, bag)) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (nc_server_config_get_certificate(node, &cert)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
nc_server_config_ts_del_certificate(bag, cert);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ts_cert_data(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
struct nc_certificate *cert;
|
||||
|
||||
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
|
||||
if (nc_server_config_get_certificate(node, &cert)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(cert->data);
|
||||
cert->data = strdup(lyd_get_value(node));
|
||||
NC_CHECK_ERRMEM_RET(!cert->data, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ts_create_public_key_bag(const struct lyd_node *node)
|
||||
{
|
||||
struct nc_truststore *ts = &server_opts.truststore;
|
||||
|
||||
node = lyd_child(node);
|
||||
assert(!strcmp(LYD_NAME(node), "name"));
|
||||
|
||||
return nc_server_config_realloc(lyd_get_value(node), (void **)&ts->pub_bags, sizeof *ts->pub_bags, &ts->pub_bag_count);
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ts_public_key_bag(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
struct nc_public_key_bag *pbag;
|
||||
|
||||
assert(!strcmp(LYD_NAME(node), "public-key-bag"));
|
||||
|
||||
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
|
||||
if (nc_server_config_ts_create_public_key_bag(node)) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (nc_server_config_get_public_key_bag(node, &pbag)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
nc_server_config_ts_del_public_key_bag(pbag);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ts_create_public_key(const struct lyd_node *node, struct nc_public_key_bag *bag)
|
||||
{
|
||||
node = lyd_child(node);
|
||||
assert(!strcmp(LYD_NAME(node), "name"));
|
||||
|
||||
return nc_server_config_realloc(lyd_get_value(node), (void **)&bag->pubkeys, sizeof *bag->pubkeys, &bag->pubkey_count);
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ts_public_key(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
int ret = 0;
|
||||
struct nc_public_key_bag *bag;
|
||||
struct nc_public_key *pkey;
|
||||
|
||||
if (nc_server_config_get_public_key_bag(node, &bag)) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (equal_parent_name(node, 1, "public-key-bag")) {
|
||||
/* public-key list */
|
||||
if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
|
||||
ret = nc_server_config_ts_create_public_key(node, bag);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
if (nc_server_config_get_public_key(node, &pkey)) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
nc_server_config_ts_del_public_key(bag, pkey);
|
||||
}
|
||||
} else {
|
||||
/* public-key leaf */
|
||||
if (nc_server_config_get_public_key(node, &pkey)) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* replace the public key */
|
||||
free(pkey->data);
|
||||
pkey->data = strdup(lyd_get_value(node));
|
||||
NC_CHECK_ERRMEM_GOTO(!pkey->data, ret = 1, cleanup);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nc_server_config_ts_public_key_format(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
const char *format;
|
||||
struct nc_public_key *pkey;
|
||||
|
||||
(void) op;
|
||||
|
||||
if (nc_server_config_get_public_key(node, &pkey)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
format = ((struct lyd_node_term *)node)->value.ident->name;
|
||||
if (!strcmp(format, "ssh-public-key-format")) {
|
||||
pkey->type = NC_PUBKEY_FORMAT_SSH;
|
||||
} else if (!strcmp(format, "subject-public-key-info-format")) {
|
||||
pkey->type = NC_PUBKEY_FORMAT_X509;
|
||||
} else {
|
||||
ERR(NULL, "Public key format (%s) not supported.", format);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nc_server_config_parse_truststore(const struct lyd_node *node, enum nc_operation op)
|
||||
{
|
||||
const char *name = LYD_NAME(node);
|
||||
int ret = 0;
|
||||
|
||||
if (!strcmp(name, "truststore")) {
|
||||
ret = nc_server_config_ts_truststore(node, op);
|
||||
} else if (!strcmp(name, "certificate-bags")) {
|
||||
ret = nc_server_config_ts_certificate_bags(node, op);
|
||||
} else if (!strcmp(name, "certificate-bag")) {
|
||||
ret = nc_server_config_ts_certificate_bag(node, op);
|
||||
} else if (!strcmp(name, "certificate")) {
|
||||
ret = nc_server_config_ts_certificate(node, op);
|
||||
} else if (!strcmp(name, "cert-data")) {
|
||||
ret = nc_server_config_ts_cert_data(node, op);
|
||||
} else if (!strcmp(name, "public-key-bags")) {
|
||||
ret = nc_server_config_ts_public_key_bags(node, op);
|
||||
} else if (!strcmp(name, "public-key-bag")) {
|
||||
ret = nc_server_config_ts_public_key_bag(node, op);
|
||||
} else if (!strcmp(name, "public-key")) {
|
||||
ret = nc_server_config_ts_public_key(node, op);
|
||||
} else if (!strcmp(name, "public-key-format")) {
|
||||
ret = nc_server_config_ts_public_key_format(node, op);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
ERR(NULL, "Configuring (%s) failed.", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nc_server_config_fill_truststore(const struct lyd_node *data, enum nc_operation op)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t prev_lo;
|
||||
struct lyd_node *tree;
|
||||
|
||||
/* silently search for nodes, some of them may not be present */
|
||||
prev_lo = ly_log_options(0);
|
||||
|
||||
ret = lyd_find_path(data, "/ietf-truststore:truststore", 0, &tree);
|
||||
if (ret || (tree->flags & LYD_DEFAULT)) {
|
||||
/* not found */
|
||||
ret = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (nc_server_config_parse_tree(tree, op, NC_MODULE_TRUSTSTORE)) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* reset the logging options back to what they were */
|
||||
ly_log_options(prev_lo);
|
||||
return ret;
|
||||
}
|
1366
src/server_config_util.c
Normal file
1366
src/server_config_util.c
Normal file
File diff suppressed because it is too large
Load diff
169
src/server_config_util.h
Normal file
169
src/server_config_util.h
Normal file
|
@ -0,0 +1,169 @@
|
|||
/**
|
||||
* @file server_config_util.h
|
||||
* @author Roman Janota <janota@cesnet.cz>
|
||||
* @brief libnetconf2 server configuration utlities header
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2023 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_CONFIG_UTIL_H_
|
||||
#define NC_SERVER_CONFIG_UTIL_H_
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "session_p.h"
|
||||
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/* private key's pkcs8 header */
|
||||
#define NC_PKCS8_PRIVKEY_HEADER "-----BEGIN PRIVATE KEY-----\n"
|
||||
|
||||
/* private key's pkcs8 footer */
|
||||
#define NC_PKCS8_PRIVKEY_FOOTER "\n-----END PRIVATE KEY-----\n"
|
||||
|
||||
/* private key's openssh header */
|
||||
#define NC_OPENSSH_PRIVKEY_HEADER "-----BEGIN OPENSSH PRIVATE KEY-----\n"
|
||||
|
||||
/* private key's openssh footer */
|
||||
#define NC_OPENSSH_PRIVKEY_FOOTER "\n-----END OPENSSH PRIVATE KEY-----\n"
|
||||
|
||||
/* private key's pkcs1 rsa header */
|
||||
#define NC_PKCS1_RSA_PRIVKEY_HEADER "-----BEGIN RSA PRIVATE KEY-----\n"
|
||||
|
||||
/* private key's pkcs1 rsa footer */
|
||||
#define NC_PKCS1_RSA_PRIVKEY_FOOTER "\n-----END RSA PRIVATE KEY-----\n"
|
||||
|
||||
/* private key's sec1 ec header */
|
||||
#define NC_SEC1_EC_PRIVKEY_HEADER "-----BEGIN EC PRIVATE KEY-----\n"
|
||||
|
||||
/* private key's sec1 ec footer */
|
||||
#define NC_SEC1_EC_PRIVKEY_FOOTER "\n-----END EC PRIVATE KEY-----\n"
|
||||
|
||||
/* private key's header when getting an EC/RSA privkey from file using libssh */
|
||||
#define NC_LIBSSH_PRIVKEY_HEADER "-----BEGIN PRIVATE KEY-----\n"
|
||||
|
||||
/* private key's footer when getting an EC/RSA privkey from file using libssh */
|
||||
#define NC_LIBSSH_PRIVKEY_FOOTER "\n-----END PRIVATE KEY-----\n"
|
||||
|
||||
/* public key's ssh2 header */
|
||||
#define NC_SSH2_PUBKEY_HEADER "---- BEGIN SSH2 PUBLIC KEY ----\n"
|
||||
|
||||
/* public key's SubjectPublicKeyInfo format header */
|
||||
#define NC_SUBJECT_PUBKEY_INFO_HEADER "-----BEGIN PUBLIC KEY-----\n"
|
||||
|
||||
/* public key's SubjectPublicKeyInfo format footer */
|
||||
#define NC_SUBJECT_PUBKEY_INFO_FOOTER "\n-----END PUBLIC KEY-----\n"
|
||||
|
||||
/* certificate's PEM format header */
|
||||
#define NC_PEM_CERTIFICATE_HEADER "-----BEGIN CERTIFICATE-----\n"
|
||||
|
||||
/* certificate's PEM format footer */
|
||||
#define NC_PEM_CERTIFICATE_FOOTER "\n-----END CERTIFICATE-----\n"
|
||||
|
||||
typedef enum {
|
||||
NC_ALG_HOSTKEY,
|
||||
NC_ALG_KEY_EXCHANGE,
|
||||
NC_ALG_ENCRYPTION,
|
||||
NC_ALG_MAC
|
||||
} NC_ALG_TYPE;
|
||||
|
||||
/**
|
||||
* @brief Gets asymmetric key pair from private key (and optionally public key) file(s).
|
||||
*
|
||||
* @param[in] privkey_path Path to private key.
|
||||
* @param[in] pubkey_path Optional path to public key. If not set, PK will be generated from private key.
|
||||
* @param[in] wanted_pubkey_type Wanted public key format to be generated (SPKI/SSH)
|
||||
* @param[out] privkey Base64 encoded private key.
|
||||
* @param[out] privkey_type Type of the private key. (RSA, EC, etc)
|
||||
* @param[out] pubkey Base64 encoded public key.
|
||||
* @return 0 on success, non-zero otherwise.
|
||||
*/
|
||||
int nc_server_config_util_get_asym_key_pair(const char *privkey_path, const char *pubkey_path, enum nc_pubkey_format wanted_pubkey_type,
|
||||
char **privkey, enum nc_privkey_format *privkey_type, char **pubkey);
|
||||
|
||||
/**
|
||||
* @brief Gets public key from a file and converts it to the SSH format if need be.
|
||||
*
|
||||
* @param[in] pubkey_path Path to the public key.
|
||||
* @param[out] pubkey Base64 encoded public key.
|
||||
*
|
||||
* @return 0 on success, non-zero otherwise.
|
||||
*/
|
||||
int nc_server_config_util_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey);
|
||||
|
||||
/**
|
||||
* @brief Gets a certificate from a file.
|
||||
*
|
||||
* @param[in] cert_path Path to the certificate.
|
||||
* @param[out] cert Base64 PEM encoded certificate data.
|
||||
*
|
||||
* @return 0 on success, non-zero otherwise.
|
||||
*/
|
||||
int nc_server_config_util_read_certificate(const char *cert_path, char **cert);
|
||||
|
||||
/**
|
||||
* @brief Converts private key format to its associated identityref value.
|
||||
*
|
||||
* @param[in] format Private key format.
|
||||
*
|
||||
* @return Identityref on success, NULL on failure.
|
||||
*/
|
||||
const char *nc_server_config_util_privkey_format_to_identityref(enum nc_privkey_format format);
|
||||
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
/**
|
||||
* @brief Creates YANG data nodes in a path and gives the final node a value.
|
||||
*
|
||||
* @param[in] ctx libyang context.
|
||||
* @param[in, out] tree The YANG data tree where the insertion will happen. On success
|
||||
* this is set to the top level container.
|
||||
* @param[in] value Value assigned to the final node in the path.
|
||||
* @param[in] path_fmt Format of the path.
|
||||
* @param[in] ... Parameters for the path format, essentially representing the lists' keys.
|
||||
* @return 0 on success, 1 otherwise.
|
||||
*/
|
||||
int nc_server_config_create(const struct ly_ctx *ctx, struct lyd_node **tree, const char *value, const char *path_fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Creates a YANG data node by appending it to a specified parent node.
|
||||
*
|
||||
* @param[in] ctx libyang context.
|
||||
* @param[in] parent_path Path to the parent node.
|
||||
* @param[in] child_name Name of the parent's child node to be created.
|
||||
* @param[in] value Value given to the child node.
|
||||
* @param[out] tree YANG data tree where the insertion will happen. On success
|
||||
* this is set to the top level container.
|
||||
* @return 0 on success, 1 otherwise.
|
||||
*/
|
||||
int nc_server_config_append(const struct ly_ctx *ctx, const char *parent_path, const char *child_name,
|
||||
const char *value, struct lyd_node **tree);
|
||||
|
||||
/**
|
||||
* @brief Deletes a subtree from the YANG data.
|
||||
*
|
||||
* @param tree YANG data from which the subtree will be deleted.
|
||||
* @param[in] path_fmt Format of the path. The last node will be the top level node of the deleted tree.
|
||||
* @param[in] ... Parameters for the path format, essentially representing the lists' keys.
|
||||
* @return 0 on success, non-zero otherwise.
|
||||
*/
|
||||
int nc_server_config_delete(struct lyd_node **tree, const char *path_fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Deletes a subtree from the YANG data, but doesn't return an error if the node doesn't exist.
|
||||
*
|
||||
* @param tree YANG data from which the subtree will be deleted.
|
||||
* @param[in] path_fmt Format of the path. The last node will be the top level node of the deleted tree.
|
||||
* @param[in] ... Parameters for the path format, essentially representing the lists' keys.
|
||||
* @return 0 on success, non-zero otherwise.
|
||||
*/
|
||||
int nc_server_config_check_delete(struct lyd_node **tree, const char *path_fmt, ...);
|
||||
|
||||
#endif /* NC_CONFIG_NEW_H_ */
|
798
src/server_config_util_ssh.c
Normal file
798
src/server_config_util_ssh.c
Normal file
|
@ -0,0 +1,798 @@
|
|||
/**
|
||||
* @file server_config_util_ssh.c
|
||||
* @author Roman Janota <janota@cesnet.cz>
|
||||
* @brief libnetconf2 server SSH configuration utilities
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2023 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 _GNU_SOURCE
|
||||
|
||||
#include "server_config_util.h"
|
||||
|
||||
#include <crypt.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "config.h"
|
||||
#include "log_p.h"
|
||||
#include "server_config.h"
|
||||
#include "session_p.h"
|
||||
|
||||
static int
|
||||
_nc_server_config_add_ssh_hostkey(const struct ly_ctx *ctx, const char *tree_path,
|
||||
const char *privkey_path, const char *pubkey_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *pubkey = NULL, *privkey = NULL;
|
||||
enum nc_privkey_format privkey_type;
|
||||
const char *privkey_format, *pubkey_format = "ietf-crypto-types:ssh-public-key-format";
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, tree_path, privkey_path, config, 1);
|
||||
|
||||
/* get the keys as a string from the given files */
|
||||
ret = nc_server_config_util_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_SSH, &privkey,
|
||||
&privkey_type, &pubkey);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* get privkey identityref value */
|
||||
privkey_format = nc_server_config_util_privkey_format_to_identityref(privkey_type);
|
||||
if (!privkey_format) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "inline-definition/public-key-format", pubkey_format, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "inline-definition/public-key", pubkey, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "inline-definition/private-key-format", privkey_format, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "inline-definition/cleartext-private-key", privkey, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete keystore choice nodes if present */
|
||||
ret = nc_server_config_check_delete(config, "%s/central-keystore-reference", tree_path);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(privkey);
|
||||
free(pubkey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name,
|
||||
const char *privkey_path, const char *pubkey_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, privkey_path, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/"
|
||||
"server-identity/host-key[name='%s']/public-key", endpt_name, hostkey_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_ssh_hostkey(ctx, path, privkey_path, pubkey_path, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_ssh_hostkey(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name,
|
||||
const char *hostkey_name, const char *privkey_path, const char *pubkey_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, privkey_path, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/"
|
||||
"host-key[name='%s']/public-key", client_name, endpt_name, hostkey_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_ssh_hostkey(ctx, path, privkey_path, pubkey_path, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ssh_hostkey(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name,
|
||||
struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, config, 1);
|
||||
|
||||
if (hostkey_name) {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/"
|
||||
"ssh/ssh-server-parameters/server-identity/host-key[name='%s']", endpt_name, hostkey_name);
|
||||
} else {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/"
|
||||
"ssh/ssh-server-parameters/server-identity/host-key", endpt_name);
|
||||
}
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_ssh_hostkey(const char *client_name, const char *endpt_name,
|
||||
const char *hostkey_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1);
|
||||
|
||||
if (hostkey_name) {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/"
|
||||
"host-key[name='%s']", client_name, endpt_name, hostkey_name);
|
||||
} else {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/"
|
||||
"host-key", client_name, endpt_name);
|
||||
}
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ssh_keystore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *hostkey_name,
|
||||
const char *keystore_reference, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, hostkey_name, keystore_reference, config, 1);
|
||||
|
||||
ret = nc_server_config_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/listen/"
|
||||
"endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/"
|
||||
"central-keystore-reference", endpt_name, hostkey_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete inline definition nodes if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/"
|
||||
"endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/"
|
||||
"inline-definition", endpt_name, hostkey_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_ssh_keystore_ref(const struct ly_ctx *ctx, const char *client_name,
|
||||
const char *endpt_name, const char *hostkey_name, const char *keystore_reference, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, hostkey_name, keystore_reference, config, 1);
|
||||
|
||||
ret = nc_server_config_create(ctx, config, keystore_reference, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/"
|
||||
"host-key[name='%s']/public-key/central-keystore-reference", client_name, endpt_name, hostkey_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete inline definition nodes if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/"
|
||||
"host-key[name='%s']/public-key/inline-definition", client_name, endpt_name, hostkey_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ssh_keystore_ref(const char *endpt_name, const char *hostkey_name,
|
||||
struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/"
|
||||
"endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/host-key[name='%s']/public-key/"
|
||||
"central-keystore-reference", endpt_name, hostkey_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_ssh_keystore_ref(const char *client_name, const char *endpt_name,
|
||||
const char *hostkey_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, hostkey_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/server-identity/"
|
||||
"host-key[name='%s']/public-key/central-keystore-reference", client_name, endpt_name, hostkey_name);
|
||||
}
|
||||
|
||||
static int
|
||||
_nc_server_config_add_ssh_user_pubkey(const struct ly_ctx *ctx, const char *tree_path, const char *pubkey_path,
|
||||
struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *pubkey = NULL;
|
||||
const char *pubkey_format = "ietf-crypto-types:ssh-public-key-format";
|
||||
|
||||
/* get pubkey data */
|
||||
ret = nc_server_config_util_get_ssh_pubkey_file(pubkey_path, &pubkey);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "public-key-format", pubkey_format, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "public-key", pubkey, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(pubkey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ssh_user_pubkey(const struct ly_ctx *ctx, const char *endpt_name,
|
||||
const char *user_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, pubkey_name, pubkey_path, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/"
|
||||
"public-key[name='%s']", endpt_name, user_name, pubkey_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_ssh_user_pubkey(ctx, path, pubkey_path, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete truststore reference if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/central-truststore-reference",
|
||||
endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete use system auth if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/"
|
||||
"libnetconf2-netconf-server:use-system-keys", endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_ssh_user_pubkey(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name,
|
||||
const char *user_name, const char *pubkey_name, const char *pubkey_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, pubkey_name, pubkey_path, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/"
|
||||
"endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/"
|
||||
"users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name,
|
||||
endpt_name, user_name, pubkey_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_ssh_user_pubkey(ctx, path, pubkey_path, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete truststore reference if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/"
|
||||
"public-keys/central-truststore-reference", client_name, endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete use system auth if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/"
|
||||
"libnetconf2-netconf-server:use-system-keys", client_name, endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ssh_user_pubkey(const char *endpt_name, const char *user_name,
|
||||
const char *pubkey_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1);
|
||||
|
||||
if (pubkey_name) {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/"
|
||||
"public-key[name='%s']", endpt_name, user_name, pubkey_name);
|
||||
} else {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition/"
|
||||
"public-key", endpt_name, user_name);
|
||||
}
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_ssh_user_pubkey(const char *client_name, const char *endpt_name,
|
||||
const char *user_name, const char *pubkey_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1);
|
||||
|
||||
if (pubkey_name) {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/"
|
||||
"users/user[name='%s']/public-keys/inline-definition/public-key[name='%s']", client_name,
|
||||
endpt_name, user_name, pubkey_name);
|
||||
} else {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/"
|
||||
"users/user[name='%s']/public-keys/inline-definition/public-key", client_name,
|
||||
endpt_name, user_name);
|
||||
}
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ssh_user_authkey(const struct ly_ctx *ctx, const char *endpt_name,
|
||||
const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/"
|
||||
"client-authentication/users/user[name='%s']/public-keys", endpt_name, user_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = nc_server_config_append(ctx, path, "libnetconf2-netconf-server:use-system-keys", NULL, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete inline definition nodes if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition",
|
||||
endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete truststore reference if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/central-truststore-reference",
|
||||
endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_ssh_user_authkey(const struct ly_ctx *ctx, const char *client_name,
|
||||
const char *endpt_name, const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/"
|
||||
"endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users"
|
||||
"/user[name='%s']/public-keys", client_name, endpt_name, user_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = nc_server_config_append(ctx, path, "libnetconf2-netconf-server:use-system-keys", NULL, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete inline definition nodes if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/"
|
||||
"public-keys/inline-definition", client_name, endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete truststore reference if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/"
|
||||
"public-keys/central-truststore-reference", client_name, endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ssh_user_authkey(const char *endpt_name, const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/"
|
||||
"public-keys/libnetconf2-netconf-server:use-system-keys", endpt_name, user_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_ch_del_ssh_user_authkey(const char *client_name, const char *endpt_name,
|
||||
const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/"
|
||||
"endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/"
|
||||
"public-keys/libnetconf2-netconf-server:use-system-keys", client_name, endpt_name, user_name);
|
||||
}
|
||||
|
||||
static int
|
||||
_nc_server_config_add_ssh_user_password(const struct ly_ctx *ctx, const char *tree_path,
|
||||
const char *password, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *hashed_pw = NULL;
|
||||
const char *salt = "$6$idsizuippipk$";
|
||||
struct crypt_data cdata = {0};
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, tree_path, password, config, 1);
|
||||
|
||||
hashed_pw = crypt_r(password, salt, &cdata);
|
||||
if (!hashed_pw) {
|
||||
ERR(NULL, "Hashing password failed (%s).", strerror(errno));
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "password", hashed_pw, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ssh_user_password(const struct ly_ctx *ctx, const char *endpt_name,
|
||||
const char *user_name, const char *password, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, password, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/"
|
||||
"client-authentication/users/user[name='%s']", endpt_name, user_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_ssh_user_password(ctx, path, password, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_ssh_user_password(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name,
|
||||
const char *user_name, const char *password, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, password, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/"
|
||||
"endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/"
|
||||
"users/user[name='%s']", client_name, endpt_name, user_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_ssh_user_password(ctx, path, password, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ssh_user_password(const char *endpt_name, const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/password", endpt_name, user_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_ssh_user_password(const char *client_name, const char *endpt_name,
|
||||
const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/"
|
||||
"users/user[name='%s']/password", client_name, endpt_name, user_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ssh_user_interactive(const struct ly_ctx *ctx, const char *endpt_name,
|
||||
const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/"
|
||||
"client-authentication/users/user[name='%s']/libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = nc_server_config_append(ctx, path, "use-system-auth", NULL, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_ssh_user_interactive(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name,
|
||||
const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/"
|
||||
"endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/"
|
||||
"libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = nc_server_config_append(ctx, path, "use-system-auth", NULL, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ssh_user_interactive(const char *endpt_name, const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/"
|
||||
"libnetconf2-netconf-server:keyboard-interactive", endpt_name, user_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_ssh_user_interactive(const char *client_name, const char *endpt_name,
|
||||
const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/"
|
||||
"endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/"
|
||||
"libnetconf2-netconf-server:keyboard-interactive", client_name, endpt_name, user_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ssh_user(const char *endpt_name,
|
||||
const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
|
||||
|
||||
if (user_name) {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']", endpt_name, user_name);
|
||||
} else {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user", endpt_name);
|
||||
}
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_ssh_user(const char *client_name, const char *endpt_name,
|
||||
const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1);
|
||||
|
||||
if (user_name) {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/"
|
||||
"endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']", client_name,
|
||||
endpt_name, user_name);
|
||||
} else {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/"
|
||||
"endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user", client_name, endpt_name);
|
||||
}
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ssh_endpoint_client_ref(const struct ly_ctx *ctx, const char *endpt_name,
|
||||
const char *referenced_endpt, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1);
|
||||
|
||||
return nc_server_config_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoints/"
|
||||
"endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/libnetconf2-netconf-server:endpoint-reference",
|
||||
endpt_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ssh_endpoint_client_ref(const char *endpt_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/"
|
||||
"ssh/ssh-server-parameters/client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ssh_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *user_name,
|
||||
const char *truststore_reference, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, user_name, truststore_reference, config, 1);
|
||||
|
||||
ret = nc_server_config_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/listen/"
|
||||
"endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/"
|
||||
"central-truststore-reference", endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete inline definition nodes if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/inline-definition",
|
||||
endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete use system auth if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/"
|
||||
"libnetconf2-netconf-server:use-system-keys", endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_ssh_truststore_ref(const struct ly_ctx *ctx, const char *client_name,
|
||||
const char *endpt_name, const char *user_name, const char *truststore_reference, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, user_name, truststore_reference, config, 1);
|
||||
|
||||
ret = nc_server_config_create(ctx, config, truststore_reference, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/"
|
||||
"users/user[name='%s']/public-keys/central-truststore-reference", client_name, endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete inline definition nodes if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/"
|
||||
"public-keys/inline-definition", client_name, endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete use system auth if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/"
|
||||
"ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/"
|
||||
"libnetconf2-netconf-server:use-system-keys", client_name, endpt_name, user_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ssh_truststore_ref(const char *endpt_name, const char *user_name,
|
||||
struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, user_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/"
|
||||
"endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/users/user[name='%s']/public-keys/"
|
||||
"central-truststore-reference", endpt_name, user_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_ssh_truststore_ref(const char *client_name, const char *endpt_name,
|
||||
const char *user_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, user_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/"
|
||||
"users/user[name='%s']/public-keys/central-truststore-reference", client_name, endpt_name, user_name);
|
||||
}
|
790
src/server_config_util_tls.c
Normal file
790
src/server_config_util_tls.c
Normal file
|
@ -0,0 +1,790 @@
|
|||
/**
|
||||
* @file server_config_util_tls.c
|
||||
* @author Roman Janota <janota@cesnet.cz>
|
||||
* @brief libnetconf2 server TLS configuration utilities
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2023 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 _GNU_SOURCE
|
||||
|
||||
#include "server_config_util.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "config.h"
|
||||
#include "log_p.h"
|
||||
#include "server_config.h"
|
||||
#include "session.h"
|
||||
#include "session_p.h"
|
||||
|
||||
static int
|
||||
_nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *tree_path, const char *privkey_path,
|
||||
const char *pubkey_path, const char *cert_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *privkey = NULL, *pubkey = NULL, *cert = NULL;
|
||||
enum nc_privkey_format privkey_type;
|
||||
const char *privkey_format, *pubkey_format = "ietf-crypto-types:subject-public-key-info-format";
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, tree_path, privkey_path, cert_path, config, 1);
|
||||
|
||||
/* get the keys as a string from the given files */
|
||||
ret = nc_server_config_util_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey, &privkey_type, &pubkey);
|
||||
if (ret) {
|
||||
ERR(NULL, "Getting keys from file(s) failed.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* get cert data from file */
|
||||
ret = nc_server_config_util_read_certificate(cert_path, &cert);
|
||||
if (ret) {
|
||||
ERR(NULL, "Getting certificate from file \"%s\" failed.", cert_path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* get privkey identityref value */
|
||||
privkey_format = nc_server_config_util_privkey_format_to_identityref(privkey_type);
|
||||
if (!privkey_format) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "inline-definition/public-key-format", pubkey_format, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "inline-definition/public-key", pubkey, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "inline-definition/private-key-format", privkey_format, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "inline-definition/cleartext-private-key", privkey, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "inline-definition/cert-data", cert, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete keystore if present */
|
||||
ret = nc_server_config_check_delete(config, "%s/central-keystore-reference", tree_path);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(privkey);
|
||||
free(pubkey);
|
||||
free(cert);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_tls_server_cert(const struct ly_ctx *ctx, const char *endpt_name, const char *privkey_path,
|
||||
const char *pubkey_path, const char *cert_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, privkey_path, cert_path, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/"
|
||||
"tls/tls-server-parameters/server-identity/certificate", endpt_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_tls_server_cert(ctx, path, privkey_path, pubkey_path,
|
||||
cert_path, config);
|
||||
if (ret) {
|
||||
ERR(NULL, "Creating new TLS server certificate YANG data failed.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_tls_server_cert(const char *endpt_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/"
|
||||
"tls/tls-server-parameters/server-identity/certificate/inline-definition", endpt_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_tls_server_cert(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name,
|
||||
const char *privkey_path, const char *pubkey_path, const char *cert_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, privkey_path, cert_path, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/"
|
||||
"certificate", client_name, endpt_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_tls_server_cert(ctx, path, privkey_path, pubkey_path,
|
||||
cert_path, config);
|
||||
if (ret) {
|
||||
ERR(NULL, "Creating new CH TLS server certificate YANG data failed.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_tls_server_cert(const char *client_name, const char *endpt_name,
|
||||
struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/"
|
||||
"certificate/inline-definition", client_name, endpt_name);
|
||||
}
|
||||
|
||||
static int
|
||||
_nc_server_config_add_tls_keystore_ref(const struct ly_ctx *ctx, const char *tree_path, const char *asym_key_ref,
|
||||
const char *cert_ref, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* create asymmetric key pair reference */
|
||||
ret = nc_server_config_append(ctx, tree_path, "central-keystore-reference/asymmetric-key", asym_key_ref, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* create cert reference, this cert has to belong to the asym key */
|
||||
ret = nc_server_config_append(ctx, tree_path, "central-keystore-reference/certificate", cert_ref, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete inline definition if present */
|
||||
ret = nc_server_config_check_delete(config, "%s/inline-definition", tree_path);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_tls_keystore_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *asym_key_ref,
|
||||
const char *cert_ref, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, asym_key_ref, cert_ref, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/"
|
||||
"tls/tls-server-parameters/server-identity/certificate", endpt_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_tls_keystore_ref(ctx, path, asym_key_ref, cert_ref, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_tls_keystore_ref(const char *endpt_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/"
|
||||
"tls/tls-server-parameters/server-identity/certificate/central-keystore-reference", endpt_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_tls_keystore_ref(const struct ly_ctx *ctx, const char *client_name,
|
||||
const char *endpt_name, const char *asym_key_ref, const char *cert_ref, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, asym_key_ref, cert_ref, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/endpoints/"
|
||||
"endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate", client_name, endpt_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_tls_keystore_ref(ctx, path, asym_key_ref, cert_ref, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_tls_keystore_ref(const char *client_name, const char *endpt_name,
|
||||
struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/tls/tls-server-parameters/server-identity/certificate/"
|
||||
"central-keystore-reference", client_name, endpt_name);
|
||||
}
|
||||
|
||||
static int
|
||||
_nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *tree_path,
|
||||
const char *cert_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *cert = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, tree_path, cert_path, config, 1);
|
||||
|
||||
ret = nc_server_config_util_read_certificate(cert_path, &cert);
|
||||
if (ret) {
|
||||
ERR(NULL, "Getting certificate from file \"%s\" failed.", cert_path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "cert-data", cert, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(cert);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_tls_client_cert(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name,
|
||||
const char *cert_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/tls-server-parameters/"
|
||||
"client-authentication/ee-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config);
|
||||
if (ret) {
|
||||
ERR(NULL, "Creating new TLS client certificate YANG data failed.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete truststore if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/"
|
||||
"tls/tls-server-parameters/client-authentication/ee-certs/central-truststore-reference", endpt_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_tls_client_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
|
||||
|
||||
if (cert_name) {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/"
|
||||
"tls-server-parameters/client-authentication/ee-certs/inline-definition/"
|
||||
"certificate[name='%s']", endpt_name, cert_name);
|
||||
} else {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/"
|
||||
"tls-server-parameters/client-authentication/ee-certs/inline-definition/"
|
||||
"certificate", endpt_name);
|
||||
}
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_tls_client_cert(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name,
|
||||
const char *cert_name, const char *cert_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/"
|
||||
"inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name) == -1;
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config);
|
||||
if (ret) {
|
||||
ERR(NULL, "Creating new CH TLS client certificate YANG data failed.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete truststore if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/tls/tls-server-parameters/"
|
||||
"client-authentication/ee-certs/central-truststore-reference", client_name, endpt_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_tls_client_cert(const char *client_name, const char *endpt_name,
|
||||
const char *cert_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1);
|
||||
|
||||
if (cert_name) {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/"
|
||||
"inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name);
|
||||
} else {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ee-certs/"
|
||||
"inline-definition/certificate", client_name, endpt_name);
|
||||
}
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_tls_client_cert_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name,
|
||||
const char *cert_bag_ref, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_bag_ref, config, 1);
|
||||
|
||||
ret = nc_server_config_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/"
|
||||
"tls-server-parameters/client-authentication/ee-certs/central-truststore-reference", endpt_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete inline definition if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/"
|
||||
"tls-server-parameters/client-authentication/ee-certs/inline-definition", endpt_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_tls_client_cert_truststore_ref(const char *endpt_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/"
|
||||
"tls-server-parameters/client-authentication/ee-certs/central-truststore-reference", endpt_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_tls_client_cert_truststore_ref(const struct ly_ctx *ctx, const char *client_name,
|
||||
const char *endpt_name, const char *cert_bag_ref, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_bag_ref, config, 1);
|
||||
|
||||
ret = nc_server_config_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/"
|
||||
"client-authentication/ee-certs/central-truststore-reference", client_name, endpt_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete inline definition if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/"
|
||||
"tls-server-parameters/client-authentication/ee-certs/inline-definition", client_name, endpt_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_tls_client_cert_truststore_ref(const char *client_name, const char *endpt_name,
|
||||
struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/"
|
||||
"client-authentication/ee-certs/central-truststore-reference", client_name, endpt_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_tls_ca_cert(const struct ly_ctx *ctx, const char *endpt_name, const char *cert_name,
|
||||
const char *cert_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_name, cert_path, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/tls-server-parameters/"
|
||||
"client-authentication/ca-certs/inline-definition/certificate[name='%s']", endpt_name, cert_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config);
|
||||
if (ret) {
|
||||
ERR(NULL, "Creating new TLS client certificate authority YANG data failed.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete truststore if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/"
|
||||
"tls/tls-server-parameters/client-authentication/ca-certs/central-truststore-reference", endpt_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_tls_ca_cert(const char *endpt_name, const char *cert_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
|
||||
|
||||
if (cert_name) {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/"
|
||||
"tls-server-parameters/client-authentication/ca-certs/inline-definition/"
|
||||
"certificate[name='%s']", endpt_name, cert_name);
|
||||
} else {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/"
|
||||
"tls-server-parameters/client-authentication/ca-certs/inline-definition/"
|
||||
"certificate", endpt_name);
|
||||
}
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_tls_ca_cert(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name,
|
||||
const char *cert_name, const char *cert_path, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_name, cert_path, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/"
|
||||
"inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_tls_client_cert(ctx, path, cert_path, config);
|
||||
if (ret) {
|
||||
ERR(NULL, "Creating new CH TLS client certificate authority YANG data failed.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete truststore if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/tls/tls-server-parameters/"
|
||||
"client-authentication/ca-certs/central-truststore-reference", client_name, endpt_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_tls_ca_cert(const char *client_name, const char *endpt_name,
|
||||
const char *cert_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1);
|
||||
|
||||
if (cert_name) {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/"
|
||||
"inline-definition/certificate[name='%s']", client_name, endpt_name, cert_name);
|
||||
} else {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/tls/tls-server-parameters/client-authentication/ca-certs/"
|
||||
"inline-definition/certificate", client_name, endpt_name);
|
||||
}
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_tls_ca_cert_truststore_ref(const struct ly_ctx *ctx, const char *endpt_name,
|
||||
const char *cert_bag_ref, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, cert_bag_ref, config, 1);
|
||||
|
||||
ret = nc_server_config_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/"
|
||||
"tls-server-parameters/client-authentication/ca-certs/central-truststore-reference", endpt_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete inline definition if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/"
|
||||
"tls-server-parameters/client-authentication/ca-certs/inline-definition", endpt_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_tls_ca_cert_truststore_ref(const char *endpt_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/"
|
||||
"tls-server-parameters/client-authentication/ca-certs/central-truststore-reference", endpt_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_tls_ca_cert_truststore_ref(const struct ly_ctx *ctx, const char *client_name,
|
||||
const char *endpt_name, const char *cert_bag_ref, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, cert_bag_ref, config, 1);
|
||||
|
||||
ret = nc_server_config_create(ctx, config, cert_bag_ref, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/"
|
||||
"client-authentication/ca-certs/central-truststore-reference", client_name, endpt_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* delete inline definition if present */
|
||||
ret = nc_server_config_check_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/"
|
||||
"client-authentication/ca-certs/inline-definition", client_name, endpt_name);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_tls_ca_cert_truststore_ref(const char *client_name, const char *endpt_name,
|
||||
struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/"
|
||||
"netconf-client[name='%s']/endpoints/endpoint[name='%s']/tls/tls-server-parameters/"
|
||||
"client-authentication/ca-certs/central-truststore-reference", client_name, endpt_name);
|
||||
}
|
||||
|
||||
static const char *
|
||||
nc_server_config_tls_maptype2str(NC_TLS_CTN_MAPTYPE map_type)
|
||||
{
|
||||
switch (map_type) {
|
||||
case NC_TLS_CTN_SPECIFIED:
|
||||
return "ietf-x509-cert-to-name:specified";
|
||||
case NC_TLS_CTN_SAN_RFC822_NAME:
|
||||
return "ietf-x509-cert-to-name:san-rfc822-name";
|
||||
case NC_TLS_CTN_SAN_DNS_NAME:
|
||||
return "ietf-x509-cert-to-name:san-dns-name";
|
||||
case NC_TLS_CTN_SAN_IP_ADDRESS:
|
||||
return "ietf-x509-cert-to-name:san-ip-address";
|
||||
case NC_TLS_CTN_SAN_ANY:
|
||||
return "ietf-x509-cert-to-name:san-any";
|
||||
case NC_TLS_CTN_COMMON_NAME:
|
||||
return "ietf-x509-cert-to-name:common-name";
|
||||
case NC_TLS_CTN_UNKNOWN:
|
||||
default:
|
||||
ERR(NULL, "Unknown CTN mapping type.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_nc_server_config_add_tls_ctn(const struct ly_ctx *ctx, const char *tree_path, const char *fingerprint,
|
||||
NC_TLS_CTN_MAPTYPE map_type, const char *name, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
const char *map;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, tree_path, name, config, 1);
|
||||
|
||||
if (fingerprint) {
|
||||
/* optional */
|
||||
ret = nc_server_config_append(ctx, tree_path, "fingerprint", fingerprint, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* get map str */
|
||||
map = nc_server_config_tls_maptype2str(map_type);
|
||||
if (!map) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "map-type", map, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = nc_server_config_append(ctx, tree_path, "name", name, config);
|
||||
if (ret) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_tls_ctn(const struct ly_ctx *ctx, const char *endpt_name, uint32_t id, const char *fingerprint,
|
||||
NC_TLS_CTN_MAPTYPE map_type, const char *name, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, id, name, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/netconf-server-parameters/"
|
||||
"client-identity-mappings/cert-to-name[id='%" PRIu32 "']", endpt_name, id);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_tls_ctn(ctx, path, fingerprint, map_type, name, config);
|
||||
if (ret) {
|
||||
ERR(NULL, "Creating new TLS cert-to-name YANG data failed.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_tls_ctn(const char *endpt_name, uint32_t id, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
|
||||
|
||||
if (id) {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/"
|
||||
"netconf-server-parameters/client-identity-mappings/cert-to-name[id='%" PRIu32 "']", endpt_name, id);
|
||||
} else {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/"
|
||||
"netconf-server-parameters/client-identity-mappings/cert-to-name", endpt_name);
|
||||
}
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_ch_tls_ctn(const struct ly_ctx *ctx, const char *client_name, const char *endpt_name,
|
||||
uint32_t id, const char *fingerprint, NC_TLS_CTN_MAPTYPE map_type, const char *name, struct lyd_node **config)
|
||||
{
|
||||
int ret = 0;
|
||||
char *path = NULL;
|
||||
|
||||
NC_CHECK_ARG_RET(NULL, ctx, client_name, endpt_name, id, name, config, 1);
|
||||
|
||||
ret = asprintf(&path, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/"
|
||||
"cert-to-name[id='%" PRIu32 "']", client_name, endpt_name, id);
|
||||
NC_CHECK_ERRMEM_GOTO(ret == -1, path = NULL; ret = 1, cleanup);
|
||||
|
||||
ret = _nc_server_config_add_tls_ctn(ctx, path, fingerprint, map_type, name, config);
|
||||
if (ret) {
|
||||
ERR(NULL, "Creating new CH TLS cert-to-name YANG data failed.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_ch_tls_ctn(const char *client_name, const char *endpt_name,
|
||||
uint32_t id, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, client_name, endpt_name, config, 1);
|
||||
|
||||
if (id) {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/"
|
||||
"cert-to-name[id='%u']", client_name, endpt_name, id);
|
||||
} else {
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='%s']/"
|
||||
"endpoints/endpoint[name='%s']/tls/netconf-server-parameters/client-identity-mappings/"
|
||||
"cert-to-name", client_name, endpt_name);
|
||||
}
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_add_tls_endpoint_client_ref(const struct ly_ctx *ctx, const char *endpt_name, const char *referenced_endpt, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1);
|
||||
|
||||
return nc_server_config_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/tls-server-parameters/"
|
||||
"client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_server_config_del_tls_endpoint_client_ref(const char *endpt_name, struct lyd_node **config)
|
||||
{
|
||||
NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
|
||||
|
||||
return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoints/endpoint[name='%s']/tls/tls-server-parameters/"
|
||||
"client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name);
|
||||
}
|
1319
src/session.c
1319
src/session.c
File diff suppressed because it is too large
Load diff
|
@ -1,9 +1,11 @@
|
|||
/**
|
||||
* \file session.h
|
||||
* \author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* \brief libnetconf2 session manipulation
|
||||
* @file session.h
|
||||
* @author Radek Krejci <rkrejci@cesnet.cz>
|
||||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 session manipulation
|
||||
*
|
||||
* Copyright (c) 2015 CESNET, z.s.p.o.
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2023 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.
|
||||
|
@ -21,7 +23,7 @@ extern "C" {
|
|||
|
||||
#include "netconf.h"
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/**
|
||||
* @brief Enumeration of NETCONF SSH authentication methods
|
||||
|
@ -32,9 +34,16 @@ typedef enum {
|
|||
NC_SSH_AUTH_INTERACTIVE = 0x04 /**< interactive SSH authentication */
|
||||
} NC_SSH_AUTH_TYPE;
|
||||
|
||||
#endif /* NC_ENABLED_SSH */
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
/**
|
||||
* @brief Enumeration of host key checking and known_hosts entry adding modes
|
||||
*/
|
||||
typedef enum {
|
||||
NC_SSH_KNOWNHOSTS_ASK = 0, /**< add a known_hosts entry, but with a prompt */
|
||||
NC_SSH_KNOWNHOSTS_STRICT, /**< do not add a known_hosts entry and the server's host key must be present in the configured known_hosts file */
|
||||
NC_SSH_KNOWNHOSTS_ACCEPT_NEW, /**< add a known_hosts entry without a prompt */
|
||||
NC_SSH_KNOWNHOSTS_ACCEPT, /**< add a known_hosts entry without a prompt and allow connections to servers which changed their host key */
|
||||
NC_SSH_KNOWNHOSTS_SKIP /**< do not add a known_hosts entry and skip all host key checks */
|
||||
} NC_SSH_KNOWNHOSTS_MODE;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of cert-to-name mapping types
|
||||
|
@ -49,7 +58,17 @@ typedef enum {
|
|||
NC_TLS_CTN_COMMON_NAME /**< common name as username */
|
||||
} NC_TLS_CTN_MAPTYPE;
|
||||
|
||||
#endif /* NC_ENABLED_TLS */
|
||||
/**
|
||||
* @brief Enumeration of TLS versions.
|
||||
*/
|
||||
typedef enum {
|
||||
NC_TLS_VERSION_10 = 1, /**< TLS1.0 */
|
||||
NC_TLS_VERSION_11 = 2, /**< TLS1.1 */
|
||||
NC_TLS_VERSION_12 = 4, /**< TLS1.2 */
|
||||
NC_TLS_VERSION_13 = 8 /**< TLS1.3 */
|
||||
} NC_TLS_VERSION;
|
||||
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
/**
|
||||
* @brief Enumeration of possible session statuses
|
||||
|
@ -70,12 +89,11 @@ typedef enum {
|
|||
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
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
NC_TI_SSH, /**< SSH - use libssh library, only for NETCONF over SSH transport */
|
||||
|
||||
NC_TI_TLS /**< TLS - use either OpenSSL or MbedTLS library, only for NETCONF over TLS transport */
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
} NC_TRANSPORT_IMPL;
|
||||
|
||||
/**
|
||||
|
@ -96,16 +114,6 @@ typedef enum {
|
|||
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
|
||||
*/
|
||||
|
@ -183,6 +191,18 @@ const char *nc_session_get_host(const struct nc_session *session);
|
|||
*/
|
||||
uint16_t nc_session_get_port(const struct nc_session *session);
|
||||
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/**
|
||||
* @brief Get the SSH banner sent by the peer.
|
||||
*
|
||||
* @param[in] session Session to get the banner from.
|
||||
* @return SSH banner on success, NULL on error.
|
||||
*/
|
||||
const char *nc_session_ssh_get_banner(const struct nc_session *session);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get session path (unix socket only).
|
||||
*
|
||||
|
@ -197,7 +217,7 @@ const char *nc_session_get_path(const struct nc_session *session);
|
|||
* @param[in] session Session to get the information from.
|
||||
* @return Session context.
|
||||
*/
|
||||
struct ly_ctx *nc_session_get_ctx(const struct nc_session *session);
|
||||
const struct ly_ctx *nc_session_get_ctx(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Assign arbitrary data to a session.
|
||||
|
@ -215,6 +235,14 @@ void nc_session_set_data(struct nc_session *session, void *data);
|
|||
*/
|
||||
void *nc_session_get_data(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Learn whether a session was created using Call Home or not.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Free the NETCONF session object.
|
||||
*
|
||||
|
@ -223,20 +251,6 @@ void *nc_session_get_data(const struct nc_session *session);
|
|||
*/
|
||||
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
|
||||
|
|
1923
src/session_client.c
1923
src/session_client.c
File diff suppressed because it is too large
Load diff
|
@ -3,6 +3,7 @@
|
|||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 session client manipulation
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
@ -21,18 +22,14 @@ extern "C" {
|
|||
|
||||
#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"
|
||||
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
# include <libssh/libssh.h>
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
/**
|
||||
* @addtogroup client
|
||||
* @{
|
||||
|
@ -82,6 +79,26 @@ int nc_client_set_schema_callback(ly_module_imp_clb clb, void *user_data);
|
|||
*/
|
||||
ly_module_imp_clb nc_client_get_schema_callback(void **user_data);
|
||||
|
||||
/**
|
||||
* @brief Enable/disable loading of all the YANG modules supported by
|
||||
* the server when a new session is created. If disabled, it is expected
|
||||
* that users update the context themselves and load the YANG modules
|
||||
* that are planned to be used. Otherwise even basic RPCs may fail to be sent!
|
||||
*
|
||||
* @param[in] enabled Whether context autofill is enabled or disabled.
|
||||
*/
|
||||
void nc_client_set_new_session_context_autofill(int enabled);
|
||||
|
||||
/**
|
||||
* @brief Set client session context to support schema-mount, if possible.
|
||||
*
|
||||
* Performed automatically unless ::nc_client_set_new_session_context_autofill() was disabled.
|
||||
*
|
||||
* @param[in] session NETCONF session to update.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_set_new_session_context_schema_mount(struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Use the provided thread-specific client's context in the current thread.
|
||||
*
|
||||
|
@ -105,13 +122,15 @@ void nc_client_set_thread_context(void *context);
|
|||
void *nc_client_get_thread_context(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize libssh and/or libssl/libcrypto for use in the client.
|
||||
* @brief Initialize client for establishing connections.
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
void nc_client_init(void);
|
||||
int 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.
|
||||
* the client options, for both SSH and TLS, and for Call Home too.
|
||||
*/
|
||||
void nc_client_destroy(void);
|
||||
|
||||
|
@ -134,13 +153,9 @@ void nc_client_destroy(void);
|
|||
*
|
||||
* @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.
|
||||
* @param[in,out] ctx Optional custom context to use for the session. If not set, a default context is created.
|
||||
* Any YANG modules not present in the context and supported by the server are loaded using \<get-schema\>
|
||||
* (if supported) and/or by searching the searchpath (see ::nc_client_set_schema_searchpath()).
|
||||
* @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);
|
||||
|
@ -153,20 +168,16 @@ struct nc_session *nc_connect_inout(int fdin, int fdout, struct ly_ctx *ctx);
|
|||
* 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.
|
||||
* @param[in,out] ctx Optional custom context to use for the session. If not set, a default context is created.
|
||||
* Any YANG modules not present in the context and supported by the server are loaded using \<get-schema\>
|
||||
* (if supported) and/or by searching the searchpath (see ::nc_client_set_schema_searchpath()).
|
||||
* @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
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/**
|
||||
* @defgroup client_ssh Client SSH
|
||||
|
@ -177,28 +188,25 @@ struct nc_session *nc_connect_unix(const char *address, struct ly_ctx *ctx);
|
|||
*/
|
||||
|
||||
/**
|
||||
* @brief Set SSH authentication hostkey check (knownhosts) callback.
|
||||
* @brief Set the behaviour of checking the host key and adding/reading entries to/from the known_hosts file.
|
||||
*
|
||||
* 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()).
|
||||
* The default mode is ::NC_SSH_KNOWNHOSTS_ASK.
|
||||
*
|
||||
* @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.
|
||||
* @param[in] mode Server host key checking mode.
|
||||
*/
|
||||
void nc_client_ssh_set_auth_hostkey_check_clb(int (*auth_hostkey_check)(const char *hostname, ssh_session session, void *priv),
|
||||
void *priv);
|
||||
void nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_MODE mode);
|
||||
|
||||
/**
|
||||
* @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().
|
||||
* @brief Set the path to the known_hosts file.
|
||||
*
|
||||
* @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.
|
||||
* Repetetive calling replaces the value. If the given file doesn't exist and the process has sufficient
|
||||
* rights, it gets created whenever the file is needed, otherwise an error occurs. If NULL is passed or the
|
||||
* path isn't set, the default known_hosts file will be used.
|
||||
*
|
||||
* @param[in] path Path to the known_hosts file.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
void nc_client_ssh_get_auth_hostkey_check_clb(int (**auth_hostkey_check)(const char *hostname, ssh_session session, void *priv),
|
||||
void **priv);
|
||||
int nc_client_ssh_set_knownhosts_path(const char *path);
|
||||
|
||||
/**
|
||||
* @brief Set SSH password authentication callback.
|
||||
|
@ -354,15 +362,11 @@ const char *nc_client_ssh_get_username(void);
|
|||
* 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.
|
||||
* '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.
|
||||
* @param[in,out] ctx Optional custom context to use for the session. If not set, a default context is created.
|
||||
* Any YANG modules not present in the context and supported by the server are loaded using \<get-schema\>
|
||||
* (if supported) and/or by searching the searchpath (see ::nc_client_set_schema_searchpath()).
|
||||
* @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);
|
||||
|
@ -375,15 +379,11 @@ struct nc_session *nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx
|
|||
* 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.
|
||||
* @param[in] ssh_session libssh structure representing SSH session object. It is fully managed by the created session
|
||||
* including freeing it.
|
||||
* @param[in,out] ctx Optional custom context to use for the session. If not set, a default context is created.
|
||||
* Any YANG modules not present in the context and supported by the server are loaded using \<get-schema\>
|
||||
* (if supported) and/or by searching the searchpath (see ::nc_client_set_schema_searchpath()).
|
||||
* @return Created NETCONF session object or NULL on error.
|
||||
*/
|
||||
struct nc_session *nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx);
|
||||
|
@ -392,24 +392,16 @@ 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.
|
||||
* it has to be created by nc_connect_ssh(), nc_connect_libssh() or nc_connect_ssh_channel().
|
||||
* @param[in,out] ctx Optional custom context to use for the session. If not set, a default context is created.
|
||||
* Any YANG modules not present in the context and supported by the server are loaded using \<get-schema\>
|
||||
* (if supported) and/or by searching the searchpath (see ::nc_client_set_schema_searchpath()).
|
||||
* @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
|
||||
|
@ -458,19 +450,12 @@ int nc_client_tls_set_trusted_ca_paths(const char *ca_file, const char *ca_dir);
|
|||
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.
|
||||
* @brief Deprecated.
|
||||
*/
|
||||
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.
|
||||
* @brief Deprecated.
|
||||
*/
|
||||
void nc_client_tls_get_crl_paths(const char **crl_file, const char **crl_dir);
|
||||
|
||||
|
@ -478,42 +463,26 @@ 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().
|
||||
* 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.
|
||||
* 'localhost' is used by default if NULL is specified. It is verified by TLS when connecting to it.
|
||||
* @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.
|
||||
* @param[in,out] ctx Optional custom context to use for the session. If not set, a default context is created.
|
||||
* Any YANG modules not present in the context and supported by the server are loaded using \<get-schema\>
|
||||
* (if supported) and/or by searching the searchpath (see ::nc_client_set_schema_searchpath()).
|
||||
* @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.
|
||||
* @brief Deprecated. Should not be needed.
|
||||
*/
|
||||
struct nc_session *nc_connect_libssl(SSL *tls, struct ly_ctx *ctx);
|
||||
struct nc_session *nc_connect_libssl(void *tls, struct ly_ctx *ctx);
|
||||
|
||||
/** @} Client TLS */
|
||||
|
||||
#endif /* NC_ENABLED_TLS */
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
/**
|
||||
* @addtogroup client_session
|
||||
|
@ -572,9 +541,9 @@ NC_MSG_TYPE nc_recv_reply(struct nc_session *session, struct nc_rpc *rpc, uint64
|
|||
* @brief Receive NETCONF Notification.
|
||||
*
|
||||
* @param[in] session NETCONF session from which the function gets data. It must be the
|
||||
* client side session object.
|
||||
* 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.
|
||||
* 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,
|
||||
|
@ -584,18 +553,44 @@ NC_MSG_TYPE nc_recv_reply(struct nc_session *session, struct nc_rpc *rpc, uint64
|
|||
*/
|
||||
NC_MSG_TYPE nc_recv_notif(struct nc_session *session, int timeout, struct lyd_node **envp, struct lyd_node **op);
|
||||
|
||||
/**
|
||||
* @brief Callback for receiving notifications in a separate thread.
|
||||
*
|
||||
* @param[in] session NC session that received the notification.
|
||||
* @param[in] envp Notification envelope data tree.
|
||||
* @param[in] op Notification body data tree.
|
||||
* @param[in] user_data Arbitrary user data passed to the callback.
|
||||
*/
|
||||
typedef void (*nc_notif_dispatch_clb)(struct nc_session *session, const struct lyd_node *envp, const struct lyd_node *op,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Receive NETCONF Notifications in a separate thread until the session is terminated
|
||||
* or \<notificationComplete\> is received.
|
||||
* 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.
|
||||
* \<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));
|
||||
int nc_recv_notif_dispatch(struct nc_session *session, nc_notif_dispatch_clb notif_clb);
|
||||
|
||||
/**
|
||||
* @brief Receive NETCONF Notifications in a separate thread until the session is terminated
|
||||
* or \<notificationComplete\> is received. Similar to ::nc_recv_notif_dispatch() but allows
|
||||
* to set arbitrary user data that can be freed as well.
|
||||
*
|
||||
* @param[in] session Netconf session to read notifications from.
|
||||
* @param[in] notif_clb Callback that is called for every received notification (including
|
||||
* \<notificationComplete\>). Parameters are the session the notification was received on
|
||||
* and the notification data.
|
||||
* @param[in] user_data Arbitrary user data.
|
||||
* @param[in] free_data Callback for freeing the user data after notif thread exit.
|
||||
* @return 0 if the thread was successfully created, -1 on error.
|
||||
*/
|
||||
int nc_recv_notif_dispatch_data(struct nc_session *session, nc_notif_dispatch_clb notif_clb, void *user_data,
|
||||
void (*free_data)(void *));
|
||||
|
||||
/**
|
||||
* @brief Send NETCONF RPC message via the session.
|
||||
|
@ -603,7 +598,7 @@ int nc_recv_notif_dispatch(struct nc_session *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.
|
||||
* 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
|
||||
|
@ -613,7 +608,7 @@ NC_MSG_TYPE nc_send_rpc(struct nc_session *session, struct nc_rpc *rpc, int time
|
|||
|
||||
/**
|
||||
* @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.
|
||||
* 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.
|
||||
|
@ -622,6 +617,58 @@ NC_MSG_TYPE nc_send_rpc(struct nc_session *session, struct nc_rpc *rpc, int time
|
|||
*/
|
||||
void nc_client_session_set_not_strict(struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Callback for monitoring client sessions.
|
||||
*
|
||||
* This callback is called whenever the client finds out that a session was disconnected by the server.
|
||||
*
|
||||
* @param[in] session Disconnected session. The session will not be freed, so it is safe to call nc_session_free() on it.
|
||||
* @param[in] user_data Arbitrary user data passed to the callback.
|
||||
*/
|
||||
typedef void (*nc_client_monitoring_clb)(struct nc_session *session, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Start a thread that monitors client sessions.
|
||||
*
|
||||
* Once the thread is running, new sessions will be monitored automatically.
|
||||
*
|
||||
* Note that once you start the monitoring thread, any other client thread that
|
||||
* calls ::nc_session_free() needs to share the same thread context (or be the same thread)
|
||||
* as the thread that called this function (see ::nc_client_set_thread_context()).
|
||||
*
|
||||
* @param[in] monitoring_clb Callback called whenever a session is terminated.
|
||||
* @param[in] user_data Arbitrary user data passed to the callback.
|
||||
* @param[in] free_data Callback for freeing the user data after monitoring thread exits.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
int nc_client_monitoring_thread_start(nc_client_monitoring_clb monitoring_clb, void *user_data, void (*free_data)(void *));
|
||||
|
||||
/**
|
||||
* @brief Stop the client session monitoring thread.
|
||||
*/
|
||||
void nc_client_monitoring_thread_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Enable or disable TCP keepalives. Only affects new sessions.
|
||||
*
|
||||
* Client-side TCP keepalives have the following default values:
|
||||
* - idle time: 1 second
|
||||
* - max probes: 10
|
||||
* - probe interval: 5 seconds
|
||||
*
|
||||
* @param[in] enable Whether to enable or disable TCP keepalives.
|
||||
*/
|
||||
void nc_client_enable_tcp_keepalives(int enable);
|
||||
|
||||
/**
|
||||
* @brief Set TCP keepalive options.
|
||||
*
|
||||
* @param[in] idle_time Time in seconds before the first keepalive probe is sent. If 0, the default value 1 is used.
|
||||
* @param[in] max_probes Maximum number of keepalive probes to send before considering the connection dead. If 0, the default value 10 is used.
|
||||
* @param[in] probe_interval Time in seconds between individual keepalive probes. If 0, the default value 5 is used.
|
||||
*/
|
||||
void nc_client_set_tcp_keepalives(uint16_t idle_time, uint16_t max_probes, uint16_t probe_interval);
|
||||
|
||||
/** @} Client Session */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 Call Home session client manipulation
|
||||
*
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2023 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.
|
||||
|
@ -21,15 +22,15 @@ extern "C" {
|
|||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
# include <libssh/libssh.h>
|
||||
#endif
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
#include "messages_client.h"
|
||||
#include "netconf.h"
|
||||
#include "session.h"
|
||||
|
||||
#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS)
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/**
|
||||
* @defgroup client_ch Client-side Call Home
|
||||
|
@ -43,8 +44,10 @@ extern "C" {
|
|||
* @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.
|
||||
* non-blocking call, -1 for infinite waiting.
|
||||
* @param[in,out] ctx Optional custom context to use for the session. If not set, a default context is created.
|
||||
* Any YANG modules not present in the context and supported by the server are loaded using \<get-schema\>
|
||||
* (if supported) and/or by searching the searchpath (see ::nc_client_set_schema_searchpath()).
|
||||
* @param[out] session New session.
|
||||
* @return 1 on success, 0 on timeout, -1 on error.
|
||||
*/
|
||||
|
@ -52,10 +55,6 @@ int nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **sess
|
|||
|
||||
/** @} 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
|
||||
|
@ -65,28 +64,26 @@ int nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **sess
|
|||
*/
|
||||
|
||||
/**
|
||||
* @brief Set SSH Call Home authentication hostkey check (knownhosts) callback.
|
||||
* @brief Set SSH Call Home behaviour of checking the host key and adding/reading entries to/from the known_hosts file.
|
||||
*
|
||||
* 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()).
|
||||
* The default mode is ::NC_SSH_KNOWNHOSTS_ASK.
|
||||
*
|
||||
* @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.
|
||||
* @param[in] mode Server host key checking mode.
|
||||
*/
|
||||
void nc_client_ssh_ch_set_auth_hostkey_check_clb(int (*auth_hostkey_check)(const char *hostname, ssh_session session, void *priv),
|
||||
void *priv);
|
||||
void nc_client_ssh_ch_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_MODE mode);
|
||||
|
||||
/**
|
||||
* @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().
|
||||
* @brief Set SSH Call Home path to the known_hosts file for connections.
|
||||
*
|
||||
* @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.
|
||||
* Repetetive calling replaces the value. If the given file doesn't exist and the process has sufficient
|
||||
* rights, it gets created whenever the file is needed, otherwise an error occurs. If NULL is passed or the
|
||||
* path isn't set, the default known_hosts file will be used.
|
||||
*
|
||||
* @param[in] path Path to the known_hosts file.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
void nc_client_ssh_ch_get_auth_hostkey_check_clb(int (**auth_hostkey_check)(const char *hostname, ssh_session session, void *priv),
|
||||
void **priv);
|
||||
int nc_client_ssh_ch_set_knownhosts_path(const char *path);
|
||||
|
||||
/**
|
||||
* @brief Set SSH Call Home password authentication callback.
|
||||
*
|
||||
|
@ -95,7 +92,7 @@ void nc_client_ssh_ch_get_auth_hostkey_check_clb(int (**auth_hostkey_check)(cons
|
|||
* 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.
|
||||
* 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),
|
||||
|
@ -119,8 +116,7 @@ void nc_client_ssh_ch_get_auth_password_clb(char *(**auth_password)(const char *
|
|||
* 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.
|
||||
* 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,
|
||||
|
@ -145,8 +141,8 @@ void nc_client_ssh_ch_get_auth_interactive_clb(char *(**auth_interactive)(const
|
|||
* 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] 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),
|
||||
|
@ -254,10 +250,6 @@ 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
|
||||
|
@ -275,6 +267,16 @@ const char *nc_client_ssh_ch_get_username(void);
|
|||
*/
|
||||
int nc_client_tls_ch_add_bind_listen(const char *address, uint16_t port);
|
||||
|
||||
/**
|
||||
* @brief Add a new client bind and start listening on it for TLS Call Home connections coming from the specified hostname.
|
||||
*
|
||||
* @param[in] address IP address to bind to.
|
||||
* @param[in] port Port to bind to.
|
||||
* @param[in] hostname Expected server hostname, verified by TLS when connecting to it. If NULL, the check is skipped.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_client_tls_ch_add_bind_hostname_listen(const char *address, uint16_t port, const char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Remove a TLS listening client bind.
|
||||
*
|
||||
|
@ -289,7 +291,7 @@ int nc_client_tls_ch_del_bind(const char *address, uint16_t port);
|
|||
*
|
||||
* @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.
|
||||
* 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);
|
||||
|
@ -298,8 +300,7 @@ int nc_client_tls_ch_set_cert_key_paths(const char *client_cert, const char *cli
|
|||
* @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.
|
||||
* @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);
|
||||
|
||||
|
@ -307,9 +308,9 @@ void nc_client_tls_ch_get_cert_key_paths(const char **client_cert, const char **
|
|||
* @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.
|
||||
* 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.
|
||||
* 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);
|
||||
|
@ -317,35 +318,24 @@ int nc_client_tls_ch_set_trusted_ca_paths(const char *ca_file, const char *ca_di
|
|||
/**
|
||||
* @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.
|
||||
* @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.
|
||||
* @brief Deprecated.
|
||||
*/
|
||||
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.
|
||||
* @brief Deprecated.
|
||||
*/
|
||||
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 */
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,11 +1,12 @@
|
|||
/**
|
||||
* \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
|
||||
* @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
|
||||
* Copyright (c) 2015 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
@ -15,225 +16,30 @@
|
|||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* pthread_rwlock_t, strdup */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <signal.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 "compat.h"
|
||||
#include "config.h"
|
||||
#include "log_p.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
|
||||
#include "session_p.h"
|
||||
#include "session_wrapper.h"
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -241,12 +47,6 @@ _nc_client_tls_destroy_opts(struct nc_client_tls_opts *opts)
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -260,32 +60,21 @@ nc_client_tls_destroy_opts(void)
|
|||
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;
|
||||
}
|
||||
NC_CHECK_ARG_RET(NULL, client_cert, -1);
|
||||
|
||||
free(opts->cert_path);
|
||||
free(opts->key_path);
|
||||
|
||||
opts->cert_path = strdup(client_cert);
|
||||
if (!opts->cert_path) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!opts->cert_path, -1);
|
||||
|
||||
if (client_key) {
|
||||
opts->key_path = strdup(client_key);
|
||||
if (!opts->key_path) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!opts->key_path, -1);
|
||||
} else {
|
||||
opts->key_path = NULL;
|
||||
}
|
||||
|
||||
opts->tls_ctx_change = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -305,7 +94,7 @@ 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");
|
||||
ERRARG(NULL, "client_cert and client_key");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -333,7 +122,7 @@ 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");
|
||||
ERRARG(NULL, "ca_file and ca_dir");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -342,26 +131,18 @@ _nc_client_tls_set_trusted_ca_paths(const char *ca_file, const char *ca_dir, str
|
|||
|
||||
if (ca_file) {
|
||||
opts->ca_file = strdup(ca_file);
|
||||
if (!opts->ca_file) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!opts->ca_file, -1);
|
||||
} else {
|
||||
opts->ca_file = NULL;
|
||||
}
|
||||
|
||||
if (ca_dir) {
|
||||
opts->ca_dir = strdup(ca_dir);
|
||||
if (!opts->ca_dir) {
|
||||
ERRMEM;
|
||||
return -1;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!opts->ca_dir, -1);
|
||||
} else {
|
||||
opts->ca_dir = NULL;
|
||||
}
|
||||
|
||||
opts->tls_ctx_change = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -381,7 +162,7 @@ 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");
|
||||
ERRARG(NULL, "ca_file and ca_dir");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -405,200 +186,197 @@ 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)
|
||||
API int
|
||||
nc_client_tls_set_crl_paths(const char *UNUSED(crl_file), const char *UNUSED(crl_dir))
|
||||
{
|
||||
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;
|
||||
ERR(NULL, "nc_client_tls_set_crl_paths() is deprecated, do not use it.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
API int
|
||||
nc_client_tls_set_crl_paths(const char *crl_file, const char *crl_dir)
|
||||
nc_client_tls_ch_set_crl_paths(const char *UNUSED(crl_file), const char *UNUSED(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;
|
||||
}
|
||||
ERR(NULL, "nc_client_tls_ch_set_crl_paths() is deprecated, do not use it.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
API void
|
||||
nc_client_tls_get_crl_paths(const char **crl_file, const char **crl_dir)
|
||||
nc_client_tls_get_crl_paths(const char **UNUSED(crl_file), const char **UNUSED(crl_dir))
|
||||
{
|
||||
_nc_client_tls_get_crl_paths(crl_file, crl_dir, &tls_opts);
|
||||
ERR(NULL, "nc_client_tls_get_crl_paths() is deprecated, do not use it.");
|
||||
return;
|
||||
}
|
||||
|
||||
API void
|
||||
nc_client_tls_ch_get_crl_paths(const char **crl_file, const char **crl_dir)
|
||||
nc_client_tls_ch_get_crl_paths(const char **UNUSED(crl_file), const char **UNUSED(crl_dir))
|
||||
{
|
||||
_nc_client_tls_get_crl_paths(crl_file, crl_dir, &tls_ch_opts);
|
||||
ERR(NULL, "nc_client_tls_ch_get_crl_paths() is deprecated, do not use it.");
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
return nc_client_ch_add_bind_listen(address, port, NULL, NC_TI_TLS);
|
||||
}
|
||||
|
||||
API int
|
||||
nc_client_tls_ch_add_bind_hostname_listen(const char *address, uint16_t port, const char *hostname)
|
||||
{
|
||||
return nc_client_ch_add_bind_listen(address, port, hostname, NC_TI_TLS);
|
||||
}
|
||||
|
||||
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);
|
||||
return nc_client_ch_del_bind(address, port, NC_TI_TLS);
|
||||
}
|
||||
|
||||
static int
|
||||
nc_client_tls_update_opts(struct nc_client_tls_opts *opts)
|
||||
nc_client_tls_connect_check(int connect_ret, void *tls_session, const char *peername)
|
||||
{
|
||||
char *key;
|
||||
X509_LOOKUP *lookup;
|
||||
uint32_t verify;
|
||||
char *err;
|
||||
|
||||
if (!opts->tls_ctx || opts->tls_ctx_change) {
|
||||
SSL_CTX_free(opts->tls_ctx);
|
||||
/* check certificate verification result */
|
||||
verify = nc_tls_get_verify_result_wrap(tls_session);
|
||||
if (!verify && (connect_ret == 1)) {
|
||||
VRB(NULL, "Server certificate verified (domain \"%s\").", peername);
|
||||
} else if (verify) {
|
||||
err = nc_tls_verify_error_string_wrap(verify);
|
||||
ERR(NULL, "Server certificate error (%s).", err);
|
||||
free(err);
|
||||
}
|
||||
|
||||
#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);
|
||||
/* check TLS connection result */
|
||||
if (connect_ret != 1) {
|
||||
nc_client_tls_print_connect_err_wrap(connect_ret, peername, tls_session);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
return connect_ret;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
static void *
|
||||
nc_client_tls_session_new(int sock, const char *host, int timeout, struct nc_client_tls_opts *opts, void **out_tls_cfg, struct nc_tls_ctx *tls_ctx)
|
||||
{
|
||||
int ret = 0, sock_tmp = sock;
|
||||
struct timespec ts_timeout;
|
||||
void *tls_session, *tls_cfg, *cli_cert, *cli_pkey, *cert_store, *crl_store;
|
||||
|
||||
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;
|
||||
tls_session = tls_cfg = cli_cert = cli_pkey = cert_store = crl_store = NULL;
|
||||
|
||||
/* prepare TLS context from which a session will be created */
|
||||
tls_cfg = nc_tls_config_new_wrap(NC_CLIENT);
|
||||
if (!tls_cfg) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* opaque CA/CRL certificate store */
|
||||
cert_store = nc_tls_cert_store_new_wrap();
|
||||
if (!cert_store) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* load client's key and certificate */
|
||||
if (nc_client_tls_load_cert_key_wrap(opts->cert_path, opts->key_path, &cli_cert, &cli_pkey)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* load trusted CA certificates */
|
||||
if (nc_client_tls_load_trusted_certs_wrap(cert_store, opts->ca_file, opts->ca_dir)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* load CRLs from set certificates' extensions */
|
||||
if (nc_session_tls_crl_from_cert_ext_fetch(cli_cert, cert_store, &crl_store)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* set client's verify mode flags */
|
||||
nc_client_tls_set_verify_wrap(tls_cfg);
|
||||
|
||||
/* init TLS context and store data which may be needed later in it */
|
||||
if (nc_tls_init_ctx_wrap(cli_cert, cli_pkey, cert_store, crl_store, tls_ctx)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* memory is managed by context now */
|
||||
cli_cert = cli_pkey = cert_store = crl_store = NULL;
|
||||
|
||||
/* setup config from ctx */
|
||||
if (nc_tls_setup_config_from_ctx_wrap(tls_ctx, NC_CLIENT, tls_cfg)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* session from config */
|
||||
tls_session = nc_tls_session_new_wrap(tls_cfg);
|
||||
if (!tls_session) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* set session fd */
|
||||
nc_tls_set_fd_wrap(tls_session, sock, tls_ctx);
|
||||
|
||||
sock = -1;
|
||||
|
||||
/* set session hostname to check against in the server cert */
|
||||
if (nc_client_tls_set_hostname_wrap(tls_session, host)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* handshake */
|
||||
if (timeout > -1) {
|
||||
nc_timeouttime_get(&ts_timeout, timeout);
|
||||
}
|
||||
while ((ret = nc_client_tls_handshake_step_wrap(tls_session, sock_tmp)) == 0) {
|
||||
usleep(NC_TIMEOUT_STEP);
|
||||
if ((timeout > -1) && (nc_timeouttime_cur_diff(&ts_timeout) < 1)) {
|
||||
ERR(NULL, "SSL connect timeout.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* check if handshake was ok */
|
||||
if (nc_client_tls_connect_check(ret, tls_session, host) != 1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
*out_tls_cfg = tls_cfg;
|
||||
return tls_session;
|
||||
|
||||
fail:
|
||||
if (sock > -1) {
|
||||
close(sock);
|
||||
}
|
||||
|
||||
nc_tls_session_destroy_wrap(tls_session);
|
||||
nc_tls_cert_destroy_wrap(cli_cert);
|
||||
nc_tls_privkey_destroy_wrap(cli_pkey);
|
||||
nc_tls_cert_store_destroy_wrap(cert_store);
|
||||
nc_tls_crl_store_destroy_wrap(crl_store);
|
||||
nc_tls_config_destroy_wrap(tls_cfg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
int sock;
|
||||
char *ip_host = NULL;
|
||||
void *tls_cfg = NULL;
|
||||
struct nc_tls_ctx tls_ctx = {0};
|
||||
|
||||
if (!tls_opts.cert_path || (!tls_opts.ca_file && !tls_opts.ca_dir)) {
|
||||
ERRINIT;
|
||||
if (!tls_opts.cert_path) {
|
||||
ERR(NULL, "Client certificate not set.");
|
||||
return NULL;
|
||||
} else if (!tls_opts.ca_file && !tls_opts.ca_dir) {
|
||||
ERR(NULL, "Certificate authority certificates not set.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* process parameters */
|
||||
if (!host || strisempty(host)) {
|
||||
if (!host || (host[0] == '\0')) {
|
||||
host = "localhost";
|
||||
}
|
||||
|
||||
|
@ -606,94 +384,33 @@ nc_connect_tls(const char *host, unsigned short port, struct ly_ctx *ctx)
|
|||
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;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!session, 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);
|
||||
sock = nc_sock_connect(NULL, 0, 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.");
|
||||
/* fill the session */
|
||||
session->ti_type = NC_TI_TLS;
|
||||
if (!(session->ti.tls.session = nc_client_tls_session_new(sock, host, NC_TRANSPORT_TIMEOUT, &tls_opts, &tls_cfg, &tls_ctx))) {
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
session->ti.tls.config = tls_cfg;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
/* memory belongs to session */
|
||||
memcpy(&session->ti.tls.ctx, &tls_ctx, sizeof tls_ctx);
|
||||
memset(&tls_ctx, 0, sizeof tls_ctx);
|
||||
|
||||
if (nc_client_session_new_ctx(session, ctx) != EXIT_SUCCESS) {
|
||||
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;
|
||||
|
@ -704,46 +421,58 @@ nc_connect_tls(const char *host, unsigned short port, struct ly_ctx *ctx)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
/* store information into session and the dictionary */
|
||||
lydict_insert_zc(ctx, ip_host, &session->host);
|
||||
/* start monitoring the session if the monitoring thread is running */
|
||||
if (nc_client_monitoring_session_start(session)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* store information into session */
|
||||
session->host = ip_host;
|
||||
session->port = port;
|
||||
lydict_insert(ctx, "certificate-based", 0, &session->username);
|
||||
session->username = strdup("certificate-based");
|
||||
|
||||
return session;
|
||||
|
||||
fail:
|
||||
free(ip_host);
|
||||
nc_session_free(session, NULL);
|
||||
nc_tls_ctx_destroy_wrap(&tls_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
API struct nc_session *
|
||||
nc_connect_libssl(SSL *tls, struct ly_ctx *ctx)
|
||||
nc_connect_libssl(void *UNUSED(tls), struct ly_ctx *UNUSED(ctx))
|
||||
{
|
||||
struct nc_session *session;
|
||||
ERR(NULL, "nc_connect_libssl() is deprecated, do not use it.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!tls) {
|
||||
ERRARG("tls");
|
||||
return NULL;
|
||||
} else if (!SSL_is_init_finished(tls)) {
|
||||
ERR(NULL, "Supplied TLS session is not fully connected!");
|
||||
return NULL;
|
||||
}
|
||||
struct nc_session *
|
||||
nc_accept_callhome_tls_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx, int timeout, const char *peername)
|
||||
{
|
||||
struct nc_session *session = NULL;
|
||||
void *tls_cfg = NULL;
|
||||
struct nc_tls_ctx tls_ctx = {0};
|
||||
|
||||
/* prepare session structure */
|
||||
session = nc_new_session(NC_CLIENT, 0);
|
||||
if (!session) {
|
||||
ERRMEM;
|
||||
return NULL;
|
||||
}
|
||||
NC_CHECK_ERRMEM_RET(!session, 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) {
|
||||
/* fill the session */
|
||||
session->ti_type = NC_TI_TLS;
|
||||
if (!(session->ti.tls.session = nc_client_tls_session_new(sock, peername, timeout, &tls_ch_opts, &tls_cfg, &tls_ctx))) {
|
||||
goto fail;
|
||||
}
|
||||
session->ti.tls.config = tls_cfg;
|
||||
|
||||
/* memory belongs to session */
|
||||
memcpy(&session->ti.tls.ctx, &tls_ctx, sizeof tls_ctx);
|
||||
memset(&tls_ctx, 0, sizeof tls_ctx);
|
||||
|
||||
if (nc_client_session_new_ctx(session, ctx) != EXIT_SUCCESS) {
|
||||
goto fail;
|
||||
}
|
||||
ctx = session->ctx;
|
||||
|
||||
/* NETCONF handshake */
|
||||
if (nc_handshake_io(session) != NC_MSG_HELLO) {
|
||||
|
@ -755,94 +484,22 @@ nc_connect_libssl(SSL *tls, struct ly_ctx *ctx)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
session->flags |= NC_SESSION_CALLHOME;
|
||||
|
||||
/* start monitoring the session if the monitoring thread is running */
|
||||
if (nc_client_monitoring_session_start(session)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* store information into session */
|
||||
session->host = strdup(host);
|
||||
session->port = port;
|
||||
session->username = strdup("certificate-based");
|
||||
|
||||
return session;
|
||||
|
||||
fail:
|
||||
session->ti.tls = NULL;
|
||||
nc_session_free(session, NULL);
|
||||
nc_tls_ctx_destroy_wrap(&tls_ctx);
|
||||
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;
|
||||
}
|
||||
|
|
2014
src/session_mbedtls.c
Normal file
2014
src/session_mbedtls.c
Normal file
File diff suppressed because it is too large
Load diff
1494
src/session_openssl.c
Normal file
1494
src/session_openssl.c
Normal file
File diff suppressed because it is too large
Load diff
1012
src/session_p.h
1012
src/session_p.h
File diff suppressed because it is too large
Load diff
4131
src/session_server.c
4131
src/session_server.c
File diff suppressed because it is too large
Load diff
|
@ -3,6 +3,7 @@
|
|||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 session server manipulation
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
@ -21,20 +22,17 @@ extern "C" {
|
|||
|
||||
#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 <sys/types.h>
|
||||
|
||||
#include "netconf.h"
|
||||
#include "session.h"
|
||||
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
# include <libssh/callbacks.h>
|
||||
# include <libssh/libssh.h>
|
||||
# include <libssh/server.h>
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
/**
|
||||
* @defgroup server_session Server Session
|
||||
* @ingroup server
|
||||
|
@ -57,6 +55,21 @@ extern "C" {
|
|||
*/
|
||||
typedef struct nc_server_reply *(*nc_rpc_clb)(struct lyd_node *rpc, struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Callback for certificate expiration notification.
|
||||
*
|
||||
* This callback is called when a certificate expiration notification is generated.
|
||||
* It is up to the user to decide what to do with the notification.
|
||||
*
|
||||
* In case an error occurs and you wish to terminate the notification thread,
|
||||
* call nc_server_notif_cert_expiration_thread_stop().
|
||||
*
|
||||
* @param[in] expiration_time Expiration time of the certificate obtained via ly_time_time2str().
|
||||
* @param[in] xpath Xpath of the certificate. Can be used to create the notification data.
|
||||
* @param[in] user_data Arbitrary user data.
|
||||
*/
|
||||
typedef void (*nc_cert_exp_notif_clb)(const char *expiration_time, const char *xpath, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Set the termination reason for a session. Use only in #nc_rpc_clb callbacks.
|
||||
*
|
||||
|
@ -85,47 +98,48 @@ 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.
|
||||
*
|
||||
* If this callback is set, the default callbacks for "get-schema" and "close-session" are not used.
|
||||
*
|
||||
* @param[in] clb An user-defined nc_rpc_clb function callback, NULL to default.
|
||||
*/
|
||||
void nc_set_global_rpc_clb(nc_rpc_clb clb);
|
||||
|
||||
/**
|
||||
* @brief Default RPC callback used for "ietf-netconf-monitoring:get-schema" RPC if no other specific
|
||||
* or global callback is set.
|
||||
*
|
||||
* @param[in] rpc Received RPC.
|
||||
* @param[in] session NC session @p rpc was received on.
|
||||
* @return Server reply.
|
||||
*/
|
||||
struct nc_server_reply *nc_clb_default_get_schema(struct lyd_node *rpc, struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Default RPC callback used for "ietf-netconf:close-session" RPC if no other specific
|
||||
* or global callback is set.
|
||||
*
|
||||
* @param[in] rpc Received RPC.
|
||||
* @param[in] session NC session @p rpc was received on.
|
||||
* @return Server reply.
|
||||
*/
|
||||
struct nc_server_reply *nc_clb_default_close_session(struct lyd_node *rpc, struct nc_session *session);
|
||||
|
||||
/** @} Server Session */
|
||||
|
||||
/**
|
||||
* @addtogroup server
|
||||
* @defgroup server_functions Server Functions
|
||||
* @ingroup server
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initialize libssh and/or libssl/libcrypto and the server using a libyang context.
|
||||
* @brief Initialize libssh and/or libssl/libcrypto and the server.
|
||||
*
|
||||
* 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).
|
||||
* Must be called before other nc_server* functions.
|
||||
*
|
||||
* 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);
|
||||
int nc_server_init(void);
|
||||
|
||||
/**
|
||||
* @brief Destroy any dynamically allocated libssh and/or libssl/libcrypto and
|
||||
|
@ -133,6 +147,23 @@ int nc_server_init(struct ly_ctx *ctx);
|
|||
*/
|
||||
void nc_server_destroy(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize a context which can serve as a default server context.
|
||||
*
|
||||
* Loads the default modules ietf-netconf and ietf-netconf-monitoring and their enabled features - ietf-netconf
|
||||
* enabled features are : writable-running, candidate, rollback-on-error, validate, startup, url, xpath, confirmed-commit and
|
||||
* ietf-netconf-monitoring has no features.
|
||||
*
|
||||
* If ctx is :
|
||||
* - NULL: a new context will be created and if the call is successful you have to free it,
|
||||
* - non NULL: context will be searched for the two modules and their features
|
||||
* and if anything is missing, it will be implemented.
|
||||
*
|
||||
* @param[in,out] ctx Optional context in which the modules will be loaded. Created if ctx is null.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_server_init_ctx(struct ly_ctx **ctx);
|
||||
|
||||
/**
|
||||
* @brief Set the with-defaults capability extra parameters.
|
||||
*
|
||||
|
@ -154,8 +185,8 @@ int nc_server_set_capab_withdefaults(NC_WD_MODE basic_mode, int also_supported);
|
|||
*
|
||||
* At least one argument must be non-NULL.
|
||||
*
|
||||
* @param[in,out] basic_mode basic-mode parameter.
|
||||
* @param[in,out] also_supported also-supported parameter.
|
||||
* @param[out] basic_mode basic-mode parameter.
|
||||
* @param[out] also_supported also-supported parameter.
|
||||
*/
|
||||
void nc_server_get_capab_withdefaults(NC_WD_MODE *basic_mode, int *also_supported);
|
||||
|
||||
|
@ -181,36 +212,6 @@ int nc_server_set_capability(const char *value);
|
|||
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.
|
||||
*
|
||||
|
@ -218,9 +219,9 @@ uint16_t nc_server_get_idle_timeout(void);
|
|||
* server options.
|
||||
*
|
||||
* @param[in] ctx Context to read most capabilities from.
|
||||
* @return Array of capabilities stored in the @p ctx dictionary, NULL on error.
|
||||
* @return Array of capabilities, NULL on error.
|
||||
*/
|
||||
const char **nc_server_get_cpblts(struct ly_ctx *ctx);
|
||||
char **nc_server_get_cpblts(const struct ly_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Get the server capabilities including the schemas with the specified YANG version.
|
||||
|
@ -231,11 +232,11 @@ const char **nc_server_get_cpblts(struct ly_ctx *ctx);
|
|||
* @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.
|
||||
* @return Array of capabilities, NULL on error.
|
||||
*/
|
||||
const char **nc_server_get_cpblts_version(struct ly_ctx *ctx, LYS_VERSION version);
|
||||
char **nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version);
|
||||
|
||||
/** @} Server */
|
||||
/** @} Server Functions */
|
||||
|
||||
/**
|
||||
* @addtogroup server_session
|
||||
|
@ -245,14 +246,18 @@ const char **nc_server_get_cpblts_version(struct ly_ctx *ctx, LYS_VERSION versio
|
|||
/**
|
||||
* @brief Accept a new session on a pre-established transport session.
|
||||
*
|
||||
* For detailed description, look at ::nc_accept().
|
||||
*
|
||||
* @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[in] ctx Context for the session to use.
|
||||
* @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);
|
||||
NC_MSG_TYPE nc_accept_inout(int fdin, int fdout, const char *username, const struct ly_ctx *ctx,
|
||||
struct nc_session **session);
|
||||
|
||||
/**
|
||||
* @brief Create an empty structure for polling sessions.
|
||||
|
@ -298,6 +303,26 @@ int nc_ps_del_session(struct nc_pollsession *ps, struct nc_session *session);
|
|||
*/
|
||||
struct nc_session *nc_ps_get_session(const struct nc_pollsession *ps, uint16_t idx);
|
||||
|
||||
/**
|
||||
* @brief Callback for finding a session in a pollsession structure.
|
||||
*
|
||||
* @param[in] session Considered NETCONF session.
|
||||
* @param[in] cb_data User data.
|
||||
* @return 0 if the session does not match.
|
||||
* @return non-zero if the session matches and should be returned.
|
||||
*/
|
||||
typedef int (*nc_ps_session_match_cb)(struct nc_session *session, void *cb_data);
|
||||
|
||||
/**
|
||||
* @brief Find a session in a pollsession structure using a matching callback.
|
||||
*
|
||||
* @param[in] ps Pollsession structure to read from.
|
||||
* @param[in] match_cb Matching callback to use.
|
||||
* @param[in] cb_data User data passed to @p cb.
|
||||
* @return Found session, NULL if none matched.
|
||||
*/
|
||||
struct nc_session *nc_ps_find_session(const struct nc_pollsession *ps, nc_ps_session_match_cb match_cb, void *cb_data);
|
||||
|
||||
/**
|
||||
* @brief Learn the number of sessions in a pollsession structure.
|
||||
*
|
||||
|
@ -317,10 +342,10 @@ uint16_t nc_ps_session_count(struct nc_pollsession *ps);
|
|||
#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
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
# 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
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
/**
|
||||
* @brief Poll sessions and process any received RPCs.
|
||||
|
@ -353,33 +378,10 @@ void nc_ps_clear(struct nc_pollsession *ps, int all, void (*data_free)(void *));
|
|||
/** @} Server Session */
|
||||
|
||||
/**
|
||||
* @addtogroup server
|
||||
* @addtogroup server_functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
@ -390,75 +392,27 @@ int nc_server_del_endpt(const char *name, NC_TRANSPORT_IMPL ti);
|
|||
int nc_server_endpt_count(void);
|
||||
|
||||
/**
|
||||
* @brief Check if an endpoint exists.
|
||||
* @brief Create a new UNIX socket endpoint and start listening.
|
||||
*
|
||||
* @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] endpt_name Arbitrary unique identifier of the endpoint.
|
||||
* @param[in] unix_socket_path Path to the listening socket.
|
||||
* @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.
|
||||
*
|
||||
* @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);
|
||||
int nc_server_add_endpt_unix_socket_listen(const char *endpt_name, const char *unix_socket_path, mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
/**
|
||||
* @brief Change endpoint keepalives state. Affects only new connections.
|
||||
* @brief Deletes a UNIX socket endpoint.
|
||||
*
|
||||
* @param[in] endpt_name Existing endpoint name.
|
||||
* @param[in] enable Whether to enable or disable keepalives.
|
||||
* @return 0 on success, -1 on error.
|
||||
* @param[in] endpt_name Identifier of the endpoint.
|
||||
* Has no effect if the endpoint doesn't exist or if its transport is not UNIX socket.
|
||||
*/
|
||||
int nc_server_endpt_enable_keepalives(const char *endpt_name, int enable);
|
||||
void nc_server_del_endpt_unix_socket(const char *endpt_name);
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
@ -472,15 +426,26 @@ int nc_server_endpt_set_keepalives(const char *endpt_name, int idle_time, int ma
|
|||
* 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.
|
||||
*
|
||||
* Server capabilities are generated based on the content of @p ctx. The context must
|
||||
* not be destroyed before the accepted NETCONF session is freed. Basic usable context may
|
||||
* be created by calling ::nc_server_init_ctx().
|
||||
*
|
||||
* 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] timeout Timeout for receiving a new connection in milliseconds, 0 for
|
||||
* non-blocking call, -1 for infinite waiting.
|
||||
* non-blocking call, -1 for infinite waiting.
|
||||
* @param[in] ctx Context for the session to use.
|
||||
* @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);
|
||||
NC_MSG_TYPE nc_accept(int timeout, const struct ly_ctx *ctx, struct nc_session **session);
|
||||
|
||||
#ifdef NC_ENABLED_SSH
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/**
|
||||
* @brief Accept a new NETCONF session on an SSH session of a running NETCONF @p orig_session.
|
||||
|
@ -516,172 +481,77 @@ NC_MSG_TYPE nc_ps_accept_ssh_channel(struct nc_pollsession *ps, struct nc_sessio
|
|||
*/
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @brief Set the format of the path to authorized_keys files.
|
||||
*
|
||||
* @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.
|
||||
* This path format will be set globally for all clients wishing to authenticate via the
|
||||
* SSH Public Key system authentication.
|
||||
*
|
||||
* @param[in] path Path to authorized_keys files. The path may contain the following tokens:
|
||||
* - %u - replaced by the username of the user trying to authenticate,
|
||||
* - %h - replaced by the home directory of the user trying to authenticate,
|
||||
* - %U - replaced by the UID of the user trying to authenticate,
|
||||
* - %% - a literal '%'.
|
||||
* @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);
|
||||
int nc_server_ssh_set_authkey_path_format(const char *path);
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @brief Keyboard interactive authentication callback.
|
||||
*
|
||||
* @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.
|
||||
* The callback has to handle sending interactive challenges and receiving responses by itself.
|
||||
* An example callback may fit the following description:
|
||||
* Prepare all prompts for the user and send them via `ssh_message_auth_interactive_request()`.
|
||||
* Get the answers either by calling `ssh_message_get()` or `nc_server_ssh_kbdint_get_nanswers()`.
|
||||
* Return value based on your authentication logic and user answers retrieved by
|
||||
* calling `ssh_userauth_kbdint_getanswer()`.
|
||||
*
|
||||
* @param[in] session NETCONF session.
|
||||
* @param[in] ssh_sess libssh session.
|
||||
* @param[in] msg SSH message that contains the interactive request and which expects a reply with prompts.
|
||||
* @param[in] user_data Arbitrary user data.
|
||||
* @return 0 for successful authentication, non-zero to deny the user.
|
||||
*/
|
||||
int nc_server_ssh_add_authkey_path(const char *pubkey_path, const char *username);
|
||||
typedef int (*nc_server_ssh_interactive_auth_clb)(const struct nc_session *session,
|
||||
ssh_session ssh_sess, ssh_message msg, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Remove an authorized client SSH public key.
|
||||
* @brief Set the callback for SSH interactive authentication.
|
||||
*
|
||||
* @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] auth_clb Keyboard interactive authentication callback. This callback is only called once per authentication.
|
||||
* @param[in] user_data Optional arbitrary user data that will be passed to @p interactive_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));
|
||||
void nc_server_ssh_set_interactive_auth_clb(nc_server_ssh_interactive_auth_clb auth_clb, 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.
|
||||
* @brief Get the number of answers to Keyboard interactive authentication prompts.
|
||||
*
|
||||
* @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.
|
||||
* The actual answers can later be retrieved by calling `ssh_userauth_kbdint_getanswer()` on
|
||||
* the @p libssh_session.
|
||||
*
|
||||
* @param[in] session NETCONF session.
|
||||
* @param[in] libssh_session libssh session.
|
||||
*
|
||||
* @return Non-negative number of answers on success, -1 on configurable authentication timeout,
|
||||
* disconnect or other error.
|
||||
*/
|
||||
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));
|
||||
int nc_server_ssh_kbdint_get_nanswers(const struct nc_session *session, ssh_session libssh_session);
|
||||
|
||||
/**
|
||||
* @brief Set the callback for SSH public key authentication. If none is set, local system users are used.
|
||||
* @brief Set the name of the PAM configuration file.
|
||||
*
|
||||
* @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.
|
||||
* This filename will be set globally for all clients wishing to authenticate via the
|
||||
* SSH Keyboard Interactive authentication method.
|
||||
*
|
||||
* @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] filename Name of the PAM configuration file. The file needs to be located in
|
||||
* the default PAM directory (usually /etc/pam.d/).
|
||||
*
|
||||
* @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.
|
||||
* @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);
|
||||
int nc_server_ssh_set_pam_conf_filename(const char *filename);
|
||||
|
||||
/** @} Server SSH */
|
||||
|
||||
#endif /* NC_ENABLED_SSH */
|
||||
|
||||
#ifdef NC_ENABLED_TLS
|
||||
|
||||
/**
|
||||
* @defgroup server_tls Server TLS
|
||||
* @ingroup server
|
||||
|
@ -690,179 +560,19 @@ int nc_server_ssh_endpt_set_auth_timeout(const char *endpt_name, uint16_t auth_t
|
|||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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);
|
||||
const void *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.
|
||||
* and this callback is set, it is also called. It should return non-zero for success, 0 to deny the user.
|
||||
*
|
||||
* @param[in] verify_clb Additional user verify callback.
|
||||
*/
|
||||
|
@ -870,7 +580,7 @@ void nc_server_tls_set_verify_clb(int (*verify_clb)(const struct nc_session *ses
|
|||
|
||||
/** @} Server TLS */
|
||||
|
||||
#endif /* NC_ENABLED_TLS */
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
/**
|
||||
* @addtogroup server_session
|
||||
|
@ -883,7 +593,7 @@ void nc_server_tls_set_verify_clb(int (*verify_clb)(const struct nc_session *ses
|
|||
* @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);
|
||||
struct timespec nc_session_get_start_time(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Increase session notification subscription flag count.
|
||||
|
@ -912,14 +622,34 @@ void nc_session_dec_notif_status(struct nc_session *session);
|
|||
*/
|
||||
int nc_session_get_notif_status(const struct nc_session *session);
|
||||
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/**
|
||||
* @brief Learn whether a session was created using Call Home or not.
|
||||
* Works only for server sessions.
|
||||
* @brief Start the certificate expiration notification thread.
|
||||
*
|
||||
* @param[in] session Session to get the information from.
|
||||
* @return 0 if a standard session, non-zero if a Call Home session.
|
||||
* The thread will periodically check the expiration time of all certificates in the configuration.
|
||||
* When a notification is about to be generated, the callback @p cert_exp_notif_clb is called.
|
||||
* The times of when these notifications are generated are based on the expiration times of certificates
|
||||
* in the configuration and on the values of intervals set in the configuration. For more information,
|
||||
* see the libnetconf2-netconf-server YANG module.
|
||||
*
|
||||
* @param[in] cert_exp_notif_clb The callback to be called when a notification is generated.
|
||||
* @param[in] user_data Arbitrary user data to pass to the callback.
|
||||
* @param[in] free_data Optional callback to free the user data.
|
||||
*
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
int nc_session_is_callhome(const struct nc_session *session);
|
||||
int nc_server_notif_cert_expiration_thread_start(nc_cert_exp_notif_clb cert_exp_notif_clb,
|
||||
void *user_data, void (*free_data)(void *));
|
||||
|
||||
/**
|
||||
* @brief Stop the certificate expiration notification thread.
|
||||
*
|
||||
* @param[in] wait Boolean representing whether to block and wait for the thread to finish.
|
||||
*/
|
||||
void nc_server_notif_cert_expiration_thread_stop(int wait);
|
||||
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
/** @} Server Session */
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* @author Michal Vasko <mvasko@cesnet.cz>
|
||||
* @brief libnetconf2 Call Home session server manipulation
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2015 - 2021 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
|
@ -21,11 +22,12 @@ extern "C" {
|
|||
|
||||
#include <libyang/libyang.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "netconf.h"
|
||||
#include "session.h"
|
||||
|
||||
#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS)
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/**
|
||||
* @defgroup server_ch Server-side Call Home
|
||||
|
@ -35,21 +37,15 @@ extern "C" {
|
|||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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);
|
||||
/** @} Server-side Call Home */
|
||||
|
||||
/**
|
||||
* @brief Drop any connections, stop connecting and remove a client.
|
||||
* @defgroup server_ch_functions Server-side Call Home Functions
|
||||
* @ingroup server_ch
|
||||
*
|
||||
* @param[in] name Client name. NULL matches all the clients.
|
||||
* @return 0 on success, -1 on not finding any match.
|
||||
* @brief Server-side Call Home functions.
|
||||
* @{
|
||||
*/
|
||||
int nc_server_ch_del_client(const char *name);
|
||||
|
||||
/**
|
||||
* @brief Check if a Call Home client exists.
|
||||
|
@ -59,28 +55,6 @@ int nc_server_ch_del_client(const char *name);
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -91,343 +65,65 @@ int nc_server_ch_client_del_endpt(const char *client_name, const char *endpt_nam
|
|||
int nc_server_ch_client_is_endpt(const char *client_name, const char *endpt_name);
|
||||
|
||||
/**
|
||||
* @brief Change Call Home client endpoint listening address.
|
||||
* @brief Callback for getting a locked context for new Call Home sessions.
|
||||
*
|
||||
* 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.
|
||||
* @param[in] cb_data Arbitrary ctx callback data.
|
||||
* @return Context for the session to use during its lifetime;
|
||||
* @return NULL on error and session fails to be created.
|
||||
*/
|
||||
int nc_server_ch_client_endpt_set_address(const char *client_name, const char *endpt_name, const char *address);
|
||||
typedef const struct ly_ctx *(*nc_server_ch_session_acquire_ctx_cb)(void *cb_data);
|
||||
|
||||
/**
|
||||
* @brief Change Call Home client endpoint listening port.
|
||||
* @brief Callback for releasing a locked context for Call Home sessions.
|
||||
*
|
||||
* 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.
|
||||
* @param[in] cb_data Arbitrary ctx callback data.
|
||||
*/
|
||||
int nc_server_ch_client_endpt_set_port(const char *client_name, const char *endpt_name, uint16_t port);
|
||||
typedef void (*nc_server_ch_session_release_ctx_cb)(void *cb_data);
|
||||
|
||||
/**
|
||||
* @brief Change Call Home client endpoint keepalives state. Affects only new connections.
|
||||
* @brief Callback for new Call Home sessions.
|
||||
*
|
||||
* @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.
|
||||
* @param[in] client_name Name of the CH client which established the session.
|
||||
* @param[in] new_session New established CH session, the pointer is internally discarded afterwards.
|
||||
* @param[in] user_data Arbitrary new session callback data.
|
||||
* @return 0 on success;
|
||||
* @return non-zero on error and @p new_session is freed.
|
||||
*/
|
||||
int nc_server_ch_client_endpt_enable_keepalives(const char *client_name, const char *endpt_name, int enable);
|
||||
typedef int (*nc_server_ch_new_session_cb)(const char *client_name, struct nc_session *new_session, void *user_data);
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @brief Dispatch a thread connecting to a listening NETCONF client and creating Call Home sessions.
|
||||
*
|
||||
* @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.
|
||||
* @param[in] acquire_ctx_cb Callback for acquiring new session context.
|
||||
* @param[in] release_ctx_cb Callback for releasing session context.
|
||||
* @param[in] ctx_cb_data Arbitrary user data passed to @p acquire_ctx_cb and @p release_ctx_cb.
|
||||
* @param[in] new_session_cb Callback called for every established session on the client.
|
||||
* @param[in] new_session_cb_data Arbitrary user data passed to @p new_session_cb.
|
||||
* @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
|
||||
int nc_connect_ch_client_dispatch(const char *client_name, nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb,
|
||||
nc_server_ch_session_release_ctx_cb release_ctx_cb, void *ctx_cb_data, nc_server_ch_new_session_cb new_session_cb,
|
||||
void *new_session_cb_data);
|
||||
|
||||
/**
|
||||
* @defgroup server_ch_ssh Server-side Call Home on SSH
|
||||
* @ingroup server_ch
|
||||
* @brief Set callbacks and their data for Call Home threads.
|
||||
*
|
||||
* @brief SSH settings for the Call Home functionality
|
||||
* @{
|
||||
* If set, Call Home threads will be dispatched automatically upon creation of new Call Home clients.
|
||||
*
|
||||
* @param[in] acquire_ctx_cb Callback for acquiring new session context.
|
||||
* @param[in] release_ctx_cb Callback for releasing session context.
|
||||
* @param[in] ctx_cb_data Arbitrary user data passed to @p acquire_ctx_cb and @p release_ctx_cb.
|
||||
* @param[in] new_session_cb Callback called for every established Call Home session.
|
||||
* @param[in] new_session_cb_data Arbitrary user data passed to @p new_session_cb.
|
||||
*/
|
||||
void nc_server_ch_set_dispatch_data(nc_server_ch_session_acquire_ctx_cb acquire_ctx_cb,
|
||||
nc_server_ch_session_release_ctx_cb release_ctx_cb, void *ctx_cb_data, nc_server_ch_new_session_cb new_session_cb,
|
||||
void *new_session_cb_data);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
/** @} Server-side Call Home Functions */
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
#endif /* NC_ENABLED_SSH_TLS */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
742
src/session_wrapper.h
Normal file
742
src/session_wrapper.h
Normal file
|
@ -0,0 +1,742 @@
|
|||
/**
|
||||
* @file session_wrapper.h
|
||||
* @author Roman Janota <janota@cesnet.cz>
|
||||
* @brief libnetconf2 - header for wrapped TLS library function calls (currently OpenSSL and MbedTLS)
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2024 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 _SESSION_WRAPPER_H_
|
||||
#define _SESSION_WRAPPER_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_MBEDTLS
|
||||
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/pk.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
#include <mbedtls/x509_crl.h>
|
||||
#include <mbedtls/x509_crt.h>
|
||||
|
||||
/**
|
||||
* @brief Context from which a TLS session may be created.
|
||||
*/
|
||||
struct nc_tls_ctx {
|
||||
int *sock; /**< Socket FD. */
|
||||
mbedtls_entropy_context *entropy; /**< Entropy. */
|
||||
mbedtls_ctr_drbg_context *ctr_drbg; /**< Random bit generator. */
|
||||
mbedtls_x509_crt *cert; /**< Certificate. */
|
||||
mbedtls_pk_context *pkey; /**< Private key. */
|
||||
mbedtls_x509_crt *cert_store; /**< CA certificates store. */
|
||||
mbedtls_x509_crl *crl_store; /**< CRL store. */
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
/**
|
||||
* @brief Context from which a TLS session may be created.
|
||||
*/
|
||||
struct nc_tls_ctx {
|
||||
X509 *cert; /**< Certificate. */
|
||||
EVP_PKEY *pkey; /**< Private key. */
|
||||
X509_STORE *cert_store; /**< CA certificate store. */
|
||||
X509_STORE *crl_store; /**< CRL store. */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Server side TLS verify callback data.
|
||||
*/
|
||||
struct nc_tls_verify_cb_data {
|
||||
struct nc_session *session; /**< NETCONF session. */
|
||||
struct nc_server_tls_opts *opts; /**< TLS server options. */
|
||||
void *chain; /**< Certificate chain used to verify the client cert. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a new TLS session from the given configuration.
|
||||
*
|
||||
* @param[in] tls_cfg TLS configuration.
|
||||
* @return New TLS session on success, NULL on fail.
|
||||
*/
|
||||
void * nc_tls_session_new_wrap(void *tls_cfg);
|
||||
|
||||
/**
|
||||
* @brief Destroys a TLS session.
|
||||
*
|
||||
* @param[in] tls_session TLS session to destroy.
|
||||
*/
|
||||
void nc_tls_session_destroy_wrap(void *tls_session);
|
||||
|
||||
/**
|
||||
* @brief Creates a new TLS configuration.
|
||||
*
|
||||
* @param[in] side Side of the TLS connection.
|
||||
* @return New TLS configuration on success, NULL on fail.
|
||||
*/
|
||||
void * nc_tls_config_new_wrap(int side);
|
||||
|
||||
/**
|
||||
* @brief Destroys a TLS configuration.
|
||||
*
|
||||
* @param[in] tls_cfg TLS configuration to destroy.
|
||||
*/
|
||||
void nc_tls_config_destroy_wrap(void *tls_cfg);
|
||||
|
||||
/**
|
||||
* @brief Creates a new TLS certificate.
|
||||
*
|
||||
* @return New TLS certificate on success, NULL on fail.
|
||||
*/
|
||||
void * nc_tls_cert_new_wrap(void);
|
||||
|
||||
/**
|
||||
* @brief Destroys a TLS certificate.
|
||||
*
|
||||
* @param[in] cert TLS certificate to destroy.
|
||||
*/
|
||||
void nc_tls_cert_destroy_wrap(void *cert);
|
||||
|
||||
/**
|
||||
* @brief Destroys a TLS private key.
|
||||
*
|
||||
* @param[in] pkey TLS private key to destroy.
|
||||
*/
|
||||
void nc_tls_privkey_destroy_wrap(void *pkey);
|
||||
|
||||
/**
|
||||
* @brief Creates a new TLS certificate store.
|
||||
*
|
||||
* @return New TLS certificate store on success, NULL on fail.
|
||||
*/
|
||||
void * nc_tls_cert_store_new_wrap(void);
|
||||
|
||||
/**
|
||||
* @brief Destroys a TLS certificate store.
|
||||
*
|
||||
* @param[in] cert_store TLS certificate store to destroy.
|
||||
*/
|
||||
void nc_tls_cert_store_destroy_wrap(void *cert_store);
|
||||
|
||||
/**
|
||||
* @brief Creates a new CRL store.
|
||||
*
|
||||
* @return New CRL store on success, NULL on fail.
|
||||
*/
|
||||
void * nc_tls_crl_store_new_wrap(void);
|
||||
|
||||
/**
|
||||
* @brief Destroys a CRL store.
|
||||
*
|
||||
* @param[in] crl_store CRL store to destroy.
|
||||
*/
|
||||
void nc_tls_crl_store_destroy_wrap(void *crl_store);
|
||||
|
||||
/**
|
||||
* @brief Converts PEM certificate data to a certificate.
|
||||
*
|
||||
* @param[in] cert_data PEM certificate data.
|
||||
* @return New certificate on success, NULL on fail.
|
||||
*/
|
||||
void * nc_tls_pem_to_cert_wrap(const char *cert_data);
|
||||
|
||||
/**
|
||||
* @brief Adds a certificate to a certificate store.
|
||||
*
|
||||
* @param[in] cert Certificate to add.
|
||||
* @param[in] cert_store Certificate store to add the certificate to.
|
||||
* @return 0 on success and the memory belongs to cert_store, non-zero on fail.
|
||||
*/
|
||||
int nc_tls_add_cert_to_store_wrap(void *cert, void *cert_store);
|
||||
|
||||
/**
|
||||
* @brief Converts PEM private key data to a private key.
|
||||
*
|
||||
* @param[in] privkey_data PEM private key data.
|
||||
* @return New private key on success, NULL on fail.
|
||||
*/
|
||||
void * nc_tls_pem_to_privkey_wrap(const char *privkey_data);
|
||||
|
||||
/**
|
||||
* @brief Parses and adds a CRL to a CRL store.
|
||||
*
|
||||
* @param[in] crl_data CRL data.
|
||||
* @param[in] size Size of the CRL data.
|
||||
* @param[in] crl_store CRL store to add the CRL to.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_server_tls_add_crl_to_store_wrap(const unsigned char *crl_data, size_t size, void *crl_store);
|
||||
|
||||
/**
|
||||
* @brief Sets the TLS version.
|
||||
*
|
||||
* @param[in] tls_cfg TLS configuration.
|
||||
* @param[in] tls_versions Bit-field of supported TLS versions.
|
||||
*
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_server_tls_set_tls_versions_wrap(void *tls_cfg, unsigned int tls_versions);
|
||||
|
||||
/**
|
||||
* @brief Set TLS server's verify flags, verify cb and its data.
|
||||
*
|
||||
* @param[in] tls_cfg TLS configuration.
|
||||
* @param[in] cb_data Verify callback data.
|
||||
*/
|
||||
void nc_server_tls_set_verify_wrap(void *tls_cfg, struct nc_tls_verify_cb_data *cb_data);
|
||||
|
||||
/**
|
||||
* @brief Set TLS client's verify flags.
|
||||
*
|
||||
* @param[in] tls_cfg TLS configuration.
|
||||
*/
|
||||
void nc_client_tls_set_verify_wrap(void *tls_cfg);
|
||||
|
||||
/**
|
||||
* @brief Verify the certificate.
|
||||
*
|
||||
* @param[in] cert Certificate to verify.
|
||||
* @param[in] depth Certificate depth.
|
||||
* @param[in] trusted Boolean flag representing whether the certificate is trusted.
|
||||
* @param[in] cb_data Data for the verify callback.
|
||||
* @return 0 on success, 1 on verify fail, -1 on fatal error.
|
||||
*/
|
||||
int nc_server_tls_verify_cert(void *cert, int depth, int trusted, struct nc_tls_verify_cb_data *cb_data);
|
||||
|
||||
/**
|
||||
* @brief Check if the peer certificate matches any configured ee certs.
|
||||
*
|
||||
* @param[in] peer_cert Peer certificate.
|
||||
* @param[in] opts TLS options.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_server_tls_verify_peer_cert(void *peer_cert, struct nc_server_tls_opts *opts);
|
||||
|
||||
/**
|
||||
* @brief Get the subject of the certificate.
|
||||
*
|
||||
* @param[in] cert Certificate.
|
||||
* @return Subject of the certificate on success, NULL on fail.
|
||||
*/
|
||||
char * nc_server_tls_get_subject_wrap(void *cert);
|
||||
|
||||
/**
|
||||
* @brief Get the issuer of the certificate.
|
||||
*
|
||||
* @param[in] cert Certificate.
|
||||
* @return Issuer of the certificate on success, NULL on fail.
|
||||
*/
|
||||
char * nc_server_tls_get_issuer_wrap(void *cert);
|
||||
|
||||
/**
|
||||
* @brief Get the Subject Alternative Names of the certificate.
|
||||
*
|
||||
* @param[in] cert Certificate.
|
||||
* @return SANs on success, NULL on fail.
|
||||
*/
|
||||
void * nc_tls_get_sans_wrap(void *cert);
|
||||
|
||||
/**
|
||||
* @brief Destroy the SANs.
|
||||
*
|
||||
* @param[in] sans SANs to destroy.
|
||||
*/
|
||||
void nc_tls_sans_destroy_wrap(void *sans);
|
||||
|
||||
/**
|
||||
* @brief Get the number of SANs.
|
||||
*
|
||||
* @param[in] sans SANs.
|
||||
* @return Number of SANs.
|
||||
*/
|
||||
int nc_tls_get_num_sans_wrap(void *sans);
|
||||
|
||||
#ifdef NC_ENABLED_SSH_TLS
|
||||
|
||||
/**
|
||||
* @brief Get the SAN value and type in the context of CTN.
|
||||
*
|
||||
* @param[in] sans SANs.
|
||||
* @param[in] idx Index of the SAN.
|
||||
* @param[out] san_value SAN value.
|
||||
* @param[out] san_type SAN type.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_tls_get_san_value_type_wrap(void *sans, int idx, char **san_value, NC_TLS_CTN_MAPTYPE *san_type);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get the number of certificates in a certificate chain.
|
||||
*
|
||||
* @param[in] chain Certificate chain.
|
||||
* @return Number of certificates in the chain.
|
||||
*/
|
||||
int nc_tls_get_num_certs_wrap(void *chain);
|
||||
|
||||
/**
|
||||
* @brief Get a certificate from a certificate chain.
|
||||
*
|
||||
* @param[in] chain Certificate chain.
|
||||
* @param[in] idx Index of the certificate to get.
|
||||
* @param[out] cert Certificate.
|
||||
*/
|
||||
void nc_tls_get_cert_wrap(void *chain, int idx, void **cert);
|
||||
|
||||
/**
|
||||
* @brief Compare two certificates.
|
||||
*
|
||||
* @param[in] cert1 Certificate 1.
|
||||
* @param[in] cert2 Certificate 2.
|
||||
* @return 1 if the certificates match, 0 otherwise.
|
||||
*/
|
||||
int nc_server_tls_certs_match_wrap(void *cert1, void *cert2);
|
||||
|
||||
/**
|
||||
* @brief Get the MD5 digest of the certificate.
|
||||
*
|
||||
* @param[in] cert Certificate.
|
||||
* @param[out] buf Buffer for the digest.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_server_tls_md5_wrap(void *cert, unsigned char *buf);
|
||||
|
||||
/**
|
||||
* @brief Get the SHA1 digest of the certificate.
|
||||
*
|
||||
* @param[in] cert Certificate.
|
||||
* @param[out] buf Buffer for the digest.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_server_tls_sha1_wrap(void *cert, unsigned char *buf);
|
||||
|
||||
/**
|
||||
* @brief Get the SHA224 digest of the certificate.
|
||||
*
|
||||
* @param[in] cert Certificate.
|
||||
* @param[out] buf Buffer for the digest.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_server_tls_sha224_wrap(void *cert, unsigned char *buf);
|
||||
|
||||
/**
|
||||
* @brief Get the SHA256 digest of the certificate.
|
||||
*
|
||||
* @param[in] cert Certificate.
|
||||
* @param[out] buf Buffer for the digest.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_server_tls_sha256_wrap(void *cert, unsigned char *buf);
|
||||
|
||||
/**
|
||||
* @brief Get the SHA384 digest of the certificate.
|
||||
*
|
||||
* @param[in] cert Certificate.
|
||||
* @param[out] buf Buffer for the digest.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_server_tls_sha384_wrap(void *cert, unsigned char *buf);
|
||||
|
||||
/**
|
||||
* @brief Get the SHA512 digest of the certificate.
|
||||
*
|
||||
* @param[in] cert Certificate.
|
||||
* @param[out] buf Buffer for the digest.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_server_tls_sha512_wrap(void *cert, unsigned char *buf);
|
||||
|
||||
/**
|
||||
* @brief Set the FD for a TLS session.
|
||||
*
|
||||
* @param[in] tls_session TLS session.
|
||||
* @param[in] sock Socket FD.
|
||||
* @param[in] tls_ctx TLS context.
|
||||
*/
|
||||
void nc_tls_set_fd_wrap(void *tls_session, int sock, struct nc_tls_ctx *tls_ctx);
|
||||
|
||||
/**
|
||||
* @brief Perform a server-side step of the TLS handshake.
|
||||
*
|
||||
* @param[in] tls_session TLS session.
|
||||
* @return 1 on success, 0 if the handshake is not finished, negative number on error.
|
||||
*/
|
||||
int nc_server_tls_handshake_step_wrap(void *tls_session);
|
||||
|
||||
/**
|
||||
* @brief Perform a client-side step of the TLS handshake.
|
||||
*
|
||||
* @param[in] tls_session TLS session.
|
||||
* @param[in] sock Socket FD.
|
||||
* @return 1 on success, 0 if the handshake is not finished, negative number on error.
|
||||
*/
|
||||
int nc_client_tls_handshake_step_wrap(void *tls_session, int sock);
|
||||
|
||||
/**
|
||||
* @brief Destroy a TLS context.
|
||||
*
|
||||
* @param[in] tls_ctx TLS context.
|
||||
*/
|
||||
void nc_tls_ctx_destroy_wrap(struct nc_tls_ctx *tls_ctx);
|
||||
|
||||
/**
|
||||
* @brief Load client's certificate and a private key.
|
||||
*
|
||||
* @param[in] cert_path Path to the certificate.
|
||||
* @param[in] key_path Path to the private key.
|
||||
* @param[out] cert Certificate.
|
||||
* @param[out] pkey Private key.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_client_tls_load_cert_key_wrap(const char *cert_path, const char *key_path, void **cert, void **pkey);
|
||||
|
||||
/**
|
||||
* @brief Load client's trusted certificates.
|
||||
*
|
||||
* @param[in] cert_store Certificate store.
|
||||
* @param[in] file_path Path to the file with trusted certificates.
|
||||
* @param[in] dir_path Path to the directory with trusted certificates.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_client_tls_load_trusted_certs_wrap(void *cert_store, const char *file_path, const char *dir_path);
|
||||
|
||||
/**
|
||||
* @brief Set the hostname for the TLS session.
|
||||
*
|
||||
* @param[in] tls_session TLS session.
|
||||
* @param[in] hostname Hostname.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_client_tls_set_hostname_wrap(void *tls_session, const char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Initialize a TLS context.
|
||||
*
|
||||
* @param[in] cert Certificate.
|
||||
* @param[in] pkey Private key.
|
||||
* @param[in] cert_store Certificate store.
|
||||
* @param[in] crl_store CRL store.
|
||||
* @param[in,out] tls_ctx TLS context.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_tls_init_ctx_wrap(void *cert, void *pkey, void *cert_store, void *crl_store, struct nc_tls_ctx *tls_ctx);
|
||||
|
||||
/**
|
||||
* @brief Setup a TLS configuration from a TLS context.
|
||||
*
|
||||
* @param[in] tls_ctx TLS context.
|
||||
* @param[in] side Side of the TLS connection.
|
||||
* @param[in,out] tls_cfg TLS configuration.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_tls_setup_config_from_ctx_wrap(struct nc_tls_ctx *tls_ctx, int side, void *tls_cfg);
|
||||
|
||||
/**
|
||||
* @brief Get the error code from a TLS session's verification.
|
||||
*
|
||||
* @param[in] tls_session TLS session.
|
||||
* @return Error code, 0 indicates success.
|
||||
*/
|
||||
uint32_t nc_tls_get_verify_result_wrap(void *tls_session);
|
||||
|
||||
/**
|
||||
* @brief Get the error string from a TLS session's verification.
|
||||
*
|
||||
* @param[in] err_code Error code.
|
||||
* @return Error string.
|
||||
*/
|
||||
char * nc_tls_verify_error_string_wrap(uint32_t err_code);
|
||||
|
||||
/**
|
||||
* @brief Print the TLS session's connection error.
|
||||
*
|
||||
* @param[in] connect_ret Error code.
|
||||
* @param[in] peername Peername.
|
||||
* @param[in] tls_session TLS session.
|
||||
*/
|
||||
void nc_client_tls_print_connect_err_wrap(int connect_ret, const char *peername, void *tls_session);
|
||||
|
||||
/**
|
||||
* @brief Print the TLS session's accept error.
|
||||
*
|
||||
* @param[in] accept_ret Error code.
|
||||
* @param[in] tls_session TLS session.
|
||||
*/
|
||||
void nc_server_tls_print_accept_err_wrap(int accept_ret, void *tls_session);
|
||||
|
||||
/**
|
||||
* @brief Checks if the DER data is a SubjectPublicKeyInfo public key.
|
||||
*
|
||||
* @param[in] der DER data.
|
||||
* @param[in] len Length of the DER data.
|
||||
*
|
||||
* @return 1 if the data is a SubjectPublicKeyInfo public key, 0 if not, -1 on error.
|
||||
*/
|
||||
int nc_tls_is_der_subpubkey_wrap(unsigned char *der, long len);
|
||||
|
||||
/**
|
||||
* @brief Decodes base64 to binary.
|
||||
*
|
||||
* @param[in] base64 Base64 string.
|
||||
* @param[out] bin Binary result, memory managed by the caller.
|
||||
* @return Length of the binary data on success, -1 on error.
|
||||
*/
|
||||
int nc_base64_decode_wrap(const char *base64, unsigned char **bin);
|
||||
|
||||
/**
|
||||
* @brief Encodes binary to base64.
|
||||
*
|
||||
* @param[in] bin Binary data.
|
||||
* @param[in] len Length of the binary data.
|
||||
* @param[out] base64 NULL terminated Base64 result, memory managed by the caller.
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int nc_base64_encode_wrap(const unsigned char *bin, size_t len, char **base64);
|
||||
|
||||
/**
|
||||
* @brief Reads data from a TLS session.
|
||||
*
|
||||
* @param[in] session NETCONF session.
|
||||
* @param[out] buf Buffer for the data.
|
||||
* @param[in] size Size of the buffer.
|
||||
* @return Number of bytes read on success, -1 on error.
|
||||
*/
|
||||
int nc_tls_read_wrap(struct nc_session *session, unsigned char *buf, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Writes data to a TLS session.
|
||||
*
|
||||
* @param[in] session NETCONF session.
|
||||
* @param[in] buf Data to write.
|
||||
* @param[in] size Size of the data.
|
||||
* @return Number of bytes written on success, -1 on error.
|
||||
*/
|
||||
int nc_tls_write_wrap(struct nc_session *session, const unsigned char *buf, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Get the number of pending bytes in a TLS session.
|
||||
*
|
||||
* @param[in] tls_session TLS session.
|
||||
* @return Number of pending bytes.
|
||||
*/
|
||||
int nc_tls_get_num_pending_bytes_wrap(void *tls_session);
|
||||
|
||||
/**
|
||||
* @brief Get the file descriptor of a TLS session.
|
||||
*
|
||||
* @param[in] session NETCONF session.
|
||||
* @return File descriptor, -1 on error.
|
||||
*/
|
||||
int nc_tls_get_fd_wrap(const struct nc_session *session);
|
||||
|
||||
/**
|
||||
* @brief Close a TLS session.
|
||||
*
|
||||
* @param[in] tls_session TLS session.
|
||||
*/
|
||||
void nc_tls_close_notify_wrap(void *tls_session);
|
||||
|
||||
/**
|
||||
* @brief Import a private key from a file.
|
||||
*
|
||||
* @param[in] privkey_path Path to the private key file.
|
||||
* @return Imported private key on success, NULL on fail.
|
||||
*/
|
||||
void * nc_tls_import_privkey_file_wrap(const char *privkey_path);
|
||||
|
||||
/**
|
||||
* @brief Import a certificate from a file.
|
||||
*
|
||||
* @param[in] cert_path Path to the certificate file.
|
||||
* @return Imported certificate on success, NULL on fail.
|
||||
*/
|
||||
void * nc_tls_import_cert_file_wrap(const char *cert_path);
|
||||
|
||||
/**
|
||||
* @brief Export a private key to a PEM string.
|
||||
*
|
||||
* @param[in] pkey Private key.
|
||||
* @return PEM string on success, NULL on fail.
|
||||
*/
|
||||
char * nc_tls_export_privkey_pem_wrap(void *pkey);
|
||||
|
||||
/**
|
||||
* @brief Export a certificate to a PEM string.
|
||||
*
|
||||
* @param[in] cert Certificate.
|
||||
* @return PEM string on success, NULL on fail.
|
||||
*/
|
||||
char * nc_tls_export_cert_pem_wrap(void *cert);
|
||||
|
||||
/**
|
||||
* @brief Export a public key to a PEM string.
|
||||
*
|
||||
* @param[in] pkey Public key.
|
||||
* @return PEM string on success, NULL on fail.
|
||||
*/
|
||||
char * nc_tls_export_pubkey_pem_wrap(void *pkey);
|
||||
|
||||
/**
|
||||
* @brief Check if a private key is RSA.
|
||||
*
|
||||
* @param[in] pkey Private key.
|
||||
* @return 1 if the private key is RSA, 0 if not.
|
||||
*/
|
||||
int nc_tls_privkey_is_rsa_wrap(void *pkey);
|
||||
|
||||
/**
|
||||
* @brief Get the RSA public key parameters from a private key.
|
||||
*
|
||||
* @param[in] pkey Private key.
|
||||
* @param[out] e Exponent.
|
||||
* @param[out] n Modulus.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_tls_get_rsa_pubkey_params_wrap(void *pkey, void **e, void **n);
|
||||
|
||||
/**
|
||||
* @brief Destroy an MPI.
|
||||
*
|
||||
* @param[in] mpi MPI.
|
||||
*/
|
||||
void nc_tls_destroy_mpi_wrap(void *mpi);
|
||||
|
||||
/**
|
||||
* @brief Check if a private key is EC.
|
||||
*
|
||||
* @param[in] pkey Private key.
|
||||
* @return 1 if the private key is EC, 0 if not.
|
||||
*/
|
||||
int nc_tls_privkey_is_ec_wrap(void *pkey);
|
||||
|
||||
/**
|
||||
* @brief Get the group name of an EC private key.
|
||||
*
|
||||
* @param[in] pkey Private key.
|
||||
* @return Group name on success, NULL on fail.
|
||||
*/
|
||||
char * nc_tls_get_ec_group_wrap(void *pkey);
|
||||
|
||||
/**
|
||||
* @brief Get the EC public key parameters from a private key.
|
||||
*
|
||||
* @param[in] pkey Private key.
|
||||
* @param[out] q Public key point.
|
||||
* @param[out] q_grp Public key group.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_tls_get_ec_pubkey_params_wrap(void *pkey, void **q, void **q_grp);
|
||||
|
||||
/**
|
||||
* @brief Convert an EC point to binary.
|
||||
*
|
||||
* @param[in] q EC point.
|
||||
* @param[in] q_grp EC group.
|
||||
* @param[out] bin Binary point.
|
||||
* @param[out] bin_len Length of the binary point.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_tls_ec_point_to_bin_wrap(void *q, void *q_grp, unsigned char **bin, int *bin_len);
|
||||
|
||||
/**
|
||||
* @brief Destroy an EC point.
|
||||
*
|
||||
* @param[in] p EC point.
|
||||
*/
|
||||
void nc_tls_ec_point_destroy_wrap(void *p);
|
||||
|
||||
/**
|
||||
* @brief Destroy an EC group.
|
||||
*
|
||||
* @param[in] grp EC group.
|
||||
*/
|
||||
void nc_tls_ec_group_destroy_wrap(void *grp);
|
||||
|
||||
/**
|
||||
* @brief Convert an MPI to binary.
|
||||
*
|
||||
* @param[in] mpi MPI.
|
||||
* @param[out] bin Binary buffer.
|
||||
* @param[out] bin_len Length of the binary.
|
||||
* @return 0 on success, 1 on error.
|
||||
*/
|
||||
int nc_tls_mpi2bin_wrap(void *mpi, unsigned char **bin, int *bin_len);
|
||||
|
||||
/**
|
||||
* @brief Import a public key from a file.
|
||||
*
|
||||
* @param[in] pubkey_path Path to the public key file.
|
||||
* @return Imported public key on success, NULL on fail.
|
||||
*/
|
||||
void * nc_tls_import_pubkey_file_wrap(const char *pubkey_path);
|
||||
|
||||
/**
|
||||
* @brief Get all the URIs from the CRLDistributionPoints x509v3 extensions.
|
||||
*
|
||||
* @param[in] leaf_cert Server/client certificate.
|
||||
* @param[in] cert_store Certificate store.
|
||||
* @param[out] uris URIs to download the CRLs from.
|
||||
* @param[out] uri_count Number of URIs found.
|
||||
* @return 0 on success, non-zero on fail.
|
||||
*/
|
||||
int nc_server_tls_get_crl_distpoint_uris_wrap(void *leaf_cert, void *cert_store, char ***uris, int *uri_count);
|
||||
|
||||
/**
|
||||
* @brief Process a cipher suite so that it can be set by the underlying TLS lib.
|
||||
*
|
||||
* @param[in] cipher Cipher suite identity value.
|
||||
* @param[out] out Processed cipher suite.
|
||||
* @return 0 on success, 1 on fail.
|
||||
*/
|
||||
int nc_tls_process_cipher_suite_wrap(const char *cipher, char **out);
|
||||
|
||||
/**
|
||||
* @brief Append a cipher suite to the list of cipher suites.
|
||||
*
|
||||
* @param[in] opts TLS options.
|
||||
* @param[in] cipher_suite Cipher suite to append.
|
||||
* @return 0 on success, 1 on fail.
|
||||
*/
|
||||
int nc_tls_append_cipher_suite_wrap(struct nc_server_tls_opts *opts, const char *cipher_suite);
|
||||
|
||||
/**
|
||||
* @brief Set the list of cipher suites for the TLS configuration.
|
||||
*
|
||||
* @param[in] tls_cfg TLS configuration.
|
||||
* @param[in] cipher_suites List of cipher suites.
|
||||
*/
|
||||
void nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, void *cipher_suites);
|
||||
|
||||
/**
|
||||
* @brief Get the certificate's expiration time.
|
||||
*
|
||||
* @param[in] cert Certificate.
|
||||
*
|
||||
* @return Calendar time of the expiration (it is in GMT) or -1 on error.
|
||||
*/
|
||||
time_t nc_tls_get_cert_exp_time_wrap(void *cert);
|
||||
|
||||
/**
|
||||
* @brief Set the session to log TLS secrets for.
|
||||
*
|
||||
* @param[in] session Session to log secrets for.
|
||||
*/
|
||||
void nc_tls_keylog_session_wrap(void *session);
|
||||
|
||||
#endif
|
|
@ -3,76 +3,100 @@ 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()
|
||||
if(${SOURCE_FORMAT_ENABLED})
|
||||
add_test(NAME format WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND cmake --build ${CMAKE_BINARY_DIR} --target format-check)
|
||||
endif()
|
||||
|
||||
foreach(src IN LISTS libsrc)
|
||||
list(APPEND test_srcs "../${src}")
|
||||
endforeach()
|
||||
add_library(testobj OBJECT ${test_srcs})
|
||||
add_library(testobj OBJECT ${test_srcs} ${compatsrc})
|
||||
|
||||
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()
|
||||
set(TEST_SRC "ln2_test.c")
|
||||
set(NEXT_TEST_PORT 10050)
|
||||
|
||||
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()
|
||||
macro(get_test_ports PORT_COUNT PORT_DEFINITIONS)
|
||||
if (NOT ${PORT_COUNT})
|
||||
set(${PORT_COUNT} 1)
|
||||
endif()
|
||||
|
||||
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()
|
||||
SET(PORT_INDEX 0)
|
||||
while(PORT_INDEX LESS ${${PORT_COUNT}})
|
||||
list(APPEND ${PORT_DEFINITIONS} "TEST_PORT_${PORT_INDEX}=${NEXT_TEST_PORT}")
|
||||
math(EXPR PORT_INDEX "${PORT_INDEX} + 1")
|
||||
math(EXPR NEXT_TEST_PORT "${NEXT_TEST_PORT} + 1")
|
||||
endwhile()
|
||||
set(NEXT_TEST_PORT ${NEXT_TEST_PORT} PARENT_SCOPE)
|
||||
endmacro()
|
||||
|
||||
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()
|
||||
function(libnetconf2_test)
|
||||
cmake_parse_arguments(TEST "" "NAME;PORT_COUNT" "WRAP_FUNCS" ${ARGN})
|
||||
|
||||
add_executable(${TEST_NAME} $<TARGET_OBJECTS:testobj> ${TEST_SRC} ${TEST_NAME}.c)
|
||||
target_link_libraries(${TEST_NAME} ${CMOCKA_LIBRARIES} ${LIBYANG_LIBRARIES} netconf2)
|
||||
target_include_directories(${TEST_NAME} PRIVATE ${CMOCKA_INCLUDE_DIR})
|
||||
|
||||
# wrap functions
|
||||
if(TEST_WRAP_FUNCS)
|
||||
set(wrap_link_flags "-Wl")
|
||||
foreach(mock_func IN LISTS TEST_WRAP_FUNCS)
|
||||
set(wrap_link_flags "${wrap_link_flags},--wrap=${mock_func}")
|
||||
endforeach()
|
||||
set_target_properties(${TEST_NAME} PROPERTIES LINK_FLAGS "${wrap_link_flags}")
|
||||
endif()
|
||||
|
||||
# create a test, generate port numbers and set them as env vars for the test
|
||||
add_test(NAME ${TEST_NAME} COMMAND $<TARGET_FILE:${TEST_NAME}>)
|
||||
get_test_ports(TEST_PORT_COUNT TEST_PORT_DEFINITIONS)
|
||||
set_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT "${TEST_PORT_DEFINITIONS}")
|
||||
|
||||
# do the same for valgrind tests
|
||||
if(ENABLE_VALGRIND_TESTS)
|
||||
add_test(${TEST_NAME}_valgrind valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1
|
||||
--suppressions=${PROJECT_SOURCE_DIR}/tests/library_valgrind.supp ${CMAKE_BINARY_DIR}/tests/${TEST_NAME})
|
||||
get_test_ports(TEST_PORT_COUNT VALGRIND_TEST_PORT_DEFINITIONS)
|
||||
set_tests_properties(${TEST_NAME}_valgrind PROPERTIES ENVIRONMENT "${VALGRIND_TEST_PORT_DEFINITIONS}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# all the tests that don't require SSH and TLS
|
||||
libnetconf2_test(NAME test_client_messages)
|
||||
libnetconf2_test(NAME test_client_thread)
|
||||
libnetconf2_test(NAME test_fd_comm)
|
||||
libnetconf2_test(NAME test_io)
|
||||
libnetconf2_test(NAME test_thread_messages)
|
||||
libnetconf2_test(NAME test_unix_socket)
|
||||
|
||||
# tests depending on SSH/TLS
|
||||
if(ENABLE_SSH_TLS)
|
||||
libnetconf2_test(NAME test_auth_ssh)
|
||||
libnetconf2_test(NAME test_authkeys)
|
||||
libnetconf2_test(NAME test_cert_exp_notif)
|
||||
libnetconf2_test(NAME test_ch PORT_COUNT 2)
|
||||
libnetconf2_test(NAME test_client_monitoring)
|
||||
libnetconf2_test(NAME test_endpt_share_clients PORT_COUNT 4)
|
||||
libnetconf2_test(NAME test_ks_ts)
|
||||
if (LIBPAM_HAVE_CONFDIR)
|
||||
libnetconf2_test(NAME test_pam WRAP_FUNCS pam_start)
|
||||
endif()
|
||||
libnetconf2_test(NAME test_replace)
|
||||
libnetconf2_test(NAME test_runtime_changes PORT_COUNT 2)
|
||||
libnetconf2_test(NAME test_tls)
|
||||
libnetconf2_test(NAME test_two_channels)
|
||||
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)
|
||||
|
||||
# compile PAM test module
|
||||
add_library(pam_netconf SHARED ${CMAKE_SOURCE_DIR}/tests/pam/pam_netconf.c)
|
||||
set_target_properties(pam_netconf PROPERTIES PREFIX "")
|
||||
target_link_libraries(pam_netconf ${LIBPAM_LIBRARIES})
|
||||
|
||||
# generate PAM configuration file
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/netconf.conf
|
||||
"#%PAM-1.4\n"
|
||||
"auth required ${CMAKE_CURRENT_BINARY_DIR}/pam_netconf.so\n"
|
||||
"account required ${CMAKE_CURRENT_BINARY_DIR}/pam_netconf.so\n"
|
||||
"password required ${CMAKE_CURRENT_BINARY_DIR}/pam_netconf.so\n"
|
||||
)
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
#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);
|
||||
}
|
|
@ -1,813 +0,0 @@
|
|||
#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);
|
||||
}
|
|
@ -1,200 +0,0 @@
|
|||
#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);
|
||||
}
|
|
@ -19,6 +19,24 @@
|
|||
#endif
|
||||
|
||||
#define TESTS_DIR "@CMAKE_SOURCE_DIR@/tests"
|
||||
#define MODULES_DIR "@CMAKE_SOURCE_DIR@/modules"
|
||||
#define BUILD_DIR "@CMAKE_BINARY_DIR@"
|
||||
|
||||
#cmakedefine HAVE_MBEDTLS
|
||||
|
||||
@SSH_MACRO@
|
||||
@TLS_MACRO@
|
||||
|
||||
|
||||
/* nc_server.h local includes (not to use the installed ones) */
|
||||
#include "netconf.h"
|
||||
#include "log.h"
|
||||
#include "messages_server.h"
|
||||
#include "server_config.h"
|
||||
#include "session_server.h"
|
||||
#include "session_server_ch.h"
|
||||
|
||||
/* nc_client.h local includes (not to use the installed ones) */
|
||||
#include "messages_client.h"
|
||||
#include "session_client.h"
|
||||
#include "session_client_ch.h"
|
||||
|
|
1
tests/data/0b527f1f.0
Symbolic link
1
tests/data/0b527f1f.0
Symbolic link
|
@ -0,0 +1 @@
|
|||
ec_serverca.pem
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue