From a225474fb413aa9b5d834abbf1c9b65c397d7242 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Paul=20H=C3=A4nsch?= Date: Thu, 26 Aug 2021 02:43:16 +0200 Subject: [PATCH] Squashed 'cgilite/' changes from 8be65ce..dcab989 dcab989 much faster hex decode function 07b4b96 simpler lock algorithm using files 38702db improved gonzo mac if openssl is unavailable git-subtree-dir: cgilite git-subtree-split: dcab9893c3e08b2ad0d0e9246b8ceefc3d40b9f8 --- cgilite.sh | 73 +++++++++++++++++++++++++++++++++++++++++++----------- session.sh | 12 +++++++-- storage.sh | 53 +++++++++++++++++++-------------------- 3 files changed, 94 insertions(+), 44 deletions(-) diff --git a/cgilite.sh b/cgilite.sh index 9fa56ee..7f828dd 100755 --- a/cgilite.sh +++ b/cgilite.sh @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright 2017 - 2020 Paul Hänsch +# Copyright 2017 - 2021 Paul Hänsch # # This is CGIlite. # A collection of posix shell functions for writing CGI scripts. @@ -32,6 +32,9 @@ cgilite_timeout=2 PATH(){ local str seg out + # normalize path + # read from stdin if no arguments are provided + [ $# -eq 0 ] && str="$(cat)" || str="$*" while [ "$str" ]; do seg=${str%%/*}; str="${str#*/}" @@ -45,18 +48,58 @@ PATH(){ [ "${str}" -a "${out}" ] && printf %s "$out" || printf %s/ "${out%/}" } -HEX_DECODE=' - s;\\;\\\\;g; :HEXDECODE_X; s;%([^0-9A-F]);\\045\1;g; tHEXDECODE_X; - # Hexadecimal { %00 - %FF } will be transformed to octal { \000 - \377 } for posix printf - s;%[0123].;&\\0;g; s;%[4567].;&\\1;g; s;%[89AB].;&\\2;g; s;%[CDEF].;&\\3;g; - s;%[048C][0-7]\\.;&0;g; s;%[048C][89A-F]\\.;&1;g; s;%[159D][0-7]\\.;&2;g; s;%[159D][89A-F]\\.;&3;g; - s;%[26AE][0-7]\\.;&4;g; s;%[26AE][89A-F]\\.;&5;g; s;%[37BF][0-7]\\.;&6;g; s;%[37BF][89A-F]\\.;&7;g; - s;%.[08](\\..);\10;g; s;%.[19](\\..);\11;g; s;%.[2A](\\..);\12;g; s;%.[3B](\\..);\13;g; - s;%.[4C](\\..);\14;g; s;%.[5D](\\..);\15;g; s;%.[6E](\\..);\16;g; s;%.[7F](\\..);\17;g; -' - HEX_DECODE(){ - printf -- "$(printf %s "$1" |sed -E "$HEX_DECODE")" + local pfx="$1" in="$2" out + # Print out Data encoded as Hex + # + # Arguments: + # pfx - required, prefix for a hex tupel, e.g. "\x", "%" "\", may be empty + # in - required, string to be decoded + # + # anything that does not constitute a tupel of valid Hex numerals + # will be copied to the output literally + + while [ "$in" ]; do + case $in in + "$pfx"[0-9a-fA-F][0-9a-fA-F]*) in="${in#${pfx}}";; + \\*) in="${in#?}"; out="${out}\\\\"; continue;; + %*) in="${in#?}"; out="${out}%%"; continue;; + *) out="${out}${in%"${in#?}"}"; in="${in#?}"; continue;; + esac; + + # Hex escaes for printf (e.g. \x41) are not portable + # The portable way for Hex output is transforming Hex to Octal + # (e.g. \x41 = \101) + case $in in + [0123]?*) out="${out}\\0";; + [4567]?*) out="${out}\\1";; + [89aAbB]?*) out="${out}\\2";; + [c-fC-F]?*) out="${out}\\3";; + esac + case $in in + [048cC][0-7]*) out="${out}0";; + [048cC][89a-fA-F]*) out="${out}1";; + [159dD][0-7]*) out="${out}2";; + [159dD][89a-fA-F]*) out="${out}3";; + [26aAeE][0-7]*) out="${out}4";; + [26aAeE][89a-fA-F]*) out="${out}5";; + [37bBfF][0-7]*) out="${out}6";; + [37bBfF][89a-fA-F]*) out="${out}7";; + esac + case $in in + ?[08]*) out="${out}0";; + ?[19]*) out="${out}1";; + ?[2aA]*) out="${out}2";; + ?[3bB]*) out="${out}3";; + ?[4cC]*) out="${out}4";; + ?[5dD]*) out="${out}5";; + ?[6eE]*) out="${out}6";; + ?[7fF]*) out="${out}7";; + esac + in="${in#?}" + in="${in#?}" + done + printf -- "$out" } if [ -z "$REQUEST_METHOD" ]; then @@ -79,7 +122,7 @@ if [ -z "$REQUEST_METHOD" ]; then kill $cgilite_watchdog SERVER_PROTOCOL="${SERVER_PROTOCOL%${CR}}" - PATH_INFO="$(HEX_DECODE "${REQUEST_URI%\?*}" |PATH)" + PATH_INFO="$(HEX_DECODE % "${REQUEST_URI%\?*}" |PATH)" [ "${REQUEST_URI}" = "${REQUEST_URI#*\?}" ] \ && QUERY_STRING='' \ || QUERY_STRING="${REQUEST_URI#*\?}" @@ -145,7 +188,7 @@ cgilite_value(){ str="${str#*&${name}=}" cnt=$((cnt - 1)) done - printf -- "$(printf %s "${str%%&*}" |sed -E 's;\+; ;g;'"$HEX_DECODE")" + HEX_DECODE % "$(printf %s "${str%%&*}" |tr + \ )" } cgilite_keys(){ @@ -185,7 +228,7 @@ HEADER(){ } COOKIE(){ - HEX_DECODE "$( + HEX_DECODE % "$( HEADER Cookie \ | grep -oE '(^|; ?)'"$1"'=[^;]*' \ | sed -En "${2:-1}"'{s;^[^=]+=;;; s;\+; ;g; p;}' diff --git a/session.sh b/session.sh index 8929ab3..ca931fa 100755 --- a/session.sh +++ b/session.sh @@ -16,8 +16,16 @@ fi if which openssl >/dev/null; then session_mac(){ { [ $# -gt 0 ] && printf %s "$*" || cat; } | openssl dgst -sha1 -hmac "$(server_key)" -binary |slopecode; } else - # sham hmac if openssl is unavailable - session_mac(){ { [ $# -gt 0 ] && printf %s "$*" || cat; server_key; } | sha256sum |cut -d\ -f1; } + # Gonzo MAC if openssl is unavailable + session_mac(){ + { server_key | dd status=none bs=256 count=1 skip=1 + { server_key | dd status=none bs=256 count=1 + [ $# -gt 0 ] && printf %s "$*" || cat + } \ + | sha256sum -; + } \ + | sha256sum | cut -d\ -f1 + } fi server_key(){ diff --git a/storage.sh b/storage.sh index 61eec88..77ee29c 100755 --- a/storage.sh +++ b/storage.sh @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright 2018, 2019 Paul Hänsch +# Copyright 2018, 2019, 2021 Paul Hänsch # # This is a file format helper, part of CGIlite. # @@ -25,41 +25,40 @@ BR=' ' LOCK(){ - local lock timeout block - lock="${1}.lock" - timeout="${2-20}" - if [ \! -w "${lock%/*}" ] || [ -e "$lock" -a \! -d "$lock" ]; then + local lock="${1}.lock" timeout="${2-20}" block + + if [ \! -w "${lock%/*}" ] || [ -e "$lock" -a \! -f "$lock" ]; then debug "Impossible to get lock: $lock" return 1 fi - while ! mkdir "$lock" 2>&-; do - block="$(cat "$lock/pid" || printf 1)" - if ! { ps -eo pid |grep -qwF "$block"; }; then - debug "Overriding stale lock: $lock" - break - fi - if [ $timeout -le 0 ]; then - debug "Timeout while trying to get lock: $lock" - return 1 + while [ $timeout -gt 0 ]; do + printf '%i\n' $$ >>"${lock}" + read block <"$lock" + if [ "$block" = $$ ]; then + return 0 + elif ! { ps -eo pid |grep -qwF "$block"; }; then + debug "Trying to override stale lock: $lock" + if LOCK "$lock" 1; then + rm -- "$lock" + RELEASE "$lock" + fi + else + timeout=$((timeout - 1)) + [ $timeout -gt 0 ] && sleep 1 fi - timeout=$((timeout - 1)) - sleep 1 done - printf '%i\n' $$ >"${lock}/pid" - return 0 + + debug "Timeout while trying to get lock: $lock" + return 1 } RELEASE(){ - local lock - lock="${1}.lock" - if [ "$(cat "$lock/pid")" = "$$" ]; then - rm "$lock/pid" - if ! rmdir "$lock"; then - debug "Cannot remove tainted lock: $lock" - printf '%i\n' $$ >"${lock}/pid" - return 1 - fi + local lock="${1}.lock" block + + read block <"$lock" + if [ "$block" = $$ ]; then + rm -- "$lock" return 0 else debug "Refusing to release foreign lock: $lock" -- 2.39.2