From 9577dd45abd3e0f68403dc38a21e69bbf2c4d813 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 13 Sep 2006 15:57:30 +0000 Subject: [PATCH] Various fixes and new features. Enhanced gpg-connect-agent. --- ChangeLog | 4 + NEWS | 16 ++- README.CVS => README.SVN | 2 +- agent/ChangeLog | 8 ++ agent/call-scd.c | 1 + agent/preset-passphrase.c | 9 +- autogen.sh | 42 ++++---- doc/ChangeLog | 9 ++ doc/HACKING | 207 ++++++-------------------------------- doc/gpg.texi | 5 +- doc/gpgsm.texi | 9 ++ doc/tools.texi | 25 +++++ g10/ChangeLog | 4 + g10/gpg.c | 1 + sm/ChangeLog | 14 +++ sm/gpgsm.c | 85 ++++++++-------- sm/keylist.c | 4 +- sm/server.c | 57 +++++++---- tools/ChangeLog | 5 + tools/gpg-connect-agent.c | 154 ++++++++++++++++++++++++---- 20 files changed, 369 insertions(+), 292 deletions(-) rename README.CVS => README.SVN (97%) diff --git a/ChangeLog b/ChangeLog index 210943c22..d2cadef1d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2006-09-13 Werner Koch + + * autogen.sh: Better detection of the cross compiler kit. + 2006-09-06 Marcus Brinkmann * configure.ac: New automake conditional RUN_GPG_TESTS. diff --git a/NEWS b/NEWS index ff5feb9ae..b4eb576d8 100644 --- 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) ------------------------------------------------- diff --git a/README.CVS b/README.SVN similarity index 97% rename from README.CVS rename to README.SVN index ae17923bd..af4f49d7d 100644 --- a/README.CVS +++ b/README.SVN @@ -1,4 +1,4 @@ -If you are building from CVS, run the script +If you are building from Subversion, run the script ./autogen.sh diff --git a/agent/ChangeLog b/agent/ChangeLog index 0db76684a..714ce15cc 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,11 @@ +2006-09-13 Werner Koch + + * preset-passphrase.c (main) [W32]: Check for WSAStartup error. + +2006-09-08 Werner Koch + + * call-scd.c: Add signal.h as we are referencing SIGUSR2. + 2006-09-06 Marcus Brinkmann * Makefile.am (AM_CFLAGS): Add $(GPG_ERR_CFLAGS). diff --git a/agent/call-scd.c b/agent/call-scd.c index 3dc869137..1c22ab364 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #ifndef HAVE_W32_SYSTEM diff --git a/agent/preset-passphrase.c b/agent/preset-passphrase.c index 8f8f60e76..1b54248a5 100644 --- a/agent/preset-passphrase.c +++ b/agent/preset-passphrase.c @@ -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 diff --git a/autogen.sh b/autogen.sh index aaf0d0ea4..29e19ea14 100755 --- a/autogen.sh +++ b/autogen.sh @@ -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 ******* diff --git a/doc/ChangeLog b/doc/ChangeLog index ae2e15743..832753d66 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,12 @@ +2006-09-13 Werner Koch + + * gpg.texi (GPG Esoteric Options): Fixed typo in + --require-cross-certification and made it the default. + +2006-09-11 Werner Koch + + * HACKING: Cleaned up. + 2006-09-08 Werner Koch * yat2m.c (parse_file): Ignore @node lines immediately. diff --git a/doc/HACKING b/doc/HACKING index 5efb6c947..07f09c56b 100644 --- a/doc/HACKING +++ b/doc/HACKING @@ -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() + xmalloc + xmalloc_secure + xtrymalloc + xtrymalloc_secure + xcalloc + xcalloc_secure + xtrycalloc + xtrycalloc_secure + xrealloc + xtryrealloc + xstrdup + xtrystrdup + xfree -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. +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] - - diff --git a/doc/gpg.texi b/doc/gpg.texi index 219ff15f4..f744c1a22 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -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 diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index 5de9efbe9..a7a24022f 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -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 diff --git a/doc/tools.texi b/doc/tools.texi index 4e9a80d8e..dec548905 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -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. diff --git a/g10/ChangeLog b/g10/ChangeLog index c6de096e2..99d73a6b7 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,7 @@ +2006-09-13 Werner Koch + + * gpg.c (main): Made --require-cross-certification the default. + 2006-09-06 Marcus Brinkmann * Makefile.am (gpg2_LDADD, gpgv2_LDADD): Replace -lassuan and diff --git a/g10/gpg.c b/g10/gpg.c index 826cdd305..79617ee3c 100644 --- 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. */ diff --git a/sm/ChangeLog b/sm/ChangeLog index 3c60f6f9c..7bf2c0713 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,17 @@ +2006-09-13 Werner Koch + + * 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 * gpgsm.h (OUT_OF_CORE): Removed and changed all callers to diff --git a/sm/gpgsm.c b/sm/gpgsm.c index aaf5c42fe..49a56cd7c 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -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,51 +1522,42 @@ 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); + case aDumpSecretKeys: + { + 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 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); - break; case aKeygen: /* generate a key */ log_error ("this function is not yet available from the commandline\n"); diff --git a/sm/keylist.c b/sm/keylist.c index 4b8f418b2..927bc88a6 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -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; } diff --git a/sm/server.c b/sm/server.c index d7046c59e..16475f66e 100644 --- a/sm/server.c +++ b/sm/server.c @@ -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= 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 [] + LISTSECRETKEYS [] +*/ 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); diff --git a/tools/ChangeLog b/tools/ChangeLog index 1b8a79345..295a574c7 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,8 @@ +2006-09-12 Werner Koch + + * gpg-connect-agent.c (read_and_print_response): With verbosity + level 2 also print comment lines. + 2006-09-06 Werner Koch * gpg-connect-agent.c: Switch everything to new Assuan error code diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index eacbd924f..31fed9504 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -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) { - rc = assuan_socket_connect (&ctx, opt.raw_socket, 0); + 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_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);