Codebase list kwalletcli / lintian-fixes/main pinentry-kwallet
lintian-fixes/main

Tree @lintian-fixes/main (Download .tar.gz)

pinentry-kwallet @lintian-fixes/mainraw · history · blame

#!/usr/bin/env mksh
rcsid='$MirOS: contrib/hosted/tg/code/kwalletcli/pinentry-kwallet,v 1.16 2016/08/30 17:37:59 tg Exp $'
#-
# Copyright © 2009, 2010, 2011
#	mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
# are retained or reproduced in an accompanying document, permission
# is granted to deal in this work without restriction, including un‐
# limited rights to use, publicly perform, distribute, sell, modify,
# merge, give away, or sublicence.
#
# This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
# the utmost extent permitted by applicable law, neither express nor
# implied; without malicious intent or gross negligence. In no event
# may a licensor, author or contributor be held liable for indirect,
# direct, other damage, loss, or other issues arising in any way out
# of dealing in the work, even if advised of the possibility of such
# damage or existence of a defect, except proven that it results out
# of said person’s immediate fault when using the work as intended.

unset LC_ALL LANGUAGE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES \
    LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION
export LANG=C LC_CTYPE=en_US.UTF-8
set -U

iodebug=0
iodp=~/pinentry-kwallet.debug
if (( iodebug )); then
	print "\n$$ === new $(date)" >>"$iodp"
	chmod 0600 "$iodp"
fi
function io_p_in {
	local io_line
	IFS= read -r io_line || return $?
	(( iodebug )) && print -r -- "$$ <p $io_line" >>"$iodp"
	eval $1='${io_line%
}'
	return 0
}
function io_s_in {
	local io_line
	IFS= read -pr io_line || return $?
	(( iodebug )) && print -r -- "$$ <s $io_line" >>"$iodp"
	eval $1=\$io_line
	return 0
}
function io_p_out {
	(( iodebug )) && print -r -- "$$ >p $(print "$@")" >>"$iodp"
	print "$@"
}
function io_s_out {
	(( iodebug )) && print -r -- "$$ >s $(print "$@")" >>"$iodp"
	print -p "$@"
}
function log {
	(( iodebug )) && print -r -- "$$ LOG $*" >>"$iodp"
}

if [[ -n $PINENTRY_KWALLET ]]; then
	io_p_out ERR 7 trying to call me recursively
	while io_p_in line; do
		io_p_out ERR 7 trying to call me recursively
	done
	exit 1
fi

quiet=0
set -A args
last=
i=0
for arg in "$@"; do
	log "argv[$((++i))]='${arg//\'/\'\\\'\'}'"
	if [[ $last = --display ]]; then
		v=DISPLAY
		last=specvar
	elif [[ $last = --ttyname ]]; then
		v=GPG_TTY
		last=specvar
	elif [[ $last = --ttytype ]]; then
		v=GPG_TERM
		last=specvar
	elif [[ $last = --lc-type ]]; then
		v=LC_CTYPE
		last=specvar
	elif [[ $last = --lc-messages ]]; then
		v=LC_MESSAGES
		last=specvar
	fi
	if [[ $last = specvar ]]; then
		eval $v=\$arg
		eval export $v
		last=addone
	fi
	if [[ $last = addone ]]; then
		args[${#args[*]}]=$arg
		last=
		continue
	fi
	last=
	if [[ $arg = -V ]]; then
		(( quiet )) || print -ru2 -- "$rcsid"
		exit 0
	elif [[ $arg = --version ]]; then
		print -r -- "$rcsid"
		exit 0
	elif [[ $arg = @(-h|--help) ]]; then
		print "Usage: pinentry-kwallet [options]"
		exit 0
	elif [[ $arg = -q ]]; then
		quiet=1
	elif [[ $arg = \
	    @(-@(d|e|g)|--@(debug|enhanced|no-global-grab)) ]]; then
		args[${#args[*]}]=$arg
	elif [[ $arg = \
	    --@(display|ttyname|ttytype|lc-type|lc-messages) ]]; then
		args[${#args[*]}]=$arg
		last=$arg
	elif [[ $arg = --parent-wid ]]; then
		args[${#args[*]}]=$arg
		last=addone
	else
		(( quiet )) || print -u2 "warning: unknown argument '$arg'"
		args[${#args[*]}]=$arg
	fi
done

if [[ -z $DISPLAY ]]; then
	log "since DISPLAY is not set, replacing with: ${PINENTRY:-pinentry}"
	PINENTRY_KWALLET=set exec "${PINENTRY:-pinentry}" "${args[@]}"
fi

PINENTRY_KWALLET=set "${PINENTRY:-pinentry}" "${args[@]}" |&
copid=$?
log "starting coproc $copid: PINENTRY_KWALLET=set '${PINENTRY:-pinentry}' args"
io_s_in resp || resp='ERR 14 no coprocess'
if [[ $resp = OK@(| *) ]]; then
	have_sub=1
	trap "kill $copid; exit 255" 1 2 3 5 13 15
else
	have_sub=0
	exec 3>&p; exec 3>&-
fi
log have_sub=$have_sub
io_p_out OK ready to listen to your demands

x_dsctxt=
x_prompt=
x_errtxt=

function getit {
	local type=$1 key=${x_prompt}$x_dsctxt pw rv tw=0 d errcnt blst=0

	copyline=0
	# the errcnt handling is a little tricky, because GnuPG v2 does
	# not reuse the pinentry session (suckers, unable to... *rant*)
	if pw=$(kwalletcli -q -f pinentry-kwallet -e "$type-B-$key") && \
	    [[ $pw = yes* ]]; then
		log "blacklisted"
		blst=1
	elif pw=$(kwalletcli -q -f pinentry-kwallet -e "$type-e-$key"); then
		log "read errcnt: '$pw'"
		set -A errcnt -- $pw
		d=$(date -u +'%s')
		(( errcnt[0] < (d - 15) )) && errcnt[1]=0
	else
		log "read errcnt failed"
	fi
	(( blst )) || [[ -z $x_errtxt ]] || (( errcnt[1]++ ))
	(( blst )) || if (( errcnt[1] )); then
		errcnt[0]=${d:-$(date -u +'%s')}
		kwalletcli -q -f pinentry-kwallet -e "$type-e-$key" \
		    -p "${errcnt[*]}"
		log "write errcnt: '${errcnt[*]}' -> $?"
	fi
	(( blst )) || if (( errcnt[1] < 2 )); then
		pw=$(kwalletcli -q -f pinentry-kwallet -e "$type-v-$key")
		rv=$?
		log "read pass $rv: '$pw'"
		case $type:$rv {
		(bool:0)
			if [[ $pw = \
			    @(1|-1|[Tt][Rr][Uu][Ee]|[Yy][Ee][Ss]) ]]; then
				io_p_out OK
				return
			elif [[ $pw = \
			    @(0|[Ff][Aa][Ll][Ss][Ee]|[Nn][Oo]) ]]; then
				io_p_out ERR 128 not confirmed
				return
			fi
			;;
		(pass:0)
			[[ -n $pw ]] && io_p_out -r "D $pw"
			io_p_out OK
			return
			;;
		}
	fi
	if (( !have_sub )); then
		io_p_out ERR 14 no coprocess
		return
	fi
	if [[ $type = bool ]]; then
		io_s_out CONFIRM
		io_s_in resp
		case $resp {
		(OK@(| *))
			pw=1
			tw=1
			;;
		(ERR\ @(128|83886194|83886179)@(| *))
			# 128 = not confirmed (hardy)
			# 83886194 = not confirmed (wheezy)
			# 83886179 = canceled (wheezy)
			pw=0
			tw=1
			;;
		}
	else
		io_s_out GETPIN
		io_s_in resp
		pw=
		#XXX normally, read until OK|ERR
		if [[ $resp = @(D )* ]]; then
			pw=${resp#D }
			io_s_in resp
		fi
		[[ $resp = OK@(| *) ]] && tw=1
	fi
	(( tw && !blst )) && if kwalletcli_getpin -q -b \
	    -t "Do you want to store your response for description
'$x_dsctxt',
prompt '$x_prompt' in the KDE Wallet?"; then
		kwalletcli -q -f pinentry-kwallet -e "$type-v-$key" -p "$pw"
		log "want store: yes, pw '$pw' -> $?"
	else
		# create blacklist entry for this answer
		kwalletcli -q -f pinentry-kwallet -e "$type-B-$key" -p yes
		log "want store: no"
	fi
	[[ $type = pass ]] && [[ -n $pw ]] && io_p_out -r "D $pw"
	io_p_out -r -- "$resp"
}

while io_p_in line; do
	[[ -z $line || $line = '#'* ]] && continue
	copyline=1
	case $line {
	(SETDESC)
		x_dsctxt=
		;;
	(SETDESC\ *)
		x_dsctxt=${line#SETDESC }
		;;
	(SETPROMPT)
		x_prompt=
		;;
	(SETPROMPT\ *)
		x_prompt=${line#SETPROMPT }
		;;
	(SETTITLE@(| *))
		;;
	(SET@(OK|CANCEL|NOTOK)@(| *))
		;;
	(SETERROR)
		x_errtxt=
		;;
	(SETERROR\ *)
		x_errtxt=${line#SETERROR }
		;;
	(SETQUALITYBAR*)
		;;
	(GETPIN)
		getit pass
		;;
	(CONFIRM)
		getit bool
		;;
	(MESSAGE|CONFIRM\ --one-button)
		;;
	(OPTION\ ttyname=*)
		GPG_TTY=${line#*=}
		export GPG_TTY
		;;
	(OPTION\ ttytype=*)
		GPG_TERM=${line#*=}
		export GPG_TERM
		;;
	(OPTION\ lc-ctype=*)
		LC_CTYPE=${line#*=}
		export LC_CTYPE
		;;
	(OPTION\ lc-messages=*)
		LC_MESSAGES=${line#*=}
		export LC_MESSAGES
		;;
	(OPTION\ *)
		;;
	(CONFIRM\ *)
		(( quiet )) || print -ru2 "warning: unknown CONFIRM" \
		    "option ${line#CONFIRM }"
		;;
	(BYE@(| *))
		io_p_out OK
		break
		;;
	(NOP@(| *))
		# copy quietly, in case of keepalive
		;;
	(GETINFO\ pid)
		# undocumented, but used by GnuPG v2
		io_p_out D $$
		io_p_out OK
		copyline=0
		;;
	(GETINFO\ version)
		# undocumented, but used by GnuPG v2
		# just copy it quietly
		#XXX maybe return "ERR 103 unknown command"?
		;;
	(GETINFO\ *)
		# undocumented, but used by GnuPG v2
		(( quiet )) || print -ru2 "warning: unknown GETINFO" \
		    "capability ${line#GETINFO }"
		;;
	(*)
		(( quiet )) || print -ru2 "warning: unknown line '$line'"
		;;
	}
	(( copyline )) && if (( have_sub )); then
		io_s_out -r -- "$line"
		resp=
		while [[ $resp != @(OK|ERR)@(| *) ]]; do
			io_s_in resp
			io_p_out -r -- "$resp"
		done
	else
		io_p_out OK
	fi
done
if (( have_sub )); then
	io_s_out BYE
	io_s_in resp
fi
exec 2>/dev/null	# avoid "no coprocess" warnings
exec 3>&p; exec 3>&-
exit 0