diff --git a/src/plugins/ietf-system-augeas/CMakeLists.txt b/src/plugins/ietf-system-augeas/CMakeLists.txt index 935a0a9..c02be91 100644 --- a/src/plugins/ietf-system-augeas/CMakeLists.txt +++ b/src/plugins/ietf-system-augeas/CMakeLists.txt @@ -19,6 +19,8 @@ set( PLUGIN_SOURCES plugin.c + datastore/running/load.c + datastore/running/store.c ) # add plugin as a sysrepo-plugind library diff --git a/src/plugins/ietf-system-augeas/datastore/running/load.c b/src/plugins/ietf-system-augeas/datastore/running/load.c new file mode 100644 index 0000000..e2bff48 --- /dev/null +++ b/src/plugins/ietf-system-augeas/datastore/running/load.c @@ -0,0 +1,10 @@ +#include "load.h" + +static int system_startup_load_hostname(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node); +static int system_startup_load_ntp(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node); + +int system_aug_running_ds_load(system_ctx_t *ctx, sr_session_ctx_t *session) +{ + int error = 0; + return error; +} \ No newline at end of file diff --git a/src/plugins/ietf-system-augeas/datastore/running/load.h b/src/plugins/ietf-system-augeas/datastore/running/load.h new file mode 100644 index 0000000..7e599aa --- /dev/null +++ b/src/plugins/ietf-system-augeas/datastore/running/load.h @@ -0,0 +1,21 @@ +/* + * telekom / sysrepo-plugin-system + * + * This program is made available under the terms of the + * BSD 3-Clause license which is available at + * https://opensource.org/licenses/BSD-3-Clause + * + * SPDX-FileCopyrightText: 2022 Deutsche Telekom AG + * SPDX-FileContributor: Sartura Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef SYSTEM_AUGEAS_PLUGIN_DATASTORE_RUNNING_LOAD_H +#define SYSTEM_AUGEAS_PLUGIN_DATASTORE_RUNNING_LOAD_H + +#include +#include + +int system_aug_running_ds_load(system_ctx_t *ctx, sr_session_ctx_t *session); + +#endif // SYSTEM_AUGEAS_PLUGIN_DATASTORE_RUNNING_LOAD_H \ No newline at end of file diff --git a/src/plugins/ietf-system-augeas/datastore/running/store.c b/src/plugins/ietf-system-augeas/datastore/running/store.c new file mode 100644 index 0000000..1fcb72c --- /dev/null +++ b/src/plugins/ietf-system-augeas/datastore/running/store.c @@ -0,0 +1,10 @@ +#include "store.h" + +static int system_startup_store_hostname(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node); +static int system_startup_store_ntp(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node); + +int system_aug_running_ds_store(system_ctx_t *ctx, sr_session_ctx_t *session) +{ + int error = 0; + return error; +} \ No newline at end of file diff --git a/src/plugins/ietf-system-augeas/datastore/running/store.h b/src/plugins/ietf-system-augeas/datastore/running/store.h new file mode 100644 index 0000000..9fd3a01 --- /dev/null +++ b/src/plugins/ietf-system-augeas/datastore/running/store.h @@ -0,0 +1,21 @@ +/* + * telekom / sysrepo-plugin-system + * + * This program is made available under the terms of the + * BSD 3-Clause license which is available at + * https://opensource.org/licenses/BSD-3-Clause + * + * SPDX-FileCopyrightText: 2022 Deutsche Telekom AG + * SPDX-FileContributor: Sartura Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef SYSTEM_AUGEAS_PLUGIN_DATASTORE_RUNNING_STORE_H +#define SYSTEM_AUGEAS_PLUGIN_DATASTORE_RUNNING_STORE_H + +#include +#include + +int system_aug_running_ds_store(system_ctx_t *ctx, sr_session_ctx_t *session); + +#endif // SYSTEM_AUGEAS_PLUGIN_DATASTORE_RUNNING_STORE_H \ No newline at end of file diff --git a/src/plugins/ietf-system-augeas/plugin.c b/src/plugins/ietf-system-augeas/plugin.c index c9dffa0..9868320 100644 --- a/src/plugins/ietf-system-augeas/plugin.c +++ b/src/plugins/ietf-system-augeas/plugin.c @@ -1,11 +1,173 @@ +/* + * telekom / sysrepo-plugin-system + * + * This program is made available under the terms of the + * BSD 3-Clause license which is available at + * https://opensource.org/licenses/BSD-3-Clause + * + * SPDX-FileCopyrightText: 2022 Deutsche Telekom AG + * SPDX-FileContributor: Sartura Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ #include "plugin.h" +#include "core/common.h" +#include "core/context.h" -int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_data) +// stdlib +#include + +// sysrepo +#include + +// libyang +#include + +#include "srpc/common.h" +#include "srpc/feature_status.h" +#include "srpc/types.h" + +// startup +#include "datastore/running/load.h" +#include "datastore/running/store.h" + +// subs +#include "core/subscription/change.h" +#include "core/subscription/operational.h" +#include "core/subscription/rpc.h" + +#include + +int sr_plugin_init_cb(sr_session_ctx_t *running_session, void **private_data) { - int error = SR_ERR_OK; - return error; + int error = 0; + + bool empty_startup = false; + + // sysrepo + sr_session_ctx_t *startup_session = NULL; + sr_conn_ctx_t *connection = NULL; + sr_subscription_ctx_t *subscription = NULL; + + // plugin + system_ctx_t *ctx = NULL; + + // init context + ctx = malloc(sizeof(*ctx)); + *ctx = (system_ctx_t){0}; + + *private_data = ctx; + + // module changes + srpc_module_change_t module_changes[] = { + { + SYSTEM_HOSTNAME_YANG_PATH, + system_subscription_change_hostname, + }, + { + SYSTEM_NTP_ENABLED_YANG_PATH, + system_subscription_change_ntp_enabled, + }, + { + SYSTEM_NTP_SERVER_YANG_PATH, + system_subscription_change_ntp_server, + }, + }; + + ctx->ietf_system_features = srpc_feature_status_hash_new(); + + // load feature status + SRPC_SAFE_CALL_ERR(error, srpc_feature_status_hash_load(&ctx->ietf_system_features, running_session, "ietf-system"), error_out); + + // log status of features + const char *features[] = { + "radius", + "authentication", + "local-users", + "radius-authentication", + "ntp", + "ntp-udp-port", + "timezone-name", + "dns-udp-tcp-port", + }; + + SRPLG_LOG_INF(PLUGIN_NAME, "Checking ietf-system YANG module used features"); + + for (size_t i = 0; i < ARRAY_SIZE(features); i++) { + const char *feature = features[i]; + + SRPLG_LOG_INF(PLUGIN_NAME, "ietf-system feature \"%s\" status = %s", feature, srpc_feature_status_hash_check(ctx->ietf_system_features, feature) ? "enabled" : "disabled"); + } + + connection = sr_session_get_connection(running_session); + error = sr_session_start(connection, SR_DS_STARTUP, &startup_session); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "sr_session_start() error (%d): %s", error, sr_strerror(error)); + goto error_out; + } + + ctx->startup_session = startup_session; + + error = srpc_check_empty_datastore(running_session, SYSTEM_HOSTNAME_YANG_PATH, &empty_startup); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "Failed checking datastore contents: %d", error); + goto error_out; + } + + if (empty_startup) { + SRPLG_LOG_INF(PLUGIN_NAME, "Running datastore is empty"); + SRPLG_LOG_INF(PLUGIN_NAME, "Loading initial system data"); + + // load data only into running DS - do not use startup unless said explicitly + error = system_aug_running_ds_load(ctx, running_session); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "Error loading initial data into the running datastore... exiting"); + goto error_out; + } + } else { + // make sure the data from startup DS is stored in the system + SRPLG_LOG_INF(PLUGIN_NAME, "Running datastore contains data"); + SRPLG_LOG_INF(PLUGIN_NAME, "Storing running datastore data in the system"); + + // check and apply if needed data from startup to the system + error = system_aug_running_ds_store(ctx, startup_session); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "Error applying initial data from startup datastore to the system... exiting"); + goto error_out; + } + } + + // subscribe every module change + for (size_t i = 0; i < ARRAY_SIZE(module_changes); i++) { + const srpc_module_change_t *change = &module_changes[i]; + + // in case of work on a specific callback set it to NULL + if (change->cb) { + error = sr_module_change_subscribe(running_session, BASE_YANG_MODULE, change->path, change->cb, *private_data, 0, SR_SUBSCR_DEFAULT, &subscription); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "sr_module_change_subscribe() error for \"%s\" (%d): %s", change->path, error, sr_strerror(error)); + goto error_out; + } + } + } + + goto out; + +error_out: + error = -1; + SRPLG_LOG_ERR(PLUGIN_NAME, "Error occured while initializing the plugin (%d)", error); + +out: + return error ? SR_ERR_CALLBACK_FAILED : SR_ERR_OK; } -void sr_plugin_cleanup_cb(sr_session_ctx_t *session, void *private_data) +void sr_plugin_cleanup_cb(sr_session_ctx_t *running_session, void *private_data) { + system_ctx_t *ctx = (system_ctx_t *) private_data; + + if (ctx->ietf_system_features) { + srpc_feature_status_hash_free(&ctx->ietf_system_features); + } + + free(ctx); } diff --git a/src/plugins/ietf-system/CMakeLists.txt b/src/plugins/ietf-system/CMakeLists.txt index 1d37a24..71ad8f4 100644 --- a/src/plugins/ietf-system/CMakeLists.txt +++ b/src/plugins/ietf-system/CMakeLists.txt @@ -19,6 +19,8 @@ set( PLUGIN_SOURCES plugin.c + datastore/running/load.c + datastore/running/store.c ) # check for systemd flag diff --git a/src/plugins/ietf-system/datastore/running/load.c b/src/plugins/ietf-system/datastore/running/load.c new file mode 100644 index 0000000..d24c5e7 --- /dev/null +++ b/src/plugins/ietf-system/datastore/running/load.c @@ -0,0 +1,502 @@ +/* + * telekom / sysrepo-plugin-system + * + * This program is made available under the terms of the + * BSD 3-Clause license which is available at + * https://opensource.org/licenses/BSD-3-Clause + * + * SPDX-FileCopyrightText: 2022 Deutsche Telekom AG + * SPDX-FileContributor: Sartura Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "load.h" +#include "core/common.h" +#include "core/context.h" +#include "core/ly_tree.h" + +// API for getting system data +#include "srpc/common.h" +#include "srpc/feature_status.h" +#include "srpc/ly_tree.h" +#include "core/api/system/load.h" +#include "core/api/system/authentication/load.h" +#include "core/api/system/dns_resolver/load.h" + +// data manipulation +#include "core/api/system/ntp/load.h" +#include "core/data/system/authentication/authorized_key/list.h" +#include "core/data/system/authentication/local_user/list.h" +#include "core/data/system/ip_address.h" +#include "core/data/system/dns_resolver/search/list.h" +#include "core/data/system/dns_resolver/server/list.h" +#include "core/data/system/ntp/server/list.h" + +#include +#include +#include + +#include + +#include + +#include + +static int system_startup_load_contact(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node); +static int system_startup_load_location(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node); +static int system_startup_load_timezone_name(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node); +static int system_startup_load_dns_resolver(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node); +static int system_startup_load_authentication(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node); + +int system_running_ds_load(system_ctx_t *ctx, sr_session_ctx_t *session) +{ + int error = 0; + + const struct ly_ctx *ly_ctx = NULL; + struct lyd_node *system_container_node = NULL; + sr_conn_ctx_t *conn_ctx = NULL; + + srpc_startup_load_t load_values[] = { + { + "contact", + system_startup_load_contact, + }, + { + "location", + system_startup_load_location, + }, + { + "timezone-name", + system_startup_load_timezone_name, + }, + { + "dns-resolver", + system_startup_load_dns_resolver, + }, + { + "authentication", + system_startup_load_authentication, + }, + }; + + conn_ctx = sr_session_get_connection(session); + ly_ctx = sr_acquire_context(conn_ctx); + if (ly_ctx == NULL) { + SRPLG_LOG_ERR(PLUGIN_NAME, "Unable to get ly_ctx variable"); + goto error_out; + } + + // reload features hash before adding all system values + SRPC_SAFE_CALL_ERR(error, srpc_feature_status_hash_reload(&ctx->ietf_system_features, session, IETF_SYSTEM_YANG_MODULE), error_out); + + // load system container info + error = system_ly_tree_create_system(ly_ctx, &system_container_node); + for (size_t i = 0; i < ARRAY_SIZE(load_values); i++) { + const srpc_startup_load_t *load = &load_values[i]; + + error = load->cb((void *) ctx, session, ly_ctx, system_container_node); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "Node creation callback failed for value %s", load->name); + goto error_out; + } + } + +// enable or disable storing into startup - use when testing load functionality for now +#define SYSTEM_PLUGIN_LOAD_STARTUP + +#ifdef SYSTEM_PLUGIN_LOAD_STARTUP + error = sr_edit_batch(session, system_container_node, "merge"); + if (error != SR_ERR_OK) { + SRPLG_LOG_ERR(PLUGIN_NAME, "sr_edit_batch() error (%d): %s", error, sr_strerror(error)); + goto error_out; + } + + error = sr_apply_changes(session, 0); + if (error != 0) { + SRPLG_LOG_ERR(PLUGIN_NAME, "sr_apply_changes() error (%d): %s", error, sr_strerror(error)); + goto error_out; + } +#endif + + goto out; + +error_out: + error = -1; + +out: + if (system_container_node) { + lyd_free_tree(system_container_node); + } + + sr_release_context(conn_ctx); + + return error; +} + +static int system_startup_load_contact(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node) +{ + int error = 0; + return error; +} + +static int system_startup_load_location(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node) +{ + int error = 0; + return error; +} + +static int system_startup_load_timezone_name(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node) +{ + int error = 0; + system_ctx_t *ctx = (system_ctx_t *) priv; + char timezone_name_buffer[SYSTEM_TIMEZONE_NAME_LENGTH_MAX] = {0}; + struct lyd_node *clock_container_node = NULL; + bool timezone_name_enabled = false; + + timezone_name_enabled = srpc_feature_status_hash_check(ctx->ietf_system_features, "timezone-name"); + + if (timezone_name_enabled) { + error = system_load_timezone_name(ctx, timezone_name_buffer); + + // setup clock container + error = system_ly_tree_create_clock(ly_ctx, parent_node, &clock_container_node); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_clock_container() error (%d)", error); + goto error_out; + } + + // set timezone-name leaf + error = system_ly_tree_create_timezone_name(ly_ctx, clock_container_node, timezone_name_buffer); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_timezone_name() error (%d)", error); + goto error_out; + } + } + + goto out; + +error_out: + error = -1; + +out: + return error; +} + +static int system_startup_load_ntp(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node) +{ + int error = 0; + + system_ctx_t *ctx = priv; + + // ietf-system nodes + struct lyd_node *ntp_container_node = NULL, *server_list_node = NULL; + + // feature check + bool ntp_enabled = srpc_feature_status_hash_check(ctx->ietf_system_features, "ntp"); + bool ntp_udp_port_enabled = srpc_feature_status_hash_check(ctx->ietf_system_features, "ntp-udp-port"); + + // load list + system_ntp_server_element_t *ntp_server_head = NULL, *ntp_server_iter = NULL; + + SRPLG_LOG_INF(PLUGIN_NAME, "Loading NTP data"); + + if (ntp_enabled) { + error = system_ly_tree_create_ntp(ly_ctx, parent_node, &ntp_container_node); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_ntp() error (%d)", error); + goto error_out; + } + + // load system values + system_ntp_server_list_init(&ntp_server_head); + error = system_ntp_load_server(ctx, &ntp_server_head); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ntp_load_server() error (%d)", error); + goto error_out; + } + + LL_FOREACH(ntp_server_head, ntp_server_iter) + { + // name + error = system_ly_tree_create_ntp_server(ly_ctx, ntp_container_node, &server_list_node, ntp_server_iter->server.name); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_ntp_server() error (%d)", error); + goto error_out; + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Setting address %s", ntp_server_iter->server.address); + + // address + error = system_ly_tree_create_ntp_server_address(ly_ctx, server_list_node, ntp_server_iter->server.address); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_ntp_server_address() error (%d)", error); + goto error_out; + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Setting port \"%s\"", ntp_server_iter->server.port); + + // port + if (ntp_server_iter->server.port && ntp_udp_port_enabled) { + error = system_ly_tree_create_ntp_server_port(ly_ctx, server_list_node, ntp_server_iter->server.port); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_ntp_server_port() error (%d)", error); + goto error_out; + } + } + + // association type + error = system_ly_tree_create_ntp_server_association_type(ly_ctx, server_list_node, ntp_server_iter->server.association_type); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_ntp_server_association_type() error (%d)", error); + goto error_out; + } + + // iburst + if (ntp_server_iter->server.iburst) { + error = system_ly_tree_create_ntp_server_iburst(ly_ctx, server_list_node, ntp_server_iter->server.iburst); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_ntp_server_iburst() error (%d)", error); + goto error_out; + } + } + + // prefer + if (ntp_server_iter->server.prefer) { + error = system_ly_tree_create_ntp_server_prefer(ly_ctx, server_list_node, ntp_server_iter->server.prefer); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_ntp_server_prefer() error (%d)", error); + goto error_out; + } + } + } + + goto out; + } + +error_out: + error = -1; + +out: + + system_ntp_server_list_free(&ntp_server_head); + + return error; +} + +static int system_startup_load_dns_resolver(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node) +{ + int error = 0; + system_ctx_t *ctx = (system_ctx_t *) priv; + struct lyd_node *dns_resolver_container_node = NULL, *server_list_node = NULL; + system_dns_search_element_t *search_head = NULL, *search_iter_el = NULL; + system_dns_server_element_t *servers_head = NULL, *servers_iter_el = NULL; + char address_buffer[100] = {0}; + char port_buffer[10] = {0}; + + // setup dns-resolver container + error = system_ly_tree_create_dns_resolver(ly_ctx, parent_node, &dns_resolver_container_node); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_dns_resolver() error (%d)", error); + goto error_out; + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Loading DNS search values from the system"); + + // load values + + error = system_dns_resolver_load_search(ctx, &search_head); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_dns_resolver_load_search_values() error (%d)", error); + goto error_out; + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Loading DNS server values from the system"); + + error = system_dns_resolver_load_server(ctx, &servers_head); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_dns_resolver_load_server_values() error (%d)", error); + goto error_out; + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Saving search values to the datastore"); + + LL_FOREACH(search_head, search_iter_el) + { + error = system_ly_tree_append_dns_resolver_search(ly_ctx, dns_resolver_container_node, search_iter_el->search.domain); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_append_dns_resolver_search() error (%d) for %s", error, search_iter_el->search.domain); + goto error_out; + } + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Saved search values to the datastore"); + SRPLG_LOG_INF(PLUGIN_NAME, "Saving server values to the datastore"); + + LL_FOREACH(servers_head, servers_iter_el) + { + error = system_ip_address_to_str(&servers_iter_el->server.address, address_buffer, sizeof(address_buffer)); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_dns_resolver_server_address_to_str() error (%d)", error); + goto error_out; + } + + error = system_ly_tree_create_dns_resolver_server(ly_ctx, dns_resolver_container_node, &server_list_node, address_buffer); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_dns_resolver_server() error (%d) for %s", error, address_buffer); + goto error_out; + } + + // address + error = system_ly_tree_create_dns_resolver_server_address(ly_ctx, server_list_node, address_buffer); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_dns_resolver_server_address() error (%d) for %s", error, address_buffer); + goto error_out; + } + + // port + if (servers_iter_el->server.port != 0) { + error = snprintf(port_buffer, sizeof(port_buffer), "%d", servers_iter_el->server.port); + if (error < 0) { + SRPLG_LOG_ERR(PLUGIN_NAME, "snprintf() error (%d) for %d port", error, servers_iter_el->server.port); + goto error_out; + } + + error = system_ly_tree_create_dns_resolver_server_port(ly_ctx, server_list_node, port_buffer); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_dns_resolver_server_address() error (%d) for %s port", error, port_buffer); + goto error_out; + } + } + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Saved server values to the datastore"); + + goto out; + +error_out: + error = -1; + +out: + // free values + system_dns_search_list_free(&search_head); + system_dns_server_list_free(&servers_head); + + return error; +} + +static int system_startup_load_authentication(void *priv, sr_session_ctx_t *session, const struct ly_ctx *ly_ctx, struct lyd_node *parent_node) +{ + int error = 0; + system_ctx_t *ctx = (system_ctx_t *) priv; + struct lyd_node *authentication_container_node = NULL; + struct lyd_node *user_list_node = NULL, *authorized_key_list_node = NULL; + system_local_user_element_t *user_head = NULL, *user_iter = NULL; + system_authorized_key_element_t *key_iter = NULL; + + bool enabled_authentication = srpc_feature_status_hash_check(ctx->ietf_system_features, "authentication"); + bool enabled_local_users = srpc_feature_status_hash_check(ctx->ietf_system_features, "local-users"); + + if (enabled_authentication) { + // create authentication container + error = system_ly_tree_create_authentication(ly_ctx, parent_node, &authentication_container_node); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_authentication() error (%d)", error); + goto error_out; + } + + if (enabled_local_users) { + SRPLG_LOG_INF(PLUGIN_NAME, "Loading users from the system"); + + // init list first + system_local_user_list_init(&user_head); + + // load user list + error = system_authentication_load_user(ctx, &user_head); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_authentication_load_user() error (%d)", error); + goto error_out; + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Loading user authorized keys"); + + LL_FOREACH(user_head, user_iter) + { + system_authorized_key_list_init(&user_iter->user.key_head); + + error = system_authentication_load_user_authorized_key(ctx, user_iter->user.name, &user_iter->user.key_head); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_authentication_load_user_authorized_key() error (%d)", error); + goto error_out; + } + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Saving users and their keys to the datastore"); + + LL_FOREACH(user_head, user_iter) + { + // list item + error = system_ly_tree_create_authentication_user(ly_ctx, authentication_container_node, &user_list_node, user_iter->user.name); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_authentication_user() error (%d) for %s", error, user_iter->user.name); + goto error_out; + } + + // password + if (user_iter->user.password && strcmp(user_iter->user.password, "")) { + error = system_ly_tree_create_authentication_user_password(ly_ctx, user_list_node, user_iter->user.password); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_authentication_user_password() error (%d) for %s", error, user_iter->user.password); + goto error_out; + } + } + + // authorized-key + int count = 0; + LL_COUNT(user_iter->user.key_head, key_iter, count); + + if (count > 0) { + key_iter = NULL; + LL_FOREACH(user_iter->user.key_head, key_iter) + { + // list item + error = system_ly_tree_create_authentication_user_authorized_key(ly_ctx, user_list_node, &authorized_key_list_node, key_iter->key.name); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_authentication_user_authorized_key() error (%d) for %s", error, key_iter->key.name); + goto error_out; + } + + // algorithm + if (key_iter->key.algorithm) { + error = system_ly_tree_create_authentication_user_authorized_key_algorithm(ly_ctx, authorized_key_list_node, key_iter->key.algorithm); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_authentication_user_authorized_key_algorithm() error (%d) for %s", error, key_iter->key.algorithm); + goto error_out; + } + } + + // key-data + if (key_iter->key.data) { + error = system_ly_tree_create_authentication_user_authorized_key_data(ly_ctx, authorized_key_list_node, key_iter->key.data); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ly_tree_create_authentication_user_authorized_key_data() error (%d) for %s", error, key_iter->key.data); + goto error_out; + } + } + } + } + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Saved users to the datastore"); + } + } + + goto out; + +error_out: + error = -1; + +out: + system_local_user_list_free(&user_head); + + return error; +} \ No newline at end of file diff --git a/src/plugins/ietf-system/datastore/running/load.h b/src/plugins/ietf-system/datastore/running/load.h new file mode 100644 index 0000000..f38d269 --- /dev/null +++ b/src/plugins/ietf-system/datastore/running/load.h @@ -0,0 +1,21 @@ +/* + * telekom / sysrepo-plugin-system + * + * This program is made available under the terms of the + * BSD 3-Clause license which is available at + * https://opensource.org/licenses/BSD-3-Clause + * + * SPDX-FileCopyrightText: 2022 Deutsche Telekom AG + * SPDX-FileContributor: Sartura Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef SYSTEM_PLUGIN_DATASTORE_RUNNING_LOAD_H +#define SYSTEM_PLUGIN_DATASTORE_RUNNING_LOAD_H + +#include +#include + +int system_running_ds_load(system_ctx_t *ctx, sr_session_ctx_t *session); + +#endif // SYSTEM_PLUGIN_DATASTORE_RUNNING_LOAD_H \ No newline at end of file diff --git a/src/plugins/ietf-system/datastore/running/store.c b/src/plugins/ietf-system/datastore/running/store.c new file mode 100644 index 0000000..222bd45 --- /dev/null +++ b/src/plugins/ietf-system/datastore/running/store.c @@ -0,0 +1,692 @@ +/* + * telekom / sysrepo-plugin-system + * + * This program is made available under the terms of the + * BSD 3-Clause license which is available at + * https://opensource.org/licenses/BSD-3-Clause + * + * SPDX-FileCopyrightText: 2022 Deutsche Telekom AG + * SPDX-FileContributor: Sartura Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "store.h" +#include "core/common.h" +#include "libyang/printer_data.h" +#include "core/ly_tree.h" + +// API for getting system data +#include "srpc/common.h" +#include "srpc/feature_status.h" +#include "srpc/ly_tree.h" +#include "srpc/types.h" +#include "core/api/system/authentication/check.h" +#include "core/api/system/authentication/load.h" +#include "core/api/system/check.h" +#include "core/api/system/ntp/check.h" +#include "core/api/system/ntp/store.h" +#include "core/api/system/store.h" +#include "core/api/system/dns_resolver/store.h" +#include "core/api/system/dns_resolver/check.h" +#include "core/api/system/authentication/store.h" + +// data manipulation +#include "core/data/system/authentication/authorized_key.h" +#include "core/data/system/authentication/authorized_key/list.h" +#include "core/data/system/authentication/local_user.h" +#include "core/data/system/authentication/local_user/list.h" +#include "core/data/system/ip_address.h" +#include "core/data/system/dns_resolver/search.h" +#include "core/data/system/dns_resolver/search/list.h" +#include "core/data/system/dns_resolver/server.h" +#include "core/data/system/dns_resolver/server/list.h" +#include "core/data/system/ntp/server.h" +#include "core/data/system/ntp/server/list.h" +#include "core/types.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +static int system_startup_store_contact(void *priv, const struct lyd_node *system_container_node); +static int system_startup_store_location(void *priv, const struct lyd_node *system_container_node); +static int system_startup_store_timezone_name(void *priv, const struct lyd_node *system_container_node); +static int system_startup_store_dns_resolver(void *priv, const struct lyd_node *system_container_node); +static int system_startup_store_authentication(void *priv, const struct lyd_node *system_container_node); + +int system_running_ds_store(system_ctx_t *ctx, sr_session_ctx_t *session) +{ + int error = 0; + sr_data_t *subtree = NULL; + + error = sr_get_subtree(session, SYSTEM_SYSTEM_CONTAINER_YANG_PATH, 0, &subtree); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "sr_get_subtree() error (%d): %s", error, sr_strerror(error)); + goto error_out; + } + + srpc_startup_store_t store_values[] = { + { + "contact", + system_startup_store_contact, + }, + { + "location", + system_startup_store_location, + }, + { + "timezone-name", + system_startup_store_timezone_name, + }, + { + "dns-resolver", + system_startup_store_dns_resolver, + }, + { + "authentication", + system_startup_store_authentication, + }, + }; + + // reload feature status hash before storing system data + SRPC_SAFE_CALL_ERR(error, srpc_feature_status_hash_reload(&ctx->ietf_system_features, session, IETF_SYSTEM_YANG_MODULE), error_out); + + for (size_t i = 0; i < ARRAY_SIZE(store_values); i++) { + const srpc_startup_store_t *store = &store_values[i]; + + error = store->cb(ctx, subtree->tree); + if (error != 0) { + SRPLG_LOG_ERR(PLUGIN_NAME, "Startup store callback failed for value %s", store->name); + goto error_out; + } + } + + goto out; + +error_out: + error = -1; + +out: + if (subtree) { + sr_release_data(subtree); + } + + return error; +} + +static int system_startup_store_contact(void *priv, const struct lyd_node *system_container_node) +{ + int error = 0; + system_ctx_t *ctx = (system_ctx_t *) priv; + + struct lyd_node *contact_node = srpc_ly_tree_get_child_leaf(system_container_node, "contact"); + + if (contact_node) { + const char *contact = lyd_get_value(contact_node); + + SRPLG_LOG_INF(PLUGIN_NAME, "contact value: %s", contact); + + error = system_store_contact(ctx, contact); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_store_contact() failed (%d)", error); + return -1; + } + } + + return 0; +} + +static int system_startup_store_location(void *priv, const struct lyd_node *system_container_node) +{ + int error = 0; + system_ctx_t *ctx = (system_ctx_t *) priv; + + struct lyd_node *location_node = srpc_ly_tree_get_child_leaf(system_container_node, "location"); + + if (location_node) { + const char *location = lyd_get_value(location_node); + + SRPLG_LOG_INF(PLUGIN_NAME, "location value: %s", location); + + error = system_store_location(ctx, location); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_store_location() failed (%d)", error); + return -1; + } + } + + return 0; +} + +static int system_startup_store_timezone_name(void *priv, const struct lyd_node *system_container_node) +{ + int error = 0; + system_ctx_t *ctx = (system_ctx_t *) priv; + srpc_check_status_t check_status = srpc_check_status_none; + bool timezone_name_enabled = srpc_feature_status_hash_check(ctx->ietf_system_features, "timezone-name"); + + struct lyd_node *clock_container_node = NULL, *timezone_name_node = NULL; + + if (timezone_name_enabled) { + clock_container_node = srpc_ly_tree_get_child_container(system_container_node, "clock"); + + if (clock_container_node) { + timezone_name_node = srpc_ly_tree_get_child_leaf(clock_container_node, "timezone-name"); + if (timezone_name_node) { + const char *timezone_name = lyd_get_value(timezone_name_node); + + SRPLG_LOG_INF(PLUGIN_NAME, "Checking system timezone-name value"); + check_status = system_check_timezone_name(ctx, timezone_name); + + switch (check_status) { + case srpc_check_status_none: + SRPLG_LOG_ERR(PLUGIN_NAME, "Error loading current system timezone-name value"); + goto error_out; + break; + case srpc_check_status_error: + SRPLG_LOG_ERR(PLUGIN_NAME, "Error loading current system timezone-name value"); + goto error_out; + break; + case srpc_check_status_non_existant: + SRPLG_LOG_INF(PLUGIN_NAME, "Storing timezone-name value %s", timezone_name); + + error = system_store_timezone_name(ctx, timezone_name); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_store_timezone_name() failed (%d)", error); + return -1; + } + break; + case srpc_check_status_equal: + SRPLG_LOG_ERR(PLUGIN_NAME, "Startup timezone-name value is already applied on the system"); + break; + case srpc_check_status_partial: + // should not be returned - treat as error + SRPLG_LOG_ERR(PLUGIN_NAME, "Error loading current system timezone-name value"); + goto error_out; + break; + } + } + } + } + + goto out; + +error_out: + error = -1; + +out: + return 0; +} + +static int system_startup_store_dns_resolver(void *priv, const struct lyd_node *system_container_node) +{ + int error = 0; + system_ctx_t *ctx = (system_ctx_t *) priv; + struct lyd_node *dns_resolver_container_node = NULL; + struct lyd_node *search_leaf_list_node = NULL; + struct lyd_node *server_list_node = NULL; + struct lyd_node *server_name_leaf_node = NULL; + struct lyd_node *server_address_leaf_node = NULL; + struct lyd_node *server_port_leaf_node = NULL; + struct lyd_node *udp_and_tcp_container_node = NULL; + system_dns_server_element_t *servers_head = NULL; + system_dns_search_element_t *search_head = NULL; + system_dns_server_t tmp_server = {0}; + system_dns_search_t tmp_search = {0}; + system_ip_address_t tmp_ip = {0}; + srpc_check_status_t search_check_status = srpc_check_status_none, server_check_status = srpc_check_status_none; + + SRPLG_LOG_INF(PLUGIN_NAME, "Storing dns-resolver startup data"); + + dns_resolver_container_node = srpc_ly_tree_get_child_container(system_container_node, "dns-resolver"); + if (dns_resolver_container_node) { + // get search leaf list + search_leaf_list_node = srpc_ly_tree_get_child_leaf_list(dns_resolver_container_node, "search"); + server_list_node = srpc_ly_tree_get_child_list(dns_resolver_container_node, "server"); + + if (search_leaf_list_node) { + // store search list + while (search_leaf_list_node) { + system_dns_search_init(&tmp_search); + + const char *domain = lyd_get_value(search_leaf_list_node); + + // SRPLG_LOG_INF(PLUGIN_NAME, "Adding DNS search value %s", domain); + + error = system_dns_search_set_domain(&tmp_search, domain); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_dns_search_set_domain() error (%d)", error); + goto error_out; + } + + error = system_dns_search_set_ifindex(&tmp_search, 0); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_dns_search_set_ifindex() error (%d)", error); + goto error_out; + } + + error = system_dns_search_set_search(&tmp_search, 0); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_dns_search_set_search() error (%d)", error); + goto error_out; + } + + // add to the list + error = system_dns_search_list_add(&search_head, tmp_search); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_dns_search_list_add() error (%d)", error); + goto error_out; + } + + system_dns_search_free(&tmp_search); + + search_leaf_list_node = srpc_ly_tree_get_leaf_list_next(search_leaf_list_node); + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Checking DNS search values on the system"); + search_check_status = system_dns_resolver_check_search(ctx, search_head); + SRPLG_LOG_INF(PLUGIN_NAME, "Recieved check status = %d", search_check_status); + + switch (search_check_status) { + case srpc_check_status_none: + // should not be recieved - treat same as an error + SRPLG_LOG_ERR(PLUGIN_NAME, "Error occured while checking DNS search system values"); + goto error_out; + break; + case srpc_check_status_error: + SRPLG_LOG_ERR(PLUGIN_NAME, "Error occured while checking DNS search system values"); + goto error_out; + break; + case srpc_check_status_non_existant: + // values don't exist - apply them to the system + SRPLG_LOG_INF(PLUGIN_NAME, "Storing DNS search values from the datastore to the system"); + + // apply search values to the system + error = system_dns_resolver_store_search(ctx, search_head); + if (error) { + SRPLG_LOG_INF(PLUGIN_NAME, "system_dns_resolver_store_search() error (%d)", error); + goto error_out; + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Stored DNS search values from the datastore to the system"); + break; + case srpc_check_status_equal: + // values exist - don't do anything + break; + case srpc_check_status_partial: + // TODO: create an union between startup and system values and apply that list to the system + break; + } + } + + if (server_list_node) { + while (server_list_node) { + // process server list node + system_dns_server_init(&tmp_server); + + server_name_leaf_node = srpc_ly_tree_get_child_leaf(server_list_node, "name"); + udp_and_tcp_container_node = srpc_ly_tree_get_child_container(server_list_node, "udp-and-tcp"); + + const char *name = lyd_get_value(server_name_leaf_node); + // SRPLG_LOG_INF(PLUGIN_NAME, "Adding DNS server %s", name); + + // set name + system_dns_server_set_name(&tmp_server, name); + + if (!udp_and_tcp_container_node) { + SRPLG_LOG_ERR(PLUGIN_NAME, "srpc_ly_tree_get_child_container() failed for udp-and-tcp"); + goto error_out; + } + + server_address_leaf_node = srpc_ly_tree_get_child_leaf(udp_and_tcp_container_node, "address"); + server_port_leaf_node = srpc_ly_tree_get_child_leaf(udp_and_tcp_container_node, "port"); + + // address + if (server_address_leaf_node) { + const char *address = lyd_get_value(server_address_leaf_node); + + // parse address + error = system_ip_address_from_str(&tmp_ip, address); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_ip_address_from_str() error (%d)", error); + goto error_out; + } + + // set address + error = system_dns_server_set_address(&tmp_server, tmp_ip); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_dns_server_set_address() error (%d)", error); + goto error_out; + } + } else { + // no address node -> unable to continue + SRPLG_LOG_INF(PLUGIN_NAME, "srpc_ly_tree_get_child_leaf() failed for leaf address"); + goto error_out; + } + + if (server_port_leaf_node) { + const char *port = lyd_get_value(server_port_leaf_node); + + // parse into int + const int port_i32 = atoi(port); + + // set port + error = system_dns_server_set_port(&tmp_server, port_i32); + if (error) { + SRPLG_LOG_INF(PLUGIN_NAME, "system_dns_server_set_port() error (%d)", error); + goto error_out; + } + } + + // append to the list + error = system_dns_server_list_add(&servers_head, tmp_server); + if (error) { + SRPLG_LOG_INF(PLUGIN_NAME, "system_dns_server_list_add() error (%d)", error); + goto error_out; + } + + system_dns_server_free(&tmp_server); + + server_list_node = srpc_ly_tree_get_list_next(server_list_node); + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Checking DNS server values on the system"); + server_check_status = system_dns_resolver_check_server(ctx, servers_head); + SRPLG_LOG_INF(PLUGIN_NAME, "Recieved check status = %d", server_check_status); + + switch (server_check_status) { + case srpc_check_status_none: + // should not be recieved - treat same as an error + SRPLG_LOG_ERR(PLUGIN_NAME, "Error occured while checking DNS server system values"); + goto error_out; + break; + case srpc_check_status_error: + SRPLG_LOG_ERR(PLUGIN_NAME, "Error occured while checking DNS server system values"); + goto error_out; + break; + case srpc_check_status_non_existant: + SRPLG_LOG_INF(PLUGIN_NAME, "Storing DNS server values from the datastore to the system"); + + // gathered all servers - store them to the system + error = system_dns_resolver_store_server(ctx, servers_head); + if (error) { + SRPLG_LOG_INF(PLUGIN_NAME, "system_dns_resolver_store_server() error (%d)", error); + goto error_out; + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Stored DNS server values from the datastore to the system"); + break; + case srpc_check_status_equal: + // don't do anything + SRPLG_LOG_INF(PLUGIN_NAME, "DNS server values already exist on the system - no need to apply anything"); + break; + case srpc_check_status_partial: + // TODO: implement + break; + } + } + } + + goto out; + +error_out: + error = -1; + +out: + // remove temp values if something was interrupted + system_dns_search_free(&tmp_search); + system_dns_server_free(&tmp_server); + + // free allocated lists + system_dns_search_list_free(&search_head); + system_dns_server_list_free(&servers_head); + + return error; +} + +static int system_startup_store_authentication(void *priv, const struct lyd_node *system_container_node) +{ + int error = 0; + + system_ctx_t *ctx = (system_ctx_t *) priv; + + // libyang + struct lyd_node *authentication_container_node = NULL; + struct lyd_node *local_user_list_node = NULL, *user_name_leaf_node = NULL, *user_password_leaf_node; + struct lyd_node *authorized_key_list_node = NULL, *key_name_leaf_node = NULL, *key_algorithm_leaf_node = NULL, *key_data_leaf_node = NULL; + + // data + system_local_user_element_t *user_head = NULL, *found_user_el = NULL, *user_iter = NULL; + system_local_user_element_t *system_user_head = NULL; + system_local_user_element_t *complement_user_head = NULL; + system_local_user_t temp_user = {0}; + system_authorized_key_t temp_key = {0}; + + // features + bool authentication_enabled = srpc_feature_status_hash_check(ctx->ietf_system_features, "authentication"); + bool local_users_enabled = srpc_feature_status_hash_check(ctx->ietf_system_features, "local-users"); + + // srpc + srpc_check_status_t user_check_status = srpc_check_status_none, key_check_status = srpc_check_status_none; + + if (authentication_enabled) { + SRPLG_LOG_INF(PLUGIN_NAME, "Storing authentication startup data"); + + authentication_container_node = srpc_ly_tree_get_child_container(system_container_node, "authentication"); + if (authentication_container_node) { + if (local_users_enabled) { + SRPLG_LOG_INF(PLUGIN_NAME, "Storing local-users startup data"); + + local_user_list_node = srpc_ly_tree_get_child_list(authentication_container_node, "user"); + while (local_user_list_node) { + // create user + system_local_user_init(&temp_user); + + user_name_leaf_node = srpc_ly_tree_get_child_leaf(local_user_list_node, "name"); + user_password_leaf_node = srpc_ly_tree_get_child_leaf(local_user_list_node, "password"); + + // a name has to exist for the list element + assert(user_name_leaf_node != NULL); + + // set name + error = system_local_user_set_name(&temp_user, lyd_get_value(user_name_leaf_node)); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_local_user_set_name() error (%d)", error); + goto error_out; + } + + // set password + if (user_password_leaf_node) { + error = system_local_user_set_password(&temp_user, lyd_get_value(user_password_leaf_node)); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_local_user_set_password() error (%d)", error); + goto error_out; + } + } + + // add user to the list + error = system_local_user_list_add(&user_head, temp_user); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_local_user_list_add() error (%d)", error); + goto error_out; + } + + // get current user + found_user_el = system_local_user_list_find(user_head, temp_user.name); + if (!found_user_el) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_local_user_list_find() failed"); + goto error_out; + } + + // user found - setup keys if any + authorized_key_list_node = srpc_ly_tree_get_child_list(local_user_list_node, "authorized-key"); + while (authorized_key_list_node) { + // add key to the current user (found_user_el) + system_authorized_key_init(&temp_key); + + key_name_leaf_node = srpc_ly_tree_get_child_leaf(authorized_key_list_node, "name"); + key_algorithm_leaf_node = srpc_ly_tree_get_child_leaf(authorized_key_list_node, "algorithm"); + key_data_leaf_node = srpc_ly_tree_get_child_leaf(authorized_key_list_node, "key-data"); + + // key must have a name + assert(key_name_leaf_node != NULL); + + error = system_authorized_key_set_name(&temp_key, lyd_get_value(key_name_leaf_node)); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_authorized_key_set_name() error (%d)", error); + goto error_out; + } + + if (key_algorithm_leaf_node) { + // set algorithm + error = system_authorized_key_set_algorithm(&temp_key, lyd_get_value(key_algorithm_leaf_node)); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_authorized_key_set_algorithm() error (%d)", error); + goto error_out; + } + } + + if (key_data_leaf_node) { + // set algorithm + error = system_authorized_key_set_data(&temp_key, lyd_get_value(key_data_leaf_node)); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_authorized_key_set_data() error (%d)", error); + goto error_out; + } + } + + // add to the list of current user keys + error = system_authorized_key_list_add(&found_user_el->user.key_head, temp_key); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_authorized_key_list_add() error (%d)", error); + goto error_out; + } + + // free temp data + system_authorized_key_free(&temp_key); + authorized_key_list_node = srpc_ly_tree_get_list_next(authorized_key_list_node); + } + + system_local_user_free(&temp_user); + local_user_list_node = srpc_ly_tree_get_list_next(local_user_list_node); + } + + // get system users + system_local_user_list_init(&system_user_head); + + // check if all users exist on the system + SRPLG_LOG_INF(PLUGIN_NAME, "Checking startup local user system values"); + user_check_status = system_authentication_check_user(ctx, user_head, &system_user_head); + SRPLG_LOG_INF(PLUGIN_NAME, "Recieved local users check status: %d", user_check_status); + + switch (user_check_status) { + case srpc_check_status_none: + SRPLG_LOG_ERR(PLUGIN_NAME, "Error occured while checking local user system values"); + goto error_out; + break; + case srpc_check_status_error: + SRPLG_LOG_ERR(PLUGIN_NAME, "Error occured while checking local user system values"); + goto error_out; + break; + case srpc_check_status_non_existant: + SRPLG_LOG_INF(PLUGIN_NAME, "Startup local users don\'t exist on the system - starting to store startup local users"); + error = system_authentication_store_user(ctx, user_head); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_authentication_store_user() error (%d)", error); + goto error_out; + } + break; + case srpc_check_status_equal: + SRPLG_LOG_INF(PLUGIN_NAME, "Startup local users already exist on the system - no need to store anything"); + break; + case srpc_check_status_partial: + SRPLG_LOG_INF(PLUGIN_NAME, "Some startup local users exist while others don\'t - creating non existant users"); + + // get complement of startup without system + complement_user_head = system_local_user_list_complement(user_head, system_user_head); + if (!complement_user_head) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_local_user_list_complement() failed"); + goto error_out; + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Storing missing local users from startup to the system"); + + // add complement users to system + error = system_authentication_store_user(ctx, complement_user_head); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_authentication_store_user() error (%d)", error); + goto error_out; + } + + SRPLG_LOG_INF(PLUGIN_NAME, "Missing local users from startup are stored in the system"); + break; + } + + // after matching startup and system values for users - match key lists for all users + SRPLG_LOG_INF(PLUGIN_NAME, "Checking startup local user authorized key system values"); + LL_FOREACH(user_head, user_iter) + { + // check first if any keys exist in startup + if (user_iter->user.key_head) { + key_check_status = system_authentication_check_user_authorized_key(ctx, user_iter->user.name, user_iter->user.key_head); + SRPLG_LOG_INF(PLUGIN_NAME, "Recieved authorized-key check status %d for user %s", user_check_status, user_iter->user.name); + + switch (key_check_status) { + case srpc_check_status_none: + SRPLG_LOG_ERR(PLUGIN_NAME, "Error occured while checking local user authorized key system values"); + goto error_out; + break; + case srpc_check_status_error: + SRPLG_LOG_ERR(PLUGIN_NAME, "Error occured while checking local user authorized key system values"); + goto error_out; + break; + case srpc_check_status_non_existant: + SRPLG_LOG_INF(PLUGIN_NAME, "Startup authorized keys don\'t exist on the system for user %s - storing authorized keys for user %s", user_iter->user.name, user_iter->user.name); + error = system_authentication_store_user_authorized_key(ctx, user_iter->user.name, user_iter->user.key_head); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "system_authentication_store_user_authorized_key() error (%d) for user %s", error, user_iter->user.name); + goto error_out; + } + break; + case srpc_check_status_equal: + SRPLG_LOG_INF(PLUGIN_NAME, "Startup authorized keys already exist for local user %s - no need to store anything", user_iter->user.name); + break; + case srpc_check_status_partial: + // TODO + break; + } + } + } + } + } + } + + goto out; + +error_out: + error = -1; + +out: + + // free temp values if interrupted + system_local_user_free(&temp_user); + system_authorized_key_free(&temp_key); + + // free lists + system_local_user_list_free(&user_head); + system_local_user_list_free(&system_user_head); + system_local_user_list_free(&complement_user_head); + + return error; +} \ No newline at end of file diff --git a/src/plugins/ietf-system/datastore/running/store.h b/src/plugins/ietf-system/datastore/running/store.h new file mode 100644 index 0000000..16f7f3a --- /dev/null +++ b/src/plugins/ietf-system/datastore/running/store.h @@ -0,0 +1,21 @@ +/* + * telekom / sysrepo-plugin-system + * + * This program is made available under the terms of the + * BSD 3-Clause license which is available at + * https://opensource.org/licenses/BSD-3-Clause + * + * SPDX-FileCopyrightText: 2022 Deutsche Telekom AG + * SPDX-FileContributor: Sartura Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef SYSTEM_PLUGIN_DATASTORE_RUNNING_STORE_H +#define SYSTEM_PLUGIN_DATASTORE_RUNNING_STORE_H + +#include +#include + +int system_running_ds_store(system_ctx_t *ctx, sr_session_ctx_t *session); + +#endif // SYSTEM_PLUGIN_DATASTORE_RUNNING_STORE_H \ No newline at end of file diff --git a/src/plugins/ietf-system/plugin.c b/src/plugins/ietf-system/plugin.c index 5d435ba..c943b17 100644 --- a/src/plugins/ietf-system/plugin.c +++ b/src/plugins/ietf-system/plugin.c @@ -28,8 +28,8 @@ #include "srpc/types.h" // startup -#include "core/startup/load.h" -#include "core/startup/store.h" +#include "datastore/running/load.h" +#include "datastore/running/store.h" // subs #include "core/subscription/change.h" @@ -186,22 +186,22 @@ int sr_plugin_init_cb(sr_session_ctx_t *running_session, void **private_data) } if (empty_startup) { - SRPLG_LOG_INF(PLUGIN_NAME, "Startup datastore is empty"); + SRPLG_LOG_INF(PLUGIN_NAME, "Running datastore is empty"); SRPLG_LOG_INF(PLUGIN_NAME, "Loading initial system data"); // load data only into running DS - do not use startup unless said explicitly - error = system_startup_load_data(ctx, running_session); + error = system_running_ds_load(ctx, running_session); if (error) { - SRPLG_LOG_ERR(PLUGIN_NAME, "Error loading initial data into the startup datastore... exiting"); + SRPLG_LOG_ERR(PLUGIN_NAME, "Error loading initial data into the running datastore... exiting"); goto error_out; } } else { // make sure the data from startup DS is stored in the system - SRPLG_LOG_INF(PLUGIN_NAME, "Startup datastore contains data"); - SRPLG_LOG_INF(PLUGIN_NAME, "Storing startup datastore data in the system"); + SRPLG_LOG_INF(PLUGIN_NAME, "Running datastore contains data"); + SRPLG_LOG_INF(PLUGIN_NAME, "Storing running datastore data in the system"); // check and apply if needed data from startup to the system - error = system_startup_store_data(ctx, startup_session); + error = system_running_ds_store(ctx, startup_session); if (error) { SRPLG_LOG_ERR(PLUGIN_NAME, "Error applying initial data from startup datastore to the system... exiting"); goto error_out;