diff --git a/NEWS.adoc b/NEWS.adoc index ce57dbe55d..d1d71e427e 100644 --- a/NEWS.adoc +++ b/NEWS.adoc @@ -103,6 +103,11 @@ https://github.com/networkupstools/nut/milestone/13 - `upsmon` client updates: * Introduced support for `CERTFILE` option, so the client can identify itself to the data server also in OpenSSL builds. [issue #3331] + * Failure of SSL connection setup (e.g. due to inability to load the + NSS library, a practical regression since NUT v2.8.4 release, now that + success of SSL initialization with both backends is more diligently + tracked) should now not cause exit of the client if secure connection + is not required by its configuration in the first place. [#3420] - Introduced `ci_build.sh` settings and respective CI workflow settings to optionally re-use a `config.cache` file from older runs, and similar diff --git a/clients/upsmon.c b/clients/upsmon.c index 7e9a9918bf..962923b25c 100644 --- a/clients/upsmon.c +++ b/clients/upsmon.c @@ -4188,8 +4188,12 @@ int main(int argc, char *argv[]) } if (upscli_init2(certverify, certpath, certname, certpasswd, certfile) < 0) { - upsnotify(NOTIFY_STATE_STOPPING, "Failed upscli_init2()"); - exit(EXIT_FAILURE); + if (certverify || certpath || certname || certpasswd || certfile) { + upslogx(LOG_WARNING, "Failed upscli_init2() while SSL was required"); + upsnotify(NOTIFY_STATE_STOPPING, "Failed upscli_init2() while SSL was required"); + exit(EXIT_FAILURE); + } + upslogx(LOG_WARNING, "Failed upscli_init2() but SSL ability was not required"); } /* prep our signal handlers */ diff --git a/scripts/Windows/dllldd.sh b/scripts/Windows/dllldd.sh index 9d5209d260..659ae11c49 100755 --- a/scripts/Windows/dllldd.sh +++ b/scripts/Windows/dllldd.sh @@ -6,7 +6,7 @@ # for Windows, bundled with open-source dependencies. # # Copyright (C) -# 2022-2025 Jim Klimov +# 2022-2026 Jim Klimov # tools [ -n "${GREP}" ] || { GREP="`command -v grep`" && [ x"${GREP}" != x ] || { echo "$0: FAILED to locate GREP tool" >&2 ; exit 1 ; } ; } @@ -14,7 +14,25 @@ REGEX_WS="`printf '[\t ]'`" REGEX_NOT_WS="`printf '[^\t ]'`" -dllldd() ( + +print_MSYS_DLL_PATH() { + echo "${PATH}:${LD_LIBRARY_PATH}" | tr ':' '\n' | \ + while read D ; do + case "$D" in + ""|/?/*|*/Windows*|*/System*|*/Progra*) continue ;; + "${MSYS_HOME}"/*|/mingw*/*|/usr/*|/clang*/*|/?bin/*|/ucrt*/*|/opt/*|/home/*|/var/*|/tmp/*) + [ -d "$D" ] && printf '%s:' "$D" + ;; + esac + done | sed 's/:*$//' +} +SEARCH_DLL_PATH="`print_MSYS_DLL_PATH`" + +filter_away_system_DLLs() { + ${EGREP} -v -i '^(/.*/)?(msvcrt|userenv|bcrypt|rpcrt4|usp10|ntdll|api-ms-win-|(advapi|kernel|user|wsock|ws2_|gdi|ole|shell)(32|64))\.dll$' +} + +dllldd_with_tools() ( # Traverse an EXE or DLL file for DLLs it needs directly, # which are provided in the cross-build env (not system ones). # Assume no whitespaces in paths and filenames of interest. @@ -30,7 +48,7 @@ dllldd() ( for OD in objdump "$ARCH-objdump" ; do (command -v "$OD" >/dev/null 2>/dev/null) || continue - ODOUT="`$OD -x \"$@\" 2>/dev/null | ${EGREP} -i \"DLL Name:\" | awk '{print $NF}' | sort | uniq | ${EGREP} -v -i '^(/.*/)?(msvcrt|userenv|bcrypt|rpcrt4|usp10|(advapi|kernel|user|wsock|ws2_|gdi|ole||shell)(32|64))\.dll$'`" \ + ODOUT="`$OD -x \"$@\" 2>/dev/null | ${EGREP} -i \"DLL Name:\" | awk '{print $NF}' | sort | uniq | filter_away_system_DLLs`" \ && [ -n "$ODOUT" ] || continue for F in $ODOUT ; do @@ -90,7 +108,7 @@ dllldd() ( done fi - echo "WARNING: '$F' was not found in searched locations (system paths)!" >&2 + echo "WARNING: '$F' was not found in searched locations (system paths) by tools matcher ($OD)!" >&2 done done if [ "$SEEN" != 0 ] ; then @@ -105,17 +123,103 @@ dllldd() ( OUT="`ldd \"$@\" 2>/dev/null | ${EGREP} -i '\.dll' | ${EGREP} '/(bin|lib)/' | sed \"s,^${REGEX_WS}*\(${REGEX_NOT_WS}${REGEX_NOT_WS}*\)${REGEX_WS}${REGEX_WS}*=>${REGEX_WS}${REGEX_WS}*\(${REGEX_NOT_WS}${REGEX_NOT_WS}*\)${REGEX_WS}.*\$,\2,\" | sort | uniq | ${EGREP} -i '\.dll$'`" \ && [ -n "$OUT" ] && { echo "$OUT" ; return 0 ; } + echo "WARNING: no suitable DLLs were found in $@ by tools matcher (ldd)!" >&2 return 1 ) -dlllddrec() ( - # Recurse to find the (mingw-provided) tree of dependencies - dllldd "$1" | while read D ; do - echo "$D" - dlllddrec "$D" - done | sort | uniq +dllldd_with_strings() ( + strings "$@" | ${EGREP} -i '..*\.dll$' | sort | uniq | filter_away_system_DLLs | \ + while read DLL ; do ( + # Avoid looping on at least self-reference in a file + for S in "$@" ; do + # echo "=== Compare '$DLL' to '$S'" >&2 + case "$DLL" in + "$S"|*/"$S") exit ;; + esac + case "$S" in + */"$DLL") exit ;; + esac + done + # echo "=== '$DLL' not in '$@'" >&2 + echo "$DLL" + ) ; done +) + +dllldd() ( + # Did at least one method not-fail and return something? + RES=0 + OUT_TOOLS="`dllldd_with_tools \"$@\"`" && [ -n "${OUT_TOOLS}" ] || RES=$? + OUT_STRINGS="`dllldd_with_strings \"$@\"`" && [ -n "${OUT_STRINGS}" ] && RES=0 + ( # Subshell to sort results in the end + if [ -n "${OUT_TOOLS}" ] ; then + echo "${OUT_TOOLS}" + fi + if [ -n "${OUT_STRINGS}" ] ; then + OUT_STRINGS_FULL="`echo \"${OUT_STRINGS}\" | ${EGREP} '[/\\]'`" || OUT_STRINGS_FULL="" + if [ -n "${OUT_STRINGS_FULL}" ] ; then + echo "${OUT_STRINGS_FULL}" + OUT_STRINGS="`echo \"${OUT_STRINGS}\" | ${EGREP} -v '[/\\]'`" + fi + + for S in ${OUT_STRINGS} ; do + if (echo "${OUT_STRINGS_FULL}"; echo "${OUT_TOOLS}") | ${GREP} -i '[/\\]'"$S"'$' ; then + # Already a full path name (reported via grep to stdout above) + continue + fi + + # Something new (e.g. something listed for dynamic loading)... + + # Is it simply in PATH (and deemed executable)? + # WARNING: Can return things in system path + # command -v "$S" && continue + + echo "${SEARCH_DLL_PATH}" | tr ':' '\n' | { + while read D ; do + if [ -s "$D/$S" ]; then + echo "$D/$S" + exit + fi + done + + echo "WARNING: '$S' was not found in searched locations (system paths) by strings matcher!" >&2 + } + done + fi + ) | sort | uniq + return $RES +) + +do_dlllddrec() ( + # Skip out if we already reported this file + if [ -n "$TEMPFILE_REC" ] ; then + if ${EGREP} '^'"$1"'$' "$TEMPFILE_REC" >/dev/null 2>/dev/null ; then + exit + fi + fi + + # Recurse to find the (mingw-provided) tree of dependencies - implem + echo "=== Recursing into '$1'..." >&2 + dllldd "$1" | while read DLL_HIT ; do + [ -n "$DLL_HIT" ] || continue + echo "$DLL_HIT" >> "$TEMPFILE_REC" + echo "$DLL_HIT" + do_dlllddrec "$DLL_HIT" + done ) +dlllddrec() { + TEMPFILE_REC="`mktemp`" || TEMPFILE_REC="" + if [ -n "$TEMPFILE_REC" ] ; then + trap 'rm -f "$TEMPFILE_REC"' 0 1 2 3 15 + fi + + # Recurse to find the (mingw-provided) tree of dependencies for one file + do_dlllddrec "$1" | sort | uniq + + rm -f "$TEMPFILE_REC" + trap - 0 1 2 3 15 +} + # Alas, can't rely on having BASH, and dash fails to parse its syntax # even if hidden by conditionals or separate method like this (might # optionally source it from another file though?) @@ -198,7 +302,13 @@ if [ x"${DLLLDD_SOURCED-}" != xtrue ] ; then cat << EOF Tool to find DLLs needed by an EXE or another DLL -Directly used libraries: +Directly used libraries, search with "proper tools": + $0 dllldd_with_tools ONEFILE.EXE + +Directly used libraries, search with "strings" and "grep": + $0 dllldd_with_strings ONEFILE.EXE + +Directly used libraries, combine the two methods above (default): $0 dllldd ONEFILE.EXE Recursively used libraries: @@ -210,7 +320,7 @@ and list their set of required DLLs $0 dllldddir_pedantic [DIRNAME...] EOF ;; - dlllddrec|dllldd|dllldddir|dllldddir_pedantic) "$@" ;; + dlllddrec|dllldd|dllldd_with_tools|dllldd_with_strings|dllldddir|dllldddir_pedantic) "$@" ;; *) dlllddrec "$1" ;; esac