1
0
Fork 0

Adding upstream version 2.0.24.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-18 11:18:17 +01:00
parent e508fcfeb9
commit afb0a8fea7
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
118 changed files with 45084 additions and 0 deletions

78
tests/CMakeLists.txt Normal file
View file

@ -0,0 +1,78 @@
# headers test for including compat.h
add_test(NAME headers
COMMAND ${CMAKE_SOURCE_DIR}/compat/check_includes.sh ${CMAKE_SOURCE_DIR}/src/)
# format
if (${SOURCE_FORMAT_ENABLED})
add_test(NAME format WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND make format-check)
endif()
# list of all the tests in each directory
set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages)
set(client_tests test_client test_client_messages)
# add -Wl,--wrap flags
set(test test_client_ssh)
set(${test}_mock_funcs connect ssh_connect ssh_userauth_none ssh_userauth_kbdint ssh_is_connected
ssh_channel_open_session ssh_channel_request_subsystem ssh_channel_is_close ssh_channel_write
ssh_channel_poll_timeout ssh_userauth_password nc_handshake_io nc_ctx_check_and_fill
ssh_userauth_try_publickey ssh_userauth_publickey nc_sock_listen_inet nc_sock_accept_binds nc_accept_callhome_ssh_sock)
set(${test}_wrap_link_flags "-Wl")
foreach(mock_func IN LISTS ${test}_mock_funcs)
set(${test}_wrap_link_flags "${${test}_wrap_link_flags},--wrap=${mock_func}")
endforeach()
set(test test_client_tls)
set(${test}_mock_funcs connect SSL_connect nc_send_hello_io nc_handshake_io nc_ctx_check_and_fill)
set(${test}_wrap_link_flags "-Wl")
foreach(mock_func IN LISTS ${test}_mock_funcs)
set(${test}_wrap_link_flags "${${test}_wrap_link_flags},--wrap=${mock_func}")
endforeach()
#append tests depending on SSH/TLS
if(ENABLE_SSH OR ENABLE_TLS)
list(APPEND tests test_server_thread)
if(ENABLE_SSH)
list(APPEND client_tests test_client_ssh)
endif()
if(ENABLE_TLS)
list(APPEND client_tests test_client_tls)
endif()
endif()
foreach(src IN LISTS libsrc)
list(APPEND test_srcs "../${src}")
endforeach()
add_library(testobj OBJECT ${test_srcs})
foreach(test_name IN LISTS tests)
add_executable(${test_name} $<TARGET_OBJECTS:testobj> ${test_name}.c)
target_link_libraries(${test_name} ${CMOCKA_LIBRARIES} ${LIBYANG_LIBRARIES} netconf2)
target_include_directories(${test_name} PRIVATE ${CMOCKA_INCLUDE_DIR})
set_target_properties(${test_name} PROPERTIES LINK_FLAGS "${${test_name}_wrap_link_flags}")
add_test(NAME ${test_name} COMMAND $<TARGET_FILE:${test_name}>)
endforeach()
foreach(test_name IN LISTS client_tests)
add_executable(${test_name} $<TARGET_OBJECTS:testobj> ./client/${test_name}.c)
target_link_libraries(${test_name} ${CMOCKA_LIBRARIES} ${LIBYANG_LIBRARIES} netconf2)
target_include_directories(${test_name} PRIVATE ${CMOCKA_INCLUDE_DIR})
set_target_properties(${test_name} PROPERTIES LINK_FLAGS "${${test_name}_wrap_link_flags}")
add_test(NAME ${test_name} COMMAND $<TARGET_FILE:${test_name}>)
endforeach()
if(ENABLE_VALGRIND_TESTS)
foreach(test_name IN LISTS tests)
add_test(${test_name}_valgrind valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1
--suppressions=${PROJECT_SOURCE_DIR}/tests/ld.supp ${CMAKE_BINARY_DIR}/tests/${test_name})
endforeach()
foreach(test_name IN LISTS client_tests)
add_test(${test_name}_valgrind valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1
--suppressions=${PROJECT_SOURCE_DIR}/tests/ld.supp ${CMAKE_BINARY_DIR}/tests/${test_name})
endforeach()
endif()
include_directories(${CMAKE_SOURCE_DIR}/src ${PROJECT_BINARY_DIR})
configure_file("${PROJECT_SOURCE_DIR}/tests/config.h.in" "${PROJECT_BINARY_DIR}/tests/config.h" ESCAPE_QUOTES @ONLY)

125
tests/client/test_client.c Normal file
View file

@ -0,0 +1,125 @@
#include <errno.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <cmocka.h>
#include <libyang/libyang.h>
#include <log.h>
#include <session_client.h>
#include "tests/config.h"
static int
setup_f(void **state)
{
(void)state;
nc_verbosity(NC_VERB_VERBOSE);
return 0;
}
static int
teardown_f(void **state)
{
(void)state;
return 0;
}
static void
test_nc_client_setting_schema_searchpath(void **state)
{
(void)state;
const char *path;
int ret;
/* initiate client */
nc_client_init();
path = nc_client_get_schema_searchpath();
assert_null(path);
ret = nc_client_set_schema_searchpath("path");
assert_int_equal(ret, 0);
path = nc_client_get_schema_searchpath();
assert_string_equal(path, "path");
ret = nc_client_set_schema_searchpath("path1");
assert_int_equal(ret, 0);
path = nc_client_get_schema_searchpath();
assert_string_equal(path, "path1");
}
LY_ERR
test_clb(const char *mod_name, const char *mod_rev, const char *submod_name, const char *sub_rev, void *user_data,
LYS_INFORMAT *format, const char **model_data, void (**free_module_data)(void *model_data, void *user_data))
{
(void)mod_name;
(void)mod_rev;
(void)submod_name;
(void)sub_rev;
(void)user_data;
(void)format;
(void)model_data;
(void)free_module_data;
return LY_SUCCESS;
}
LY_ERR
test_clb1(const char *mod_name, const char *mod_rev, const char *submod_name, const char *sub_rev, void *user_data,
LYS_INFORMAT *format, const char **model_data, void (**free_module_data)(void *model_data, void *user_data))
{
(void)mod_name;
(void)mod_rev;
(void)submod_name;
(void)sub_rev;
(void)user_data;
(void)format;
(void)model_data;
(void)free_module_data;
return LY_SUCCESS;
}
static void
test_nc_client_setting_schema_callback(void **state)
{
(void)state;
ly_module_imp_clb ret_f;
char *data_ret;
int ret;
ret_f = nc_client_get_schema_callback((void **)&data_ret);
assert_null(ret_f);
assert_null(data_ret);
ret = nc_client_set_schema_callback(test_clb, "DATA");
assert_int_equal(ret, 0);
ret_f = nc_client_get_schema_callback((void **)&data_ret);
assert_ptr_equal(test_clb, ret_f);
assert_string_equal("DATA", data_ret);
ret = nc_client_set_schema_callback(test_clb1, "DATA1");
assert_int_equal(ret, 0);
ret_f = nc_client_get_schema_callback((void **)&data_ret);
assert_ptr_equal(test_clb1, ret_f);
assert_string_equal("DATA1", data_ret);
/* destroy client */
nc_client_destroy();
}
int
main(void)
{
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(test_nc_client_setting_schema_searchpath, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_client_setting_schema_callback, setup_f, teardown_f),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,709 @@
#include <errno.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <cmocka.h>
#include <config.h>
#include <libyang/libyang.h>
#include <log.h>
#include <messages_p.h>
#include <session_client.h>
#include "tests/config.h"
static int
setup_f(void **state)
{
(void)state;
nc_verbosity(NC_VERB_VERBOSE);
return 0;
}
static int
teardown_f(void **state)
{
(void)state;
return 0;
}
static void
test_nc_rpc_act_generic_xml(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
struct nc_rpc_act_generic *generic_rpc = NULL;
/* create generic rpc with NC_PARAMTYPE_CONST */
rpc = nc_rpc_act_generic_xml("xml", NC_PARAMTYPE_CONST);
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_ACT_GENERIC);
generic_rpc = (struct nc_rpc_act_generic *)rpc;
assert_int_equal(generic_rpc->type, NC_RPC_ACT_GENERIC);
assert_int_equal(generic_rpc->has_data, 0);
assert_string_equal(generic_rpc->content.xml_str, "xml");
nc_rpc_free(rpc);
/* create generic rpc with NC_PARAMTYPE_FREE */
char *str = strdup("str");
rpc = nc_rpc_act_generic_xml(str, NC_PARAMTYPE_FREE);
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_ACT_GENERIC);
generic_rpc = (struct nc_rpc_act_generic *)rpc;
assert_int_equal(generic_rpc->type, NC_RPC_ACT_GENERIC);
assert_int_equal(generic_rpc->has_data, 0);
assert_string_equal(generic_rpc->content.xml_str, str);
nc_rpc_free(rpc);
/* create generic rpc with NC_PARAMTYPE_DUP_AND_FREE */
rpc = nc_rpc_act_generic_xml("xml", NC_PARAMTYPE_DUP_AND_FREE);
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_ACT_GENERIC);
generic_rpc = (struct nc_rpc_act_generic *)rpc;
assert_int_equal(generic_rpc->type, NC_RPC_ACT_GENERIC);
assert_int_equal(generic_rpc->has_data, 0);
assert_string_equal(generic_rpc->content.xml_str, "xml");
nc_rpc_free(rpc);
}
static void
test_nc_rpc_act_generic(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
struct nc_rpc_act_generic *generic_rpc = NULL;
struct lyd_node node;
node.next = NULL;
node.prev = &node;
rpc = nc_rpc_act_generic(&node, NC_PARAMTYPE_CONST);
assert_non_null(rpc);
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_ACT_GENERIC);
generic_rpc = (struct nc_rpc_act_generic *)rpc;
assert_int_equal(generic_rpc->type, NC_RPC_ACT_GENERIC);
assert_int_equal(generic_rpc->has_data, 1);
assert_ptr_equal(generic_rpc->content.data, &node);
nc_rpc_free(rpc);
}
/* function to check if values of getconfig rpc are set correctly */
void
check_getconfig(struct nc_rpc *rpc, enum NC_DATASTORE_TYPE source, char *filter, NC_WD_MODE wd_mode)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_GETCONFIG);
struct nc_rpc_getconfig *getconfig_rpc = (struct nc_rpc_getconfig *)rpc;
assert_int_equal(getconfig_rpc->type, NC_RPC_GETCONFIG);
assert_int_equal(getconfig_rpc->source, source);
assert_string_equal(getconfig_rpc->filter, filter);
assert_int_equal(getconfig_rpc->wd_mode, wd_mode);
}
static void
test_nc_rpc_getconfig(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
/* create getconfig rpc with NC_PARAMTYPE_CONST */
rpc = nc_rpc_getconfig(NC_DATASTORE_CANDIDATE, "filter-string", NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
assert_non_null(rpc);
check_getconfig(rpc, NC_DATASTORE_CANDIDATE, "filter-string", NC_WD_UNKNOWN);
nc_rpc_free(rpc);
/* create getconfig rpc with NC_PARAMTYPE_FREE */
char *filter = strdup("string");
rpc = nc_rpc_getconfig(NC_DATASTORE_CONFIG, filter, NC_WD_EXPLICIT, NC_PARAMTYPE_FREE);
assert_non_null(rpc);
check_getconfig(rpc, NC_DATASTORE_CONFIG, filter, NC_WD_EXPLICIT);
nc_rpc_free(rpc);
/* create getconfig rpc with NC_PARAMTYPE_DUP_AND_FREE */
rpc = nc_rpc_getconfig(NC_DATASTORE_RUNNING, "filter", NC_WD_ALL, NC_PARAMTYPE_DUP_AND_FREE);
assert_non_null(rpc);
check_getconfig(rpc, NC_DATASTORE_RUNNING, "filter", NC_WD_ALL);
nc_rpc_free(rpc);
}
/* function to check if values of edit rpc are set correctly */
void
check_edit(struct nc_rpc *rpc, NC_DATASTORE target, NC_RPC_EDIT_DFLTOP default_op, NC_RPC_EDIT_TESTOPT test_opt,
NC_RPC_EDIT_ERROPT error_opt, const char *edit_content)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_EDIT);
struct nc_rpc_edit *edit_rpc = (struct nc_rpc_edit *)rpc;
assert_int_equal(edit_rpc->type, NC_RPC_EDIT);
assert_int_equal(edit_rpc->target, target);
assert_int_equal(edit_rpc->default_op, default_op);
assert_int_equal(edit_rpc->test_opt, test_opt);
assert_int_equal(edit_rpc->error_opt, error_opt);
assert_string_equal(edit_rpc->edit_cont, edit_content);
}
static void
test_nc_rpc_edit(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
/* create edit rpc with NC_PARAMTYPE_CONST */
rpc = nc_rpc_edit(NC_DATASTORE_RUNNING, NC_RPC_EDIT_DFLTOP_REPLACE, NC_RPC_EDIT_TESTOPT_TESTSET,
NC_RPC_EDIT_ERROPT_STOP, "url", NC_PARAMTYPE_CONST);
assert_non_null(rpc);
check_edit(rpc, NC_DATASTORE_RUNNING, NC_RPC_EDIT_DFLTOP_REPLACE,
NC_RPC_EDIT_TESTOPT_TESTSET, NC_RPC_EDIT_ERROPT_STOP, "url");
nc_rpc_free(rpc);
/* create edit rpc with NC_PARAMTYPE_FREE */
char *str = strdup("string");
rpc = nc_rpc_edit(NC_DATASTORE_CANDIDATE, NC_RPC_EDIT_DFLTOP_MERGE, NC_RPC_EDIT_TESTOPT_SET,
NC_RPC_EDIT_ERROPT_ROLLBACK, str, NC_PARAMTYPE_FREE);
assert_non_null(rpc);
check_edit(rpc, NC_DATASTORE_CANDIDATE, NC_RPC_EDIT_DFLTOP_MERGE,
NC_RPC_EDIT_TESTOPT_SET, NC_RPC_EDIT_ERROPT_ROLLBACK, str);
nc_rpc_free(rpc);
/* create edit rpc with NC_PARAMTYPE_DUP_AND_FREE */
rpc = nc_rpc_edit(NC_DATASTORE_CONFIG, NC_RPC_EDIT_DFLTOP_NONE, NC_RPC_EDIT_TESTOPT_TEST,
NC_RPC_EDIT_ERROPT_CONTINUE, "url1", NC_PARAMTYPE_DUP_AND_FREE);
assert_non_null(rpc);
check_edit(rpc, NC_DATASTORE_CONFIG, NC_RPC_EDIT_DFLTOP_NONE,
NC_RPC_EDIT_TESTOPT_TEST, NC_RPC_EDIT_ERROPT_CONTINUE, "url1");
nc_rpc_free(rpc);
}
/* function to check if values of copy rpc are set correctly */
void
check_copy(struct nc_rpc *rpc, NC_DATASTORE target, const char *url_trg, NC_DATASTORE source,
const char *url_or_config_src, NC_WD_MODE wd_mode)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_COPY);
struct nc_rpc_copy *copy_rpc = (struct nc_rpc_copy *)rpc;
assert_int_equal(copy_rpc->type, NC_RPC_COPY);
assert_int_equal(copy_rpc->target, target);
assert_string_equal(copy_rpc->url_trg, url_trg);
assert_int_equal(copy_rpc->source, source);
assert_string_equal(copy_rpc->url_config_src, url_or_config_src);
assert_int_equal(copy_rpc->wd_mode, wd_mode);
}
static void
test_nc_rpc_copy(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
/* create copy rpc with NC_PARAMTYPE_CONST */
rpc = nc_rpc_copy(NC_DATASTORE_RUNNING, "target-url", NC_DATASTORE_RUNNING, "src-url",
NC_WD_ALL, NC_PARAMTYPE_CONST);
assert_non_null(rpc);
check_copy(rpc, NC_DATASTORE_RUNNING, "target-url", NC_DATASTORE_RUNNING, "src-url", NC_WD_ALL);
nc_rpc_free(rpc);
/* create copy rpc with NC_PARAMTYPE_FREE */
char *target = strdup("target");
char *src = strdup("src");
rpc = nc_rpc_copy(NC_DATASTORE_STARTUP, target, NC_DATASTORE_RUNNING, src,
NC_WD_ALL_TAG, NC_PARAMTYPE_FREE);
assert_non_null(rpc);
check_copy(rpc, NC_DATASTORE_STARTUP, target, NC_DATASTORE_RUNNING, src, NC_WD_ALL_TAG);
nc_rpc_free(rpc);
/* create copy rpc with NC_PARAMTYPE_DUP_AND_FREE */
rpc = nc_rpc_copy(NC_DATASTORE_STARTUP, "url", NC_DATASTORE_CANDIDATE, "url",
NC_WD_TRIM, NC_PARAMTYPE_DUP_AND_FREE);
assert_non_null(rpc);
check_copy(rpc, NC_DATASTORE_STARTUP, "url", NC_DATASTORE_CANDIDATE, "url", NC_WD_TRIM);
nc_rpc_free(rpc);
}
/* function to check if values of delete rpc are set correctly */
void
check_delete(struct nc_rpc *rpc, NC_DATASTORE target, const char *url)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_DELETE);
struct nc_rpc_delete *delete_rpc = (struct nc_rpc_delete *)rpc;
assert_int_equal(delete_rpc->type, NC_RPC_DELETE);
assert_int_equal(delete_rpc->target, target);
assert_string_equal(delete_rpc->url, url);
}
static void
test_nc_rpc_delete(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
/* create delete rpc with NC_PARAMTYPE_CONST */
rpc = nc_rpc_delete(NC_DATASTORE_RUNNING, "target-url", NC_PARAMTYPE_CONST);
assert_non_null(rpc);
check_delete(rpc, NC_DATASTORE_RUNNING, "target-url");
nc_rpc_free(rpc);
/* create delete rpc with NC_PARAMTYPE_FREE */
char *url = strdup("url");
rpc = nc_rpc_delete(NC_DATASTORE_CANDIDATE, url, NC_PARAMTYPE_FREE);
assert_non_null(rpc);
check_delete(rpc, NC_DATASTORE_CANDIDATE, url);
nc_rpc_free(rpc);
/* create delete rpc with NC_PARAMTYPE_DUP_AND_FREE */
rpc = nc_rpc_delete(NC_DATASTORE_CONFIG, "target", NC_PARAMTYPE_DUP_AND_FREE);
assert_non_null(rpc);
check_delete(rpc, NC_DATASTORE_CONFIG, "target");
nc_rpc_free(rpc);
}
static void
test_nc_rpc_lock(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
struct nc_rpc_lock *lock_rpc = NULL;
rpc = nc_rpc_lock(NC_DATASTORE_RUNNING);
assert_non_null(rpc);
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_LOCK);
lock_rpc = (struct nc_rpc_lock *)rpc;
assert_int_equal(lock_rpc->type, NC_RPC_LOCK);
assert_int_equal(lock_rpc->target, NC_DATASTORE_RUNNING);
nc_rpc_free(rpc);
}
static void
test_nc_rpc_unlock(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
struct nc_rpc_lock *unlock_rpc = NULL;
rpc = nc_rpc_unlock(NC_DATASTORE_RUNNING);
assert_non_null(rpc);
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_UNLOCK);
unlock_rpc = (struct nc_rpc_lock *)rpc;
assert_int_equal(unlock_rpc->type, NC_RPC_UNLOCK);
assert_int_equal(unlock_rpc->target, NC_DATASTORE_RUNNING);
nc_rpc_free(rpc);
}
/* function to check if values of get rpc are set correctly */
void
check_get_rpc(struct nc_rpc *rpc, const char *filter, NC_WD_MODE wd_mode)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_GET);
struct nc_rpc_get *get_rpc = (struct nc_rpc_get *)rpc;
assert_int_equal(get_rpc->type, NC_RPC_GET);
assert_string_equal(get_rpc->filter, filter);
assert_int_equal(get_rpc->wd_mode, wd_mode);
}
static void
test_nc_rpc_get(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
/* create get rpc with NC_PARAMTYPE_CONST */
rpc = nc_rpc_get("filter", NC_WD_ALL, NC_PARAMTYPE_CONST);
assert_non_null(rpc);
check_get_rpc(rpc, "filter", NC_WD_ALL);
nc_rpc_free(rpc);
/* create get rpc with NC_PARAMTYPE_FREE */
char *str = strdup("string");
rpc = nc_rpc_get(str, NC_WD_EXPLICIT, NC_PARAMTYPE_FREE);
assert_non_null(rpc);
check_get_rpc(rpc, str, NC_WD_EXPLICIT);
nc_rpc_free(rpc);
/* create get rpc with NC_PARAMTYPE_DUP_AND_FREE */
rpc = nc_rpc_get("filter-string", NC_WD_UNKNOWN, NC_PARAMTYPE_DUP_AND_FREE);
assert_non_null(rpc);
check_get_rpc(rpc, "filter-string", NC_WD_UNKNOWN);
nc_rpc_free(rpc);
}
static void
test_nc_rpc_kill(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
struct nc_rpc_kill *kill_rpc = NULL;
rpc = nc_rpc_kill(10);
assert_non_null(rpc);
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_KILL);
kill_rpc = (struct nc_rpc_kill *)rpc;
assert_int_equal(kill_rpc->type, NC_RPC_KILL);
assert_int_equal(kill_rpc->sid, 10);
nc_rpc_free(rpc);
}
/* function to check if values of commit rpc are set correctly */
void
check_commit_rpc(struct nc_rpc *rpc, int confirmed, uint32_t confirm_timeout, const char *persist, const char *persist_id)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_COMMIT);
struct nc_rpc_commit *commit_rpc = (struct nc_rpc_commit *)rpc;
assert_int_equal(commit_rpc->type, NC_RPC_COMMIT);
assert_int_equal(commit_rpc->confirmed, confirmed);
assert_int_equal(commit_rpc->confirm_timeout, confirm_timeout);
assert_string_equal(commit_rpc->persist, persist);
assert_string_equal(commit_rpc->persist_id, persist_id);
}
static void
test_nc_rpc_commit(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
/* create commit rpc with NC_PARAMTYPE_CONST*/
rpc = nc_rpc_commit(1, 100, "persist", "persist-id", NC_PARAMTYPE_CONST);
assert_non_null(rpc);
check_commit_rpc(rpc, 1, 100, "persist", "persist-id");
nc_rpc_free(rpc);
/* create commit rpc with NC_PARAMTYPE_FREE*/
char *str1 = strdup("str1");
char *str2 = strdup("str2");
rpc = nc_rpc_commit(2, 5, str1, str2, NC_PARAMTYPE_FREE);
assert_non_null(rpc);
check_commit_rpc(rpc, 2, 5, str1, str2);
nc_rpc_free(rpc);
/* create commit rpc with NC_PARAMTYPE_DUP_AND_FREE*/
rpc = nc_rpc_commit(10, 200, "persistent", "persistent-id", NC_PARAMTYPE_DUP_AND_FREE);
assert_non_null(rpc);
check_commit_rpc(rpc, 10, 200, "persistent", "persistent-id");
nc_rpc_free(rpc);
}
static void
test_nc_rpc_discard(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
rpc = nc_rpc_discard();
assert_non_null(rpc);
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_DISCARD);
nc_rpc_free(rpc);
}
/* function to check if values of cancel rpc are set correctly */
void
check_cancel_rpc(struct nc_rpc *rpc, const char *persist_id)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_CANCEL);
struct nc_rpc_cancel *cancel_rpc = (struct nc_rpc_cancel *)rpc;
assert_int_equal(cancel_rpc->type, NC_RPC_CANCEL);
assert_string_equal(cancel_rpc->persist_id, persist_id);
}
static void
test_nc_rpc_cancel(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
/* create cancel rpc with NC_PARAMTYPE_CONST*/
rpc = nc_rpc_cancel("persist-id", NC_PARAMTYPE_CONST);
assert_non_null(rpc);
check_cancel_rpc(rpc, "persist-id");
nc_rpc_free(rpc);
/* create cancel rpc with NC_PARAMTYPE_FREE*/
char *str = strdup("string");
rpc = nc_rpc_cancel(str, NC_PARAMTYPE_FREE);
assert_non_null(rpc);
check_cancel_rpc(rpc, str);
nc_rpc_free(rpc);
/* create cancel rpc with NC_PARAMTYPE_DUP_AND_FREE*/
rpc = nc_rpc_cancel("id", NC_PARAMTYPE_DUP_AND_FREE);
assert_non_null(rpc);
check_cancel_rpc(rpc, "id");
nc_rpc_free(rpc);
}
/* function to check if values of validate rpc are set correctly */
void
check_validate_rpc(struct nc_rpc *rpc, NC_DATASTORE source, const char *url_or_config)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_VALIDATE);
struct nc_rpc_validate *validate_rpc = (struct nc_rpc_validate *)rpc;
assert_int_equal(validate_rpc->type, NC_RPC_VALIDATE);
assert_int_equal(validate_rpc->source, source);
assert_string_equal(validate_rpc->url_config_src, url_or_config);
}
static void
test_nc_rpc_validate(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
/* create validate rpc with NC_PARAMTYPE_CONST */
rpc = nc_rpc_validate(NC_DATASTORE_RUNNING, "url", NC_PARAMTYPE_CONST);
assert_non_null(rpc);
check_validate_rpc(rpc, NC_DATASTORE_RUNNING, "url");
nc_rpc_free(rpc);
/* create validate rpc with NC_PARAMTYPE_FREE */
char *str = strdup("string");
rpc = nc_rpc_validate(NC_DATASTORE_CANDIDATE, str, NC_PARAMTYPE_FREE);
assert_non_null(rpc);
check_validate_rpc(rpc, NC_DATASTORE_CANDIDATE, str);
nc_rpc_free(rpc);
/* create validate rpc with NC_PARAMTYPE_DUP_AND_FREE */
rpc = nc_rpc_validate(NC_DATASTORE_CONFIG, "url1", NC_PARAMTYPE_DUP_AND_FREE);
assert_non_null(rpc);
check_validate_rpc(rpc, NC_DATASTORE_CONFIG, "url1");
nc_rpc_free(rpc);
}
/* function to check if values of getschema rpc are set correctly */
void
check_getschema_rpc(struct nc_rpc *rpc, const char *identifier, const char *version, const char *format)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_GETSCHEMA);
struct nc_rpc_getschema *getchema_rpc = (struct nc_rpc_getschema *)rpc;
assert_int_equal(getchema_rpc->type, NC_RPC_GETSCHEMA);
assert_string_equal(getchema_rpc->identifier, identifier);
assert_string_equal(getchema_rpc->version, version);
assert_string_equal(getchema_rpc->format, format);
}
static void
test_nc_rpc_getschema(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
/* create getchema with NC_PARAMTYPE_CONST*/
rpc = nc_rpc_getschema("id", "version", "format", NC_PARAMTYPE_CONST);
assert_non_null(rpc);
check_getschema_rpc(rpc, "id", "version", "format");
nc_rpc_free(rpc);
/* create getchema with NC_PARAMTYPE_FREE*/
char *str1 = strdup("str1");
char *str2 = strdup("str2");
char *str3 = strdup("str3");
rpc = nc_rpc_getschema(str1, str2, str3, NC_PARAMTYPE_FREE);
assert_non_null(rpc);
check_getschema_rpc(rpc, str1, str2, str3);
nc_rpc_free(rpc);
/* create getchema with NC_PARAMTYPE_DUP_AND_FREE*/
rpc = nc_rpc_getschema("id1", "version1", "format1", NC_PARAMTYPE_DUP_AND_FREE);
assert_non_null(rpc);
check_getschema_rpc(rpc, "id1", "version1", "format1");
nc_rpc_free(rpc);
}
/* function to check if values of subscribe rpc are set correctly */
void
check_subscribe_rpc(struct nc_rpc *rpc, const char *stream_name, const char *filter,
const char *start_time, const char *stop_time)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_SUBSCRIBE);
struct nc_rpc_subscribe *subscribe_rpc = (struct nc_rpc_subscribe *)rpc;
assert_int_equal(subscribe_rpc->type, NC_RPC_SUBSCRIBE);
assert_string_equal(subscribe_rpc->stream, stream_name);
assert_string_equal(subscribe_rpc->filter, filter);
assert_string_equal(subscribe_rpc->start, start_time);
assert_string_equal(subscribe_rpc->stop, stop_time);
}
static void
test_nc_rpc_subscribe(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
/* create subscribe rpc with NC_PARAMTYPE_CONST*/
rpc = nc_rpc_subscribe("stream-name", "filter", "start-time", "stop-time", NC_PARAMTYPE_CONST);
assert_non_null(rpc);
check_subscribe_rpc(rpc, "stream-name", "filter", "start-time", "stop-time");
nc_rpc_free(rpc);
/* create subscribe rpc with NC_PARAMTYPE_FREE*/
char *str1 = strdup("str1");
char *str2 = strdup("str2");
char *str3 = strdup("str3");
char *str4 = strdup("str4");
rpc = nc_rpc_subscribe(str1, str2, str3, str4, NC_PARAMTYPE_FREE);
assert_non_null(rpc);
check_subscribe_rpc(rpc, str1, str2, str3, str4);
nc_rpc_free(rpc);
/* create subscribe rpc with NC_PARAMTYPE_DUP_AND_FREE*/
rpc = nc_rpc_subscribe("name", "filter-str", "start", "stop", NC_PARAMTYPE_DUP_AND_FREE);
assert_non_null(rpc);
check_subscribe_rpc(rpc, "name", "filter-str", "start", "stop");
nc_rpc_free(rpc);
}
/* function to check if values of getdata rpc are set correctly */
void
check_getdata(struct nc_rpc *rpc, char *datastore, const char *filter, const char *config_filter,
char **origin_filter, int origin_filter_count, int negated_origin_filter, uint16_t max_depth,
int with_origin, NC_WD_MODE wd_mode)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_GETDATA);
struct nc_rpc_getdata *rpc_getdata = (struct nc_rpc_getdata *)rpc;
assert_int_equal(rpc_getdata->type, NC_RPC_GETDATA);
assert_string_equal(rpc_getdata->datastore, datastore);
assert_string_equal(rpc_getdata->filter, filter);
assert_string_equal(rpc_getdata->config_filter, config_filter);
assert_string_equal(*rpc_getdata->origin_filter, *origin_filter);
assert_int_equal(rpc_getdata->origin_filter_count, origin_filter_count);
assert_int_equal(rpc_getdata->negated_origin_filter, negated_origin_filter);
assert_int_equal(rpc_getdata->max_depth, max_depth);
assert_int_equal(rpc_getdata->with_origin, with_origin);
assert_int_equal(rpc_getdata->wd_mode, wd_mode);
}
static void
test_nc_rpc_getdata(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
/* create getdata rpc with NC_PARAMTYPE_CONST */
char *origin_filters = "origin_filter";
rpc = nc_rpc_getdata("candidate", "filter", "true", &origin_filters, 1, 1, 3, 1, NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
assert_non_null(rpc);
check_getdata(rpc, "candidate", "filter", "true", &origin_filters, 1, 1, 3, 1, NC_WD_UNKNOWN);
nc_rpc_free(rpc);
/* create getdata rpc with NC_PARAMTYPE_FREE */
char *datastore = strdup("running");
char *filter = strdup("filter");
char *config_filter = strdup("true");
char buf[20] = {0};
char **origin_filter;
int origin_filter_count = 2;
origin_filter = calloc(origin_filter_count, sizeof *origin_filter);
assert_non_null(origin_filter);
for (int i = 0; i < origin_filter_count; i++) {
snprintf(buf, sizeof(buf) - 1, "origin_filter%d", i + 1);
origin_filter[i] = strdup(buf);
}
rpc = nc_rpc_getdata(datastore, filter, config_filter, origin_filter, origin_filter_count, 2, 3, 1, NC_WD_EXPLICIT, NC_PARAMTYPE_FREE);
assert_non_null(rpc);
check_getdata(rpc, datastore, filter, config_filter, origin_filter, origin_filter_count, 2, 3, 1, NC_WD_EXPLICIT);
nc_rpc_free(rpc);
/* create getdata rpc with NC_PARAMTYPE_DUP_AND_FREE */
char *origin_filter1 = "origin_filter1";
rpc = nc_rpc_getdata("startup", "filter1", "false", &origin_filter1, 1, 0, 3, 1, NC_WD_ALL, NC_PARAMTYPE_DUP_AND_FREE);
assert_non_null(rpc);
check_getdata(rpc, "startup", "filter1", "false", &origin_filter1, 1, 0, 3, 1, NC_WD_ALL);
nc_rpc_free(rpc);
}
/* function to check if values of editdata rpc are set correctly */
void
check_editdata(struct nc_rpc *rpc, char *datastore, NC_RPC_EDIT_DFLTOP default_op, const char *edit_content)
{
assert_int_equal(nc_rpc_get_type(rpc), NC_RPC_EDITDATA);
struct nc_rpc_editdata *rpc_editdata = (struct nc_rpc_editdata *)rpc;
assert_int_equal(rpc_editdata->type, NC_RPC_EDITDATA);
assert_string_equal(rpc_editdata->datastore, datastore);
assert_int_equal(rpc_editdata->default_op, default_op);
assert_string_equal(rpc_editdata->edit_cont, edit_content);
}
static void
test_nc_rpc_editdata(void **state)
{
(void)state;
struct nc_rpc *rpc = NULL;
/* create editdata rpc with NC_PARAMTYPE_CONST */
rpc = nc_rpc_editdata("candidate", NC_RPC_EDIT_DFLTOP_UNKNOWN, "edit", NC_PARAMTYPE_CONST);
assert_non_null(rpc);
check_editdata(rpc, "candidate", NC_RPC_EDIT_DFLTOP_UNKNOWN, "edit");
nc_rpc_free(rpc);
/* create editdata rpc with NC_PARAMTYPE_FREE */
char *datastore = strdup("running");
char *edit_cont = strdup("edit_data");
rpc = nc_rpc_editdata(datastore, NC_RPC_EDIT_DFLTOP_MERGE, edit_cont, NC_PARAMTYPE_FREE);
assert_non_null(rpc);
check_editdata(rpc, datastore, NC_RPC_EDIT_DFLTOP_MERGE, edit_cont);
nc_rpc_free(rpc);
/* create editdata rpc with NC_PARAMTYPE_DUP_AND_FREE */
rpc = nc_rpc_editdata("startup", NC_RPC_EDIT_DFLTOP_REPLACE, "edit_cont", NC_PARAMTYPE_DUP_AND_FREE);
assert_non_null(rpc);
check_editdata(rpc, "startup", NC_RPC_EDIT_DFLTOP_REPLACE, "edit_cont");
nc_rpc_free(rpc);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(test_nc_rpc_act_generic_xml, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_act_generic, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_getconfig, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_edit, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_copy, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_delete, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_lock, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_unlock, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_get, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_kill, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_commit, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_discard, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_cancel, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_validate, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_getschema, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_subscribe, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_getdata, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_rpc_editdata, setup_f, teardown_f),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,813 @@
#include <errno.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <cmocka.h>
#include <config.h>
#include <libyang/libyang.h>
#include <log.h>
#include <session_client.h>
#include <session_client_ch.h>
#include <session_p.h>
#include "tests/config.h"
#include <libssh/callbacks.h>
#include <libssh/libssh.h>
#include <libssh/server.h>
static int
ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv)
{
(void)hostname;
(void)session;
(void)priv;
return 0;
}
static int
setup_f(void **state)
{
(void)state;
int ret;
nc_verbosity(NC_VERB_VERBOSE);
ret = nc_client_ssh_set_username("username");
assert_int_equal(ret, 0);
ret = nc_client_ssh_ch_set_username("ch_username");
assert_int_equal(ret, 0);
nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL);
return 0;
}
static int
teardown_f(void **state)
{
(void)state;
return 0;
}
MOCK int
__wrap_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
(void)sockfd;
(void)addr;
(void)addrlen;
return (int)mock();
}
MOCK int
__wrap_ssh_connect(ssh_session session)
{
(void)session;
/* set support of all authentication methods by fake server */
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_INTERACTIVE);
return (int)mock();
}
MOCK int
__wrap_ssh_userauth_none(ssh_session session, const char *username)
{
(void)session;
(void)username;
return (int)mock();
}
MOCK int
__wrap_ssh_userauth_kbdint(ssh_session session, const char *user, const char *submethods)
{
(void)session;
(void)user;
(void)submethods;
return (int)mock();
}
MOCK int
__wrap_ssh_is_connected(ssh_session session)
{
(void)session;
return (int)mock();
}
MOCK int
__wrap_ssh_channel_open_session(ssh_channel channel)
{
(void)channel;
return (int)mock();
}
MOCK int
__wrap_ssh_channel_request_subsystem(ssh_channel channel, const char *subsystem)
{
(void)channel;
(void)subsystem;
return (int)mock();
}
MOCK int
__wrap_ssh_channel_is_closed(ssh_channel channel)
{
(void)channel;
return 0;
}
MOCK int
__wrap_ssh_channel_write(ssh_channel channel, const void *data, uint32_t len)
{
(void)channel;
(void)data;
return len;
}
MOCK int
__wrap_ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr)
{
(void)channel;
(void)timeout;
(void)is_stderr;
return (int)mock();
}
MOCK int
__wrap_ssh_userauth_password(ssh_session session, const char *username, const char *password)
{
(void)session;
check_expected(password);
check_expected(username);
return (int)mock();
}
MOCK int
__wrap_nc_handshake_io(struct nc_session *session)
{
(void)session;
return (int)mock();
}
MOCK int
__wrap_nc_ctx_check_and_fill(struct nc_session *session)
{
(void)session;
return (int)mock();
}
MOCK int
__wrap_ssh_userauth_try_publickey(ssh_session session, const char *username, const ssh_key pubkey)
{
(void)session;
(void)username;
(void)pubkey;
return (int)mock();
}
MOCK int
__wrap_ssh_userauth_publickey(ssh_session session, const char *username, const ssh_key privkey)
{
(void)session;
(void)username;
(void)privkey;
return (int)mock();
}
MOCK int
__wrap_nc_sock_listen_inet(const char *address, uint16_t port, struct nc_keepalives *ka)
{
(void)address;
(void)port;
(void)ka;
return (int)mock();
}
MOCK int
__wrap_nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, char **host, uint16_t *port, uint16_t *idx)
{
(void)binds;
(void)bind_count;
(void)timeout;
(void)host;
(void)port;
*idx = 0;
return (int)mock();
}
MOCK struct nc_session *
__wrap_nc_accept_callhome_ssh_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx, int timeout)
{
(void)sock;
(void)host;
(void)port;
(void)ctx;
(void)timeout;
return mock_ptr_type(struct nc_session *);
}
static int
test_hostkey_clb(const char *hostname, ssh_session session, void *priv)
{
(void)hostname;
(void)session;
(void)priv;
return 0;
}
static void
test_nc_client_ssh_setting_auth_hostkey_check_clb(void **state)
{
(void)state;
int (*ret_f)(const char *hostname, ssh_session session, void *priv);
char *priv_data_ret;
/* ssh_hostkey_check_clb is set in setup_f */
nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret);
assert_ptr_equal(ret_f, ssh_hostkey_check_clb);
assert_null(priv_data_ret);
/* set different callback and private data */
nc_client_ssh_set_auth_hostkey_check_clb(test_hostkey_clb, "DATA");
nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret);
assert_ptr_equal(ret_f, test_hostkey_clb);
assert_string_equal(priv_data_ret, "DATA");
}
char *
test_pwd_clb1(const char *username, const char *hostname, void *priv)
{
char *pass, *pass_to_return;
check_expected(username);
check_expected(hostname);
check_expected(priv);
pass = (char *)mock();
pass_to_return = malloc(sizeof *pass * (strlen(pass) + 1));
strcpy(pass_to_return, pass);
return pass_to_return;
}
char *
test_pwd_clb2(const char *username, const char *hostname, void *priv)
{
(void)username;
(void)hostname;
(void)priv;
return 0;
}
static void
test_nc_client_ssh_setting_auth_password_clb(void **state)
{
(void)state;
char *(*ret_f)(const char *username, const char *hostname, void *priv);
char *priv_data_ret;
/* set callback */
nc_client_ssh_set_auth_password_clb(test_pwd_clb1, "DATA");
nc_client_ssh_get_auth_password_clb(&ret_f, (void **)&priv_data_ret);
assert_ptr_equal(test_pwd_clb1, ret_f);
assert_string_equal("DATA", priv_data_ret);
/* set different callback */
nc_client_ssh_set_auth_password_clb(test_pwd_clb2, "NEW DATA");
nc_client_ssh_get_auth_password_clb(&ret_f, (void **)&priv_data_ret);
assert_ptr_equal(test_pwd_clb2, ret_f);
assert_string_equal("NEW DATA", priv_data_ret);
}
char *
test_inter_clb1(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv)
{
(void)auth_name;
(void)instruction;
(void)prompt;
(void)echo;
(void)priv;
return 0;
}
char *
test_inter_clb2(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv)
{
(void)auth_name;
(void)instruction;
(void)prompt;
(void)echo;
(void)priv;
return 0;
}
static void
test_nc_client_ssh_setting_auth_interactive_clb(void **state)
{
(void)state;
char *(*ret_f)(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv);
char *priv_data_ret;
/* set callback */
nc_client_ssh_set_auth_interactive_clb(test_inter_clb1, "DATA");
nc_client_ssh_get_auth_interactive_clb(&ret_f, (void **)&priv_data_ret);
assert_ptr_equal(test_inter_clb1, ret_f);
assert_string_equal("DATA", priv_data_ret);
/* set diferent callback */
nc_client_ssh_set_auth_interactive_clb(test_inter_clb2, "NEW DATA");
nc_client_ssh_get_auth_interactive_clb(&ret_f, (void **)&priv_data_ret);
assert_ptr_equal(test_inter_clb2, ret_f);
assert_string_equal("NEW DATA", priv_data_ret);
}
char *
test_passphrase_clb1(const char *privkey_path, void *priv)
{
(void)privkey_path;
(void)priv;
return 0;
}
char *
test_passphrase_clb2(const char *privkey_path, void *priv)
{
(void)privkey_path;
(void)priv;
return 0;
}
static void
test_nc_client_ssh_setting_auth_privkey_passphrase_clb(void **state)
{
(void)state;
char *(*ret_f)(const char *privkey_path, void *priv);
char *priv_data_ret;
/* set first callback */
nc_client_ssh_set_auth_privkey_passphrase_clb(test_passphrase_clb1, "DATA");
nc_client_ssh_get_auth_privkey_passphrase_clb(&ret_f, (void **)&priv_data_ret);
assert_ptr_equal(ret_f, test_passphrase_clb1);
assert_string_equal("DATA", priv_data_ret);
/* set different callback */
nc_client_ssh_set_auth_privkey_passphrase_clb(test_passphrase_clb2, "NEW DATA");
nc_client_ssh_get_auth_privkey_passphrase_clb(&ret_f, (void **)&priv_data_ret);
assert_ptr_equal(ret_f, test_passphrase_clb2);
assert_string_equal("NEW DATA", priv_data_ret);
}
static void
test_nc_client_ssh_adding_keypair(void **state)
{
(void)state;
int ret;
const char *pubkey1, *pubkey2;
/* at the beginning keypair count should be 0 */
ret = nc_client_ssh_get_keypair_count();
assert_int_equal(ret, 0);
/* add first key pair */
ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_dsa.pub", TESTS_DIR "/data/key_dsa");
assert_int_equal(ret, 0);
ret = nc_client_ssh_get_keypair_count();
assert_int_equal(ret, 1);
/* add second keypair */
ret = nc_client_ssh_add_keypair("key_pub", "key_priv");
assert_int_equal(ret, 0);
ret = nc_client_ssh_get_keypair_count();
assert_int_equal(ret, 2);
ret = nc_client_ssh_get_keypair(1, &pubkey1, &pubkey2);
assert_int_equal(ret, 0);
assert_string_equal(pubkey1, "key_pub");
assert_string_equal(pubkey2, "key_priv");
/* delete first keypair */
ret = nc_client_ssh_del_keypair(0);
assert_int_equal(ret, 0);
ret = nc_client_ssh_get_keypair_count();
assert_int_equal(ret, 1);
/* try to get deleted keypair */
ret = nc_client_ssh_get_keypair(5, &pubkey1, &pubkey2);
assert_int_equal(ret, -1);
/* try to add keypair that is already set */
ret = nc_client_ssh_add_keypair("key_pub", "key_priv");
assert_int_equal(ret, -1);
ret = nc_client_ssh_get_keypair_count();
assert_int_equal(ret, 1);
/* try to delete keypair with id that is not used */
ret = nc_client_ssh_del_keypair(42);
assert_int_equal(ret, -1);
ret = nc_client_ssh_get_keypair_count();
assert_int_equal(ret, 1);
/* remove remaining keypairs */
ret = nc_client_ssh_del_keypair(0);
assert_int_equal(ret, 0);
ret = nc_client_ssh_get_keypair_count();
assert_int_equal(ret, 0);
}
static void
test_nc_client_ssh_setting_auth_pref(void **state)
{
(void)state;
int ret;
/* initiate client, must be called in first test */
nc_client_init();
/* check default prefference settings according to documentation */
ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_INTERACTIVE);
assert_int_equal(ret, 3);
ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PASSWORD);
assert_int_equal(ret, 2);
ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PUBLICKEY);
assert_int_equal(ret, 1);
/* try to set prefetence of non existing method */
nc_client_ssh_set_auth_pref(42, 22);
/* try to get preference of non existing method */
ret = nc_client_ssh_get_auth_pref(42);
assert_int_equal(ret, 0);
/* change values of all methods and check if they actually changed */
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 9);
ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_INTERACTIVE);
assert_int_equal(ret, 9);
/* negative value should be set as -1 */
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -5);
ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PASSWORD);
assert_int_equal(ret, -1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 11);
ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PUBLICKEY);
assert_int_equal(ret, 11);
}
static void
test_nc_client_ssh_setting_username(void **state)
{
(void)state;
int ret;
const char *username_ret;
username_ret = nc_client_ssh_get_username();
/* username is set to "username" in setup_f */
assert_string_equal(username_ret, "username");
/* set new username and check if it changes */
ret = nc_client_ssh_set_username("new_username");
assert_int_equal(ret, 0);
username_ret = nc_client_ssh_get_username();
assert_string_equal(username_ret, "new_username");
}
static void
test_nc_connect_ssh_interactive_succesfull(void **state)
{
(void)state;
struct nc_session *session;
/* set authentication method to use interactive authentication */
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 20);
/* prepare return values for functions used by nc_connect_ssh */
will_return(__wrap_connect, 0);
will_return(__wrap_ssh_connect, 0);
will_return(__wrap_ssh_userauth_none, 1);
will_return(__wrap_ssh_userauth_kbdint, 0);
will_return(__wrap_ssh_is_connected, 1);
will_return(__wrap_ssh_is_connected, 1);
will_return(__wrap_ssh_channel_open_session, 0);
will_return(__wrap_ssh_channel_request_subsystem, 0);
will_return(__wrap_nc_handshake_io, 3);
will_return(__wrap_nc_ctx_check_and_fill, 0);
session = nc_connect_ssh("127.0.0.1", 8080, NULL);
assert_non_null(session);
will_return(__wrap_ssh_channel_poll_timeout, 0);
nc_session_free(session, NULL);
}
static void
test_nc_connect_ssh_password_succesfull(void **state)
{
(void)state;
struct nc_session *session;
/* set authentication method to use password authentication */
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, 1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
/* set authentication callback */
nc_client_ssh_set_auth_password_clb(test_pwd_clb1, "private_data");
will_return(test_pwd_clb1, "secret password");
/* set values that are expected as parameters for authentication callback */
expect_string(test_pwd_clb1, username, "username");
expect_string(test_pwd_clb1, hostname, "127.0.0.1");
expect_string(test_pwd_clb1, priv, "private_data");
/* fake succesfull connection */
will_return(__wrap_connect, 0);
will_return(__wrap_ssh_connect, 0);
/* do not authenticate using no authentication method */
will_return(__wrap_ssh_userauth_none, 1);
/* succesfully authenticate via password authentication */
expect_string(__wrap_ssh_userauth_password, password, "secret password");
expect_string(__wrap_ssh_userauth_password, username, "username");
will_return(__wrap_ssh_userauth_password, 0);
/* fake ssh functions that are used to open netconf channel */
will_return(__wrap_ssh_channel_open_session, 0);
will_return(__wrap_ssh_channel_request_subsystem, 0);
/* fake that connection is still alive*/
will_return(__wrap_ssh_is_connected, 1);
/* fake ssh function for recieving hello message */
will_return(__wrap_ssh_is_connected, 1);
will_return(__wrap_nc_handshake_io, 3);
will_return(__wrap_nc_ctx_check_and_fill, 0);
session = nc_connect_ssh("127.0.0.1", 8080, NULL);
assert_non_null(session);
/* disconnect */
will_return(__wrap_ssh_channel_poll_timeout, 0);
nc_session_free(session, NULL);
}
static void
test_nc_connect_ssh_pubkey_succesfull(void **state)
{
(void)state;
struct nc_session *session;
int ret = 0;
/* set authentication method to use password authentication */
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
/* add keypair for authentication */
ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_dsa.pub", TESTS_DIR "/data/key_dsa");
assert_int_equal(ret, 0);
/* fake succesfull connection */
will_return(__wrap_connect, 0);
will_return(__wrap_ssh_connect, 0);
/* do not authenticate using no authentication method */
will_return(__wrap_ssh_userauth_none, 1);
will_return(__wrap_ssh_userauth_try_publickey, 0);
will_return(__wrap_ssh_userauth_publickey, 0);
will_return(__wrap_ssh_is_connected, 1);
will_return(__wrap_ssh_channel_open_session, 0);
will_return(__wrap_ssh_channel_request_subsystem, 0);
/* fake ssh function for recieving hello message */
will_return(__wrap_ssh_is_connected, 1);
will_return(__wrap_nc_handshake_io, 3);
will_return(__wrap_nc_ctx_check_and_fill, 0);
session = nc_connect_ssh("127.0.0.1", 8080, NULL);
assert_non_null(session);
/* disconnect */
will_return(__wrap_ssh_channel_poll_timeout, 0);
nc_session_free(session, NULL);
}
static void
test_nc_connect_connection_failed(void **state)
{
(void)state;
struct nc_session *session;
errno = ECONNREFUSED;
will_return(__wrap_connect, -1);
will_return(__wrap_ssh_is_connected, 0);
session = nc_connect_ssh("127.0.0.1", 8080, NULL);
assert_null(session);
}
static void
test_nc_connect_ssh_bad_hello(void **state)
{
(void)state;
struct nc_session *session;
/* set authentication method to use interactive authentication */
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1);
nc_client_ssh_set_auth_password_clb(test_pwd_clb2, NULL);
will_return(__wrap_connect, 0);
will_return(__wrap_ssh_connect, 0);
will_return(__wrap_ssh_userauth_none, 1);
will_return(__wrap_ssh_userauth_kbdint, 0);
will_return(__wrap_ssh_is_connected, 1);
will_return(__wrap_ssh_is_connected, 1);
will_return(__wrap_ssh_channel_open_session, 0);
will_return(__wrap_ssh_channel_request_subsystem, 0);
will_return(__wrap_nc_handshake_io, 4);
session = nc_connect_ssh("127.0.0.1", 8080, NULL);
assert_null(session);
/* destroy client, must be called in last test */
nc_client_destroy();
}
static void
test_nc_client_ssh_ch_setting_username(void **state)
{
(void)state;
const char *username_ret;
int ret;
/* username is set to "ch_username" in setup_f */
username_ret = nc_client_ssh_ch_get_username();
assert_string_equal(username_ret, "ch_username");
/* set new username and check if it changes */
ret = nc_client_ssh_ch_set_username("new_ch_username");
assert_int_equal(ret, 0);
username_ret = nc_client_ssh_ch_get_username();
assert_string_equal(username_ret, "new_ch_username");
}
static void
test_nc_client_ssh_ch_add_bind_listen(void **state)
{
(void)state;
int ret;
/* invalid parameters, address NULL or port 0 */
ret = nc_client_ssh_ch_add_bind_listen(NULL, 4334);
assert_int_equal(ret, -1);
ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 0);
assert_int_equal(ret, -1);
/* failed to create an ssh listening socket */
will_return(__wrap_nc_sock_listen_inet, -1);
ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334);
assert_int_equal(ret, -1);
/* fake a successful CH ssh listening socket */
will_return(__wrap_nc_sock_listen_inet, 1);
ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334);
assert_int_equal(ret, 0);
/* remove ssh listening client binds */
ret = nc_client_ssh_ch_del_bind("127.0.0.1", 4334);
assert_int_equal(ret, 0);
}
static void
test_nc_accept_callhome(void **state)
{
(void)state;
struct nc_session *session = NULL;
int timeout = 10;
int ret;
/* invalid parameter session */
ret = nc_accept_callhome(timeout, NULL, NULL);
assert_int_equal(ret, -1);
/* no client bind */
ret = nc_accept_callhome(timeout, NULL, &session);
assert_int_equal(ret, -1);
/* successfully add a client Call Home bind */
will_return(__wrap_nc_sock_listen_inet, 1);
ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334);
assert_int_equal(ret, 0);
/* failed to accept a client bind */
will_return(__wrap_nc_sock_accept_binds, -1);
ret = nc_accept_callhome(timeout, NULL, &session);
assert_int_equal(ret, -1);
/* failed to accept a server Call Home connection */
will_return(__wrap_nc_accept_callhome_ssh_sock, NULL);
will_return(__wrap_nc_sock_accept_binds, 2);
ret = nc_accept_callhome(timeout, NULL, &session);
assert_int_equal(ret, -1);
/* create session structure to fake a successful server call home connection */
session = nc_new_session(NC_CLIENT, 0);
assert_non_null(session);
will_return(__wrap_nc_sock_accept_binds, 2);
will_return(__wrap_nc_accept_callhome_ssh_sock, session);
ret = nc_accept_callhome(timeout, NULL, &session);
assert_int_equal(ret, 1);
/* remove ssh listening client binds */
ret = nc_client_ssh_ch_del_bind("127.0.0.1", 4334);
assert_int_equal(ret, 0);
/* free session */
nc_session_free(session, NULL);
}
static void
test_nc_client_ssh_callhome_successful(void **state)
{
(void)state;
struct nc_session *session = NULL;
int timeout = 10;
int ret;
/* create session structure */
session = nc_new_session(NC_CLIENT, 0);
assert_non_null(session);
/* prepare to fake return values for functions used by nc_accept_callhome */
will_return(__wrap_nc_sock_listen_inet, 1);
will_return(__wrap_nc_sock_accept_binds, 2);
will_return(__wrap_nc_accept_callhome_ssh_sock, session);
ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334);
assert_int_equal(ret, 0);
ret = nc_accept_callhome(timeout, NULL, &session);
assert_int_equal(ret, 1);
/* remove ssh listening client binds */
ret = nc_client_ssh_ch_del_bind("127.0.0.1", 4334);
assert_int_equal(ret, 0);
/* free session */
nc_session_free(session, NULL);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_pref, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_hostkey_check_clb, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_password_clb, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_interactive_clb, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_privkey_passphrase_clb, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_client_ssh_adding_keypair, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_username, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_connect_ssh_interactive_succesfull, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_connect_ssh_password_succesfull, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_connect_ssh_pubkey_succesfull, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_connect_connection_failed, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_connect_ssh_bad_hello, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_client_ssh_ch_setting_username, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_client_ssh_ch_add_bind_listen, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_accept_callhome, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_client_ssh_callhome_successful, setup_f, teardown_f),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -0,0 +1,200 @@
#include <errno.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <cmocka.h>
#include <config.h>
#include <libyang/libyang.h>
#include <log.h>
#include <session_client.h>
#include "tests/config.h"
static int
setup_f(void **state)
{
(void)state;
nc_verbosity(NC_VERB_VERBOSE);
return 0;
}
static int
teardown_f(void **state)
{
(void)state;
return 0;
}
MOCK int
__wrap_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
(void)sockfd;
(void)addr;
(void)addrlen;
return (int)mock();
}
MOCK int
__wrap_SSL_connect(SSL *ssl)
{
(void)ssl;
return (int)mock();
}
MOCK int
__wrap_nc_handshake_io(struct nc_session *session)
{
(void)session;
return (int)mock();
}
MOCK int
__wrap_nc_ctx_check_and_fill(struct nc_session *session)
{
(void)session;
return (int)mock();
}
static void
test_nc_client_tls_setting_cert_key_paths(void **state)
{
(void)state;
const char *cert, *key;
int ret;
nc_client_init();
/* no certificats are set, nc_client_tls_get_cert_key_paths should output NULL */
nc_client_tls_get_cert_key_paths(&cert, &key);
assert_null(cert);
assert_null(key);
/* set certificate path */
ret = nc_client_tls_set_cert_key_paths("cert_path", "key_path");
assert_int_equal(ret, 0);
nc_client_tls_get_cert_key_paths(&cert, &key);
assert_string_equal(cert, "cert_path");
assert_string_equal(key, "key_path");
/* override certificate path */
ret = nc_client_tls_set_cert_key_paths("cert_path1", "key_path1");
assert_int_equal(ret, 0);
nc_client_tls_get_cert_key_paths(&cert, &key);
assert_string_equal(cert, "cert_path1");
assert_string_equal(key, "key_path1");
}
static void
test_nc_client_tls_setting_trusted_ca_paths(void **state)
{
(void)state;
const char *file, *dir;
int ret;
ret = nc_client_tls_set_trusted_ca_paths("ca_file", "ca_dir");
assert_int_equal(ret, 0);
nc_client_tls_get_trusted_ca_paths(&file, &dir);
assert_string_equal("ca_file", file);
assert_string_equal("ca_dir", dir);
ret = nc_client_tls_set_trusted_ca_paths("ca_file1", "ca_dir1");
assert_int_equal(ret, 0);
nc_client_tls_get_trusted_ca_paths(&file, &dir);
assert_string_equal("ca_file1", file);
assert_string_equal("ca_dir1", dir);
}
static void
test_nc_connect_tls_succesfull(void **state)
{
(void)state;
int ret;
struct nc_session *session;
ret = nc_client_tls_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key");
assert_int_equal(ret, 0);
ret = nc_client_tls_set_trusted_ca_paths(NULL, TESTS_DIR "/data");
assert_int_equal(ret, 0);
will_return(__wrap_connect, 0);
will_return(__wrap_SSL_connect, 1);
/* fake succesfull handshake */
will_return(__wrap_nc_handshake_io, 3);
will_return(__wrap_nc_ctx_check_and_fill, 0);
session = nc_connect_tls("0.0.0.0", 6001, NULL);
assert_non_null(session);
nc_session_free(session, NULL);
}
static void
test_nc_client_tls_setting_crl_paths(void **state)
{
(void)state;
const char *file, *dir;
int ret;
nc_client_tls_get_crl_paths(&file, &dir);
assert_null(file);
assert_null(dir);
ret = nc_client_tls_set_crl_paths("file", "dir");
assert_int_equal(ret, 0);
nc_client_tls_get_crl_paths(&file, &dir);
assert_string_equal(file, "file");
assert_string_equal(dir, "dir");
ret = nc_client_tls_set_crl_paths("file1", "dir1");
assert_int_equal(ret, 0);
nc_client_tls_get_crl_paths(&file, &dir);
assert_string_equal(file, "file1");
assert_string_equal(dir, "dir1");
/* destroy client */
nc_client_destroy();
}
static void
test_nc_connect_tls_handshake_failed(void **state)
{
(void)state;
int ret;
struct nc_session *session;
ret = nc_client_tls_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key");
assert_int_equal(ret, 0);
ret = nc_client_tls_set_trusted_ca_paths(NULL, TESTS_DIR "/data");
assert_int_equal(ret, 0);
will_return(__wrap_connect, 0);
will_return(__wrap_SSL_connect, 1);
/* fake failed handshake */
will_return(__wrap_nc_handshake_io, 0);
session = nc_connect_tls("0.0.0.0", 6001, NULL);
assert_null(session);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(test_nc_client_tls_setting_cert_key_paths, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_connect_tls_handshake_failed, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_connect_tls_succesfull, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_client_tls_setting_trusted_ca_paths, setup_f, teardown_f),
cmocka_unit_test_setup_teardown(test_nc_client_tls_setting_crl_paths, setup_f, teardown_f),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

24
tests/config.h.in Normal file
View file

@ -0,0 +1,24 @@
/**
* @file config.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief cmocka tests configuration header.
*
* Copyright (c) 2015 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifdef __GNUC__
# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
#else
# define UNUSED(x) UNUSED_ ## x
#endif
#define TESTS_DIR "@CMAKE_SOURCE_DIR@/tests"
@SSH_MACRO@
@TLS_MACRO@

1
tests/data/042686bb.0 Symbolic link
View file

@ -0,0 +1 @@
serverca.pem

1
tests/data/5412ca73.0 Symbolic link
View file

@ -0,0 +1 @@
server.crt

1
tests/data/62436b04.0 Symbolic link
View file

@ -0,0 +1 @@
client.crt

25
tests/data/client.crt Normal file
View file

@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIEQDCCAygCCQCV65JgDvfWkDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJD
WjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwG
Q0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMB4XDTE4MTEw
NTA3MzAzOVoXDTI4MTEwMjA3MzAzOVowYTELMAkGA1UEBhMCQ1oxEzARBgNVBAgM
ClNvbWUtU3RhdGUxDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoG
A1UECwwDVE1DMQ8wDQYDVQQDDAZjbGllbnQwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQC+kqPqDL9GbWmqVQhp4qla4vYo4kFuh2HG48b7RLp/4l/guik4
Hvq2aDVFD9sBcs3FeQbjoLH1Q4doUr8jG6VwJsfovE5SD3T8dVLs2dtpW0OyXTcc
b0I9lOVDMz6f6IUBe/m5vk8XNbdUII0NJ8y1dQ51VH3e784Bzu7PSdaMaFac4fkw
8kJA9LxkWkv2FDFC7IBcVjRgtb/15EwODH849O6+VPEgX5gdozNj5bL45rKDBvvx
0KjD7dFBGAIHbSjmjp7HHadfYKqvtQnMb83fRcK6wohxNP3vy13wBTtSOlvOg16G
b+2ZB0Or7wgOw19ZvEIcNgswPwhHfZQNcYMNVLCu02BSzwdY00IEqNM0J5B/W//K
JF3uFF/ZqP7D2wO7w8j5UL2lpuxF7YrGecNT1Kr7ggHdkzcLlekkNu7wNWKAZlJ6
+Kbun8PqZbamGXLG2Ur1aZDkyKyD9nyMzsRneAlxO+HbQhLojimUbsMm+wgL89zc
hLYkL/DSmsJlryA4qhvzHaaONBw4DV5UhSbLDpZtXVfrn+MAm8hLpqf+gUCThsFN
8kDp9h9Tg9v01ai9jGb941HkFtGYUWHS5drSz3ZLnSI6i1/wKdbs9ns9YqDMqq2c
305v5h7taMN0b40KuGSIME4K4cOsdfCprFYGZQgKjaadQwrsm4k1Jl7kMwIDAQAB
MA0GCSqGSIb3DQEBCwUAA4IBAQAtwH2u1o16jkABlqEGDIvAJSMwBmZzNTNHgOXt
WDlkzWGsj+L1wc/DNjDRBkE31h4h7ASthhqi1nzzHYQ1hhPVhUUqI532AS/V7EPs
Bg3f+BI8gxqQ31TUBEQ4Ll6FtW36nqpJOe6Uui2rH2FonuUg2Av5BvDRil42Tu7f
YW4WpSU3e00HiGJ0J0t+QjoKRnnoLJJqlmzk8Y4aIlQim7Azvrlo1WEtOhI3L9UE
1GEqxLjRB45P36FSe1wfkgt7xmD0Xjy33Wh6Ae2Fvx7OfJ0K1zy0LHr4rDDJ3tLT
qjPqHIFhaa73jGXwXk8sZnbAk542Oa6C6AjzNFyqV7T5Q5lg
-----END CERTIFICATE-----

51
tests/data/client.key Normal file
View file

@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEAvpKj6gy/Rm1pqlUIaeKpWuL2KOJBbodhxuPG+0S6f+Jf4Lop
OB76tmg1RQ/bAXLNxXkG46Cx9UOHaFK/IxulcCbH6LxOUg90/HVS7NnbaVtDsl03
HG9CPZTlQzM+n+iFAXv5ub5PFzW3VCCNDSfMtXUOdVR93u/OAc7uz0nWjGhWnOH5
MPJCQPS8ZFpL9hQxQuyAXFY0YLW/9eRMDgx/OPTuvlTxIF+YHaMzY+Wy+Oaygwb7
8dCow+3RQRgCB20o5o6exx2nX2Cqr7UJzG/N30XCusKIcTT978td8AU7UjpbzoNe
hm/tmQdDq+8IDsNfWbxCHDYLMD8IR32UDXGDDVSwrtNgUs8HWNNCBKjTNCeQf1v/
yiRd7hRf2aj+w9sDu8PI+VC9pabsRe2KxnnDU9Sq+4IB3ZM3C5XpJDbu8DVigGZS
evim7p/D6mW2phlyxtlK9WmQ5Misg/Z8jM7EZ3gJcTvh20IS6I4plG7DJvsIC/Pc
3IS2JC/w0prCZa8gOKob8x2mjjQcOA1eVIUmyw6WbV1X65/jAJvIS6an/oFAk4bB
TfJA6fYfU4Pb9NWovYxm/eNR5BbRmFFh0uXa0s92S50iOotf8CnW7PZ7PWKgzKqt
nN9Ob+Ye7WjDdG+NCrhkiDBOCuHDrHXwqaxWBmUICo2mnUMK7JuJNSZe5DMCAwEA
AQKCAgA3X963LHsL2NECSHEIa28wVJCYcp32oun7Y8Y2ztKuRDX907oUb5QEGqWX
6rKFajl2buNckx4CmVuoKZsWdXsN6obeDpFncMxaazDsV6VUqMsz8bgI0B9cS36O
lz5UMrkrJD39BdpvcRFTJZ42u2DVPS01VJa6h83BYsKrgtYPuGWqclL5MPulajev
pTk7SMTDoHrv2bCghU9BANREpMb24tzYe1ARSxWlTv2owl7NyiMGxanBqxLO07Sh
CHvWcpaW38wtKWWv5iPSqHUvbTFR9jBOGiaRVoeO/PXPv4VsMD7q8+ssfyt38s9s
Dym1OHnlVjmTfvSjUT1zoH67pUchv/RUsUT8SR2zvK2Cm9xwEG+Nn2izuUZwCjxp
Pouan6ZZrCnJut0PKWbEpeEzwKWgEx3r+tYeoV+svkePKKU3oQEUgzACAA5PHRZT
GiaFBHznb57HZaw5xXCmm1g3k31wP0MEnLebEeFtFvqcc0LWQ6uN5UZtpZNM393n
w87CVIZqX0miuB7GsDsZwg8ODWy7nEsAppeoudFg81Gy0jrVluI72le2sYGU4SRe
TBjAf/9H6GF+rYWYgWFfkDeQp31Vx3gkJC6V+lSdMh6OMa8A+vk47alwQbX5kbLJ
AqtSFjOCWLDhUB650huOnk9PyhoK85D+hd9Tx924TByeegXO2QKCAQEA/QptsVKV
fUlfKN2HVntPP6+y/fnR2nSGRWP91KP1I1/PyG+FSXGxR1ngXFpn5TByD5CFBEhv
0PX8pUjbC1cgNC7WJuy2B0g4Cn4m25yiMPz7g1Ngt+JkWH3E57AeSYCqUUm41Qb0
PUA1zZDE4izvEzweTp04ZFk/1+oPQDeol0oIFhrlrxDSYRjpgDcwPWrQvRnmqfQL
C1aB9+ulHqLIzvhpsWBg4+mYsMfFGX6P+f0NxWFH2hVZoax2STcupAXiRcUbzTO9
z6Yan6DydHv0dS3XcReOFhgB1fRC4hbnJPRZxH1rJ6H0PzmN6vfKeWzZ60Uflyti
r100P+Mh2rUobwKCAQEAwM0w282zqmn71pqmCUrC153uRY1eXRtGmDkuLvpPO0N9
LPLo1AblboIdxXw4pUBzmxtO+J8L+rYzi+sorNhL0GuOHulgVSe27WMfEXeGOhay
m0qGiEEs1s2Ctgj7MdzHzW2moiMOJUgnBIQraJ9JF7KGwMoblUsFE3EeIF2sy8qk
tHugxfx/HUouCx5m8Fsh0HMkvsJMZvmJPMihsVYL57UxGTuKMPsNGpNfdyKgHo3G
0t+0yR81EPsfnhxoLbGlvgA9Bcn5I2tU9WyYI+e5LdbsXg2EAltXY4YHyg+GRFnL
2ZrPNfm5Wrh2P5w0xepGflwW0QfL1CVPJz9+0c86fQKCAQB4FgDkzGqBYNa2UBuw
YSjE8p8hhPOglvg56jBGP+FQfmHfn31D057sW6zsZ0MzM4CN/moCFFZsdrEFx8Oc
aCayXR/orSHd5tohsKjERFt8oDLEqkcWPWydymIuChj1jQhHN5NuFbTHdLeT7QZi
yCxVloxThq2CghCYaU3/jeqGke2wf+dM49DTn70AyjAslYqmk6oyMc0j/lQD0mM0
XNCr2JxgP3r77po2Gzhg1v2BCCUG7RnqV4OIBI7GRFfwI5K0xcxh4BJOf2fXJcyq
l0D2c2DxHNqjhZUpcphjL7dWhFgttc+qqWN+tdOyFRKT+aKZ0t4hIcfdrX/kaehh
IOQlAoIBAQCCEmyh/db2Y2Yp1E+r+SoWOVAk0EkXW213CSylOO33N4Ldrktxr+1d
bp8TOskkg6T6waO3i+WTERUZkl7wrUQIqmdJZ308Nfztjm/JYu/FhMaeidrVVdMg
X6mNkeWWMDMD3rQKsse6U0EvhNOcU8oGGMVcj32obOJRyYDfqRMIsgAIW1eN+tjv
M7p4edxMz86ySNxDbeYJmtQBlAGyGDET82PaeBa1EMo4YbCIOW347wFyBsZ64Xj1
qdYc32FRYoZE9vg0TZytTp4UrVy+7Hg7+sGgelHTHTiJxkS/B1Y4CrTCa/Tbn0xz
bfso0wOvemxwl0Q1ZaMXzsvl2KqAdeQpAoIBAQC9tvBTKaBxcaijwLqa+lKOQZnO
4MxQsCX5hcXyBJPPhEjP8J3MoyEOGQZK1gu6fRnDuOhgEFqBHJAGIEvLYId2qP3f
4/wZp4as4BYrEPBplwehrh9ufG8NrY4v9vSFzWkNCvuiOgGxmmzo9CPDRvMHSjnx
R1FqAc4PfMqU7LYEX9MKgu5KwCzp8Ot6Y5ifm1hXr2x7ARxe/S3zdvIpaB/aY9TC
D/gWkXVplQDGrLwcguleMy4ZUKuD6L9QLbBBjN18ua5yHfCfw3flSgC9hBxazqce
WChZob9ttZIXX/W0sefNjQjo0etQFakkGYAZihK34fUnCSuMVQDWWxdl1wJA
-----END RSA PRIVATE KEY-----

12
tests/data/key_dsa Normal file
View file

@ -0,0 +1,12 @@
-----BEGIN DSA PRIVATE KEY-----
MIIBugIBAAKBgQC5UysgLVJXTBaY4hPuLBBmxsOkC9VzFKbH581ufLqKxBZlQhcn
OZ4DaQWXUvMXOmDTnG+ROpjbXBMxaYRmCwrUL9Gz0JeTYuqE413D1XYpQYZH5oJH
7SyIe4R+mlCdORekeSKdY2oJ9dREVVe0WXiAzrBV+Eg5Ve3uWQkYw3HAMwIVAMOo
rc88si96YqcYSPf//761FJtVAoGANwUJNODSvguHU6x55+UTGHLyWnbIqd/nbUn1
cnCRa4xeHSHq0rBayoHh3hJiqqpcdRpb0lVoYNe51HmFJHJUGLHtYcxgnqdvIF5K
QiP5h1ESxYqb4v4AXHl5+CVyC0Yp/hkowqaNfVqyOgol/IhNlJknZDCMxWUD9NUJ
iiV5oc0CgYACU3qrETmgEHbwx5kCKN1/Ly4pWzS5rNg764aYsU0wE714TfYs5nOf
yEvQYkfBDb+rEpGyKot6ZvDsHvL0WVVVx7mIDSKnzHAYwYGl1wKNHlLenOMZIDRT
43AKfTz03wRkCrzBl2fAmLLq7wFaXcDDxaBg4zN2CDbuHjmJgRuwzAIUBRb7QH4c
p2gVuWcmRuuI9Qexmzc=
-----END DSA PRIVATE KEY-----

1
tests/data/key_dsa.pub Normal file
View file

@ -0,0 +1 @@
ssh-dss AAAAB3NzaC1kc3MAAACBALlTKyAtUldMFpjiE+4sEGbGw6QL1XMUpsfnzW58uorEFmVCFyc5ngNpBZdS8xc6YNOcb5E6mNtcEzFphGYLCtQv0bPQl5Ni6oTjXcPVdilBhkfmgkftLIh7hH6aUJ05F6R5Ip1jagn11ERVV7RZeIDOsFX4SDlV7e5ZCRjDccAzAAAAFQDDqK3PPLIvemKnGEj3//++tRSbVQAAAIA3BQk04NK+C4dTrHnn5RMYcvJadsip3+dtSfVycJFrjF4dIerSsFrKgeHeEmKqqlx1GlvSVWhg17nUeYUkclQYse1hzGCep28gXkpCI/mHURLFipvi/gBceXn4JXILRin+GSjCpo19WrI6CiX8iE2UmSdkMIzFZQP01QmKJXmhzQAAAIACU3qrETmgEHbwx5kCKN1/Ly4pWzS5rNg764aYsU0wE714TfYs5nOfyEvQYkfBDb+rEpGyKot6ZvDsHvL0WVVVx7mIDSKnzHAYwYGl1wKNHlLenOMZIDRT43AKfTz03wRkCrzBl2fAmLLq7wFaXcDDxaBg4zN2CDbuHjmJgRuwzA== vasko@pcvasko

5
tests/data/key_ecdsa Normal file
View file

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEICQ2fr9Jt2xluom0YQQ7HseE8YTo5reZRVcQENKUWOrooAoGCCqGSM49
AwEHoUQDQgAENEgHZ41JFZT4c1ZFQYqvvqCEIuDxFoyVQKmz2UGOdzqCBomXZD5M
4ufyx7bAB0reVgEzPd1ypH5KVTt4HzAkBw==
-----END EC PRIVATE KEY-----

1
tests/data/key_ecdsa.pub Normal file
View file

@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDRIB2eNSRWU+HNWRUGKr76ghCLg8RaMlUCps9lBjnc6ggaJl2Q+TOLn8se2wAdK3lYBMz3dcqR+SlU7eB8wJAc= vasko@pcvasko

27
tests/data/key_rsa Normal file
View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAz2r1QC4jO0MEyFAJ3TvBPRjpEg0Fo7hMJM2yd5DgT2u5JKu9
VDmRXnnA4xW/XoqZJY3xcrPyWBxkGmFRfP7L09CleYex5brUXResr6khG46W0zkW
9u6XR194hRMgwsAiKKvbzHl/sMl57Xsp9NRqSC9IoNFgJ75Kl/0j47qZV+WSLVEq
9DIVzO3zUl+dAQ+hvCDtP3Y1HHTFHI04xr+90sQfWcy78Z4V7lCW8xCSSS4+qmo8
hCFWiUmu97wN9yQg/Ks2q67LiE6I1SzwxZnh8EgKAeXT/OsqKenusqbl8yscXn+s
jV3BPKE4/FBWASF7ICD9pwb1pONRGitFZN2BZQIDAQABAoIBAQC1jeTQYdI67EXC
ZLTNrqFNroFMaJOYJBiaWmat2+VL/3nWzHDzyVQiQyaAXyfcRCsbQSyn/zTQxUEm
Cis+4vRdGpPNVeZ0tN1wAuoH9F3jdiM1DhK44E0Qj1O5/+08Ktt7iDrjtzH699A+
/ADUqh3Bw4mqIrss7pbyhQSmME5LLTbaWikZ8LgtUiF9f5JWzsqjPb6Yd8JEg0O+
5lDngLfgEYevKCJxxBMtQQQ6gZCjQQWmir+/0NBezSHsoltPlw1m8Vs8Y5zz684y
v33J/qxDM7+rbGbte2fSQ06OuK7abCZMyfXyWdp4cQpG1JZRxGp4Y8vQKvsU5ZOQ
UT/v7ur9AoGBAO+Li/vUzU3GlL7mxBlPTg5LavItWq6C7Rnwftjql7yPxrQ/+m5R
Za0YujnqvZq5SpdpljCZbF9KYrFr92wgFqlt5uYptI4eD0/6xALEUcJJIlllTjiK
tJmuyFkkD45WEn1IlDGAURQiDn6aqd40odlPsv4L5EdnQEQQz6Kfv6JLAoGBAN2q
chHTKv1PBXfqRm0ABYSPyFhki2RqI4DWsbwykFXn3qP7tDDnmR/VMsAbApgTVW77
LGffJ7DZXsqgzujwcqvLBKf8Wl5MRJg2jTe0GkKEBYqhGWNzBhuIwnIcKu/6HsEd
FfCD93hwUPaVTBE+2ckXQVb9RSUCpGarXKk9cZ0PAoGBAJ/Hku29OdwA80KKpo7D
SStbvtAe1HfGuOQueE2z3NZXiJC+hAqFnK5i6gSrwSCtK0XnldiA3bqJ4V66x2SF
2tfUiMlJVDffcRNGDuxRir9vDMxYOF6alnBUFyruVLn6S4bpnH+QOYSWWtizzU58
CODsulWeFPxTsJg2Jmkw6SAVAoGANWBGqX4k2uw9T9vM65BWw83vm0FSw3I/bFXG
ZJ/0W4tC9E+22xPZrm2jE9ktLbtyFhBLaBO3NgGRrs88I6FKq41uaJj+lbhdyB1S
sfgfXqb1wqT6PRVEgjrTP7ECsdiTsUK0tr7AR3McO9RFhd2Ribec1zqTfM7/EW3w
GRyfkAcCgYAtw6KO+5fXHE79v9pUdZAJ4PAc/KdHjv0zE9s5snwUrh7TO5fIB62d
i6nPBWLwD5InDZ9sNgxzTBt+0o2N6PsvKQFtfEBemKimmZShMytFkx9/KTRNR9se
2qcBMiJsdAaz6hHUliYVWV3Ui+Uy+vYh5reuEhcvEjEzT6ySaCrZfg==
-----END RSA PRIVATE KEY-----

1
tests/data/key_rsa.pub Normal file
View file

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl vasko@pcvasko

View file

@ -0,0 +1,464 @@
<?xml version="1.0" encoding="UTF-8"?>
<module name="ietf-netconf-acm"
xmlns="urn:ietf:params:xml:ns:yang:yin:1"
xmlns:nacm="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"
xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types">
<namespace uri="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"/>
<prefix value="nacm"/>
<import module="ietf-yang-types">
<prefix value="yang"/>
</import>
<organization>
<text>IETF NETCONF (Network Configuration) Working Group</text>
</organization>
<contact>
<text>WG Web: &lt;https://datatracker.ietf.org/wg/netconf/&gt;
WG List: &lt;mailto:netconf@ietf.org&gt;
Author: Andy Bierman
&lt;mailto:andy@yumaworks.com&gt;
Author: Martin Bjorklund
&lt;mailto:mbj@tail-f.com&gt;</text>
</contact>
<description>
<text>Network Configuration Access Control Model.
Copyright (c) 2012 - 2018 IETF Trust and the persons
identified as authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD
License set forth in Section 4.c of the IETF Trust's
Legal Provisions Relating to IETF Documents
(https://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 8341; see
the RFC itself for full legal notices.</text>
</description>
<revision date="2018-02-14">
<description>
<text>Added support for YANG 1.1 actions and notifications tied to
data nodes. Clarified how NACM extensions can be used by
other data models.</text>
</description>
<reference>
<text>RFC 8341: Network Configuration Access Control Model</text>
</reference>
</revision>
<revision date="2012-02-22">
<description>
<text>Initial version.</text>
</description>
<reference>
<text>RFC 6536: Network Configuration Protocol (NETCONF)
Access Control Model</text>
</reference>
</revision>
<extension name="default-deny-write">
<description>
<text>Used to indicate that the data model node
represents a sensitive security system parameter.
If present, the NETCONF server will only allow the designated
'recovery session' to have write access to the node. An
explicit access control rule is required for all other users.
If the NACM module is used, then it must be enabled (i.e.,
/nacm/enable-nacm object equals 'true'), or this extension
is ignored.
The 'default-deny-write' extension MAY appear within a data
definition statement. It is ignored otherwise.</text>
</description>
</extension>
<extension name="default-deny-all">
<description>
<text>Used to indicate that the data model node
controls a very sensitive security system parameter.
If present, the NETCONF server will only allow the designated
'recovery session' to have read, write, or execute access to
the node. An explicit access control rule is required for all
other users.
If the NACM module is used, then it must be enabled (i.e.,
/nacm/enable-nacm object equals 'true'), or this extension
is ignored.
The 'default-deny-all' extension MAY appear within a data
definition statement, 'rpc' statement, or 'notification'
statement. It is ignored otherwise.</text>
</description>
</extension>
<typedef name="user-name-type">
<type name="string">
<length value="1..max"/>
</type>
<description>
<text>General-purpose username string.</text>
</description>
</typedef>
<typedef name="matchall-string-type">
<type name="string">
<pattern value="\*"/>
</type>
<description>
<text>The string containing a single asterisk '*' is used
to conceptually represent all possible values
for the particular leaf using this data type.</text>
</description>
</typedef>
<typedef name="access-operations-type">
<type name="bits">
<bit name="create">
<description>
<text>Any protocol operation that creates a
new data node.</text>
</description>
</bit>
<bit name="read">
<description>
<text>Any protocol operation or notification that
returns the value of a data node.</text>
</description>
</bit>
<bit name="update">
<description>
<text>Any protocol operation that alters an existing
data node.</text>
</description>
</bit>
<bit name="delete">
<description>
<text>Any protocol operation that removes a data node.</text>
</description>
</bit>
<bit name="exec">
<description>
<text>Execution access to the specified protocol operation.</text>
</description>
</bit>
</type>
<description>
<text>Access operation.</text>
</description>
</typedef>
<typedef name="group-name-type">
<type name="string">
<length value="1..max"/>
<pattern value="[^\*].*"/>
</type>
<description>
<text>Name of administrative group to which
users can be assigned.</text>
</description>
</typedef>
<typedef name="action-type">
<type name="enumeration">
<enum name="permit">
<description>
<text>Requested action is permitted.</text>
</description>
</enum>
<enum name="deny">
<description>
<text>Requested action is denied.</text>
</description>
</enum>
</type>
<description>
<text>Action taken by the server when a particular
rule matches.</text>
</description>
</typedef>
<typedef name="node-instance-identifier">
<type name="yang:xpath1.0"/>
<description>
<text>Path expression used to represent a special
data node, action, or notification instance-identifier
string.
A node-instance-identifier value is an
unrestricted YANG instance-identifier expression.
All the same rules as an instance-identifier apply,
except that predicates for keys are optional. If a key
predicate is missing, then the node-instance-identifier
represents all possible server instances for that key.
This XML Path Language (XPath) expression is evaluated in the
following context:
o The set of namespace declarations are those in scope on
the leaf element where this type is used.
o The set of variable bindings contains one variable,
'USER', which contains the name of the user of the
current session.
o The function library is the core function library, but
note that due to the syntax restrictions of an
instance-identifier, no functions are allowed.
o The context node is the root node in the data tree.
The accessible tree includes actions and notifications tied
to data nodes.</text>
</description>
</typedef>
<container name="nacm">
<nacm:default-deny-all/>
<description>
<text>Parameters for NETCONF access control model.</text>
</description>
<leaf name="enable-nacm">
<type name="boolean"/>
<default value="true"/>
<description>
<text>Enables or disables all NETCONF access control
enforcement. If 'true', then enforcement
is enabled. If 'false', then enforcement
is disabled.</text>
</description>
</leaf>
<leaf name="read-default">
<type name="action-type"/>
<default value="permit"/>
<description>
<text>Controls whether read access is granted if
no appropriate rule is found for a
particular read request.</text>
</description>
</leaf>
<leaf name="write-default">
<type name="action-type"/>
<default value="deny"/>
<description>
<text>Controls whether create, update, or delete access
is granted if no appropriate rule is found for a
particular write request.</text>
</description>
</leaf>
<leaf name="exec-default">
<type name="action-type"/>
<default value="permit"/>
<description>
<text>Controls whether exec access is granted if no appropriate
rule is found for a particular protocol operation request.</text>
</description>
</leaf>
<leaf name="enable-external-groups">
<type name="boolean"/>
<default value="true"/>
<description>
<text>Controls whether the server uses the groups reported by the
NETCONF transport layer when it assigns the user to a set of
NACM groups. If this leaf has the value 'false', any group
names reported by the transport layer are ignored by the
server.</text>
</description>
</leaf>
<leaf name="denied-operations">
<type name="yang:zero-based-counter32"/>
<config value="false"/>
<mandatory value="true"/>
<description>
<text>Number of times since the server last restarted that a
protocol operation request was denied.</text>
</description>
</leaf>
<leaf name="denied-data-writes">
<type name="yang:zero-based-counter32"/>
<config value="false"/>
<mandatory value="true"/>
<description>
<text>Number of times since the server last restarted that a
protocol operation request to alter
a configuration datastore was denied.</text>
</description>
</leaf>
<leaf name="denied-notifications">
<type name="yang:zero-based-counter32"/>
<config value="false"/>
<mandatory value="true"/>
<description>
<text>Number of times since the server last restarted that
a notification was dropped for a subscription because
access to the event type was denied.</text>
</description>
</leaf>
<container name="groups">
<description>
<text>NETCONF access control groups.</text>
</description>
<list name="group">
<key value="name"/>
<description>
<text>One NACM group entry. This list will only contain
configured entries, not any entries learned from
any transport protocols.</text>
</description>
<leaf name="name">
<type name="group-name-type"/>
<description>
<text>Group name associated with this entry.</text>
</description>
</leaf>
<leaf-list name="user-name">
<type name="user-name-type"/>
<description>
<text>Each entry identifies the username of
a member of the group associated with
this entry.</text>
</description>
</leaf-list>
</list>
</container>
<list name="rule-list">
<key value="name"/>
<ordered-by value="user"/>
<description>
<text>An ordered collection of access control rules.</text>
</description>
<leaf name="name">
<type name="string">
<length value="1..max"/>
</type>
<description>
<text>Arbitrary name assigned to the rule-list.</text>
</description>
</leaf>
<leaf-list name="group">
<type name="union">
<type name="matchall-string-type"/>
<type name="group-name-type"/>
</type>
<description>
<text>List of administrative groups that will be
assigned the associated access rights
defined by the 'rule' list.
The string '*' indicates that all groups apply to the
entry.</text>
</description>
</leaf-list>
<list name="rule">
<key value="name"/>
<ordered-by value="user"/>
<description>
<text>One access control rule.
Rules are processed in user-defined order until a match is
found. A rule matches if 'module-name', 'rule-type', and
'access-operations' match the request. If a rule
matches, the 'action' leaf determines whether or not
access is granted.</text>
</description>
<leaf name="name">
<type name="string">
<length value="1..max"/>
</type>
<description>
<text>Arbitrary name assigned to the rule.</text>
</description>
</leaf>
<leaf name="module-name">
<type name="union">
<type name="matchall-string-type"/>
<type name="string"/>
</type>
<default value="*"/>
<description>
<text>Name of the module associated with this rule.
This leaf matches if it has the value '*' or if the
object being accessed is defined in the module with the
specified module name.</text>
</description>
</leaf>
<choice name="rule-type">
<description>
<text>This choice matches if all leafs present in the rule
match the request. If no leafs are present, the
choice matches all requests.</text>
</description>
<case name="protocol-operation">
<leaf name="rpc-name">
<type name="union">
<type name="matchall-string-type"/>
<type name="string"/>
</type>
<description>
<text>This leaf matches if it has the value '*' or if
its value equals the requested protocol operation
name.</text>
</description>
</leaf>
</case>
<case name="notification">
<leaf name="notification-name">
<type name="union">
<type name="matchall-string-type"/>
<type name="string"/>
</type>
<description>
<text>This leaf matches if it has the value '*' or if its
value equals the requested notification name.</text>
</description>
</leaf>
</case>
<case name="data-node">
<leaf name="path">
<type name="node-instance-identifier"/>
<mandatory value="true"/>
<description>
<text>Data node instance-identifier associated with the
data node, action, or notification controlled by
this rule.
Configuration data or state data
instance-identifiers start with a top-level
data node. A complete instance-identifier is
required for this type of path value.
The special value '/' refers to all possible
datastore contents.</text>
</description>
</leaf>
</case>
</choice>
<leaf name="access-operations">
<type name="union">
<type name="matchall-string-type"/>
<type name="access-operations-type"/>
</type>
<default value="*"/>
<description>
<text>Access operations associated with this rule.
This leaf matches if it has the value '*' or if the
bit corresponding to the requested operation is set.</text>
</description>
</leaf>
<leaf name="action">
<type name="action-type"/>
<mandatory value="true"/>
<description>
<text>The access control action associated with the
rule. If a rule has been determined to match a
particular request, then this object is used
to determine whether to permit or deny the
request.</text>
</description>
</leaf>
<leaf name="comment">
<type name="string"/>
<description>
<text>A textual description of the access rule.</text>
</description>
</leaf>
</list>
</list>
</container>
</module>

View file

@ -0,0 +1,600 @@
<?xml version="1.0" encoding="UTF-8"?>
<module name="ietf-netconf-monitoring"
xmlns="urn:ietf:params:xml:ns:yang:yin:1"
xmlns:ncm="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"
xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types"
xmlns:inet="urn:ietf:params:xml:ns:yang:ietf-inet-types">
<namespace uri="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"/>
<prefix value="ncm"/>
<import module="ietf-yang-types">
<prefix value="yang"/>
</import>
<import module="ietf-inet-types">
<prefix value="inet"/>
</import>
<organization>
<text>IETF NETCONF (Network Configuration) Working Group</text>
</organization>
<contact>
<text>WG Web: &lt;http://tools.ietf.org/wg/netconf/&gt;
WG List: &lt;mailto:netconf@ietf.org&gt;
WG Chair: Mehmet Ersue
&lt;mailto:mehmet.ersue@nsn.com&gt;
WG Chair: Bert Wijnen
&lt;mailto:bertietf@bwijnen.net&gt;
Editor: Mark Scott
&lt;mailto:mark.scott@ericsson.com&gt;
Editor: Martin Bjorklund
&lt;mailto:mbj@tail-f.com&gt;</text>
</contact>
<description>
<text>NETCONF Monitoring Module.
All elements in this module are read-only.
Copyright (c) 2010 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD
License set forth in Section 4.c of the IETF Trust's
Legal Provisions Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 6022; see
the RFC itself for full legal notices.</text>
</description>
<revision date="2010-10-04">
<description>
<text>Initial revision.</text>
</description>
<reference>
<text>RFC 6022: YANG Module for NETCONF Monitoring</text>
</reference>
</revision>
<typedef name="netconf-datastore-type">
<type name="enumeration">
<enum name="running"/>
<enum name="candidate"/>
<enum name="startup"/>
</type>
<description>
<text>Enumeration of possible NETCONF datastore types.</text>
</description>
<reference>
<text>RFC 4741: NETCONF Configuration Protocol</text>
</reference>
</typedef>
<identity name="transport">
<description>
<text>Base identity for NETCONF transport types.</text>
</description>
</identity>
<identity name="netconf-ssh">
<base name="transport"/>
<description>
<text>NETCONF over Secure Shell (SSH).</text>
</description>
<reference>
<text>RFC 4742: Using the NETCONF Configuration Protocol
over Secure SHell (SSH)</text>
</reference>
</identity>
<identity name="netconf-soap-over-beep">
<base name="transport"/>
<description>
<text>NETCONF over Simple Object Access Protocol (SOAP) over
Blocks Extensible Exchange Protocol (BEEP).</text>
</description>
<reference>
<text>RFC 4743: Using NETCONF over the Simple Object
Access Protocol (SOAP)</text>
</reference>
</identity>
<identity name="netconf-soap-over-https">
<base name="transport"/>
<description>
<text>NETCONF over Simple Object Access Protocol (SOAP)
over Hypertext Transfer Protocol Secure (HTTPS).</text>
</description>
<reference>
<text>RFC 4743: Using NETCONF over the Simple Object
Access Protocol (SOAP)</text>
</reference>
</identity>
<identity name="netconf-beep">
<base name="transport"/>
<description>
<text>NETCONF over Blocks Extensible Exchange Protocol (BEEP).</text>
</description>
<reference>
<text>RFC 4744: Using the NETCONF Protocol over the
Blocks Extensible Exchange Protocol (BEEP)</text>
</reference>
</identity>
<identity name="netconf-tls">
<base name="transport"/>
<description>
<text>NETCONF over Transport Layer Security (TLS).</text>
</description>
<reference>
<text>RFC 5539: NETCONF over Transport Layer Security (TLS)</text>
</reference>
</identity>
<identity name="schema-format">
<description>
<text>Base identity for data model schema languages.</text>
</description>
</identity>
<identity name="xsd">
<base name="schema-format"/>
<description>
<text>W3C XML Schema Definition.</text>
</description>
<reference>
<text>W3C REC REC-xmlschema-1-20041028:
XML Schema Part 1: Structures</text>
</reference>
</identity>
<identity name="yang">
<base name="schema-format"/>
<description>
<text>The YANG data modeling language for NETCONF.</text>
</description>
<reference>
<text>RFC 6020: YANG - A Data Modeling Language for the
Network Configuration Protocol (NETCONF)</text>
</reference>
</identity>
<identity name="yin">
<base name="schema-format"/>
<description>
<text>The YIN syntax for YANG.</text>
</description>
<reference>
<text>RFC 6020: YANG - A Data Modeling Language for the
Network Configuration Protocol (NETCONF)</text>
</reference>
</identity>
<identity name="rng">
<base name="schema-format"/>
<description>
<text>Regular Language for XML Next Generation (RELAX NG).</text>
</description>
<reference>
<text>ISO/IEC 19757-2:2008: RELAX NG</text>
</reference>
</identity>
<identity name="rnc">
<base name="schema-format"/>
<description>
<text>Relax NG Compact Syntax</text>
</description>
<reference>
<text>ISO/IEC 19757-2:2008: RELAX NG</text>
</reference>
</identity>
<grouping name="common-counters">
<description>
<text>Counters that exist both per session, and also globally,
accumulated from all sessions.</text>
</description>
<leaf name="in-rpcs">
<type name="yang:zero-based-counter32"/>
<description>
<text>Number of correct &lt;rpc&gt; messages received.</text>
</description>
</leaf>
<leaf name="in-bad-rpcs">
<type name="yang:zero-based-counter32"/>
<description>
<text>Number of messages received when an &lt;rpc&gt; message was expected,
that were not correct &lt;rpc&gt; messages. This includes XML parse
errors and errors on the rpc layer.</text>
</description>
</leaf>
<leaf name="out-rpc-errors">
<type name="yang:zero-based-counter32"/>
<description>
<text>Number of &lt;rpc-reply&gt; messages sent that contained an
&lt;rpc-error&gt; element.</text>
</description>
</leaf>
<leaf name="out-notifications">
<type name="yang:zero-based-counter32"/>
<description>
<text>Number of &lt;notification&gt; messages sent.</text>
</description>
</leaf>
</grouping>
<container name="netconf-state">
<config value="false"/>
<description>
<text>The netconf-state container is the root of the monitoring
data model.</text>
</description>
<container name="capabilities">
<description>
<text>Contains the list of NETCONF capabilities supported by the
server.</text>
</description>
<leaf-list name="capability">
<type name="inet:uri"/>
<description>
<text>List of NETCONF capabilities supported by the server.</text>
</description>
</leaf-list>
</container>
<container name="datastores">
<description>
<text>Contains the list of NETCONF configuration datastores.</text>
</description>
<list name="datastore">
<key value="name"/>
<description>
<text>List of NETCONF configuration datastores supported by
the NETCONF server and related information.</text>
</description>
<leaf name="name">
<type name="netconf-datastore-type"/>
<description>
<text>Name of the datastore associated with this list entry.</text>
</description>
</leaf>
<container name="locks">
<presence value="This container is present only if the datastore&#10;is locked."/>
<description>
<text>The NETCONF &lt;lock&gt; and &lt;partial-lock&gt; operations allow
a client to lock specific resources in a datastore. The
NETCONF server will prevent changes to the locked
resources by all sessions except the one that acquired
the lock(s).
Monitoring information is provided for each datastore
entry including details such as the session that acquired
the lock, the type of lock (global or partial) and the
list of locked resources. Multiple locks per datastore
are supported.</text>
</description>
<grouping name="lock-info">
<description>
<text>Lock related parameters, common to both global and
partial locks.</text>
</description>
<leaf name="locked-by-session">
<type name="uint32"/>
<mandatory value="true"/>
<description>
<text>The session ID of the session that has locked
this resource. Both a global lock and a partial
lock MUST contain the NETCONF session-id.
If the lock is held by a session that is not managed
by the NETCONF server (e.g., a CLI session), a session
id of 0 (zero) is reported.</text>
</description>
<reference>
<text>RFC 4741: NETCONF Configuration Protocol</text>
</reference>
</leaf>
<leaf name="locked-time">
<type name="yang:date-and-time"/>
<mandatory value="true"/>
<description>
<text>The date and time of when the resource was
locked.</text>
</description>
</leaf>
</grouping>
<choice name="lock-type">
<description>
<text>Indicates if a global lock or a set of partial locks
are set.</text>
</description>
<container name="global-lock">
<description>
<text>Present if the global lock is set.</text>
</description>
<uses name="lock-info"/>
</container>
<list name="partial-lock">
<key value="lock-id"/>
<description>
<text>List of partial locks.</text>
</description>
<reference>
<text>RFC 5717: Partial Lock Remote Procedure Call (RPC) for
NETCONF</text>
</reference>
<leaf name="lock-id">
<type name="uint32"/>
<description>
<text>This is the lock id returned in the &lt;partial-lock&gt;
response.</text>
</description>
</leaf>
<uses name="lock-info"/>
<leaf-list name="select">
<type name="yang:xpath1.0"/>
<min-elements value="1"/>
<description>
<text>The xpath expression that was used to request
the lock. The select expression indicates the
original intended scope of the lock.</text>
</description>
</leaf-list>
<leaf-list name="locked-node">
<type name="instance-identifier"/>
<description>
<text>The list of instance-identifiers (i.e., the
locked nodes).
The scope of the partial lock is defined by the list
of locked nodes.</text>
</description>
</leaf-list>
</list>
</choice>
</container>
</list>
</container>
<container name="schemas">
<description>
<text>Contains the list of data model schemas supported by the
server.</text>
</description>
<list name="schema">
<key value="identifier version format"/>
<description>
<text>List of data model schemas supported by the server.</text>
</description>
<leaf name="identifier">
<type name="string"/>
<description>
<text>Identifier to uniquely reference the schema. The
identifier is used in the &lt;get-schema&gt; operation and may
be used for other purposes such as file retrieval.
For modeling languages that support or require a data
model name (e.g., YANG module name) the identifier MUST
match that name. For YANG data models, the identifier is
the name of the module or submodule. In other cases, an
identifier such as a filename MAY be used instead.</text>
</description>
</leaf>
<leaf name="version">
<type name="string"/>
<description>
<text>Version of the schema supported. Multiple versions MAY be
supported simultaneously by a NETCONF server. Each
version MUST be reported individually in the schema list,
i.e., with same identifier, possibly different location,
but different version.
For YANG data models, version is the value of the most
recent YANG 'revision' statement in the module or
submodule, or the empty string if no 'revision' statement
is present.</text>
</description>
</leaf>
<leaf name="format">
<type name="identityref">
<base name="schema-format"/>
</type>
<description>
<text>The data modeling language the schema is written
in (currently xsd, yang, yin, rng, or rnc).
For YANG data models, 'yang' format MUST be supported and
'yin' format MAY also be provided.</text>
</description>
</leaf>
<leaf name="namespace">
<type name="inet:uri"/>
<mandatory value="true"/>
<description>
<text>The XML namespace defined by the data model.
For YANG data models, this is the module's namespace.
If the list entry describes a submodule, this field
contains the namespace of the module to which the
submodule belongs.</text>
</description>
</leaf>
<leaf-list name="location">
<type name="union">
<type name="enumeration">
<enum name="NETCONF"/>
</type>
<type name="inet:uri"/>
</type>
<description>
<text>One or more locations from which the schema can be
retrieved. This list SHOULD contain at least one
entry per schema.
A schema entry may be located on a remote file system
(e.g., reference to file system for ftp retrieval) or
retrieved directly from a server supporting the
&lt;get-schema&gt; operation (denoted by the value 'NETCONF').</text>
</description>
</leaf-list>
</list>
</container>
<container name="sessions">
<description>
<text>The sessions container includes session-specific data for
NETCONF management sessions. The session list MUST include
all currently active NETCONF sessions.</text>
</description>
<list name="session">
<key value="session-id"/>
<description>
<text>All NETCONF sessions managed by the NETCONF server
MUST be reported in this list.</text>
</description>
<leaf name="session-id">
<type name="uint32">
<range value="1..max"/>
</type>
<description>
<text>Unique identifier for the session. This value is the
NETCONF session identifier, as defined in RFC 4741.</text>
</description>
<reference>
<text>RFC 4741: NETCONF Configuration Protocol</text>
</reference>
</leaf>
<leaf name="transport">
<type name="identityref">
<base name="transport"/>
</type>
<mandatory value="true"/>
<description>
<text>Identifies the transport for each session, e.g.,
'netconf-ssh', 'netconf-soap', etc.</text>
</description>
</leaf>
<leaf name="username">
<type name="string"/>
<mandatory value="true"/>
<description>
<text>The username is the client identity that was authenticated
by the NETCONF transport protocol. The algorithm used to
derive the username is NETCONF transport protocol specific
and in addition specific to the authentication mechanism
used by the NETCONF transport protocol.</text>
</description>
</leaf>
<leaf name="source-host">
<type name="inet:host"/>
<description>
<text>Host identifier of the NETCONF client. The value
returned is implementation specific (e.g., hostname,
IPv4 address, IPv6 address)</text>
</description>
</leaf>
<leaf name="login-time">
<type name="yang:date-and-time"/>
<mandatory value="true"/>
<description>
<text>Time at the server at which the session was established.</text>
</description>
</leaf>
<uses name="common-counters">
<description>
<text>Per-session counters. Zero based with following reset
behaviour:
- at start of a session
- when max value is reached</text>
</description>
</uses>
</list>
</container>
<container name="statistics">
<description>
<text>Statistical data pertaining to the NETCONF server.</text>
</description>
<leaf name="netconf-start-time">
<type name="yang:date-and-time"/>
<description>
<text>Date and time at which the management subsystem was
started.</text>
</description>
</leaf>
<leaf name="in-bad-hellos">
<type name="yang:zero-based-counter32"/>
<description>
<text>Number of sessions silently dropped because an
invalid &lt;hello&gt; message was received. This includes &lt;hello&gt;
messages with a 'session-id' attribute, bad namespace, and
bad capability declarations.</text>
</description>
</leaf>
<leaf name="in-sessions">
<type name="yang:zero-based-counter32"/>
<description>
<text>Number of sessions started. This counter is incremented
when a &lt;hello&gt; message with a &lt;session-id&gt; is sent.
'in-sessions' - 'in-bad-hellos' =
'number of correctly started netconf sessions'</text>
</description>
</leaf>
<leaf name="dropped-sessions">
<type name="yang:zero-based-counter32"/>
<description>
<text>Number of sessions that were abnormally terminated, e.g.,
due to idle timeout or transport close. This counter is not
incremented when a session is properly closed by a
&lt;close-session&gt; operation, or killed by a &lt;kill-session&gt;
operation.</text>
</description>
</leaf>
<uses name="common-counters">
<description>
<text>Global counters, accumulated from all sessions.
Zero based with following reset behaviour:
- re-initialization of NETCONF server
- when max value is reached</text>
</description>
</uses>
</container>
</container>
<rpc name="get-schema">
<description>
<text>This operation is used to retrieve a schema from the
NETCONF server.
Positive Response:
The NETCONF server returns the requested schema.
Negative Response:
If requested schema does not exist, the &lt;error-tag&gt; is
'invalid-value'.
If more than one schema matches the requested parameters, the
&lt;error-tag&gt; is 'operation-failed', and &lt;error-app-tag&gt; is
'data-not-unique'.</text>
</description>
<input>
<leaf name="identifier">
<type name="string"/>
<mandatory value="true"/>
<description>
<text>Identifier for the schema list entry.</text>
</description>
</leaf>
<leaf name="version">
<type name="string"/>
<description>
<text>Version of the schema requested. If this parameter is not
present, and more than one version of the schema exists on
the server, a 'data-not-unique' error is returned, as
described above.</text>
</description>
</leaf>
<leaf name="format">
<type name="identityref">
<base name="schema-format"/>
</type>
<description>
<text>The data modeling language of the schema. If this
parameter is not present, and more than one formats of
the schema exists on the server, a 'data-not-unique' error
is returned, as described above.</text>
</description>
</leaf>
</input>
<output>
<anyxml name="data">
<description>
<text>Contains the schema content.</text>
</description>
</anyxml>
</output>
</rpc>
</module>

View file

@ -0,0 +1,353 @@
<?xml version="1.0" encoding="UTF-8"?>
<module name="ietf-netconf-notifications"
xmlns="urn:ietf:params:xml:ns:yang:yin:1"
xmlns:ncn="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications"
xmlns:inet="urn:ietf:params:xml:ns:yang:ietf-inet-types"
xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
<namespace uri="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications"/>
<prefix value="ncn"/>
<import module="ietf-inet-types">
<prefix value="inet"/>
</import>
<import module="ietf-netconf">
<prefix value="nc"/>
</import>
<organization>
<text>IETF NETCONF (Network Configuration Protocol) Working Group</text>
</organization>
<contact>
<text>WG Web: &lt;http://tools.ietf.org/wg/netconf/&gt;
WG List: &lt;mailto:netconf@ietf.org&gt;
WG Chair: Bert Wijnen
&lt;mailto:bertietf@bwijnen.net&gt;
WG Chair: Mehmet Ersue
&lt;mailto:mehmet.ersue@nsn.com&gt;
Editor: Andy Bierman
&lt;mailto:andy@netconfcentral.org&gt;</text>
</contact>
<description>
<text>This module defines a YANG data model for use with the
NETCONF protocol that allows the NETCONF client to
receive common NETCONF base event notifications.
Copyright (c) 2012 IETF Trust and the persons identified as
the document authors. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 6470; see
the RFC itself for full legal notices.</text>
</description>
<revision date="2012-02-06">
<description>
<text>Initial version.</text>
</description>
<reference>
<text>RFC 6470: NETCONF Base Notifications</text>
</reference>
</revision>
<grouping name="common-session-parms">
<description>
<text>Common session parameters to identify a
management session.</text>
</description>
<leaf name="username">
<type name="string"/>
<mandatory value="true"/>
<description>
<text>Name of the user for the session.</text>
</description>
</leaf>
<leaf name="session-id">
<type name="nc:session-id-or-zero-type"/>
<mandatory value="true"/>
<description>
<text>Identifier of the session.
A NETCONF session MUST be identified by a non-zero value.
A non-NETCONF session MAY be identified by the value zero.</text>
</description>
</leaf>
<leaf name="source-host">
<type name="inet:ip-address"/>
<description>
<text>Address of the remote host for the session.</text>
</description>
</leaf>
</grouping>
<grouping name="changed-by-parms">
<description>
<text>Common parameters to identify the source
of a change event, such as a configuration
or capability change.</text>
</description>
<container name="changed-by">
<description>
<text>Indicates the source of the change.
If caused by internal action, then the
empty leaf 'server' will be present.
If caused by a management session, then
the name, remote host address, and session ID
of the session that made the change will be reported.</text>
</description>
<choice name="server-or-user">
<mandatory value="true"/>
<leaf name="server">
<type name="empty"/>
<description>
<text>If present, the change was caused
by the server.</text>
</description>
</leaf>
<case name="by-user">
<uses name="common-session-parms"/>
</case>
</choice>
</container>
</grouping>
<notification name="netconf-config-change">
<description>
<text>Generated when the NETCONF server detects that the
&lt;running&gt; or &lt;startup&gt; configuration datastore
has been changed by a management session.
The notification summarizes the edits that
have been detected.
The server MAY choose to also generate this
notification while loading a datastore during the
boot process for the device.</text>
</description>
<uses name="changed-by-parms"/>
<leaf name="datastore">
<type name="enumeration">
<enum name="running">
<description>
<text>The &lt;running&gt; datastore has changed.</text>
</description>
</enum>
<enum name="startup">
<description>
<text>The &lt;startup&gt; datastore has changed</text>
</description>
</enum>
</type>
<default value="running"/>
<description>
<text>Indicates which configuration datastore has changed.</text>
</description>
</leaf>
<list name="edit">
<description>
<text>An edit record SHOULD be present for each distinct
edit operation that the server has detected on
the target datastore. This list MAY be omitted
if the detailed edit operations are not known.
The server MAY report entries in this list for
changes not made by a NETCONF session (e.g., CLI).</text>
</description>
<leaf name="target">
<type name="instance-identifier"/>
<description>
<text>Topmost node associated with the configuration change.
A server SHOULD set this object to the node within
the datastore that is being altered. A server MAY
set this object to one of the ancestors of the actual
node that was changed, or omit this object, if the
exact node is not known.</text>
</description>
</leaf>
<leaf name="operation">
<type name="nc:edit-operation-type"/>
<description>
<text>Type of edit operation performed.
A server MUST set this object to the NETCONF edit
operation performed on the target datastore.</text>
</description>
</leaf>
</list>
</notification>
<notification name="netconf-capability-change">
<description>
<text>Generated when the NETCONF server detects that
the server capabilities have changed.
Indicates which capabilities have been added, deleted,
and/or modified. The manner in which a server
capability is changed is outside the scope of this
document.</text>
</description>
<uses name="changed-by-parms"/>
<leaf-list name="added-capability">
<type name="inet:uri"/>
<description>
<text>List of capabilities that have just been added.</text>
</description>
</leaf-list>
<leaf-list name="deleted-capability">
<type name="inet:uri"/>
<description>
<text>List of capabilities that have just been deleted.</text>
</description>
</leaf-list>
<leaf-list name="modified-capability">
<type name="inet:uri"/>
<description>
<text>List of capabilities that have just been modified.
A capability is considered to be modified if the
base URI for the capability has not changed, but
one or more of the parameters encoded at the end of
the capability URI have changed.
The new modified value of the complete URI is returned.</text>
</description>
</leaf-list>
</notification>
<notification name="netconf-session-start">
<description>
<text>Generated when a NETCONF server detects that a
NETCONF session has started. A server MAY generate
this event for non-NETCONF management sessions.
Indicates the identity of the user that started
the session.</text>
</description>
<uses name="common-session-parms"/>
</notification>
<notification name="netconf-session-end">
<description>
<text>Generated when a NETCONF server detects that a
NETCONF session has terminated.
A server MAY optionally generate this event for
non-NETCONF management sessions. Indicates the
identity of the user that owned the session,
and why the session was terminated.</text>
</description>
<uses name="common-session-parms"/>
<leaf name="killed-by">
<when condition="../termination-reason = 'killed'"/>
<type name="nc:session-id-type"/>
<description>
<text>The ID of the session that directly caused this session
to be abnormally terminated. If this session was abnormally
terminated by a non-NETCONF session unknown to the server,
then this leaf will not be present.</text>
</description>
</leaf>
<leaf name="termination-reason">
<type name="enumeration">
<enum name="closed">
<description>
<text>The session was terminated by the client in normal
fashion, e.g., by the NETCONF &lt;close-session&gt;
protocol operation.</text>
</description>
</enum>
<enum name="killed">
<description>
<text>The session was terminated in abnormal
fashion, e.g., by the NETCONF &lt;kill-session&gt;
protocol operation.</text>
</description>
</enum>
<enum name="dropped">
<description>
<text>The session was terminated because the transport layer
connection was unexpectedly closed.</text>
</description>
</enum>
<enum name="timeout">
<description>
<text>The session was terminated because of inactivity,
e.g., waiting for the &lt;hello&gt; message or &lt;rpc&gt;
messages.</text>
</description>
</enum>
<enum name="bad-hello">
<description>
<text>The client's &lt;hello&gt; message was invalid.</text>
</description>
</enum>
<enum name="other">
<description>
<text>The session was terminated for some other reason.</text>
</description>
</enum>
</type>
<mandatory value="true"/>
<description>
<text>Reason the session was terminated.</text>
</description>
</leaf>
</notification>
<notification name="netconf-confirmed-commit">
<description>
<text>Generated when a NETCONF server detects that a
confirmed-commit event has occurred. Indicates the event
and the current state of the confirmed-commit procedure
in progress.</text>
</description>
<reference>
<text>RFC 6241, Section 8.4</text>
</reference>
<uses name="common-session-parms">
<when condition="confirm-event != 'timeout'"/>
</uses>
<leaf name="confirm-event">
<type name="enumeration">
<enum name="start">
<description>
<text>The confirmed-commit procedure has started.</text>
</description>
</enum>
<enum name="cancel">
<description>
<text>The confirmed-commit procedure has been canceled,
e.g., due to the session being terminated, or an
explicit &lt;cancel-commit&gt; operation.</text>
</description>
</enum>
<enum name="timeout">
<description>
<text>The confirmed-commit procedure has been canceled
due to the confirm-timeout interval expiring.
The common session parameters will not be present
in this sub-mode.</text>
</description>
</enum>
<enum name="extend">
<description>
<text>The confirmed-commit timeout has been extended,
e.g., by a new &lt;confirmed-commit&gt; operation.</text>
</description>
</enum>
<enum name="complete">
<description>
<text>The confirmed-commit procedure has been completed.</text>
</description>
</enum>
</type>
<mandatory value="true"/>
<description>
<text>Indicates the event that caused the notification.</text>
</description>
</leaf>
<leaf name="timeout">
<when condition="../confirm-event = 'start' or ../confirm-event = 'extend'"/>
<type name="uint32"/>
<units name="seconds"/>
<description>
<text>The configured timeout value if the event type
is 'start' or 'extend'. This value represents
the approximate number of seconds from the event
time when the 'timeout' event might occur.</text>
</description>
</leaf>
</notification>
</module>

View file

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
<module name="ietf-netconf-with-defaults"
xmlns="urn:ietf:params:xml:ns:yang:yin:1"
xmlns:ncwd="urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults"
xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
<namespace uri="urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults"/>
<prefix value="ncwd"/>
<import module="ietf-netconf">
<prefix value="nc"/>
</import>
<organization>
<text>IETF NETCONF (Network Configuration Protocol) Working Group</text>
</organization>
<contact>
<text>WG Web: &lt;http://tools.ietf.org/wg/netconf/&gt;
WG List: &lt;netconf@ietf.org&gt;
WG Chair: Bert Wijnen
&lt;bertietf@bwijnen.net&gt;
WG Chair: Mehmet Ersue
&lt;mehmet.ersue@nsn.com&gt;
Editor: Andy Bierman
&lt;andy.bierman@brocade.com&gt;
Editor: Balazs Lengyel
&lt;balazs.lengyel@ericsson.com&gt;</text>
</contact>
<description>
<text>This module defines an extension to the NETCONF protocol
that allows the NETCONF client to control how default
values are handled by the server in particular NETCONF
operations.
Copyright (c) 2011 IETF Trust and the persons identified as
the document authors. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 6243; see
the RFC itself for full legal notices.</text>
</description>
<revision date="2011-06-01">
<description>
<text>Initial version.</text>
</description>
<reference>
<text>RFC 6243: With-defaults Capability for NETCONF</text>
</reference>
</revision>
<typedef name="with-defaults-mode">
<description>
<text>Possible modes to report default data.</text>
</description>
<reference>
<text>RFC 6243; Section 3.</text>
</reference>
<type name="enumeration">
<enum name="report-all">
<description>
<text>All default data is reported.</text>
</description>
<reference>
<text>RFC 6243; Section 3.1</text>
</reference>
</enum>
<enum name="report-all-tagged">
<description>
<text>All default data is reported.
Any nodes considered to be default data
will contain a 'default' XML attribute,
set to 'true' or '1'.</text>
</description>
<reference>
<text>RFC 6243; Section 3.4</text>
</reference>
</enum>
<enum name="trim">
<description>
<text>Values are not reported if they contain the default.</text>
</description>
<reference>
<text>RFC 6243; Section 3.2</text>
</reference>
</enum>
<enum name="explicit">
<description>
<text>Report values that contain the definition of
explicitly set data.</text>
</description>
<reference>
<text>RFC 6243; Section 3.3</text>
</reference>
</enum>
</type>
</typedef>
<grouping name="with-defaults-parameters">
<description>
<text>Contains the &lt;with-defaults&gt; parameter for control
of defaults in NETCONF retrieval operations.</text>
</description>
<leaf name="with-defaults">
<description>
<text>The explicit defaults processing mode requested.</text>
</description>
<reference>
<text>RFC 6243; Section 4.5.1</text>
</reference>
<type name="with-defaults-mode"/>
</leaf>
</grouping>
<augment target-node="/nc:get-config/nc:input">
<description>
<text>Adds the &lt;with-defaults&gt; parameter to the
input of the NETCONF &lt;get-config&gt; operation.</text>
</description>
<reference>
<text>RFC 6243; Section 4.5.1</text>
</reference>
<uses name="with-defaults-parameters"/>
</augment>
<augment target-node="/nc:get/nc:input">
<description>
<text>Adds the &lt;with-defaults&gt; parameter to
the input of the NETCONF &lt;get&gt; operation.</text>
</description>
<reference>
<text>RFC 6243; Section 4.5.1</text>
</reference>
<uses name="with-defaults-parameters"/>
</augment>
<augment target-node="/nc:copy-config/nc:input">
<description>
<text>Adds the &lt;with-defaults&gt; parameter to
the input of the NETCONF &lt;copy-config&gt; operation.</text>
</description>
<reference>
<text>RFC 6243; Section 4.5.1</text>
</reference>
<uses name="with-defaults-parameters"/>
</augment>
</module>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,16 @@
module module-a-dv {
namespace "urn:jmu:params:xml:ns:yang:module-a-dv";
prefix dv;
import module-a {
prefix a;
}
description
"Contains some deviations to module-a";
deviation "/a:top/a:hidden" {
deviate not-supported;
}
}

View file

@ -0,0 +1,21 @@
module module-a-dv2 {
namespace "urn:jmu:params:xml:ns:yang:module-a-dv2";
prefix dv2;
import module-a {
prefix a;
}
description
"Contains some deviations to module-a";
deviation "/a:top/a:type" {
deviate add {
default "admin";
must "count(.) = 1";
}
}
}

View file

@ -0,0 +1,23 @@
module module-a {
namespace "urn:jmu:params:xml:ns:yang:module-a";
prefix a;
description "This is a simple user module";
container top {
leaf name {
type string;
}
leaf type {
type string;
}
leaf hidden {
type boolean;
}
}
}

View file

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<module name="nc-notifications"
xmlns="urn:ietf:params:xml:ns:yang:yin:1"
xmlns:manageEvent="urn:ietf:params:xml:ns:netmod:notification"
xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types"
xmlns:ncEvent="urn:ietf:params:xml:ns:netconf:notification:1.0">
<namespace uri="urn:ietf:params:xml:ns:netmod:notification"/>
<prefix value="manageEvent"/>
<import module="ietf-yang-types">
<prefix value="yang"/>
</import>
<import module="notifications">
<prefix value="ncEvent"/>
</import>
<organization>
<text>IETF NETCONF WG</text>
</organization>
<contact>
<text>netconf@ietf.org</text>
</contact>
<description>
<text>Conversion of the 'manageEvent' XSD in the NETCONF
Notifications RFC.</text>
</description>
<reference>
<text>RFC 5277</text>
</reference>
<revision date="2008-07-14">
<description>
<text>RFC 5277 version.</text>
</description>
</revision>
<container name="netconf">
<description>
<text>Top-level element in the notification namespace</text>
</description>
<config value="false"/>
<container name="streams">
<description>
<text>The list of event streams supported by the system. When
a query is issued, the returned set of streams is
determined based on user privileges.</text>
</description>
<list name="stream">
<description>
<text>Stream name, description and other information.</text>
</description>
<key value="name"/>
<min-elements value="1"/>
<leaf name="name">
<description>
<text>The name of the event stream. If this is the default
NETCONF stream, this must have the value 'NETCONF'.</text>
</description>
<type name="ncEvent:streamNameType"/>
</leaf>
<leaf name="description">
<description>
<text>A description of the event stream, including such
information as the type of events that are sent over
this stream.</text>
</description>
<type name="string"/>
<mandatory value="true"/>
</leaf>
<leaf name="replaySupport">
<description>
<text>A description of the event stream, including such
information as the type of events that are sent over
this stream.</text>
</description>
<type name="boolean"/>
<mandatory value="true"/>
</leaf>
<leaf name="replayLogCreationTime">
<description>
<text>The timestamp of the creation of the log used to support
the replay function on this stream. Note that this might
be earlier then the earliest available notification in
the log. This object is updated if the log resets for
some reason. This object MUST be present if replay is
supported.</text>
</description>
<type name="yang:date-and-time"/>
</leaf>
</list>
</container>
</container>
<notification name="replayComplete">
<description>
<text>This notification is sent to signal the end of a replay
portion of a subscription.</text>
</description>
</notification>
<notification name="notificationComplete">
<description>
<text>This notification is sent to signal the end of a notification
subscription. It is sent in the case that stopTime was
specified during the creation of the subscription..</text>
</description>
</notification>
</module>

View file

@ -0,0 +1,10 @@
module notif1 {
namespace "n1";
prefix "n1";
notification n1 {
leaf first {
type string;
}
}
}

View file

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<module name="notifications"
xmlns="urn:ietf:params:xml:ns:yang:yin:1"
xmlns:ncEvent="urn:ietf:params:xml:ns:netconf:notification:1.0"
xmlns:yang="urn:ietf:params:xml:ns:yang:ietf-yang-types">
<namespace uri="urn:ietf:params:xml:ns:netconf:notification:1.0"/>
<prefix value="ncEvent"/>
<import module="ietf-yang-types">
<prefix value="yang"/>
</import>
<organization>
<text>IETF NETCONF WG</text>
</organization>
<contact>
<text>netconf@ops.ietf.org</text>
</contact>
<description>
<text>Conversion of the 'ncEvent' XSD in the
NETCONF Notifications RFC.</text>
</description>
<reference>
<text>RFC 5277.</text>
</reference>
<revision date="2008-07-14">
<description>
<text>RFC 5277 version.</text>
</description>
</revision>
<typedef name="streamNameType">
<description>
<text>The name of an event stream.</text>
</description>
<type name="string"/>
</typedef>
<rpc name="create-subscription">
<description>
<text>The command to create a notification subscription. It
takes as argument the name of the notification stream
and filter. Both of those options limit the content of
the subscription. In addition, there are two time-related
parameters, startTime and stopTime, which can be used to
select the time interval of interest to the notification
replay feature.</text>
</description>
<input>
<leaf name="stream">
<description>
<text>An optional parameter that indicates which stream of events
is of interest. If not present, then events in the default
NETCONF stream will be sent.</text>
</description>
<type name="streamNameType"/>
<default value="NETCONF"/>
</leaf>
<anyxml name="filter">
<description>
<text>An optional parameter that indicates which subset of all
possible events is of interest. The format of this
parameter is the same as that of the filter parameter
in the NETCONF protocol operations. If not present,
all events not precluded by other parameters will
be sent.</text>
</description>
</anyxml>
<leaf name="startTime">
<description>
<text>A parameter used to trigger the replay feature and
indicates that the replay should start at the time
specified. If start time is not present, this is not a
replay subscription.</text>
</description>
<type name="yang:date-and-time"/>
</leaf>
<leaf name="stopTime">
<description>
<text>An optional parameter used with the optional replay
feature to indicate the newest notifications of
interest. If stop time is not present, the notifications
will continue until the subscription is terminated.
Must be used with startTime.</text>
</description>
<type name="yang:date-and-time"/>
</leaf>
</input>
</rpc>
<container name="notification">
<description>
<text>internal struct to start a notification</text>
</description>
<config value="false"/>
<leaf name="eventTime">
<mandatory value="true"/>
<type name="yang:date-and-time"/>
</leaf>
</container>
</module>

9
tests/data/nc10/rpc-lock Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1">
<lock>
<target>
<running/>
</target>
</lock>
</rpc>
]]>]]>

7
tests/data/nc11/rpc-lock Normal file
View file

@ -0,0 +1,7 @@
#11
<rpc xmlns=
#103
"urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1"><lock><target><running/></target></lock></rpc>
##

26
tests/data/server.crt Normal file
View file

@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIETjCCAzYCFEO1ljvG2ET9vb1itRsNMb8xN0R3MA0GCSqGSIb3DQEBCwUAMGMx
CzAJBgNVBAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQHDARCcm5v
MQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzERMA8GA1UEAwwIc2VydmVy
Y2EwHhcNMjEwOTAzMTExNjMyWhcNMzEwOTAxMTExNjMyWjBkMQswCQYDVQQGEwJD
WjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwG
Q0VTTkVUMQwwCgYDVQQLDANUTUMxEjAQBgNVBAMMCTEyNy4wLjAuMTCCAiIwDQYJ
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAOqI7Y3w5r8kD9WZCMAaa/e3ig7nm76a
IJUR0Xb1bk6X/4FNVQKwEJsBodOYupZvE5FZdZ6DJSMSyQ3FrJWnlZ+isr7F9B4b
ELV8Kj6sJGuVAr+mpcH/4rwL3DaXF9Y9Lf7iBgiOHUoip80Asn9BU4q80JI6w2VH
d5ng4TUE67gmpRleIHzViKt3taBrsAJ9bS5bvaE6xOB8zKYGzRFOsDZrEqqcBsVI
WC6EmjO29HS5qj/mXM0ktFGnNDxTZHoRkNgmCE/NH+fNKOFxraCwlFBpKemAky+G
dgngRGiQAVowyAx/nSmCFAalKc+E4ddoFwD/oft6iOvvXqaXh6368wEQ7Hy48FDc
UCbHtUEgK4wMrX9BSrRh6zkXO1tE4ghb0dM2qFDS0ypO3p04kUPa31mTgLuOH1Lz
wmlwxOs113mlYKCgqOFR5YaN+nq1HI5RATPo5NvCMpG2RrQW+ooCr2GtbT0oHmJv
8yaBVY0HJ69eLnIv37dfjWvoTiBKBBIisXAD5Nm9rwSjZUSFu1iyd7u2YrkBCUzZ
uvt3BOPpX8GgQgagU6BPnac76FF6DMhRUXlBXdTuWsbuH14LdNIzGjkMZhNL/Tpk
f6S/z1iH5VReGc+clTjWGg1XO5fr3mNKBGa7hDydIZRIMbgsy63DIY7n5dqhNkO3
0CGmr/9TagVZAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAEjP2Zed4zY/nProMy67
JyI3vV2fDYpYUkPD7ofSjFHjQc3ooXfBCF6Ho0dCdBTpof6kGIjfDmhcKoVcPqr8
A/EA1pEGOB0RZkCjrwEnbAVdIb/5QP6nLtm7M5md3dEF+rttfBwisH6CV4XbXXZc
t/cNP+MPK2sXevCK2w8Xbt9nHeI/MXZoUW3WNGFwlRNlmQxCIoI0hnge9Gyb0WcT
ciHvhm8WtUQI1Ff3DLDgcQZQ1oOhci+ocBJVhC9l9lDCOpu93coyM7PD4CbVTFxf
nPnOy81525W6ya0nmZOKafG20bdc+T1LqMXM+uR5hBHsg9K6UbREHEoP3pLYW7zg
0Aw=
-----END CERTIFICATE-----

51
tests/data/server.key Normal file
View file

@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

27
tests/data/serverca.key Normal file
View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpgIBAAKCAQEAyMrKraqraFGklO2itRIEWxfuzWo1IwxZ22aJmeXDLeomt689
3NXelMLaC3swQ+hu49JjiIY81DXvbVgmIgLm7cAz5tHTHuJbfdI4Q6gyic4aOpy2
s3s1/vYz+1TvEUFCiPXEsJrH72he/z9nBxL8vY6Eg8U8EG8NvKp9zyCKA7vmNSgQ
OtuyF18fesYHAnvQjNXO5q6diPXdHOr2bjTRUvARGbWlv4Rvf81RwUkRsWoF/0pg
lV/TxnW2MoHnn3apxb/kmH92CQ+GWKxq5SkhvbkYePlA87kgKnDtXl4wEXIhYwM5
1kafRhhlAKN+qYeV9teBqGpjsZRYesrh3mXHlQIDAQABAoIBAQC0eeI2usKaX1fJ
LNckXW9g2WAhbicYu49ArydbFrOaX24xh+fYyLrph0IpM66sOw0A5SflnJKsQ1ZT
N/n+dBFQ/YMpIsvaZKbLrto3pcTXLFNS/20QYdyksHMEotDG95twM0d5XYX74BoS
3tAiAaT+VE0zi2Jzev4j6DJwq9ShiPclZFcpAbyVqi77ruJLID0j+lxLEOsTpN9h
Y/36CMwfAVe8OwiBl8vOAjEf3ssNz0iesEIB/Rx0rmg0dNquuYvJmF7pJNdQNq7Q
5fOM5Ww0iwqb8lzIU9fkMwFhljcxtc51nrr6mg8kKT1A0cDu4dJuYa6Od+IkW0nP
ozE7JDo5AoGBAPgfEwtsr/w5OFDtwiO+9wRxug+M6zuczeYIvK/FtDSghnZv18MK
HZJx6omApdgqF10ya5VuZg6VGBCO7DF20wORWriI7zPXIY0QBIw5zzEnMpw/wW6J
GSQ3KBBgVJKiSsv0pmf7h+pt2Tz/leh4bIgV7gryYyy2x+M0S5qk30EjAoGBAM8q
/PdTwpE8AKEr5LgQvSUpSXKl2tLewyK6XL7FMNIQxe8frlIeF+jgPsNFlWaVl+e6
qDksEqlltn2rmBRYVsSWFytpOHyVAfFtoJw1Qpa7bx3cYqA+jgIw3Lrva3AdircW
DG9sLjk4V3y5FJogXuNbeYj/exUq4CTzRwMoXIvnAoGBAOyHWvVaIA3WUkw7ywWe
hwZSj+dBFAHZAiMXEyCQ3LAKkwQWrF1+qCAxvj5kSDTgMzOh3BMwkdO256DpTln9
Bz1wdEZUK4uEurQpn9w5Q718u29eC7yerzvp5KRv4E+ErL7vMy8PBktBeoT+tN5O
5k94cFs5I7e9aqG5+ZSrNTR3AoGBAIln7djtiUNjFNfRkSY0k/+t3rVYJEdw0OSb
zyAJElSCI4Zy8OAubZVcBsTlxi4AUny0ZRdmkAojGGNKCNiVrxc8pal5ZKnc+yjy
mXCCMuRe9VhM8G1wkCgL2Jt0aUI3leXRjfXpPs9c+0oSSAPiLI2IAphHO4/SnFBl
u1fw0VFJAoGBAK+yZBxqo3nJqYhhPyvNUyEkDZJnuhcc7mQJsPd4AbgmeN/3izbI
2Rvn1wzkqz5LoCvAWAg51gWJBO99XvuT/J0ob4w494NtUYJdSq8Bg7dkebhdaAXl
lBXCI5kOmboHCaTsbJlXglxv7p6zkctU844p2Ki8XlkAbQTL+uQgZ6fE
-----END RSA PRIVATE KEY-----

22
tests/data/serverca.pem Normal file
View file

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDnDCCAoSgAwIBAgIJAIjf7UNx4uabMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV
BAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQHDARCcm5vMQ8wDQYD
VQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzERMA8GA1UEAwwIc2VydmVyY2EwHhcN
MTgxMTA1MDcyNjM5WhcNMjgxMTAyMDcyNjM5WjBjMQswCQYDVQQGEwJDWjETMBEG
A1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVU
MQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAyMrKraqraFGklO2itRIEWxfuzWo1IwxZ22aJmeXD
Leomt6893NXelMLaC3swQ+hu49JjiIY81DXvbVgmIgLm7cAz5tHTHuJbfdI4Q6gy
ic4aOpy2s3s1/vYz+1TvEUFCiPXEsJrH72he/z9nBxL8vY6Eg8U8EG8NvKp9zyCK
A7vmNSgQOtuyF18fesYHAnvQjNXO5q6diPXdHOr2bjTRUvARGbWlv4Rvf81RwUkR
sWoF/0pglV/TxnW2MoHnn3apxb/kmH92CQ+GWKxq5SkhvbkYePlA87kgKnDtXl4w
EXIhYwM51kafRhhlAKN+qYeV9teBqGpjsZRYesrh3mXHlQIDAQABo1MwUTAdBgNV
HQ4EFgQU60nJ4q3ItcfaOOBjJSqadAPiMg8wHwYDVR0jBBgwFoAU60nJ4q3Itcfa
OOBjJSqadAPiMg8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA
xIqIQ5SCXnKslZfrXiAEbB5dglxVOSa8me5a/70uHK/27JZ6veeIgRqZ4VgPHnBC
a3m6EHr+mnTjjqSUcGIUiKV3g2Dumw8paqZC+Qv+Ib/NKquS1lO2Ry1wHBtXzn5K
KHHyM1bWMDaDszirw2+pp22VdRrPZNA9NWXheEDYOLyQekyL2CfidhxhaXvUZyWg
alLyF2XRZ5/jAT+NjfWw39EmWPUGk13Jm83OaFc1VdrXNCiD0sGCQ+BTCllDinQv
R08yzd4fzA3YXthvX1dBu1SvqQAGOS7gssRCyv9uWI6MXta25X91eY1ZMz1euJ04
mB8EdyYiZc0kzrb9dv5d0g==
-----END CERTIFICATE-----

10
tests/ld.supp Normal file
View file

@ -0,0 +1,10 @@
{
ld
Memcheck:Leak
match-leak-kinds: reachable
fun:calloc
fun:_dlerror_run
fun:dlopen@@GLIBC_2.2.5
fun:lyext_load_plugins
fun:ly_ctx_new
}

View file

@ -0,0 +1,77 @@
/**
* \file test_client_thread.c
* \author Radek Krejci <rkrejci@cesnet.cz>
* \brief libnetconf2 tests - threads functions in client
*
* Copyright (c) 2017 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <libyang/libyang.h>
#include <session_client.h>
#include "tests/config.h"
#define nc_assert(cond) if (!(cond)) { fprintf(stderr, "assert failed (%s:%d)\n", __FILE__, __LINE__); exit(1); }
static void *
thread(void *arg)
{
/* default search path is NULL */
nc_assert(nc_client_get_schema_searchpath() == NULL);
/* use the context shared from the main thread */
nc_client_set_thread_context(arg);
/* check that we have now the search path set in main thread */
nc_assert(strcmp(nc_client_get_schema_searchpath(), "/tmp") == 0);
/* and change it to check it later in main thread */
nc_assert(nc_client_set_schema_searchpath("/etc") == 0)
return NULL;
}
int
main(void)
{
void *arg;
pthread_t t;
int r;
nc_client_init();
/*
* TEST sharing the thread context
*/
nc_assert(nc_client_set_schema_searchpath("/tmp") == 0)
/* get the context for sharing */
arg = nc_client_get_thread_context();
/* create new thread and provide the context */
r = pthread_create(&t, NULL, &thread, arg);
nc_assert(r == 0);
pthread_join(t, NULL);
/* check the changed search path value from the thread */
nc_assert(strcmp(nc_client_get_schema_searchpath(), "/etc") == 0);
/* cleanup */
nc_client_destroy();
return EXIT_SUCCESS;
}

555
tests/test_fd_comm.c Normal file
View file

@ -0,0 +1,555 @@
/**
* \file test_fd_comm.c
* \author Michal Vasko <mvasko@cesnet.cz>
* \brief libnetconf2 tests - file descriptor basic RPC communication
*
* Copyright (c) 2015 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cmocka.h>
#include <libyang/libyang.h>
#include <messages_p.h>
#include <session_client.h>
#include <session_p.h>
#include <session_server.h>
#include "tests/config.h"
struct nc_session *server_session;
struct nc_session *client_session;
struct ly_ctx *ctx;
pthread_mutex_t state_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_barrier_t barrier;
int glob_state;
struct nc_server_reply *
my_get_rpc_clb(struct lyd_node *rpc, struct nc_session *session)
{
assert_string_equal(rpc->schema->name, "get");
assert_ptr_equal(session, server_session);
return nc_server_reply_ok();
}
struct nc_server_reply *
my_getconfig_rpc_clb(struct lyd_node *rpc, struct nc_session *session)
{
struct lyd_node *data;
assert_string_equal(rpc->schema->name, "get-config");
assert_ptr_equal(session, server_session);
lyd_new_path(NULL, session->ctx, "/ietf-netconf:get-config/data", NULL, LYD_NEW_PATH_OUTPUT, &data);
assert_non_null(data);
return nc_server_reply_data(data, NC_WD_EXPLICIT, NC_PARAMTYPE_FREE);
}
struct nc_server_reply *
my_commit_rpc_clb(struct lyd_node *rpc, struct nc_session *session)
{
assert_string_equal(rpc->schema->name, "commit");
assert_ptr_equal(session, server_session);
/* update state */
pthread_mutex_lock(&state_lock);
glob_state = 1;
/* wait until the client receives the notification */
while (glob_state != 3) {
pthread_mutex_unlock(&state_lock);
usleep(100000);
pthread_mutex_lock(&state_lock);
}
pthread_mutex_unlock(&state_lock);
return nc_server_reply_ok();
}
static struct nc_session *
test_new_session(NC_SIDE side)
{
struct nc_session *sess;
sess = calloc(1, sizeof *sess);
if (!sess) {
return NULL;
}
sess->side = side;
if (side == NC_SERVER) {
pthread_mutex_init(&sess->opts.server.rpc_lock, NULL);
pthread_cond_init(&sess->opts.server.rpc_cond, NULL);
sess->opts.server.rpc_inuse = 0;
}
sess->io_lock = malloc(sizeof *sess->io_lock);
if (!sess->io_lock) {
goto error;
}
pthread_mutex_init(sess->io_lock, NULL);
return sess;
error:
free(sess);
return NULL;
}
static int
setup_sessions(void **state)
{
(void)state;
int sock[2];
/* create communication channel */
socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
/* create server session */
server_session = test_new_session(NC_SERVER);
server_session->status = NC_STATUS_RUNNING;
server_session->id = 1;
server_session->ti_type = NC_TI_FD;
server_session->ti.fd.in = sock[0];
server_session->ti.fd.out = sock[0];
server_session->ctx = ctx;
server_session->flags = NC_SESSION_SHAREDCTX;
/* create client session */
client_session = test_new_session(NC_CLIENT);
client_session->status = NC_STATUS_RUNNING;
client_session->id = 1;
client_session->ti_type = NC_TI_FD;
client_session->ti.fd.in = sock[1];
client_session->ti.fd.out = sock[1];
client_session->ctx = ctx;
client_session->flags = NC_SESSION_SHAREDCTX;
client_session->opts.client.msgid = 50;
return 0;
}
static int
teardown_sessions(void **state)
{
(void)state;
close(server_session->ti.fd.in);
server_session->ti.fd.in = -1;
nc_session_free(server_session, NULL);
close(client_session->ti.fd.in);
client_session->ti.fd.in = -1;
nc_session_free(client_session, NULL);
return 0;
}
static void
test_send_recv_ok(void)
{
int ret;
uint64_t msgid;
NC_MSG_TYPE msgtype;
struct nc_rpc *rpc;
struct lyd_node *envp, *op;
struct nc_pollsession *ps;
/* client RPC */
rpc = nc_rpc_get(NULL, 0, 0);
assert_non_null(rpc);
msgtype = nc_send_rpc(client_session, rpc, 0, &msgid);
assert_int_equal(msgtype, NC_MSG_RPC);
/* server RPC, send reply */
ps = nc_ps_new();
assert_non_null(ps);
nc_ps_add_session(ps, server_session);
ret = nc_ps_poll(ps, 0, NULL);
assert_int_equal(ret, NC_PSPOLL_RPC);
/* server finished */
nc_ps_free(ps);
/* client reply */
msgtype = nc_recv_reply(client_session, rpc, msgid, 0, &envp, &op);
assert_int_equal(msgtype, NC_MSG_REPLY);
nc_rpc_free(rpc);
assert_null(op);
assert_string_equal(LYD_NAME(lyd_child(envp)), "ok");
lyd_free_tree(envp);
}
static void
test_send_recv_ok_10(void **state)
{
(void)state;
server_session->version = NC_VERSION_10;
client_session->version = NC_VERSION_10;
test_send_recv_ok();
}
static void
test_send_recv_ok_11(void **state)
{
(void)state;
server_session->version = NC_VERSION_11;
client_session->version = NC_VERSION_11;
test_send_recv_ok();
}
static void
test_send_recv_error(void)
{
int ret;
uint64_t msgid;
NC_MSG_TYPE msgtype;
struct nc_rpc *rpc;
struct lyd_node *envp, *op, *node;
struct nc_pollsession *ps;
/* client RPC */
rpc = nc_rpc_kill(1);
assert_non_null(rpc);
msgtype = nc_send_rpc(client_session, rpc, 0, &msgid);
assert_int_equal(msgtype, NC_MSG_RPC);
/* server RPC, send reply */
ps = nc_ps_new();
assert_non_null(ps);
nc_ps_add_session(ps, server_session);
ret = nc_ps_poll(ps, 0, NULL);
assert_int_equal(ret, NC_PSPOLL_RPC | NC_PSPOLL_REPLY_ERROR);
/* server finished */
nc_ps_free(ps);
/* client reply */
msgtype = nc_recv_reply(client_session, rpc, msgid, 0, &envp, &op);
assert_int_equal(msgtype, NC_MSG_REPLY);
nc_rpc_free(rpc);
assert_string_equal(LYD_NAME(lyd_child(envp)), "rpc-error");
lyd_find_sibling_opaq_next(lyd_child(lyd_child(envp)), "error-tag", &node);
assert_non_null(node);
assert_string_equal(((struct lyd_node_opaq *)node)->value, "operation-not-supported");
lyd_free_tree(envp);
assert_null(op);
}
static void
test_send_recv_error_10(void **state)
{
(void)state;
server_session->version = NC_VERSION_10;
client_session->version = NC_VERSION_10;
test_send_recv_error();
}
static void
test_send_recv_error_11(void **state)
{
(void)state;
server_session->version = NC_VERSION_11;
client_session->version = NC_VERSION_11;
test_send_recv_error();
}
static void
test_send_recv_data(void)
{
int ret;
uint64_t msgid;
NC_MSG_TYPE msgtype;
struct nc_rpc *rpc;
struct lyd_node *envp, *op;
struct nc_pollsession *ps;
/* client RPC */
rpc = nc_rpc_getconfig(NC_DATASTORE_RUNNING, NULL, 0, 0);
assert_non_null(rpc);
msgtype = nc_send_rpc(client_session, rpc, 0, &msgid);
assert_int_equal(msgtype, NC_MSG_RPC);
/* server RPC, send reply */
ps = nc_ps_new();
assert_non_null(ps);
nc_ps_add_session(ps, server_session);
ret = nc_ps_poll(ps, 0, NULL);
assert_int_equal(ret, NC_PSPOLL_RPC);
/* server finished */
nc_ps_free(ps);
/* client reply */
msgtype = nc_recv_reply(client_session, rpc, msgid, 0, &envp, &op);
assert_int_equal(msgtype, NC_MSG_REPLY);
nc_rpc_free(rpc);
assert_non_null(envp);
lyd_free_tree(envp);
assert_non_null(op);
lyd_free_tree(op);
}
static void
test_send_recv_data_10(void **state)
{
(void)state;
server_session->version = NC_VERSION_10;
client_session->version = NC_VERSION_10;
test_send_recv_data();
}
static void
test_send_recv_data_11(void **state)
{
(void)state;
server_session->version = NC_VERSION_11;
client_session->version = NC_VERSION_11;
test_send_recv_data();
}
static void *
server_send_notif_thread(void *arg)
{
NC_MSG_TYPE msg_type;
struct lyd_node *notif_tree;
struct nc_server_notif *notif;
struct timespec ts;
char *buf;
(void)arg;
/* wait for the RPC callback to be called */
pthread_mutex_lock(&state_lock);
while (glob_state != 1) {
pthread_mutex_unlock(&state_lock);
usleep(1000);
pthread_mutex_lock(&state_lock);
}
/* create notif */
lyd_new_path(NULL, ctx, "/nc-notifications:notificationComplete", NULL, 0, &notif_tree);
assert_non_null(notif_tree);
clock_gettime(CLOCK_REALTIME, &ts);
ly_time_ts2str(&ts, &buf);
notif = nc_server_notif_new(notif_tree, buf, NC_PARAMTYPE_FREE);
assert_non_null(notif);
/* send notif */
nc_session_inc_notif_status(server_session);
msg_type = nc_server_notif_send(server_session, notif, 100);
nc_server_notif_free(notif);
assert_int_equal(msg_type, NC_MSG_NOTIF);
/* update state */
glob_state = 2;
pthread_barrier_wait(&barrier);
pthread_mutex_unlock(&state_lock);
return NULL;
}
static void *
thread_recv_notif(void *arg)
{
struct nc_session *session = (struct nc_session *)arg;
struct lyd_node *envp;
struct lyd_node *op;
NC_MSG_TYPE msgtype;
pthread_barrier_wait(&barrier);
msgtype = nc_recv_notif(session, 1000, &envp, &op);
assert_int_equal(msgtype, NC_MSG_NOTIF);
assert_string_equal(op->schema->name, "notificationComplete");
lyd_free_tree(envp);
lyd_free_tree(op);
pthread_mutex_lock(&state_lock);
glob_state = 3;
pthread_mutex_unlock(&state_lock);
return (void *)0;
}
static void
test_send_recv_notif(void)
{
int ret;
pthread_t tid[2];
uint64_t msgid;
NC_MSG_TYPE msgtype;
struct nc_rpc *rpc;
struct lyd_node *envp, *op;
struct nc_pollsession *ps;
/* client RPC */
rpc = nc_rpc_commit(0, 0, NULL, NULL, 0);
assert_non_null(rpc);
msgtype = nc_send_rpc(client_session, rpc, 0, &msgid);
assert_int_equal(msgtype, NC_MSG_RPC);
/* client subscription */
pthread_create(&tid[0], NULL, thread_recv_notif, client_session);
/* create server */
ps = nc_ps_new();
assert_non_null(ps);
nc_ps_add_session(ps, server_session);
/* server will send a notification */
pthread_mutex_lock(&state_lock);
glob_state = 0;
pthread_mutex_unlock(&state_lock);
ret = pthread_create(&tid[1], NULL, server_send_notif_thread, NULL);
assert_int_equal(ret, 0);
/* server blocked on RPC */
ret = nc_ps_poll(ps, 0, NULL);
assert_int_equal(ret, NC_PSPOLL_RPC);
/* RPC, notification finished fine */
pthread_mutex_lock(&state_lock);
assert_int_equal(glob_state, 3);
pthread_mutex_unlock(&state_lock);
/* server finished */
ret = 0;
ret |= pthread_join(tid[0], NULL);
ret |= pthread_join(tid[1], NULL);
assert_int_equal(ret, 0);
nc_ps_free(ps);
/* client reply */
msgtype = nc_recv_reply(client_session, rpc, msgid, 0, &envp, &op);
assert_int_equal(msgtype, NC_MSG_REPLY);
nc_rpc_free(rpc);
assert_string_equal(LYD_NAME(lyd_child(envp)), "ok");
lyd_free_tree(envp);
assert_null(op);
}
static void
test_send_recv_notif_10(void **state)
{
(void)state;
server_session->version = NC_VERSION_10;
client_session->version = NC_VERSION_10;
test_send_recv_notif();
}
static void
test_send_recv_notif_11(void **state)
{
(void)state;
server_session->version = NC_VERSION_11;
client_session->version = NC_VERSION_11;
test_send_recv_notif();
}
int
main(void)
{
int ret;
const struct lys_module *module;
struct lysc_node *node;
const char *nc_features[] = {"candidate", NULL};
pthread_barrier_init(&barrier, NULL, 2);
/* create ctx */
ly_ctx_new(TESTS_DIR "/data/modules", 0, &ctx);
assert_non_null(ctx);
/* load modules */
module = ly_ctx_load_module(ctx, "ietf-netconf-acm", NULL, NULL);
assert_non_null(module);
module = ly_ctx_load_module(ctx, "ietf-netconf", NULL, nc_features);
assert_non_null(module);
module = ly_ctx_load_module(ctx, "nc-notifications", NULL, NULL);
assert_non_null(module);
/* set RPC callbacks */
node = (struct lysc_node *)lys_find_path(module->ctx, NULL, "/ietf-netconf:get", 0);
assert_non_null(node);
node->priv = my_get_rpc_clb;
node = (struct lysc_node *)lys_find_path(module->ctx, NULL, "/ietf-netconf:get-config", 0);
assert_non_null(node);
node->priv = my_getconfig_rpc_clb;
node = (struct lysc_node *)lys_find_path(module->ctx, NULL, "/ietf-netconf:commit", 0);
assert_non_null(node);
node->priv = my_commit_rpc_clb;
nc_server_init(ctx);
const struct CMUnitTest comm[] = {
cmocka_unit_test_setup_teardown(test_send_recv_ok_10, setup_sessions, teardown_sessions),
cmocka_unit_test_setup_teardown(test_send_recv_error_10, setup_sessions, teardown_sessions),
cmocka_unit_test_setup_teardown(test_send_recv_data_10, setup_sessions, teardown_sessions),
cmocka_unit_test_setup_teardown(test_send_recv_notif_10, setup_sessions, teardown_sessions),
cmocka_unit_test_setup_teardown(test_send_recv_ok_11, setup_sessions, teardown_sessions),
cmocka_unit_test_setup_teardown(test_send_recv_error_11, setup_sessions, teardown_sessions),
cmocka_unit_test_setup_teardown(test_send_recv_data_11, setup_sessions, teardown_sessions),
cmocka_unit_test_setup_teardown(test_send_recv_notif_11, setup_sessions, teardown_sessions),
};
ret = cmocka_run_group_tests(comm, NULL, NULL);
nc_server_destroy();
ly_ctx_destroy(ctx);
pthread_barrier_destroy(&barrier);
return ret;
}

View file

@ -0,0 +1,69 @@
/**
* \file test_init_destroy_client.c
* \author Michal Vasko <mvasko@cesnet.cz>
* \brief libnetconf2 tests - init/destroy client
*
* Copyright (c) 2015 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cmocka.h>
#include <libyang/libyang.h>
#include <session_client.h>
#include "tests/config.h"
static int
setup_client(void **state)
{
(void)state;
nc_client_init();
return 0;
}
static int
teardown_client(void **state)
{
(void)state;
nc_client_destroy();
return 0;
}
static void
test_dummy(void **state)
{
(void)state;
}
int
main(void)
{
const struct CMUnitTest init_destroy[] = {
cmocka_unit_test_setup_teardown(test_dummy, setup_client, teardown_client)
};
return cmocka_run_group_tests(init_destroy, NULL, NULL);
}

View file

@ -0,0 +1,75 @@
/**
* \file test_init_destroy_server.c
* \author Michal Vasko <mvasko@cesnet.cz>
* \brief libnetconf2 tests - init/destroy server
*
* Copyright (c) 2015 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cmocka.h>
#include <libyang/libyang.h>
#include <session_server.h>
#include "tests/config.h"
struct ly_ctx *ctx;
static int
setup_server(void **state)
{
(void)state;
ly_ctx_new(NULL, 0, &ctx);
assert_non_null(ctx);
nc_server_init(ctx);
return 0;
}
static int
teardown_server(void **state)
{
(void)state;
nc_server_destroy();
ly_ctx_destroy(ctx);
return 0;
}
static void
test_dummy(void **state)
{
(void)state;
}
int
main(void)
{
const struct CMUnitTest init_destroy[] = {
cmocka_unit_test_setup_teardown(test_dummy, setup_server, teardown_server)
};
return cmocka_run_group_tests(init_destroy, NULL, NULL);
}

186
tests/test_io.c Normal file
View file

@ -0,0 +1,186 @@
/**
* \file test_io.c
* \author Radek Krejci <rkrejci@cesnet.cz>
* \brief libnetconf2 tests - input/output functions
*
* Copyright (c) 2015 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cmocka.h>
#include <libyang/libyang.h>
#include <messages_p.h>
#include <session_client.h>
#include <session_p.h>
#include "tests/config.h"
struct wr {
struct nc_session *session;
struct nc_rpc *rpc;
};
static int
setup_write(void **state)
{
(void) state; /* unused */
int fd, pipes[2];
struct wr *w;
w = malloc(sizeof *w);
w->session = calloc(1, sizeof *w->session);
ly_ctx_new(TESTS_DIR "/data/modules", 0, &w->session->ctx);
/* ietf-netconf */
fd = open(TESTS_DIR "/data/modules/ietf-netconf.yin", O_RDONLY);
if (fd == -1) {
free(w);
return -1;
}
lys_parse_fd(w->session->ctx, fd, LYS_IN_YIN, NULL);
close(fd);
assert_return_code(pipe(pipes), errno);
w->session->status = NC_STATUS_RUNNING;
w->session->version = NC_VERSION_10;
w->session->opts.client.msgid = 999;
w->session->ti_type = NC_TI_FD;
w->session->io_lock = malloc(sizeof *w->session->io_lock);
pthread_mutex_init(w->session->io_lock, NULL);
w->session->ti.fd.in = pipes[0];
w->session->ti.fd.out = pipes[1];
/* get rpc to write */
w->rpc = nc_rpc_lock(NC_DATASTORE_RUNNING);
assert_non_null(w->rpc);
*state = w;
return 0;
}
static int
teardown_write(void **state)
{
struct wr *w = (struct wr *)*state;
nc_rpc_free(w->rpc);
close(w->session->ti.fd.in);
w->session->ti.fd.in = -1;
close(w->session->ti.fd.out);
w->session->ti.fd.out = -1;
nc_session_free(w->session, NULL);
free(w);
*state = NULL;
return 0;
}
static void
test_write_rpc(void **state)
{
struct wr *w = (struct wr *)*state;
uint64_t msgid;
NC_MSG_TYPE type;
w->session->side = NC_CLIENT;
do {
type = nc_send_rpc(w->session, w->rpc, 1000, &msgid);
} while (type == NC_MSG_WOULDBLOCK);
assert_int_equal(type, NC_MSG_RPC);
assert_int_equal(write(w->session->ti.fd.out, "\n", 1), 1);
}
static void
test_write_rpc_10(void **state)
{
struct wr *w = (struct wr *)*state;
w->session->version = NC_VERSION_10;
return test_write_rpc(state);
}
static void
test_write_rpc_11(void **state)
{
struct wr *w = (struct wr *)*state;
w->session->version = NC_VERSION_11;
return test_write_rpc(state);
}
static void
test_write_rpc_bad(void **state)
{
struct wr *w = (struct wr *)*state;
uint64_t msgid;
NC_MSG_TYPE type;
w->session->side = NC_SERVER;
pthread_mutex_init(&w->session->opts.server.rpc_lock, NULL);
pthread_cond_init(&w->session->opts.server.rpc_cond, NULL);
w->session->opts.server.rpc_inuse = 0;
do {
type = nc_send_rpc(w->session, w->rpc, 1000, &msgid);
} while (type == NC_MSG_WOULDBLOCK);
assert_int_equal(type, NC_MSG_ERROR);
}
static void
test_write_rpc_10_bad(void **state)
{
struct wr *w = (struct wr *)*state;
w->session->version = NC_VERSION_10;
return test_write_rpc_bad(state);
}
static void
test_write_rpc_11_bad(void **state)
{
struct wr *w = (struct wr *)*state;
w->session->version = NC_VERSION_11;
return test_write_rpc_bad(state);
}
int
main(void)
{
const struct CMUnitTest io[] = {
cmocka_unit_test_setup_teardown(test_write_rpc_10, setup_write, teardown_write),
cmocka_unit_test_setup_teardown(test_write_rpc_10_bad, setup_write, teardown_write),
cmocka_unit_test_setup_teardown(test_write_rpc_11, setup_write, teardown_write),
cmocka_unit_test_setup_teardown(test_write_rpc_11_bad, setup_write, teardown_write)
};
return cmocka_run_group_tests(io, NULL, NULL);
}

765
tests/test_server_thread.c Normal file
View file

@ -0,0 +1,765 @@
/**
* \file test_server_thread.c
* \author Michal Vasko <mvasko@cesnet.cz>
* \brief libnetconf2 tests - thread-safety of all server functions
*
* Copyright (c) 2017 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <libyang/libyang.h>
#include <log.h>
#include <session_client.h>
#include <session_server.h>
#include "tests/config.h"
/* millisec */
#define NC_ACCEPT_TIMEOUT 5000
/* millisec */
#define NC_PS_POLL_TIMEOUT 5000
/* sec */
#define CLIENT_SSH_AUTH_TIMEOUT 10
#define nc_assert(cond) if (!(cond)) { fprintf(stderr, "assert failed (%s:%d)\n", __FILE__, __LINE__); exit(1); }
#if _POSIX_BARRIERS >= 200112L
pthread_barrier_t barrier;
#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS)
static void *
server_thread(void *arg)
{
(void)arg;
NC_MSG_TYPE msgtype;
int ret;
struct nc_pollsession *ps;
struct nc_session *session;
ps = nc_ps_new();
nc_assert(ps);
pthread_barrier_wait(&barrier);
#if defined (NC_ENABLED_SSH) && defined (NC_ENABLED_TLS)
msgtype = nc_accept(NC_ACCEPT_TIMEOUT, &session);
nc_assert(msgtype == NC_MSG_HELLO);
nc_ps_add_session(ps, session);
ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL);
nc_assert(ret & NC_PSPOLL_RPC);
nc_ps_clear(ps, 0, NULL);
#endif
msgtype = nc_accept(NC_ACCEPT_TIMEOUT, &session);
nc_assert(msgtype == NC_MSG_HELLO);
nc_ps_add_session(ps, session);
ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL);
nc_assert(ret & NC_PSPOLL_RPC);
nc_ps_clear(ps, 0, NULL);
nc_ps_free(ps);
nc_thread_destroy();
return NULL;
}
#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */
#ifdef NC_ENABLED_SSH
static int
clb_hostkeys(const char *name, void *UNUSED(user_data), char **privkey_path, char **UNUSED(privkey_data),
NC_SSH_KEY_TYPE *UNUSED(privkey_type))
{
if (!strcmp(name, "key_rsa")) {
*privkey_path = strdup(TESTS_DIR "/data/key_rsa");
return 0;
} else if (!strcmp(name, "key_dsa")) {
*privkey_path = strdup(TESTS_DIR "/data/key_dsa");
return 0;
}
return 1;
}
static void *
add_endpt_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_add_endpt("tertiary", NC_TI_LIBSSH);
nc_assert(!ret);
return NULL;
}
static void *
del_endpt_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_del_endpt("secondary", 0);
nc_assert(!ret);
return NULL;
}
static void *
ssh_endpt_set_hostkey_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_ssh_endpt_add_hostkey("main_ssh", "key_dsa", -1);
nc_assert(!ret);
return NULL;
}
static void *
ssh_endpt_set_auth_methods_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_ssh_endpt_set_auth_methods("main_ssh", NC_SSH_AUTH_PUBLICKEY | NC_SSH_AUTH_PASSWORD | NC_SSH_AUTH_INTERACTIVE);
nc_assert(!ret);
return NULL;
}
static void *
ssh_endpt_set_auth_attempts_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_ssh_endpt_set_auth_attempts("main_ssh", 2);
nc_assert(!ret);
return NULL;
}
static void *
ssh_endpt_set_auth_timeout_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_ssh_endpt_set_auth_timeout("main_ssh", 5);
nc_assert(!ret);
return NULL;
}
static void *
ssh_endpt_add_authkey_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_ssh_add_authkey_path(TESTS_DIR "/data/key_rsa.pub", "test3");
nc_assert(!ret);
return NULL;
}
static void *
ssh_endpt_del_authkey_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_ssh_del_authkey(TESTS_DIR "/data/key_dsa.pub", NULL, 0, "test2");
nc_assert(!ret);
return NULL;
}
static int
ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv)
{
(void)hostname;
(void)session;
(void)priv;
return 0;
}
static void *
ssh_client_thread(void *arg)
{
int ret, read_pipe = *(int *)arg;
char buf[9];
struct nc_session *session;
fprintf(stdout, "SSH client start.\n");
ret = read(read_pipe, buf, 9);
nc_assert(ret == 9);
nc_assert(!strncmp(buf, "ssh_ready", 9));
/* skip the knownhost check */
nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL);
ret = nc_client_ssh_set_username("test");
nc_assert(!ret);
ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_ecdsa.pub", TESTS_DIR "/data/key_ecdsa");
nc_assert(!ret);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
session = nc_connect_ssh("127.0.0.1", 6001, NULL);
nc_assert(session);
nc_session_free(session, NULL);
fprintf(stdout, "SSH client finished.\n");
nc_thread_destroy();
return NULL;
}
#endif /* NC_ENABLED_SSH */
#ifdef NC_ENABLED_TLS
static int
clb_server_cert(const char *name, void *UNUSED(user_data), char **cert_path, char **cert_data, char **privkey_path,
char **privkey_data, NC_SSH_KEY_TYPE *privkey_type)
{
if (!strcmp(name, "server_cert1")) {
*cert_data = strdup("MIIEQDCCAygCCQCV65JgDvfWkTANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJD\n"
"WjETMBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwG\n"
"Q0VTTkVUMQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMB4XDTE4MTEw\n"
"NTA3MzExMFoXDTI4MTEwMjA3MzExMFowYTELMAkGA1UEBhMCQ1oxEzARBgNVBAgM\n"
"ClNvbWUtU3RhdGUxDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEMMAoG\n"
"A1UECwwDVE1DMQ8wDQYDVQQDDAZzZXJ2ZXIwggIiMA0GCSqGSIb3DQEBAQUAA4IC\n"
"DwAwggIKAoICAQDqiO2N8Oa/JA/VmQjAGmv3t4oO55u+miCVEdF29W5Ol/+BTVUC\n"
"sBCbAaHTmLqWbxORWXWegyUjEskNxayVp5WforK+xfQeGxC1fCo+rCRrlQK/pqXB\n"
"/+K8C9w2lxfWPS3+4gYIjh1KIqfNALJ/QVOKvNCSOsNlR3eZ4OE1BOu4JqUZXiB8\n"
"1Yird7Wga7ACfW0uW72hOsTgfMymBs0RTrA2axKqnAbFSFguhJoztvR0uao/5lzN\n"
"JLRRpzQ8U2R6EZDYJghPzR/nzSjhca2gsJRQaSnpgJMvhnYJ4ERokAFaMMgMf50p\n"
"ghQGpSnPhOHXaBcA/6H7eojr716ml4et+vMBEOx8uPBQ3FAmx7VBICuMDK1/QUq0\n"
"Yes5FztbROIIW9HTNqhQ0tMqTt6dOJFD2t9Zk4C7jh9S88JpcMTrNdd5pWCgoKjh\n"
"UeWGjfp6tRyOUQEz6OTbwjKRtka0FvqKAq9hrW09KB5ib/MmgVWNByevXi5yL9+3\n"
"X41r6E4gSgQSIrFwA+TZva8Eo2VEhbtYsne7tmK5AQlM2br7dwTj6V/BoEIGoFOg\n"
"T52nO+hRegzIUVF5QV3U7lrG7h9eC3TSMxo5DGYTS/06ZH+kv89Yh+VUXhnPnJU4\n"
"1hoNVzuX695jSgRmu4Q8nSGUSDG4LMutwyGO5+XaoTZDt9Ahpq//U2oFWQIDAQAB\n"
"MA0GCSqGSIb3DQEBCwUAA4IBAQAXWHf/MG8RPCyA0rC3RwxmM70ndyKPIJoL4ggU\n"
"VgkN66BdpsE4UlWdlp0XL3aauMPxzLn9rq1yRtoHWT4/ucL9iEa6B295JBNjkgW+\n"
"ct9/y8060P9BUhY1DTv5DLzitsA4bjRaraIevjATDPfsbHFx9DTNrS5pXHIFbRcz\n"
"y3WniYXTKhpfM6m+1X8ogImE968DG8RqAW5YZZtrZW0VF/dhlQp20jEX/8Rv33Bp\n"
"RhNEIhPnYAquKCesMMclUtPW+5n2z8rgj5t/ETv4wc5QegpyPfdHNq09bGKB10Sy\n"
"sGvC6hP9GKU3R2Jhxih/t88O3WoisFQ8+Tf9s2LuSxUV0bzp");
*privkey_data = strdup("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");
*privkey_type = NC_SSH_KEY_RSA;
return 0;
} else if (!strcmp(name, "main_cert")) {
*cert_path = strdup(TESTS_DIR "/data/server.crt");
*privkey_path = strdup(TESTS_DIR "/data/server.key");
return 0;
}
return 1;
}
static int
clb_trusted_cert_lists(const char *name, void *UNUSED(user_data), char ***cert_paths, int *cert_path_count,
char ***cert_data, int *cert_data_count)
{
if (!strcmp(name, "trusted_cert_list1")) {
*cert_data = malloc(sizeof **cert_data);
(*cert_data)[0] = strdup("MIIDnDCCAoSgAwIBAgIJAIjf7UNx4uabMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV\n"
"BAYTAkNaMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQHDARCcm5vMQ8wDQYD\n"
"VQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzERMA8GA1UEAwwIc2VydmVyY2EwHhcN\n"
"MTgxMTA1MDcyNjM5WhcNMjgxMTAyMDcyNjM5WjBjMQswCQYDVQQGEwJDWjETMBEG\n"
"A1UECAwKU29tZS1TdGF0ZTENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGQ0VTTkVU\n"
"MQwwCgYDVQQLDANUTUMxETAPBgNVBAMMCHNlcnZlcmNhMIIBIjANBgkqhkiG9w0B\n"
"AQEFAAOCAQ8AMIIBCgKCAQEAyMrKraqraFGklO2itRIEWxfuzWo1IwxZ22aJmeXD\n"
"Leomt6893NXelMLaC3swQ+hu49JjiIY81DXvbVgmIgLm7cAz5tHTHuJbfdI4Q6gy\n"
"ic4aOpy2s3s1/vYz+1TvEUFCiPXEsJrH72he/z9nBxL8vY6Eg8U8EG8NvKp9zyCK\n"
"A7vmNSgQOtuyF18fesYHAnvQjNXO5q6diPXdHOr2bjTRUvARGbWlv4Rvf81RwUkR\n"
"sWoF/0pglV/TxnW2MoHnn3apxb/kmH92CQ+GWKxq5SkhvbkYePlA87kgKnDtXl4w\n"
"EXIhYwM51kafRhhlAKN+qYeV9teBqGpjsZRYesrh3mXHlQIDAQABo1MwUTAdBgNV\n"
"HQ4EFgQU60nJ4q3ItcfaOOBjJSqadAPiMg8wHwYDVR0jBBgwFoAU60nJ4q3Itcfa\n"
"OOBjJSqadAPiMg8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA\n"
"xIqIQ5SCXnKslZfrXiAEbB5dglxVOSa8me5a/70uHK/27JZ6veeIgRqZ4VgPHnBC\n"
"a3m6EHr+mnTjjqSUcGIUiKV3g2Dumw8paqZC+Qv+Ib/NKquS1lO2Ry1wHBtXzn5K\n"
"KHHyM1bWMDaDszirw2+pp22VdRrPZNA9NWXheEDYOLyQekyL2CfidhxhaXvUZyWg\n"
"alLyF2XRZ5/jAT+NjfWw39EmWPUGk13Jm83OaFc1VdrXNCiD0sGCQ+BTCllDinQv\n"
"R08yzd4fzA3YXthvX1dBu1SvqQAGOS7gssRCyv9uWI6MXta25X91eY1ZMz1euJ04\n"
"mB8EdyYiZc0kzrb9dv5d0g==");
*cert_data_count = 1;
return 0;
} else if (!strcmp(name, "client_cert_list")) {
*cert_paths = malloc(sizeof **cert_paths);
(*cert_paths)[0] = strdup(TESTS_DIR "/data/client.crt");
*cert_path_count = 1;
return 0;
}
return 1;
}
static void *
endpt_set_address_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_endpt_set_address("quaternary", "0.0.0.0");
nc_assert(!ret);
return NULL;
}
static void *
endpt_set_port_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_endpt_set_port("quaternary", 6003);
nc_assert(!ret);
return NULL;
}
static void *
tls_endpt_set_server_cert_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_tls_endpt_set_server_cert("quaternary", "server_cert1");
nc_assert(!ret);
nc_thread_destroy();
return NULL;
}
static void *
tls_endpt_add_trusted_cert_list_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_tls_endpt_add_trusted_cert_list("quaternary", "trusted_cert_list1");
nc_assert(!ret);
nc_thread_destroy();
return NULL;
}
static void *
tls_endpt_set_trusted_ca_paths_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_tls_endpt_set_trusted_ca_paths("quaternary", TESTS_DIR "/data/serverca.pem", "data");
nc_assert(!ret);
nc_thread_destroy();
return NULL;
}
static void *
tls_endpt_del_trusted_cert_list_thread(void *arg)
{
(void)arg;
pthread_barrier_wait(&barrier);
nc_server_tls_endpt_del_trusted_cert_list("quaternary", "trusted_cert_list1");
return NULL;
}
static void *
tls_endpt_set_crl_paths_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_tls_endpt_set_crl_paths("quaternary", NULL, "data");
nc_assert(!ret);
nc_thread_destroy();
return NULL;
}
static void *
tls_endpt_clear_crls_thread(void *arg)
{
(void)arg;
pthread_barrier_wait(&barrier);
nc_server_tls_endpt_clear_crls("quaternary");
return NULL;
}
static void *
tls_endpt_add_ctn_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_tls_endpt_add_ctn("main_tls", 2, "02:F0:F1:F2:F3:F4:F5:F6:F7:F8:F9:10:11:12:EE:FF:A0:A1:A2:A3",
NC_TLS_CTN_SAN_IP_ADDRESS, NULL);
nc_assert(!ret);
return NULL;
}
static void *
tls_endpt_del_ctn_thread(void *arg)
{
(void)arg;
int ret;
pthread_barrier_wait(&barrier);
ret = nc_server_tls_endpt_del_ctn("main_tls", -1, NULL, NC_TLS_CTN_SAN_ANY, NULL);
nc_assert(!ret);
return NULL;
}
static void *
tls_client_thread(void *arg)
{
int ret, read_pipe = *(int *)arg;
char buf[9];
struct nc_session *session;
fprintf(stdout, "TLS client start.\n");
ret = read(read_pipe, buf, 9);
nc_assert(ret == 9);
nc_assert(!strncmp(buf, "tls_ready", 9));
ret = nc_client_tls_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key");
nc_assert(!ret);
ret = nc_client_tls_set_trusted_ca_paths(NULL, TESTS_DIR "/data");
nc_assert(!ret);
session = nc_connect_tls("127.0.0.1", 6501, NULL);
nc_assert(session);
/* verify some capabilities */
nc_assert(nc_session_cpblt(session, "urn:jmu:params:xml:ns:yang:module-a?module=module-a&deviations=module-a-dv,module-a-dv2"));
nc_session_free(session, NULL);
fprintf(stdout, "TLS client finished.\n");
nc_thread_destroy();
return NULL;
}
#endif /* NC_ENABLED_TLS */
static void *(*thread_funcs[])(void *) = {
#if defined (NC_ENABLED_SSH) || defined (NC_ENABLED_TLS)
server_thread,
#endif
#ifdef NC_ENABLED_SSH
add_endpt_thread,
del_endpt_thread,
ssh_endpt_set_hostkey_thread,
ssh_endpt_set_auth_methods_thread,
ssh_endpt_set_auth_attempts_thread,
ssh_endpt_set_auth_timeout_thread,
ssh_endpt_add_authkey_thread,
ssh_endpt_del_authkey_thread,
#endif
#ifdef NC_ENABLED_TLS
endpt_set_address_thread,
endpt_set_port_thread,
tls_endpt_set_server_cert_thread,
tls_endpt_add_trusted_cert_list_thread,
tls_endpt_set_trusted_ca_paths_thread,
tls_endpt_del_trusted_cert_list_thread,
tls_endpt_set_crl_paths_thread,
tls_endpt_clear_crls_thread,
tls_endpt_add_ctn_thread,
tls_endpt_del_ctn_thread,
#endif
};
const int thread_count = sizeof thread_funcs / sizeof *thread_funcs;
#if defined (NC_ENABLED_SSH) && defined (NC_ENABLED_TLS)
const int client_count = 2;
pid_t pids[2];
int pipes[4];
#else
const int client_count = 1;
pid_t pids[1];
int pipes[2];
#endif
static void
client_fork(void)
{
int ret, clients = 0;
#ifdef NC_ENABLED_SSH
nc_assert(pipe(pipes + clients * 2) == 0);
if (!(pids[clients] = fork())) {
nc_client_init();
ret = nc_client_set_schema_searchpath(TESTS_DIR "/data/modules");
nc_assert(!ret);
/* close write */
close(pipes[clients * 2 + 1]);
ssh_client_thread(&pipes[clients * 2]);
close(pipes[clients * 2]);
nc_client_destroy();
exit(0);
}
/* close read */
close(pipes[clients * 2]);
++clients;
#endif
#ifdef NC_ENABLED_TLS
nc_assert(pipe(pipes + clients * 2) == 0);
if (!(pids[clients] = fork())) {
nc_client_init();
ret = nc_client_set_schema_searchpath(TESTS_DIR "/data/modules");
nc_assert(!ret);
/* close write */
close(pipes[clients * 2 + 1]);
tls_client_thread(&pipes[clients * 2]);
close(pipes[clients * 2]);
nc_client_destroy();
exit(0);
}
/* close read */
close(pipes[clients * 2]);
++clients;
#endif
}
#endif
int
main(void)
{
#if _POSIX_BARRIERS >= 200112L
struct ly_ctx *ctx;
int ret, i, clients = 0;
pthread_t tids[thread_count];
nc_verbosity(NC_VERB_VERBOSE);
client_fork();
ly_ctx_new(TESTS_DIR "/data/modules", 0, &ctx);
nc_assert(ctx);
ly_ctx_load_module(ctx, "ietf-netconf", NULL, NULL);
/* load some application models with deviations */
nc_assert(ly_ctx_load_module(ctx, "module-a", NULL, NULL));
nc_assert(ly_ctx_load_module(ctx, "module-a-dv", NULL, NULL));
nc_assert(ly_ctx_load_module(ctx, "module-a-dv2", NULL, NULL));
nc_server_init(ctx);
pthread_barrier_init(&barrier, NULL, thread_count);
#ifdef NC_ENABLED_SSH
/* set callback */
nc_server_ssh_set_hostkey_clb(clb_hostkeys, NULL, NULL);
/* do first, so that client can connect on SSH */
ret = nc_server_add_endpt("main_ssh", NC_TI_LIBSSH);
nc_assert(!ret);
ret = nc_server_endpt_set_address("main_ssh", "0.0.0.0");
nc_assert(!ret);
ret = nc_server_endpt_set_port("main_ssh", 6001);
nc_assert(!ret);
ret = nc_server_ssh_add_authkey_path(TESTS_DIR "/data/key_ecdsa.pub", "test");
nc_assert(!ret);
ret = nc_server_ssh_endpt_add_hostkey("main_ssh", "key_rsa", -1);
nc_assert(!ret);
/* client ready */
ret = write(pipes[clients * 2 + 1], "ssh_ready", 9);
nc_assert(ret == 9);
++clients;
/* for ssh_endpt_del_authkey */
ret = nc_server_ssh_add_authkey_path(TESTS_DIR "/data/key_dsa.pub", "test2");
nc_assert(!ret);
ret = nc_server_add_endpt("secondary", NC_TI_LIBSSH);
nc_assert(!ret);
#endif
#ifdef NC_ENABLED_TLS
/* set callbacks */
nc_server_tls_set_server_cert_clb(clb_server_cert, NULL, NULL);
nc_server_tls_set_trusted_cert_list_clb(clb_trusted_cert_lists, NULL, NULL);
/* do first, so that client can connect on TLS */
ret = nc_server_add_endpt("main_tls", NC_TI_OPENSSL);
nc_assert(!ret);
ret = nc_server_endpt_set_address("main_tls", "0.0.0.0");
nc_assert(!ret);
ret = nc_server_endpt_set_port("main_tls", 6501);
nc_assert(!ret);
ret = nc_server_tls_endpt_set_server_cert("main_tls", "main_cert");
nc_assert(!ret);
ret = nc_server_tls_endpt_add_trusted_cert_list("main_tls", "client_cert_list");
nc_assert(!ret);
ret = nc_server_tls_endpt_add_ctn("main_tls", 0, "02:B3:9F:26:65:76:6B:CC:FC:86:8E:D4:1A:81:64:0F:92:EB:18:AE:FF", NC_TLS_CTN_SPECIFIED, "test");
nc_assert(!ret);
/* client ready */
ret = write(pipes[clients * 2 + 1], "tls_ready", 9);
nc_assert(ret == 9);
++clients;
/* for tls_endpt_del_ctn */
ret = nc_server_tls_endpt_add_ctn("main_tls", 1, "02:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:A0:A1:A2:A3", NC_TLS_CTN_SAN_ANY, NULL);
nc_assert(!ret);
ret = nc_server_add_endpt("quaternary", NC_TI_OPENSSL);
nc_assert(!ret);
#endif
/* threads'n'stuff */
ret = 0;
for (i = 0; i < thread_count; ++i) {
ret += pthread_create(&tids[i], NULL, thread_funcs[i], NULL);
}
nc_assert(!ret);
/* cleanup */
for (i = 0; i < thread_count; ++i) {
pthread_join(tids[i], NULL);
}
for (i = 0; i < client_count; ++i) {
waitpid(pids[i], NULL, 0);
close(pipes[i * 2 + 1]);
}
pthread_barrier_destroy(&barrier);
nc_server_destroy();
ly_ctx_destroy(ctx);
#endif
return 0;
}

View file

@ -0,0 +1,15 @@
{
<custom_func_global_variables_check>
Helgrind:Race
fun:CRYPTO_malloc
}
{
<global_variable_always_set_with_default_method_when_getting>
Helgrind:Race
fun:DSA_get_default_method
}
{
<helgrind_ignores_rwlocks>
Helgrind:Race
fun:nc_server_endpt_set_address_port
}

View file

@ -0,0 +1,189 @@
/**
* \file test_thread_messages
* \author Tadeas Vintrlik <xvint04@stud.fit.vutbr.cz>
* \brief libnetconf2 tests - thread-safety for receiving messages
*
* Copyright 2021 Deutsche Telekom AG.
* Copyright 2021 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <libyang/libyang.h>
#include <log.h>
#include <messages_p.h>
#include <messages_server.h>
#include <session_client.h>
#include <session_server.h>
#include "tests/config.h"
/* millisec */
#define NC_ACCEPT_TIMEOUT 5000
/* millisec */
#define NC_PS_POLL_TIMEOUT 5000
/* sec */
#define CLIENT_SSH_AUTH_TIMEOUT 10
#define nc_assert(cond) if (!(cond)) { fprintf(stderr, "assert failed (%s:%d)\n", __FILE__, __LINE__); exit(1); }
#if _POSIX_BARRIERS >= 200112L
pthread_barrier_t barrier;
pthread_barrier_t barrier_msg;
#endif
typedef struct arg {
int in;
int out;
struct ly_ctx *ctx;
} arg_t;
struct nc_server_reply *
rpc_clb(struct lyd_node *rpc, struct nc_session *session)
{
(void)rpc; (void)session;
return nc_server_reply_ok();
}
static void *
server_thread(void *arg)
{
struct nc_session *sess;
struct nc_server_notif *notif;
struct lyd_node *ntf;
struct ly_in *in;
struct nc_pollsession *ps;
arg_t args = *(arg_t *)arg;
char *eventtime;
struct timespec ts;
const char *data;
int poll;
nc_assert(!nc_server_init(args.ctx));
nc_assert(nc_accept_inout(args.in, args.out, "test", &sess) == NC_MSG_HELLO);
nc_session_inc_notif_status(sess);
data =
"<n1 xmlns=\"n1\">\n"
" <first>Test</first>\n"
"</n1>\n";
nc_assert(ly_in_new_memory(data, &in) == LY_SUCCESS);
nc_assert(lyd_parse_op(args.ctx, NULL, in, LYD_XML, LYD_TYPE_NOTIF_YANG, &ntf, NULL) == LY_SUCCESS);
ly_in_free(in, 0);
nc_assert(clock_gettime(CLOCK_REALTIME, &ts) != -1);
nc_assert(ly_time_ts2str(&ts, &eventtime) == LY_SUCCESS);
notif = nc_server_notif_new(ntf, eventtime, NC_PARAMTYPE_FREE);
ps = nc_ps_new();
nc_assert(ps);
nc_ps_add_session(ps, sess);
poll = nc_ps_poll(ps, 1000, &sess);
nc_server_notif_send(sess, notif, 1000);
nc_assert(poll == NC_PSPOLL_RPC);
nc_ps_clear(ps, 1, NULL);
nc_ps_free(ps);
/* Waiting for end of test */
pthread_barrier_wait(&barrier);
nc_server_notif_free(notif);
return arg;
}
static void *
notif_thread(void *arg)
{
struct nc_session *sess = (struct nc_session *)arg;
struct lyd_node *envp;
struct lyd_node *op;
NC_MSG_TYPE msgtype;
/* Sync threads for receiving message to increase chance of datarace */
pthread_barrier_wait(&barrier_msg);
do {
msgtype = nc_recv_notif(sess, 1000, &envp, &op);
} while (msgtype == NC_MSG_REPLY);
nc_assert(msgtype == NC_MSG_NOTIF);
lyd_free_tree(envp);
lyd_free_tree(op);
return arg;
}
int
main(void)
{
int pipes[4];
struct nc_session *sess;
struct lyd_node *op, *envp;
struct ly_ctx *ctx;
struct nc_rpc *rpc;
uint64_t msgid;
NC_MSG_TYPE msgtype;
const char *features[] = {"startup", NULL};
arg_t thread_arg;
pthread_t t[2];
pthread_barrier_init(&barrier, NULL, 2);
pthread_barrier_init(&barrier_msg, NULL, 2);
/* Create a two pipes */
nc_assert(pipe(pipes) != -1);
nc_assert(pipe(pipes + 2) != -1);
thread_arg.in = pipes[0];
thread_arg.out = pipes[3];
/* Create context */
nc_assert(ly_ctx_new(TESTS_DIR "/data/modules", 0, &ctx) == LY_SUCCESS);
nc_assert(ly_ctx_load_module(ctx, "ietf-netconf", NULL, features));
nc_assert(ly_ctx_load_module(ctx, "notif1", NULL, NULL));
thread_arg.ctx = ctx;
nc_set_global_rpc_clb(rpc_clb);
/* Start server thread */
pthread_create(&t[0], NULL, server_thread, &thread_arg);
nc_client_init();
/* Listen for notifications */
sess = nc_connect_inout(pipes[2], pipes[1], ctx);
nc_assert(sess);
pthread_create(&t[1], NULL, notif_thread, sess);
/* Send rpc */
rpc = nc_rpc_delete(NC_DATASTORE_STARTUP, NULL, NC_PARAMTYPE_CONST);
nc_assert(nc_send_rpc(sess, rpc, 1000, &msgid) == NC_MSG_RPC);
/* Sync threads for receiving message to increase chance of datarace */
pthread_barrier_wait(&barrier_msg);
do {
msgtype = nc_recv_reply(sess, rpc, msgid, 1000, &envp, &op);
} while (msgtype == NC_MSG_NOTIF);
nc_assert(msgtype == NC_MSG_REPLY);
nc_rpc_free(rpc);
lyd_free_tree(envp);
/* Waiting of end of test */
pthread_barrier_wait(&barrier);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
/* Cleanup */
nc_session_free(sess, NULL);
ly_ctx_destroy(ctx);
for (uint8_t i = 0; i < 4; i++) {
close(pipes[i]);
}
return 0;
}