diff options
Diffstat (limited to 'debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry')
12 files changed, 7398 insertions, 0 deletions
diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/Makefile.am b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/Makefile.am new file mode 100644 index 00000000..0866ccec --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/Makefile.am @@ -0,0 +1,44 @@ +# Pinentry support library Makefile +# Copyright (C) 2002, 2015 g10 Code GmbH +# +# This file is part of PINENTRY. +# +# PINENTRY is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PINENTRY is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses/>. +# SPDX-License-Identifier: GPL-2.0+ + +## Process this file with automake to produce Makefile.in + +EXTRA_DIST = + +if BUILD_LIBPINENTRY_CURSES +pinentry_curses = libpinentry-curses.a +else +pinentry_curses = +endif + +if BUILD_LIBPINENTRY_EMACS +pinentry_emacs_sources = pinentry-emacs.h pinentry-emacs.c +else +pinentry_emacs_sources = +endif + +noinst_LIBRARIES = libpinentry.a $(pinentry_curses) + +LDADD = $(COMMON_LIBS) +AM_CPPFLAGS = $(COMMON_CFLAGS) -I$(top_srcdir)/secmem + +libpinentry_a_SOURCES = pinentry.h pinentry.c argparse.c argparse.h \ + password-cache.h password-cache.c $(pinentry_emacs_sources) +libpinentry_curses_a_SOURCES = pinentry-curses.h pinentry-curses.c +libpinentry_curses_a_CFLAGS = @NCURSES_CFLAGS@ diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/Makefile.in b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/Makefile.in new file mode 100644 index 00000000..5d4f9154 --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/Makefile.in @@ -0,0 +1,696 @@ +# Makefile.in generated by automake 1.16.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Pinentry support library Makefile +# Copyright (C) 2002, 2015 g10 Code GmbH +# +# This file is part of PINENTRY. +# +# PINENTRY is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PINENTRY is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses/>. +# SPDX-License-Identifier: GPL-2.0+ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = pinentry +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/curses.m4 \ + $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/libassuan.m4 $(top_srcdir)/m4/pkg.m4 \ + $(top_srcdir)/m4/qt.m4 $(top_srcdir)/m4/qt4.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libpinentry_curses_a_AR = $(AR) $(ARFLAGS) +libpinentry_curses_a_LIBADD = +am_libpinentry_curses_a_OBJECTS = \ + libpinentry_curses_a-pinentry-curses.$(OBJEXT) +libpinentry_curses_a_OBJECTS = $(am_libpinentry_curses_a_OBJECTS) +libpinentry_a_AR = $(AR) $(ARFLAGS) +libpinentry_a_LIBADD = +am__libpinentry_a_SOURCES_DIST = pinentry.h pinentry.c argparse.c \ + argparse.h password-cache.h password-cache.c pinentry-emacs.h \ + pinentry-emacs.c +@BUILD_LIBPINENTRY_EMACS_TRUE@am__objects_1 = \ +@BUILD_LIBPINENTRY_EMACS_TRUE@ pinentry-emacs.$(OBJEXT) +am_libpinentry_a_OBJECTS = pinentry.$(OBJEXT) argparse.$(OBJEXT) \ + password-cache.$(OBJEXT) $(am__objects_1) +libpinentry_a_OBJECTS = $(am_libpinentry_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/argparse.Po \ + ./$(DEPDIR)/libpinentry_curses_a-pinentry-curses.Po \ + ./$(DEPDIR)/password-cache.Po ./$(DEPDIR)/pinentry-emacs.Po \ + ./$(DEPDIR)/pinentry.Po +am__mv = mv -f +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libpinentry_curses_a_SOURCES) $(libpinentry_a_SOURCES) +DIST_SOURCES = $(libpinentry_curses_a_SOURCES) \ + $(am__libpinentry_a_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +COMMON_CFLAGS = @COMMON_CFLAGS@ +COMMON_LIBS = @COMMON_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EFL_CFLAGS = @EFL_CFLAGS@ +EFL_LIBS = @EFL_LIBS@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FLTKCFLAGS = @FLTKCFLAGS@ +FLTKCXXFLAGS = @FLTKCXXFLAGS@ +FLTKLIBS = @FLTKLIBS@ +FLTK_CONFIG = @FLTK_CONFIG@ +GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@ +GNOME3_CFLAGS = @GNOME3_CFLAGS@ +GNOME3_LIBS = @GNOME3_LIBS@ +GPGRT_CONFIG = @GPGRT_CONFIG@ +GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@ +GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@ +GPG_ERROR_LIBS = @GPG_ERROR_LIBS@ +GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@ +GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@ +GREP = @GREP@ +GTK2_CFLAGS = @GTK2_CFLAGS@ +GTK2_LIBS = @GTK2_LIBS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KF5WAYLANDCLIENT_CFLAGS = @KF5WAYLANDCLIENT_CFLAGS@ +KF5WAYLANDCLIENT_LIBS = @KF5WAYLANDCLIENT_LIBS@ +LDFLAGS = @LDFLAGS@ +LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@ +LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@ +LIBASSUAN_LIBS = @LIBASSUAN_LIBS@ +LIBCURSES = @LIBCURSES@ +LIBICONV = @LIBICONV@ +LIBNCURSES = @LIBNCURSES@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSECRET_CFLAGS = @LIBSECRET_CFLAGS@ +LIBSECRET_LIBS = @LIBSECRET_LIBS@ +LIBTERMCAP = @LIBTERMCAP@ +LIBX11_CFLAGS = @LIBX11_CFLAGS@ +LIBX11_LIBS = @LIBX11_LIBS@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MOC = @MOC@ +MOC2 = @MOC2@ +MOC4 = @MOC4@ +MOC42 = @MOC42@ +NCURSES_CFLAGS = @NCURSES_CFLAGS@ +NCURSES_INCLUDE = @NCURSES_INCLUDE@ +NCURSES_LIBS = @NCURSES_LIBS@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PINENTRY_DEFAULT = @PINENTRY_DEFAULT@ +PINENTRY_QT4_CFLAGS = @PINENTRY_QT4_CFLAGS@ +PINENTRY_QT4_LDFLAGS = @PINENTRY_QT4_LDFLAGS@ +PINENTRY_QT4_LIBS = @PINENTRY_QT4_LIBS@ +PINENTRY_QT_CFLAGS = @PINENTRY_QT_CFLAGS@ +PINENTRY_QT_LDFLAGS = @PINENTRY_QT_LDFLAGS@ +PINENTRY_QT_LIBS = @PINENTRY_QT_LIBS@ +PINENTRY_QT_REQUIRE_CPP11_CFLAGS = @PINENTRY_QT_REQUIRE_CPP11_CFLAGS@ +PINENTRY_QT_REQUIRE_CPP11_LIBS = @PINENTRY_QT_REQUIRE_CPP11_LIBS@ +PINENTRY_QT_X11_EXTRAS_CFLAGS = @PINENTRY_QT_X11_EXTRAS_CFLAGS@ +PINENTRY_QT_X11_EXTRAS_LIBS = @PINENTRY_QT_X11_EXTRAS_LIBS@ +PINENTRY_TQT_CFLAGS = @PINENTRY_TQT_CFLAGS@ +PINENTRY_TQT_LIBS = @PINENTRY_TQT_LIBS@ +PKG_CONFIG = @PKG_CONFIG@ +QTCHOOSER = @QTCHOOSER@ +RANLIB = @RANLIB@ +RCC = @RCC@ +RCC2 = @RCC2@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TQT_MOC = @TQT_MOC@ +VERSION = @VERSION@ +WINDRES = @WINDRES@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = +@BUILD_LIBPINENTRY_CURSES_FALSE@pinentry_curses = +@BUILD_LIBPINENTRY_CURSES_TRUE@pinentry_curses = libpinentry-curses.a +@BUILD_LIBPINENTRY_EMACS_FALSE@pinentry_emacs_sources = +@BUILD_LIBPINENTRY_EMACS_TRUE@pinentry_emacs_sources = pinentry-emacs.h pinentry-emacs.c +noinst_LIBRARIES = libpinentry.a $(pinentry_curses) +LDADD = $(COMMON_LIBS) +AM_CPPFLAGS = $(COMMON_CFLAGS) -I$(top_srcdir)/secmem +libpinentry_a_SOURCES = pinentry.h pinentry.c argparse.c argparse.h \ + password-cache.h password-cache.c $(pinentry_emacs_sources) + +libpinentry_curses_a_SOURCES = pinentry-curses.h pinentry-curses.c +libpinentry_curses_a_CFLAGS = @NCURSES_CFLAGS@ +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu pinentry/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu pinentry/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libpinentry-curses.a: $(libpinentry_curses_a_OBJECTS) $(libpinentry_curses_a_DEPENDENCIES) $(EXTRA_libpinentry_curses_a_DEPENDENCIES) + $(AM_V_at)-rm -f libpinentry-curses.a + $(AM_V_AR)$(libpinentry_curses_a_AR) libpinentry-curses.a $(libpinentry_curses_a_OBJECTS) $(libpinentry_curses_a_LIBADD) + $(AM_V_at)$(RANLIB) libpinentry-curses.a + +libpinentry.a: $(libpinentry_a_OBJECTS) $(libpinentry_a_DEPENDENCIES) $(EXTRA_libpinentry_a_DEPENDENCIES) + $(AM_V_at)-rm -f libpinentry.a + $(AM_V_AR)$(libpinentry_a_AR) libpinentry.a $(libpinentry_a_OBJECTS) $(libpinentry_a_LIBADD) + $(AM_V_at)$(RANLIB) libpinentry.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/argparse.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpinentry_curses_a-pinentry-curses.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/password-cache.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pinentry-emacs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pinentry.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +libpinentry_curses_a-pinentry-curses.o: pinentry-curses.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpinentry_curses_a_CFLAGS) $(CFLAGS) -MT libpinentry_curses_a-pinentry-curses.o -MD -MP -MF $(DEPDIR)/libpinentry_curses_a-pinentry-curses.Tpo -c -o libpinentry_curses_a-pinentry-curses.o `test -f 'pinentry-curses.c' || echo '$(srcdir)/'`pinentry-curses.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpinentry_curses_a-pinentry-curses.Tpo $(DEPDIR)/libpinentry_curses_a-pinentry-curses.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pinentry-curses.c' object='libpinentry_curses_a-pinentry-curses.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpinentry_curses_a_CFLAGS) $(CFLAGS) -c -o libpinentry_curses_a-pinentry-curses.o `test -f 'pinentry-curses.c' || echo '$(srcdir)/'`pinentry-curses.c + +libpinentry_curses_a-pinentry-curses.obj: pinentry-curses.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpinentry_curses_a_CFLAGS) $(CFLAGS) -MT libpinentry_curses_a-pinentry-curses.obj -MD -MP -MF $(DEPDIR)/libpinentry_curses_a-pinentry-curses.Tpo -c -o libpinentry_curses_a-pinentry-curses.obj `if test -f 'pinentry-curses.c'; then $(CYGPATH_W) 'pinentry-curses.c'; else $(CYGPATH_W) '$(srcdir)/pinentry-curses.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpinentry_curses_a-pinentry-curses.Tpo $(DEPDIR)/libpinentry_curses_a-pinentry-curses.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pinentry-curses.c' object='libpinentry_curses_a-pinentry-curses.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libpinentry_curses_a_CFLAGS) $(CFLAGS) -c -o libpinentry_curses_a-pinentry-curses.obj `if test -f 'pinentry-curses.c'; then $(CYGPATH_W) 'pinentry-curses.c'; else $(CYGPATH_W) '$(srcdir)/pinentry-curses.c'; fi` + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/argparse.Po + -rm -f ./$(DEPDIR)/libpinentry_curses_a-pinentry-curses.Po + -rm -f ./$(DEPDIR)/password-cache.Po + -rm -f ./$(DEPDIR)/pinentry-emacs.Po + -rm -f ./$(DEPDIR)/pinentry.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/argparse.Po + -rm -f ./$(DEPDIR)/libpinentry_curses_a-pinentry-curses.Po + -rm -f ./$(DEPDIR)/password-cache.Po + -rm -f ./$(DEPDIR)/pinentry-emacs.Po + -rm -f ./$(DEPDIR)/pinentry.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-noinstLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/argparse.c b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/argparse.c new file mode 100644 index 00000000..ee9c08b9 --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/argparse.c @@ -0,0 +1,1608 @@ +/* [argparse.c wk 17.06.97] Argument Parser for option handling + * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc. + * Copyright (C) 1997-2001, 2006-2008, 2013-2015 Werner Koch + * + * This file is part of JNLIB, which is a subsystem of GnuPG. + * + * JNLIB is free software; you can redistribute it and/or modify it + * under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * JNLIB is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copies of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: (GPL-2.0+ OR LGPL-3.0+) + */ + +/* This file may be used as part of GnuPG or standalone. A GnuPG + build is detected by the presence of the macro GNUPG_MAJOR_VERSION. + Some feature are only availalbe in the GnuPG build mode. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <stdarg.h> +#include <limits.h> +#include <errno.h> + +#ifdef GNUPG_MAJOR_VERSION +# include "libjnlib-config.h" +# include "mischelp.h" +# include "stringhelp.h" +# include "logging.h" +# ifdef JNLIB_NEED_UTF8CONV +# include "utf8conv.h" +# endif +#endif /*GNUPG_MAJOR_VERSION*/ + +#include "argparse.h" + +/* GnuPG uses GPLv3+ but a standalone version of this defaults to + GPLv2+ because that is the license of this file. Change this if + you include it in a program which uses GPLv3. If you don't want to + set a a copyright string for your usage() you may also hardcode it + here. */ +#ifndef GNUPG_MAJOR_VERSION + +# define ARGPARSE_GPL_VERSION 2 +# define ARGPARSE_CRIGHT_STR "Copyright (C) YEAR NAME" + +#else /* Used by GnuPG */ + +# define ARGPARSE_GPL_VERSION 3 +# define ARGPARSE_CRIGHT_STR "Copyright (C) 2015 Free Software Foundation, Inc." + +#endif /*GNUPG_MAJOR_VERSION*/ + +/* Replacements for standalone builds. */ +#ifndef GNUPG_MAJOR_VERSION +# ifndef _ +# define _(a) (a) +# endif +# ifndef DIM +# define DIM(v) (sizeof(v)/sizeof((v)[0])) +# endif +# define jnlib_malloc(a) malloc ((a)) +# define jnlib_realloc(a,b) realloc ((a), (b)) +# define jnlib_strdup(a) strdup ((a)) +# define jnlib_free(a) free ((a)) +# define jnlib_log_error my_log_error +# define jnlib_log_bug my_log_bug +# define trim_spaces(a) my_trim_spaces ((a)) +# define map_static_macro_string(a) (a) +#endif /*!GNUPG_MAJOR_VERSION*/ + + +#define ARGPARSE_STR(v) #v +#define ARGPARSE_STR2(v) ARGPARSE_STR(v) + + +/* Replacements for standalone builds. */ +#ifndef GNUPG_MAJOR_VERSION +static void +my_log_error (const char *fmt, ...) +{ + va_list arg_ptr ; + + va_start (arg_ptr, fmt); + fprintf (stderr, "%s: ", strusage (11)); + vfprintf (stderr, fmt, arg_ptr); + va_end (arg_ptr); +} + +static void +my_log_bug (const char *fmt, ...) +{ + va_list arg_ptr ; + + va_start (arg_ptr, fmt); + fprintf (stderr, "%s: Ohhhh jeeee: ", strusage (11)); + vfprintf (stderr, fmt, arg_ptr); + va_end (arg_ptr); + abort (); +} + +static char * +my_trim_spaces (char *str) +{ + char *string, *p, *mark; + + string = str; + /* Find first non space character. */ + for (p=string; *p && isspace (*(unsigned char*)p) ; p++) + ; + /* Move characters. */ + for ((mark = NULL); (*string = *p); string++, p++) + if (isspace (*(unsigned char*)p)) + { + if (!mark) + mark = string; + } + else + mark = NULL; + if (mark) + *mark = '\0' ; /* Remove trailing spaces. */ + + return str ; +} + +#endif /*!GNUPG_MAJOR_VERSION*/ + + + +/********************************* + * @Summary arg_parse + * #include "argparse.h" + * + * typedef struct { + * char *argc; pointer to argc (value subject to change) + * char ***argv; pointer to argv (value subject to change) + * unsigned flags; Global flags (DO NOT CHANGE) + * int err; print error about last option + * 1 = warning, 2 = abort + * int r_opt; return option + * int r_type; type of return value (0 = no argument found) + * union { + * int ret_int; + * long ret_long + * ulong ret_ulong; + * char *ret_str; + * } r; Return values + * struct { + * int idx; + * const char *last; + * void *aliases; + * } internal; DO NOT CHANGE + * } ARGPARSE_ARGS; + * + * typedef struct { + * int short_opt; + * const char *long_opt; + * unsigned flags; + * } ARGPARSE_OPTS; + * + * int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts ); + * + * @Description + * This is my replacement for getopt(). See the example for a typical usage. + * Global flags are: + * Bit 0 : Do not remove options form argv + * Bit 1 : Do not stop at last option but return other args + * with r_opt set to -1. + * Bit 2 : Assume options and real args are mixed. + * Bit 3 : Do not use -- to stop option processing. + * Bit 4 : Do not skip the first arg. + * Bit 5 : allow usage of long option with only one dash + * Bit 6 : ignore --version + * all other bits must be set to zero, this value is modified by the + * function, so assume this is write only. + * Local flags (for each option): + * Bit 2-0 : 0 = does not take an argument + * 1 = takes int argument + * 2 = takes string argument + * 3 = takes long argument + * 4 = takes ulong argument + * Bit 3 : argument is optional (r_type will the be set to 0) + * Bit 4 : allow 0x etc. prefixed values. + * Bit 6 : Ignore this option + * Bit 7 : This is a command and not an option + * You stop the option processing by setting opts to NULL, the function will + * then return 0. + * @Return Value + * Returns the args.r_opt or 0 if ready + * r_opt may be -2/-7 to indicate an unknown option/command. + * @See Also + * ArgExpand + * @Notes + * You do not need to process the options 'h', '--help' or '--version' + * because this function includes standard help processing; but if you + * specify '-h', '--help' or '--version' you have to do it yourself. + * The option '--' stops argument processing; if bit 1 is set the function + * continues to return normal arguments. + * To process float args or unsigned args you must use a string args and do + * the conversion yourself. + * @Example + * + * ARGPARSE_OPTS opts[] = { + * { 'v', "verbose", 0 }, + * { 'd', "debug", 0 }, + * { 'o', "output", 2 }, + * { 'c', "cross-ref", 2|8 }, + * { 'm', "my-option", 1|8 }, + * { 300, "ignored-long-option, ARGPARSE_OP_IGNORE}, + * { 500, "have-no-short-option-for-this-long-option", 0 }, + * {0} }; + * ARGPARSE_ARGS pargs = { &argc, &argv, 0 } + * + * while( ArgParse( &pargs, &opts) ) { + * switch( pargs.r_opt ) { + * case 'v': opt.verbose++; break; + * case 'd': opt.debug++; break; + * case 'o': opt.outfile = pargs.r.ret_str; break; + * case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; + * case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; + * case 500: opt.a_long_one++; break + * default : pargs.err = 1; break; -- force warning output -- + * } + * } + * if( argc > 1 ) + * log_fatal( "Too many args"); + * + */ + +typedef struct alias_def_s *ALIAS_DEF; +struct alias_def_s { + ALIAS_DEF next; + char *name; /* malloced buffer with name, \0, value */ + const char *value; /* ptr into name */ +}; + + +/* Object to store the names for the --ignore-invalid-option option. + This is a simple linked list. */ +typedef struct iio_item_def_s *IIO_ITEM_DEF; +struct iio_item_def_s +{ + IIO_ITEM_DEF next; + char name[1]; /* String with the long option name. */ +}; + +static const char *(*strusage_handler)( int ) = NULL; +static int (*custom_outfnc) (int, const char *); + +static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s); +static void show_help(ARGPARSE_OPTS *opts, unsigned flags); +static void show_version(void); +static int writestrings (int is_error, const char *string, ...) +#if __GNUC__ >= 4 + __attribute__ ((sentinel(0))) +#endif + ; + + +void +argparse_register_outfnc (int (*fnc)(int, const char *)) +{ + custom_outfnc = fnc; +} + + +/* Write STRING and all following const char * arguments either to + stdout or, if IS_ERROR is set, to stderr. The list of strings must + be terminated by a NULL. */ +static int +writestrings (int is_error, const char *string, ...) +{ + va_list arg_ptr; + const char *s; + int count = 0; + + if (string) + { + s = string; + va_start (arg_ptr, string); + do + { + if (custom_outfnc) + custom_outfnc (is_error? 2:1, s); + else + fputs (s, is_error? stderr : stdout); + count += strlen (s); + } + while ((s = va_arg (arg_ptr, const char *))); + va_end (arg_ptr); + } + return count; +} + + +static void +flushstrings (int is_error) +{ + if (custom_outfnc) + custom_outfnc (is_error? 2:1, NULL); + else + fflush (is_error? stderr : stdout); +} + + +static void +initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno ) +{ + if( !(arg->flags & (1<<15)) ) + { + /* Initialize this instance. */ + arg->internal.idx = 0; + arg->internal.last = NULL; + arg->internal.inarg = 0; + arg->internal.stopped = 0; + arg->internal.aliases = NULL; + arg->internal.cur_alias = NULL; + arg->internal.iio_list = NULL; + arg->err = 0; + arg->flags |= 1<<15; /* Mark as initialized. */ + if ( *arg->argc < 0 ) + jnlib_log_bug ("invalid argument for arg_parse\n"); + } + + + if (arg->err) + { + /* Last option was erroneous. */ + const char *s; + + if (filename) + { + if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG ) + s = _("argument not expected"); + else if ( arg->r_opt == ARGPARSE_READ_ERROR ) + s = _("read error"); + else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG ) + s = _("keyword too long"); + else if ( arg->r_opt == ARGPARSE_MISSING_ARG ) + s = _("missing argument"); + else if ( arg->r_opt == ARGPARSE_INVALID_ARG ) + s = _("invalid argument"); + else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND ) + s = _("invalid command"); + else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS ) + s = _("invalid alias definition"); + else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE ) + s = _("out of core"); + else + s = _("invalid option"); + jnlib_log_error ("%s:%u: %s\n", filename, *lineno, s); + } + else + { + s = arg->internal.last? arg->internal.last:"[??]"; + + if ( arg->r_opt == ARGPARSE_MISSING_ARG ) + jnlib_log_error (_("missing argument for option \"%.50s\"\n"), s); + else if ( arg->r_opt == ARGPARSE_INVALID_ARG ) + jnlib_log_error (_("invalid argument for option \"%.50s\"\n"), s); + else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG ) + jnlib_log_error (_("option \"%.50s\" does not expect an " + "argument\n"), s ); + else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND ) + jnlib_log_error (_("invalid command \"%.50s\"\n"), s); + else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION ) + jnlib_log_error (_("option \"%.50s\" is ambiguous\n"), s); + else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND ) + jnlib_log_error (_("command \"%.50s\" is ambiguous\n"),s ); + else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE ) + jnlib_log_error ("%s\n", _("out of core\n")); + else + jnlib_log_error (_("invalid option \"%.50s\"\n"), s); + } + if (arg->err != ARGPARSE_PRINT_WARNING) + exit (2); + arg->err = 0; + } + + /* Zero out the return value union. */ + arg->r.ret_str = NULL; + arg->r.ret_long = 0; +} + + +static void +store_alias( ARGPARSE_ARGS *arg, char *name, char *value ) +{ + /* TODO: replace this dummy function with a rea one + * and fix the probelms IRIX has with (ALIAS_DEV)arg.. + * used as lvalue + */ + (void)arg; + (void)name; + (void)value; +#if 0 + ALIAS_DEF a = jnlib_xmalloc( sizeof *a ); + a->name = name; + a->value = value; + a->next = (ALIAS_DEF)arg->internal.aliases; + (ALIAS_DEF)arg->internal.aliases = a; +#endif +} + + +/* Return true if KEYWORD is in the ignore-invalid-option list. */ +static int +ignore_invalid_option_p (ARGPARSE_ARGS *arg, const char *keyword) +{ + IIO_ITEM_DEF item = arg->internal.iio_list; + + for (; item; item = item->next) + if (!strcmp (item->name, keyword)) + return 1; + return 0; +} + + +/* Add the keywords up to the next LF to the list of to be ignored + options. After returning FP will either be at EOF or the next + character read wll be the first of a new line. The function + returns 0 on success or true on malloc failure. */ +static int +ignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp) +{ + IIO_ITEM_DEF item; + int c; + char name[100]; + int namelen = 0; + int ready = 0; + enum { skipWS, collectNAME, skipNAME, addNAME} state = skipWS; + + while (!ready) + { + c = getc (fp); + if (c == '\n') + ready = 1; + else if (c == EOF) + { + c = '\n'; + ready = 1; + } + again: + switch (state) + { + case skipWS: + if (!isascii (c) || !isspace(c)) + { + namelen = 0; + state = collectNAME; + goto again; + } + break; + + case collectNAME: + if (isspace (c)) + { + state = addNAME; + goto again; + } + else if (namelen < DIM(name)-1) + name[namelen++] = c; + else /* Too long. */ + state = skipNAME; + break; + + case skipNAME: + if (isspace (c)) + { + state = skipWS; + goto again; + } + break; + + case addNAME: + name[namelen] = 0; + if (!ignore_invalid_option_p (arg, name)) + { + item = jnlib_malloc (sizeof *item + namelen); + if (!item) + return 1; + strcpy (item->name, name); + item->next = (IIO_ITEM_DEF)arg->internal.iio_list; + arg->internal.iio_list = item; + } + state = skipWS; + goto again; + } + } + return 0; +} + + +/* Clear the entire ignore-invalid-option list. */ +static void +ignore_invalid_option_clear (ARGPARSE_ARGS *arg) +{ + IIO_ITEM_DEF item, tmpitem; + + for (item = arg->internal.iio_list; item; item = tmpitem) + { + tmpitem = item->next; + jnlib_free (item); + } + arg->internal.iio_list = NULL; +} + + + +/**************** + * Get options from a file. + * Lines starting with '#' are comment lines. + * Syntax is simply a keyword and the argument. + * Valid keywords are all keywords from the long_opt list without + * the leading dashes. The special keywords "help", "warranty" and "version" + * are not valid here. + * The special keyword "alias" may be used to store alias definitions, + * which are later expanded like long options. + * The option + * ignore-invalid-option OPTIONNAMEs + * is recognized and updates a list of option which should be ignored if they + * are not defined. + * Caller must free returned strings. + * If called with FP set to NULL command line args are parse instead. + * + * Q: Should we allow the syntax + * keyword = value + * and accept for boolean options a value of 1/0, yes/no or true/false? + * Note: Abbreviation of options is here not allowed. + */ +int +optfile_parse (FILE *fp, const char *filename, unsigned *lineno, + ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) +{ + int state, i, c; + int idx=0; + char keyword[100]; + char *buffer = NULL; + size_t buflen = 0; + int in_alias=0; + + if (!fp) /* Divert to to arg_parse() in this case. */ + return arg_parse (arg, opts); + + initialize (arg, filename, lineno); + + /* Find the next keyword. */ + state = i = 0; + for (;;) + { + c = getc (fp); + if (c == '\n' || c== EOF ) + { + if ( c != EOF ) + ++*lineno; + if (state == -1) + break; + else if (state == 2) + { + keyword[i] = 0; + for (i=0; opts[i].short_opt; i++ ) + { + if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword)) + break; + } + idx = i; + arg->r_opt = opts[idx].short_opt; + if ((opts[idx].flags & ARGPARSE_OPT_IGNORE)) + { + state = i = 0; + continue; + } + else if (!opts[idx].short_opt ) + { + if (!strcmp (keyword, "ignore-invalid-option")) + { + /* No argument - ignore this meta option. */ + state = i = 0; + continue; + } + else if (ignore_invalid_option_p (arg, keyword)) + { + /* This invalid option is in the iio list. */ + state = i = 0; + continue; + } + arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND) + ? ARGPARSE_INVALID_COMMAND + : ARGPARSE_INVALID_OPTION); + } + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) + arg->r_type = 0; /* Does not take an arg. */ + else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL) ) + arg->r_type = 0; /* Arg is optional. */ + else + arg->r_opt = ARGPARSE_MISSING_ARG; + + break; + } + else if (state == 3) + { + /* No argument found. */ + if (in_alias) + arg->r_opt = ARGPARSE_MISSING_ARG; + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) + arg->r_type = 0; /* Does not take an arg. */ + else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL)) + arg->r_type = 0; /* No optional argument. */ + else + arg->r_opt = ARGPARSE_MISSING_ARG; + + break; + } + else if (state == 4) + { + /* Has an argument. */ + if (in_alias) + { + if (!buffer) + arg->r_opt = ARGPARSE_UNEXPECTED_ARG; + else + { + char *p; + + buffer[i] = 0; + p = strpbrk (buffer, " \t"); + if (p) + { + *p++ = 0; + trim_spaces (p); + } + if (!p || !*p) + { + jnlib_free (buffer); + arg->r_opt = ARGPARSE_INVALID_ALIAS; + } + else + { + store_alias (arg, buffer, p); + } + } + } + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) + arg->r_opt = ARGPARSE_UNEXPECTED_ARG; + else + { + char *p; + + if (!buffer) + { + keyword[i] = 0; + buffer = jnlib_strdup (keyword); + if (!buffer) + arg->r_opt = ARGPARSE_OUT_OF_CORE; + } + else + buffer[i] = 0; + + if (buffer) + { + trim_spaces (buffer); + p = buffer; + if (*p == '"') + { + /* Remove quotes. */ + p++; + if (*p && p[strlen(p)-1] == '\"' ) + p[strlen(p)-1] = 0; + } + if (!set_opt_arg (arg, opts[idx].flags, p)) + jnlib_free(buffer); + } + } + break; + } + else if (c == EOF) + { + ignore_invalid_option_clear (arg); + if (ferror (fp)) + arg->r_opt = ARGPARSE_READ_ERROR; + else + arg->r_opt = 0; /* EOF. */ + break; + } + state = 0; + i = 0; + } + else if (state == -1) + ; /* Skip. */ + else if (state == 0 && isascii (c) && isspace(c)) + ; /* Skip leading white space. */ + else if (state == 0 && c == '#' ) + state = 1; /* Start of a comment. */ + else if (state == 1) + ; /* Skip comments. */ + else if (state == 2 && isascii (c) && isspace(c)) + { + /* Check keyword. */ + keyword[i] = 0; + for (i=0; opts[i].short_opt; i++ ) + if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword)) + break; + idx = i; + arg->r_opt = opts[idx].short_opt; + if ((opts[idx].flags & ARGPARSE_OPT_IGNORE)) + { + state = 1; /* Process like a comment. */ + } + else if (!opts[idx].short_opt) + { + if (!strcmp (keyword, "alias")) + { + in_alias = 1; + state = 3; + } + else if (!strcmp (keyword, "ignore-invalid-option")) + { + if (ignore_invalid_option_add (arg, fp)) + { + arg->r_opt = ARGPARSE_OUT_OF_CORE; + break; + } + state = i = 0; + ++*lineno; + } + else if (ignore_invalid_option_p (arg, keyword)) + state = 1; /* Process like a comment. */ + else + { + arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND) + ? ARGPARSE_INVALID_COMMAND + : ARGPARSE_INVALID_OPTION); + state = -1; /* Skip rest of line and leave. */ + } + } + else + state = 3; + } + else if (state == 3) + { + /* Skip leading spaces of the argument. */ + if (!isascii (c) || !isspace(c)) + { + i = 0; + keyword[i++] = c; + state = 4; + } + } + else if (state == 4) + { + /* Collect the argument. */ + if (buffer) + { + if (i < buflen-1) + buffer[i++] = c; + else + { + char *tmp; + size_t tmplen = buflen + 50; + + tmp = jnlib_realloc (buffer, tmplen); + if (tmp) + { + buflen = tmplen; + buffer = tmp; + buffer[i++] = c; + } + else + { + jnlib_free (buffer); + arg->r_opt = ARGPARSE_OUT_OF_CORE; + break; + } + } + } + else if (i < DIM(keyword)-1) + keyword[i++] = c; + else + { + size_t tmplen = DIM(keyword) + 50; + buffer = jnlib_malloc (tmplen); + if (buffer) + { + buflen = tmplen; + memcpy(buffer, keyword, i); + buffer[i++] = c; + } + else + { + arg->r_opt = ARGPARSE_OUT_OF_CORE; + break; + } + } + } + else if (i >= DIM(keyword)-1) + { + arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG; + state = -1; /* Skip rest of line and leave. */ + } + else + { + keyword[i++] = c; + state = 2; + } + } + + return arg->r_opt; +} + + + +static int +find_long_option( ARGPARSE_ARGS *arg, + ARGPARSE_OPTS *opts, const char *keyword ) +{ + int i; + size_t n; + + (void)arg; + + /* Would be better if we can do a binary search, but it is not + possible to reorder our option table because we would mess + up our help strings - What we can do is: Build a nice option + lookup table when this function is first invoked */ + if( !*keyword ) + return -1; + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) ) + return i; +#if 0 + { + ALIAS_DEF a; + /* see whether it is an alias */ + for( a = args->internal.aliases; a; a = a->next ) { + if( !strcmp( a->name, keyword) ) { + /* todo: must parse the alias here */ + args->internal.cur_alias = a; + return -3; /* alias available */ + } + } + } +#endif + /* not found, see whether it is an abbreviation */ + /* aliases may not be abbreviated */ + n = strlen( keyword ); + for(i=0; opts[i].short_opt; i++ ) { + if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) { + int j; + for(j=i+1; opts[j].short_opt; j++ ) { + if( opts[j].long_opt + && !strncmp( opts[j].long_opt, keyword, n ) ) + return -2; /* abbreviation is ambiguous */ + } + return i; + } + } + return -1; /* Not found. */ +} + +int +arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) +{ + int idx; + int argc; + char **argv; + char *s, *s2; + int i; + + initialize( arg, NULL, NULL ); + argc = *arg->argc; + argv = *arg->argv; + idx = arg->internal.idx; + + if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0)) + { + /* Skip the first argument. */ + argc--; argv++; idx++; + } + + next_one: + if (!argc) + { + /* No more args. */ + arg->r_opt = 0; + goto leave; /* Ready. */ + } + + s = *argv; + arg->internal.last = s; + + if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL)) + { + arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */ + arg->r_type = 2; + arg->r.ret_str = s; + argc--; argv++; idx++; /* set to next one */ + } + else if( arg->internal.stopped ) + { + arg->r_opt = 0; + goto leave; /* Ready. */ + } + else if ( *s == '-' && s[1] == '-' ) + { + /* Long option. */ + char *argpos; + + arg->internal.inarg = 0; + if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP)) + { + /* Stop option processing. */ + arg->internal.stopped = 1; + arg->flags |= ARGPARSE_FLAG_STOP_SEEN; + argc--; argv++; idx++; + goto next_one; + } + + argpos = strchr( s+2, '=' ); + if ( argpos ) + *argpos = 0; + i = find_long_option ( arg, opts, s+2 ); + if ( argpos ) + *argpos = '='; + + if ( i < 0 && !strcmp ( "help", s+2) ) + show_help (opts, arg->flags); + else if ( i < 0 && !strcmp ( "version", s+2) ) + { + if (!(arg->flags & ARGPARSE_FLAG_NOVERSION)) + { + show_version (); + exit(0); + } + } + else if ( i < 0 && !strcmp( "warranty", s+2)) + { + writestrings (0, strusage (16), "\n", NULL); + exit (0); + } + else if ( i < 0 && !strcmp( "dump-options", s+2) ) + { + for (i=0; opts[i].short_opt; i++ ) + { + if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE)) + writestrings (0, "--", opts[i].long_opt, "\n", NULL); + } + writestrings (0, "--dump-options\n--help\n--version\n--warranty\n", + NULL); + exit (0); + } + + if ( i == -2 ) + arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION; + else if ( i == -1 ) + { + arg->r_opt = ARGPARSE_INVALID_OPTION; + arg->r.ret_str = s+2; + } + else + arg->r_opt = opts[i].short_opt; + if ( i < 0 ) + ; + else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) ) + { + if ( argpos ) + { + s2 = argpos+1; + if ( !*s2 ) + s2 = NULL; + } + else + s2 = argv[1]; + if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) + { + arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */ + } + else if ( !s2 ) + { + arg->r_opt = ARGPARSE_MISSING_ARG; + } + else if ( !argpos && *s2 == '-' + && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) + { + /* The argument is optional and the next seems to be an + option. We do not check this possible option but + assume no argument */ + arg->r_type = ARGPARSE_TYPE_NONE; + } + else + { + set_opt_arg (arg, opts[i].flags, s2); + if ( !argpos ) + { + argc--; argv++; idx++; /* Skip one. */ + } + } + } + else + { + /* Does not take an argument. */ + if ( argpos ) + arg->r_type = ARGPARSE_UNEXPECTED_ARG; + else + arg->r_type = 0; + } + argc--; argv++; idx++; /* Set to next one. */ + } + else if ( (*s == '-' && s[1]) || arg->internal.inarg ) + { + /* Short option. */ + int dash_kludge = 0; + + i = 0; + if ( !arg->internal.inarg ) + { + arg->internal.inarg++; + if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) ) + { + for (i=0; opts[i].short_opt; i++ ) + if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1)) + { + dash_kludge = 1; + break; + } + } + } + s += arg->internal.inarg; + + if (!dash_kludge ) + { + for (i=0; opts[i].short_opt; i++ ) + if ( opts[i].short_opt == *s ) + break; + } + + if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) ) + show_help (opts, arg->flags); + + arg->r_opt = opts[i].short_opt; + if (!opts[i].short_opt ) + { + arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)? + ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION; + arg->internal.inarg++; /* Point to the next arg. */ + arg->r.ret_str = s; + } + else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) ) + { + if ( s[1] && !dash_kludge ) + { + s2 = s+1; + set_opt_arg (arg, opts[i].flags, s2); + } + else + { + s2 = argv[1]; + if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) + { + arg->r_type = ARGPARSE_TYPE_NONE; + } + else if ( !s2 ) + { + arg->r_opt = ARGPARSE_MISSING_ARG; + } + else if ( *s2 == '-' && s2[1] + && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) + { + /* The argument is optional and the next seems to + be an option. We do not check this possible + option but assume no argument. */ + arg->r_type = ARGPARSE_TYPE_NONE; + } + else + { + set_opt_arg (arg, opts[i].flags, s2); + argc--; argv++; idx++; /* Skip one. */ + } + } + s = "x"; /* This is so that !s[1] yields false. */ + } + else + { + /* Does not take an argument. */ + arg->r_type = ARGPARSE_TYPE_NONE; + arg->internal.inarg++; /* Point to the next arg. */ + } + if ( !s[1] || dash_kludge ) + { + /* No more concatenated short options. */ + arg->internal.inarg = 0; + argc--; argv++; idx++; + } + } + else if ( arg->flags & ARGPARSE_FLAG_MIXED ) + { + arg->r_opt = ARGPARSE_IS_ARG; + arg->r_type = 2; + arg->r.ret_str = s; + argc--; argv++; idx++; /* Set to next one. */ + } + else + { + arg->internal.stopped = 1; /* Stop option processing. */ + goto next_one; + } + + leave: + *arg->argc = argc; + *arg->argv = argv; + arg->internal.idx = idx; + return arg->r_opt; +} + + +/* Returns: -1 on error, 0 for an integer type and 1 for a non integer + type argument. */ +static int +set_opt_arg (ARGPARSE_ARGS *arg, unsigned flags, char *s) +{ + int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10; + long l; + + switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) ) + { + case ARGPARSE_TYPE_LONG: + case ARGPARSE_TYPE_INT: + errno = 0; + l = strtol (s, NULL, base); + if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) + { + arg->r_opt = ARGPARSE_INVALID_ARG; + return -1; + } + if (arg->r_type == ARGPARSE_TYPE_LONG) + arg->r.ret_long = l; + else if ( (l < 0 && l < INT_MIN) || l > INT_MAX ) + { + arg->r_opt = ARGPARSE_INVALID_ARG; + return -1; + } + else + arg->r.ret_int = (int)l; + return 0; + + case ARGPARSE_TYPE_ULONG: + while (isascii (*s) && isspace(*s)) + s++; + if (*s == '-') + { + arg->r.ret_ulong = 0; + arg->r_opt = ARGPARSE_INVALID_ARG; + return -1; + } + errno = 0; + arg->r.ret_ulong = strtoul (s, NULL, base); + if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE) + { + arg->r_opt = ARGPARSE_INVALID_ARG; + return -1; + } + return 0; + + case ARGPARSE_TYPE_STRING: + default: + arg->r.ret_str = s; + return 1; + } +} + + +static size_t +long_opt_strlen( ARGPARSE_OPTS *o ) +{ + size_t n = strlen (o->long_opt); + + if ( o->description && *o->description == '|' ) + { + const char *s; +#ifdef JNLIB_NEED_UTF8CONV + int is_utf8 = is_native_utf8 (); +#endif + + s=o->description+1; + if ( *s != '=' ) + n++; + /* For a (mostly) correct length calculation we exclude + continuation bytes (10xxxxxx) if we are on a native utf8 + terminal. */ + for (; *s && *s != '|'; s++ ) +#ifdef JNLIB_NEED_UTF8CONV + if ( is_utf8 && (*s&0xc0) != 0x80 ) +#endif + n++; + } + return n; +} + + +/**************** + * Print formatted help. The description string has some special + * meanings: + * - A description string which is "@" suppresses help output for + * this option + * - a description,ine which starts with a '@' and is followed by + * any other characters is printed as is; this may be used for examples + * ans such. + * - A description which starts with a '|' outputs the string between this + * bar and the next one as arguments of the long option. + */ +static void +show_help (ARGPARSE_OPTS *opts, unsigned int flags) +{ + const char *s; + char tmp[2]; + + show_version (); + writestrings (0, "\n", NULL); + s = strusage (42); + if (s && *s == '1') + { + s = strusage (40); + writestrings (1, s, NULL); + if (*s && s[strlen(s)] != '\n') + writestrings (1, "\n", NULL); + } + s = strusage(41); + writestrings (0, s, "\n", NULL); + if ( opts[0].description ) + { + /* Auto format the option description. */ + int i,j, indent; + + /* Get max. length of long options. */ + for (i=indent=0; opts[i].short_opt; i++ ) + { + if ( opts[i].long_opt ) + if ( !opts[i].description || *opts[i].description != '@' ) + if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 ) + indent = j; + } + + /* Example: " -v, --verbose Viele Sachen ausgeben" */ + indent += 10; + if ( *opts[0].description != '@' ) + writestrings (0, "Options:", "\n", NULL); + for (i=0; opts[i].short_opt; i++ ) + { + s = map_static_macro_string (_( opts[i].description )); + if ( s && *s== '@' && !s[1] ) /* Hide this line. */ + continue; + if ( s && *s == '@' ) /* Unindented comment only line. */ + { + for (s++; *s; s++ ) + { + if ( *s == '\n' ) + { + if( s[1] ) + writestrings (0, "\n", NULL); + } + else + { + tmp[0] = *s; + tmp[1] = 0; + writestrings (0, tmp, NULL); + } + } + writestrings (0, "\n", NULL); + continue; + } + + j = 3; + if ( opts[i].short_opt < 256 ) + { + tmp[0] = opts[i].short_opt; + tmp[1] = 0; + writestrings (0, " -", tmp, NULL ); + if ( !opts[i].long_opt ) + { + if (s && *s == '|' ) + { + writestrings (0, " ", NULL); j++; + for (s++ ; *s && *s != '|'; s++, j++ ) + { + tmp[0] = *s; + tmp[1] = 0; + writestrings (0, tmp, NULL); + } + if ( *s ) + s++; + } + } + } + else + writestrings (0, " ", NULL); + if ( opts[i].long_opt ) + { + tmp[0] = opts[i].short_opt < 256?',':' '; + tmp[1] = 0; + j += writestrings (0, tmp, " --", opts[i].long_opt, NULL); + if (s && *s == '|' ) + { + if ( *++s != '=' ) + { + writestrings (0, " ", NULL); + j++; + } + for ( ; *s && *s != '|'; s++, j++ ) + { + tmp[0] = *s; + tmp[1] = 0; + writestrings (0, tmp, NULL); + } + if ( *s ) + s++; + } + writestrings (0, " ", NULL); + j += 3; + } + for (;j < indent; j++ ) + writestrings (0, " ", NULL); + if ( s ) + { + if ( *s && j > indent ) + { + writestrings (0, "\n", NULL); + for (j=0;j < indent; j++ ) + writestrings (0, " ", NULL); + } + for (; *s; s++ ) + { + if ( *s == '\n' ) + { + if ( s[1] ) + { + writestrings (0, "\n", NULL); + for (j=0; j < indent; j++ ) + writestrings (0, " ", NULL); + } + } + else + { + tmp[0] = *s; + tmp[1] = 0; + writestrings (0, tmp, NULL); + } + } + } + writestrings (0, "\n", NULL); + } + if ( (flags & ARGPARSE_FLAG_ONEDASH) ) + writestrings (0, "\n(A single dash may be used " + "instead of the double ones)\n", NULL); + } + if ( (s=strusage(19)) ) + { + writestrings (0, "\n", NULL); + writestrings (0, s, NULL); + } + flushstrings (0); + exit(0); +} + +static void +show_version () +{ + const char *s; + int i; + + /* Version line. */ + writestrings (0, strusage (11), NULL); + if ((s=strusage (12))) + writestrings (0, " (", s, ")", NULL); + writestrings (0, " ", strusage (13), "\n", NULL); + /* Additional version lines. */ + for (i=20; i < 30; i++) + if ((s=strusage (i))) + writestrings (0, s, "\n", NULL); + /* Copyright string. */ + if ((s=strusage (14))) + writestrings (0, s, "\n", NULL); + /* Licence string. */ + if( (s=strusage (10)) ) + writestrings (0, s, "\n", NULL); + /* Copying conditions. */ + if ( (s=strusage(15)) ) + writestrings (0, s, NULL); + /* Thanks. */ + if ((s=strusage(18))) + writestrings (0, s, NULL); + /* Additional program info. */ + for (i=30; i < 40; i++ ) + if ( (s=strusage (i)) ) + writestrings (0, s, NULL); + flushstrings (0); +} + + +void +usage (int level) +{ + const char *p; + + if (!level) + { + writestrings (1, strusage(11), " ", strusage(13), "; ", + strusage (14), "\n", NULL); + flushstrings (1); + } + else if (level == 1) + { + p = strusage (40); + writestrings (1, p, NULL); + if (*p && p[strlen(p)] != '\n') + writestrings (1, "\n", NULL); + exit (2); + } + else if (level == 2) + { + p = strusage (42); + if (p && *p == '1') + { + p = strusage (40); + writestrings (1, p, NULL); + if (*p && p[strlen(p)] != '\n') + writestrings (1, "\n", NULL); + } + writestrings (0, strusage(41), "\n", NULL); + exit (0); + } +} + +/* Level + * 0: Print copyright string to stderr + * 1: Print a short usage hint to stderr and terminate + * 2: Print a long usage hint to stdout and terminate + * 10: Return license info string + * 11: Return the name of the program + * 12: Return optional name of package which includes this program. + * 13: version string + * 14: copyright string + * 15: Short copying conditions (with LFs) + * 16: Long copying conditions (with LFs) + * 17: Optional printable OS name + * 18: Optional thanks list (with LFs) + * 19: Bug report info + *20..29: Additional lib version strings. + *30..39: Additional program info (with LFs) + * 40: short usage note (with LF) + * 41: long usage note (with LF) + * 42: Flag string: + * First char is '1': + * The short usage notes needs to be printed + * before the long usage note. + */ +const char * +strusage( int level ) +{ + const char *p = strusage_handler? strusage_handler(level) : NULL; + + if ( p ) + return map_static_macro_string (p); + + switch ( level ) + { + + case 10: +#if ARGPARSE_GPL_VERSION == 3 + p = ("License GPLv3+: GNU GPL version 3 or later " + "<https://www.gnu.org/licenses/gpl.html>"); +#else + p = ("License GPLv2+: GNU GPL version 2 or later " + "<https://www.gnu.org/licenses/>"); +#endif + break; + case 11: p = "foo"; break; + case 13: p = "0.0"; break; + case 14: p = ARGPARSE_CRIGHT_STR; break; + case 15: p = +"This is free software: you are free to change and redistribute it.\n" +"There is NO WARRANTY, to the extent permitted by law.\n"; + break; + case 16: p = +"This is free software; you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation; either version " +ARGPARSE_STR2(ARGPARSE_GPL_VERSION) +" of the License, or\n" +"(at your option) any later version.\n\n" +"It is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n\n" +"You should have received a copy of the GNU General Public License\n" +"along with this software. If not, see <https://www.gnu.org/licenses/>.\n"; + break; + case 40: /* short and long usage */ + case 41: p = ""; break; + } + + return p; +} + + +/* Set the usage handler. This function is basically a constructor. */ +void +set_strusage ( const char *(*f)( int ) ) +{ + strusage_handler = f; +} + + +#ifdef TEST +static struct { + int verbose; + int debug; + char *outfile; + char *crf; + int myopt; + int echo; + int a_long_one; +} opt; + +int +main(int argc, char **argv) +{ + ARGPARSE_OPTS opts[] = { + ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"), + ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, " + "was wir eingegeben haben")), + ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"), + ARGPARSE_s_s('o', "output", 0 ), + ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ), + /* Note that on a non-utf8 terminal the ß might garble the output. */ + ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"), + ARGPARSE_o_i('m', "my-option", 0), + ARGPARSE_s_n(500, "a-long-option", 0 ), + ARGPARSE_end() + }; + ARGPARSE_ARGS pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL + | ARGPARSE_FLAG_MIXED + | ARGPARSE_FLAG_ONEDASH) }; + int i; + + while (arg_parse (&pargs, opts)) + { + switch (pargs.r_opt) + { + case ARGPARSE_IS_ARG : + printf ("arg='%s'\n", pargs.r.ret_str); + break; + case 'v': opt.verbose++; break; + case 'e': opt.echo++; break; + case 'd': opt.debug++; break; + case 'o': opt.outfile = pargs.r.ret_str; break; + case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; + case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; + case 500: opt.a_long_one++; break; + default : pargs.err = ARGPARSE_PRINT_WARNING; break; + } + } + for (i=0; i < argc; i++ ) + printf ("%3d -> (%s)\n", i, argv[i] ); + puts ("Options:"); + if (opt.verbose) + printf (" verbose=%d\n", opt.verbose ); + if (opt.debug) + printf (" debug=%d\n", opt.debug ); + if (opt.outfile) + printf (" outfile='%s'\n", opt.outfile ); + if (opt.crf) + printf (" crffile='%s'\n", opt.crf ); + if (opt.myopt) + printf (" myopt=%d\n", opt.myopt ); + if (opt.a_long_one) + printf (" a-long-one=%d\n", opt.a_long_one ); + if (opt.echo) + printf (" echo=%d\n", opt.echo ); + + return 0; +} +#endif /*TEST*/ + +/**** bottom of file ****/ diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/argparse.h b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/argparse.h new file mode 100644 index 00000000..5b652eba --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/argparse.h @@ -0,0 +1,204 @@ +/* argparse.h - Argument parser for option handling. + * Copyright (C) 1998,1999,2000,2001,2006 Free Software Foundation, Inc. + * + * This file is part of JNLIB, which is a subsystem of GnuPG. + * + * JNLIB is free software; you can redistribute it and/or modify it + * under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * JNLIB is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copies of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: (GPL-2.0+ OR LGPL-3.0+) + */ + +#ifndef LIBJNLIB_ARGPARSE_H +#define LIBJNLIB_ARGPARSE_H + +#include <stdio.h> + +typedef struct +{ + int *argc; /* Pointer to ARGC (value subject to change). */ + char ***argv; /* Pointer to ARGV (value subject to change). */ + unsigned int flags; /* Global flags. May be set prior to calling the + parser. The parser may change the value. */ + int err; /* Print error description for last option. + Either 0, ARGPARSE_PRINT_WARNING or + ARGPARSE_PRINT_ERROR. */ + + int r_opt; /* Returns option code. */ + int r_type; /* Returns type of option value. */ + union { + int ret_int; + long ret_long; + unsigned long ret_ulong; + char *ret_str; + } r; /* Return values */ + + struct { + int idx; + int inarg; + int stopped; + const char *last; + void *aliases; + const void *cur_alias; + void *iio_list; + } internal; /* Private - do not change. */ +} ARGPARSE_ARGS; + +typedef struct +{ + int short_opt; + const char *long_opt; + unsigned int flags; + const char *description; /* Optional option description. */ +} ARGPARSE_OPTS; + + +/* Global flags (ARGPARSE_ARGS). */ +#define ARGPARSE_FLAG_KEEP 1 /* Do not remove options form argv. */ +#define ARGPARSE_FLAG_ALL 2 /* Do not stop at last option but return + remaining args with R_OPT set to -1. */ +#define ARGPARSE_FLAG_MIXED 4 /* Assume options and args are mixed. */ +#define ARGPARSE_FLAG_NOSTOP 8 /* Do not stop processing at "--". */ +#define ARGPARSE_FLAG_ARG0 16 /* Do not skip the first arg. */ +#define ARGPARSE_FLAG_ONEDASH 32 /* Allow long options with one dash. */ +#define ARGPARSE_FLAG_NOVERSION 64 /* No output for "--version". */ + +#define ARGPARSE_FLAG_STOP_SEEN 256 /* Set to true if a "--" has been seen. */ + +/* Flags for each option (ARGPARSE_OPTS). The type code may be + ORed with the OPT flags. */ +#define ARGPARSE_TYPE_NONE 0 /* Does not take an argument. */ +#define ARGPARSE_TYPE_INT 1 /* Takes an int argument. */ +#define ARGPARSE_TYPE_STRING 2 /* Takes a string argument. */ +#define ARGPARSE_TYPE_LONG 3 /* Takes a long argument. */ +#define ARGPARSE_TYPE_ULONG 4 /* Takes an unsigned long argument. */ +#define ARGPARSE_OPT_OPTIONAL (1<<3) /* Argument is optional. */ +#define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */ +#define ARGPARSE_OPT_IGNORE (1<<6) /* Ignore command or option. */ +#define ARGPARSE_OPT_COMMAND (1<<7) /* The argument is a command. */ + +#define ARGPARSE_TYPE_MASK 7 /* Mask for the type values (internal). */ + +/* A set of macros to make option definitions easier to read. */ +#define ARGPARSE_x(s,l,t,f,d) \ + { (s), (l), ARGPARSE_TYPE_ ## t | (f), (d) } + +#define ARGPARSE_s(s,l,t,d) \ + { (s), (l), ARGPARSE_TYPE_ ## t, (d) } +#define ARGPARSE_s_n(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_NONE, (d) } +#define ARGPARSE_s_i(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_INT, (d) } +#define ARGPARSE_s_s(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_STRING, (d) } +#define ARGPARSE_s_l(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_LONG, (d) } +#define ARGPARSE_s_u(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_ULONG, (d) } + +#define ARGPARSE_o(s,l,t,d) \ + { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_n(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_i(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_s(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_l(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_u(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_OPTIONAL), (d) } + +#define ARGPARSE_p(s,l,t,d) \ + { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_n(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_i(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_s(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_l(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_u(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_PREFIX), (d) } + +#define ARGPARSE_op(s,l,t,d) \ + { (s), (l), (ARGPARSE_TYPE_ ## t \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_n(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_i(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_INT \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_s(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_STRING \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_l(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_LONG \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_u(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_ULONG \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } + +#define ARGPARSE_c(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) } + +#define ARGPARSE_ignore(s,l) \ + { (s), (l), (ARGPARSE_OPT_IGNORE), "@" } + +#define ARGPARSE_group(s,d) \ + { (s), NULL, 0, (d) } + +#define ARGPARSE_end() { 0, NULL, 0, NULL } + + +/* Other constants. */ +#define ARGPARSE_PRINT_WARNING 1 +#define ARGPARSE_PRINT_ERROR 2 + + +/* Error values. */ +#define ARGPARSE_IS_ARG (-1) +#define ARGPARSE_INVALID_OPTION (-2) +#define ARGPARSE_MISSING_ARG (-3) +#define ARGPARSE_KEYWORD_TOO_LONG (-4) +#define ARGPARSE_READ_ERROR (-5) +#define ARGPARSE_UNEXPECTED_ARG (-6) +#define ARGPARSE_INVALID_COMMAND (-7) +#define ARGPARSE_AMBIGUOUS_OPTION (-8) +#define ARGPARSE_AMBIGUOUS_COMMAND (-9) +#define ARGPARSE_INVALID_ALIAS (-10) +#define ARGPARSE_OUT_OF_CORE (-11) +#define ARGPARSE_INVALID_ARG (-12) + + +int arg_parse (ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); +int optfile_parse (FILE *fp, const char *filename, unsigned *lineno, + ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); +void usage (int level); +const char *strusage (int level); +void set_strusage (const char *(*f)( int )); +void argparse_register_outfnc (int (*fnc)(int, const char *)); + +#endif /*LIBJNLIB_ARGPARSE_H*/ diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/password-cache.c b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/password-cache.c new file mode 100644 index 00000000..f9523b1c --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/password-cache.c @@ -0,0 +1,172 @@ +/* password-cache.c - Password cache support. + Copyright (C) 2015 g10 Code GmbH + + This file is part of PINENTRY. + + PINENTRY is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PINENTRY is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <https://www.gnu.org/licenses/>. + SPDX-License-Identifier: GPL-2.0+ + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#ifdef HAVE_LIBSECRET +# include <libsecret/secret.h> +#endif + +#include "password-cache.h" +#include "memory.h" + +#ifdef HAVE_LIBSECRET +static const SecretSchema * +gpg_schema (void) +{ + static const SecretSchema the_schema = { + "org.gnupg.Passphrase", SECRET_SCHEMA_NONE, + { + { "stored-by", SECRET_SCHEMA_ATTRIBUTE_STRING }, + { "keygrip", SECRET_SCHEMA_ATTRIBUTE_STRING }, + { "NULL", 0 }, + } + }; + return &the_schema; +} + +static char * +keygrip_to_label (const char *keygrip) +{ + char const prefix[] = "GnuPG: "; + char *label; + + label = malloc (sizeof (prefix) + strlen (keygrip)); + if (label) + { + memcpy (label, prefix, sizeof (prefix) - 1); + strcpy (&label[sizeof (prefix) - 1], keygrip); + } + return label; +} +#endif + +void +password_cache_save (const char *keygrip, const char *password) +{ +#ifdef HAVE_LIBSECRET + char *label; + GError *error = NULL; + + if (! *keygrip) + return; + + label = keygrip_to_label (keygrip); + if (! label) + return; + + if (! secret_password_store_sync (gpg_schema (), + SECRET_COLLECTION_DEFAULT, + label, password, NULL, &error, + "stored-by", "GnuPG Pinentry", + "keygrip", keygrip, NULL)) + { + fprintf (stderr, "Failed to cache password for key %s with secret service: %s\n", + keygrip, error->message); + + g_error_free (error); + } + + free (label); +#else + (void) keygrip; + (void) password; + return; +#endif +} + +char * +password_cache_lookup (const char *keygrip, int *fatal_error) +{ +#ifdef HAVE_LIBSECRET + GError *error = NULL; + char *password; + char *password2; + + if (! *keygrip) + return NULL; + + password = secret_password_lookup_nonpageable_sync + (gpg_schema (), NULL, &error, + "keygrip", keygrip, NULL); + + if (error != NULL) + { + if (fatal_error) + *fatal_error = 1; + + fprintf (stderr, "Failed to lookup password for key %s with secret service: %s\n", + keygrip, error->message); + g_error_free (error); + return NULL; + } + if (! password) + /* The password for this key is not cached. Just return NULL. */ + return NULL; + + /* The password needs to be returned in secmem allocated memory. */ + password2 = secmem_malloc (strlen (password) + 1); + if (password2) + strcpy(password2, password); + else + fprintf (stderr, "secmem_malloc failed: can't copy password!\n"); + + secret_password_free (password); + + return password2; +#else + (void) keygrip; + (void) fatal_error; + return NULL; +#endif +} + +/* Try and remove the cached password for key grip. Returns -1 on + error, 0 if the key is not found and 1 if the password was + removed. */ +int +password_cache_clear (const char *keygrip) +{ +#ifdef HAVE_LIBSECRET + GError *error = NULL; + int removed = secret_password_clear_sync (gpg_schema (), NULL, &error, + "keygrip", keygrip, NULL); + if (error != NULL) + { + fprintf (stderr, "Failed to clear password for key %s with secret service: %s\n", + keygrip, error->message); + g_debug("%s", error->message); + g_error_free (error); + return -1; + } + if (removed) + return 1; + return 0; +#else + (void) keygrip; + return -1; +#endif +} diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/password-cache.h b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/password-cache.h new file mode 100644 index 00000000..d7ccfeef --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/password-cache.h @@ -0,0 +1,30 @@ +/* password-cache.h - Password cache support interfaces. + Copyright (C) 2015 g10 Code GmbH + + This file is part of PINENTRY. + + PINENTRY is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PINENTRY is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <https://www.gnu.org/licenses/>. + SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef PASSWORD_CACHE_H +#define PASSWORD_CACHE_H + +void password_cache_save (const char *key_grip, const char *password); + +char *password_cache_lookup (const char *key_grip, int *fatal_error); + +int password_cache_clear (const char *keygrip); + +#endif diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry-curses.c b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry-curses.c new file mode 100644 index 00000000..cc4cecbe --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry-curses.c @@ -0,0 +1,1410 @@ +/* pinentry-curses.c - A secure curses dialog for PIN entry, library version + * Copyright (C) 2002, 2015 g10 Code GmbH + * + * This file is part of PINENTRY. + * + * PINENTRY is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * PINENTRY is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <assert.h> +#include <curses.h> +#include <signal.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <locale.h> +#include <iconv.h> +#if defined(HAVE_LANGINFO_H) +# include <langinfo.h> +#elif defined(HAVE_W32_SYSTEM) +# include <stdio.h> +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include <windows.h> +/* A simple replacement for nl_langinfo that only understands + CODESET. */ +# define CODESET 1 +char * +nl_langinfo (int ignore) +{ + static char codepage[20]; + UINT cp = GetACP (); + + (void)ignore; + + sprintf (codepage, "CP%u", cp); + return codepage; +} +#endif +#include <limits.h> +#include <string.h> +#include <errno.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_UTIME_H +#include <utime.h> +#endif /*HAVE_UTIME_H*/ + +#include <memory.h> + +#ifdef HAVE_WCHAR_H +#include <wchar.h> +#endif /*HAVE_WCHAR_H*/ + +#include <assuan.h> + +#include "pinentry.h" + +#if GPG_ERROR_VERSION_NUMBER < 0x011900 /* 1.25 */ +# define GPG_ERR_WINDOW_TOO_SMALL 301 +# define GPG_ERR_MISSING_ENVVAR 303 +#endif + + +/* FIXME: We should allow configuration of these button labels and in + any case use the default_ok, default_cancel values if available. + However, I have no clue about curses and localization. */ +#define STRING_OK "<OK>" +#define STRING_NOTOK "<No>" +#define STRING_CANCEL "<Cancel>" + +#define USE_COLORS (has_colors () && COLOR_PAIRS >= 2) +static short pinentry_color[] = { -1, -1, COLOR_BLACK, COLOR_RED, + COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, + COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE }; +static int init_screen; +#ifndef HAVE_DOSISH_SYSTEM +static int timed_out; +#endif + +typedef enum + { + DIALOG_POS_NONE, + DIALOG_POS_PIN, + DIALOG_POS_OK, + DIALOG_POS_NOTOK, + DIALOG_POS_CANCEL + } +dialog_pos_t; + +struct dialog +{ + dialog_pos_t pos; + int pin_y; + int pin_x; + /* Width of the PIN field. */ + int pin_size; + /* Cursor location in PIN field. */ + int pin_loc; + int pin_max; + /* Length of PIN. */ + int pin_len; + int got_input; + int no_echo; + + int ok_y; + int ok_x; + char *ok; + int cancel_y; + int cancel_x; + char *cancel; + int notok_y; + int notok_x; + char *notok; + + pinentry_t pinentry; +}; +typedef struct dialog *dialog_t; + +/* Flag to remember whether a warning has been printed. */ +static int lc_ctype_unknown_warning; + +static char * +pinentry_utf8_to_local (const char *lc_ctype, const char *text) +{ + iconv_t cd; + const char *input = text; + size_t input_len = strlen (text) + 1; + char *output; + size_t output_len; + char *output_buf; + size_t processed; + char *old_ctype; + char *target_encoding; + const char *pgmname = pinentry_get_pgmname (); + + /* If no locale setting could be determined, simply copy the + string. */ + if (!lc_ctype) + { + if (! lc_ctype_unknown_warning) + { + fprintf (stderr, "%s: no LC_CTYPE known - assuming UTF-8\n", + pgmname); + lc_ctype_unknown_warning = 1; + } + return strdup (text); + } + + old_ctype = strdup (setlocale (LC_CTYPE, NULL)); + if (!old_ctype) + return NULL; + setlocale (LC_CTYPE, lc_ctype); + target_encoding = nl_langinfo (CODESET); + if (!target_encoding) + target_encoding = "?"; + setlocale (LC_CTYPE, old_ctype); + free (old_ctype); + + /* This is overkill, but simplifies the iconv invocation greatly. */ + output_len = input_len * MB_LEN_MAX; + output_buf = output = malloc (output_len); + if (!output) + return NULL; + + cd = iconv_open (target_encoding, "UTF-8"); + if (cd == (iconv_t) -1) + { + fprintf (stderr, "%s: can't convert from UTF-8 to %s: %s\n", + pgmname, target_encoding, strerror (errno)); + free (output_buf); + return NULL; + } + processed = iconv (cd, (ICONV_CONST char **)&input, &input_len, + &output, &output_len); + iconv_close (cd); + if (processed == (size_t) -1 || input_len) + { + fprintf (stderr, "%s: error converting from UTF-8 to %s: %s\n", + pgmname, target_encoding, strerror (errno)); + free (output_buf); + return NULL; + } + return output_buf; +} + +/* Convert TEXT which is encoded according to LC_CTYPE to UTF-8. With + SECURE set to true, use secure memory for the returned buffer. + Return NULL on error. */ +static char * +pinentry_local_to_utf8 (char *lc_ctype, char *text, int secure) +{ + char *old_ctype; + char *source_encoding; + iconv_t cd; + const char *input = text; + size_t input_len = strlen (text) + 1; + char *output; + size_t output_len; + char *output_buf; + size_t processed; + const char *pgmname = pinentry_get_pgmname (); + + /* If no locale setting could be determined, simply copy the + string. */ + if (!lc_ctype) + { + if (! lc_ctype_unknown_warning) + { + fprintf (stderr, "%s: no LC_CTYPE known - assuming UTF-8\n", + pgmname); + lc_ctype_unknown_warning = 1; + } + output_buf = secure? secmem_malloc (input_len) : malloc (input_len); + if (output_buf) + strcpy (output_buf, input); + return output_buf; + } + + old_ctype = strdup (setlocale (LC_CTYPE, NULL)); + if (!old_ctype) + return NULL; + setlocale (LC_CTYPE, lc_ctype); + source_encoding = nl_langinfo (CODESET); + setlocale (LC_CTYPE, old_ctype); + free (old_ctype); + + /* This is overkill, but simplifies the iconv invocation greatly. */ + output_len = input_len * MB_LEN_MAX; + output_buf = output = secure? secmem_malloc (output_len):malloc (output_len); + if (!output) + return NULL; + + cd = iconv_open ("UTF-8", source_encoding); + if (cd == (iconv_t) -1) + { + fprintf (stderr, "%s: can't convert from %s to UTF-8: %s\n", + pgmname, source_encoding? source_encoding : "?", + strerror (errno)); + if (secure) + secmem_free (output_buf); + else + free (output_buf); + return NULL; + } + processed = iconv (cd, (ICONV_CONST char **)&input, &input_len, + &output, &output_len); + iconv_close (cd); + if (processed == (size_t) -1 || input_len) + { + fprintf (stderr, "%s: error converting from %s to UTF-8: %s\n", + pgmname, source_encoding? source_encoding : "?", + strerror (errno)); + if (secure) + secmem_free (output_buf); + else + free (output_buf); + return NULL; + } + return output_buf; +} + +#ifdef HAVE_NCURSESW +typedef wchar_t CH; +#define STRLEN(x) wcslen (x) +#define STRWIDTH(x) wcswidth (x, wcslen (x)) +#define ADDCH(x) addnwstr (&x, 1); +#define CHWIDTH(x) wcwidth (x) +#define NULLCH L'\0' +#define NLCH L'\n' +#define SPCH L' ' +#else +typedef char CH; +#define STRLEN(x) strlen (x) +#define STRWIDTH(x) strlen (x) +#define ADDCH(x) addch ((unsigned char) x) +#define CHWIDTH(x) 1 +#define NULLCH '\0' +#define NLCH '\n' +#define SPCH ' ' +#endif + +/* Return the next line up to MAXWIDTH columns wide in START and LEN. + Return value is the width needed for the line. + The first invocation should have 0 as *LEN. If the line ends with + a \n, it is a normal line that will be continued. If it is a '\0' + the end of the text is reached after this line. In all other cases + there is a forced line break. A full line is returned and will be + continued in the next line. */ +static int +collect_line (int maxwidth, CH **start_p, int *len_p) +{ + int last_space = 0; + int len = *len_p; + int width = 0; + CH *end; + + /* Skip to next line. */ + *start_p += len; + /* Skip leading space. */ + while (**start_p == SPCH) + (*start_p)++; + + end = *start_p; + len = 0; + + while (width < maxwidth - 1 && *end != NULLCH && *end != NLCH) + { + if (*end == SPCH) + last_space = len; + width += CHWIDTH (*end); + len++; + end++; + } + + if (*end != NULLCH && *end != NLCH && last_space != 0) + { + /* We reached the end of the available space, but still have + characters to go in this line. We can break the line into + two parts at a space. */ + len = last_space; + (*start_p)[len] = NLCH; + } + *len_p = len + 1; + return width; +} + +#ifdef HAVE_NCURSESW +static CH * +utf8_to_local (char *lc_ctype, char *string) +{ + mbstate_t ps; + size_t len; + char *local; + const char *p; + wchar_t *wcs = NULL; + char *old_ctype = NULL; + + local = pinentry_utf8_to_local (lc_ctype, string); + if (!local) + return NULL; + + old_ctype = strdup (setlocale (LC_CTYPE, NULL)); + setlocale (LC_CTYPE, lc_ctype? lc_ctype : ""); + + p = local; + memset (&ps, 0, sizeof(mbstate_t)); + len = mbsrtowcs (NULL, &p, strlen (string), &ps); + if (len == (size_t)-1) + { + free (local); + goto leave; + } + wcs = calloc (len + 1, sizeof(wchar_t)); + if (!wcs) + { + free (local); + goto leave; + } + + p = local; + memset (&ps, 0, sizeof(mbstate_t)); + mbsrtowcs (wcs, &p, len, &ps); + + free (local); + + leave: + if (old_ctype) + { + setlocale (LC_CTYPE, old_ctype); + free (old_ctype); + } + + return wcs; +} +#else +static CH * +utf8_to_local (const char *lc_ctype, const char *string) +{ + return pinentry_utf8_to_local (lc_ctype, string); +} +#endif + +static int +dialog_create (pinentry_t pinentry, dialog_t dialog) +{ + int err = 0; + int size_y; + int size_x; + int y; + int x; + int ypos; + int xpos; + int description_x = 0; + int error_x = 0; + CH *description = NULL; + CH *error = NULL; + CH *prompt = NULL; + + dialog->pinentry = pinentry; + +#define COPY_OUT(what) \ + do \ + if (pinentry->what) \ + { \ + what = utf8_to_local (pinentry->lc_ctype, pinentry->what); \ + if (!what) \ + { \ + err = 1; \ + pinentry->specific_err = gpg_error (GPG_ERR_LOCALE_PROBLEM); \ + pinentry->specific_err_loc = "dialog_create_copy"; \ + goto out; \ + } \ + } \ + while (0) + + COPY_OUT (description); + COPY_OUT (error); + COPY_OUT (prompt); + + /* There is no pinentry->default_notok. Map it to + pinentry->notok. */ +#define default_notok notok +#define MAKE_BUTTON(which,default) \ + do \ + { \ + char *new = NULL; \ + if (pinentry->default_##which || pinentry->which) \ + { \ + int len; \ + char *msg; \ + int i, j; \ + \ + msg = pinentry->which; \ + if (! msg) \ + msg = pinentry->default_##which; \ + len = strlen (msg); \ + \ + new = malloc (len + 3); \ + if (!new) \ + { \ + err = 1; \ + pinentry->specific_err = gpg_error_from_syserror (); \ + pinentry->specific_err_loc = "dialog_create_mk_button"; \ + goto out; \ + } \ + \ + new[0] = '<'; \ + for (i = 0, j = 1; i < len; i ++, j ++) \ + { \ + if (msg[i] == '_') \ + { \ + i ++; \ + if (msg[i] == 0) \ + /* _ at end of string. */ \ + break; \ + } \ + new[j] = msg[i]; \ + } \ + \ + new[j] = '>'; \ + new[j + 1] = 0; \ + } \ + dialog->which = pinentry_utf8_to_local (pinentry->lc_ctype, \ + new ? new : default); \ + free (new); \ + if (!dialog->which) \ + { \ + err = 1; \ + pinentry->specific_err = gpg_error (GPG_ERR_LOCALE_PROBLEM); \ + pinentry->specific_err_loc = "dialog_create_utf8conv"; \ + goto out; \ + } \ + } \ + while (0) + + MAKE_BUTTON (ok, STRING_OK); + if (!pinentry->one_button) + MAKE_BUTTON (cancel, STRING_CANCEL); + else + dialog->cancel = NULL; + if (!pinentry->one_button && pinentry->notok) + MAKE_BUTTON (notok, STRING_NOTOK); + else + dialog->notok = NULL; + + getmaxyx (stdscr, size_y, size_x); + + /* Check if all required lines fit on the screen. */ + y = 1; /* Top frame. */ + if (description) + { + CH *start = description; + int len = 0; + + do + { + int width = collect_line (size_x - 4, &start, &len); + + if (width > description_x) + description_x = width; + y++; + } + while (start[len - 1]); + y++; + } + + if (pinentry->pin) + { + if (error) + { + CH *p = error; + int err_x = 0; + + while (*p) + { + if (*(p++) == '\n') + { + if (err_x > error_x) + error_x = err_x; + y++; + err_x = 0; + } + else + err_x++; + } + if (err_x > error_x) + error_x = err_x; + y += 2; /* Error message. */ + } + y += 2; /* Pin entry field. */ + } + y += 2; /* OK/Cancel and bottom frame. */ + + if (y > size_y) + { + err = 1; + pinentry->specific_err = gpg_error (size_y < 0? GPG_ERR_MISSING_ENVVAR + /* */ : GPG_ERR_WINDOW_TOO_SMALL); + pinentry->specific_err_loc = "dialog_create"; + goto out; + } + + /* Check if all required columns fit on the screen. */ + x = 0; + if (description) + { + int new_x = description_x; + if (new_x > size_x - 4) + new_x = size_x - 4; + if (new_x > x) + x = new_x; + } + if (pinentry->pin) + { +#define MIN_PINENTRY_LENGTH 40 + int new_x; + + if (error) + { + new_x = error_x; + if (new_x > size_x - 4) + new_x = size_x - 4; + if (new_x > x) + x = new_x; + } + + new_x = MIN_PINENTRY_LENGTH; + if (prompt) + { + new_x += STRWIDTH (prompt) + 1; /* One space after prompt. */ + } + if (new_x > size_x - 4) + new_x = size_x - 4; + if (new_x > x) + x = new_x; + } + /* We position the buttons after the first, second and third fourth + of the width. Account for rounding. */ + if (x < 3 * strlen (dialog->ok)) + x = 3 * strlen (dialog->ok); + if (dialog->cancel) + if (x < 3 * strlen (dialog->cancel)) + x = 3 * strlen (dialog->cancel); + if (dialog->notok) + if (x < 3 * strlen (dialog->notok)) + x = 3 * strlen (dialog->notok); + + /* Add the frame. */ + x += 4; + + if (x > size_x) + { + err = 1; + pinentry->specific_err = gpg_error (size_x < 0? GPG_ERR_MISSING_ENVVAR + /* */ : GPG_ERR_WINDOW_TOO_SMALL); + pinentry->specific_err_loc = "dialog_create"; + goto out; + } + + dialog->pos = DIALOG_POS_NONE; + dialog->pin_max = pinentry->pin_len; + dialog->pin_loc = 0; + dialog->pin_len = 0; + ypos = (size_y - y) / 2; + xpos = (size_x - x) / 2; + move (ypos, xpos); + addch (ACS_ULCORNER); + hline (0, x - 2); + move (ypos, xpos + x - 1); + addch (ACS_URCORNER); + move (ypos + 1, xpos + x - 1); + vline (0, y - 2); + move (ypos + y - 1, xpos); + addch (ACS_LLCORNER); + hline (0, x - 2); + move (ypos + y - 1, xpos + x - 1); + addch (ACS_LRCORNER); + ypos++; + if (description) + { + CH *start = description; + int len = 0; + + do + { + int i; + + move (ypos, xpos); + addch (ACS_VLINE); + addch (' '); + collect_line (size_x - 4, &start, &len); + for (i = 0; i < len - 1; i++) + { + ADDCH (start[i]); + } + if (start[len - 1] != NULLCH && start[len - 1] != NLCH) + ADDCH (start[len - 1]); + ypos++; + } + while (start[len - 1]); + move (ypos, xpos); + addch (ACS_VLINE); + ypos++; + } + if (pinentry->pin) + { + int i; + + if (error) + { + CH *p = error; + i = 0; + + while (*p) + { + move (ypos, xpos); + addch (ACS_VLINE); + addch (' '); + if (USE_COLORS && pinentry->color_so != PINENTRY_COLOR_NONE) + { + attroff (COLOR_PAIR (1) | (pinentry->color_fg_bright ? A_BOLD : 0)); + attron (COLOR_PAIR (2) | (pinentry->color_so_bright ? A_BOLD : 0)); + } + else + standout (); + for (;*p && *p != NLCH; p++) + if (i < x - 4) + { + i++; + ADDCH (*p); + } + if (USE_COLORS && pinentry->color_so != PINENTRY_COLOR_NONE) + { + attroff (COLOR_PAIR (2) | (pinentry->color_so_bright ? A_BOLD : 0)); + attron (COLOR_PAIR (1) | (pinentry->color_fg_bright ? A_BOLD : 0)); + } + else + standend (); + if (*p == '\n') + p++; + i = 0; + ypos++; + } + move (ypos, xpos); + addch (ACS_VLINE); + ypos++; + } + + move (ypos, xpos); + addch (ACS_VLINE); + addch (' '); + + dialog->pin_y = ypos; + dialog->pin_x = xpos + 2; + dialog->pin_size = x - 4; + if (prompt) + { + CH *p = prompt; + i = STRWIDTH (prompt); + if (i > x - 4 - MIN_PINENTRY_LENGTH) + i = x - 4 - MIN_PINENTRY_LENGTH; + dialog->pin_x += i + 1; + dialog->pin_size -= i + 1; + i = STRLEN (prompt); + while (i-- > 0) + { + ADDCH (*(p++)); + } + addch (' '); + } + for (i = 0; i < dialog->pin_size; i++) + addch ('_'); + ypos++; + move (ypos, xpos); + addch (ACS_VLINE); + ypos++; + } + move (ypos, xpos); + addch (ACS_VLINE); + + if (dialog->cancel || dialog->notok) + { + dialog->ok_y = ypos; + /* Calculating the left edge of the left button, rounding down. */ + dialog->ok_x = xpos + 2 + ((x - 4) / 3 - strlen (dialog->ok)) / 2; + move (dialog->ok_y, dialog->ok_x); + addstr (dialog->ok); + + if (! pinentry->pin && dialog->notok) + { + dialog->notok_y = ypos; + /* Calculating the left edge of the middle button, rounding up. */ + dialog->notok_x = xpos + x / 2 - strlen (dialog->notok) / 2; + move (dialog->notok_y, dialog->notok_x); + addstr (dialog->notok); + } + if (dialog->cancel) + { + dialog->cancel_y = ypos; + /* Calculating the left edge of the right button, rounding up. */ + dialog->cancel_x = xpos + x - 2 - ((x - 4) / 3 + strlen (dialog->cancel)) / 2; + move (dialog->cancel_y, dialog->cancel_x); + addstr (dialog->cancel); + } + } + else + { + dialog->ok_y = ypos; + /* Calculating the left edge of the OK button, rounding down. */ + dialog->ok_x = xpos + x / 2 - strlen (dialog->ok) / 2; + move (dialog->ok_y, dialog->ok_x); + addstr (dialog->ok); + } + + dialog->got_input = 0; + dialog->no_echo = 0; + + out: + if (description) + free (description); + if (error) + free (error); + if (prompt) + free (prompt); + return err; +} + + +static void +set_cursor_state (int on) +{ + static int normal_state = -1; + static int on_last; + + if (normal_state < 0 && !on) + { + normal_state = curs_set (0); + on_last = on; + } + else if (on != on_last) + { + curs_set (on ? normal_state : 0); + on_last = on; + } +} + +static int +dialog_switch_pos (dialog_t diag, dialog_pos_t new_pos) +{ + if (new_pos != diag->pos) + { + switch (diag->pos) + { + case DIALOG_POS_OK: + move (diag->ok_y, diag->ok_x); + addstr (diag->ok); + break; + case DIALOG_POS_NOTOK: + if (diag->notok) + { + move (diag->notok_y, diag->notok_x); + addstr (diag->notok); + } + break; + case DIALOG_POS_CANCEL: + if (diag->cancel) + { + move (diag->cancel_y, diag->cancel_x); + addstr (diag->cancel); + } + break; + default: + break; + } + diag->pos = new_pos; + switch (diag->pos) + { + case DIALOG_POS_PIN: + move (diag->pin_y, diag->pin_x + diag->pin_loc); + set_cursor_state (1); + break; + case DIALOG_POS_OK: + set_cursor_state (0); + move (diag->ok_y, diag->ok_x); + standout (); + addstr (diag->ok); + standend (); + move (diag->ok_y, diag->ok_x); + break; + case DIALOG_POS_NOTOK: + if (diag->notok) + { + set_cursor_state (0); + move (diag->notok_y, diag->notok_x); + standout (); + addstr (diag->notok); + standend (); + move (diag->notok_y, diag->notok_x); + } + break; + case DIALOG_POS_CANCEL: + if (diag->cancel) + { + set_cursor_state (0); + move (diag->cancel_y, diag->cancel_x); + standout (); + addstr (diag->cancel); + standend (); + move (diag->cancel_y, diag->cancel_x); + } + break; + case DIALOG_POS_NONE: + set_cursor_state (0); + break; + } + refresh (); + } + return 0; +} + +/* XXX Assume that field width is at least > 5. */ +static void +dialog_input (dialog_t diag, int alt, int chr) +{ + int old_loc = diag->pin_loc; + assert (diag->pinentry->pin); + assert (diag->pos == DIALOG_POS_PIN); + + if (alt && chr == KEY_BACKSPACE) + /* Remap alt-backspace to control-W. */ + chr = 'w' - 'a' + 1; + + switch (chr) + { + case KEY_BACKSPACE: + /* control-h. */ + case 'h' - 'a' + 1: + /* ASCII DEL. What Mac OS X apparently emits when the "delete" + (backspace) key is pressed. */ + case 127: + if (diag->pin_len > 0) + { + diag->pin_len--; + diag->pin_loc--; + if (diag->pin_loc == 0 && diag->pin_len > 0) + { + diag->pin_loc = diag->pin_size - 5; + if (diag->pin_loc > diag->pin_len) + diag->pin_loc = diag->pin_len; + } + } + else if (!diag->got_input) + { + diag->no_echo = 1; + move (diag->pin_y, diag->pin_x); + addstr ("[no echo]"); + } + break; + + case 'l' - 'a' + 1: /* control-l */ + /* Refresh the screen. */ + endwin (); + refresh (); + break; + + case 'u' - 'a' + 1: /* control-u */ + /* Erase the whole line. */ + if (diag->pin_len > 0) + { + diag->pin_len = 0; + diag->pin_loc = 0; + } + break; + + case 'w' - 'a' + 1: /* control-w. */ + while (diag->pin_len > 0 + && diag->pinentry->pin[diag->pin_len - 1] == ' ') + { + diag->pin_len --; + diag->pin_loc --; + if (diag->pin_loc < 0) + { + diag->pin_loc += diag->pin_size; + if (diag->pin_loc > diag->pin_len) + diag->pin_loc = diag->pin_len; + } + } + while (diag->pin_len > 0 + && diag->pinentry->pin[diag->pin_len - 1] != ' ') + { + diag->pin_len --; + diag->pin_loc --; + if (diag->pin_loc < 0) + { + diag->pin_loc += diag->pin_size; + if (diag->pin_loc > diag->pin_len) + diag->pin_loc = diag->pin_len; + } + } + + break; + + default: + if (chr > 0 && chr < 256 && diag->pin_len < diag->pin_max) + { + /* Make sure there is enough room for this character and a + following NUL byte. */ + if (! pinentry_setbufferlen (diag->pinentry, diag->pin_len + 2)) + { + /* Bail. Here we use a simple approach. It would be + better to have a pinentry_bug function. */ + assert (!"setbufferlen failed"); + abort (); + } + + diag->pinentry->pin[diag->pin_len] = (char) chr; + diag->pin_len++; + diag->pin_loc++; + if (diag->pin_loc == diag->pin_size && diag->pin_len < diag->pin_max) + { + diag->pin_loc = 5; + if (diag->pin_loc < diag->pin_size - (diag->pin_max + 1 - diag->pin_len)) + diag->pin_loc = diag->pin_size - (diag->pin_max + 1 - diag->pin_len); + } + } + break; + } + + diag->got_input = 1; + + if (!diag->no_echo) + { + if (old_loc < diag->pin_loc) + { + move (diag->pin_y, diag->pin_x + old_loc); + while (old_loc++ < diag->pin_loc) + addch ('*'); + } + else if (old_loc > diag->pin_loc) + { + move (diag->pin_y, diag->pin_x + diag->pin_loc); + while (old_loc-- > diag->pin_loc) + addch ('_'); + } + move (diag->pin_y, diag->pin_x + diag->pin_loc); + } +} + +static int +dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type) +{ + int confirm_mode = !pinentry->pin; + struct dialog diag; + FILE *ttyfi = NULL; + FILE *ttyfo = NULL; + SCREEN *screen = 0; + int done = 0; + char *pin_utf8; + int alt = 0; +#ifndef HAVE_DOSISH_SYSTEM + int no_input = 1; +#endif + +#ifdef HAVE_NCURSESW + char *old_ctype = NULL; + + if (pinentry->lc_ctype) + { + old_ctype = strdup (setlocale (LC_CTYPE, NULL)); + setlocale (LC_CTYPE, pinentry->lc_ctype); + } + else + setlocale (LC_CTYPE, ""); +#endif + + /* Open the desired terminal if necessary. */ + if (tty_name) + { + ttyfi = fopen (tty_name, "r"); + if (!ttyfi) + { + pinentry->specific_err = gpg_error_from_syserror (); + pinentry->specific_err_loc = "open_tty_for_read"; +#ifdef HAVE_NCURSESW + free (old_ctype); +#endif + return confirm_mode? 0 : -1; + } + ttyfo = fopen (tty_name, "w"); + if (!ttyfo) + { + int err = errno; + fclose (ttyfi); + errno = err; + pinentry->specific_err = gpg_error_from_syserror (); + pinentry->specific_err_loc = "open_tty_for_write"; +#ifdef HAVE_NCURSESW + free (old_ctype); +#endif + return confirm_mode? 0 : -1; + } + screen = newterm (tty_type, ttyfo, ttyfi); + if (!screen) + { + pinentry->specific_err = gpg_error (GPG_ERR_WINDOW_TOO_SMALL); + pinentry->specific_err_loc = "curses_init"; + fclose (ttyfo); + fclose (ttyfi); +#ifdef HAVE_NCURSESW + free (old_ctype); +#endif + return confirm_mode? 0 : -1; + } + set_term (screen); + } + else + { + if (!init_screen) + { + if (!(isatty(fileno(stdin)) && isatty(fileno(stdout)))) + { + errno = ENOTTY; + pinentry->specific_err = gpg_error_from_syserror (); + pinentry->specific_err_loc = "isatty"; +#ifdef HAVE_NCURSESW + free (old_ctype); +#endif + return confirm_mode? 0 : -1; + } + init_screen = 1; + initscr (); + } + else + clear (); + } + + keypad (stdscr, TRUE); /* Enable keyboard mapping. */ + nonl (); /* Tell curses not to do NL->CR/NL on output. */ + cbreak (); /* Take input chars one at a time, no wait for \n. */ + noecho (); /* Don't echo input - in color. */ + + if (pinentry->ttyalert) + { + if (! strcmp(pinentry->ttyalert, "beep")) + beep (); + else if (! strcmp(pinentry->ttyalert, "flash")) + flash (); + } + + if (has_colors ()) + { + start_color (); + + /* Ncurses has use_default_colors, an extentions to the curses + library, which allows use of -1 to select default color. */ +#ifdef NCURSES_VERSION + use_default_colors (); +#else + /* With no extention, we need to specify color explicitly. */ + if (pinentry->color_fg == PINENTRY_COLOR_DEFAULT) + pinentry->color_fg = PINENTRY_COLOR_WHITE; + if (pinentry->color_bg == PINENTRY_COLOR_DEFAULT) + pinentry->color_bg = PINENTRY_COLOR_BLACK; +#endif + + if (pinentry->color_so == PINENTRY_COLOR_DEFAULT) + { + pinentry->color_so = PINENTRY_COLOR_RED; + pinentry->color_so_bright = 1; + } + if (COLOR_PAIRS >= 2) + { + init_pair (1, pinentry_color[pinentry->color_fg], + pinentry_color[pinentry->color_bg]); + init_pair (2, pinentry_color[pinentry->color_so], + pinentry_color[pinentry->color_bg]); + + bkgd (COLOR_PAIR (1)); + attron (COLOR_PAIR (1) | (pinentry->color_fg_bright ? A_BOLD : 0)); + } + } + refresh (); + + /* Create the dialog. */ + if (dialog_create (pinentry, &diag)) + { + /* Note: pinentry->specific_err has already been set. */ + endwin (); + if (screen) + delscreen (screen); + +#ifdef HAVE_NCURSESW + if (old_ctype) + { + setlocale (LC_CTYPE, old_ctype); + free (old_ctype); + } +#endif + if (ttyfi) + fclose (ttyfi); + if (ttyfo) + fclose (ttyfo); + return -2; + } + dialog_switch_pos (&diag, confirm_mode? DIALOG_POS_OK : DIALOG_POS_PIN); + +#ifndef HAVE_DOSISH_SYSTEM + wtimeout (stdscr, 70); +#endif + + do + { + int c; + + c = wgetch (stdscr); /* Refresh, accept single keystroke of input. */ +#ifndef HAVE_DOSISH_SYSTEM + if (timed_out && no_input) + { + done = -2; + pinentry->specific_err = gpg_error (GPG_ERR_TIMEOUT); + break; + } +#endif + + switch (c) + { + case ERR: +#ifndef HAVE_DOSISH_SYSTEM + continue; +#else + done = -2; + break; +#endif + + case 27: /* Alt was pressed. */ + alt = 1; + /* Get the next key press. */ + continue; + + case KEY_LEFT: + case KEY_UP: + switch (diag.pos) + { + case DIALOG_POS_OK: + if (!confirm_mode) + dialog_switch_pos (&diag, DIALOG_POS_PIN); + break; + case DIALOG_POS_NOTOK: + dialog_switch_pos (&diag, DIALOG_POS_OK); + break; + case DIALOG_POS_CANCEL: + if (diag.notok) + dialog_switch_pos (&diag, DIALOG_POS_NOTOK); + else + dialog_switch_pos (&diag, DIALOG_POS_OK); + break; + default: + break; + } + break; + + case KEY_RIGHT: + case KEY_DOWN: + switch (diag.pos) + { + case DIALOG_POS_PIN: + dialog_switch_pos (&diag, DIALOG_POS_OK); + break; + case DIALOG_POS_OK: + if (diag.notok) + dialog_switch_pos (&diag, DIALOG_POS_NOTOK); + else + dialog_switch_pos (&diag, DIALOG_POS_CANCEL); + break; + case DIALOG_POS_NOTOK: + dialog_switch_pos (&diag, DIALOG_POS_CANCEL); + break; + default: + break; + } + break; + + case '\t': + switch (diag.pos) + { + case DIALOG_POS_PIN: + dialog_switch_pos (&diag, DIALOG_POS_OK); + break; + case DIALOG_POS_OK: + if (diag.notok) + dialog_switch_pos (&diag, DIALOG_POS_NOTOK); + else + dialog_switch_pos (&diag, DIALOG_POS_CANCEL); + break; + case DIALOG_POS_NOTOK: + dialog_switch_pos (&diag, DIALOG_POS_CANCEL); + break; + case DIALOG_POS_CANCEL: + if (confirm_mode) + dialog_switch_pos (&diag, DIALOG_POS_OK); + else + dialog_switch_pos (&diag, DIALOG_POS_PIN); + break; + default: + break; + } + break; + + case '\005': + done = -2; + break; + + case '\r': + switch (diag.pos) + { + case DIALOG_POS_PIN: + case DIALOG_POS_OK: + done = 1; + break; + case DIALOG_POS_NOTOK: + done = -1; + break; + case DIALOG_POS_CANCEL: + done = -2; + break; + case DIALOG_POS_NONE: + break; + } + break; + + default: + if (diag.pos == DIALOG_POS_PIN) + dialog_input (&diag, alt, c); + } +#ifndef HAVE_DOSISH_SYSTEM + no_input = 0; +#endif + if (c != -1) + alt = 0; + } + while (!done); + + if (!confirm_mode) + { + /* NUL terminate the passphrase. dialog_run makes sure there is + enough space for the terminating NUL byte. */ + diag.pinentry->pin[diag.pin_len] = 0; + } + + set_cursor_state (1); + endwin (); + if (screen) + delscreen (screen); + +#ifdef HAVE_NCURSESW + if (old_ctype) + { + setlocale (LC_CTYPE, old_ctype); + free (old_ctype); + } +#endif + if (ttyfi) + fclose (ttyfi); + if (ttyfo) + fclose (ttyfo); + /* XXX Factor out into dialog_release or something. */ + free (diag.ok); + if (diag.cancel) + free (diag.cancel); + if (diag.notok) + free (diag.notok); + + if (!confirm_mode) + { + pinentry->locale_err = 1; + pin_utf8 = pinentry_local_to_utf8 (pinentry->lc_ctype, pinentry->pin, 1); + if (pin_utf8) + { + pinentry_setbufferlen (pinentry, strlen (pin_utf8) + 1); + if (pinentry->pin) + strcpy (pinentry->pin, pin_utf8); + secmem_free (pin_utf8); + pinentry->locale_err = 0; + } + } + + if (done == -2) + pinentry->canceled = 1; + + /* In confirm mode return cancel instead of error. */ + if (confirm_mode) + return done < 0 ? 0 : 1; + + return done < 0 ? -1 : diag.pin_len; +} + + +/* If a touch has been registered, touch that file. */ +static void +do_touch_file (pinentry_t pinentry) +{ +#ifdef HAVE_UTIME_H + struct stat st; + time_t tim; + + if (!pinentry->touch_file || !*pinentry->touch_file) + return; + + if (stat (pinentry->touch_file, &st)) + return; /* Oops. */ + + /* Make sure that we actually update the mtime. */ + while ( (tim = time (NULL)) == st.st_mtime ) + sleep (1); + + /* Update but ignore errors as we can't do anything in that case. + Printing error messages may even clubber the display further. */ + utime (pinentry->touch_file, NULL); +#endif /*HAVE_UTIME_H*/ +} + +#ifndef HAVE_DOSISH_SYSTEM +static void +catchsig (int sig) +{ + if (sig == SIGALRM) + timed_out = 1; +} +#endif + +int +curses_cmd_handler (pinentry_t pinentry) +{ + int rc; + +#ifndef HAVE_DOSISH_SYSTEM + timed_out = 0; + + if (pinentry->timeout) + { + struct sigaction sa; + + memset (&sa, 0, sizeof(sa)); + sa.sa_handler = catchsig; + sigaction (SIGALRM, &sa, NULL); + alarm (pinentry->timeout); + } +#endif + + rc = dialog_run (pinentry, pinentry->ttyname, pinentry->ttytype_l); + do_touch_file (pinentry); + return rc; +} diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry-curses.h b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry-curses.h new file mode 100644 index 00000000..b33f1349 --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry-curses.h @@ -0,0 +1,35 @@ +/* pinentry-curses.h - A secure curses dialog for PIN entry, library version + * Copyright (C) 2002 g10 Code GmbH + * + * This file is part of PINENTRY. + * + * PINENTRY is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * PINENTRY is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef PINENTRY_CURSES_H +#define PINENTRY_CURSES_H + +#include "pinentry.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int curses_cmd_handler (pinentry_t pinentry); + +#ifdef __cplusplus +} +#endif + +#endif /* PINENTRY_CURSES_H */ diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry-emacs.c b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry-emacs.c new file mode 100644 index 00000000..9685b67d --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry-emacs.c @@ -0,0 +1,721 @@ +/* pinentry-emacs.c - A secure emacs dialog for PIN entry, library version + * Copyright (C) 2015 Daiki Ueno + * + * This file is part of PINENTRY. + * + * PINENTRY is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * PINENTRY is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif +#include <assert.h> +#include <signal.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <limits.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> +#ifdef HAVE_UTIME_H +#include <utime.h> +#endif /*HAVE_UTIME_H*/ + +#include <assuan.h> + +#include "pinentry-emacs.h" +#include "memory.h" +#include "secmem-util.h" + +/* The communication mechanism is similar to emacsclient, but there + are a few differences: + + - To avoid unnecessary character escaping and encoding conversion, + we use a subset of the Pinentry Assuan protocol, instead of the + emacsclient protocol. + + - We only use a Unix domain socket, while emacsclient has an + ability to use a TCP socket. The socket file is located at + ${TMPDIR-/tmp}/emacs$(id -u)/pinentry (i.e., under the same + directory as the socket file used by emacsclient, so the same + permission and file owner settings apply). + + - The server implementation can be found in pinentry.el, which is + available in Emacs 25+ or from ELPA. */ + +#define LINELENGTH ASSUAN_LINELENGTH +#define SEND_BUFFER_SIZE 4096 +#define INITIAL_TIMEOUT 60 + +static int initial_timeout = INITIAL_TIMEOUT; + +#undef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +#undef MAX +#define MAX(x, y) ((x) < (y) ? (y) : (x)) + +#ifndef SUN_LEN +# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \ + + strlen ((ptr)->sun_path)) +#endif + +/* FIXME: We could use the I/O functions in Assuan directly, once + Pinentry links to libassuan. */ +static int emacs_socket = -1; +static char send_buffer[SEND_BUFFER_SIZE + 1]; +static int send_buffer_length; /* Fill pointer for the send buffer. */ + +static pinentry_cmd_handler_t fallback_cmd_handler; + +#ifndef HAVE_DOSISH_SYSTEM +static int timed_out; +#endif + +static int +set_socket (const char *socket_name) +{ + struct sockaddr_un unaddr; + struct stat statbuf; + const char *tmpdir; + char *tmpdir_storage = NULL; + char *socket_name_storage = NULL; + uid_t uid; + + unaddr.sun_family = AF_UNIX; + + /* We assume 32-bit UIDs, which can be represented with 10 decimal + digits. */ + uid = getuid (); + if (uid != (uint32_t) uid) + { + fprintf (stderr, "UID is too large\n"); + return 0; + } + + tmpdir = getenv ("TMPDIR"); + if (!tmpdir) + { +#ifdef _CS_DARWIN_USER_TEMP_DIR + size_t n = confstr (_CS_DARWIN_USER_TEMP_DIR, NULL, (size_t) 0); + if (n > 0) + { + tmpdir = tmpdir_storage = malloc (n); + if (!tmpdir) + { + fprintf (stderr, "out of core\n"); + return 0; + } + confstr (_CS_DARWIN_USER_TEMP_DIR, tmpdir_storage, n); + } + else +#endif + tmpdir = "/tmp"; + } + + socket_name_storage = malloc (strlen (tmpdir) + + strlen ("/emacs") + 10 + strlen ("/") + + strlen (socket_name) + + 1); + if (!socket_name_storage) + { + fprintf (stderr, "out of core\n"); + free (tmpdir_storage); + return 0; + } + + sprintf (socket_name_storage, "%s/emacs%u/%s", tmpdir, + (uint32_t) uid, socket_name); + free (tmpdir_storage); + + if (strlen (socket_name_storage) >= sizeof (unaddr.sun_path)) + { + fprintf (stderr, "socket name is too long\n"); + free (socket_name_storage); + return 0; + } + + strcpy (unaddr.sun_path, socket_name_storage); + free (socket_name_storage); + + /* See if the socket exists, and if it's owned by us. */ + if (stat (unaddr.sun_path, &statbuf) == -1) + { + perror ("stat"); + return 0; + } + + if (statbuf.st_uid != geteuid ()) + { + fprintf (stderr, "socket is not owned by the same user\n"); + return 0; + } + + emacs_socket = socket (AF_UNIX, SOCK_STREAM, 0); + if (emacs_socket < 0) + { + perror ("socket"); + return 0; + } + + if (connect (emacs_socket, (struct sockaddr *) &unaddr, + SUN_LEN (&unaddr)) < 0) + { + perror ("connect"); + close (emacs_socket); + emacs_socket = -1; + return 0; + } + + return 1; +} + +/* Percent-escape control characters in DATA. Return a newly + allocated string. */ +static char * +escape (const char *data) +{ + char *buffer, *out_p; + size_t length, buffer_length; + size_t offset; + size_t count = 0; + + length = strlen (data); + for (offset = 0; offset < length; offset++) + { + switch (data[offset]) + { + case '%': case '\n': case '\r': + count++; + break; + default: + break; + } + } + + buffer_length = length + count * 2; + buffer = malloc (buffer_length + 1); + if (!buffer) + return NULL; + + out_p = buffer; + for (offset = 0; offset < length; offset++) + { + int c = data[offset]; + switch (c) + { + case '%': case '\n': case '\r': + sprintf (out_p, "%%%02X", c); + out_p += 3; + break; + default: + *out_p++ = c; + break; + } + } + *out_p = '\0'; + + return buffer; +} + +/* The inverse of escape. Unlike escape, it removes quoting in string + DATA by modifying the string in place, to avoid copying of secret + data sent from Emacs. */ +static char * +unescape (char *data) +{ + char *p = data, *q = data; + + while (*p) + { + if (*p == '%' && p[1] && p[2]) + { + p++; + *q++ = xtoi_2 (p); + p += 2; + } + else + *q++ = *p++; + } + *q = 0; + return data; +} + +/* Let's send the data to Emacs when either + - the data ends in "\n", or + - the buffer is full (but this shouldn't happen) + Otherwise, we just accumulate it. */ +static int +send_to_emacs (int s, const char *buffer) +{ + size_t length; + + length = strlen (buffer); + while (*buffer) + { + size_t part = MIN (length, SEND_BUFFER_SIZE - send_buffer_length); + memcpy (&send_buffer[send_buffer_length], buffer, part); + buffer += part; + send_buffer_length += part; + + if (send_buffer_length == SEND_BUFFER_SIZE + || (send_buffer_length > 0 + && send_buffer[send_buffer_length-1] == '\n')) + { + int sent = send (s, send_buffer, send_buffer_length, 0); + if (sent < 0) + { + fprintf (stderr, "failed to send %d bytes to socket: %s\n", + send_buffer_length, strerror (errno)); + send_buffer_length = 0; + return 0; + } + if (sent != send_buffer_length) + memmove (send_buffer, &send_buffer[sent], + send_buffer_length - sent); + send_buffer_length -= sent; + } + + length -= part; + } + + return 1; +} + +/* Read a server response. If the response contains data, it will be + stored in BUFFER with a terminating NUL byte. BUFFER must be + at least as large as CAPACITY. */ +static gpg_error_t +read_from_emacs (int s, int timeout, char *buffer, size_t capacity) +{ + struct timeval tv; + fd_set rfds; + int retval; + /* Offset in BUFFER. */ + size_t offset = 0; + int got_response = 0; + char read_buffer[LINELENGTH + 1]; + /* Offset in READ_BUFFER. */ + size_t read_offset = 0; + gpg_error_t result = 0; + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + FD_ZERO (&rfds); + FD_SET (s, &rfds); + retval = select (s + 1, &rfds, NULL, NULL, &tv); + if (retval == -1) + { + perror ("select"); + return gpg_error (GPG_ERR_ASS_GENERAL); + } + else if (retval == 0) + { + timed_out = 1; + return gpg_error (GPG_ERR_TIMEOUT); + } + + /* Loop until we get either OK or ERR. */ + while (!got_response) + { + int rl = 0; + char *p, *end_p; + do + { + errno = 0; + rl = recv (s, read_buffer + read_offset, LINELENGTH - read_offset, 0); + } + /* If we receive a signal (e.g. SIGWINCH, which we pass + through to Emacs), on some OSes we get EINTR and must retry. */ + while (rl < 0 && errno == EINTR); + + if (rl < 0) + { + perror ("recv"); + return gpg_error (GPG_ERR_ASS_GENERAL);; + } + if (rl == 0) + break; + + read_offset += rl; + read_buffer[read_offset] = '\0'; + + end_p = strchr (read_buffer, '\n'); + + /* If the buffer is filled without NL, throw away the content + and start over the buffering. + + FIXME: We could return ASSUAN_Line_Too_Long or + ASSUAN_Line_Not_Terminated here. */ + if (!end_p && read_offset == sizeof (read_buffer) - 1) + { + read_offset = 0; + continue; + } + + /* Loop over all NL-terminated messages. */ + for (p = read_buffer; end_p; p = end_p + 1, end_p = strchr (p, '\n')) + { + *end_p = '\0'; + if (!strncmp ("D ", p, 2)) + { + char *data; + size_t data_length; + size_t needed_capacity; + + data = p + 2; + data_length = end_p - data; + if (data_length > 0) + { + needed_capacity = offset + data_length + 1; + + /* Check overflow. This is unrealistic but can + happen since OFFSET is cumulative. */ + if (needed_capacity < offset) + return gpg_error (GPG_ERR_ASS_GENERAL);; + + if (needed_capacity > capacity) + return gpg_error (GPG_ERR_ASS_GENERAL);; + + memcpy (&buffer[offset], data, data_length); + offset += data_length; + buffer[offset] = 0; + } + } + else if (!strcmp ("OK", p) || !strncmp ("OK ", p, 3)) + { + got_response = 1; + break; + } + else if (!strncmp ("ERR ", p, 4)) + { + unsigned long code = strtoul (p + 4, NULL, 10); + if (code == ULONG_MAX && errno == ERANGE) + return gpg_error (GPG_ERR_ASS_GENERAL); + else + result = code; + got_response = 1; + break; + } + else if (*p == '#') + ; + else + fprintf (stderr, "invalid response: %s\n", p); + } + + if (!got_response) + { + size_t length = &read_buffer[read_offset] - p; + memmove (read_buffer, p, length); + read_offset = length; + } + } + + return result; +} + +int +set_label (pinentry_t pe, const char *name, const char *value) +{ + char buffer[16], *escaped; + gpg_error_t error; + int retval; + + if (!send_to_emacs (emacs_socket, name) + || !send_to_emacs (emacs_socket, " ")) + return 0; + + escaped = escape (value); + if (!escaped) + return 0; + + retval = send_to_emacs (emacs_socket, escaped) + && send_to_emacs (emacs_socket, "\n"); + + free (escaped); + if (!retval) + return 0; + + error = read_from_emacs (emacs_socket, pe->timeout, buffer, sizeof (buffer)); + return error == 0; +} + +static void +set_labels (pinentry_t pe) +{ + char *p; + + p = pinentry_get_title (pe); + if (p) + { + set_label (pe, "SETTITLE", p); + free (p); + } + if (pe->description) + set_label (pe, "SETDESC", pe->description); + if (pe->error) + set_label (pe, "SETERROR", pe->error); + if (pe->prompt) + set_label (pe, "SETPROMPT", pe->prompt); + else if (pe->default_prompt) + set_label (pe, "SETPROMPT", pe->default_prompt); + if (pe->repeat_passphrase) + set_label (pe, "SETREPEAT", pe->repeat_passphrase); + if (pe->repeat_error_string) + set_label (pe, "SETREPEATERROR", pe->repeat_error_string); + + /* XXX: pe->quality_bar and pe->quality_bar_tt are not supported. */ + + /* Buttons. */ + if (pe->ok) + set_label (pe, "SETOK", pe->ok); + else if (pe->default_ok) + set_label (pe, "SETOK", pe->default_ok); + if (pe->cancel) + set_label (pe, "SETCANCEL", pe->cancel); + else if (pe->default_cancel) + set_label (pe, "SETCANCEL", pe->default_cancel); + if (pe->notok) + set_label (pe, "SETNOTOK", pe->notok); +} + +static int +do_password (pinentry_t pe) +{ + char *buffer, *password; + size_t length = LINELENGTH; + gpg_error_t error; + + set_labels (pe); + + if (!send_to_emacs (emacs_socket, "GETPIN\n")) + return -1; + + buffer = secmem_malloc (length); + if (!buffer) + { + pe->specific_err = gpg_error (GPG_ERR_ENOMEM); + return -1; + } + + error = read_from_emacs (emacs_socket, pe->timeout, buffer, length); + if (error != 0) + { + if (gpg_err_code (error) == GPG_ERR_CANCELED) + pe->canceled = 1; + + secmem_free (buffer); + pe->specific_err = error; + return -1; + } + + password = unescape (buffer); + pinentry_setbufferlen (pe, strlen (password) + 1); + if (pe->pin) + strcpy (pe->pin, password); + secmem_free (buffer); + + if (pe->repeat_passphrase) + pe->repeat_okay = 1; + + /* XXX: we don't support external password cache (yet). */ + + return 1; +} + +static int +do_confirm (pinentry_t pe) +{ + char buffer[16]; + gpg_error_t error; + + set_labels (pe); + + if (!send_to_emacs (emacs_socket, "CONFIRM\n")) + return 0; + + error = read_from_emacs (emacs_socket, pe->timeout, buffer, sizeof (buffer)); + if (error != 0) + { + if (gpg_err_code (error) == GPG_ERR_CANCELED) + pe->canceled = 1; + + pe->specific_err = error; + return 0; + } + + return 1; +} + +/* If a touch has been registered, touch that file. */ +static void +do_touch_file (pinentry_t pinentry) +{ +#ifdef HAVE_UTIME_H + struct stat st; + time_t tim; + + if (!pinentry->touch_file || !*pinentry->touch_file) + return; + + if (stat (pinentry->touch_file, &st)) + return; /* Oops. */ + + /* Make sure that we actually update the mtime. */ + while ( (tim = time (NULL)) == st.st_mtime ) + sleep (1); + + /* Update but ignore errors as we can't do anything in that case. + Printing error messages may even clubber the display further. */ + utime (pinentry->touch_file, NULL); +#endif /*HAVE_UTIME_H*/ +} + +#ifndef HAVE_DOSISH_SYSTEM +static void +catchsig (int sig) +{ + if (sig == SIGALRM) + timed_out = 1; +} +#endif + +int +emacs_cmd_handler (pinentry_t pe) +{ + int rc; + +#ifndef HAVE_DOSISH_SYSTEM + timed_out = 0; + + if (pe->timeout) + { + struct sigaction sa; + + memset (&sa, 0, sizeof(sa)); + sa.sa_handler = catchsig; + sigaction (SIGALRM, &sa, NULL); + alarm (pe->timeout); + } +#endif + + if (pe->pin) + rc = do_password (pe); + else + rc = do_confirm (pe); + + do_touch_file (pe); + return rc; +} + +static int +initial_emacs_cmd_handler (pinentry_t pe) +{ + /* Let the select() call in pinentry_emacs_init honor the timeout + value set through an Assuan option. */ + initial_timeout = pe->timeout; + + if (emacs_socket < 0) + pinentry_emacs_init (); + + /* If we have successfully connected to Emacs, swap + pinentry_cmd_handler to emacs_cmd_handler, so further + interactions will be forwarded to Emacs. Otherwise, set it back + to the original command handler saved as + fallback_cmd_handler. */ + if (emacs_socket < 0) + pinentry_cmd_handler = fallback_cmd_handler; + else + { + pinentry_cmd_handler = emacs_cmd_handler; + pinentry_set_flavor_flag ("emacs"); + } + + return (* pinentry_cmd_handler) (pe); +} + +void +pinentry_enable_emacs_cmd_handler (void) +{ + const char *envvar; + + /* Check if pinentry_cmd_handler is already prepared for Emacs. */ + if (pinentry_cmd_handler == initial_emacs_cmd_handler + || pinentry_cmd_handler == emacs_cmd_handler) + return; + + /* Check if INSIDE_EMACS envvar is set. */ + envvar = getenv ("INSIDE_EMACS"); + if (!envvar || !*envvar) + return; + + /* Save the original command handler as fallback_cmd_handler, and + swap pinentry_cmd_handler to initial_emacs_cmd_handler. */ + fallback_cmd_handler = pinentry_cmd_handler; + pinentry_cmd_handler = initial_emacs_cmd_handler; +} + + +/* Returns true if the Emacs pinentry is enabled. The value is 1 + * before the first connection with Emacs has been done and 2 if the + * connection to Emacs has been establish. Returns false if the Emacs + * pinentry is not enabled. */ +int +pinentry_emacs_status (void) +{ + if (pinentry_cmd_handler == initial_emacs_cmd_handler) + return 1; + else if (pinentry_cmd_handler == emacs_cmd_handler) + return 2; + else + return 0; +} + +int +pinentry_emacs_init (void) +{ + char buffer[256]; + gpg_error_t error; + + assert (emacs_socket < 0); + + /* Check if we can connect to the Emacs server socket. */ + if (!set_socket ("pinentry")) + return 0; + + /* Check if the server responds. */ + error = read_from_emacs (emacs_socket, initial_timeout, + buffer, sizeof (buffer)); + if (error != 0) + { + close (emacs_socket); + emacs_socket = -1; + return 0; + } + return 1; +} diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry-emacs.h b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry-emacs.h new file mode 100644 index 00000000..b05d53bc --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry-emacs.h @@ -0,0 +1,47 @@ +/* pinentry-emacs.c - A secure emacs dialog for PIN entry, library version + * Copyright (C) 2015 Daiki Ueno + * + * This file is part of PINENTRY. + * + * PINENTRY is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * PINENTRY is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef PINENTRY_EMACS_H +#define PINENTRY_EMACS_H + +#include "pinentry.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Enable pinentry command handler which interacts with Emacs, if + INSIDE_EMACS envvar is set. This function shall be called upon + receiving an Assuan request "OPTION allow-emacs-prompt". */ +void pinentry_enable_emacs_cmd_handler (void); + +/* Return info on whether emacs support is enabled. */ +int pinentry_emacs_status (void); + +/* Initialize the Emacs interface, return true if success. */ +int pinentry_emacs_init (void); + +int emacs_cmd_handler (pinentry_t pinentry); + +#ifdef __cplusplus +} +#endif + +#endif /* PINENTRY_EMACS_H */ diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry.c b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry.c new file mode 100644 index 00000000..ea11b67f --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry.c @@ -0,0 +1,2067 @@ +/* pinentry.c - The PIN entry support library + * Copyright (C) 2002, 2003, 2007, 2008, 2010, 2015, 2016, 2021 g10 Code GmbH + * + * This file is part of PINENTRY. + * + * PINENTRY is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * PINENTRY is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifndef HAVE_W32CE_SYSTEM +# include <errno.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <assert.h> +#ifndef HAVE_W32_SYSTEM +# include <sys/utsname.h> +#endif +#ifndef HAVE_W32CE_SYSTEM +# include <locale.h> +#endif +#include <limits.h> +#ifdef HAVE_W32CE_SYSTEM +# include <windows.h> +#endif + +#include <assuan.h> + +#include "memory.h" +#include "secmem-util.h" +#include "argparse.h" +#include "pinentry.h" +#include "password-cache.h" + +#ifdef INSIDE_EMACS +# include "pinentry-emacs.h" +#endif +#ifdef FALLBACK_CURSES +# include "pinentry-curses.h" +#endif + +#ifdef HAVE_W32CE_SYSTEM +#define getpid() GetCurrentProcessId () +#endif + +/* Keep the name of our program here. */ +static char this_pgmname[50]; + +struct pinentry pinentry; + + +static const char *flavor_flag; + +/* Because gtk_init removes the --display arg from the command lines + * and our command line parser is called after gtk_init (so that it + * does not see gtk specific options) we don't have a way to get hold + * of the --display option. Our solution is to remember --display in + * the call to pinentry_have_display and set it then in our + * parser. */ +static char *remember_display; + +static void +pinentry_reset (int use_defaults) +{ + /* GPG Agent sets these options once when it starts the pinentry. + Don't reset them. */ + int grab = pinentry.grab; + char *ttyname = pinentry.ttyname; + char *ttytype = pinentry.ttytype_l; + char *ttyalert = pinentry.ttyalert; + char *lc_ctype = pinentry.lc_ctype; + char *lc_messages = pinentry.lc_messages; + int allow_external_password_cache = pinentry.allow_external_password_cache; + char *default_ok = pinentry.default_ok; + char *default_cancel = pinentry.default_cancel; + char *default_prompt = pinentry.default_prompt; + char *default_pwmngr = pinentry.default_pwmngr; + char *default_cf_visi = pinentry.default_cf_visi; + char *default_tt_visi = pinentry.default_tt_visi; + char *default_tt_hide = pinentry.default_tt_hide; + char *default_capshint = pinentry.default_capshint; + char *touch_file = pinentry.touch_file; + unsigned long owner_pid = pinentry.owner_pid; + int owner_uid = pinentry.owner_uid; + char *owner_host = pinentry.owner_host; + int constraints_enforce = pinentry.constraints_enforce; + char *constraints_hint_short = pinentry.constraints_hint_short; + char *constraints_hint_long = pinentry.constraints_hint_long; + char *constraints_error_title = pinentry.constraints_error_title; + + /* These options are set from the command line. Don't reset + them. */ + int debug = pinentry.debug; + char *display = pinentry.display; + int parent_wid = pinentry.parent_wid; + + pinentry_color_t color_fg = pinentry.color_fg; + int color_fg_bright = pinentry.color_fg_bright; + pinentry_color_t color_bg = pinentry.color_bg; + pinentry_color_t color_so = pinentry.color_so; + int color_so_bright = pinentry.color_so_bright; + + int timeout = pinentry.timeout; + + char *invisible_char = pinentry.invisible_char; + + + /* Free any allocated memory. */ + if (use_defaults) + { + free (pinentry.ttyname); + free (pinentry.ttytype_l); + free (pinentry.ttyalert); + free (pinentry.lc_ctype); + free (pinentry.lc_messages); + free (pinentry.default_ok); + free (pinentry.default_cancel); + free (pinentry.default_prompt); + free (pinentry.default_pwmngr); + free (pinentry.default_cf_visi); + free (pinentry.default_tt_visi); + free (pinentry.default_tt_hide); + free (pinentry.default_capshint); + free (pinentry.touch_file); + free (pinentry.owner_host); + free (pinentry.display); + free (pinentry.constraints_hint_short); + free (pinentry.constraints_hint_long); + free (pinentry.constraints_error_title); + } + + free (pinentry.title); + free (pinentry.description); + free (pinentry.error); + free (pinentry.prompt); + free (pinentry.ok); + free (pinentry.notok); + free (pinentry.cancel); + secmem_free (pinentry.pin); + free (pinentry.repeat_passphrase); + free (pinentry.repeat_error_string); + free (pinentry.quality_bar); + free (pinentry.quality_bar_tt); + free (pinentry.formatted_passphrase_hint); + free (pinentry.keyinfo); + free (pinentry.specific_err_info); + + /* Reset the pinentry structure. */ + memset (&pinentry, 0, sizeof (pinentry)); + + /* Restore options without a default we want to preserve. */ + pinentry.invisible_char = invisible_char; + + /* Restore other options or set defaults. */ + + if (use_defaults) + { + /* Pinentry timeout in seconds. */ + pinentry.timeout = 60; + + /* Global grab. */ + pinentry.grab = 1; + + pinentry.color_fg = PINENTRY_COLOR_DEFAULT; + pinentry.color_fg_bright = 0; + pinentry.color_bg = PINENTRY_COLOR_DEFAULT; + pinentry.color_so = PINENTRY_COLOR_DEFAULT; + pinentry.color_so_bright = 0; + + pinentry.owner_uid = -1; + } + else /* Restore the options. */ + { + pinentry.grab = grab; + pinentry.ttyname = ttyname; + pinentry.ttytype_l = ttytype; + pinentry.ttyalert = ttyalert; + pinentry.lc_ctype = lc_ctype; + pinentry.lc_messages = lc_messages; + pinentry.allow_external_password_cache = allow_external_password_cache; + pinentry.default_ok = default_ok; + pinentry.default_cancel = default_cancel; + pinentry.default_prompt = default_prompt; + pinentry.default_pwmngr = default_pwmngr; + pinentry.default_cf_visi = default_cf_visi; + pinentry.default_tt_visi = default_tt_visi; + pinentry.default_tt_hide = default_tt_hide; + pinentry.default_capshint = default_capshint; + pinentry.touch_file = touch_file; + pinentry.owner_pid = owner_pid; + pinentry.owner_uid = owner_uid; + pinentry.owner_host = owner_host; + pinentry.constraints_enforce = constraints_enforce; + pinentry.constraints_hint_short = constraints_hint_short; + pinentry.constraints_hint_long = constraints_hint_long; + pinentry.constraints_error_title = constraints_error_title; + + pinentry.debug = debug; + pinentry.display = display; + pinentry.parent_wid = parent_wid; + + pinentry.color_fg = color_fg; + pinentry.color_fg_bright = color_fg_bright; + pinentry.color_bg = color_bg; + pinentry.color_so = color_so; + pinentry.color_so_bright = color_so_bright; + + pinentry.timeout = timeout; + } +} + +static gpg_error_t +pinentry_assuan_reset_handler (assuan_context_t ctx, char *line) +{ + (void)ctx; + (void)line; + + pinentry_reset (0); + + return 0; +} + + + +/* Copy TEXT or TEXTLEN to BUFFER and escape as required. Return a + pointer to the end of the new buffer. Note that BUFFER must be + large enough to keep the entire text; allocataing it 3 times of + TEXTLEN is sufficient. */ +static char * +copy_and_escape (char *buffer, const void *text, size_t textlen) +{ + int i; + const unsigned char *s = (unsigned char *)text; + char *p = buffer; + + for (i=0; i < textlen; i++) + { + if (s[i] < ' ' || s[i] == '+') + { + snprintf (p, 4, "%%%02X", s[i]); + p += 3; + } + else if (s[i] == ' ') + *p++ = '+'; + else + *p++ = s[i]; + } + return p; +} + + +/* Perform percent unescaping in STRING and return the new valid length + of the string. A terminating Nul character is inserted at the end of + the unescaped string. + */ +static size_t +do_unescape_inplace (char *s) +{ + unsigned char *p, *p0; + + p = p0 = s; + while (*s) + { + if (*s == '%' && s[1] && s[2]) + { + s++; + *p++ = xtoi_2 (s); + s += 2; + } + else + *p++ = *s++; + } + *p = 0; + + return (p - p0); +} + + +/* Return a malloced copy of the commandline for PID. If this is not + * possible NULL is returned. */ +#ifndef HAVE_W32_SYSTEM +static char * +get_cmdline (unsigned long pid) +{ + char buffer[200]; + FILE *fp; + size_t i, n; + + snprintf (buffer, sizeof buffer, "/proc/%lu/cmdline", pid); + + fp = fopen (buffer, "rb"); + if (!fp) + return NULL; + n = fread (buffer, 1, sizeof buffer - 1, fp); + if (n < sizeof buffer -1 && ferror (fp)) + { + /* Some error occurred. */ + fclose (fp); + return NULL; + } + fclose (fp); + if (n == 0) + return NULL; + /* Arguments are delimited by Nuls. We should do proper quoting but + * that can be a bit complicated, thus we simply replace the Nuls by + * spaces. */ + for (i=0; i < n; i++) + if (!buffer[i] && i < n-1) + buffer[i] = ' '; + buffer[i] = 0; /* Make sure the last byte is the string terminator. */ + + return strdup (buffer); +} +#endif /*!HAVE_W32_SYSTEM*/ + + +/* Atomically ask the kernel for information about process PID. + * Return a malloc'ed copy of the process name as long as the process + * uid matches UID. If it cannot determine that the process has uid + * UID, it returns NULL. + * + * This is not as informative as get_cmdline, but it verifies that the + * process does belong to the user in question. + */ +#ifndef HAVE_W32_SYSTEM +static char * +get_pid_name_for_uid (unsigned long pid, int uid) +{ + char buffer[400]; + FILE *fp; + size_t end, n; + char *uidstr; + + snprintf (buffer, sizeof buffer, "/proc/%lu/status", pid); + + fp = fopen (buffer, "rb"); + if (!fp) + return NULL; + n = fread (buffer, 1, sizeof buffer - 1, fp); + if (n < sizeof buffer -1 && ferror (fp)) + { + /* Some error occurred. */ + fclose (fp); + return NULL; + } + fclose (fp); + if (n == 0) + return NULL; + buffer[n] = 0; + /* Fixme: Is it specified that "Name" is always the first line? For + * robustness I would prefer to have a real parser here. -wk */ + if (strncmp (buffer, "Name:\t", 6)) + return NULL; + end = strcspn (buffer + 6, "\n") + 6; + buffer[end] = 0; + + /* check that uid matches what we expect */ + uidstr = strstr (buffer + end + 1, "\nUid:\t"); + if (!uidstr) + return NULL; + if (atoi (uidstr + 6) != uid) + return NULL; + + return strdup (buffer + 6); +} +#endif /*!HAVE_W32_SYSTEM*/ + + +const char * +pinentry_get_pgmname (void) +{ + return this_pgmname; +} + + +/* Return a malloced string with the title. The caller mus free the + * string. If no title is available or the title string has an error + * NULL is returned. */ +char * +pinentry_get_title (pinentry_t pe) +{ + char *title; + + if (pe->title) + title = strdup (pe->title); +#ifndef HAVE_W32_SYSTEM + else if (pe->owner_pid) + { + char buf[200]; + struct utsname utsbuf; + char *pidname = NULL; + char *cmdline = NULL; + + if (pe->owner_host && + !uname (&utsbuf) && + !strcmp (utsbuf.nodename, pe->owner_host)) + { + pidname = get_pid_name_for_uid (pe->owner_pid, pe->owner_uid); + if (pidname) + cmdline = get_cmdline (pe->owner_pid); + } + + if (pe->owner_host && (cmdline || pidname)) + snprintf (buf, sizeof buf, "[%lu]@%s (%s)", + pe->owner_pid, pe->owner_host, cmdline ? cmdline : pidname); + else if (pe->owner_host) + snprintf (buf, sizeof buf, "[%lu]@%s", + pe->owner_pid, pe->owner_host); + else + snprintf (buf, sizeof buf, "[%lu] <unknown host>", + pe->owner_pid); + free (pidname); + free (cmdline); + title = strdup (buf); + } +#endif /*!HAVE_W32_SYSTEM*/ + else + title = strdup (this_pgmname); + + return title; +} + + +/* Run a quality inquiry for PASSPHRASE of LENGTH. (We need LENGTH + because not all backends might be able to return a proper + C-string.). Returns: A value between -100 and 100 to give an + estimate of the passphrase's quality. Negative values are use if + the caller won't even accept that passphrase. Note that we expect + just one data line which should not be escaped in any represent a + numeric signed decimal value. Extra data is currently ignored but + should not be send at all. */ +int +pinentry_inq_quality (pinentry_t pin, const char *passphrase, size_t length) +{ + assuan_context_t ctx = pin->ctx_assuan; + const char prefix[] = "INQUIRE QUALITY "; + char *command; + char *line; + size_t linelen; + int gotvalue = 0; + int value = 0; + int rc; + + if (!ctx) + return 0; /* Can't run the callback. */ + + if (length > 300) + length = 300; /* Limit so that it definitely fits into an Assuan + line. */ + + command = secmem_malloc (strlen (prefix) + 3*length + 1); + if (!command) + return 0; + strcpy (command, prefix); + copy_and_escape (command + strlen(command), passphrase, length); + rc = assuan_write_line (ctx, command); + secmem_free (command); + if (rc) + { + fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc); + return 0; + } + + for (;;) + { + do + { + rc = assuan_read_line (ctx, &line, &linelen); + if (rc) + { + fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc); + return 0; + } + } + while (*line == '#' || !linelen); + if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' + && (!line[3] || line[3] == ' ')) + break; /* END command received*/ + if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' + && (!line[3] || line[3] == ' ')) + break; /* CAN command received*/ + if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' + && (!line[3] || line[3] == ' ')) + break; /* ERR command received*/ + if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) + continue; + gotvalue = 1; + value = atoi (line+2); + } + if (value < -100) + value = -100; + else if (value > 100) + value = 100; + + return value; +} + + +/* Run a checkpin inquiry */ +char * +pinentry_inq_checkpin (pinentry_t pin, const char *passphrase, size_t length) +{ + assuan_context_t ctx = pin->ctx_assuan; + const char prefix[] = "INQUIRE CHECKPIN "; + char *command; + char *line; + size_t linelen; + int gotvalue = 0; + char *value = NULL; + int rc; + + if (!ctx) + return 0; /* Can't run the callback. */ + + if (length > 300) + length = 300; /* Limit so that it definitely fits into an Assuan + line. */ + + command = secmem_malloc (strlen (prefix) + 3*length + 1); + if (!command) + return 0; + strcpy (command, prefix); + copy_and_escape (command + strlen(command), passphrase, length); + rc = assuan_write_line (ctx, command); + secmem_free (command); + if (rc) + { + fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc); + return 0; + } + + for (;;) + { + do + { + rc = assuan_read_line (ctx, &line, &linelen); + if (rc) + { + fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc); + return 0; + } + } + while (*line == '#' || !linelen); + if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' + && (!line[3] || line[3] == ' ')) + break; /* END command received*/ + if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' + && (!line[3] || line[3] == ' ')) + break; /* CAN command received*/ + if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' + && (!line[3] || line[3] == ' ')) + break; /* ERR command received*/ + if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) + continue; + gotvalue = 1; + value = strdup (line + 2); + } + + return value; +} + + +/* Run a genpin inquiry */ +char * +pinentry_inq_genpin (pinentry_t pin) +{ + assuan_context_t ctx = pin->ctx_assuan; + const char prefix[] = "INQUIRE GENPIN"; + char *line; + size_t linelen; + int gotvalue = 0; + char *value = NULL; + int rc; + + if (!ctx) + return 0; /* Can't run the callback. */ + + rc = assuan_write_line (ctx, prefix); + if (rc) + { + fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc); + return 0; + } + + for (;;) + { + do + { + rc = assuan_read_line (ctx, &line, &linelen); + if (rc) + { + fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc); + free (value); + return 0; + } + } + while (*line == '#' || !linelen); + if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' + && (!line[3] || line[3] == ' ')) + break; /* END command received*/ + if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' + && (!line[3] || line[3] == ' ')) + break; /* CAN command received*/ + if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' + && (!line[3] || line[3] == ' ')) + break; /* ERR command received*/ + if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) + continue; + gotvalue = 1; + value = strdup (line + 2); + } + + return value; +} + +/* Try to make room for at least LEN bytes in the pinentry. Returns + new buffer on success and 0 on failure or when the old buffer is + sufficient. */ +char * +pinentry_setbufferlen (pinentry_t pin, int len) +{ + char *newp; + + if (pin->pin_len) + assert (pin->pin); + else + assert (!pin->pin); + + if (len < 2048) + len = 2048; + + if (len <= pin->pin_len) + return pin->pin; + + newp = secmem_realloc (pin->pin, len); + if (newp) + { + pin->pin = newp; + pin->pin_len = len; + } + else + { + secmem_free (pin->pin); + pin->pin = 0; + pin->pin_len = 0; + } + return newp; +} + +static void +pinentry_setbuffer_clear (pinentry_t pin) +{ + if (! pin->pin) + { + assert (pin->pin_len == 0); + return; + } + + assert (pin->pin_len > 0); + + secmem_free (pin->pin); + pin->pin = NULL; + pin->pin_len = 0; +} + +static void +pinentry_setbuffer_init (pinentry_t pin) +{ + pinentry_setbuffer_clear (pin); + pinentry_setbufferlen (pin, 0); +} + +/* passphrase better be alloced with secmem_alloc. */ +void +pinentry_setbuffer_use (pinentry_t pin, char *passphrase, int len) +{ + if (! passphrase) + { + assert (len == 0); + pinentry_setbuffer_clear (pin); + + return; + } + + if (passphrase && len == 0) + len = strlen (passphrase) + 1; + + if (pin->pin) + secmem_free (pin->pin); + + pin->pin = passphrase; + pin->pin_len = len; +} + +static struct assuan_malloc_hooks assuan_malloc_hooks = { + secmem_malloc, secmem_realloc, secmem_free +}; + +/* Initialize the secure memory subsystem, drop privileges and return. + Must be called early. */ +void +pinentry_init (const char *pgmname) +{ + /* Store away our name. */ + if (strlen (pgmname) > sizeof this_pgmname - 2) + abort (); + strcpy (this_pgmname, pgmname); + + gpgrt_check_version (NULL); + + /* Initialize secure memory. 1 is too small, so the default size + will be used. */ + secmem_init (1); + secmem_set_flags (SECMEM_WARN); + drop_privs (); + + if (atexit (secmem_term)) + { + /* FIXME: Could not register at-exit function, bail out. */ + } + + assuan_set_malloc_hooks (&assuan_malloc_hooks); +} + +/* Simple test to check whether DISPLAY is set or the option --display + was given. Used to decide whether the GUI or curses should be + initialized. */ +int +pinentry_have_display (int argc, char **argv) +{ + int found = 0; + + for (; argc; argc--, argv++) + { + if (!strcmp (*argv, "--display")) + { + if (argv[1] && !remember_display) + { + remember_display = strdup (argv[1]); + if (!remember_display) + { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif + exit (EXIT_FAILURE); + } + } + found = 1; + break; + } + else if (!strncmp (*argv, "--display=", 10)) + { + if (!remember_display) + { + remember_display = strdup (*argv+10); + if (!remember_display) + { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif + exit (EXIT_FAILURE); + } + } + found = 1; + break; + } + } + +#ifndef HAVE_W32CE_SYSTEM + { + const char *s; + s = getenv ("DISPLAY"); + if (s && *s) + found = 1; + } +#endif + + return found; +} + + + +/* Print usage information and and provide strings for help. */ +static const char * +my_strusage( int level ) +{ + const char *p; + + switch (level) + { + case 11: p = this_pgmname; break; + case 12: p = "pinentry"; break; + case 13: p = PACKAGE_VERSION; break; + case 14: p = "Copyright (C) 2016 g10 Code GmbH"; break; + case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break; + case 1: + case 40: + { + static char *str; + + if (!str) + { + size_t n = 50 + strlen (this_pgmname); + str = malloc (n); + if (str) + { + snprintf (str, n, "Usage: %s [options] (-h for help)", + this_pgmname); + } + } + p = str; + } + break; + case 41: + p = "Ask securely for a secret and print it to stdout."; + break; + + case 42: + p = "1"; /* Flag print 40 as part of 41. */ + break; + + default: p = NULL; break; + } + return p; +} + + +char * +parse_color (char *arg, pinentry_color_t *color_p, int *bright_p) +{ + static struct + { + const char *name; + pinentry_color_t color; + } colors[] = { { "none", PINENTRY_COLOR_NONE }, + { "default", PINENTRY_COLOR_DEFAULT }, + { "black", PINENTRY_COLOR_BLACK }, + { "red", PINENTRY_COLOR_RED }, + { "green", PINENTRY_COLOR_GREEN }, + { "yellow", PINENTRY_COLOR_YELLOW }, + { "blue", PINENTRY_COLOR_BLUE }, + { "magenta", PINENTRY_COLOR_MAGENTA }, + { "cyan", PINENTRY_COLOR_CYAN }, + { "white", PINENTRY_COLOR_WHITE } }; + + int i; + char *new_arg; + pinentry_color_t color = PINENTRY_COLOR_DEFAULT; + + if (!arg) + return NULL; + + new_arg = strchr (arg, ','); + if (new_arg) + new_arg++; + + if (bright_p) + { + const char *bname[] = { "bright-", "bright", "bold-", "bold" }; + + *bright_p = 0; + for (i = 0; i < sizeof (bname) / sizeof (bname[0]); i++) + if (!strncasecmp (arg, bname[i], strlen (bname[i]))) + { + *bright_p = 1; + arg += strlen (bname[i]); + } + } + + for (i = 0; i < sizeof (colors) / sizeof (colors[0]); i++) + if (!strncasecmp (arg, colors[i].name, strlen (colors[i].name))) + color = colors[i].color; + + *color_p = color; + return new_arg; +} + +/* Parse the command line options. May exit the program if only help + or version output is requested. */ +void +pinentry_parse_opts (int argc, char *argv[]) +{ + static ARGPARSE_OPTS opts[] = { + ARGPARSE_s_n('d', "debug", "Turn on debugging output"), + ARGPARSE_s_s('D', "display", "|DISPLAY|Set the X display"), + ARGPARSE_s_s('T', "ttyname", "|FILE|Set the tty terminal node name"), + ARGPARSE_s_s('N', "ttytype", "|NAME|Set the tty terminal type"), + ARGPARSE_s_s('C', "lc-ctype", "|STRING|Set the tty LC_CTYPE value"), + ARGPARSE_s_s('M', "lc-messages", "|STRING|Set the tty LC_MESSAGES value"), + ARGPARSE_s_i('o', "timeout", + "|SECS|Timeout waiting for input after this many seconds"), + ARGPARSE_s_n('g', "no-global-grab", + "Grab keyboard only while window is focused"), + ARGPARSE_s_u('W', "parent-wid", "Parent window ID (for positioning)"), + ARGPARSE_s_s('c', "colors", "|STRING|Set custom colors for ncurses"), + ARGPARSE_s_s('a', "ttyalert", "|STRING|Set the alert mode (none, beep or flash)"), + ARGPARSE_end() + }; + ARGPARSE_ARGS pargs = { &argc, &argv, 0 }; + + set_strusage (my_strusage); + + pinentry_reset (1); + + while (arg_parse (&pargs, opts)) + { + switch (pargs.r_opt) + { + case 'd': + pinentry.debug = 1; + break; + case 'g': + pinentry.grab = 0; + break; + + case 'D': + /* Note, this is currently not used because the GUI engine + has already been initialized when parsing these options. */ + pinentry.display = strdup (pargs.r.ret_str); + if (!pinentry.display) + { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif + exit (EXIT_FAILURE); + } + break; + case 'T': + pinentry.ttyname = strdup (pargs.r.ret_str); + if (!pinentry.ttyname) + { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif + exit (EXIT_FAILURE); + } + break; + case 'N': + pinentry.ttytype_l = strdup (pargs.r.ret_str); + if (!pinentry.ttytype_l) + { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif + exit (EXIT_FAILURE); + } + break; + case 'C': + pinentry.lc_ctype = strdup (pargs.r.ret_str); + if (!pinentry.lc_ctype) + { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif + exit (EXIT_FAILURE); + } + break; + case 'M': + pinentry.lc_messages = strdup (pargs.r.ret_str); + if (!pinentry.lc_messages) + { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif + exit (EXIT_FAILURE); + } + break; + case 'W': + pinentry.parent_wid = pargs.r.ret_ulong; + break; + + case 'c': + { + char *tmpstr = pargs.r.ret_str; + + tmpstr = parse_color (tmpstr, &pinentry.color_fg, + &pinentry.color_fg_bright); + tmpstr = parse_color (tmpstr, &pinentry.color_bg, NULL); + tmpstr = parse_color (tmpstr, &pinentry.color_so, + &pinentry.color_so_bright); + } + break; + + case 'o': + pinentry.timeout = pargs.r.ret_int; + break; + + case 'a': + pinentry.ttyalert = strdup (pargs.r.ret_str); + if (!pinentry.ttyalert) + { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif + exit (EXIT_FAILURE); + } + break; + + default: + pargs.err = ARGPARSE_PRINT_WARNING; + break; + } + } + + if (!pinentry.display && remember_display) + { + pinentry.display = remember_display; + remember_display = NULL; + } +} + + +/* Set the optional flag used with getinfo. */ +void +pinentry_set_flavor_flag (const char *string) +{ + flavor_flag = string; +} + + + + +static gpg_error_t +option_handler (assuan_context_t ctx, const char *key, const char *value) +{ + (void)ctx; + + if (!strcmp (key, "no-grab") && !*value) + pinentry.grab = 0; + else if (!strcmp (key, "grab") && !*value) + pinentry.grab = 1; + else if (!strcmp (key, "debug-wait")) + { +#ifndef HAVE_W32_SYSTEM + fprintf (stderr, "%s: waiting for debugger - my pid is %u ...\n", + this_pgmname, (unsigned int) getpid()); + sleep (*value?atoi (value):5); + fprintf (stderr, "%s: ... okay\n", this_pgmname); +#endif + } + else if (!strcmp (key, "display")) + { + if (pinentry.display) + free (pinentry.display); + pinentry.display = strdup (value); + if (!pinentry.display) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "ttyname")) + { + if (pinentry.ttyname) + free (pinentry.ttyname); + pinentry.ttyname = strdup (value); + if (!pinentry.ttyname) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "ttytype")) + { + if (pinentry.ttytype_l) + free (pinentry.ttytype_l); + pinentry.ttytype_l = strdup (value); + if (!pinentry.ttytype_l) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "ttyalert")) + { + if (pinentry.ttyalert) + free (pinentry.ttyalert); + pinentry.ttyalert = strdup (value); + if (!pinentry.ttyalert) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "lc-ctype")) + { + if (pinentry.lc_ctype) + free (pinentry.lc_ctype); + pinentry.lc_ctype = strdup (value); + if (!pinentry.lc_ctype) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "lc-messages")) + { + if (pinentry.lc_messages) + free (pinentry.lc_messages); + pinentry.lc_messages = strdup (value); + if (!pinentry.lc_messages) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "owner")) + { + long along; + char *endp; + + free (pinentry.owner_host); + pinentry.owner_host = NULL; + pinentry.owner_uid = -1; + pinentry.owner_pid = 0; + + errno = 0; + along = strtol (value, &endp, 10); + if (along && !errno) + { + pinentry.owner_pid = (unsigned long)along; + if (*endp) + { + errno = 0; + if (*endp == '/') { /* we have a uid */ + endp++; + along = strtol (endp, &endp, 10); + if (along >= 0 && !errno) + pinentry.owner_uid = (int)along; + } + if (endp) + { + while (*endp == ' ') + endp++; + if (*endp) + { + pinentry.owner_host = strdup (endp); + for (endp=pinentry.owner_host; + *endp && *endp != ' '; endp++) + ; + *endp = 0; + } + } + } + } + } + else if (!strcmp (key, "parent-wid")) + { + pinentry.parent_wid = atoi (value); + /* FIXME: Use strtol and add some error handling. */ + } + else if (!strcmp (key, "touch-file")) + { + if (pinentry.touch_file) + free (pinentry.touch_file); + pinentry.touch_file = strdup (value); + if (!pinentry.touch_file) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "default-ok")) + { + pinentry.default_ok = strdup (value); + if (!pinentry.default_ok) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "default-cancel")) + { + pinentry.default_cancel = strdup (value); + if (!pinentry.default_cancel) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "default-prompt")) + { + pinentry.default_prompt = strdup (value); + if (!pinentry.default_prompt) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "default-pwmngr")) + { + pinentry.default_pwmngr = strdup (value); + if (!pinentry.default_pwmngr) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "default-cf-visi")) + { + pinentry.default_cf_visi = strdup (value); + if (!pinentry.default_cf_visi) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "default-tt-visi")) + { + pinentry.default_tt_visi = strdup (value); + if (!pinentry.default_tt_visi) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "default-tt-hide")) + { + pinentry.default_tt_hide = strdup (value); + if (!pinentry.default_tt_hide) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "default-capshint")) + { + pinentry.default_capshint = strdup (value); + if (!pinentry.default_capshint) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "allow-external-password-cache") && !*value) + { + pinentry.allow_external_password_cache = 1; + pinentry.tried_password_cache = 0; + } + else if (!strcmp (key, "allow-emacs-prompt") && !*value) + { +#ifdef INSIDE_EMACS + pinentry_enable_emacs_cmd_handler (); +#endif + } + else if (!strcmp (key, "invisible-char")) + { + if (pinentry.invisible_char) + free (pinentry.invisible_char); + pinentry.invisible_char = strdup (value); + if (!pinentry.invisible_char) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "formatted-passphrase") && !*value) + { + pinentry.formatted_passphrase = 1; + } + else if (!strcmp (key, "formatted-passphrase-hint")) + { + if (pinentry.formatted_passphrase_hint) + free (pinentry.formatted_passphrase_hint); + pinentry.formatted_passphrase_hint = strdup (value); + if (!pinentry.formatted_passphrase_hint) + return gpg_error_from_syserror (); + do_unescape_inplace(pinentry.formatted_passphrase_hint); + } + else if (!strcmp (key, "constraints-enforce") && !*value) + pinentry.constraints_enforce = 1; + else if (!strcmp (key, "constraints-hint-short")) + { + if (pinentry.constraints_hint_short) + free (pinentry.constraints_hint_short); + pinentry.constraints_hint_short = strdup (value); + if (!pinentry.constraints_hint_short) + return gpg_error_from_syserror (); + do_unescape_inplace(pinentry.constraints_hint_short); + } + else if (!strcmp (key, "constraints-hint-long")) + { + if (pinentry.constraints_hint_long) + free (pinentry.constraints_hint_long); + pinentry.constraints_hint_long = strdup (value); + if (!pinentry.constraints_hint_long) + return gpg_error_from_syserror (); + do_unescape_inplace(pinentry.constraints_hint_long); + } + else if (!strcmp (key, "constraints-error-title")) + { + if (pinentry.constraints_error_title) + free (pinentry.constraints_error_title); + pinentry.constraints_error_title = strdup (value); + if (!pinentry.constraints_error_title) + return gpg_error_from_syserror (); + do_unescape_inplace(pinentry.constraints_error_title); + } + else + return gpg_error (GPG_ERR_UNKNOWN_OPTION); + return 0; +} + + +/* Note, that it is sufficient to allocate the target string D as + long as the source string S, i.e.: strlen(s)+1; */ +static void +strcpy_escaped (char *d, const char *s) +{ + while (*s) + { + if (*s == '%' && s[1] && s[2]) + { + s++; + *d++ = xtoi_2 ( s); + s += 2; + } + else + *d++ = *s++; + } + *d = 0; +} + + +static void +write_status_error (assuan_context_t ctx, pinentry_t pe) +{ + char buf[500]; + const char *pgm; + + pgm = strchr (this_pgmname, '-'); + if (pgm && pgm[1]) + pgm++; + else + pgm = this_pgmname; + + snprintf (buf, sizeof buf, "%s.%s %d %s", + pgm, + pe->specific_err_loc? pe->specific_err_loc : "?", + pe->specific_err, + pe->specific_err_info? pe->specific_err_info : ""); + assuan_write_status (ctx, "ERROR", buf); +} + + +static gpg_error_t +cmd_setdesc (assuan_context_t ctx, char *line) +{ + char *newd; + + (void)ctx; + + newd = malloc (strlen (line) + 1); + if (!newd) + return gpg_error_from_syserror (); + + strcpy_escaped (newd, line); + if (pinentry.description) + free (pinentry.description); + pinentry.description = newd; + return 0; +} + + +static gpg_error_t +cmd_setprompt (assuan_context_t ctx, char *line) +{ + char *newp; + + (void)ctx; + + newp = malloc (strlen (line) + 1); + if (!newp) + return gpg_error_from_syserror (); + + strcpy_escaped (newp, line); + if (pinentry.prompt) + free (pinentry.prompt); + pinentry.prompt = newp; + return 0; +} + + +/* The data provided at LINE may be used by pinentry implementations + to identify a key for caching strategies of its own. The empty + string and --clear mean that the key does not have a stable + identifier. */ +static gpg_error_t +cmd_setkeyinfo (assuan_context_t ctx, char *line) +{ + (void)ctx; + + if (pinentry.keyinfo) + free (pinentry.keyinfo); + + if (*line && strcmp(line, "--clear") != 0) + pinentry.keyinfo = strdup (line); + else + pinentry.keyinfo = NULL; + + return 0; +} + + +static gpg_error_t +cmd_setrepeat (assuan_context_t ctx, char *line) +{ + char *p; + + (void)ctx; + + p = malloc (strlen (line) + 1); + if (!p) + return gpg_error_from_syserror (); + + strcpy_escaped (p, line); + free (pinentry.repeat_passphrase); + pinentry.repeat_passphrase = p; + return 0; +} + + +static gpg_error_t +cmd_setrepeaterror (assuan_context_t ctx, char *line) +{ + char *p; + + (void)ctx; + + p = malloc (strlen (line) + 1); + if (!p) + return gpg_error_from_syserror (); + + strcpy_escaped (p, line); + free (pinentry.repeat_error_string); + pinentry.repeat_error_string = p; + return 0; +} + + +static gpg_error_t +cmd_seterror (assuan_context_t ctx, char *line) +{ + char *newe; + + (void)ctx; + + newe = malloc (strlen (line) + 1); + if (!newe) + return gpg_error_from_syserror (); + + strcpy_escaped (newe, line); + if (pinentry.error) + free (pinentry.error); + pinentry.error = newe; + return 0; +} + + +static gpg_error_t +cmd_setok (assuan_context_t ctx, char *line) +{ + char *newo; + + (void)ctx; + + newo = malloc (strlen (line) + 1); + if (!newo) + return gpg_error_from_syserror (); + + strcpy_escaped (newo, line); + if (pinentry.ok) + free (pinentry.ok); + pinentry.ok = newo; + return 0; +} + + +static gpg_error_t +cmd_setnotok (assuan_context_t ctx, char *line) +{ + char *newo; + + (void)ctx; + + newo = malloc (strlen (line) + 1); + if (!newo) + return gpg_error_from_syserror (); + + strcpy_escaped (newo, line); + if (pinentry.notok) + free (pinentry.notok); + pinentry.notok = newo; + return 0; +} + + +static gpg_error_t +cmd_setcancel (assuan_context_t ctx, char *line) +{ + char *newc; + + (void)ctx; + + newc = malloc (strlen (line) + 1); + if (!newc) + return gpg_error_from_syserror (); + + strcpy_escaped (newc, line); + if (pinentry.cancel) + free (pinentry.cancel); + pinentry.cancel = newc; + return 0; +} + + +static gpg_error_t +cmd_settimeout (assuan_context_t ctx, char *line) +{ + (void)ctx; + + if (line && *line) + pinentry.timeout = atoi (line); + + return 0; +} + +static gpg_error_t +cmd_settitle (assuan_context_t ctx, char *line) +{ + char *newt; + + (void)ctx; + + newt = malloc (strlen (line) + 1); + if (!newt) + return gpg_error_from_syserror (); + + strcpy_escaped (newt, line); + if (pinentry.title) + free (pinentry.title); + pinentry.title = newt; + return 0; +} + +static gpg_error_t +cmd_setqualitybar (assuan_context_t ctx, char *line) +{ + char *newval; + + (void)ctx; + + if (!*line) + line = "Quality:"; + + newval = malloc (strlen (line) + 1); + if (!newval) + return gpg_error_from_syserror (); + + strcpy_escaped (newval, line); + if (pinentry.quality_bar) + free (pinentry.quality_bar); + pinentry.quality_bar = newval; + return 0; +} + +/* Set the tooltip to be used for a quality bar. */ +static gpg_error_t +cmd_setqualitybar_tt (assuan_context_t ctx, char *line) +{ + char *newval; + + (void)ctx; + + if (*line) + { + newval = malloc (strlen (line) + 1); + if (!newval) + return gpg_error_from_syserror (); + + strcpy_escaped (newval, line); + } + else + newval = NULL; + if (pinentry.quality_bar_tt) + free (pinentry.quality_bar_tt); + pinentry.quality_bar_tt = newval; + return 0; +} + +/* Set the tooltip to be used for a generate action. */ +static gpg_error_t +cmd_setgenpin_tt (assuan_context_t ctx, char *line) +{ + char *newval; + + (void)ctx; + + if (*line) + { + newval = malloc (strlen (line) + 1); + if (!newval) + return gpg_error_from_syserror (); + + strcpy_escaped (newval, line); + } + else + newval = NULL; + if (pinentry.genpin_tt) + free (pinentry.genpin_tt); + pinentry.genpin_tt = newval; + return 0; +} + +/* Set the label to be used for a generate action. */ +static gpg_error_t +cmd_setgenpin_label (assuan_context_t ctx, char *line) +{ + char *newval; + + (void)ctx; + + if (*line) + { + newval = malloc (strlen (line) + 1); + if (!newval) + return gpg_error_from_syserror (); + + strcpy_escaped (newval, line); + } + else + newval = NULL; + if (pinentry.genpin_label) + free (pinentry.genpin_label); + pinentry.genpin_label = newval; + return 0; +} + +static gpg_error_t +cmd_getpin (assuan_context_t ctx, char *line) +{ + int result; + int set_prompt = 0; + int just_read_password_from_cache = 0; + + (void)line; + + pinentry_setbuffer_init (&pinentry); + if (!pinentry.pin) + return gpg_error (GPG_ERR_ENOMEM); + + /* Try reading from the password cache. */ + if (/* If repeat passphrase is set, then we don't want to read from + the cache. */ + ! pinentry.repeat_passphrase + /* Are we allowed to read from the cache? */ + && pinentry.allow_external_password_cache + && pinentry.keyinfo + /* Only read from the cache if we haven't already tried it. */ + && ! pinentry.tried_password_cache + /* If the last read resulted in an error, then don't read from + the cache. */ + && ! pinentry.error) + { + char *password; + int give_up_on_password_store = 0; + + pinentry.tried_password_cache = 1; + + password = password_cache_lookup (pinentry.keyinfo, &give_up_on_password_store); + if (give_up_on_password_store) + pinentry.allow_external_password_cache = 0; + + if (password) + /* There is a cached password. Try it. */ + { + int len = strlen(password) + 1; + if (len > pinentry.pin_len) + len = pinentry.pin_len; + + memcpy (pinentry.pin, password, len); + pinentry.pin[len] = '\0'; + + secmem_free (password); + + pinentry.pin_from_cache = 1; + + assuan_write_status (ctx, "PASSWORD_FROM_CACHE", ""); + + /* Result is the length of the password not including the + NUL terminator. */ + result = len - 1; + + just_read_password_from_cache = 1; + + goto out; + } + } + + /* The password was not cached (or we are not allowed to / cannot + use the cache). Prompt the user. */ + pinentry.pin_from_cache = 0; + + if (!pinentry.prompt) + { + pinentry.prompt = pinentry.default_prompt?pinentry.default_prompt:"PIN:"; + set_prompt = 1; + } + pinentry.locale_err = 0; + pinentry.specific_err = 0; + pinentry.specific_err_loc = NULL; + free (pinentry.specific_err_info); + pinentry.specific_err_info = NULL; + pinentry.close_button = 0; + pinentry.repeat_okay = 0; + pinentry.one_button = 0; + pinentry.ctx_assuan = ctx; + result = (*pinentry_cmd_handler) (&pinentry); + pinentry.ctx_assuan = NULL; + if (pinentry.error) + { + free (pinentry.error); + pinentry.error = NULL; + } + if (pinentry.repeat_passphrase) + { + free (pinentry.repeat_passphrase); + pinentry.repeat_passphrase = NULL; + } + if (set_prompt) + pinentry.prompt = NULL; + + pinentry.quality_bar = 0; /* Reset it after the command. */ + + if (pinentry.close_button) + assuan_write_status (ctx, "BUTTON_INFO", "close"); + + if (result < 0) + { + pinentry_setbuffer_clear (&pinentry); + if (pinentry.specific_err) + { + write_status_error (ctx, &pinentry); + + if (gpg_err_code (pinentry.specific_err) == GPG_ERR_FULLY_CANCELED) + assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1); + + return pinentry.specific_err; + } + return (pinentry.locale_err + ? gpg_error (GPG_ERR_LOCALE_PROBLEM) + : gpg_error (GPG_ERR_CANCELED)); + } + + out: + if (result) + { + if (pinentry.repeat_okay) + assuan_write_status (ctx, "PIN_REPEATED", ""); + assuan_begin_confidential (ctx); + result = assuan_send_data (ctx, pinentry.pin, strlen(pinentry.pin)); + if (!result) + result = assuan_send_data (ctx, NULL, 0); + assuan_end_confidential (ctx); + + if (/* GPG Agent says it's okay. */ + pinentry.allow_external_password_cache && pinentry.keyinfo + /* We didn't just read it from the cache. */ + && ! just_read_password_from_cache + /* And the user said it's okay. */ + && pinentry.may_cache_password) + /* Cache the password. */ + password_cache_save (pinentry.keyinfo, pinentry.pin); + } + + pinentry_setbuffer_clear (&pinentry); + + return result; +} + + +/* Note that the option --one-button is a hack to allow the use of old + pinentries while the caller is ignoring the result. Given that + options have never been used or flagged as an error the new option + is an easy way to enable the messsage mode while not requiring to + update pinentry or to have the caller test for the message + command. New applications which are free to require an updated + pinentry should use MESSAGE instead. */ +static gpg_error_t +cmd_confirm (assuan_context_t ctx, char *line) +{ + int result; + + pinentry.one_button = !!strstr (line, "--one-button"); + pinentry.quality_bar = 0; + pinentry.close_button = 0; + pinentry.locale_err = 0; + pinentry.specific_err = 0; + pinentry.specific_err_loc = NULL; + free (pinentry.specific_err_info); + pinentry.specific_err_info = NULL; + pinentry.canceled = 0; + pinentry_setbuffer_clear (&pinentry); + result = (*pinentry_cmd_handler) (&pinentry); + if (pinentry.error) + { + free (pinentry.error); + pinentry.error = NULL; + } + + if (pinentry.close_button) + assuan_write_status (ctx, "BUTTON_INFO", "close"); + + if (result > 0) + return 0; /* OK */ + + if (pinentry.specific_err) + { + write_status_error (ctx, &pinentry); + + if (gpg_err_code (pinentry.specific_err) == GPG_ERR_FULLY_CANCELED) + assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1); + + return pinentry.specific_err; + } + + if (pinentry.locale_err) + return gpg_error (GPG_ERR_LOCALE_PROBLEM); + + if (pinentry.one_button) + return 0; /* OK */ + + if (pinentry.canceled) + return gpg_error (GPG_ERR_CANCELED); + return gpg_error (GPG_ERR_NOT_CONFIRMED); +} + + +static gpg_error_t +cmd_message (assuan_context_t ctx, char *line) +{ + (void)line; + + return cmd_confirm (ctx, "--one-button"); +} + + +/* Return a staically allocated string with information on the mode, + * uid, and gid of DEVICE. On error "?" is returned if DEVICE is + * NULL, "-" is returned. */ +static const char * +device_stat_string (const char *device) +{ +#ifdef HAVE_STAT + static char buf[40]; + struct stat st; + + if (!device || !*device) + return "-"; + + if (stat (device, &st)) + return "?"; /* Error */ + snprintf (buf, sizeof buf, "%lo/%lu/%lu", + (unsigned long)st.st_mode, + (unsigned long)st.st_uid, + (unsigned long)st.st_gid); + return buf; +#else + return "-"; +#endif +} + + +/* GETINFO <what> + + Multipurpose function to return a variety of information. + Supported values for WHAT are: + + version - Return the version of the program. + pid - Return the process id of the server. + flavor - Return information about the used pinentry flavor + ttyinfo - Return DISPLAY, ttyinfo and an emacs pinentry status + */ +static gpg_error_t +cmd_getinfo (assuan_context_t ctx, char *line) +{ + int rc; + const char *s; + char buffer[150]; + + if (!strcmp (line, "version")) + { + s = VERSION; + rc = assuan_send_data (ctx, s, strlen (s)); + } + else if (!strcmp (line, "pid")) + { + + snprintf (buffer, sizeof buffer, "%lu", (unsigned long)getpid ()); + rc = assuan_send_data (ctx, buffer, strlen (buffer)); + } + else if (!strcmp (line, "flavor")) + { + if (!strncmp (this_pgmname, "pinentry-", 9) && this_pgmname[9]) + s = this_pgmname + 9; + else + s = this_pgmname; + + snprintf (buffer, sizeof buffer, "%s%s%s", + s, + flavor_flag? ":":"", + flavor_flag? flavor_flag : ""); + rc = assuan_send_data (ctx, buffer, strlen (buffer)); + /* if (!rc) */ + /* rc = assuan_write_status (ctx, "FEATURES", "tabbing foo bar"); */ + } + else if (!strcmp (line, "ttyinfo")) + { + char emacs_status[10]; +#ifdef INSIDE_EMACS + snprintf (emacs_status, sizeof emacs_status, + "%d", pinentry_emacs_status ()); +#else + strcpy (emacs_status, "-"); +#endif + snprintf (buffer, sizeof buffer, "%s %s %s %s %lu/%lu %s", + pinentry.ttyname? pinentry.ttyname : "-", + pinentry.ttytype_l? pinentry.ttytype_l : "-", + pinentry.display? pinentry.display : "-", + device_stat_string (pinentry.ttyname), +#ifdef HAVE_DOSISH_SYSTEM + 0l, 0l, +#else + (unsigned long)geteuid (), (unsigned long)getegid (), +#endif + emacs_status + ); + rc = assuan_send_data (ctx, buffer, strlen (buffer)); + } + else + rc = gpg_error (GPG_ERR_ASS_PARAMETER); + return rc; +} + +/* CLEARPASSPHRASE <cacheid> + + Clear the cache passphrase associated with the key identified by + cacheid. + */ +static gpg_error_t +cmd_clear_passphrase (assuan_context_t ctx, char *line) +{ + (void)ctx; + + if (! line) + return gpg_error (GPG_ERR_ASS_INV_VALUE); + + /* Remove leading and trailing white space. */ + while (*line == ' ') + line ++; + while (line[strlen (line) - 1] == ' ') + line[strlen (line) - 1] = 0; + + switch (password_cache_clear (line)) + { + case 1: return 0; + case 0: return gpg_error (GPG_ERR_ASS_INV_VALUE); + default: return gpg_error (GPG_ERR_ASS_GENERAL); + } +} + +/* Tell the assuan library about our commands. */ +static gpg_error_t +register_commands (assuan_context_t ctx) +{ + static struct + { + const char *name; + gpg_error_t (*handler) (assuan_context_t, char *line); + } table[] = + { + { "SETDESC", cmd_setdesc }, + { "SETPROMPT", cmd_setprompt }, + { "SETKEYINFO", cmd_setkeyinfo }, + { "SETREPEAT", cmd_setrepeat }, + { "SETREPEATERROR", cmd_setrepeaterror }, + { "SETERROR", cmd_seterror }, + { "SETOK", cmd_setok }, + { "SETNOTOK", cmd_setnotok }, + { "SETCANCEL", cmd_setcancel }, + { "GETPIN", cmd_getpin }, + { "CONFIRM", cmd_confirm }, + { "MESSAGE", cmd_message }, + { "SETQUALITYBAR", cmd_setqualitybar }, + { "SETQUALITYBAR_TT", cmd_setqualitybar_tt }, + { "SETGENPIN", cmd_setgenpin_label }, + { "SETGENPIN_TT", cmd_setgenpin_tt }, + { "GETINFO", cmd_getinfo }, + { "SETTITLE", cmd_settitle }, + { "SETTIMEOUT", cmd_settimeout }, + { "CLEARPASSPHRASE", cmd_clear_passphrase }, + { NULL } + }; + int i, j; + gpg_error_t rc; + + for (i = j = 0; table[i].name; i++) + { + rc = assuan_register_command (ctx, table[i].name, table[i].handler, NULL); + if (rc) + return rc; + } + return 0; +} + + +int +pinentry_loop2 (int infd, int outfd) +{ + gpg_error_t rc; + assuan_fd_t filedes[2]; + assuan_context_t ctx; + + /* Extra check to make sure we have dropped privs. */ +#ifndef HAVE_DOSISH_SYSTEM + if (getuid() != geteuid()) + abort (); +#endif + + rc = assuan_new (&ctx); + if (rc) + { + fprintf (stderr, "server context creation failed: %s\n", + gpg_strerror (rc)); + return -1; + } + + /* For now we use a simple pipe based server so that we can work + from scripts. We will later add options to run as a daemon and + wait for requests on a Unix domain socket. */ + filedes[0] = assuan_fdopen (infd); + filedes[1] = assuan_fdopen (outfd); + rc = assuan_init_pipe_server (ctx, filedes); + if (rc) + { + fprintf (stderr, "%s: failed to initialize the server: %s\n", + this_pgmname, gpg_strerror (rc)); + return -1; + } + rc = register_commands (ctx); + if (rc) + { + fprintf (stderr, "%s: failed to the register commands with Assuan: %s\n", + this_pgmname, gpg_strerror (rc)); + return -1; + } + + assuan_register_option_handler (ctx, option_handler); +#if 0 + assuan_set_log_stream (ctx, stderr); +#endif + assuan_register_reset_notify (ctx, pinentry_assuan_reset_handler); + + for (;;) + { + rc = assuan_accept (ctx); + if (rc == -1) + break; + else if (rc) + { + fprintf (stderr, "%s: Assuan accept problem: %s\n", + this_pgmname, gpg_strerror (rc)); + break; + } + + rc = assuan_process (ctx); + if (rc) + { + fprintf (stderr, "%s: Assuan processing failed: %s\n", + this_pgmname, gpg_strerror (rc)); + continue; + } + } + + assuan_release (ctx); + return 0; +} + + +/* Start the pinentry event loop. The program will start to process + Assuan commands until it is finished or an error occurs. If an + error occurs, -1 is returned. Otherwise, 0 is returned. */ +int +pinentry_loop (void) +{ + return pinentry_loop2 (STDIN_FILENO, STDOUT_FILENO); +} diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry.h b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry.h new file mode 100644 index 00000000..b97f069b --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/pinentry/pinentry.h @@ -0,0 +1,364 @@ +/* pinentry.h - The interface for the PIN entry support library. + * Copyright (C) 2002, 2003, 2010, 2015, 2021 g10 Code GmbH + * + * This file is part of PINENTRY. + * + * PINENTRY is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * PINENTRY is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef PINENTRY_H +#define PINENTRY_H + +#ifdef __cplusplus +extern "C" { +#if 0 +} +#endif +#endif + +typedef enum { + PINENTRY_COLOR_NONE, PINENTRY_COLOR_DEFAULT, + PINENTRY_COLOR_BLACK, PINENTRY_COLOR_RED, + PINENTRY_COLOR_GREEN, PINENTRY_COLOR_YELLOW, + PINENTRY_COLOR_BLUE, PINENTRY_COLOR_MAGENTA, + PINENTRY_COLOR_CYAN, PINENTRY_COLOR_WHITE +} pinentry_color_t; + +struct pinentry +{ + /* The window title, or NULL. (Assuan: "SETTITLE TITLE".) */ + char *title; + /* The description to display, or NULL. (Assuan: "SETDESC + DESC".) */ + char *description; + /* The error message to display, or NULL. (Assuan: "SETERROR + MESSAGE".) */ + char *error; + /* The prompt to display, or NULL. (Assuan: "SETPROMPT + prompt".) */ + char *prompt; + /* The OK button text to display, or NULL. (Assuan: "SETOK + OK".) */ + char *ok; + /* The Not-OK button text to display, or NULL. This is the text for + the alternative option shown by the third button. (Assuan: + "SETNOTOK NOTOK".) */ + char *notok; + /* The Cancel button text to display, or NULL. (Assuan: "SETCANCEL + CANCEL".) */ + char *cancel; + + /* The buffer to store the secret into. */ + char *pin; + /* The length of the buffer. */ + int pin_len; + /* Whether the pin was read from an external cache (1) or entered by + the user (0). */ + int pin_from_cache; + + /* The name of the X display to use if X is available and supported. + (Assuan: "OPTION display DISPLAY".) */ + char *display; + /* The name of the terminal node to open if X not available or + supported. (Assuan: "OPTION ttyname TTYNAME".) */ + char *ttyname; + /* The type of the terminal. (Assuan: "OPTION ttytype TTYTYPE".) */ + char *ttytype_l; + /* Set the alert mode (none, beep or flash). */ + char *ttyalert; + /* The LC_CTYPE value for the terminal. (Assuan: "OPTION lc-ctype + LC_CTYPE".) */ + char *lc_ctype; + /* The LC_MESSAGES value for the terminal. (Assuan: "OPTION + lc-messages LC_MESSAGES".) */ + char *lc_messages; + + /* True if debug mode is requested. */ + int debug; + + /* The number of seconds before giving up while waiting for user input. */ + int timeout; + + /* True if caller should grab the keyboard. (Assuan: "OPTION grab" + or "OPTION no-grab".) */ + int grab; + + /* The PID of the owner or 0 if not known. The owner is the process + * which actually triggered the the pinentry. For example gpg. */ + unsigned long owner_pid; + + /* The numeric uid (user ID) of the owner process or -1 if not + * known. */ + int owner_uid; + + /* The malloced hostname of the owner or NULL. */ + char *owner_host; + + /* The window ID of the parent window over which the pinentry window + should be displayed. (Assuan: "OPTION parent-wid WID".) */ + int parent_wid; + + /* The name of an optional file which will be touched after a curses + entry has been displayed. (Assuan: "OPTION touch-file + FILENAME".) */ + char *touch_file; + + /* The frontend should set this to -1 if the user canceled the + request, and to the length of the PIN stored in pin + otherwise. */ + int result; + + /* The frontend should set this if the NOTOK button was pressed. */ + int canceled; + + /* The frontend should set this to true if an error with the local + conversion occurred. */ + int locale_err; + + /* The frontend should set this to a gpg-error so that commands are + able to return specific error codes. This is an ugly hack due to + the fact that pinentry_cmd_handler_t returns the length of the + passphrase or a negative error code. */ + int specific_err; + + /* The frontend may store a string with the error location here. */ + const char *specific_err_loc; + + /* The frontend may store a malloced string here to emit an ERROR + * status code with this extra info along with SPECIFIC_ERR. */ + char *specific_err_info; + + /* The frontend should set this to true if the window close button + has been used. This flag is used in addition to a regular return + value. */ + int close_button; + + /* The caller should set this to true if only one button is + required. This is useful for notification dialogs where only a + dismiss button is required. */ + int one_button; + + /* If true a second prompt for the passphrase is shown and the user + is expected to enter the same passphrase again. Pinentry checks + that both match. (Assuan: "SETREPEAT".) */ + char *repeat_passphrase; + + /* The string to show if a repeated passphrase does not match. + (Assuan: "SETREPEATERROR ERROR".) */ + char *repeat_error_string; + + /* Set to true if the passphrase has been entered a second time and + matches the first passphrase. */ + int repeat_okay; + + /* If this is not NULL, a passphrase quality indicator is shown. + There will also be an inquiry back to the caller to get an + indication of the quality for the passphrase entered so far. The + string is used as a label for the quality bar. (Assuan: + "SETQUALITYBAR LABEL".) */ + char *quality_bar; + + /* The tooltip to be shown for the qualitybar. Malloced or NULL. + (Assuan: "SETQUALITYBAR_TT TOOLTIP".) */ + char *quality_bar_tt; + + /* If this is not NULL, a generate action should be shown. + There will be an inquiry back to the caller to get such a + PIN. generate action. Malloced or NULL. + (Assuan: "SETGENPIN LABEL" .) */ + char *genpin_label; + + /* The tooltip to be shown for the generate action. Malloced or NULL. + (Assuan: "SETGENPIN_TT TOOLTIP".) */ + char *genpin_tt; + + /* Specifies whether passphrase formatting should be enabled. + (Assuan: "OPTION formatted-passphrase") */ + int formatted_passphrase; + + /* A hint to be shown near the passphrase input field if passphrase + formatting is enabled. Malloced or NULL. + (Assuan: "OPTION formatted-passphrase-hint=HINT".) */ + char *formatted_passphrase_hint; + + /* For the curses pinentry, the color of error messages. */ + pinentry_color_t color_fg; + int color_fg_bright; + pinentry_color_t color_bg; + pinentry_color_t color_so; + int color_so_bright; + + /* Malloced and i18ned default strings or NULL. These strings may + include an underscore character to indicate an accelerator key. + A double underscore represents a plain one. */ + /* (Assuan: "OPTION default-ok OK"). */ + char *default_ok; + /* (Assuan: "OPTION default-cancel CANCEL"). */ + char *default_cancel; + /* (Assuan: "OPTION default-prompt PROMPT"). */ + char *default_prompt; + /* (Assuan: "OPTION default-pwmngr + SAVE_PASSWORD_WITH_PASSWORD_MANAGER?"). */ + char *default_pwmngr; + /* (Assuan: "OPTION default-cf-visi + Do you really want to make your passphrase visible?"). */ + char *default_cf_visi; + /* (Assuan: "OPTION default-tt-visi + Make passphrase visible?"). */ + char *default_tt_visi; + /* (Assuan: "OPTION default-tt-hide + Hide passphrase"). */ + char *default_tt_hide; + /* (Assuan: "OPTION default-capshint + Caps Lock is on"). */ + char *default_capshint; + + /* Whether we are allowed to read the password from an external + cache. (Assuan: "OPTION allow-external-password-cache") */ + int allow_external_password_cache; + + /* We only try the cache once. */ + int tried_password_cache; + + /* A stable identifier for the key. (Assuan: "SETKEYINFO + KEYINFO".) */ + char *keyinfo; + + /* Whether we may cache the password (according to the user). */ + int may_cache_password; + + /* NOTE: If you add any additional fields to this structure, be sure + to update the initializer in pinentry/pinentry.c!!! */ + + /* For the quality indicator and genpin we need to do an inquiry. + Thus we need to save the assuan ctx. */ + void *ctx_assuan; + + /* An UTF-8 string with an invisible character used to override the + default in some pinentries. Only the first character is + used. */ + char *invisible_char; + + /* Whether the passphrase constraints are enforced by gpg-agent. + (Assuan: "OPTION constraints-enforce") */ + int constraints_enforce; + + /* A short translated hint for the user with the constraints for new + passphrases to be displayed near the passphrase input field. + Malloced or NULL. + (Assuan: "OPTION constraints-hint-short=At least 8 characters".) */ + char *constraints_hint_short; + + /* A longer translated hint for the user with the constraints for new + passphrases to be displayed for example as tooltip. Malloced or NULL. + (Assuan: "OPTION constraints-hint-long=The passphrase must ...".) */ + char *constraints_hint_long; + + /* A short translated title for an error dialog informing the user about + unsatisfied passphrase constraints. Malloced or NULL. + (Assuan: "OPTION constraints-error-title=Passphrase Not Allowed".) */ + char *constraints_error_title; + +}; +typedef struct pinentry *pinentry_t; + + +/* The pinentry command handler type processes the pinentry request + PIN. If PIN->pin is zero, request a confirmation, otherwise a PIN + entry. On confirmation, the function should return TRUE if + confirmed, and FALSE otherwise. On PIN entry, the function should + return -1 if an error occurred or the user cancelled the operation + and 1 otherwise. */ +typedef int (*pinentry_cmd_handler_t) (pinentry_t pin); + +/* Start the pinentry event loop. The program will start to process + Assuan commands until it is finished or an error occurs. If an + error occurs, -1 is returned and errno indicates the type of an + error. Otherwise, 0 is returned. */ +int pinentry_loop (void); + +/* The same as above but allows to specify the i/o descriptors. + * infd and outfd will be duplicated in this function so the caller + * still has to close them if necessary. + */ +int pinentry_loop2 (int infd, int outfd); + +const char *pinentry_get_pgmname (void); + +char *pinentry_get_title (pinentry_t pe); + +/* Run a quality inquiry for PASSPHRASE of LENGTH. */ +int pinentry_inq_quality (pinentry_t pin, + const char *passphrase, size_t length); + +/* Run a checkpin inquiry for PASSPHRASE of LENGTH. Returns NULL, if the + passphrase satisfies the constraints. Otherwise, returns a malloced error + string. */ +char *pinentry_inq_checkpin (pinentry_t pin, + const char *passphrase, size_t length); + +/* Run a genpin iquriry. Returns a malloced string or NULL */ +char *pinentry_inq_genpin (pinentry_t pin); + +/* Try to make room for at least LEN bytes for the pin in the pinentry + PIN. Returns new buffer on success and 0 on failure. */ +char *pinentry_setbufferlen (pinentry_t pin, int len); + +/* Use the buffer at BUFFER for PIN->PIN. BUFFER must be NULL or + allocated using secmem_alloc. LEN is the size of the buffer. If + it is unknown, but BUFFER is a NUL terminated string, you pass 0 to + just use strlen(buffer)+1. */ +void pinentry_setbuffer_use (pinentry_t pin, char *buffer, int len); + +/* Initialize the secure memory subsystem, drop privileges and + return. Must be called early. */ +void pinentry_init (const char *pgmname); + +/* Return true if either DISPLAY is set or ARGV contains the string + "--display". */ +int pinentry_have_display (int argc, char **argv); + +/* Parse the command line options. May exit the program if only help + or version output is requested. */ +void pinentry_parse_opts (int argc, char *argv[]); + +/* Set the optional flag used with getinfo. */ +void pinentry_set_flavor_flag (const char *string); + + + +/* The caller must define this variable to process assuan commands. */ +extern pinentry_cmd_handler_t pinentry_cmd_handler; + + + + + +#ifdef HAVE_W32_SYSTEM +/* Windows declares sleep as obsolete, but provides a definition for + _sleep but non for the still existing sleep. */ +#define sleep(a) _sleep ((a)) +#endif /*HAVE_W32_SYSTEM*/ + + + +#if 0 +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif /* PINENTRY_H */ |