diff --git a/board/common/rootfs/etc/nginx/restconf.app b/board/common/rootfs/etc/nginx/restconf.app index 7c8caddae..45a047e51 100644 --- a/board/common/rootfs/etc/nginx/restconf.app +++ b/board/common/rootfs/etc/nginx/restconf.app @@ -1,5 +1,11 @@ # /telemetry/optics is for streaming (not used atm) +# Proxy buffer settings for large files +proxy_buffering off; # Disable buffering for streaming +proxy_request_buffering off; # Stream request body immediately +proxy_max_temp_file_size 0; # No temp files location ~ ^/(restconf|yang|.well-known)/ { + client_max_body_size 200M; + client_body_buffer_size 1M; grpc_pass grpc://[::1]:10080; grpc_set_header Host $host; grpc_set_header X-Real-IP $remote_addr; diff --git a/src/confd/configure.ac b/src/confd/configure.ac index 12982e00d..1115beb8b 100644 --- a/src/confd/configure.ac +++ b/src/confd/configure.ac @@ -78,6 +78,7 @@ PKG_CHECK_MODULES([jansson], [jansson >= 2.0.0]) PKG_CHECK_MODULES([libite], [libite >= 2.6.1]) PKG_CHECK_MODULES([sysrepo], [sysrepo >= 2.2.36]) PKG_CHECK_MODULES([libsrx], [libsrx >= 1.0.0]) +PKG_CHECK_MODULES([libssl], [libssl >= 1.0.0]) # Control build with automake flags AM_CONDITIONAL(CONTAINERS, [test "x$enable_containers" != "xno"]) diff --git a/src/confd/src/Makefile.am b/src/confd/src/Makefile.am index 87beb5920..356ffe25a 100644 --- a/src/confd/src/Makefile.am +++ b/src/confd/src/Makefile.am @@ -12,6 +12,7 @@ confd_plugin_la_CFLAGS = \ $(libite_CFLAGS) \ $(sysrepo_CFLAGS) \ $(libsrx_CFLAGS) \ + $(libssl_CFLAGS) \ $(CFLAGS) confd_plugin_la_LIBADD = \ @@ -20,7 +21,8 @@ confd_plugin_la_LIBADD = \ $(jansson_LIBS) \ $(libite_LIBS) \ $(sysrepo_LIBS) \ - $(libsrx_LIBS) + $(libsrx_LIBS) \ + $(libssl_LIBS) confd_plugin_la_SOURCES = \ base64.c base64.h \ diff --git a/src/confd/src/infix-system-software.c b/src/confd/src/infix-system-software.c index 1b24a186e..b4e244221 100644 --- a/src/confd/src/infix-system-software.c +++ b/src/confd/src/infix-system-software.c @@ -1,6 +1,9 @@ /* SPDX-License-Identifier: BSD-3-Clause */ #include #include +#include +#include +#include #include "core.h" #include "rauc-installer.h" @@ -21,24 +24,111 @@ static RaucInstaller *infix_system_sw_new_rauc(void) return rauc; } +static int base64_decode_inplace(char *input, size_t input_len, size_t *output_len) +{ + BIO *bio, *b64; + int decode_len; + + bio = BIO_new_mem_buf(input, input_len); + if (!bio) { + return -1; + } + + b64 = BIO_new(BIO_f_base64()); + if (!b64) { + BIO_free(bio); + return -1; + } + + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + bio = BIO_push(b64, bio); + + /* Decode directly into the same buffer */ + decode_len = BIO_read(bio, input, input_len); + BIO_free_all(bio); + + if (decode_len < 0) { + return -1; + } + + *output_len = decode_len; + return 0; +} + static int infix_system_sw_install(sr_session_ctx_t *session, uint32_t sub_id, const char *path, const sr_val_t *input, const size_t input_cnt, sr_event_t event, unsigned request_id, sr_val_t **output, size_t *output_cnt, void *priv) { - char *url = input->data.string_val; sr_error_t srerr = SR_ERR_OK; GError *raucerr = NULL; - RaucInstaller *rauc; + RaucInstaller *rauc = NULL; + char *install_source = NULL; + + const char *url = NULL; + char *binary_data = NULL; + size_t binary_len = 0; + size_t decoded_len = 0; + + for (size_t i = 0; i < input_cnt; i++) { + if (strcmp(input[i].xpath, "/infix-system:install-bundle/url") == 0) { + if (input[i].type == SR_STRING_T) { + url = input[i].data.string_val; + } + } else if (strcmp(input[i].xpath, "/infix-system:install-bundle/image") == 0) { + if (input[i].type == SR_BINARY_T) { + binary_data = (char *)input[i].data.binary_val; // Cast away const for in-place decode + binary_len = strlen(binary_data); // Length of base64 string + } + } + } - DEBUG("url:%s", url); + if (url) { + DEBUG("Installing from URL: %s", url); + install_source = (char *)url; + + } else if (binary_data) { + const char *temp_dir = "/tmp"; + char path[256]; + FILE *fp; + + DEBUG("Installing from uploaded binary data (%zu bytes base64)", binary_len); + + if (base64_decode_inplace(binary_data, binary_len, &decoded_len) != 0) { + sr_session_set_netconf_error(session, "application", "invalid-value", + NULL, NULL, "Failed to decode base64 image data", 0); + srerr = SR_ERR_INVAL_ARG; + goto cleanup; + } + + fmkpath(0775, "%s/images", temp_dir); + snprintf(path, sizeof(path), "%s/images/install_bundle", temp_dir); + + fp = fopen(path, "wb"); + if (!fp) { + ERROR("Could not open %s", path); + return SR_ERR_NO_MEMORY; + } + + fwrite(binary_data, sizeof(char), decoded_len, fp); + fclose(fp); + install_source = path; + + } else { + ERROR("Unknown source"); + return 0; + } rauc = infix_system_sw_new_rauc(); - if (!rauc) - return SR_ERR_INTERNAL; + if (!rauc) { + sr_session_set_netconf_error(session, "application", "operation-failed", + NULL, NULL, "Failed to initialize RAUC installer", 0); + srerr = SR_ERR_INTERNAL; + goto cleanup; + } - rauc_installer_call_install_sync(rauc, url, NULL, &raucerr); + rauc_installer_call_install_sync(rauc, install_source, NULL, &raucerr); if (raucerr) { sr_session_set_netconf_error(session, "application", "operation-failed", NULL, NULL, raucerr->message, 0); @@ -46,13 +136,18 @@ static int infix_system_sw_install(sr_session_ctx_t *session, uint32_t sub_id, srerr = SR_ERR_OPERATION_FAILED; } - g_object_unref(rauc); +cleanup: + if (rauc) { + g_object_unref(rauc); + } + return srerr; } + /* boot order can only be: primary, secondary and net, limited by model - */ +*/ static int infix_system_sw_set_boot_order(sr_session_ctx_t *session, uint32_t sub_id, const char *path, const sr_val_t *input, const size_t input_cnt, sr_event_t event, @@ -63,24 +158,24 @@ static int infix_system_sw_set_boot_order(sr_session_ctx_t *session, uint32_t su const sr_val_t *val = &input[i]; if (i != 0) - strlcat(boot_order, " ", sizeof(boot_order)); - strlcat(boot_order, val->data.string_val, sizeof(boot_order)); - } - - if (fexist("/sys/firmware/devicetree/base/chosen/u-boot,version")) { - if (systemf("fw_setenv BOOT_ORDER %s", boot_order)) { - ERROR("Set-boot-order: Failed to set boot order in U-Boot"); - return SR_ERR_INTERNAL; - } - } else if (fexist("/mnt/aux/grub/grubenv")) { - if (systemf("grub-editenv /mnt/aux/grub/grubenv set ORDER=\"%s\"", boot_order)) { - ERROR("Set-boot-order: Failed to set boot order in Grub"); - return SR_ERR_INTERNAL; - } - } else { - ERROR("No supported boot loader found"); - return SR_ERR_UNSUPPORTED; - } + strlcat(boot_order, " ", sizeof(boot_order)); + strlcat(boot_order, val->data.string_val, sizeof(boot_order)); + } + + if (fexist("/sys/firmware/devicetree/base/chosen/u-boot,version")) { + if (systemf("fw_setenv BOOT_ORDER %s", boot_order)) { + ERROR("Set-boot-order: Failed to set boot order in U-Boot"); + return SR_ERR_INTERNAL; + } + } else if (fexist("/mnt/aux/grub/grubenv")) { + if (systemf("grub-editenv /mnt/aux/grub/grubenv set ORDER=\"%s\"", boot_order)) { + ERROR("Set-boot-order: Failed to set boot order in Grub"); + return SR_ERR_INTERNAL; + } + } else { + ERROR("No supported boot loader found"); + return SR_ERR_UNSUPPORTED; + } return SR_ERR_OK; } diff --git a/src/confd/yang/confd/infix-system-software.yang b/src/confd/yang/confd/infix-system-software.yang index 907b4224d..41058f4e7 100644 --- a/src/confd/yang/confd/infix-system-software.yang +++ b/src/confd/yang/confd/infix-system-software.yang @@ -204,16 +204,42 @@ submodule infix-system-software { description "Upgrade the system's software by installing the specified bundle."; input { - leaf url { - type string; + choice source { mandatory true; description - "The location of the software bundle, specified as a Uniform - Resource Locator (URL). Currently supported protocols include - FTP, HTTP(S) and SCP."; + "Source of the software bundle to install."; + case url { + leaf url { + type string; + description + "The location of the software bundle, specified as a Uniform + Resource Locator (URL). Currently supported protocols include + FTP, HTTP(S) and SCP."; + } + } + + case upload { + leaf image { + type binary; + description + "The image data to install, provided as base64-encoded binary data."; + } + } } } } + rpc install-upload-bundle { + nacm:default-deny-all; + description "Upgrade the system's software by installing from a supplied blob."; + input { + leaf image { + type binary; + mandatory true; + description "The image to install"; + } + } + } + rpc set-boot-order { nacm:default-deny-all; description