diff --git a/g10/ChangeLog b/g10/ChangeLog index 91c9b554a..ec0778c5f 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,19 @@ +2006-12-21 Werner Koch + + * gpg.c (main): New command --server. + * gpg.h (struct server_control_s, ctrl_t): New. + * server.c: New. + * verify.c (gpg_verify): New. + * mainproc.c (mainproc_context): Made SIGNED_DATA a structure. + (proc_signature_packets_by_fd): New. + (proc_compressed_cb): Divert depending on SIGNED_DATA. + * plaintext.c (hash_datafile_by_fd): New. + * mainproc.c (proc_tree): Use it here. + + * verify.c (verify_signatures): Init AFX only when needed. + Don't leak a context on error. + (verify_one_file): Don't leak a context on error. + 2006-12-07 Werner Koch * openfile.c (copy_options_file): Use log_info instead of diff --git a/g10/Makefile.am b/g10/Makefile.am index c3e5432e3..fdca1405c 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -72,6 +72,7 @@ common_source = \ pkglue.c pkglue.h gpg2_SOURCES = gpg.c \ + server.c \ $(common_source) \ pkclist.c \ skclist.c \ diff --git a/g10/gpg.c b/g10/gpg.c index 846842054..05ea39039 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -149,6 +149,7 @@ enum cmd_and_opt_values aCardStatus, aCardEdit, aChangePIN, + aServer, oTextmode, oNoTextmode, @@ -424,7 +425,8 @@ static ARGPARSE_OPTS opts[] = { { aEnArmor, "enarmour", 256, "@"}, { aPrintMD, "print-md" , 256, N_("|algo [files]|print message digests")}, { aPrimegen, "gen-prime" , 256, "@" }, - { aGenRandom, "gen-random" , 256, "@" }, + { aGenRandom, "gen-random", 256, "@" }, + { aServer, "server", 256, N_("run in server mode")}, { 301, NULL, 0, N_("@\nOptions:\n ") }, @@ -1740,6 +1742,25 @@ encode_s2k_iterations(int iterations) return result; } + +/* This fucntion called to initialized a new control object. It is + assumed that this object has been zeroed out before calling this + function. */ +static void +gpg_init_default_ctrl (ctrl_t ctrl) +{ +} + + +/* This function is called to deinitialize a control object. It is + not deallocated. */ +static void +gpg_deinit_default_ctrl (ctrl_t ctrl) +{ +} + + + int main (int argc, char **argv ) { @@ -2094,6 +2115,10 @@ main (int argc, char **argv ) case aVerifyFiles: multifile=1; /* fall through */ case aVerify: set_cmd( &cmd, aVerify); break; + case aServer: + set_cmd (&cmd, pargs.r_opt); + opt.batch = 1; + break; case oArmor: opt.armor = 1; opt.no_armor=0; break; case oOutput: opt.outfile = pargs.r.ret_str; break; @@ -3254,6 +3279,16 @@ main (int argc, char **argv ) switch( cmd ) { + case aServer: + { + ctrl_t ctrl = xtrycalloc (1, sizeof *ctrl); + gpg_init_default_ctrl (ctrl); + gpg_server (ctrl); + gpg_deinit_default_ctrl (ctrl); + xfree (ctrl); + } + break; + case aStore: /* only store the file */ if( argc > 1 ) wrong_args(_("--store [filename]")); @@ -4169,3 +4204,4 @@ add_keyserver_url( const char *string, int which ) if(critical) sl->flags |= 1; } + diff --git a/g10/gpg.h b/g10/gpg.h index 100a8e349..9e0c9607e 100644 --- a/g10/gpg.h +++ b/g10/gpg.h @@ -43,12 +43,44 @@ #define MAX_FINGERPRINT_LEN 20 -/* Forward declarations. */ +/* + Forward declarations. + */ + +/* Object used to keep state locally to server.c . */ +struct server_local_s; + +/* Object used to describe a keyblok node. */ typedef struct kbnode_struct *KBNODE; +/* Object used for looking ob keys. */ typedef struct keydb_search_desc KEYDB_SEARCH_DESC; +/* Session control object. This object is passed to most functions to + convey the status of a session. Note that the defaults are set by + gpg_init_default_ctrl(). */ +struct server_control_s +{ + struct server_local_s *server_local; +}; +typedef struct server_control_s *ctrl_t; + + + + +/*-- server.c --*/ +int gpg_server (ctrl_t); + + + + + + +/* + Compatibility stuff to be faded out over time. + */ + /* Simple wrappers. */ #define g10_errstr(a) gpg_strerror ((a)) @@ -98,5 +130,4 @@ typedef struct keydb_search_desc KEYDB_SEARCH_DESC; #define G10ERR_WRONG_SECKEY GPG_ERR_WRONG_SECKEY - #endif /*GNUPG_G10_GPG_H*/ diff --git a/g10/main.h b/g10/main.h index 5303aa3a9..478e56de9 100644 --- a/g10/main.h +++ b/g10/main.h @@ -278,6 +278,7 @@ void print_card_key_info (FILE *fp, KBNODE keyblock); void print_file_status( int status, const char *name, int what ); int verify_signatures( int nfiles, char **files ); int verify_files( int nfiles, char **files ); +int gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, FILE *out_fp); /*-- decrypt.c --*/ int decrypt_message( const char *filename ); @@ -286,6 +287,8 @@ void decrypt_messages(int nfiles, char *files[]); /*-- plaintext.c --*/ int hash_datafiles( gcry_md_hd_t md, gcry_md_hd_t md2, strlist_t files, const char *sigfilename, int textmode ); +int hash_datafile_by_fd ( gcry_md_hd_t md, gcry_md_hd_t md2, int data_fd, + int textmode ); PKT_plaintext *setup_plaintext_name(const char *filename,IOBUF iobuf); /*-- signal.c --*/ diff --git a/g10/mainproc.c b/g10/mainproc.c index dc7988987..2a5db6e97 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -65,8 +65,26 @@ struct mainproc_context md_filter_context_t mfx; int sigs_only; /* Process only signatures and reject all other stuff. */ int encrypt_only; /* Process only encryption messages. */ - strlist_t signed_data; + + /* Name of the file with the complete signature or the file with the + detached signature. This is currently only used to deduce the + file name of the data file if that has not been given. */ const char *sigfilename; + + /* A structure to describe the signed data in case of a detached + signature. */ + struct + { + /* A file descriptor of the the signed data. Only used if not -1. */ + int data_fd; + /* A list of filenames with the data files or NULL. This is only + used if DATA_FD is -1. */ + strlist_t data_names; + /* Flag to indicated that either one of the next previous fieldss + is used. This is only needed for better readability. */ + int used; + } signed_data; + DEK *dek; int last_was_session_key; KBNODE list; /* The current list of packets. */ @@ -692,8 +710,14 @@ proc_plaintext( CTX c, PACKET *pkt ) static int proc_compressed_cb( IOBUF a, void *info ) { - return proc_signature_packets( info, a, ((CTX)info)->signed_data, - ((CTX)info)->sigfilename ); + if ( ((CTX)info)->signed_data.used + && ((CTX)info)->signed_data.data_fd != -1) + return proc_signature_packets_by_fd (info, a, + ((CTX)info)->signed_data.data_fd); + else + return proc_signature_packets (info, a, + ((CTX)info)->signed_data.data_names, + ((CTX)info)->sigfilename ); } static int @@ -1124,7 +1148,11 @@ proc_signature_packets( void *anchor, IOBUF a, c->anchor = anchor; c->sigs_only = 1; - c->signed_data = signedfiles; + + c->signed_data.data_fd = -1; + c->signed_data.data_names = signedfiles; + c->signed_data.used = !!signedfiles; + c->sigfilename = sigfilename; rc = do_proc_packets( c, a ); @@ -1150,6 +1178,43 @@ proc_signature_packets( void *anchor, IOBUF a, return rc; } +int +proc_signature_packets_by_fd (void *anchor, IOBUF a, int signed_data_fd ) +{ + int rc; + CTX c = xcalloc (1, sizeof *c); + + c->anchor = anchor; + c->sigs_only = 1; + + c->signed_data.data_fd = signed_data_fd; + c->signed_data.data_names = NULL; + c->signed_data.used = (signed_data_fd != -1); + + rc = do_proc_packets ( c, a ); + + /* If we have not encountered any signature we print an error + messages, send a NODATA status back and return an error code. + Using log_error is required because verify_files does not check + error codes for each file but we want to terminate the process + with an error. */ + if (!rc && !c->any_sig_seen) + { + write_status_text (STATUS_NODATA, "4"); + log_error (_("no signature found\n")); + rc = gpg_error (GPG_ERR_NO_DATA); + } + + /* Propagate the signature seen flag upward. Do this only on success + so that we won't issue the nodata status several times. */ + if (!rc && c->anchor && c->any_sig_seen) + c->anchor->any_sig_seen = 1; + + xfree ( c ); + return rc; +} + + int proc_encryption_packets( void *anchor, IOBUF a ) { @@ -1899,6 +1964,8 @@ proc_tree( CTX c, KBNODE node ) else if( node->pkt->pkttype == PKT_ONEPASS_SIG ) { /* check all signatures */ if( !c->have_data ) { + int use_textmode = 0; + free_md_filter_context( &c->mfx ); /* prepare to create all requested message digests */ if (gcry_md_open (&c->mfx.md, 0, 0)) @@ -1911,23 +1978,33 @@ proc_tree( CTX c, KBNODE node ) gcry_md_enable (c->mfx.md, n1->pkt->pkt.signature->digest_algo); } - /* ask for file and hash it */ + + if (n1 && n1->pkt->pkt.onepass_sig->sig_class == 0x01) + use_textmode = 1; + + /* Ask for file and hash it. */ if( c->sigs_only ) { - rc = hash_datafiles( c->mfx.md, NULL, - c->signed_data, c->sigfilename, - n1? (n1->pkt->pkt.onepass_sig->sig_class == 0x01):0 ); + if (c->signed_data.used && c->signed_data.data_fd != -1) + rc = hash_datafile_by_fd (c->mfx.md, NULL, + c->signed_data.data_fd, + use_textmode); + else + rc = hash_datafiles (c->mfx.md, NULL, + c->signed_data.data_names, + c->sigfilename, + use_textmode ); } else { - rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2, + rc = ask_for_detached_datafile (c->mfx.md, c->mfx.md2, iobuf_get_real_fname(c->iobuf), - n1? (n1->pkt->pkt.onepass_sig->sig_class == 0x01):0 ); + use_textmode ); } if( rc ) { log_error("can't hash datafile: %s\n", g10_errstr(rc)); return; } } - else if ( c->signed_data ) { + else if ( c->signed_data.used ) { log_error (_("not a detached signature\n") ); return; } @@ -1943,7 +2020,7 @@ proc_tree( CTX c, KBNODE node ) log_error("cleartext signature without data\n" ); return; } - else if ( c->signed_data ) { + else if ( c->signed_data.used ) { log_error (_("not a detached signature\n") ); return; } @@ -2019,9 +2096,15 @@ proc_tree( CTX c, KBNODE node ) gcry_md_start_debug( c->mfx.md2, "verify2" ); } if( c->sigs_only ) { - rc = hash_datafiles( c->mfx.md, c->mfx.md2, - c->signed_data, c->sigfilename, - (sig->sig_class == 0x01) ); + if (c->signed_data.used && c->signed_data.data_fd != -1) + rc = hash_datafile_by_fd (c->mfx.md, c->mfx.md2, + c->signed_data.data_fd, + (sig->sig_class == 0x01)); + else + rc = hash_datafiles (c->mfx.md, c->mfx.md2, + c->signed_data.data_names, + c->sigfilename, + (sig->sig_class == 0x01)); } else { rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2, @@ -2033,7 +2116,7 @@ proc_tree( CTX c, KBNODE node ) return; } } - else if ( c->signed_data ) { + else if ( c->signed_data.used ) { log_error (_("not a detached signature\n") ); return; } diff --git a/g10/options.h b/g10/options.h index 530eac206..8bc81b943 100644 --- a/g10/options.h +++ b/g10/options.h @@ -266,6 +266,11 @@ struct { #define DBG_EXTPROG_VALUE 1024 /* debug external program calls */ #define DBG_CARD_IO_VALUE 2048 /* debug smart card I/O. */ +/* Fixme: For now alias this value. */ +#define DBG_ASSUAN_VALUE DBG_EXTPROG_VALUE + + +/* Tests for the debugging flags. */ #define DBG_PACKET (opt.debug & DBG_PACKET_VALUE) #define DBG_CIPHER (opt.debug & DBG_CIPHER_VALUE) #define DBG_FILTER (opt.debug & DBG_FILTER_VALUE) @@ -274,6 +279,7 @@ struct { #define DBG_HASHING (opt.debug & DBG_HASHING_VALUE) #define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE) #define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE) +#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE) /* FIXME: We need to check whey we did not put this into opt. */ #define DBG_MEMORY memory_debug_mode diff --git a/g10/packet.h b/g10/packet.h index c61ab073a..9a38d76bd 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -371,6 +371,7 @@ struct notation int proc_packets( void *ctx, iobuf_t a ); int proc_signature_packets( void *ctx, iobuf_t a, strlist_t signedfiles, const char *sigfile ); +int proc_signature_packets_by_fd ( void *anchor, IOBUF a, int signed_data_fd ); int proc_encryption_packets( void *ctx, iobuf_t a ); int list_packets( iobuf_t a ); diff --git a/g10/plaintext.c b/g10/plaintext.c index cab4d6d46..6c58ae7d7 100644 --- a/g10/plaintext.c +++ b/g10/plaintext.c @@ -567,6 +567,42 @@ hash_datafiles( gcry_md_hd_t md, gcry_md_hd_t md2, strlist_t files, } +/* Hash the data from file descriptor DATA_FD and append the hash to hash + contexts MD and MD2. */ +int +hash_datafile_by_fd ( gcry_md_hd_t md, gcry_md_hd_t md2, int data_fd, + int textmode ) +{ + progress_filter_context_t *pfx = new_progress_context (); + iobuf_t fp; + + fp = iobuf_fdopen (data_fd, "rb"); + if (fp && is_secured_file (data_fd)) + { + iobuf_close (fp); + fp = NULL; + errno = EPERM; + } + if ( !fp ) + { + int rc = gpg_error_from_syserror (); + log_error ( _("can't open signed data fd=%d: %s\n"), + data_fd, strerror (errno)); + release_progress_context (pfx); + return rc; + } + + handle_progress (pfx, fp, NULL); + + do_hash ( md, md2, fp, textmode); + + iobuf_close(fp); + + release_progress_context (pfx); + return 0; +} + + /* Set up a plaintext packet with the appropriate filename. If there is a --set-filename, use it (it's already UTF8). If there is a regular filename, UTF8-ize it if necessary. If there is no diff --git a/g10/server.c b/g10/server.c new file mode 100644 index 000000000..9aa69ff6e --- /dev/null +++ b/g10/server.c @@ -0,0 +1,526 @@ +/* server.c - server mode for gpg + * Copyright (C) 2006 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "gpg.h" +#include "util.h" +#include "i18n.h" +#include "options.h" + + + +#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t)) + + +/* Data used to associate an Assuan context with local server data. */ +struct server_local_s +{ + /* Our current Assuan context. */ + assuan_context_t assuan_ctx; + /* File descriptor as set by the MESSAGE command. */ + int message_fd; +}; + + + +/* Helper to close the message fd if it is open. */ +static void +close_message_fd (ctrl_t ctrl) +{ + if (ctrl->server_local->message_fd != -1) + { + close (ctrl->server_local->message_fd); + ctrl->server_local->message_fd = -1; + } +} + + + +/* Called by libassuan for Assuan options. See the Assuan manual for + details. */ +static int +option_handler (assuan_context_t ctx, const char *key, const char *value) +{ +/* ctrl_t ctrl = assuan_get_pointer (ctx); */ + + /* Fixme: Implement the tty and locale args. */ + if (!strcmp (key, "display")) + { + } + else if (!strcmp (key, "ttyname")) + { + } + else if (!strcmp (key, "ttytype")) + { + } + else if (!strcmp (key, "lc-ctype")) + { + } + else if (!strcmp (key, "lc-messages")) + { + } + else if (!strcmp (key, "list-mode")) + { + /* This is for now a dummy option. */ + } + else + return gpg_error (GPG_ERR_UNKNOWN_OPTION); + + return 0; +} + + +/* Called by libassuan for RESET commands. */ +static void +reset_notify (assuan_context_t ctx) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + + close_message_fd (ctrl); + assuan_close_input_fd (ctx); + assuan_close_output_fd (ctx); +} + + +/* Called by libassuan for INPUT commands. */ +static void +input_notify (assuan_context_t ctx, const char *line) +{ +/* ctrl_t ctrl = assuan_get_pointer (ctx); */ + + if (strstr (line, "--armor")) + ; /* FIXME */ + else if (strstr (line, "--base64")) + ; /* FIXME */ + else if (strstr (line, "--binary")) + ; + else + ; /* FIXME (autodetect encoding) */ +} + + +/* Called by libassuan for OUTPUT commands. */ +static void +output_notify (assuan_context_t ctx, const char *line) +{ +/* ctrl_t ctrl = assuan_get_pointer (ctx); */ + + if (strstr (line, "--armor")) + ; /* FIXME */ + else if (strstr (line, "--base64")) + ; /* FIXME */ +} + + + + +/* RECIPIENT + + Set the recipient for the encryption. should be the + internal representation of the key; the server may accept any other + way of specification. If this is a valid and trusted recipient the + server does respond with OK, otherwise the return is an ERR with + the reason why the recipient can't be used, the encryption will + then not be done for this recipient. If the policy is not to + encrypt at all if not all recipients are valid, the client has to + take care of this. All RECIPIENT commands are cumulative until a + RESET or an successful ENCRYPT command. */ +static int +cmd_recipient (assuan_context_t ctx, char *line) +{ + return gpg_error (GPG_ERR_NOT_SUPPORTED); +} + + + +/* SIGNER + + Set the signer's keys for the signature creation. should + be the internal representation of the key; the server may accept + any other way of specification. If this is a valid and usable + signing key the server does respond with OK, otherwise it returns + an ERR with the reason why the key can't be used, the signing will + then not be done for this key. If the policy is not to sign at all + if not all signer keys are valid, the client has to take care of + this. All SIGNER commands are cumulative until a RESET but they + are *not* reset by an SIGN command becuase it can be expected that + set of signers are used for more than one sign operation. + + Note that this command returns an INV_RECP status which is a bit + strange, but they are very similar. */ +static int +cmd_signer (assuan_context_t ctx, char *line) +{ + return gpg_error (GPG_ERR_NOT_SUPPORTED); +} + + + +/* ENCRYPT + + Do the actual encryption process. Takes the plaintext from the + INPUT command, writes to the ciphertext to the file descriptor set + with the OUTPUT command, take the recipients form all the + recipients set so far. If this command fails the clients should + try to delete all output currently done or otherwise mark it as + invalid. GPG does ensure that there won't be any security problem + with leftover data on the output in this case. + + This command should in general not fail, as all necessary checks + have been done while setting the recipients. The input and output + pipes are closed. */ +static int +cmd_encrypt (assuan_context_t ctx, char *line) +{ + return gpg_error (GPG_ERR_NOT_SUPPORTED); +} + + + +/* DECRYPT + + This performs the decrypt operation after doing some checks on the + internal state (e.g. that only needed data has been set). */ +static int +cmd_decrypt (assuan_context_t ctx, char *line) +{ + return gpg_error (GPG_ERR_NOT_SUPPORTED); +} + + + +/* VERIFY + + This does a verify operation on the message send to the input-FD. + The result is written out using status lines. If an output FD was + given, the signed text will be written to that. + + If the signature is a detached one, the server will inquire about + the signed material and the client must provide it. + */ +static int +cmd_verify (assuan_context_t ctx, char *line) +{ + int rc; + ctrl_t ctrl = assuan_get_pointer (ctx); + int fd = assuan_get_input_fd (ctx); + int out_fd = assuan_get_output_fd (ctx); + FILE *out_fp = NULL; + + if (fd == -1) + return gpg_error (GPG_ERR_ASS_NO_INPUT); + + if (out_fd != -1) + { + out_fp = fdopen ( dup(out_fd), "w"); + if (!out_fp) + return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed"); + } + + log_debug ("WARNING: The server mode work in progress and not ready for use\n"); + + /* Need to dup it because it might get closed and libassuan won't + know about it then. */ + rc = gpg_verify (ctrl, + dup (fd), + dup (ctrl->server_local->message_fd), + out_fp); + + if (out_fp) + fclose (out_fp); + close_message_fd (ctrl); + assuan_close_input_fd (ctx); + assuan_close_output_fd (ctx); + + return rc; +} + + + +/* SIGN [--detached] + + Sign the data set with the INPUT command and write it to the sink + set by OUTPUT. With "--detached" specified, a detached signature + is created. */ +static int +cmd_sign (assuan_context_t ctx, char *line) +{ + return gpg_error (GPG_ERR_NOT_SUPPORTED); +} + + + +/* IMPORT + + Import keys as read from the input-fd, return status message for + each imported one. The import checks the validity of the key. */ +static int +cmd_import (assuan_context_t ctx, char *line) +{ + return gpg_error (GPG_ERR_NOT_SUPPORTED); +} + + + +/* EXPORT [--data [--armor|--base64]] [--] pattern + + Similar to the --export command line command, this command exports + public keys matching PATTERN. The output is send to the output fd + unless the --data option has been used in which case the output + gets send inline using regular data lines. The options "--armor" + and "--base" ospecify an output format if "--data" has been used. + Recall that in general the output format is set with the OUTPUT + command. + */ +static int +cmd_export (assuan_context_t ctx, char *line) +{ + return gpg_error (GPG_ERR_NOT_SUPPORTED); +} + + + +/* DELKEYS + + Fixme +*/ +static int +cmd_delkeys (assuan_context_t ctx, char *line) +{ + return gpg_error (GPG_ERR_NOT_SUPPORTED); +} + + + +/* MESSAGE FD[=] + + Set the file descriptor to read a message which is used with + detached signatures. */ +static int +cmd_message (assuan_context_t ctx, char *line) +{ + int rc; + int fd; + ctrl_t ctrl = assuan_get_pointer (ctx); + + rc = assuan_command_parse_fd (ctx, line, &fd); + if (rc) + return rc; + if (fd == -1) + return gpg_error (GPG_ERR_ASS_NO_INPUT); + ctrl->server_local->message_fd = fd; + return 0; +} + + + +/* LISTKEYS [] + LISTSECRETKEYS [] + + fixme +*/ +static int +do_listkeys (assuan_context_t ctx, char *line, int mode) +{ + return gpg_error (GPG_ERR_NOT_SUPPORTED); +} + + +static int +cmd_listkeys (assuan_context_t ctx, char *line) +{ + return do_listkeys (ctx, line, 3); +} + + +static int +cmd_listsecretkeys (assuan_context_t ctx, char *line) +{ + return do_listkeys (ctx, line, 2); +} + + + +/* GENKEY + + Read the parameters in native format from the input fd and create a + new OpenPGP key. + */ +static int +cmd_genkey (assuan_context_t ctx, char *line) +{ + return gpg_error (GPG_ERR_NOT_SUPPORTED); +} + + + + + + +/* Helper to register our commands with libassuan. */ +static int +register_commands (assuan_context_t ctx) +{ + static struct + { + const char *name; + int (*handler)(assuan_context_t, char *line); + } table[] = { + { "RECIPIENT", cmd_recipient }, + { "SIGNER", cmd_signer }, + { "ENCRYPT", cmd_encrypt }, + { "DECRYPT", cmd_decrypt }, + { "VERIFY", cmd_verify }, + { "SIGN", cmd_sign }, + { "IMPORT", cmd_import }, + { "EXPORT", cmd_export }, + { "INPUT", NULL }, + { "OUTPUT", NULL }, + { "MESSAGE", cmd_message }, + { "LISTKEYS", cmd_listkeys }, + { "LISTSECRETKEYS",cmd_listsecretkeys }, + { "GENKEY", cmd_genkey }, + { "DELKEYS", cmd_delkeys }, + { NULL } + }; + int i, rc; + + for (i=0; table[i].name; i++) + { + rc = assuan_register_command (ctx, table[i].name, table[i].handler); + if (rc) + return rc; + } + return 0; +} + + + + +/* Startup the server. CTRL must have been allocated by the caller + and set to the default values. */ +int +gpg_server (ctrl_t ctrl) +{ + int rc; + int filedes[2]; + assuan_context_t ctx; + static const char hello[] = ("GNU Privacy Guard's OpenPGP server " + VERSION " ready"); + + /* 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 FILEDES in this case. */ + filedes[0] = 0; + filedes[1] = 1; + rc = assuan_init_pipe_server (&ctx, filedes); + if (rc) + { + log_error ("failed to initialize the server: %s\n", gpg_strerror (rc)); + goto leave; + } + + rc = register_commands (ctx); + if (rc) + { + log_error ("failed to the register commands with Assuan: %s\n", + gpg_strerror(rc)); + goto leave; + } + + assuan_set_pointer (ctx, ctrl); + if (opt.verbose || opt.debug) + { + char *tmp = NULL; + const char *s1 = getenv ("GPG_AGENT_INFO"); + + if (asprintf (&tmp, + "Home: %s\n" + "Config: %s\n" + "AgentInfo: %s\n" + "%s", + opt.homedir, + "fixme: need config filename", + s1?s1:"[not set]", + hello) > 0) + { + assuan_set_hello_line (ctx, tmp); + free (tmp); + } + } + else + assuan_set_hello_line (ctx, hello); + assuan_register_reset_notify (ctx, reset_notify); + assuan_register_input_notify (ctx, input_notify); + assuan_register_output_notify (ctx, output_notify); + assuan_register_option_handler (ctx, option_handler); + + ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local); + if (!ctrl->server_local) + { + rc = gpg_error_from_syserror (); + goto leave; + } + ctrl->server_local->assuan_ctx = ctx; + ctrl->server_local->message_fd = -1; + + if (DBG_ASSUAN) + assuan_set_log_stream (ctx, log_get_stream ()); + + for (;;) + { + rc = assuan_accept (ctx); + if (rc == -1) + { + rc = 0; + break; + } + else if (rc) + { + log_info ("Assuan accept problem: %s\n", gpg_strerror (rc)); + break; + } + + rc = assuan_process (ctx); + if (rc) + { + log_info ("Assuan processing failed: %s\n", gpg_strerror (rc)); + continue; + } + } + + leave: + xfree (ctrl->server_local); + ctrl->server_local = NULL; + assuan_deinit_server (ctx); + return rc; +} + diff --git a/g10/verify.c b/g10/verify.c index 5145525f5..e8f5891a4 100644 --- a/g10/verify.c +++ b/g10/verify.c @@ -55,15 +55,13 @@ int verify_signatures( int nfiles, char **files ) { IOBUF fp; - armor_filter_context_t *afx; - progress_filter_context_t *pfx; + armor_filter_context_t *afx = NULL; + progress_filter_context_t *pfx = new_progress_context (); const char *sigfile; int i, rc; strlist_t sl; - pfx = new_progress_context (); - afx = new_armor_context (); - /* decide whether we should handle a detached or a normal signature, + /* Decide whether we should handle a detached or a normal signature, * which is needed so that the code later can hash the correct data and * not have a normal signature act as detached signature and ignoring the * indended signed material from the 2nd file or stdin. @@ -72,7 +70,7 @@ verify_signatures( int nfiles, char **files ) * 3. gpg file 0 ; i-- ) @@ -123,12 +122,14 @@ verify_signatures( int nfiles, char **files ) rc = 0; } + leave: release_armor_context (afx); release_progress_context (pfx); return rc; } + void print_file_status( int status, const char *name, int what ) { @@ -144,10 +145,9 @@ verify_one_file( const char *name ) { IOBUF fp; armor_filter_context_t *afx = NULL; - progress_filter_context_t *pfx; + progress_filter_context_t *pfx = new_progress_context (); int rc; - pfx = new_progress_context (); print_file_status( STATUS_FILE_START, name, 1 ); fp = iobuf_open(name); if (fp) @@ -163,8 +163,7 @@ verify_one_file( const char *name ) log_error(_("can't open `%s': %s\n"), print_fname_stdin(name), strerror (errno)); print_file_status( STATUS_FILE_ERROR, name, 1 ); - release_progress_context (pfx); - return rc; + goto leave; } handle_progress (pfx, fp, name); @@ -178,6 +177,8 @@ verify_one_file( const char *name ) rc = proc_signature_packets( NULL, fp, NULL, name ); iobuf_close(fp); write_status( STATUS_FILE_DONE ); + + leave: release_armor_context (afx); release_progress_context (pfx); return rc; @@ -217,3 +218,57 @@ verify_files( int nfiles, char **files ) } return 0; } + + + + +/* Perform a verify operation. To verify detached signatures, DATA_FD + shall be the descriptor of the signed data; for regular signatures + it needs to be -1. If OUT_FP is not NULL and DATA_FD is not -1 the + the signed material gets written that stream. + + FIXME: OUTFP is not yet implemented. +*/ +int +gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, FILE *out_fp) +{ + int rc; + iobuf_t fp; + armor_filter_context_t *afx = NULL; + progress_filter_context_t *pfx = new_progress_context (); + + fp = iobuf_fdopen (sig_fd, "rb"); + if (fp && is_secured_file (sig_fd)) + { + fp = NULL; + errno = EPERM; + } + if ( !fp ) + { + rc = gpg_error_from_syserror (); + log_error (_("can't open fd %d: %s\n"), sig_fd, strerror (errno)); + goto leave; + } + + handle_progress (pfx, fp, NULL); + + if ( !opt.no_armor && use_armor_filter (fp) ) + { + afx = new_armor_context (); + push_armor_filter (afx, fp); + } + + rc = proc_signature_packets_by_fd ( NULL, fp, data_fd ); + + if ( afx && afx->no_openpgp_data + && (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) ) + rc = gpg_error (GPG_ERR_NO_DATA); + + leave: + if (fp) + iobuf_close (fp); + release_progress_context (pfx); + release_armor_context (afx); + return rc; +} +