diff --git a/tools/Makefile.am b/tools/Makefile.am
index e4fd81c5d..4833bff5e 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,182 +1,192 @@
# Makefile.am - Tools directory
# Copyright (C) 2003, 2007 Free Software Foundation, Inc.
#
# This file is part of GnuPG.
#
# GnuPG 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 3 of the License, or
# (at your option) any later version.
#
# GnuPG 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 .
EXTRA_DIST = \
Manifest watchgnupg.c no-libgcrypt.c \
addgnupghome applygnupgdefaults \
lspgpot mail-signed-keys convert-from-106 sockprox.c \
- ccidmon.c ChangeLog-2011 gpg-connect-agent-w32info.rc
-
+ ccidmon.c ChangeLog-2011 \
+ gpg-connect-agent-w32info.rc \
+ gpg-card-tool-w32info.rc
AM_CPPFLAGS =
include $(top_srcdir)/am/cmacros.am
if HAVE_W32_SYSTEM
-resource_objs += gpg-connect-agent-w32info.o
+gpg_connect_agent_rc_objs = gpg-connect-agent-w32info.o
+gpg_card_tool_rc_objs = gpg-card-tool-w32info.o
+resource_objs += $(gpg_connect_agent_rc_objs) $(gpg_card_tool_rc_objs)
endif
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS) $(LIBASSUAN_CFLAGS)
sbin_SCRIPTS = addgnupghome applygnupgdefaults
if BUILD_SYMCRYPTRUN
symcryptrun = symcryptrun
else
symcryptrun =
endif
if BUILD_WKS_TOOLS
gpg_wks_server = gpg-wks-server
else
gpg_wks_server =
endif
libexec_PROGRAMS = gpg-wks-client gpg-pair-tool
-bin_PROGRAMS = gpgconf gpg-connect-agent ${symcryptrun}
+bin_PROGRAMS = gpgconf gpg-connect-agent gpg-card-tool ${symcryptrun}
if !HAVE_W32_SYSTEM
bin_PROGRAMS += watchgnupg gpgparsemail ${gpg_wks_server}
endif
if !DISABLE_REGEX
libexec_PROGRAMS += gpg-check-pattern
endif
if !HAVE_W32CE_SYSTEM
noinst_PROGRAMS = clean-sat make-dns-cert gpgsplit
endif
if !HAVE_W32CE_SYSTEM
if BUILD_GPGTAR
bin_PROGRAMS += gpgtar
else
noinst_PROGRAMS += gpgtar
endif
endif
common_libs = $(libcommon)
commonpth_libs = $(libcommonpth)
# Some modules require PTH under W32CE.
if HAVE_W32CE_SYSTEM
maybe_commonpth_libs = $(commonpth_libs)
else
maybe_commonpth_libs = $(common_libs)
endif
if HAVE_W32CE_SYSTEM
pwquery_libs =
else
pwquery_libs = ../common/libsimple-pwquery.a
endif
if HAVE_W32CE_SYSTEM
opt_libassuan_libs = $(LIBASSUAN_LIBS)
endif
gpgsplit_LDADD = $(common_libs) \
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
$(ZLIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV)
gpgconf_SOURCES = gpgconf.c gpgconf.h gpgconf-comp.c
# common sucks in gpg-error, will they, nil they (some compilers
# do not eliminate the supposed-to-be-unused-inline-functions).
gpgconf_LDADD = $(maybe_commonpth_libs) $(opt_libassuan_libs) \
$(LIBINTL) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(NETLIBS) \
$(LIBICONV) $(W32SOCKLIBS)
gpgconf_LDFLAGS = $(extra_bin_ldflags)
gpgparsemail_SOURCES = gpgparsemail.c rfc822parse.c rfc822parse.h
gpgparsemail_LDADD =
symcryptrun_SOURCES = symcryptrun.c
symcryptrun_LDADD = $(LIBUTIL_LIBS) $(common_libs) $(pwquery_libs) \
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) \
$(LIBICONV) $(NETLIBS) $(W32SOCKLIBS) $(LIBASSUAN_LIBS)
watchgnupg_SOURCES = watchgnupg.c
watchgnupg_LDADD = $(NETLIBS)
gpg_connect_agent_SOURCES = gpg-connect-agent.c
gpg_connect_agent_LDADD = ../common/libgpgrl.a $(common_libs) \
$(LIBASSUAN_LIBS) $(LIBGCRYPT_LIBS) \
$(GPG_ERROR_LIBS) \
$(LIBREADLINE) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
- $(resource_objs)
+ $(gpg_connect_agent_rc_objs)
+
+gpg_card_tool_SOURCES = gpg-card-tool.c
+gpg_card_tool_LDADD = ../common/libgpgrl.a $(common_libs) \
+ $(LIBASSUAN_LIBS) $(LIBGCRYPT_LIBS) \
+ $(GPG_ERROR_LIBS) \
+ $(LIBREADLINE) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
+ $(gpg_card_tool_rc_objs)
if !DISABLE_REGEX
gpg_check_pattern_SOURCES = gpg-check-pattern.c
gpg_check_pattern_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS) $(INCICONV)
gpg_check_pattern_LDADD = $(common_libs) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
$(LIBINTL) $(NETLIBS) $(LIBICONV) $(W32SOCKLIBS) \
$(LIBICONV)
endif
gpgtar_SOURCES = \
gpgtar.c gpgtar.h \
gpgtar-create.c \
gpgtar-extract.c \
gpgtar-list.c
gpgtar_CFLAGS = $(GPG_ERROR_CFLAGS)
gpgtar_LDADD = $(libcommon) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
$(LIBINTL) $(NETLIBS) $(LIBICONV) $(W32SOCKLIBS)
gpg_wks_server_SOURCES = \
gpg-wks-server.c \
gpg-wks.h \
wks-util.c \
wks-receive.c \
rfc822parse.c rfc822parse.h \
mime-parser.c mime-parser.h \
mime-maker.c mime-maker.h \
send-mail.c send-mail.h
gpg_wks_server_CFLAGS = $(GPG_ERROR_CFLAGS) $(INCICONV)
gpg_wks_server_LDADD = $(libcommon) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
$(LIBINTL) $(LIBICONV)
gpg_wks_client_SOURCES = \
gpg-wks-client.c \
gpg-wks.h \
wks-util.c \
wks-receive.c \
rfc822parse.c rfc822parse.h \
mime-parser.c mime-parser.h \
mime-maker.h mime-maker.c \
send-mail.c send-mail.h \
call-dirmngr.c call-dirmngr.h
gpg_wks_client_CFLAGS = $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS) $(INCICONV)
gpg_wks_client_LDADD = $(libcommon) \
$(LIBASSUAN_LIBS) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
$(LIBINTL) $(LIBICONV)
gpg_pair_tool_SOURCES = \
gpg-pair-tool.c
gpg_pair_tool_CFLAGS = $(GPG_ERROR_CFLAGS) $(INCICONV)
gpg_pair_tool_LDADD = $(libcommon) \
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
$(LIBINTL) $(LIBICONV) $(W32SOCKLIBS)
# Make sure that all libs are build before we use them. This is
# important for things like make -j2.
$(PROGRAMS): $(common_libs) $(pwquery_libs) ../common/libgpgrl.a
diff --git a/tools/gpg-connect-agent-w32info.rc b/tools/gpg-card-tool-w32info.rc
similarity index 83%
copy from tools/gpg-connect-agent-w32info.rc
copy to tools/gpg-card-tool-w32info.rc
index 4e7b19d35..6937c3e34 100644
--- a/tools/gpg-connect-agent-w32info.rc
+++ b/tools/gpg-card-tool-w32info.rc
@@ -1,51 +1,51 @@
-/* scdaemon-w32info.rc -*- c -*-
- * Copyright (C) 2013 g10 Code GmbH
+/* gpg-card-toolt-w32info.rc -*- c -*-
+ * Copyright (C) 2019 g10 Code GmbH
*
* This file is free software; as a special exception the author 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.
*/
#include "afxres.h"
#include "../common/w32info-rc.h"
1 ICON "../common/gnupg.ico"
1 VERSIONINFO
FILEVERSION W32INFO_VI_FILEVERSION
PRODUCTVERSION W32INFO_VI_PRODUCTVERSION
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x01L /* VS_FF_DEBUG (0x1)*/
#else
FILEFLAGS 0x00L
#endif
FILEOS 0x40004L /* VOS_NT (0x40000) | VOS__WINDOWS32 (0x4) */
FILETYPE 0x1L /* VFT_APP (0x1) */
FILESUBTYPE 0x0L /* VFT2_UNKNOWN */
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" /* US English (0409), Unicode (04b0) */
BEGIN
- VALUE "FileDescription", L"GnuPG\x2019s command line access \
+ VALUE "FileDescription", L"GnuPG\x2019s card tool \
to the agent\0"
- VALUE "InternalName", "gpg-connect-agent\0"
- VALUE "OriginalFilename", "gpg-connect-agent.exe\0"
+ VALUE "InternalName", "gpg-card-tool\0"
+ VALUE "OriginalFilename", "gpg-card-tool.exe\0"
VALUE "ProductName", W32INFO_PRODUCTNAME
VALUE "ProductVersion", W32INFO_PRODUCTVERSION
VALUE "CompanyName", W32INFO_COMPANYNAME
VALUE "FileVersion", W32INFO_FILEVERSION
VALUE "LegalCopyright", W32INFO_LEGALCOPYRIGHT
VALUE "Comments", W32INFO_COMMENTS
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 0x4b0
END
END
diff --git a/tools/gpg-card-tool.c b/tools/gpg-card-tool.c
new file mode 100644
index 000000000..91f04108e
--- /dev/null
+++ b/tools/gpg-card-tool.c
@@ -0,0 +1,869 @@
+/* gpg-card-tool.c - An interactive tool to work with cards.
+ * Copyright (C) 2019 g10 Code GmbH Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This file 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 Lesser 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 .
+ * SPDX-License-Identifier: GPL-3.0+
+ */
+
+#include
+#include
+#include
+#include
+#ifdef HAVE_LIBREADLINE
+# define GNUPG_LIBREADLINE_H_INCLUDED
+# include
+#endif /*HAVE_LIBREADLINE*/
+
+#include "../common/util.h"
+#include "../common/status.h"
+#include "../common/i18n.h"
+#include "../common/init.h"
+#include "../common/sysutils.h"
+#include "../common/asshelp.h"
+#include "../common/userids.h"
+#include "../common/ccparray.h"
+#include "../common/exectool.h"
+#include "../common/ttyio.h"
+
+#define CONTROL_D ('D' - 'A' + 1)
+
+/* Constants to identify the commands and options. */
+enum cmd_and_opt_values
+ {
+ aNull = 0,
+
+ oQuiet = 'q',
+ oVerbose = 'v',
+
+ oDebug = 500,
+
+ oGpgProgram,
+ oGpgsmProgram,
+ oStatusFD,
+ oWithColons,
+
+ oDummy
+ };
+
+
+/* The list of commands and options. */
+static ARGPARSE_OPTS opts[] = {
+ ARGPARSE_group (300, ("@Commands:\n ")),
+
+ ARGPARSE_group (301, ("@\nOptions:\n ")),
+
+ ARGPARSE_s_n (oVerbose, "verbose", ("verbose")),
+ ARGPARSE_s_n (oQuiet, "quiet", ("be somewhat more quiet")),
+ ARGPARSE_s_s (oDebug, "debug", "@"),
+ ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
+ ARGPARSE_s_s (oGpgsmProgram, "gpgsm", "@"),
+ ARGPARSE_s_i (oStatusFD, "status-fd", N_("|FD|write status info to this FD")),
+ ARGPARSE_s_n (oWithColons, "with-colons", "@"),
+
+ ARGPARSE_end ()
+};
+
+/* Debug values and macros. */
+#define DBG_IPC_VALUE 1024 /* Debug assuan communication. */
+#define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
+
+
+/* The list of supported debug flags. */
+static struct debug_flags_s debug_flags [] =
+ {
+ { DBG_IPC_VALUE , "ipc" },
+ { DBG_EXTPROG_VALUE, "extprog" },
+ { 0, NULL }
+ };
+
+
+
+/* We keep all global options in the structure OPT. */
+struct
+{
+ int verbose;
+ unsigned int debug;
+ int quiet;
+ int with_colons;
+ const char *gpg_program;
+ const char *gpgsm_program;
+} opt;
+
+
+static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
+static void interactive_loop (void);
+#ifdef HAVE_LIBREADLINE
+static char **command_completion (const char *text, int start, int end);
+#endif /*HAVE_LIBREADLINE*/
+
+
+
+/* Print usage information and provide strings for help. */
+static const char *
+my_strusage( int level )
+{
+ const char *p;
+
+ switch (level)
+ {
+ case 11: p = "gpg-card-tool"; break;
+ case 12: p = "@GNUPG@"; break;
+ case 13: p = VERSION; break;
+ case 17: p = PRINTABLE_OS_NAME; break;
+ case 19: p = ("Please report bugs to <@EMAIL@>.\n"); break;
+
+ case 1:
+ case 40:
+ p = ("Usage: gpg-card-tool [command] [options] [args] (-h for help)");
+ break;
+ case 41:
+ p = ("Syntax: gpg-card-tool [command] [options] [args]\n"
+ "Tool to configure cards and tokens\n");
+ break;
+
+ default: p = NULL; break;
+ }
+ return p;
+}
+
+
+static void
+wrong_args (const char *text)
+{
+ es_fprintf (es_stderr, _("usage: %s [options] %s\n"), strusage (11), text);
+ exit (2);
+}
+
+
+
+/* Command line parsing. */
+static enum cmd_and_opt_values
+parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
+{
+ enum cmd_and_opt_values cmd = 0;
+ int no_more_options = 0;
+
+ while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
+ {
+ switch (pargs->r_opt)
+ {
+ case oQuiet: opt.quiet = 1; break;
+ case oVerbose: opt.verbose++; break;
+ case oDebug:
+ if (parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags))
+ {
+ pargs->r_opt = ARGPARSE_INVALID_ARG;
+ pargs->err = ARGPARSE_PRINT_ERROR;
+ }
+ break;
+
+ case oGpgProgram:
+ opt.gpg_program = pargs->r.ret_str;
+ break;
+ case oGpgsmProgram:
+ opt.gpgsm_program = pargs->r.ret_str;
+ break;
+ case oStatusFD:
+ gnupg_set_status_fd (translate_sys2libc_fd_int (pargs->r.ret_int, 1));
+ break;
+ case oWithColons:
+ opt.with_colons = 1;
+ break;
+
+ default: pargs->err = 2; break;
+ }
+ }
+
+ return cmd;
+}
+
+
+
+/* gpg-card-tool main. */
+int
+main (int argc, char **argv)
+{
+ gpg_error_t err;
+ ARGPARSE_ARGS pargs;
+ enum cmd_and_opt_values cmd;
+
+ gnupg_reopen_std ("gpg-card-tool");
+ set_strusage (my_strusage);
+ gnupg_rl_initialize ();
+ log_set_prefix ("gpg-card-tool", GPGRT_LOG_WITH_PREFIX);
+
+ /* Make sure that our subsystems are ready. */
+ i18n_init();
+ init_common_subsystems (&argc, &argv);
+
+ assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
+ setup_libassuan_logging (&opt.debug, NULL);
+
+ /* Parse the command line. */
+ pargs.argc = &argc;
+ pargs.argv = &argv;
+ pargs.flags = ARGPARSE_FLAG_KEEP;
+ cmd = parse_arguments (&pargs, opts);
+
+ if (log_get_errorcount (0))
+ exit (2);
+
+ /* Print a warning if an argument looks like an option. */
+ if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
+ {
+ int i;
+
+ for (i=0; i < argc; i++)
+ if (argv[i][0] == '-' && argv[i][1] == '-')
+ log_info (("NOTE: '%s' is not considered an option\n"), argv[i]);
+ }
+
+ /* Set defaults for non given options. */
+ if (!opt.gpg_program)
+ opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
+ if (!opt.gpgsm_program)
+ opt.gpgsm_program = gnupg_module_name (GNUPG_MODULE_NAME_GPGSM);
+
+ /* Run the selected command. */
+ switch (cmd)
+ {
+ default:
+ interactive_loop ();
+ err = 0;
+ break;
+ }
+
+ if (err)
+ gnupg_status_printf (STATUS_FAILURE, "- %u", err);
+ else if (log_get_errorcount (0))
+ gnupg_status_printf (STATUS_FAILURE, "- %u", GPG_ERR_GENERAL);
+ else
+ gnupg_status_printf (STATUS_SUCCESS, NULL);
+ return log_get_errorcount (0)? 1:0;
+}
+
+
+
+/* Print all available information about the current card. */
+static void
+print_card_status (char *serialno, size_t serialnobuflen)
+{
+ /* struct agent_card_info_s info; */
+ /* PKT_public_key *pk = xcalloc (1, sizeof *pk); */
+ /* kbnode_t keyblock = NULL; */
+ /* int rc; */
+ /* unsigned int uval; */
+ /* const unsigned char *thefpr; */
+ /* unsigned int thefprlen; */
+ /* int i; */
+
+ /* if (serialno && serialnobuflen) */
+ /* *serialno = 0; */
+
+ /* rc = agent_scd_learn (&info, 0); */
+ /* if (rc) */
+ /* { */
+ /* if (opt.with_colons) */
+ /* es_fputs ("AID:::\n", fp); */
+ /* log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (rc)); */
+ /* xfree (pk); */
+ /* return; */
+ /* } */
+
+ /* if (opt.with_colons) */
+ /* es_fprintf (fp, "Reader:%s:", info.reader? info.reader : ""); */
+ /* else */
+ /* tty_fprintf (fp, "Reader ...........: %s\n", */
+ /* info.reader? info.reader : "[none]"); */
+ /* if (opt.with_colons) */
+ /* es_fprintf (fp, "AID:%s:", info.serialno? info.serialno : ""); */
+ /* else */
+ /* tty_fprintf (fp, "Application ID ...: %s\n", */
+ /* info.serialno? info.serialno : "[none]"); */
+ /* if (!info.serialno || strncmp (info.serialno, "D27600012401", 12) */
+ /* || strlen (info.serialno) != 32 ) */
+ /* { */
+ /* if (info.apptype && !strcmp (info.apptype, "NKS")) */
+ /* { */
+ /* if (opt.with_colons) */
+ /* es_fputs ("netkey-card:\n", fp); */
+ /* log_info ("this is a NetKey card\n"); */
+ /* } */
+ /* else if (info.apptype && !strcmp (info.apptype, "DINSIG")) */
+ /* { */
+ /* if (opt.with_colons) */
+ /* es_fputs ("dinsig-card:\n", fp); */
+ /* log_info ("this is a DINSIG compliant card\n"); */
+ /* } */
+ /* else if (info.apptype && !strcmp (info.apptype, "P15")) */
+ /* { */
+ /* if (opt.with_colons) */
+ /* es_fputs ("pkcs15-card:\n", fp); */
+ /* log_info ("this is a PKCS#15 compliant card\n"); */
+ /* } */
+ /* else if (info.apptype && !strcmp (info.apptype, "GELDKARTE")) */
+ /* { */
+ /* if (opt.with_colons) */
+ /* es_fputs ("geldkarte-card:\n", fp); */
+ /* log_info ("this is a Geldkarte compliant card\n"); */
+ /* } */
+ /* else */
+ /* { */
+ /* if (opt.with_colons) */
+ /* es_fputs ("unknown:\n", fp); */
+ /* } */
+ /* log_info ("not an OpenPGP card\n"); */
+ /* agent_release_card_info (&info); */
+ /* xfree (pk); */
+ /* return; */
+ /* } */
+
+ /* if (!serialno) */
+ /* ; */
+ /* else if (strlen (info.serialno)+1 > serialnobuflen) */
+ /* log_error ("serial number longer than expected\n"); */
+ /* else */
+ /* strcpy (serialno, info.serialno); */
+
+ /* if (opt.with_colons) */
+ /* es_fputs ("openpgp-card:\n", fp); */
+
+
+ /* tty_fprintf (fp, "Version ..........: %.1s%c.%.1s%c\n", */
+ /* info.serialno[12] == '0'?"":info.serialno+12, */
+ /* info.serialno[13], */
+ /* info.serialno[14] == '0'?"":info.serialno+14, */
+ /* info.serialno[15]); */
+ /* tty_fprintf (fp, "Manufacturer .....: %s\n", */
+ /* get_manufacturer (xtoi_2(info.serialno+16)*256 */
+ /* + xtoi_2 (info.serialno+18))); */
+ /* tty_fprintf (fp, "Serial number ....: %.8s\n", info.serialno+20); */
+
+ /* print_isoname (fp, "Name of cardholder: ", "name", info.disp_name); */
+ /* print_name (fp, "Language prefs ...: ", info.disp_lang); */
+ /* tty_fprintf (fp, "Salutation .......: %s\n", */
+ /* info.disp_sex == 1? _("Mr."): */
+ /* info.disp_sex == 2? _("Mrs.") : ""); */
+ /* print_name (fp, "URL of public key : ", info.pubkey_url); */
+ /* print_name (fp, "Login data .......: ", info.login_data); */
+ /* if (info.private_do[0]) */
+ /* print_name (fp, "Private DO 1 .....: ", info.private_do[0]); */
+ /* if (info.private_do[1]) */
+ /* print_name (fp, "Private DO 2 .....: ", info.private_do[1]); */
+ /* if (info.private_do[2]) */
+ /* print_name (fp, "Private DO 3 .....: ", info.private_do[2]); */
+ /* if (info.private_do[3]) */
+ /* print_name (fp, "Private DO 4 .....: ", info.private_do[3]); */
+ /* if (info.cafpr1len) */
+ /* { */
+ /* tty_fprintf (fp, "CA fingerprint %d .:", 1); */
+ /* print_shax_fpr (fp, info.cafpr1, info.cafpr1len); */
+ /* } */
+ /* if (info.cafpr2len) */
+ /* { */
+ /* tty_fprintf (fp, "CA fingerprint %d .:", 2); */
+ /* print_shax_fpr (fp, info.cafpr2, info.cafpr2len); */
+ /* } */
+ /* if (info.cafpr3len) */
+ /* { */
+ /* tty_fprintf (fp, "CA fingerprint %d .:", 3); */
+ /* print_shax_fpr (fp, info.cafpr3, info.cafpr3len); */
+ /* } */
+ /* tty_fprintf (fp, "Signature PIN ....: %s\n", */
+ /* info.chv1_cached? _("not forced"): _("forced")); */
+ /* if (info.key_attr[0].algo) */
+ /* { */
+ /* tty_fprintf (fp, "Key attributes ...:"); */
+ /* for (i=0; i < DIM (info.key_attr); i++) */
+ /* if (info.key_attr[i].algo == PUBKEY_ALGO_RSA) */
+ /* tty_fprintf (fp, " rsa%u", info.key_attr[i].nbits); */
+ /* else if (info.key_attr[i].algo == PUBKEY_ALGO_ECDH */
+ /* || info.key_attr[i].algo == PUBKEY_ALGO_ECDSA */
+ /* || info.key_attr[i].algo == PUBKEY_ALGO_EDDSA) */
+ /* { */
+ /* const char *curve_for_print = "?"; */
+
+ /* if (info.key_attr[i].curve) */
+ /* { */
+ /* const char *oid; */
+ /* oid = openpgp_curve_to_oid (info.key_attr[i].curve, NULL); */
+ /* if (oid) */
+ /* curve_for_print = openpgp_oid_to_curve (oid, 0); */
+ /* } */
+ /* tty_fprintf (fp, " %s", curve_for_print); */
+ /* } */
+ /* tty_fprintf (fp, "\n"); */
+ /* } */
+ /* tty_fprintf (fp, "Max. PIN lengths .: %d %d %d\n", */
+ /* info.chvmaxlen[0], info.chvmaxlen[1], info.chvmaxlen[2]); */
+ /* tty_fprintf (fp, "PIN retry counter : %d %d %d\n", */
+ /* info.chvretry[0], info.chvretry[1], info.chvretry[2]); */
+ /* tty_fprintf (fp, "Signature counter : %lu\n", info.sig_counter); */
+ /* if (info.extcap.kdf) */
+ /* { */
+ /* tty_fprintf (fp, "KDF setting ......: %s\n", */
+ /* info.kdf_do_enabled ? "on" : "off"); */
+ /* } */
+ /* if (info.extcap.bt) */
+ /* { */
+ /* tty_fprintf (fp, "UIF setting ......: Sign=%s Decrypt=%s Auth=%s\n", */
+ /* info.uif[0] ? "on" : "off", info.uif[1] ? "on" : "off", */
+ /* info.uif[2] ? "on" : "off"); */
+ /* } */
+ /* tty_fprintf (fp, "Signature key ....:"); */
+ /* print_shax_fpr (fp, info.fpr1len? info.fpr1:NULL, info.fpr1len); */
+ /* if (info.fpr1len && info.fpr1time) */
+ /* { */
+ /* tty_fprintf (fp, " created ....: %s\n", */
+ /* isotimestamp (info.fpr1time)); */
+ /* print_keygrip (fp, info.grp1); */
+ /* } */
+ /* tty_fprintf (fp, "Encryption key....:"); */
+ /* print_shax_fpr (fp, info.fpr2len? info.fpr2:NULL, info.fpr2len); */
+ /* if (info.fpr2len && info.fpr2time) */
+ /* { */
+ /* tty_fprintf (fp, " created ....: %s\n", */
+ /* isotimestamp (info.fpr2time)); */
+ /* print_keygrip (fp, info.grp2); */
+ /* } */
+ /* tty_fprintf (fp, "Authentication key:"); */
+ /* print_shax_fpr (fp, info.fpr3len? info.fpr3:NULL, info.fpr3len); */
+ /* if (info.fpr3len && info.fpr3time) */
+ /* { */
+ /* tty_fprintf (fp, " created ....: %s\n", */
+ /* isotimestamp (info.fpr3time)); */
+ /* print_keygrip (fp, info.grp3); */
+ /* } */
+ /* tty_fprintf (fp, "General key info..: "); */
+
+ /* thefpr = (info.fpr1len? info.fpr1 : info.fpr2len? info.fpr2 : */
+ /* info.fpr3len? info.fpr3 : NULL); */
+ /* thefprlen = (info.fpr1len? info.fpr1len : info.fpr2len? info.fpr2len : */
+ /* info.fpr3len? info.fpr3len : 0); */
+ /* /\* If the fingerprint is all 0xff, the key has no associated */
+ /* OpenPGP certificate. *\/ */
+ /* if ( thefpr && !fpr_is_ff (thefpr, thefprlen) */
+ /* && !get_pubkey_byfprint (ctrl, pk, &keyblock, thefpr, thefprlen)) */
+ /* { */
+ /* print_pubkey_info (ctrl, fp, pk); */
+ /* if (keyblock) */
+ /* print_card_key_info (fp, keyblock); */
+ /* } */
+ /* else */
+ /* tty_fprintf (fp, "[none]\n"); */
+
+ /* release_kbnode (keyblock); */
+ /* free_public_key (pk); */
+ /* agent_release_card_info (&info); */
+}
+
+
+
+static void
+cmd_verify (void)
+{
+ /* agent_scd_checkpin (serialnobuf); */
+}
+
+
+static void
+cmd_name (void)
+{
+ /* change_name (); */
+}
+
+
+static void
+cmd_url (void)
+{
+ /* change_url (); */
+}
+
+
+static void
+cmd_fetch (void)
+{
+ /* fetch_url (); */
+}
+
+
+static void
+cmd_login (char *arg_string)
+{
+ /* change_login (arg_string); */
+}
+
+
+static void
+cmd_lang (void)
+{
+ /* change_lang (); */
+}
+
+
+static void
+cmd_salut (void)
+{
+ /* change_salut (); */
+}
+
+
+static void
+cmd_cafpr (int arg_number)
+{
+ if ( arg_number < 1 || arg_number > 3 )
+ tty_printf ("usage: cafpr N\n"
+ " 1 <= N <= 3\n");
+ /* else */
+ /* change_cafpr (arg_number); */
+}
+
+
+static void
+cmd_privatedo (int arg_number, char *arg_string)
+{
+ if ( arg_number < 1 || arg_number > 4 )
+ tty_printf ("usage: privatedo N\n"
+ " 1 <= N <= 4\n");
+ /* else */
+ /* change_private_do (arg_string, arg_number); */
+}
+
+
+static void
+cmd_writecert (int arg_number, char *arg_rest)
+{
+ if ( arg_number != 3 )
+ tty_printf ("usage: writecert 3 < FILE\n");
+ /* else */
+ /* change_cert (arg_rest); */
+}
+
+
+static void
+cmd_readcert (int arg_number, char *arg_rest)
+{
+ if ( arg_number != 3 )
+ tty_printf ("usage: readcert 3 > FILE\n");
+ /* else */
+ /* read_cert (arg_rest); */
+}
+
+
+static void
+cmd_forcesig (void)
+{
+ /* toggle_forcesig (); */
+}
+
+
+static void
+cmd_generate (void)
+{
+ /* generate_card_keys (); */
+}
+
+
+static void
+cmd_passwd (int allow_admin)
+{
+ /* change_pin (0, allow_admin); */
+}
+
+
+static void
+cmd_unblock (int allow_admin)
+{
+ /* change_pin (1, allow_admin); */
+}
+
+
+static void
+cmd_factoryreset (void)
+{
+ /* factory_reset (); */
+}
+
+
+static void
+cmd_kdfsetup (char *argstring)
+{
+ /* kdf_setup (arg_string); */
+}
+
+
+static void
+cmd_keyattr (void)
+{
+ /* key_attr (); */
+}
+
+
+static void
+cmd_uif (int arg_number, char *arg_rest)
+{
+ if ( arg_number < 1 || arg_number > 3 )
+ tty_printf ("usage: uif N [on|off|permanent]\n"
+ " 1 <= N <= 3\n");
+ /* else */
+ /* uif (arg_number, arg_rest); */
+}
+
+
+
+/* Data used by the command parser. This needs to be outside of the
+ * function scope to allow readline based command completion. */
+enum cmdids
+ {
+ cmdNOP = 0,
+ cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY,
+ cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSALUT, cmdCAFPR,
+ cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
+ cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP,
+ cmdKEYATTR, cmdUIF,
+ cmdINVCMD
+ };
+
+static struct
+{
+ const char *name;
+ enum cmdids id;
+ int admin_only;
+ const char *desc;
+} cmds[] = {
+ { "quit" , cmdQUIT , 0, N_("quit this menu")},
+ { "q" , cmdQUIT , 0, NULL },
+ { "admin" , cmdADMIN , 0, N_("show admin commands")},
+ { "help" , cmdHELP , 0, N_("show this help")},
+ { "?" , cmdHELP , 0, NULL },
+ { "list" , cmdLIST , 0, N_("list all available data")},
+ { "l" , cmdLIST , 0, NULL },
+ { "debug" , cmdDEBUG , 0, NULL },
+ { "name" , cmdNAME , 1, N_("change card holder's name")},
+ { "url" , cmdURL , 1, N_("change URL to retrieve key")},
+ { "fetch" , cmdFETCH , 0, N_("fetch the key specified in the card URL")},
+ { "login" , cmdLOGIN , 1, N_("change the login name")},
+ { "lang" , cmdLANG , 1, N_("change the language preferences")},
+ { "salutation",cmdSALUT, 1, N_("change card holder's salutation")},
+ { "cafpr" , cmdCAFPR , 1, N_("change a CA fingerprint")},
+ { "forcesig", cmdFORCESIG, 1, N_("toggle the signature force PIN flag")},
+ { "generate", cmdGENERATE, 1, N_("generate new keys")},
+ { "passwd" , cmdPASSWD, 0, N_("menu to change or unblock the PIN")},
+ { "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
+ { "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code")},
+ { "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
+ { "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
+ { "key-attr", cmdKEYATTR, 1, N_("change the key attribute")},
+ { "uif", cmdUIF, 1, N_("change the User Interaction Flag")},
+ /* Note, that we do not announce these command yet. */
+ { "privatedo", cmdPRIVATEDO, 0, NULL },
+ { "readcert", cmdREADCERT, 0, NULL },
+ { "writecert", cmdWRITECERT, 1, NULL },
+ { NULL, cmdINVCMD, 0, NULL }
+};
+
+
+/* The main loop. */
+static void
+interactive_loop (void)
+{
+ char *answer = NULL; /* The input line. */
+ enum cmdids cmd = cmdNOP; /* The command. */
+ int cmd_admin_only; /* The command is an admin only command. */
+ int arg_number; /* The first argument as a number. */
+ char *arg_string = ""; /* The first argument as a string. */
+ char *arg_rest = ""; /* The remaining arguments. */
+ int redisplay = 1; /* Whether to redisplay the main info. */
+ int allow_admin = 0; /* Whether admin commands are allowed. */
+ char serialnobuf[50];
+ char *p;
+ int i;
+
+ for (;;)
+ {
+
+ tty_printf ("\n");
+ if (redisplay)
+ {
+ print_card_status (serialnobuf, DIM (serialnobuf));
+ tty_printf("\n");
+ redisplay = 0;
+ }
+
+ do
+ {
+ xfree (answer);
+ tty_enable_completion (command_completion);
+ answer = tty_get (_("gpg/card> "));
+ tty_kill_prompt();
+ tty_disable_completion ();
+ trim_spaces(answer);
+ }
+ while ( *answer == '#' );
+
+ arg_number = 0;
+ cmd_admin_only = 0;
+ if (!*answer)
+ cmd = cmdLIST; /* We default to the list command */
+ else if (*answer == CONTROL_D)
+ cmd = cmdQUIT;
+ else
+ {
+ if ((p=strchr (answer,' ')))
+ {
+ *p++ = 0;
+ trim_spaces (answer);
+ trim_spaces (p);
+ arg_number = atoi (p);
+ arg_string = p;
+ arg_rest = p;
+ while (digitp (arg_rest))
+ arg_rest++;
+ while (spacep (arg_rest))
+ arg_rest++;
+ }
+
+ for (i=0; cmds[i].name; i++ )
+ if (!ascii_strcasecmp (answer, cmds[i].name ))
+ break;
+
+ cmd = cmds[i].id;
+ cmd_admin_only = cmds[i].admin_only;
+ }
+
+ if (!allow_admin && cmd_admin_only)
+ {
+ tty_printf ("\n");
+ tty_printf (_("Admin-only command\n"));
+ continue;
+ }
+
+ switch (cmd)
+ {
+ case cmdNOP:
+ break;
+
+ case cmdQUIT:
+ goto leave;
+
+ case cmdHELP:
+ for (i=0; cmds[i].name; i++ )
+ if(cmds[i].desc
+ && (!cmds[i].admin_only || (cmds[i].admin_only && allow_admin)))
+ tty_printf("%-14s %s\n", cmds[i].name, _(cmds[i].desc) );
+ break;
+
+ case cmdADMIN:
+ if ( !strcmp (arg_string, "on") )
+ allow_admin = 1;
+ else if ( !strcmp (arg_string, "off") )
+ allow_admin = 0;
+ else if ( !strcmp (arg_string, "verify") )
+ {
+ /* Force verification of the Admin Command. However,
+ this is only done if the retry counter is at initial
+ state. */
+ /* FIXME: Must depend on the type of the card. */
+ /* char *tmp = xmalloc (strlen (serialnobuf) + 6 + 1); */
+ /* strcpy (stpcpy (tmp, serialnobuf), "[CHV3]"); */
+ /* allow_admin = !agent_scd_checkpin (tmp); */
+ /* xfree (tmp); */
+ }
+ else /* Toggle. */
+ allow_admin=!allow_admin;
+ if(allow_admin)
+ tty_printf(_("Admin commands are allowed\n"));
+ else
+ tty_printf(_("Admin commands are not allowed\n"));
+ break;
+
+ case cmdVERIFY: cmd_verify (); redisplay = 1; break;
+ case cmdLIST: redisplay = 1; break;
+ case cmdNAME: cmd_name (); break;
+ case cmdURL: cmd_url (); break;
+ case cmdFETCH: cmd_fetch (); break;
+ case cmdLOGIN: cmd_login (arg_string); break;
+ case cmdLANG: cmd_lang (); break;
+ case cmdSALUT: cmd_salut (); break;
+ case cmdCAFPR: cmd_cafpr (arg_number); break;
+ case cmdPRIVATEDO: cmd_privatedo (arg_number, arg_string); break;
+ case cmdWRITECERT: cmd_writecert (arg_number, arg_rest); break;
+ case cmdREADCERT: cmd_readcert (arg_number, arg_rest); break;
+ case cmdFORCESIG: cmd_forcesig (); break;
+ case cmdGENERATE: cmd_generate (); break;
+ case cmdPASSWD: cmd_passwd (allow_admin); break;
+ case cmdUNBLOCK: cmd_unblock (allow_admin); break;
+ case cmdFACTORYRESET: cmd_factoryreset (); break;
+ case cmdKDFSETUP: cmd_kdfsetup (arg_string); break;
+ case cmdKEYATTR: cmd_keyattr (); break;
+ case cmdUIF: cmd_uif (arg_number, arg_rest); break;
+
+ case cmdINVCMD:
+ default:
+ tty_printf ("\n");
+ tty_printf (_("Invalid command (try \"help\")\n"));
+ break;
+ } /* End command switch. */
+ } /* End of main menu loop. */
+
+ leave:
+ xfree (answer);
+}
+
+#ifdef HAVE_LIBREADLINE
+/* Helper function for readline's command completion. */
+static char *
+command_generator (const char *text, int state)
+{
+ static int list_index, len;
+ const char *name;
+
+ /* If this is a new word to complete, initialize now. This includes
+ * saving the length of TEXT for efficiency, and initializing the
+ index variable to 0. */
+ if (!state)
+ {
+ list_index = 0;
+ len = strlen(text);
+ }
+
+ /* Return the next partial match */
+ while ((name = cmds[list_index].name))
+ {
+ /* Only complete commands that have help text. */
+ if (cmds[list_index++].desc && !strncmp (name, text, len))
+ return strdup(name);
+ }
+
+ return NULL;
+}
+
+/* Second helper function for readline's command completion. */
+static char **
+command_completion (const char *text, int start, int end)
+{
+ (void)end;
+
+ /* If we are at the start of a line, we try and command-complete.
+ * If not, just do nothing for now. */
+ if (!start)
+ return rl_completion_matches (text, command_generator);
+
+ rl_attempted_completion_over = 1;
+
+ return NULL;
+}
+#endif /*HAVE_LIBREADLINE*/
diff --git a/tools/gpg-connect-agent-w32info.rc b/tools/gpg-connect-agent-w32info.rc
index 4e7b19d35..8c6735918 100644
--- a/tools/gpg-connect-agent-w32info.rc
+++ b/tools/gpg-connect-agent-w32info.rc
@@ -1,51 +1,51 @@
-/* scdaemon-w32info.rc -*- c -*-
+/* gpg-connect-agent-w32info.rc -*- c -*-
* Copyright (C) 2013 g10 Code GmbH
*
* This file is free software; as a special exception the author 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.
*/
#include "afxres.h"
#include "../common/w32info-rc.h"
1 ICON "../common/gnupg.ico"
1 VERSIONINFO
FILEVERSION W32INFO_VI_FILEVERSION
PRODUCTVERSION W32INFO_VI_PRODUCTVERSION
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x01L /* VS_FF_DEBUG (0x1)*/
#else
FILEFLAGS 0x00L
#endif
FILEOS 0x40004L /* VOS_NT (0x40000) | VOS__WINDOWS32 (0x4) */
FILETYPE 0x1L /* VFT_APP (0x1) */
FILESUBTYPE 0x0L /* VFT2_UNKNOWN */
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" /* US English (0409), Unicode (04b0) */
BEGIN
VALUE "FileDescription", L"GnuPG\x2019s command line access \
to the agent\0"
VALUE "InternalName", "gpg-connect-agent\0"
VALUE "OriginalFilename", "gpg-connect-agent.exe\0"
VALUE "ProductName", W32INFO_PRODUCTNAME
VALUE "ProductVersion", W32INFO_PRODUCTVERSION
VALUE "CompanyName", W32INFO_COMPANYNAME
VALUE "FileVersion", W32INFO_FILEVERSION
VALUE "LegalCopyright", W32INFO_LEGALCOPYRIGHT
VALUE "Comments", W32INFO_COMMENTS
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 0x4b0
END
END