Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Wed, 9 May 2012 10:32:09 +0200
From: Frank Dittrich <frank_dittrich@...mail.com>
To: john-dev@...ts.openwall.com
Subject: Re: Fwd: bash auto-completion for john

On 05/09/2012 08:17 AM, magnum wrote:
> On 05/09/2012 02:42 AM, Frank Dittrich wrote:
>> But this works:
>> $ ./john --markov
>> --markov               --markov=LEVEL[:opts]
> 
> This is actually better, as --markov by itself is also valid. Though if
> you write --markov= and then TAB, I presume it will write all that to
> your line.

It would have, but I handled the --markov=* case before --markov.
For --markov=*, I don't provide any completion.

 Still, I think this would be a good addition. A similar
> approach could be used for -users, -groups, -shells and -salts.

IMO, this won't work.
The option --markov is valid without =value, but the others aren't.

If I would have just --users on the command line, and press [tab], I
would end up with --users=[-]LOGIN|UID[,..]

> Perhaps you could do this:
> $ ./john --markov
> --markov               --markov[=LEVEL[:START[:END[:LENGTH]]]]
> 
> This is even better than the usage blob, where this is too long to fit.

Sure.
I did, however, remove the outer pair of square brackets, otherwise the
second option would include the first one as a special case.

$ ./john --markov
--markov                               --markov=LEVEL[:START[:END[:LENGTH]]]

If we extend the usage of markov to --markov=MKV_SECTION (referring to a
section [Options.Markov:...], we can add the third option to the
expansion logic.

Frank

# bash completion for john
#
# john can either be globally installed (e.g. in /usr/bin/john),
# or it can be installed locally somewhere in a user's home directory.
# It can be an official version, or a community encanced (jumbo) version,
# with a variety of patches.
#
# Trying to build a perfect completion script will be hard.
# So let's start with a first humble attempt.
# If possible, I'd like to avoid the need to maintain this script whenever
# john gets a new option.
#
# The code is ugly, many things can probably be done more efficiently.
# At least, grep and sed are the only external commands used
#
# FIXME:
# 	I put this file into the /etc/bash_completion.d directory.
# 	A proper rollout is probably not that easy.
# 	(Of course, this file is anything but ready for a rollout to end users.) 
#
# TODO:
#       --wordlist=~user/filename or --wordlist=~/dir/file doesn't work,
#         but pressing [tab] expands this to something useful
#	Does anybody know a command where tab expansion and globbing works correctly?
#
#       --rules= or --single= should use names of existing [List.Rules:...] sections
#         Currently a hard coded list of section names (NT single wordlist) is used
#       --incremental should use names of [Incremental:...] sections
#         Currently a hard coded list is used (All Alpha Digits Alnum LanMan)
#       --external should use names of [List.External:..-.] sections
#         (Just sections without a generate() function, if --wordlist, --incremental or --single
#         is present on the command line; with a generate() function, if none of these
#         options is used - WHAT IF the user adds a --wordlist option later?)
#         Currently a hard coded List is used:
#	  Filter_Alpha Filter_Digits Filter_Alnum Filter_LanMan LanMan Double Parallel Strip Keyboard
#	  DumbForce KnownForce DateTime Repeats Subsets AtLeast1-Simple AtLeast1-Generic Policy AppendLuhn
#       --rules=, --single=, --incremental=, --external= need to take into account a --config file
#         which might have been specified on the command line, correct default john.conf locations 
#         (/etc/, ~/.john/, or ./, depending on build options), and included config files...
#         FIXME: The user might have used -co: instead of --config..., the user might specify 
#         --config=... later (should we really scan config files for sections referenced by other
#         command line options, to skip config files which do not have the right sections?)
#         Currently -opt is expanded to --option or --option=...
#         FIXME: With includes all this doesn't get easier (what if the john version which is used
#         doesn't even support these fancy additions?)
#         FIXME: To be able to locate the correct .conf and .rec files, we might even need a new
#         john option to know the values of JOHN_SYSTEMWIDE ... (e.g. --build-options)
#       --restore= and --status= expansion should search for existing .rec files in the correct directory.
#       --mkpc and other options which are not mentioned in the usage output are currently ignored
#       Several other options probably are still not considered.
#       Should I support -option instead of --option? (currently -option gets replaced with --option 
#       during expansion.
#       Should I support --option:val, -option:val, or even -opt:val instead of just --option=val?
#

# grep,sed, and ls are used to process john's usage info or to list .rec files...
have grep && have sed && have ls &&
_john()
{
	local first cur options valopts compreplya compreplyb encodings formats subformats sessions
	COMPREPLY=()
	_get_comp_words_by_ref -n = cur

# we need to make sure we run the correct program, not some other program 
# called john which is located somewhere in $PATH
	first="${COMP_WORDS[0]}"
	#first=`which ${first} 2>/dev/null`
#	Most options are listed at the begin of the line, but the line with the --pipe option
#	does have trailing spaces, and --stdin is mentioned after --wordlist=FILE.
#
#	all options (the '=' will be emoved for options with an optional value)
	options=""
# FIXME: How do I suppress the error message if someone tries to be clever: cd run; ./john --[tab] ???
	options=`${first} |grep '^ *--'|sed 's#^ *\([a-z=-]*\).*$#\1#'|sed 's#--wordlist=#--wordlist=\n--stdin#'|sed 's#--subformat=#--subformat=LIST#'`
	if [[ "_$options_" == "__" ]] ; then
		compopt -F _filedir_xspec
		return 0
	fi
#	Just the options that can be used together with a value, even if that value is optional
#	(That means, for a jumbo build, --rules doesn't get a trailing space, but for the john version
#	distributed by fedora16, --rules does get a trailing space during expansion.
#	The same applies for --show)
	valopts=`${first}|grep '^ *--[a-z\[-]*='|grep -v '^ *--subformat='|sed 's#^ *\([a-z=-]*\).*$#\1#'`

	case "$cur" in
# --config= could be restricted to *.conf files (or *.ini files on Windows?),
# --pot= to *.pot files, 
# --make-charset= should probably excluded, to make overwriting existing files harder
# (otherwise it should be restricted to *.chr files)
		--markov=*)
			return 0
			;;
		--markov*)
			if  echo "${options}" | grep ".*--subformat" > /dev/null ; then
				COMPREPLY=( $(compgen -W "--markov --markov=LEVEL[:START[:END[:LENGTH]]]" -- ${cur}) )
			fi
			return 0
			;;
		--wordlist=*|--make-charset=*)
			#cur=${cur#*=}
			#_filedir expansion of --wordlist=~/te doesn't work
			# _filedir_xspec "_xspecs: bad array subscript" written to stderr
			_filedir_xspec 2> /dev/null
			return 0
			;;
		--pot=*)
			cur=${cur#*=}
			_filedir "pot"
			return 0
			;;
		--config=*)
			## either expansion for tilde filename
			#_filedir_xspec
			## or restrict completion to config files
			cur=${cur#*=}
			_filedir '@...nf|ini)'

			return 0
			;;
		--restore|--status|--incremental)
			COMPREPLY=( $(compgen -W "${cur}=" -- ${cur}) )
			compopt -o nospace
			return 0
			;;
		--restore=*|--status=*)
			cur=${cur#*=}
			sessions=`ls *.rec|sed 's#\.rec$##'`
			COMPREPLY=( $(compgen -W "${sessions}" -- ${cur}) )
			return 0
			;;
 
## May be I should not suggest all dynamic formats immediately.
## Instead, just suggest "dynamic" first, don't append a space 
## if the current value gets expanded to --format=dynamic,
## and add a --format=dynamic*) switch before --format=*)
#		--format=*)
#			cur=${cur#*=}
#			formats=`${first} |grep -A 100 '^--format='|sed 's#^--format=[A-Za-z]*##'|sed 's#force hash type NAME:##'|sed 's#/# #g'|sed 's#dynamic_n##'|grep -v '^--'`
#			if echo "${options}" | grep ".*--subformat" > /dev/null ; then
#				subformats=`${first} --subformat=LIST|sed 's#^User##'|sed 's#^Format = \(dynamic_[0-9]*\).*$#\1#'`
#			else
#				subformats=""
#			fi
#			COMPREPLY=( $(compgen -W "${formats} ${subformats}" -- ${cur}) )
#			return 0
#			;;

		--format=dynamic*)
			if echo "${options}" | grep ".*--subformat" > /dev/null ; then
				 subformats=`${first} --subformat=LIST|sed 's#^User##'|sed 's#^Format = \(dynamic_[0-9]*\).*$#\1#'`
				cur=${cur#*=}
				COMPREPLY=( $(compgen -W "${subformats}" -- ${cur}) )
			fi
			return 0
			;;
		--format=dy|--format=dyn|--format=dyna|--format=dynam|--format=dynami)
			if echo "${options}" | grep ".*--subformat" > /dev/null ; then
				cur=${cur#*=}
				COMPREPLY=( $(compgen -W "dynamic" -- ${cur}) )
				compopt -o nospace
			fi
			return 0
			;;
		--format=*)
			cur=${cur#*=}
			formats=`${first} |grep -A 100 '^--format='|sed 's#^--format=[A-Za-z]*##'|sed 's#force hash type NAME:##'|sed 's#/# #g'|sed 's#dynamic_n#dynamic#'|grep -v '^--'`
			COMPREPLY=( $(compgen -W "${formats}" -- ${cur}) )
			return 0
			;;

		--encoding=*)
			if  echo "${options}" | grep ".*--encoding" > /dev/null ; then
				cur=${cur#*=}
				encodings=`${first} --encoding=LIST 2>&1|grep -v 'Supported encodings'|sed 's#[,)]##g'|sed 's#(or ##g'`
				COMPREPLY=( $(compgen -W "${encodings}" -- ${cur}) )
			fi
			return 0
			;;
		--show)
			if echo "${valopts}" | grep ".*--rules" > /dev/null ; then
				COMPREPLY=( $(compgen -W "--show --show=LEFT" -- ${cur}) )
			else
				COMPREPLY=( $(compgen -W "--show" -- ${cur}) )
			fi
			return 0
			;;
		--show=l*)
			if echo "${valopts}" | grep ".*--rules" > /dev/null ; then
				cur=${cur#*=}
				COMPREPLY=( $(compgen -W "left" -- ${cur}) )
			fi
			return 0
			;;
		--show=*)
			if echo "${valopts}" | grep ".*--rules" > /dev/null ; then
				cur=${cur#*=}
				COMPREPLY=( $(compgen -W "LEFT" -- ${cur}) )
			fi
			return 0
			;;
		--rules)
			if echo "${valopts}" | grep ".*--rules" > /dev/null ; then
				COMPREPLY=( $(compgen -W "--rules --rules=NT --rules=single --rules=wordlist" -- ${cur}) )
			else
				COMPREPLY=( $(compgen -W "--rules" -- ${cur}) )
			fi
			return 0
			;;
		--single)
                        if echo "${valopts}" | grep ".*--single" > /dev/null ; then
                                COMPREPLY=( $(compgen -W "--single --single=NT --single=single --single=wordlist" -- ${cur}) )
                        else
                                COMPREPLY=( $(compgen -W "--single" -- ${cur}) )
                        fi
                        return 0
                        ;;
		--rules=*|--single=*)
			if echo "${valopts}" | grep ".*--rules" > /dev/null ; then
				cur=${cur#*=}
				COMPREPLY=( $(compgen -W "NT single wordlist" -- ${cur}) )
			fi
			return 0
			;;
		--incremental=*)
			cur=${cur#*=}
			COMPREPLY=( $(compgen -W "All Alpha Digits Alnum LanMan" -- ${cur}) )
			return 0
			;;
		--external=*)
			cur=${cur#*=}
			COMPREPLY=( $(compgen -W "Filter_Alpha Filter_Digits Filter_Alnum Filter_LanMan LanMan Double Parallel Strip Keyboard DumbForce KnownForce DateTime Repeats Subsets AtLeast1-Simple AtLeast1-Generic Policy AppendLuhn" -- ${cur}) )
			return 0
			;;
		--regen-lost-salts=*)
			if echo "${options}" | grep ".*--regen-lost-salts" > /dev/null ; then
				cur=${cur#*=}
				COMPREPLY=( $(compgen -W "1 2 3 4 5" -- ${cur}) )
			fi
			return 0
			;;
		--save-memory=*)
			cur=${cur#*=}
			COMPREPLY=( $(compgen -W "1 2 3" -- ${cur}) )
			return 0
			;;
		--subformat=*)
			if echo "${options}" | grep ".*--subformat" > /dev/null ; then
				cur=${cur#*=}
				COMPREPLY=( $(compgen -W "LIST" -- ${cur}) )
			fi
			return 0
			;;
                --session=|--users=|--groups=|--shells=|--salts=|--mem-file-size=|--field-separator-char=|--fix-state-delay=|--max-run-time=|--regen-lost-salts=)
			return 0
			;;
#--regen-lost-salts=N      regenerate lost salts for some hashes (see OPTIONS)
#--plugin=NAME[,..]        load this (these) dynamic plugin(s)
		-*)
			compreplya=`compgen -W "${options}" -- ${cur}`
			if [[ "_${compreplya}_" == "__" ]] ; then
				cur="-${cur}"
				compreplya=`compgen -W "${options}" -- ${cur}`
			fi
			compreplyb=`compgen -W "${valopts}" -- ${cur}`
			COMPREPLY=( $(compgen -W "${options}" -- ${cur}) )
			if [[ "_$compreplya" == "_$compreplyb" ]] ; then
				compopt -o nospace
			fi
			return 0
			;;
		*)
			_filedir
			return 0
			;;
	esac
} &&
complete -F _john john

Powered by blists - more mailing lists

Your e-mail address:

Powered by Openwall GNU/*/Linux - Powered by OpenVZ