#!/bin/bash # # function "argument" # # What function does. # # Password source. # # --- # # encrypted_function [options] [arguments...] # # Encrypted Shell function. The function is stored in the script in # encrypted form. When executed a password is requested to decrypt and # execute the function. # # Options are provided to make it easy to replace, view or change the function # or encrypting password. All you need to do is copy this script and use the # options to set the appropraite function to store in the new script. # # Function Encryption Options (no arguments needed for these) # -fe Encode a function and store it in this script. (DANGER) # -fd Decode and output the actual function stored in this script! # -fp Change the password of the stored function # -fc Clear any cached password saved for function # # Without any of the above options the 'function' is decrypted using the # a password requested from the user. Any 'argument' is provided to the # encoded function as "$1", etc... # # Example: Convert 'argument' to a password to use... # Argument encrypted (without salt) using the built-in 'phrase'. The first # 8 characters is then base64 encoded, and prefixed by the string 'Pwd'. # Do NOT use this exact example for your own password generator. # # ( echo 'phrase'; echo -n "$1" ) | # openssl enc -aes-256-cbc -nosalt -pass stdin -base64 | # s/^\(........\)/Pwd\1/' # ### # # Any changes or improvements should be passed back to author... # # Created: 30 Jun 2017 - Anthony Thyssen # Updated: 4 Jul 2017 - Version 1.2 # Updated: 15 May 2018 - Version 1.3 - add passwd caching # Updated: 3 May 2024 - Version 2.0 - More like "keepout" # ### # Discover where the shell script resides PROGNAME=`type "$0" | awk '{print $3}'` # search for executable on path PROGDIR=`dirname "$PROGNAME"` # extract directory of program PROGNAME=`basename "$PROGNAME"` # base name of program unset FUNCTION # ensure these are not an environment variables unset function # FUNCTION START FUNCTION='Encrypted Function will be stored here by the script options' # FUNCTION END Usage() { # Report error and Synopsis line only echo >&2 "$PROGNAME:" "$@" sed >&2 -n '1,2d; /^###/q; /^#/!q; /^#$/q; s/^# */Usage: /p;' \ "$PROGDIR/$PROGNAME" echo >&2 "For help use option '-help'" exit 10; } Help() { # Output Full header comments as documentation sed >&2 -n '1d; /^###/q; /^#/!q; s/^#//; s/^ //; p' \ "$PROGDIR/$PROGNAME" exit 10; } Error() { # Just output an error condition and exit (no usage) echo >&2 "$PROGNAME:" "$@" exit 2 } # -------------------------------------------------------------------------- unset passwd # ensure these are not environment variables unset passwd2 read_password_noecho() { # A 'no-echo' TTY Password Reader (BASH) unset passwd # ensure it is not an environment variable! read -r -s -p "$1" passwd tty >/dev/null && echo '' } read_password() { # Read password from helper, or no-echo fallback unset passwd # ensure it is not an environment variable! if [[ "$TTY_ASKPASS" ]]; then # User defined password reader passwd=$("$TTY_ASKPASS" "$1" /dev/null 2>&1 fi } read_password_with_cache() { if [[ -n "$KEY" ]]; then if key_id=$(keyctl request user "$KEY" 2>/dev/null); then # key_id found in cache, read password from cache passwd=$(keyctl pipe "$key_id" 3>/dev/null) else # read passwd and cache it read_password "$1" key_id=$(echo -n "$passwd" | keyctl padd user "$KEY" @u 2>/dev/null) fi # reset password cache timeout (even if it came from cache) keyctl timeout "$key_id" $key_timeout 2>/dev/null unset $key_id else # read password (no cache) read_password "$1" fi } # -------------------------------------------------------------------------- # encrypted function functions decrypt_function() { # decrypt the function stored in this script function=$( ( echo "$passwd"; echo "$FUNCTION"; ) | openssl enc -d -aes-256-cbc -nosalt -pbkdf2 -pass stdin -base64 ) [ $? -eq 0 ] && return # FAILED! Clear password cache - in case it was used (see above) clear_cached_password Error "Failed to Decrypt Function. Invalid Password?" } encrypt_n_store_function() { # encrypt the function function=$( ( echo "$passwd"; echo -n "$function"; ) | openssl enc -aes-256-cbc -nosalt -pbkdf2 -pass stdin -base64 ) # DANGER -- Save the function into this script -- DANGER perl -i -pe '$_.="FUNCTION='\'"$function"\''\n# FUNCTION END\n",next if /^# FUNCTION START$/; $_="" if /^FUNCTION=/.../^# FUNCTION END$/; ' "$PROGDIR/$PROGNAME" } # -------------------------------------------------------------------------- # Option functions encode_function() { # read in a shell function and encode it into a base64 string read_passwd_twice echo "Type Function (Ctrl-D to finish):" function=$(cat) encrypt_n_store_function exit 0 } output_function() { # ask the password and decode the function read_password "Function Password:" decrypt_function echo "$function" exit 0 } change_password() { # ask the password and decode the function (no cache) clear_cached_password read_password "Old Password:" decrypt_function # ask new password and encode function again read_password_twice encrypt_n_store_function exit 0 } # --------------------------------------------------------------------------- # Option Handling while [ $# -gt 0 ]; do case "$1" in # Standard help option. -\?|-help|--help|--doc*) Help ;; -fe) encode_function ;; # encode a new function into this script -fd) output_function ;; # output the function stored in this script -fp) change_password ;; # change the password of the stored function -fc) clear_cached_password; exit 0 ;; # clear any cached password --) shift; break ;; # forced end of user options -*) Usage "Unknown option \"$1\"" ;; *) break ;; # unforced end of user options esac shift # next option done [ $# -gt 1 ] && Usage "Too many Arguments" [ $# -ne 1 ] && Usage "Missing Argument" # Optional Argument (adjust to suit) # --------------------------------------------------------------------------- # Execute Encrypted Function (normal use) # # Decrypt and execute the function. read_password_with_cache "Password for Function \"$PROGNAME\":" decrypt_function $SHELL -c "$function" - "$@" # ---------------------------------------------------------------------------