Various fixes and new features.
authorWerner Koch <wk@gnupg.org>
Wed, 13 Sep 2006 15:57:30 +0000 (15:57 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 13 Sep 2006 15:57:30 +0000 (15:57 +0000)
Enhanced gpg-connect-agent.

20 files changed:
ChangeLog
NEWS
README.SVN [moved from README.CVS with 97% similarity]
agent/ChangeLog
agent/call-scd.c
agent/preset-passphrase.c
autogen.sh
doc/ChangeLog
doc/HACKING
doc/gpg.texi
doc/gpgsm.texi
doc/tools.texi
g10/ChangeLog
g10/gpg.c
sm/ChangeLog
sm/gpgsm.c
sm/keylist.c
sm/server.c
tools/ChangeLog
tools/gpg-connect-agent.c

index 210943c..d2cadef 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2006-09-13  Werner Koch  <wk@g10code.com>
+
+       * autogen.sh: Better detection of the cross compiler kit.
+
 2006-09-06  Marcus Brinkmann  <marcus@g10code.de>
 
        * configure.ac: New automake conditional RUN_GPG_TESTS.
diff --git a/NEWS b/NEWS
index ff5feb9..b4eb576 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,8 @@
 Noteworthy changes in version 1.9.23
 -------------------------------------------------
 
- * man pages for most tools are now build directly from the texinfo
-   source.
+ * Regular man pages for most tools are now build directly from the
+   texinfo source.
 
  * The gpg code from 1.4.5 has been fully merged into this release.
    The configure option --enable-gpg is still required to build this
@@ -14,6 +14,18 @@ Noteworthy changes in version 1.9.23
 
  * The scdaemon will now call a script on reader status changes.
 
+ * gpgsm now allows file descriptor passing for "INPUT", "OUTPUT" and
+   "MESSAGE".
+
+ * The gpgsm server may now output a key listing to the output file
+   handle. This needs to be enabled using "OPTION list-to-output=1".
+
+ * The --output option of gpgsm has now an effect on list-keys.
+
+ * New gpgsm commands --dump-chain and list-chain.
+
+ * gpg-connect-agent has new options to utilize descriptor passing.
+
 
 Noteworthy changes in version 1.9.22 (2006-07-27)
 -------------------------------------------------
similarity index 97%
rename from README.CVS
rename to README.SVN
index ae17923..af4f49d 100644 (file)
@@ -1,4 +1,4 @@
-If you are building from CVS, run the script
+If you are building from Subversion, run the script
 
 ./autogen.sh
 
index 0db7668..714ce15 100644 (file)
@@ -1,3 +1,11 @@
+2006-09-13  Werner Koch  <wk@g10code.com>
+
+       * preset-passphrase.c (main) [W32]: Check for WSAStartup error.
+
+2006-09-08  Werner Koch  <wk@g10code.com>
+
+       * call-scd.c: Add signal.h as we are referencing SIGUSR2.
+
 2006-09-06  Marcus Brinkmann  <marcus@g10code.de>
 
        * Makefile.am (AM_CFLAGS): Add $(GPG_ERR_CFLAGS).
index 3dc8691..1c22ab3 100644 (file)
@@ -27,6 +27,7 @@
 #include <ctype.h>
 #include <assert.h>
 #include <unistd.h>
+#include <signal.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #ifndef HAVE_W32_SYSTEM
index 8f8f60e..1b54248 100644 (file)
@@ -281,10 +281,15 @@ main (int argc, char **argv)
 #ifdef HAVE_W32_SYSTEM
   /* Fixme: Need to initialize the Windows sockets: This should be
      moved to another place and we should make sure that it won't get
-     doen twice, like when Pth is used too. */
+     done twice, like when Pth is used too. */
   {
     WSADATA wsadat;
-    WSAStartup (0x202, &wsadat);
+    if (WSAStartup (0x202, &wsadat) )
+      {
+        log_error ("error initializing socket library: ec=%d\n", 
+                   (int)WSAGetLastError () );
+        return 2;
+      }
   }
 #endif
 
index aaf0d0e..29e19ea 100755 (executable)
@@ -55,36 +55,32 @@ if test "$1" = "--build-w32"; then
     [ -z "$w32root" ] && w32root="$HOME/w32root"
     echo "Using $w32root as standard install directory" >&2
     
-    # See whether we have the Debian cross compiler package or the
-    # old mingw32/cpd system
-    if i586-mingw32msvc-gcc --version >/dev/null 2>&1 ; then
-        host=i586-mingw32msvc
-        crossbindir=/usr/$host/bin
-    else
-       host=i386--mingw32
-       if ! mingw32 --version >/dev/null; then
-          echo "We need at least version 0.3 of MingW32/CPD" >&2
-          exit 1
-       fi
-       crossbindir=`mingw32 --install-dir`/bin
-       # Old autoconf version required us to setup the environment
-       # with the proper tool names.
-       CC=`mingw32 --get-path gcc`
-       CPP=`mingw32 --get-path cpp`
-       AR=`mingw32 --get-path ar`
-       RANLIB=`mingw32 --get-path ranlib`
-       export CC CPP AR RANLIB 
+    # Locate the cross compiler
+    crossbindir=
+    for host in i586-mingw32msvc i386-mingw32msvc; do
+        if ${host}-gcc --version >/dev/null 2>&1 ; then
+            crossbindir=/usr/${host}/bin
+            conf_CC="CC=${host}-gcc"
+            break;
+        fi
+    done
+    if [ -z "$crossbindir" ]; then
+        echo "Cross compiler kit not installed" >&2
+        echo "Under Debian GNU/Linux, you may install it using" >&2
+        echo "  apt-get install mingw32 mingw32-runtime mingw32-binutils" >&2 
+        echo "Stop." >&2
+        exit 1
     fi
    
     if [ -f "$tsdir/config.log" ]; then
         if ! head $tsdir/config.log | grep "$host" >/dev/null; then
-            echo "Pease run a 'make distclean' first" >&2
+            echo "Please run a 'make distclean' first" >&2
             exit 1
         fi
     fi
 
     ./configure --enable-maintainer-mode --prefix=${w32root}  \
-             --host=i586-mingw32msvc --build=${build} \
+             --host=${host} --build=${build} \
              --with-gpg-error-prefix=${w32root} \
             --with-ksba-prefix=${w32root} \
             --with-libgcrypt-prefix=${w32root} \
@@ -93,10 +89,6 @@ if test "$1" = "--build-w32"; then
              --with-pth-prefix=${w32root} \
              --disable-gpg
     rc=$?
-    # Ugly hack to overcome a gettext problem.  Someone should look into
-    # gettext to figure out why the po directory is not ignored as it used
-    # to be.
-    [ $rc = 0 ] && touch $tsdir/po/all
     exit $rc
 fi
 # ***** end W32 build script *******
index ae2e157..832753d 100644 (file)
@@ -1,3 +1,12 @@
+2006-09-13  Werner Koch  <wk@g10code.com>
+
+       * gpg.texi (GPG Esoteric Options): Fixed typo in
+       --require-cross-certification and made it the default.
+
+2006-09-11  Werner Koch  <wk@g10code.com>
+
+       * HACKING: Cleaned up.
+
 2006-09-08  Werner Koch  <wk@g10code.com>
 
        * yat2m.c (parse_file): Ignore @node lines immediately.
index 5efb6c9..07f09c5 100644 (file)
@@ -6,76 +6,6 @@
                   ===> Under construction <=======
 
 
-SOURCE FILES
-============
-
-Here is a list of directories with source files:
-
-jnlib/  utility functions
-kbx/    keybox library
-g10/    the gpg program here called gpg2
-sm/     the gpgsm program
-agent/  the gpg-agent
-scd/    the smartcard daemon
-doc/    documentation
-
-
-
-
-CVS Access
-==========
-
-NOTE: CVS access has been disabled while we are migrating to Subversion.
-Watch www.gnupg.org for instarctions on how to use the Subversion repository.
-
-Anonymous read-only CVS access is available:
-
-  cvs -z3 -d :pserver:anoncvs@cvs.gnupg.org:/cvs/gnupg login
-
-use the password "anoncvs".  To check out the the complete
-archive use:
-
-  cvs -z3 -d :pserver:anoncvs@cvs.gnupg.org:/cvs/gnupg \
-        checkout -R STABLE-BRANCH-1-0 gnupg
-
-This service is provided to help you in hunting bugs and not to deliver
-stable snapshots; it may happen that it even does not compile, so please
-don't complain. CVS may put a high load on a server, so please don't poll
-poll for new updates but wait for an announcement; to receive this you may
-want to subscribe to:
-
-    gnupg-commit-watchers@gnupg.org
-
-by sending a mail with subject "subscribe" to
-
-    gnupg-commit-watchers-request@gnupg.org
-
-
-You must run scripts/autogen.sh before doing the ./configure,
-as this creates some needed while which are not in the CVS.
-autogen.sh should checks that you have all required tools
-installed.
-
-
-RSYNC access
-============
-The FTP archive is also available by anonymous rsync.  A daily snapshot
-of the CVS head revision is also available.  See rsync(1) and try
-"rsync ftp.gnupg.org::" to see available resources.
-
-
-
-Special Tools
-=============
-Documentation is based on the docbook DTD.  Actually we have only the
-man page for now.  To build a man page you need the docbook-to-man
-tool and all the other thinks needed for SGML processing.  Debian
-comes with the docbook tools and you only need this docbook-to-man
-script which is comes with gtk-doc or download it from
-ftp.openit.de:/pub/devel/sgml. If you don't have it everything
-should still work fine but you will have only a dummy man page.
-
-
 RFCs
 ====
 
@@ -98,44 +28,23 @@ RFCs
 
 
 
-Debug Flags
------------
-Use the option "--debug n" to output debug information. This option
-can be used multiple times, all values are ORed; n maybe prefixed with
-0x to use hex-values.
-
-     value  used for
-     -----  ----------------------------------------------
-      1     packet reading/writing
-      2     MPI details
-      4     ciphers and primes (may reveal sensitive data)
-      8     iobuf filter functions
-      16    iobuf stuff
-      32    memory allocation stuff
-      64    caching
-      128   show memory statistics at exit
-      256   trust verification stuff
-
-
-
-
 Directory Layout
 ----------------
-  ./           Readme, configure
-  ./scripts    Scripts needed by configure and others
-  ./doc        Documentation
-  ./util       General purpose utility function
-  ./mpi        Multi precision integer library
-  ./cipher     Cryptographic functions
-  ./g10        GnuPG application
-  ./tools      Some helper and demo programs
-  ./keybox     The keybox library (under construction)
-  ./gcrypt     Stuff needed to build libgcrypt (under construction)
+  ./          Readme, configure
+  ./agent      Gpg-agent and related tools
+  ./doc        Documentation
+  ./doc        Documentation
+  ./g10        Gpg program here called gpg2
+  ./jnlib      Utility functions
+  ./kbx        Keybox library
+  ./scd        Smartcard daemon
+  ./scripts    Scripts needed by configure and others
+  ./sm         Gpgsm program
 
 
 Detailed Roadmap
 ----------------
-g10/g10.c      Main module with option parsing and all the stuff you have
+g10/gpg.c      Main module with option parsing and all the stuff you have
                to do on startup.  Also has the exout handler and some
                helper functions.
 g10/sign.c      Create signature and optionally encrypt
@@ -208,17 +117,28 @@ Memory allocation
 -----------------
 Use only the functions:
 
-    m_alloc()
-    m_alloc_clear()
-    m_strdup()
-    m_free()
-
-If you want to store a passphrase or some other sensitive data you may
-want to use m_alloc_secure() instead of m_alloc(), as this puts the data
-into a memory region which is protected from swapping (on some platforms).
-m_free() works for both.  This functions will not return if there is not
-enough memory available.
-
+    xmalloc
+    xmalloc_secure
+    xtrymalloc
+    xtrymalloc_secure
+    xcalloc
+    xcalloc_secure
+    xtrycalloc
+    xtrycalloc_secure
+    xrealloc
+    xtryrealloc
+    xstrdup
+    xtrystrdup
+    xfree
+
+
+The *secure versions allocated memory in the secure memory. That is,
+swapping out of this memory is avoided and is gets overwritten on
+free.  Use this for passphrases, session keys and other sensitive
+material.  This memory set aside for secure memory is linited to a few
+k.  In general the function don't print a memeory message and
+terminate the process if there is not enough memory available.  The
+"try" versions of the functions return NULL instead.
 
 
 Logging
@@ -254,68 +174,3 @@ the other way: constructing messages using pushed filters but it may be
 easier to understand.
 
 
-How to use the message digest functions
----------------------------------------
-cipher/md.c implements an interface to hash (message digest functions).
-
-a) If you have a common part of data and some variable parts
-   and you need to hash of the concatenated parts, you can use this:
-       md = md_open(...)
-       md_write( md,  common_part )
-       md1 = md_copy( md )
-       md_write(md1, part1)
-       md_final(md1);
-       digest1 = md_read(md1)
-       md2 = md_copy( md )
-       md_write(md2, part2)
-       md_final(md2);
-       digest2 = md_read(md2)
-
-   An example are key signatures; the key packet is the common part
-   and the user-id packets are the variable parts.
-
-b) If you need a running digest you should use this:
-       md = md_open(...)
-       md_write( md, part1 )
-       digest_of_part1 = md_digest( md );
-       md_write( md, part2 )
-       digest_of_part1_cat_part2 = md_digest( md );
-       ....
-
-Both methods may be combined. [Please see the source for the real syntax]
-
-
-
-
-How to use the cipher functions
--------------------------------
-cipher/cipher.c implements the interface to symmetric encryption functions.
-As usual you have a function to open a cipher (which returns a handle to be used
-with all other functions), some functions to set the key and other stuff and
-a encrypt and decrypt function which does the real work.  You probably know
-how to work with files - so it should really be easy to work with these
-functions.  Here is an example:
-
-    CIPHER_HANDLE hd;
-
-    hd = cipher_open( CIPHER_ALGO_TWOFISH, CIPHER_MODE_CFB, 0 );
-    if( !hd )
-       oops( use other function to check for the real error );
-    rc = cipher_setkey( hd, key256bit, 32 ) )
-    if( rc )
-       oops( weak key or something like this );
-    cipher_setiv( hd, some_IV_or_NULL_for_all_zeroes );
-    cipher_encrypt( hd, plain, cipher, size );
-    cipher_close( hd );
-
-
-
-How to use the public key functions
------------------------------------
-cipher/pubkey.c implements the interface to asymmetric encryption and
-signature functions. This is basically the same as with the symmetric
-counterparts, but due to their nature it is a little bit more complicated.
-
-   [Give an example]
-
-
index 219ff15..f744c1a 100644 (file)
@@ -2178,12 +2178,11 @@ content of an encrypted message; using this option you can do this without
 handing out the secret key.
 
 @item --require-cross-certification
-@itemx --no-require-certification
+@itemx --no-require-cross-certification
 When verifying a signature made from a subkey, ensure that the cross
 certification "back signature" on the subkey is present and valid.
 This protects against a subtle attack against subkeys that can sign.
-Currently defaults to --no-require-cross-certification, but will be
-changed to --require-cross-certification in the future.
+Defaults to --require-cross-certification for @command{gpg2}.
 
 @item --ask-sig-expire
 @itemx --no-ask-sig-expire
index 5de9efb..a7a2402 100644 (file)
@@ -184,11 +184,20 @@ is available.
 List certificates matching @var{pattern} using an external server.  This
 utilizes the @code{dirmngr} service.  
 
+@item --list-chain
+@opindex list-chain
+Same as @option{--list-keys} but also prints all keys making up the chain.
+
+
 @item --dump-keys
 @opindex dump-keys
 List all available certificates stored in the local key database using a
 format useful mainly for debugging.
 
+@item --dump-chain
+@opindex dump-chain
+Same as @option{--dump-keys} but also prints all keys making up the chain.
+
 @item --dump-secret-keys
 @opindex dump-secret-keys
 List all available certificates for which a corresponding a secret key
index 4e9a80d..dec5489 100644 (file)
@@ -989,6 +989,22 @@ Connect to socket @var{name} assuming this is an Assuan style server.
 Do not run any special initializations or environment checks.  This may
 be used to directly connect to any Assuan style socket server.
 
+@item -E
+@itemx --exec
+@opindex exec
+Take the rest of the command line as a program and it's arguments and
+execute it as an assuan server. Here is how you would run @command{gpgsm}:
+@smallexample
+ gpg-connect-agent --exec gpgsm --server
+@end smallexample
+
+
+@item --no-ext-connect
+@opindex no-ext-connect
+When using @option{-S} or @option{--exec}, @command{gpg-connect-agent}
+connects to the assuan server in extended mode to allow descriptor
+passing.  This option makes it use the old mode.
+
 @end table
 
 @mansect control commands
@@ -1020,6 +1036,15 @@ Print all definitions
 @item /cleardef
 Delete all definitions
 
+@item /sendfd @var{file} @var{mode}
+Open @var{file} in @var{mode} (which needs to be a valid @code{fopen}
+mode string) and send the file descriptor to the server.  This is
+usually followed by a command like @code{INPUT FD} to set the
+input source for other commands.
+
+@item /recvfd
+Not yet implemented.
+
 @item /help
 Print a list of available control commands.
 
index c6de096..99d73a6 100644 (file)
@@ -1,3 +1,7 @@
+2006-09-13  Werner Koch  <wk@g10code.com>
+
+       * gpg.c (main): Made --require-cross-certification the default. 
+
 2006-09-06  Marcus Brinkmann  <marcus@g10code.de>
 
        * Makefile.am (gpg2_LDADD, gpgv2_LDADD): Replace -lassuan and
index 826cdd3..79617ee 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -1834,6 +1834,7 @@ main (int argc, char **argv )
     opt.rfc2440_text=1;
     opt.def_sig_expire="0";
     opt.def_cert_expire="0";
+    opt.require_cross_cert = 1;
     set_homedir ( default_homedir () );
 
     /* Check whether we have a config file on the command line.  */
index 3c60f6f..7bf2c07 100644 (file)
@@ -1,3 +1,17 @@
+2006-09-13  Werner Koch  <wk@g10code.com>
+
+       * keylist.c (list_internal_keys): Print marker line to FP and not
+       to stdout.
+
+       * gpgsm.c (main): All list key list commands now make ose of
+       --output. Cleaned up calls to list modes.  New command
+       --dump-chain.  Renamed --list-sigs to --list-chain and added an
+       alias for the old one.
+
+       * server.c (cmd_message): Changed to use assuan_command_parse_fd.
+       (option_handler): New option list-to-output.
+       (do_listkeys): Use it.
+
 2006-09-06  Werner Koch  <wk@g10code.com>
 
        * gpgsm.h (OUT_OF_CORE): Removed and changed all callers to
index aaf5c42..49a56cd 100644 (file)
@@ -80,7 +80,7 @@ enum cmd_and_opt_values {
   aVerify,
   aVerifyFiles,
   aListExternalKeys,
-  aListSigs,
+  aListChain,
   aSendKeys,
   aRecvKeys,
   aExport,
@@ -93,6 +93,7 @@ enum cmd_and_opt_values {
   aPasswd,
   aGPGConfList,
   aDumpKeys,
+  aDumpChain,
   aDumpSecretKeys,
   aDumpExternalKeys,
   aKeydbClearSomeCertFlags,
@@ -251,8 +252,7 @@ static ARGPARSE_OPTS opts[] = {
     { aListKeys, "list-keys", 256, N_("list keys")},
     { aListExternalKeys, "list-external-keys", 256, N_("list external keys")},
     { aListSecretKeys, "list-secret-keys", 256, N_("list secret keys")},
-    { aListSigs,   "list-sigs", 256, N_("list certificate chain")}, 
-    { aListSigs,   "check-sigs",256, "@"},
+    { aListChain,   "list-chain",  256, N_("list certificate chain")}, 
     { oFingerprint, "fingerprint", 256, N_("list keys and fingerprints")},
     { aKeygen,    "gen-key",  256, N_("generate a new key pair")},
     { aDeleteKey, "delete-key",256, N_("remove key from the public keyring")},
@@ -269,6 +269,7 @@ static ARGPARSE_OPTS opts[] = {
     { aGPGConfList, "gpgconf-list", 256, "@" },
 
     { aDumpKeys, "dump-keys", 256, "@"},
+    { aDumpChain, "dump-chain", 256, "@"},
     { aDumpExternalKeys, "dump-external-keys", 256, "@"},
     { aDumpSecretKeys, "dump-secret-keys", 256, "@"},
     { aKeydbClearSomeCertFlags, "keydb-clear-some-cert-flags", 256, "@"},
@@ -428,9 +429,11 @@ static ARGPARSE_OPTS opts[] = {
     { oWithValidation, "with-validation", 0, "@"},
     { oWithMD5Fingerprint, "with-md5-fingerprint", 0, "@"},
     { oWithEphemeralKeys,  "with-ephemeral-keys", 0, "@"},
-    { aListKeys, "list-key", 0, "@" }, /* alias */
-    { aListSigs, "list-sig", 0, "@" }, /* alias */
-    { aListSigs, "check-sig",0, "@" }, /* alias */
+    { aListKeys, "list-key", 256, "@" },  /* alias */
+    { aListChain, "list-sig", 256, "@" }, /* alias */
+    { aListChain, "list-sigs",256, "@" }, /* alias */
+    { aListChain, "check-sig",256, "@" }, /* alias */
+    { aListChain, "check-sigs",256, "@"}, /* alias */
     { oSkipVerify, "skip-verify",0, "@" },
     { oCompressKeys, "compress-keys",0, "@"},
     { oCompressSigs, "compress-sigs",0, "@"},
@@ -930,12 +933,13 @@ main ( int argc, char **argv)
         case aExport: 
         case aExportSecretKeyP12: 
         case aDumpKeys:
+        case aDumpChain:
         case aDumpExternalKeys: 
         case aDumpSecretKeys: 
         case aListKeys:
         case aListExternalKeys: 
         case aListSecretKeys: 
-        case aListSigs
+        case aListChain
         case aLearnCard: 
         case aPasswd: 
         case aKeydbClearSomeCertFlags:
@@ -1518,52 +1522,43 @@ main ( int argc, char **argv)
       free_strlist(sl);
       break;
 
-    case aListSigs:
-      ctrl.with_chain = 1;
+    case aListChain:
+    case aDumpChain:
+       ctrl.with_chain = 1;
     case aListKeys:
-      for (sl=NULL; argc; argc--, argv++)
-        add_to_strlist (&sl, *argv);
-      gpgsm_list_keys (&ctrl, sl, stdout, (0 | (1<<6)));
-      free_strlist(sl);
-      break;
-
     case aDumpKeys:
-      for (sl=NULL; argc; argc--, argv++)
-        add_to_strlist (&sl, *argv);
-      gpgsm_list_keys (&ctrl, sl, stdout, (256 | (1<<6)));
-      free_strlist(sl);
-      break;
-
     case aListExternalKeys:
-      for (sl=NULL; argc; argc--, argv++)
-        add_to_strlist (&sl, *argv);
-      gpgsm_list_keys (&ctrl, sl, stdout,
-                       (0 | (1<<7)));
-      free_strlist(sl);
-      break;
-
     case aDumpExternalKeys:
-      for (sl=NULL; argc; argc--, argv++)
-        add_to_strlist (&sl, *argv);
-      gpgsm_list_keys (&ctrl, sl, stdout,
-                       (256 | (1<<7)));
-      free_strlist(sl);
-      break;
-
     case aListSecretKeys:
-      for (sl=NULL; argc; argc--, argv++)
-        add_to_strlist (&sl, *argv);
-      gpgsm_list_keys (&ctrl, sl, stdout, (2 | (1<<6)));
-      free_strlist(sl);
-      break;
-
     case aDumpSecretKeys:
-      for (sl=NULL; argc; argc--, argv++)
-        add_to_strlist (&sl, *argv);
-      gpgsm_list_keys (&ctrl, sl, stdout, (256 | 2 | (1<<6)));
-      free_strlist(sl);
+      {
+        unsigned int mode;
+        FILE *fp;
+
+        switch (cmd)
+          {
+          case aListChain:
+          case aListKeys:         mode = (0   | 0 | (1<<6)); break;
+          case aDumpChain: 
+          case aDumpKeys:         mode = (256 | 0 | (1<<6)); break;
+          case aListExternalKeys: mode = (0   | 0 | (1<<7)); break;
+          case aDumpExternalKeys: mode = (256 | 0 | (1<<7)); break;
+          case aListSecretKeys:   mode = (0   | 2 | (1<<6)); break;
+          case aDumpSecretKeys:   mode = (256 | 2 | (1<<6)); break;
+          default: BUG();
+          }
+
+        fp = open_fwrite (opt.outfile?opt.outfile:"-");
+        for (sl=NULL; argc; argc--, argv++)
+          add_to_strlist (&sl, *argv);
+        gpgsm_list_keys (&ctrl, sl, fp, mode);
+        free_strlist(sl);
+        if (fp != stdout)
+          fclose (fp);
+      }
       break;
 
+
     case aKeygen: /* generate a key */
       log_error ("this function is not yet available from the commandline\n");
       break;
index 4b8f418..927bc88 100644 (file)
@@ -1130,7 +1130,7 @@ list_cert_chain (ctrl_t ctrl, KEYDB_HANDLE hd,
 /* List all internal keys or just the keys given as NAMES.  MODE is a
    bit vector to specify what keys are to be included; see
    gpgsm_list_keys (below) for details.  If RAW_MODE is true, the raw
-   output mode will be used intead of the standard beautified one.
+   output mode will be used instead of the standard beautified one.
  */
 static gpg_error_t
 list_internal_keys (ctrl_t ctrl, STRLIST names, FILE *fp,
@@ -1229,7 +1229,7 @@ list_internal_keys (ctrl_t ctrl, STRLIST names, FILE *fp,
             {
               fprintf (fp, "%s\n", resname );
               for (i=strlen(resname); i; i-- )
-                putchar('-');
+                putc ('-', fp);
               putc ('\n', fp);
               lastresname = resname;
             }
index d7046c5..16475f6 100644 (file)
@@ -44,6 +44,7 @@ struct server_local_s {
   int message_fd;
   int list_internal;
   int list_external;
+  int list_to_output;           /* Write keylistings to the output fd. */
   certlist_t recplist;
   certlist_t signerlist;
   certlist_t default_recplist; /* As set by main() - don't release. */
@@ -171,6 +172,11 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
       else
         return gpg_error (GPG_ERR_ASS_PARAMETER);
     }
+  else if (!strcmp (key, "list-to-output"))
+    {
+      int i = *value? atoi (value) : 0;
+      ctrl->server_local->list_to_output = i;
+    }
   else if (!strcmp (key, "with-validation"))
     {
       int i = *value? atoi (value) : 0;
@@ -624,40 +630,33 @@ cmd_delkeys (assuan_context_t ctx, char *line)
 static int 
 cmd_message (assuan_context_t ctx, char *line)
 {
-  char *endp;
+  int rc;
   int fd;
   ctrl_t ctrl = assuan_get_pointer (ctx);
 
-  if (strncmp (line, "FD=", 3))
-    return set_error (GPG_ERR_ASS_SYNTAX, "FD=<n> expected");
-  line += 3;
-  if (!digitp (line))
-    return set_error (GPG_ERR_ASS_SYNTAX, "number required");
-  fd = strtoul (line, &endp, 10);
-  if (*endp)
-    return set_error (GPG_ERR_ASS_SYNTAX, "garbage found");
+  rc = assuan_command_parse_fd (ctx, line, &fd);
+  if (rc)
+    return rc;
   if (fd == -1)
     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
-
   ctrl->server_local->message_fd = fd;
   return 0;
 }
 
-
+/* LISTKEYS [<patterns>]
+   LISTSECRETKEYS [<patterns>]
+*/
 static int 
 do_listkeys (assuan_context_t ctx, char *line, int mode)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
-  FILE *fp = assuan_get_data_fp (ctx);
+  FILE *fp;
   char *p;
   STRLIST list, sl;
   unsigned int listmode;
   gpg_error_t err;
 
-  if (!fp)
-    return set_error (GPG_ERR_ASS_GENERAL, "no data stream");
-  
-  /* break the line down into an STRLIST */
+  /* Break the line down into an STRLIST. */
   list = NULL;
   for (p=line; *p; line = p)
     {
@@ -680,6 +679,21 @@ do_listkeys (assuan_context_t ctx, char *line, int mode)
         }
     }
 
+  if (ctrl->server_local->list_to_output)
+    {
+      if ( assuan_get_output_fd (ctx) == -1 )
+        return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
+      fp = fdopen (assuan_get_output_fd (ctx), "w");
+      if (!fp)
+        return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
+    }
+  else
+    {
+      fp = assuan_get_data_fp (ctx);
+      if (!fp)
+        return set_error (GPG_ERR_ASS_GENERAL, "no data stream");
+    }
+  
   ctrl->with_colons = 1;
   listmode = mode; 
   if (ctrl->server_local->list_internal)
@@ -688,6 +702,11 @@ do_listkeys (assuan_context_t ctx, char *line, int mode)
     listmode |= (1<<7);
   err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
   free_strlist (list);
+  if (ctrl->server_local->list_to_output)
+    {
+      fclose (fp);
+      assuan_close_output_fd (ctx);
+    }
   return err;
 }
 
@@ -793,9 +812,9 @@ gpgsm_server (certlist_t default_recplist)
   memset (&ctrl, 0, sizeof ctrl);
   gpgsm_init_default_ctrl (&ctrl);
 
-  /* 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 */
+  /* We use a pipe based server so that we can work from scripts.
+     assuan_init_pipe_server will automagically detect when we are
+     called with a socketpair and ignore FIELDES in this case. */
   filedes[0] = 0;
   filedes[1] = 1;
   rc = assuan_init_pipe_server (&ctx, filedes);
index 1b8a793..295a574 100644 (file)
@@ -1,3 +1,8 @@
+2006-09-12  Werner Koch  <wk@g10code.com>
+
+       * gpg-connect-agent.c (read_and_print_response): With verbosity
+       level 2 also print comment lines.
+
 2006-09-06  Werner Koch  <wk@g10code.com>
 
        * gpg-connect-agent.c: Switch everything to new Assuan error code
index eacbd92..31fed95 100644 (file)
@@ -41,10 +41,12 @@ enum cmd_and_opt_values
     oQuiet      = 'q',
     oVerbose   = 'v',
     oRawSocket  = 'S',
+    oExec       = 'E',
 
     oNoVerbose = 500,
     oHomedir,
-    oHex
+    oHex,
+    oNoExtConnect
 
   };
 
@@ -58,6 +60,9 @@ static ARGPARSE_OPTS opts[] =
     { oQuiet, "quiet",      0, N_("quiet") },
     { oHex,   "hex",        0, N_("print data out hex encoded") },
     { oRawSocket, "raw-socket", 2, N_("|NAME|connect to Assuan socket NAME")},
+    { oExec, "exec", 0, N_("run the Assuan server given on the command line")},
+    { oNoExtConnect, "no-ext-connect",
+                            0, N_("do not use extended connect mode")},
 
     /* hidden options */
     { oNoVerbose, "no-verbose",  0, "@"},
@@ -74,6 +79,8 @@ struct
   const char *homedir;  /* Configuration directory name */
   int hex;              /* Print data lines in hex format. */
   const char *raw_socket; /* Name of socket to connect in raw mode. */
+  int exec;             /* Run the pgm given on the command line. */
+  unsigned int connect_flags;    /* Flags used for connecting. */
 } opt;
 
 
@@ -209,13 +216,68 @@ clear_definq (void)
 }      
 
 
+static void
+do_sendfd (assuan_context_t ctx, char *line)
+{
+  FILE *fp;
+  char *name, *mode, *p;
+  int rc, fd;
+
+  /* Get file name. */
+  name = line;
+  for (p=name; *p && !spacep (p); p++)
+    ;
+  if (*p)
+    *p++ = 0;
+  while (spacep (p))
+    p++;
+
+  /* Get mode.  */
+  mode = p;
+  if (!*mode)
+    mode = "r";
+  else
+    {
+      for (p=mode; *p && !spacep (p); p++)
+        ;
+      if (*p)
+        *p++ = 0;
+    }
+
+  /* Open and send. */
+  fp = fopen (name, mode);
+  if (!fp)
+    {
+      log_error ("can't open `%s' in \"%s\" mode: %s\n",
+                 name, mode, strerror (errno));
+      return;
+    }
+  fd = fileno (fp);
+
+  if (opt.verbose)
+    log_error ("file `%s' opened in \"%s\" mode, fd=%d\n",
+               name, mode, fd);
+
+  rc = assuan_sendfd (ctx, fd);
+  if (rc)
+    log_error ("sednig  descriptor %d failed: %s\n", fd, gpg_strerror (rc));
+  fclose (fp);
+}
+
+
+static void
+do_recvfd (assuan_context_t ctx, char *line)
+{
+  log_info ("This command has not yet been implemented\n");
+}
+
+
 
 /* gpg-connect-agent's entry point. */
 int
 main (int argc, char **argv)
 {
   ARGPARSE_ARGS pargs;
-  const char *fname;
   int no_more_options = 0;
   assuan_context_t ctx;
   char *line, *p;
@@ -229,6 +291,7 @@ main (int argc, char **argv)
   i18n_init();
 
   opt.homedir = default_homedir ();
+  opt.connect_flags = 1; /* Use extended connect mode.  */
 
   /* Parse the command line. */
   pargs.argc  = &argc;
@@ -244,6 +307,8 @@ main (int argc, char **argv)
         case oHomedir:   opt.homedir = pargs.r.ret_str; break;
         case oHex:       opt.hex = 1; break;
         case oRawSocket: opt.raw_socket = pargs.r.ret_str; break;
+        case oExec:      opt.exec = 1; break;
+        case oNoExtConnect: opt.connect_flags &= ~(1); break;
 
         default: pargs.err = 2; break;
        }
@@ -251,12 +316,48 @@ main (int argc, char **argv)
 
   if (log_get_errorcount (0))
     exit (2);
-  
-  fname = argc ? *argv : NULL;
 
-  if (opt.raw_socket)
+  if (opt.exec)
+    {
+      if (!argc)
+        {
+          log_error (_("option \"%s\" requires a program "
+                       "and optional arguments\n"), "--exec" );
+          exit (1);
+        }
+    }
+  else if (argc)
+    usage (1);
+
+  if (opt.exec && opt.raw_socket)
+    log_info (_("option \"%s\" ignored due to \"%s\"\n"),
+              "--raw-socket", "--exec");
+
+  if (opt.exec)
+    {
+      int no_close[3];
+
+      no_close[0] = fileno (stderr);
+      no_close[1] = log_get_fd ();
+      no_close[2] = -1;
+      rc = assuan_pipe_connect_ext (&ctx, *argv, (const char **)argv,
+                                    no_close, NULL, NULL,
+                                    opt.connect_flags);
+      if (rc)
+        {
+          log_error ("assuan_pipe_connect_ext failed: %s\n",
+                     gpg_strerror (rc));
+          exit (1);
+        }
+
+      if (opt.verbose)
+        log_info ("server `%s' started\n", *argv);
+
+    }
+  else if (opt.raw_socket)
     {
-      rc = assuan_socket_connect (&ctx, opt.raw_socket, 0);
+      rc = assuan_socket_connect_ext (&ctx, opt.raw_socket, 0,
+                                      opt.connect_flags);
       if (rc)
         {
           log_error ("can't connect to socket `%s': %s\n",
@@ -325,18 +426,31 @@ main (int argc, char **argv)
             {
               puts (p);
             }
+          else if (!strcmp (cmd, "sendfd"))
+            {
+              do_sendfd (ctx, p);
+              continue;
+            }
+          else if (!strcmp (cmd, "recvfd"))
+            {
+              do_recvfd (ctx, p);
+              continue;
+            }
           else if (!strcmp (cmd, "help"))
             {
-              puts ("Available commands:\n"
-                    "/echo ARGS             Echo ARGS.\n"
-                    "/definqfile NAME FILE\n"
-                    "    Use content of FILE for inquiries with NAME.\n"
-                    "    NAME may be \"*\" to match any inquiry.\n"
-                    "/definqprog NAME PGM\n"
-                    "    Run PGM for inquiries matching NAME and pass the\n"
-                    "    entire line to it as arguments.\n"
-                    "/showdef               Print all definitions.\n"
-                    "/cleardef              Delete all definitions.\n"
+              puts (
+"Available commands:\n"
+"/echo ARGS             Echo ARGS.\n"
+"/definqfile NAME FILE\n"
+"    Use content of FILE for inquiries with NAME.\n"
+"    NAME may be \"*\" to match any inquiry.\n"
+"/definqprog NAME PGM\n"
+"    Run PGM for inquiries matching NAME and pass the\n"
+"    entire line to it as arguments.\n"
+"/showdef               Print all definitions.\n"
+"/cleardef              Delete all definitions.\n"
+"/sendfd FILE MODE      Open FILE and pass descripor to server.\n"
+"/recvfd                Receive FD from server and print. \n"
                     "/help                  Print this help.");
             }
           else
@@ -352,7 +466,7 @@ main (int argc, char **argv)
           continue;
         }
       if (*line == '#' || !*line)
-        continue; /* Don't expect a response for a coment line. */
+        continue; /* Don't expect a response for a comment line. */
 
       rc = read_and_print_response (ctx);
       if (rc)
@@ -471,6 +585,12 @@ read_and_print_response (assuan_context_t ctx)
           rc = assuan_read_line (ctx, &line, &linelen);
           if (rc)
             return rc;
+
+          if (opt.verbose > 1 && *line == '#')
+            {
+              fwrite (line, linelen, 1, stdout);
+              putchar ('\n');
+            }
         }    
       while (*line == '#' || !linelen);