From 11e2e775859dccfb21d615d38cb2b640eae7fb10 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Fri, 5 Feb 2021 16:25:04 -0500 Subject: [PATCH] Simplified Windows man page processing. Added Cygwin support to update_windows_man_page.sh. --- src/ssh_audit/ssh_audit.py | 61 +------------------------------ update_windows_man_page.sh | 73 +++++++++++++++++++++++++++++++------- 2 files changed, 62 insertions(+), 72 deletions(-) mode change 100644 => 100755 update_windows_man_page.sh diff --git a/src/ssh_audit/ssh_audit.py b/src/ssh_audit/ssh_audit.py index b95b738..62adf53 100755 --- a/src/ssh_audit/ssh_audit.py +++ b/src/ssh_audit/ssh_audit.py @@ -998,8 +998,6 @@ def target_worker_thread(host: str, port: int, shared_aconf: AuditConf) -> Tuple def windows_manual(out: OutputBuffer) -> int: '''Prints the man page on Windows. Returns an exitcodes.* flag.''' - import os - import ctypes retval = exitcodes.GOOD @@ -1008,64 +1006,7 @@ def windows_manual(out: OutputBuffer) -> int: retval = exitcodes.FAILURE return retval - # Support for ANSI escape sequences was first introduced in Windows 10 - # version 1511. - # - # Calling 'os.system' activates ANSI support if available. - # - # NB: If output is redirected to a file or piped to another program, ANSI - # support is suppressed. - os.system("") - - STD_OUTPUT_HANDLE = -11 - ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4 - - kernel32 = ctypes.WinDLL('kernel32') - hStdin = kernel32.GetStdHandle(STD_OUTPUT_HANDLE) - consoleMode = ctypes.c_ulong() - - # GetConsoleMode - # https://docs.microsoft.com/en-us/windows/console/getconsolemode - # - # Parameters: - # 1. hConsoleHandle [in] - # 2. lpMode [out] - # - # Return value: - # Success: A non-zero value. - # Fail: A value of zero. - kernel32.GetConsoleMode(hStdin, ctypes.byref(consoleMode)) - - # Use a bitwise and (&) between the console mode value and the flag. If the - # console mode value contains the flag then ANSI is supported. - ansi_supported = bool(consoleMode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING) - - if ansi_supported: - out.info(WINDOWS_MAN_PAGE) - else: - import io - import re - - # If the text contains unicode characters this may result in a - # "UnicodeEncodeError" error when printing depending on the active - # console code page. Therefore the stdout's encoding is explicitly set - # to utf8. - # - # NB: If ANSI support enabled then unicode is implicitly handled. - new_stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8', errors=sys.stdout.errors) - old_stdout = sys.stdout - sys.stdout = new_stdout - - # An ANSI escape sequence starts with an ESC character (033 in decimal - # and 1b in hex), followed by an open bracket and terminates with 'm'. - strip_ansi = re.compile(r'\x1b\[.*?m') - man_plain_text = strip_ansi.sub('', WINDOWS_MAN_PAGE) - - out.info(man_plain_text) - - new_stdout.detach() - sys.stdout = old_stdout - + out.info(WINDOWS_MAN_PAGE) return retval diff --git a/update_windows_man_page.sh b/update_windows_man_page.sh old mode 100644 new mode 100755 index b96a8d5..0bf4bd0 --- a/update_windows_man_page.sh +++ b/update_windows_man_page.sh @@ -1,7 +1,32 @@ #!/bin/bash +# +# The MIT License (MIT) +# +# Copyright (C) 2021 Joe Testa (jtesta@positronsecurity.com) +# Copyright (C) 2021 Adam Russell () +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + ################################################################################ -# update_windows_man_page +# update_windows_man_page.sh # # PURPOSE # Since Windows lacks a manual reader it's necessary to provide an alternative @@ -13,12 +38,29 @@ # 'WINDOWS_MAN_PAGE' by invoking ssh-audit with the manual parameters # (--manual / -m). # +# Cygwin is required. +# # USAGE -# update_windows_man_page.sh -m -g +# update_windows_man_page.sh [-m ] [-g ] # ################################################################################ -while getopts "m: g:" OPTION +function usage { + echo >&2 "Usage: $0 [-m ] [-g ] [-h]" + echo >&2 " -m Specify an alternate man page path (default: ./ssh-audit.1)" + echo >&2 " -g Specify an alternate globals.py path (default: ./src/ssh_audit/globals.py)" + echo >&2 " -h This help message" +} + +if [[ $(uname -s) != CYGWIN* ]]; then + echo >&2 "This script is designed to be run under Cygwin only. It can potentially be extended to run under Linux, but this is not supported at this time." + exit -1 +fi + +MAN_PAGE=ssh-audit.1 +GLOBALS_PY=src/ssh_audit/globals.py + +while getopts "m: g: h" OPTION do case "$OPTION" in m) @@ -27,24 +69,24 @@ do g) GLOBALS_PY="$OPTARG" ;; + h) + usage + exit 0 + ;; *) echo >&2 "Invalid parameter(s) provided" + usage exit 1 ;; esac done -if [[ -z "$MAN_PAGE" || -z "$GLOBALS_PY" ]]; then - echo >&2 "Missing parameter(s)." - exit 1 -fi - # Check that the specified files exist. [ -f "$MAN_PAGE" ] || { echo >&2 "man page file not found: $MAN_PAGE"; exit 1; } [ -f "$GLOBALS_PY" ] || { echo >&2 "globals.py file not found: $GLOBALS_PY"; exit 1; } -# Check that the 'ul' (do underlining) binary exists. -command -v ul >/dev/null 2>&1 || { echo >&2 "ul not found."; exit 1; } +# Check that the 'ul' (do underlining) binary exists. (Commented out since Cygwin's man outputs ANSI escape codes automatically; re-enable if running under Linux.) +# command -v ul >/dev/null 2>&1 || { echo >&2 "ul not found."; exit 1; } # Check that the 'sed' (stream editor) binary exists. command -v sed >/dev/null 2>&1 || { echo >&2 "sed not found."; exit 1; } @@ -52,6 +94,8 @@ command -v sed >/dev/null 2>&1 || { echo >&2 "sed not found."; exit 1; } # Remove the Windows man page placeholder from 'globals.py'. sed -i '/^WINDOWS_MAN_PAGE/d' "$GLOBALS_PY" +echo "Processing man page at ${MAN_PAGE} and placing output into ${GLOBALS_PY}..." + # Append the man page content to 'globals.py'. # * man outputs a backspace-overwrite sequence rather than an ANSI escape # sequence. @@ -60,5 +104,10 @@ sed -i '/^WINDOWS_MAN_PAGE/d' "$GLOBALS_PY" # * The 'ul' command converts the backspace-overwrite sequence to an ANSI escape # sequence. echo WINDOWS_MAN_PAGE = '"""' >> "$GLOBALS_PY" -MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "$MAN_PAGE" | ul >> "$GLOBALS_PY" -echo '"""' >> "$GLOBALS_PY" \ No newline at end of file +# The 'ul' tool would be necessary if running under Linux to convert the overstrike characters into ANSI escape sequences. +# MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "$MAN_PAGE" | ul >> "$GLOBALS_PY" +MANWIDTH=80 MAN_KEEP_FORMATTING=1 man "./$MAN_PAGE" >> "$GLOBALS_PY" +echo '"""' >> "$GLOBALS_PY" + +echo "Done." +exit 0