diff --git a/board/common/rootfs/etc/fstab b/board/common/rootfs/etc/fstab index fc5850c79..70d11aac7 100644 --- a/board/common/rootfs/etc/fstab +++ b/board/common/rootfs/etc/fstab @@ -15,9 +15,9 @@ cfgfs /config configfs nofail,noauto 0 0 # The chosen backing storage for the overlays placed on /cfg, /etc, # /home, /root, and /var, are determined dynamically by /usr/libexec/infix/mnt # depending on the available devices. -mnttmp /mnt/tmp tmpfs defaults 0 0 -LABEL=aux /mnt/aux auto noatime,nodiratime,noauto,commit=30,errors=remount-ro 0 0 -LABEL=var /mnt/var auto noatime,nodiratime,noauto,commit=30,errors=remount-ro 0 0 -LABEL=cfg /mnt/cfg auto noatime,nodiratime,noauto,commit=30,errors=remount-ro 0 0 -hostfs /mnt/host 9p cache=none,msize=16384,noauto 0 0 -/usr/libexec/infix/mnt# /cfg helper none 0 0 +mnttmp /mnt/tmp tmpfs defaults 0 0 +LABEL=aux /mnt/aux auto noatime,nodiratime,noauto,errors=remount-ro 0 0 +LABEL=var /mnt/var ext4 noatime,nodiratime,noauto,commit=30,errors=remount-ro 0 0 +LABEL=cfg /mnt/cfg ext4 noatime,nodiratime,noauto,commit=30,errors=remount-ro 0 0 +hostfs /mnt/host 9p cache=none,msize=16384,noauto 0 0 +/usr/libexec/infix/mnt# /cfg helper none 0 0 diff --git a/board/common/rootfs/usr/libexec/infix/mnt b/board/common/rootfs/usr/libexec/infix/mnt index d46af0c64..4421613f3 100755 --- a/board/common/rootfs/usr/libexec/infix/mnt +++ b/board/common/rootfs/usr/libexec/infix/mnt @@ -44,12 +44,15 @@ check_factory() factory_reset() { find /sys/class/leds/ -type l -exec sh -c 'echo 100 > $0/brightness' {} \; - logger $opt -p user.crit -t "$nm" "Resetting to factory defaults." + print_start "Resetting to factory defaults." + logger $opt -p user.notice -t "$nm" "Resetting to factory defaults." rm -rf /mnt/cfg/* /mnt/var/* - - logger $opt -p user.crit -t "$nm" "Factory reset complete." sync + + logger $opt -p user.notice -t "$nm" "Factory reset complete." + print_end 0 "Factory reset complete." + print_restore } is_mmc() @@ -105,15 +108,18 @@ find_partition_by_label() esac disk="/dev/$devname" + + # + # 1. Try GPT/MBR partition label using sgdisk + # result=$(sgdisk -p "$disk" 2>/dev/null | awk -v label="$label" -v devname="$devname" ' - /^ *[0-9]/ { + /^ *[0-9]/ { if ($7 == label) { - if (devname ~ /^(mmcblk|nvme|loop)/) { - print devname "p" $1 - } else { - print devname $1 - } - exit 0 + if (devname ~ /^(mmcblk|nvme|loop)/) + print devname "p" $1; + else + print devname $1; + exit 0; } } ') @@ -122,7 +128,30 @@ find_partition_by_label() echo "$result" return 0 fi + + # + # 2. Fallback: Check if the whole disk is an ext4/ext2/ext3 filesystem + # + + # Check for ext4/ext2/ext3 magic number (0xEF53) at offset 1080 (1024+56). + magic_number=$(dd if="$disk" bs=1 skip=1080 count=2 2>/dev/null | od -t x2 -A n | tr -d ' \n') + + # Check for both Little-Endian ('53ef') and Big-Endian ('ef53') interpretations of 0xEF53. + # This supports bi-endian architectures like MIPS that may run in BE mode, + # as well as the LE mode which is standard for RISC-V and ext filesystems. + if [ "$magic_number" = "ef53" ] || [ "$magic_number" = "53ef" ]; then + + # Read the volume label from offset 1144 (1024+120) + fslabel=$(dd if="$disk" bs=1 skip=1144 count=16 2>/dev/null | tr -d '\000') + logger $opt -p user.notice -t "$nm" "Found label $fslabel on disk $disk ..." + + if [ "$fslabel" = "$label" ]; then + echo "$devname" + return 0 + fi + fi done + return 1 } @@ -273,6 +302,9 @@ mount_rw() # If something is already setup, leave it be. mountpoint -q "/$1" && return 0 + # If partition doesn't exist (var is optional), signal caller. + find_partition_by_label "$1" >/dev/null || return 1 + # Check if /var has been resized to fill the sdcard/eMMC if [ "$1" = "var" ] && is_mmc; then if [ -f /mnt/aux/resized ] || [ -f /mnt/aux/resized.failed ]; then @@ -289,8 +321,10 @@ mount_rw() # TODO: Also look for UBI partitions - # - tune2fs -c 0 -i 0 LABEL="$1" 2>/dev/null + # Disable periodic fsck, yet keeping safety checks on ext4 + if grep "LABEL=$label" /etc/fstab |grep -q ext4; then + tune2fs -c 0 -i 0 LABEL="$1" 2>/dev/null + fi mount LABEL="$1" 2>/dev/null && return 0 return 1 diff --git a/src/confd/src/core.c b/src/confd/src/core.c index 8ba0ba985..4fbf1bebb 100644 --- a/src/confd/src/core.c +++ b/src/confd/src/core.c @@ -8,16 +8,9 @@ struct confd confd; -int core_startup_save(sr_session_ctx_t *session, uint32_t sub_id, const char *module, - const char *xpath, sr_event_t event, unsigned request_id, void *priv) +static int startup_save(sr_session_ctx_t *session, uint32_t sub_id, const char *model, + const char *xpath, sr_event_t event, unsigned request_id, void *priv) { - sr_event_t last_event = -1; - static unsigned int last_request = -1; - if (last_event == event && last_request == request_id) - return SR_ERR_OK; - last_event = event; - last_request = request_id; - /* skip in bootstrap, triggered by load script to initialize startup datastore */ if (systemf("runlevel >/dev/null 2>&1")) return SR_ERR_OK; @@ -33,9 +26,10 @@ static confd_dependency_t add_dependencies(struct lyd_node **diff, const char *x struct lyd_node *new_node = NULL; struct lyd_node *target = NULL; struct lyd_node *root = NULL; - int rc; if (!lydx_get_xpathf(*diff, "%s", xpath)) { + int rc; + /* Create the path, potentially creating a new tree */ rc = lyd_new_path(NULL, LYD_CTX(*diff), xpath, value, LYD_NEW_PATH_UPDATE, &new_node); if (rc != LY_SUCCESS || !new_node) { @@ -147,7 +141,7 @@ static confd_dependency_t handle_dependencies(struct lyd_node **diff, struct lyd return result; } -static int change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *module_name, +static int change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *model_name, const char *xpath, sr_event_t event, uint32_t request_id, void *_confd) { struct lyd_node *diff = NULL, *config = NULL; @@ -258,16 +252,20 @@ static int change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *mod AUDIT("The new configuration has been applied."); } + free_diff: - lyd_free_tree(diff); - return rc; + lyd_free_tree(diff); + return rc; } -static inline int subscribe_module(char *model, struct confd *confd, int flags) { - return sr_module_change_subscribe(confd->session, model, "//.", change_cb, confd, - CB_PRIO_PRIMARY, SR_SUBSCR_CHANGE_ALL_MODULES | SR_SUBSCR_DEFAULT | flags, &confd->sub) && - sr_module_change_subscribe(confd->startup, model, "//.", core_startup_save, NULL, - CB_PRIO_PASSIVE, SR_SUBSCR_PASSIVE | SR_SUBSCR_CHANGE_ALL_MODULES, &confd->sub); +static inline int subscribe_model(char *model, struct confd *confd, int flags) +{ + return sr_module_change_subscribe(confd->session, model, "//.", change_cb, confd, + CB_PRIO_PRIMARY, SR_SUBSCR_CHANGE_ALL_MODULES | + SR_SUBSCR_DEFAULT | flags, &confd->sub) || + sr_module_change_subscribe(confd->startup, model, "//.", startup_save, NULL, + CB_PRIO_PASSIVE, SR_SUBSCR_CHANGE_ALL_MODULES | + SR_SUBSCR_PASSIVE, &confd->sub); } int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv) @@ -295,7 +293,7 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv) if (!confd.conn) goto err; - /* The startup datastore is used for the core_startup_save() hook */ + /* The startup datastore is used for the startup_save() hook */ rc = sr_session_start(confd.conn, SR_DS_STARTUP, &confd.startup); if (rc) goto err; @@ -314,69 +312,69 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv) */ confd.ifquirks = json_load_file("/etc/product/interface-quirks.json", 0, NULL); - rc = subscribe_module("ietf-interfaces", &confd, 0); + rc = subscribe_model("ietf-interfaces", &confd, 0); if (rc) { ERROR("Failed to subscribe to ietf-interfaces"); goto err; } - rc = subscribe_module("ietf-netconf-acm", &confd, 0); + rc = subscribe_model("ietf-netconf-acm", &confd, 0); if (rc) { ERROR("Failed to subscribe to ietf-netconf-acm"); goto err; } - rc = subscribe_module("infix-dhcp-client", &confd, 0); + rc = subscribe_model("infix-dhcp-client", &confd, 0); if (rc) { ERROR("Failed to subscribe to infix-dhcp-client"); goto err; } - rc = subscribe_module("ietf-keystore", &confd, SR_SUBSCR_UPDATE); + rc = subscribe_model("ietf-keystore", &confd, SR_SUBSCR_UPDATE); if (rc) { ERROR("Failed to subscribe to ietf-keystore"); goto err; } - rc = subscribe_module("infix-services", &confd, 0); + rc = subscribe_model("infix-services", &confd, 0); if (rc) { ERROR("Failed to subscribe to infix-services"); goto err; } - rc = subscribe_module("ietf-system", &confd, 0); + rc = subscribe_model("ietf-system", &confd, 0); if (rc) { ERROR("Failed to subscribe to ietf-system"); goto err; } - rc = subscribe_module("ieee802-dot1ab-lldp", &confd, 0); + rc = subscribe_model("ieee802-dot1ab-lldp", &confd, 0); if (rc) { ERROR("Failed to subscribe to ieee802-dot1ab-lldp"); goto err; } #ifdef CONTAINERS - rc = subscribe_module("infix-containers", &confd, 0); + rc = subscribe_model("infix-containers", &confd, 0); if (rc) { ERROR("Failed to subscribe to infix-containers"); goto err; } #endif - rc = subscribe_module("infix-dhcp-server", &confd, 0); + rc = subscribe_model("infix-dhcp-server", &confd, 0); if (rc) { ERROR("Failed to subscribe to infix-dhcp-server"); goto err; } - rc = subscribe_module("ietf-routing", &confd, 0); + rc = subscribe_model("ietf-routing", &confd, 0); if (rc) { ERROR("Failed to subscribe to ietf-routing"); goto err; } - rc = subscribe_module("ietf-hardware", &confd, 0); + rc = subscribe_model("ietf-hardware", &confd, 0); if (rc) { ERROR("Failed to subscribe to ietf-hardware"); goto err; } - rc = subscribe_module("infix-firewall", &confd, 0); + rc = subscribe_model("infix-firewall", &confd, 0); if (rc) { ERROR("Failed to subscribe to infix-firewall"); goto err; } - rc = subscribe_module("infix-meta", &confd, SR_SUBSCR_UPDATE); + rc = subscribe_model("infix-meta", &confd, SR_SUBSCR_UPDATE); if (rc) { ERROR("Failed to subscribe to infix-meta"); goto err; diff --git a/src/confd/src/core.h b/src/confd/src/core.h index 0317f83ec..d7c2f2e0d 100644 --- a/src/confd/src/core.h +++ b/src/confd/src/core.h @@ -135,7 +135,6 @@ struct confd { struct dagger netdag; }; -int core_startup_save (sr_session_ctx_t *, uint32_t, const char *, const char *, sr_event_t, unsigned, void *); static inline int register_change(sr_session_ctx_t *session, const char *module, const char *xpath, int flags, sr_module_change_cb cb, void *arg, sr_subscription_ctx_t **sub) diff --git a/src/confd/src/ietf-keystore.c b/src/confd/src/ietf-keystore.c index a87303ee5..fa1d786fe 100644 --- a/src/confd/src/ietf-keystore.c +++ b/src/confd/src/ietf-keystore.c @@ -51,89 +51,122 @@ static char *filerd(const char *fn, size_t len) return buf; } -int ietf_keystore_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd) +static int gen_hostkey(const char *name, struct lyd_node *change) { - struct lyd_node *changes, *change; - sr_val_t *list = NULL; + const char *private_key, *public_key; int rc = SR_ERR_OK; + + private_key = lydx_get_cattr(change, "cleartext-private-key"); + public_key = lydx_get_cattr(change, "public-key"); + + if (mkdir(SSH_HOSTKEYS_NEXT, 0600) && (errno != EEXIST)) { + ERRNO("Failed creating %s", SSH_HOSTKEYS_NEXT); + rc = SR_ERR_INTERNAL; + } + + if (systemf("/usr/libexec/infix/mksshkey %s %s %s %s", name, SSH_HOSTKEYS_NEXT, public_key, private_key)) + rc = SR_ERR_INTERNAL; + + return rc; +} + +static int keystore_update(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff) +{ + const char *xpath = "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key"; + sr_val_t *list = NULL; size_t count = 0; - if (diff && !lydx_find_xpathf(diff, XPATH_KEYSTORE_)) - return SR_ERR_OK; + int rc; - switch (event) { - case SR_EV_UPDATE: - rc = sr_get_items(session, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key", 0, 0, &list, &count); - if (rc != SR_ERR_OK) { - ERROR("Cannot find any asymmetric keys in configuration"); - return 0; + rc = sr_get_items(session, xpath, 0, 0, &list, &count); + if (rc != SR_ERR_OK) { + ERROR("Cannot find any asymmetric keys in configuration"); + return 0; + } + + for (size_t i = 0; i < count; i++) { + char *name = srx_get_str(session, "%s/name", list[i].xpath); + char *public_key_format, *private_key_format; + char *pub_key = NULL, *priv_key = NULL; + sr_val_t *entry = &list[i]; + + if (srx_isset(session, "%s/cleartext-private-key", entry->xpath) || + srx_isset(session, "%s/public-key", entry->xpath)) + continue; + + public_key_format = srx_get_str(session, "%s/public-key-format", entry->xpath); + if (!public_key_format) + continue; + + private_key_format = srx_get_str(session, "%s/private-key-format", entry->xpath); + if (!private_key_format) { + free(public_key_format); + continue; } + if (strcmp(private_key_format, "infix-crypto-types:rsa-private-key-format") || + strcmp(public_key_format, "infix-crypto-types:ssh-public-key-format")) + continue; - for (size_t i = 0; i < count; ++i) { - sr_val_t *entry = &list[i]; - - if (!srx_isset(session, "%s/cleartext-private-key", entry->xpath) && !srx_isset(session, "%s/public-key", entry->xpath)) { - char *private_key_format, *public_key_format; - - public_key_format = srx_get_str(session, "%s/public-key-format", entry->xpath); - if (!public_key_format) - continue; - private_key_format = srx_get_str(session, "%s/private-key-format", entry->xpath); - if (!private_key_format) { - free(public_key_format); - continue; - } - - if (!strcmp(private_key_format, "infix-crypto-types:rsa-private-key-format") && - !strcmp(public_key_format, "infix-crypto-types:ssh-public-key-format")) { - char *pub_key = NULL, *priv_key = NULL, *name; - - name = srx_get_str(session, "%s/name", entry->xpath); - NOTE("SSH key (%s) does not exist, generating...", name); - if (systemf("/usr/libexec/infix/mkkeys %s %s", SSH_PRIVATE_KEY, SSH_PUBLIC_KEY)) { - ERROR("Failed to generate SSH keys for %s", name); - goto next; - } - - priv_key = filerd(SSH_PRIVATE_KEY, filesz(SSH_PRIVATE_KEY)); - if (!priv_key) - goto next; - - pub_key = filerd(SSH_PUBLIC_KEY, filesz(SSH_PUBLIC_KEY)); - if (!pub_key) - goto next; - - rc = srx_set_str(session, priv_key, 0, "%s/cleartext-private-key", entry->xpath); - if (rc) { - ERROR("Failed setting private key for %s... rc: %d", name, rc); - goto next; - } - rc = srx_set_str(session, pub_key, 0, "%s/public-key", entry->xpath); - if (rc != SR_ERR_OK) { - ERROR("Failed setting public key for %s... rc: %d", name, rc); - goto next; - } - next: - if (erase(SSH_PRIVATE_KEY)) - ERRNO("Failed removing SSH server private key"); - if (erase(SSH_PUBLIC_KEY)) - ERRNO("Failed removing SSH server public key"); - - if (priv_key) - free(priv_key); - - if (pub_key) - free(pub_key); - - free(name); - } - free(public_key_format); - free(private_key_format); - } + NOTE("SSH key (%s) does not exist, generating...", name); + if (systemf("/usr/libexec/infix/mkkeys %s %s", SSH_PRIVATE_KEY, SSH_PUBLIC_KEY)) { + ERROR("Failed generating SSH keys for %s", name); + goto next; } - if (list) - sr_free_values(list, count); + priv_key = filerd(SSH_PRIVATE_KEY, filesz(SSH_PRIVATE_KEY)); + if (!priv_key) + goto next; + + pub_key = filerd(SSH_PUBLIC_KEY, filesz(SSH_PUBLIC_KEY)); + if (!pub_key) + goto next; + + rc = srx_set_str(session, priv_key, 0, "%s/cleartext-private-key", entry->xpath); + if (rc) { + ERROR("Failed setting private key for %s... rc: %d", name, rc); + goto next; + } + + rc = srx_set_str(session, pub_key, 0, "%s/public-key", entry->xpath); + if (rc != SR_ERR_OK) { + ERROR("Failed setting public key for %s... rc: %d", name, rc); + goto next; + } + next: + if (erase(SSH_PRIVATE_KEY)) + ERRNO("Failed removing SSH server private key"); + if (erase(SSH_PUBLIC_KEY)) + ERRNO("Failed removing SSH server public key"); + + if (priv_key) + free(priv_key); + + if (pub_key) + free(pub_key); + + free(name); + free(public_key_format); + free(private_key_format); + } + + if (list) + sr_free_values(list, count); + + return 0; +} + +int ietf_keystore_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, + sr_event_t event, struct confd *confd) +{ + struct lyd_node *changes, *change; + int rc = SR_ERR_OK; + + if (diff && !lydx_find_xpathf(diff, XPATH_KEYSTORE_)) + return SR_ERR_OK; + + switch (event) { + case SR_EV_UPDATE: + rc = keystore_update(session, config, diff); break; case SR_EV_CHANGE: case SR_EV_ENABLED: @@ -142,49 +175,35 @@ int ietf_keystore_change(sr_session_ctx_t *session, struct lyd_node *config, str rmrf(SSH_HOSTKEYS_NEXT); return SR_ERR_OK; case SR_EV_DONE: - if(fexist(SSH_HOSTKEYS_NEXT)) { - if(rmrf(SSH_HOSTKEYS)) { + if (fexist(SSH_HOSTKEYS_NEXT)) { + if (rmrf(SSH_HOSTKEYS)) ERRNO("Failed to remove old SSH hostkeys: %d", errno); - } - if (rename(SSH_HOSTKEYS_NEXT, SSH_HOSTKEYS)) ERRNO("Failed switching to new %s", SSH_HOSTKEYS); } return SR_ERR_OK; - default: return SR_ERR_OK; } changes = lydx_get_descendant(config, "keystore", "asymmetric-keys", "asymmetric-key", NULL); - LYX_LIST_FOR_EACH(changes, change, "asymmetric-key") { - const char *name, *private_key_type, *public_key_type; - const char *private_key, *public_key; + const char *name = lydx_get_cattr(change, "name"); + const char *type; - name = lydx_get_cattr(change, "name"); - private_key_type = lydx_get_cattr(change, "private-key-format"); - public_key_type = lydx_get_cattr(change, "public-key-format"); - - if (strcmp(private_key_type, "infix-crypto-types:rsa-private-key-format")) { - INFO("Private key %s is not of SSH type", name); + type = lydx_get_cattr(change, "private-key-format"); + if (strcmp(type, "infix-crypto-types:rsa-private-key-format")) { + INFO("Private key %s is not of SSH type (%s)", name, type); continue; } - if (strcmp(public_key_type, "infix-crypto-types:ssh-public-key-format")) { - INFO("Public key %s is not of SSH type", name); + type = lydx_get_cattr(change, "public-key-format"); + if (strcmp(type, "infix-crypto-types:ssh-public-key-format")) { + INFO("Public key %s is not of SSH type (%s)", name, type); continue; } - private_key = lydx_get_cattr(change, "cleartext-private-key"); - public_key = lydx_get_cattr(change, "public-key"); - - if (mkdir(SSH_HOSTKEYS_NEXT, 0600) && (errno != EEXIST)) { - ERRNO("Failed creating %s", SSH_HOSTKEYS_NEXT); - rc = SR_ERR_INTERNAL; - } - if(systemf("/usr/libexec/infix/mksshkey %s %s %s %s", name, SSH_HOSTKEYS_NEXT, public_key, private_key)) - rc = SR_ERR_INTERNAL; + gen_hostkey(name, change); } return rc; diff --git a/src/confd/src/infix-dhcp-server.c b/src/confd/src/infix-dhcp-server.c index 2a5431749..ffff18407 100644 --- a/src/confd/src/infix-dhcp-server.c +++ b/src/confd/src/infix-dhcp-server.c @@ -300,9 +300,6 @@ int infix_dhcp_server_change(sr_session_ctx_t *session, struct lyd_node *config, int enabled = 0, added = 0, deleted = 0; sr_error_t err = 0; - if (!lydx_get_xpathf(diff, CFG_XPATH)) - return SR_ERR_OK; - switch (event) { case SR_EV_DONE: break; @@ -312,6 +309,9 @@ int infix_dhcp_server_change(sr_session_ctx_t *session, struct lyd_node *config, return SR_ERR_OK; } + if (!lydx_get_xpathf(diff, CFG_XPATH)) + return SR_ERR_OK; + global = lydx_get_descendant(config, "dhcp-server", NULL); enabled = lydx_is_enabled(global, "enabled");