diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/ChangeLog | 28 | ||||
-rw-r--r-- | g10/compress.c | 3 | ||||
-rw-r--r-- | g10/dearmor.c | 4 | ||||
-rw-r--r-- | g10/encrypt.c | 81 | ||||
-rw-r--r-- | g10/export.c | 2 | ||||
-rw-r--r-- | g10/gpg.c | 9 | ||||
-rw-r--r-- | g10/keydb.h | 22 | ||||
-rw-r--r-- | g10/main.h | 6 | ||||
-rw-r--r-- | g10/openfile.c | 256 | ||||
-rw-r--r-- | g10/parse-packet.c | 12 | ||||
-rw-r--r-- | g10/pkclist.c | 211 | ||||
-rw-r--r-- | g10/revoke.c | 4 | ||||
-rw-r--r-- | g10/server.c | 167 | ||||
-rw-r--r-- | g10/sign.c | 7 |
14 files changed, 533 insertions, 279 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog index a44dac6b8..043da496e 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,5 +1,33 @@ +2009-09-30 Werner Koch <[email protected]> + + * parse-packet.c (skip_packet, parse_gpg_control) <ist_mode>: Take + care of premature EOFs. + + * gpg.c (main): Remove obsolete GCRYCTL_DISABLE_INTERNAL_LOCKING. + +2009-09-29 Werner Koch <[email protected]> + + * openfile.c (open_outfile): Re-indent. Use xstrconcat. + (NAME_OF_DEV_NULL): New. + (open_outfile): Use it. + (overwrite_filep): Use it. Also use case insensitive compare + when needed. Re-indent. + (open_outfile): Add arg INP_FD. Change all callers. + + * encrypt.c (encrypt_crypt): Add new args FILEFD, OUTPUTFD and + PROVIDED_KEYS. Change all callers. + 2009-09-28 Werner Koch <[email protected]> + * server.c (skip_options, has_option): New. + (cmd_recipient): Implement. + + * keydb.h (pk_list_t): New. + + * pkclist.c (send_status_inv_recp): New. Replace direct calls. + (build_pk_list): Factor some code out to ... + (find_and_check_key): ... new. + * encode.c: Rename to encrypt.c. Re-indent all. * encrypt.c (encode_symmetric, encode_store, encode_seskey) (encode_simple, encode_crypt, encode_filter) diff --git a/g10/compress.c b/g10/compress.c index a91dd2303..6a29c0a94 100644 --- a/g10/compress.c +++ b/g10/compress.c @@ -245,6 +245,9 @@ compress_filter( void *opaque, int control, memset( &cd, 0, sizeof cd ); cd.len = 0; cd.algorithm = zfx->algo; + /* Fixme: We should force a new CTB here: + cd.new_ctb = zfx->new_ctb; + */ init_packet( &pkt ); pkt.pkttype = PKT_COMPRESSED; pkt.pkt.compressed = &cd; diff --git a/g10/dearmor.c b/g10/dearmor.c index da888ad14..00bdf7bbd 100644 --- a/g10/dearmor.c +++ b/g10/dearmor.c @@ -64,7 +64,7 @@ dearmor_file( const char *fname ) push_armor_filter ( afx, inp ); - if( (rc = open_outfile( fname, 0, &out )) ) + if( (rc = open_outfile (GNUPG_INVALID_FD, fname, 0, &out )) ) goto leave; while( (c = iobuf_get(inp)) != -1 ) @@ -110,7 +110,7 @@ enarmor_file( const char *fname ) } - if( (rc = open_outfile( fname, 1, &out )) ) + if( (rc = open_outfile (GNUPG_INVALID_FD, fname, 1, &out )) ) goto leave; afx->what = 4; diff --git a/g10/encrypt.c b/g10/encrypt.c index 90a206522..bb3f2432a 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -264,7 +264,8 @@ encrypt_simple (const char *filename, int mode, int use_seskey) do_compress = 0; } - if ( rc || (rc = open_outfile( filename, opt.armor? 1:0, &out ))) + if ( rc || (rc = open_outfile (GNUPG_INVALID_FD, filename, + opt.armor? 1:0, &out ))) { iobuf_cancel (inp); xfree (cfx.dek); @@ -455,11 +456,15 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek, /* - * Encrypt the file with the given userids (or ask if none - * is supplied). + * Encrypt the file with the given userids (or ask if none is + * supplied). Either FILENAME or FILEFD must be given, but not both. + * The caller may provide a checked list of public keys in + * PROVIDED_PKS; if not the function builds a list of keys on its own. */ int -encrypt_crypt (const char *filename, strlist_t remusr, int use_symkey) +encrypt_crypt (gnupg_fd_t filefd, const char *filename, + strlist_t remusr, int use_symkey, pk_list_t provided_keys, + gnupg_fd_t outputfd) { iobuf_t inp = NULL; iobuf_t out = NULL; @@ -477,6 +482,9 @@ encrypt_crypt (const char *filename, strlist_t remusr, int use_symkey) PK_LIST pk_list, work_list; int do_compress; + if (filefd != GNUPG_INVALID_FD && filename) + return gpg_error (GPG_ERR_INV_ARG); + do_compress = opt.compress_algo && !RFC1991; pfx = new_progress_context (); @@ -492,10 +500,15 @@ encrypt_crypt (const char *filename, strlist_t remusr, int use_symkey) return rc; } - if ((rc = build_pk_list (remusr, &pk_list, PUBKEY_USAGE_ENC))) + if (provided_keys) + pk_list = provided_keys; + else { - release_progress_context (pfx); - return rc; + if ((rc = build_pk_list (remusr, &pk_list, PUBKEY_USAGE_ENC))) + { + release_progress_context (pfx); + return rc; + } } if(PGP2) @@ -512,7 +525,7 @@ encrypt_crypt (const char *filename, strlist_t remusr, int use_symkey) } /* Prepare iobufs. */ - inp = iobuf_open(filename); + inp = iobuf_open_fd_or_name (filefd, filename, "rb"); if (inp) iobuf_ioctl (inp, 3, 1, NULL); /* Disable fd caching. */ if (inp && is_secured_file (iobuf_get_fd (inp))) @@ -523,20 +536,30 @@ encrypt_crypt (const char *filename, strlist_t remusr, int use_symkey) } if (!inp) { + char xname[64]; + rc = gpg_error_from_syserror (); + if (filefd != GNUPG_INVALID_FD) + snprintf (xname, sizeof xname, "[fd %d]", filefd); + else if (!filename) + strcpy (xname, "[stdin]"); + else + *xname = 0; log_error (_("can't open `%s': %s\n"), - filename? filename: "[stdin]", gpg_strerror (rc) ); + *xname? xname : filename, gpg_strerror (rc) ); goto leave; } - else if (opt.verbose) - log_info (_("reading from `%s'\n"), filename? filename: "[stdin]"); + + if (opt.verbose) + log_info (_("reading from `%s'\n"), iobuf_get_fname_nonnull (inp)); handle_progress (pfx, inp, filename); if (opt.textmode) iobuf_push_filter (inp, text_filter, &tfx); - if ((rc = open_outfile( filename, opt.armor? 1:0, &out ))) + rc = open_outfile (outputfd, filename, opt.armor? 1:0, &out); + if (rc) goto leave; if (opt.armor) @@ -629,7 +652,8 @@ encrypt_crypt (const char *filename, strlist_t remusr, int use_symkey) if (!opt.no_literal) pt = setup_plaintext_name (filename, inp); - if (!iobuf_is_pipe_filename (filename) && *filename && !opt.textmode ) + if (filefd != GNUPG_INVALID_FD + && !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode ) { off_t tmpsize; int overflow; @@ -709,13 +733,16 @@ encrypt_crypt (const char *filename, strlist_t remusr, int use_symkey) plain data. */ byte copy_buffer[4096]; int bytes_copied; - while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1) - if ((rc=iobuf_write(out, copy_buffer, bytes_copied))) - { - log_error ("copying input to output failed: %s\n", - gpg_strerror (rc)); - break; - } + while ((bytes_copied = iobuf_read (inp, copy_buffer, 4096)) != -1) + { + rc = iobuf_write (out, copy_buffer, bytes_copied); + if (rc) + { + log_error ("copying input to output failed: %s\n", + gpg_strerror (rc)); + break; + } + } wipememory (copy_buffer, 4096); /* Burn the buffer. */ } @@ -735,7 +762,8 @@ encrypt_crypt (const char *filename, strlist_t remusr, int use_symkey) xfree (cfx.dek); xfree (symkey_dek); xfree (symkey_s2k); - release_pk_list (pk_list); + if (!provided_keys) + release_pk_list (pk_list); release_armor_context (afx); release_progress_context (pfx); return rc; @@ -936,9 +964,11 @@ encrypt_crypt_files (int nfiles, char **files, strlist_t remusr) } line[strlen(line)-1] = '\0'; print_file_status(STATUS_FILE_START, line, 2); - if ( (rc = encrypt_crypt(line, remusr, 0)) ) - log_error("encryption of `%s' failed: %s\n", - print_fname_stdin(line), g10_errstr(rc) ); + rc = encrypt_crypt (GNUPG_INVALID_FD, line, remusr, 0, + NULL, GNUPG_INVALID_FD); + if (rc) + log_error ("encryption of `%s' failed: %s\n", + print_fname_stdin(line), g10_errstr(rc) ); write_status( STATUS_FILE_DONE ); } } @@ -947,7 +977,8 @@ encrypt_crypt_files (int nfiles, char **files, strlist_t remusr) while (nfiles--) { print_file_status(STATUS_FILE_START, *files, 2); - if ( (rc = encrypt_crypt(*files, remusr, 0)) ) + if ( (rc = encrypt_crypt (GNUPG_INVALID_FD, *files, remusr, 0, + NULL, GNUPG_INVALID_FD)) ) log_error("encryption of `%s' failed: %s\n", print_fname_stdin(*files), g10_errstr(rc) ); write_status( STATUS_FILE_DONE ); diff --git a/g10/export.c b/g10/export.c index 09faa0375..9b87e5924 100644 --- a/g10/export.c +++ b/g10/export.c @@ -140,7 +140,7 @@ do_export( strlist_t users, int secret, unsigned int options ) memset( &zfx, 0, sizeof zfx); - rc = open_outfile( NULL, 0, &out ); + rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out ); if (rc) return rc; @@ -1920,9 +1920,6 @@ main (int argc, char **argv) gnupg_rl_initialize (); set_strusage (my_strusage); gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); - /* We don't need any locking in libgcrypt unless we use any kind of - threading. */ - gcry_control (GCRYCTL_DISABLE_INTERNAL_LOCKING); log_set_prefix ("gpg", 1); /* Make sure that our subsystems are ready. */ @@ -3437,7 +3434,8 @@ main (int argc, char **argv) { if( argc > 1 ) wrong_args(_("--encrypt [filename]")); - if( (rc = encrypt_crypt(fname,remusr,0)) ) + if( (rc = encrypt_crypt (GNUPG_INVALID_FD, fname, + remusr, 0, NULL, GNUPG_INVALID_FD)) ) log_error("%s: encryption failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) ); } @@ -3458,7 +3456,8 @@ main (int argc, char **argv) " while in %s mode\n"),compliance_option_string()); else { - if( (rc = encrypt_crypt(fname,remusr,1)) ) + if( (rc = encrypt_crypt (GNUPG_INVALID_FD, fname, + remusr, 1, NULL, GNUPG_INVALID_FD)) ) log_error("%s: encryption failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) ); } diff --git a/g10/keydb.h b/g10/keydb.h index ca3ca77ec..c58a1012b 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -83,12 +83,14 @@ struct keyblock_pos_struct { }; typedef struct keyblock_pos_struct KBPOS; -/* structure to hold a couple of public key certificates */ -typedef struct pk_list *PK_LIST; -struct pk_list { - PK_LIST next; - PKT_public_key *pk; - int flags; /* flag bit 1==throw_keyid */ +/* Structure to hold a couple of public key certificates. */ +typedef struct pk_list *PK_LIST; /* Deprecated. */ +typedef struct pk_list *pk_list_t; +struct pk_list +{ + PK_LIST next; + PKT_public_key *pk; + int flags; /* flag bit 1==throw_keyid */ }; /* structure to hold a couple of secret key certificates */ @@ -179,8 +181,12 @@ int keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr); /*-- pkclist.c --*/ void show_revocation_reason( PKT_public_key *pk, int mode ); int check_signatures_trust( PKT_signature *sig ); -void release_pk_list( PK_LIST pk_list ); -int build_pk_list( strlist_t rcpts, PK_LIST *ret_pk_list, unsigned use ); + +void release_pk_list (PK_LIST pk_list); +int build_pk_list (strlist_t rcpts, PK_LIST *ret_pk_list, unsigned use); +gpg_error_t find_and_check_key (const char *name, unsigned int use, + int mark_hidden, pk_list_t *pk_list_addr); + int algo_available( preftype_t preftype, int algo, const union pref_hint *hint ); int select_algo_from_prefs( PK_LIST pk_list, int preftype, diff --git a/g10/main.h b/g10/main.h index 4ed878d6e..4971154f9 100644 --- a/g10/main.h +++ b/g10/main.h @@ -185,7 +185,9 @@ void display_online_help( const char *keyword ); int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek); int encrypt_symmetric (const char *filename ); int encrypt_store (const char *filename ); -int encrypt_crypt (const char *filename, strlist_t remusr, int use_symkey ); +int encrypt_crypt (gnupg_fd_t filefd, const char *filename, + strlist_t remusr, int use_symkey, pk_list_t provided_keys, + gnupg_fd_t outputfd); void encrypt_crypt_files (int nfiles, char **files, strlist_t remusr); int encrypt_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len); @@ -243,7 +245,7 @@ int save_unprotected_key_to_card (PKT_secret_key *sk, int keyno); int overwrite_filep( const char *fname ); char *make_outfile_name( const char *iname ); char *ask_outfile_name( const char *name, size_t namelen ); -int open_outfile( const char *iname, int mode, iobuf_t *a ); +int open_outfile (gnupg_fd_t inp_fd, const char *iname, int mode, iobuf_t *a); iobuf_t open_sigfile( const char *iname, progress_filter_context_t *pfx ); void try_make_homedir( const char *fname ); diff --git a/g10/openfile.c b/g10/openfile.c index 55dd42c4b..5908b2e8f 100644 --- a/g10/openfile.c +++ b/g10/openfile.c @@ -1,6 +1,6 @@ /* openfile.c * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, - * 2005 Free Software Foundation, Inc. + * 2005, 2009 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -43,6 +43,13 @@ #define SKELEXT EXTSEP_S "skel" #endif +#ifdef HAVE_W32_SYSTEM +#define NAME_OF_DEV_NULL "nul" +#else +#define NAME_OF_DEV_NULL "/dev/null" +#endif + + #if defined (HAVE_DRIVE_LETTERS) || defined (__riscos__) #define CMP_FILENAME(a,b) ascii_strcasecmp( (a), (b) ) #else @@ -65,34 +72,27 @@ int overwrite_filep( const char *fname ) { - if( iobuf_is_pipe_filename (fname) ) - return 1; /* Writing to stdout is always okay */ - - if( access( fname, F_OK ) ) - return 1; /* does not exist */ - -#ifndef HAVE_DOSISH_SYSTEM - if ( !strcmp ( fname, "/dev/null" ) ) - return 1; /* does not do any harm */ -#endif -#ifdef HAVE_W32_SYSTEM - if ( !strcmp ( fname, "nul" ) ) - return 1; -#endif - - /* fixme: add some backup stuff in case of overwrite */ - if( opt.answer_yes ) - return 1; - if( opt.answer_no || opt.batch ) - return 0; /* do not overwrite */ - - tty_printf(_("File `%s' exists. "), fname); - if( cpr_enabled () ) - tty_printf ("\n"); - if( cpr_get_answer_is_yes("openfile.overwrite.okay", - _("Overwrite? (y/N) ")) ) - return 1; - return 0; + if ( iobuf_is_pipe_filename (fname) ) + return 1; /* Writing to stdout is always okay. */ + + if ( access( fname, F_OK ) ) + return 1; /* Does not exist. */ + + if ( !compare_filenames (fname, NAME_OF_DEV_NULL) ) + return 1; /* Does not do any harm. */ + + if (opt.answer_yes) + return 1; + if (opt.answer_no || opt.batch) + return 0; /* Do not overwrite. */ + + tty_printf (_("File `%s' exists. "), fname); + if (cpr_enabled ()) + tty_printf ("\n"); + if (cpr_get_answer_is_yes ("openfile.overwrite.okay", + _("Overwrite? (y/N) ")) ) + return 1; + return 0; } @@ -178,110 +178,134 @@ ask_outfile_name( const char *name, size_t namelen ) * Mode 0 = use ".gpg" * 1 = use ".asc" * 2 = use ".sig" + + * If INP_FD is not GNUPG_INVALID_FD the function will simply create + * an IOBUF for that file descriptor and ignore a INAME and MODE. + * Note that INP_FD won't be closed if the returned IOBUF is closed. */ int -open_outfile( const char *iname, int mode, IOBUF *a ) +open_outfile (gnupg_fd_t inp_fd, const char *iname, int mode, iobuf_t *a) { int rc = 0; *a = NULL; - if( iobuf_is_pipe_filename (iname) && !opt.outfile ) { - *a = iobuf_create(NULL); - if( !*a ) { - rc = gpg_error_from_syserror (); - log_error(_("can't open `%s': %s\n"), "[stdout]", strerror(errno) ); + if (inp_fd != GNUPG_INVALID_FD) + { + char xname[64]; + gnupg_fd_t fd2; + + fd2 = INT2FD (dup (FD2INT (inp_fd))); + if (fd2 == GNUPG_INVALID_FD) + *a = NULL; + else + *a = iobuf_fdopen (fd2, "wb"); + if (!*a) + { + rc = gpg_error_from_syserror (); + snprintf (xname, sizeof xname, "[fd %d]", inp_fd); + log_error (_("can't open `%s': %s\n"), xname, gpg_strerror (rc)); + } + else if (opt.verbose) + { + snprintf (xname, sizeof xname, "[fd %d]", inp_fd); + log_info (_("writing to `%s'\n"), xname); + } + } + else if (iobuf_is_pipe_filename (iname) && !opt.outfile) + { + *a = iobuf_create(NULL); + if ( !*a ) + { + rc = gpg_error_from_syserror (); + log_error (_("can't open `%s': %s\n"), "[stdout]", strerror(errno) ); + } + else if ( opt.verbose ) + log_info (_("writing to stdout\n")); } - else if( opt.verbose ) - log_info(_("writing to stdout\n")); - } - else { - char *buf = NULL; - const char *name; + else + { + char *buf = NULL; + const char *name; - if ( opt.dry_run ) - { -#ifdef HAVE_W32_SYSTEM - name = "nul"; -#else - name = "/dev/null"; -#endif - } - else if( opt.outfile ) - name = opt.outfile; - else { -#ifdef USE_ONLY_8DOT3 - if (opt.mangle_dos_filenames) + if (opt.dry_run) + name = NAME_OF_DEV_NULL; + else if (opt.outfile) + name = opt.outfile; + else { - /* It is quite common DOS system to have only one dot in a - * a filename So if we have something like this, we simple - * replace the suffix execpt in cases where the suffix is - * larger than 3 characters and not the same as. - * We should really map the filenames to 8.3 but this tends to - * be more complicated and is probaly a duty of the filesystem - */ - char *dot; - const char *newsfx = mode==1 ? ".asc" : - mode==2 ? ".sig" : ".gpg"; +#ifdef USE_ONLY_8DOT3 + if (opt.mangle_dos_filenames) + { + /* It is quite common for DOS systems to have only one + dot in a filename. If we have something like this, + we simple replace the suffix except in cases where + the suffix is larger than 3 characters and not the + same as the new one. We don't map the filenames to + 8.3 because this is a duty of the file system. */ + char *dot; + const char *newsfx; + + newsfx = (mode==1 ? ".asc" : + mode==2 ? ".sig" : ".gpg"); - buf = xmalloc(strlen(iname)+4+1); - strcpy(buf,iname); - dot = strchr(buf, '.' ); - if ( dot && dot > buf && dot[1] && strlen(dot) <= 4 - && CMP_FILENAME(newsfx, dot) ) + buf = xmalloc (strlen(iname)+4+1); + strcpy (buf, iname); + dot = strchr (buf, '.' ); + if ( dot && dot > buf && dot[1] && strlen(dot) <= 4 + && CMP_FILENAME (newsfx, dot) ) + strcpy (dot, newsfx); + else if (dot && !dot[1]) /* Do not duplicate a dot. */ + strcpy (dot, newsfx+1); + else + strcat (buf, newsfx); + } + if (!buf) +#endif /* USE_ONLY_8DOT3 */ { - strcpy(dot, newsfx ); + buf = xstrconcat (iname, + (mode==1 ? EXTSEP_S "asc" : + mode==2 ? EXTSEP_S "sig" : EXTSEP_S "gpg"), + NULL); } - else if ( dot && !dot[1] ) /* don't duplicate a dot */ - strcpy( dot, newsfx+1 ); - else - strcat ( buf, newsfx ); + name = buf; } - if (!buf) -#endif /* USE_ONLY_8DOT3 */ + + rc = 0; + while ( !overwrite_filep (name) ) { - buf = xmalloc(strlen(iname)+4+1); - strcpy(stpcpy(buf,iname), mode==1 ? EXTSEP_S "asc" : - mode==2 ? EXTSEP_S "sig" : EXTSEP_S "gpg"); + char *tmp = ask_outfile_name (NULL, 0); + if ( !tmp || !*tmp ) + { + xfree (tmp); + rc = gpg_error (GPG_ERR_EEXIST); + break; + } + xfree (buf); + name = buf = tmp; } - name = buf; - } - - rc = 0; - while( !overwrite_filep (name) ) - { - char *tmp = ask_outfile_name (NULL, 0); - if ( !tmp || !*tmp ) - { - xfree (tmp); - rc = gpg_error (GPG_ERR_EEXIST); - break; - } - xfree (buf); - name = buf = tmp; - } - if( !rc ) - { - if (is_secured_filename (name) ) - { - *a = NULL; - errno = EPERM; - } - else - *a = iobuf_create( name ); - if( !*a ) - { - rc = gpg_error_from_syserror (); - log_error(_("can't create `%s': %s\n"), name, strerror(errno) ); - } - else if( opt.verbose ) - log_info(_("writing to `%s'\n"), name ); - } - xfree(buf); - } - + if ( !rc ) + { + if (is_secured_filename (name) ) + { + *a = NULL; + errno = EPERM; + } + else + *a = iobuf_create (name); + if (!*a) + { + rc = gpg_error_from_syserror (); + log_error(_("can't create `%s': %s\n"), name, strerror(errno) ); + } + else if( opt.verbose ) + log_info (_("writing to `%s'\n"), name ); + } + xfree(buf); + } + if (*a) - iobuf_ioctl (*a,3,1,NULL); /* disable fd caching */ + iobuf_ioctl (*a, 3, 1, NULL); /* Disable fd caching. */ return rc; } diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 16ca7514f..74f7ae840 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -682,7 +682,11 @@ skip_packet( IOBUF inp, int pkttype, unsigned long pktlen, int partial ) else { for( ; pktlen; pktlen-- ) - dump_hex_line(iobuf_get(inp), &i); + { + dump_hex_line( (c=iobuf_get(inp)), &i); + if (c == -1) + break; + } } putc ('\n', listfp); return; @@ -2529,7 +2533,11 @@ parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen, } else { for( ; pktlen; pktlen-- ) - dump_hex_line(iobuf_get(inp), &i); + { + dump_hex_line ((c=iobuf_get (inp)), &i); + if (c == -1) + break; + } } putc ('\n', listfp); } diff --git a/g10/pkclist.c b/g10/pkclist.c index 3203a7ea6..16835926e 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -1,6 +1,6 @@ /* pkclist.c - create a list of public keys * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, - * 2008 Free Software Foundation, Inc. + * 2008, 2009 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -40,6 +40,18 @@ #define CONTROL_D ('D' - 'A' + 1) +static void +send_status_inv_recp (int reason, const char *name) +{ + char buf[40]; + + snprintf (buf, sizeof buf, "%d ", reason); + write_status_text_and_buffer (STATUS_INV_RECP, buf, + name, strlen (name), + -1); +} + + /**************** * Show the revocation reason as it is stored with the given signature */ @@ -656,14 +668,15 @@ check_signatures_trust( PKT_signature *sig ) void -release_pk_list( PK_LIST pk_list ) +release_pk_list (pk_list_t pk_list) { - PK_LIST pk_rover; - - for( ; pk_list; pk_list = pk_rover ) { - pk_rover = pk_list->next; - free_public_key( pk_list->pk ); - xfree( pk_list ); + PK_LIST pk_rover; + + for ( ; pk_list; pk_list = pk_rover) + { + pk_rover = pk_list->next; + free_public_key ( pk_list->pk ); + xfree ( pk_list ); } } @@ -680,7 +693,7 @@ key_present_in_pk_list(PK_LIST pk_list, PKT_public_key *pk) /**************** - * Return a malloced string with a default reciepient if there is any + * Return a malloced string with a default recipient if there is any */ static char * default_recipient(void) @@ -760,6 +773,96 @@ expand_group(strlist_t input) } +/* Helper for build_pk_list to find and check one key. This helper is + also used directly in server mode by the RECIPIENTS command. On + success the new key is added to PK_LIST_ADDR. NAME is the user id + of the key. USE the requested usage and a set MARK_HIDDEN will mark + the key in the updated list as a hidden recipient. */ +gpg_error_t +find_and_check_key (const char *name, unsigned int use, + int mark_hidden, pk_list_t *pk_list_addr) +{ + int rc; + PKT_public_key *pk; + int trustlevel; + + if (!name || !*name) + return gpg_error (GPG_ERR_INV_NAME); + + pk = xtrycalloc (1, sizeof *pk); + if (!pk) + return gpg_error_from_syserror (); + pk->req_usage = use; + + rc = get_pubkey_byname (NULL, pk, name, NULL, NULL, 0, 0); + if (rc) + { + /* Key not found or other error. */ + log_error (_("%s: skipped: %s\n"), name, g10_errstr(rc) ); + send_status_inv_recp (0, name); + free_public_key (pk); + return rc; + } + + rc = openpgp_pk_test_algo2 (pk->pubkey_algo, use); + if (rc) + { + /* Key found but not usable for us (e.g. sign-only key). */ + send_status_inv_recp (0, name); + log_error (_("%s: skipped: %s\n"), name, g10_errstr(rc) ); + free_public_key (pk); + return rc; + } + + /* Key found and usable. Check validity. */ + trustlevel = get_validity (pk, pk->user_id); + if ( (trustlevel & TRUST_FLAG_DISABLED) ) + { + /* Key has been disabled. */ + send_status_inv_recp (0, name); + log_info (_("%s: skipped: public key is disabled\n"), name); + free_public_key (pk); + return G10ERR_UNU_PUBKEY; + } + + if ( !do_we_trust_pre (pk, trustlevel) ) + { + /* We don't trust this key. */ + send_status_inv_recp (10, name); + free_public_key (pk); + return G10ERR_UNU_PUBKEY; + } + /* Note: do_we_trust may have changed the trustlevel. */ + + /* Skip the actual key if the key is already present in the + list. */ + if (!key_present_in_pk_list (*pk_list_addr, pk)) + { + log_info (_("%s: skipped: public key already present\n"), name); + free_public_key (pk); + } + else + { + pk_list_t r; + + r = xtrymalloc (sizeof *r); + if (!r) + { + rc = gpg_error_from_syserror (); + free_public_key (pk); + return rc; + } + r->pk = pk; + r->next = *pk_list_addr; + r->flags = mark_hidden? 1:0; + *pk_list_addr = r; + } + + return 0; +} + + + /* This is the central function to collect the keys for recipients. It is thus used to prepare a public key encryption. encrypt-to keys, default keys and the keys for the actual recipients are all @@ -831,8 +934,7 @@ build_pk_list( strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use ) { free_public_key ( pk ); pk = NULL; log_error (_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) ); - write_status_text_and_buffer (STATUS_INV_RECP, "0 ", - rov->d, strlen (rov->d), -1); + send_status_inv_recp (0, rov->d); goto fail; } else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo, use)) ) @@ -873,8 +975,7 @@ build_pk_list( strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use ) available. */ free_public_key( pk ); pk = NULL; log_error(_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) ); - write_status_text_and_buffer (STATUS_INV_RECP, "0 ", - rov->d, strlen (rov->d), -1); + send_status_inv_recp (0, rov->d); goto fail; } } @@ -1078,85 +1179,11 @@ build_pk_list( strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use ) if ( (remusr->flags & 1) ) continue; /* encrypt-to keys are already handled. */ - pk = xmalloc_clear( sizeof *pk ); - pk->req_usage = use; - if ((rc = get_pubkey_byname (NULL, pk, remusr->d, NULL, NULL, 0, 0))) - { - /* Key not found or other error. */ - free_public_key( pk ); pk = NULL; - log_error(_("%s: skipped: %s\n"), remusr->d, g10_errstr(rc) ); - write_status_text_and_buffer (STATUS_INV_RECP, "0 ", - remusr->d, strlen (remusr->d), - -1); - goto fail; - } - else if ( !(rc=openpgp_pk_test_algo2(pk->pubkey_algo, use )) ) - { - /* Key found and usable. Check validity. */ - int trustlevel; - - trustlevel = get_validity (pk, pk->user_id); - if ( (trustlevel & TRUST_FLAG_DISABLED) ) - { - /*Key has been disabled. */ - free_public_key(pk); pk = NULL; - log_info(_("%s: skipped: public key is disabled\n"), - remusr->d); - write_status_text_and_buffer (STATUS_INV_RECP, "0 ", - remusr->d, - strlen (remusr->d), - -1); - rc=G10ERR_UNU_PUBKEY; - goto fail; - } - else if ( do_we_trust_pre( pk, trustlevel ) ) - { - /* Note: do_we_trust may have changed the trustlevel */ - - /* We have at least one valid recipient. It doesn't - * matters if this recipient is already present. */ - any_recipients = 1; - - /* Skip the actual key if the key is already present - * in the list */ - if (!key_present_in_pk_list(pk_list, pk)) - { - free_public_key(pk); pk = NULL; - log_info(_("%s: skipped: public key already present\n"), - remusr->d); - } - else - { - PK_LIST r; - r = xmalloc( sizeof *r ); - r->pk = pk; pk = NULL; - r->next = pk_list; - r->flags = (remusr->flags&2)?1:0; - pk_list = r; - } - } - else - { /* We don't trust this key. */ - free_public_key( pk ); pk = NULL; - write_status_text_and_buffer (STATUS_INV_RECP, "10 ", - remusr->d, - strlen (remusr->d), - -1); - rc=G10ERR_UNU_PUBKEY; - goto fail; - } - } - else - { - /* Key found but not usable for us (e.g. sign-only key). */ - free_public_key( pk ); pk = NULL; - write_status_text_and_buffer (STATUS_INV_RECP, "0 ", - remusr->d, - strlen (remusr->d), - -1); - log_error(_("%s: skipped: %s\n"), remusr->d, g10_errstr(rc) ); - goto fail; - } + rc = find_and_check_key (remusr->d, use, !!(remusr->flags&2), + &pk_list); + if (rc) + goto fail; + any_recipients = 1; } } diff --git a/g10/revoke.c b/g10/revoke.c index cce6d69f6..b34684ecd 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -326,7 +326,7 @@ gen_desig_revoke( const char *uname, strlist_t locusr ) if( !opt.armor ) tty_printf(_("ASCII armored output forced.\n")); - if( (rc = open_outfile( NULL, 0, &out )) ) + if( (rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out )) ) goto leave; afx->what = 1; @@ -550,7 +550,7 @@ gen_revoke( const char *uname ) if( !opt.armor ) tty_printf(_("ASCII armored output forced.\n")); - if( (rc = open_outfile( NULL, 0, &out )) ) + if( (rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out )) ) goto leave; afx->what = 1; diff --git a/g10/server.c b/g10/server.c index b2285955e..87a52d21f 100644 --- a/g10/server.c +++ b/g10/server.c @@ -33,6 +33,7 @@ #include "i18n.h" #include "options.h" #include "../common/sysutils.h" +#include "status.h" #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t)) @@ -45,6 +46,10 @@ struct server_local_s assuan_context_t assuan_ctx; /* File descriptor as set by the MESSAGE command. */ gnupg_fd_t message_fd; + + /* List of prepared recipients. */ + pk_list_t recplist; + }; @@ -61,6 +66,39 @@ close_message_fd (ctrl_t ctrl) } +/* Skip over options. Blanks after the options are also removed. */ +static char * +skip_options (const char *line) +{ + while (spacep (line)) + line++; + while ( *line == '-' && line[1] == '-' ) + { + while (*line && !spacep (line)) + line++; + while (spacep (line)) + line++; + } + return (char*)line; +} + + +/* Check whether the option NAME appears in LINE. */ +static int +has_option (const char *line, const char *name) +{ + const char *s; + int n = strlen (name); + + s = strstr (line, name); + if (s && s >= skip_options (line)) + return 0; + return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); +} + + + + /* Called by libassuan for Assuan options. See the Assuan manual for details. */ @@ -111,6 +149,9 @@ reset_notify (assuan_context_t ctx) { ctrl_t ctrl = assuan_get_pointer (ctx); + release_pk_list (ctrl->server_local->recplist); + ctrl->server_local->recplist = NULL; + close_message_fd (ctrl); assuan_close_input_fd (ctx); assuan_close_output_fd (ctx); @@ -157,7 +198,7 @@ output_notify (assuan_context_t ctx, const char *line) -/* RECIPIENT <userID> +/* RECIPIENT [--hidden] <userID> Set the recipient for the encryption. <userID> should be the internal representation of the key; the server may accept any other @@ -171,9 +212,26 @@ output_notify (assuan_context_t ctx, const char *line) static gpg_error_t cmd_recipient (assuan_context_t ctx, char *line) { - (void)ctx; - (void)line; - return gpg_error (GPG_ERR_NOT_SUPPORTED); + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err; + int hidden; + + hidden = has_option (line,"--hidden"); + line = skip_options (line); + + /* FIXME: Expand groups + if (opt.grouplist) + remusr = expand_group (rcpts); + else + remusr = rcpts; + */ + + err = find_and_check_key (line, PUBKEY_USAGE_ENC, hidden, + &ctrl->server_local->recplist); + + if (err) + log_error ("command '%s' failed: %s\n", "RECIPIENT", gpg_strerror (err)); + return err; } @@ -206,22 +264,81 @@ cmd_signer (assuan_context_t ctx, char *line) /* 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. */ + INPUT command, writes the ciphertext to the file descriptor set + with the OUTPUT command, take the recipients from all the + recipients set so far with RECIPIENTS. + + 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. + + In most cases this command won't fail because most necessary checks + have been done while setting the recipients. However some checks + can only be done right here and thus error may occur anyway (for + example, no recipients at all). + + The input, output and message pipes are closed after this + command. */ static gpg_error_t cmd_encrypt (assuan_context_t ctx, char *line) { - (void)ctx; - (void)line; - return gpg_error (GPG_ERR_NOT_SUPPORTED); + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err; + int inp_fd, out_fd; + + (void)line; /* LINE is not used. */ + + if ( !ctrl->server_local->recplist ) + { + write_status_text (STATUS_NO_RECP, "0"); + err = gpg_error (GPG_ERR_NO_USER_ID); + goto leave; + } + + inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0); + if (inp_fd == -1) + { + err = set_error (GPG_ERR_ASS_NO_INPUT, NULL); + goto leave; + } + out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1); + if (out_fd == -1) + { + err = set_error (GPG_ERR_ASS_NO_OUTPUT, NULL); + goto leave; + } + + /* Fixme: Check that we are using real files and not pipes if in + PGP-2 mode. Do all the other checks we do in gpg.c for aEncr. + Maybe we should drop the PGP2 compatibility. */ + + + /* FIXME: GPGSM does this here: Add all encrypt-to marked recipients + from the default list. */ + + /* fixme: err = ctrl->audit? 0 : start_audit_session (ctrl);*/ + + err = encrypt_crypt (inp_fd, NULL, NULL, 0, + ctrl->server_local->recplist, + out_fd); + + leave: + /* Release the recipient list on success. */ + if (!err) + { + release_pk_list (ctrl->server_local->recplist); + ctrl->server_local->recplist = NULL; + } + + /* Close and reset the fds. */ + close_message_fd (ctrl); + assuan_close_input_fd (ctx); + assuan_close_output_fd (ctx); + + if (err) + log_error ("command '%s' failed: %s\n", "ENCRYPT", gpg_strerror (err)); + return err; } @@ -258,6 +375,9 @@ cmd_verify (assuan_context_t ctx, char *line) gnupg_fd_t out_fd = assuan_get_output_fd (ctx); FILE *out_fp = NULL; + /* FIXME: Revamp this code it is nearly to 3 years old and was only + intended as a quick test. */ + (void)line; if (fd == GNUPG_INVALID_FD) @@ -270,8 +390,8 @@ cmd_verify (assuan_context_t ctx, char *line) return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed"); } - log_debug ("WARNING: The server mode work " - "in progress and not ready for use\n"); + log_debug ("WARNING: The server mode is 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. */ @@ -596,8 +716,13 @@ gpg_server (ctrl_t ctrl) } leave: - xfree (ctrl->server_local); - ctrl->server_local = NULL; + if (ctrl->server_local) + { + release_pk_list (ctrl->server_local->recplist); + + xfree (ctrl->server_local); + ctrl->server_local = NULL; + } assuan_release (ctx); return rc; } diff --git a/g10/sign.c b/g10/sign.c index 0528427db..92617a981 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -801,7 +801,8 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr, else if( opt.verbose ) log_info(_("writing to `%s'\n"), outfile ); } - else if( (rc = open_outfile( fname, opt.armor? 1: detached? 2:0, &out ))) + else if( (rc = open_outfile (GNUPG_INVALID_FD, fname, + opt.armor? 1: detached? 2:0, &out ))) goto leave; /* prepare to calculate the MD over the input */ @@ -1110,7 +1111,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile ) else if( opt.verbose ) log_info(_("writing to `%s'\n"), outfile ); } - else if( (rc = open_outfile( fname, 1, &out )) ) + else if( (rc = open_outfile (GNUPG_INVALID_FD, fname, 1, &out )) ) goto leave; iobuf_writestr(out, "-----BEGIN PGP SIGNED MESSAGE-----" LF ); @@ -1275,7 +1276,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr) cfx.dek->use_mdc=1; /* now create the outfile */ - rc = open_outfile (fname, opt.armor? 1:0, &out); + rc = open_outfile (GNUPG_INVALID_FD, fname, opt.armor? 1:0, &out); if (rc) goto leave; |