From: Daniel F. Dickinson Date: Mon, 6 Jul 2026 23:00:39 +0000 (-0400) Subject: nut: add more common validators and add more validation X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=e3f051cefc5c43f97f28d32976a69622bf8cd98b;p=openwrt-packages.git nut: add more common validators and add more validation Factor out some common validation code into some validator functions, and add more UCI config validation. Signed-off-by: Daniel F. Dickinson --- diff --git a/net/nut/files/nut-cgi.init b/net/nut/files/nut-cgi.init index 9c9592358..c44c7773a 100644 --- a/net/nut/files/nut-cgi.init +++ b/net/nut/files/nut-cgi.init @@ -170,12 +170,10 @@ validate_host() { fi ;; hostname) - case "$hostname" in - "" | *[!a-zA-Z0-9.:-\[\]-]*) + if ! check_safe_hostname_or_ip "$hostname"; then log_validation_error "$var" "$ups" return 1 - ;; - esac + fi ;; displayname) # We accept a minimally useful set of characters for a display name @@ -191,24 +189,9 @@ validate_host() { esac ;; port) - # We don't log missing port log, as port is optional (NUT defaults - # to using 3493 when it is not present) - if [ -n "$port" ]; then - case "$port" in - 0*) - log_validation_error "$var" "$ups" - return 1 - ;; - *[!0-9]*) - log_validation_error "$var" "$ups" - return 1 - ;; - esac - # Catches illegal port numbers, including negative port numbers - if [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then - log_error "Port set, but not between 1-65535 for '$ups'" nut-cgi nut-cgi - return 1 - fi + if ! check_port "$port"; then + log_validation_error "$var" "$ups" + return 1 fi ;; esac diff --git a/net/nut/files/nut-common.sh.functions b/net/nut/files/nut-common.sh.functions index c077c27f5..368ef9b0a 100644 --- a/net/nut/files/nut-common.sh.functions +++ b/net/nut/files/nut-common.sh.functions @@ -68,6 +68,18 @@ check_valid_user_group_name() { return 0 } +# Just a check for safe/allowed characters, not a full validation +check_safe_hostname_or_ip() { + local hostname="$1" + + case "$hostname" in + "" | *[!a-zA-Z0-9.:-\[\]-]*) + return 1 + ;; + esac + return 0 +} + # shellcheck disable=SC2329,SC2317 check_valid_hex_number() { local number="$1" @@ -113,6 +125,58 @@ check_valid_hex_number() { # catch-all have a return) and shellcheck will complain if we do. } +# also passes on an empty value +check_signed_int() { + local number="$1" + + # a minus sign with no number is invalid + if [ "$number" = "-" ]; then + return 1 + fi + + case "${number#[-]}" in + *[!0123456789]*) + return 1 + ;; + *) + return 0 + ;; + esac +} + +# also passes on an empty value +check_unsigned_int() { + local number="$1" + + case "$number" in + *[!0123456789]*) + return 1 + ;; + *) + return 0 + ;; + esac +} + +# check for valid port, if present +# also passes on an empty value +check_port() { + local port="$1" + + if [ -n "$port" ]; then + case "$port" in + *[!0-9]*) + return 1 + ;; + esac + # Catches port numbers outside valid range (1-65535) + if [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then + return 1 + fi + fi + return 0 +} + # Wrap logging, in case we decide to update the logging, everywhere log_msg() { local reason="$1" diff --git a/net/nut/files/nut-monitor-config.sh.functions b/net/nut/files/nut-monitor-config.sh.functions index 865e46689..35f305b21 100644 --- a/net/nut/files/nut-monitor-config.sh.functions +++ b/net/nut/files/nut-monitor-config.sh.functions @@ -137,22 +137,15 @@ nut_upsmon_conf() { OVERDURATION | \ OBLBDURATION) config_get val "$cfg" "$uci_option" - case "${val#[-]}" in - *[!0123456789]*) + if ! check_signed_int "$val"; then log_error "upsmon section '$cfg' bad value for '$uci_option'" nut-monitor-config.sh nut-monitor-config return 1 - ;; - '') - # Ignore options with no configuration - : - ;; - *) + elif [ -n "$val" ]; then # Ignore options with no configuration if ! printf "%s %s\n" "$nut_option" "$val" >>"$config_file"; then log_error "upsmon section '$cfg' failed to write '$nut_option'" nut-monitor-config.sh nut-monitor-config return 1 fi - ;; - esac + fi ;; # integer: negative values not allowed DEADTIME | \ @@ -165,22 +158,15 @@ nut_upsmon_conf() { POLLFREQALERT | \ RBWARNTIME) config_get val "$cfg" "$uci_option" - case "$val" in - *[!0123456789]*) + if ! check_unsigned_int "$val"; then log_error "upsmon section '$cfg' bad value for '$uci_option'" nut-monitor-config.sh nut-monitor-config return 1 - ;; - '') - # Ignore options with no configuration - : - ;; - *) + elif [ -n "$val" ]; then # Ignore options with no configuration if ! printf "%s %s\n" "$nut_option" "$val" >>"$config_file"; then log_error "upsmon section '$cfg' failed to write '$nut_option'" nut-monitor-config.sh nut-monitor-config return 1 fi - ;; - esac + fi ;; SHUTDOWNCMD) upsmon_conf_get_write "$cfg" "$config_file" "$uci_option" "$nut_option" @@ -258,12 +244,48 @@ nut_upsmon_add() { local type config_get upsname "$cfg" upsname "$cfg" + if ! check_safe_uci_name "$upsname"; then + log_error "upsmon section '$cfg' has invalid upsname" nut-monitor-config.sh nut-monitor-config + upsmon_conf_fail="true" + # we do not error exit so as not abort processing of other sections on the config_foreach + return 0 + fi config_get hostname "$cfg" hostname localhost + if ! check_safe_hostname_or_ip "$hostname"; then + log_error "upsmon section '$cfg' has invalid hostname" nut-monitor-config.sh nut-monitor-config + upsmon_conf_fail="true" + # we do not error exit so as not abort processing of other sections on the config_foreach + return 0 + fi config_get port "$cfg" port + if ! check_port "$port"; then + log_error "upsmon section '$cfg' has invalid port" nut-monitor-config.sh nut-monitor-config + upsmon_conf_fail="true" + # we do not error exit so as not abort processing of other sections on the config_foreach + return 0 + fi config_get powervalue "$cfg" powervalue 1 + if ! check_unsigned_int "$powervalue" || [ -z "$powervalue" ]; then + log_error "upsmon section '$cfg' has invalid powervalue" nut-monitor-config.sh nut-monitor-config + upsmon_conf_fail="true" + # we do not error exit so as not abort processing of other sections on the config_foreach + return 0 + fi config_get username "$cfg" username config_get password "$cfg" password config_get type "$cfg" type secondary + case "$type" in + primary | secondary) + # primary or secondary are the only allowed values + : + ;; + *) + log_error "upsmon section '$cfg' has invalid user/ups type" nut-monitor-config.sh nut-monitor-config + upsmon_conf_fail="true" + # we do not error exit so as not abort processing of other sections on the config_foreach + return 0 + ;; + esac system="$upsname@$hostname" if [ -n "$port" ]; then diff --git a/net/nut/files/nut-monitor.init b/net/nut/files/nut-monitor.init index 7fa9dccbf..959448b8c 100644 --- a/net/nut/files/nut-monitor.init +++ b/net/nut/files/nut-monitor.init @@ -201,6 +201,8 @@ stop_service() { } service_triggers() { + local val interface_reload_delay + # No config, or error loading config is fatal config_load nut_monitor || { log_config_load_error "nut_monitor" "nut-monitor" "nut-monitor" @@ -208,6 +210,10 @@ service_triggers() { } config_get interface_reload_delay upsmon interface_reload_delay $DEFAULT_PROCD_INTERFACE_RELOAD_DELAY + if ! check_unsigned_int "$interface_reload_delay" || [ -z "$interface_reload_delay" ]; then + log_msg "interface_reload_delay must be an unsigned integer" nut-monitor nut-monitor warn + interface_reload_delay="$DEFAULT_PROCD_INTERFACE_RELOAD_DELAY" + fi # We do not pass a variadic instance name as the nut-monitor initscript does # not need an additional instance name argument, only the initscript name diff --git a/net/nut/files/nut-server-config.sh.functions b/net/nut/files/nut-server-config.sh.functions index f5533b15b..f688e2e2f 100644 --- a/net/nut/files/nut-server-config.sh.functions +++ b/net/nut/files/nut-server-config.sh.functions @@ -11,7 +11,7 @@ # * /lib/functions.sh has been sourced # * /lib/functions/nut/nut-service.sh has been sourced -# * /lib/functions/nut/nut-common.sh must be source and find_statepath executed +# * /lib/functions/nut/nut-common.sh must be sourced and find_statepath executed # before build_config is called # Ensure find_statepath from nut-service.sh is executed @@ -158,7 +158,7 @@ build_server_config() { return 1 fi else - # Otherwise if nut-server is already configured, make sure both + # Otherwise if nut-monitor is already configured, make sure both # nut-server (this service) and nut-monitor are started if grep -q '^MODE=netclient' "$NUT_CONF"; then # In modern OpenWrt 'sed -i' modifies the specified files, without backup diff --git a/net/nut/files/nut-server.init b/net/nut/files/nut-server.init index e317e46a3..1354e90ab 100644 --- a/net/nut/files/nut-server.init +++ b/net/nut/files/nut-server.init @@ -556,6 +556,10 @@ service_triggers() { } config_get interface_reload_delay upsd interface_reload_delay $DEFAULT_PROCD_INTERFACE_RELOAD_DELAY + if ! check_unsigned_int "$interface_reload_delay" || [ -z "$interface_reload_delay" ]; then + log_msg "interface_reload_delay must be an unsigned integer" nut-server nut-server warn + interface_reload_delay="$DEFAULT_PROCD_INTERFACE_RELOAD_DELAY" + fi interface_triggers "add_trigger" "upsd" "$interface_reload_delay" "nut-server" "upsd" procd_add_reload_trigger "nut_server"