diff --git a/common/ChangeLog b/common/ChangeLog index 34894effd..575c9ed1a 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,15 @@ +2009-09-29 Werner Koch + + * exechelp.c (create_inheritable_pipe): Rename to + create_inheritable_pipe_w. + (create_inheritable_pipe_r): New. + (gnupg_create_outbound_pipe): New. + + * iobuf.h: Include "sysutils.h" + + * iobuf.c (iobuf_open_fd_or_name): New. + (iobuf_get_fname_nonnull): New. + 2009-09-23 Marcus Brinkmann * asshelp.c (start_new_gpg_agent): Allocate assuan context before diff --git a/common/audit.h b/common/audit.h index 491710706..5f5aff419 100644 --- a/common/audit.h +++ b/common/audit.h @@ -62,6 +62,15 @@ typedef enum operations the Dirmngr is not required and thus no such event will be logged. */ + AUDIT_GPG_READY, /* err */ + /* Indicates whether the Gpg engine is available. */ + + AUDIT_GPGSM_READY, /* err */ + /* Indicates whether the Gpgsm engine is available. */ + + AUDIT_G13_READY, /* err */ + /* Indicates whether the G13 engine is available. */ + AUDIT_GOT_DATA, /* Data to be processed has been seen. */ diff --git a/common/exechelp.c b/common/exechelp.c index a5e25fd5d..89604902a 100644 --- a/common/exechelp.c +++ b/common/exechelp.c @@ -304,7 +304,7 @@ build_w32_commandline (const char *pgmname, const char * const *argv, #ifdef HAVE_W32_SYSTEM /* Create pipe where the write end is inheritable. */ static int -create_inheritable_pipe (int filedes[2]) +create_inheritable_pipe_w (int filedes[2]) { HANDLE r, w, h; SECURITY_ATTRIBUTES sec_attr; @@ -332,6 +332,37 @@ create_inheritable_pipe (int filedes[2]) filedes[1] = handle_to_fd (w); return 0; } + +/* Create pipe where the read end is inheritable. */ +static int +create_inheritable_pipe_r (int filedes[2]) +{ + HANDLE r, w, h; + SECURITY_ATTRIBUTES sec_attr; + + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + if (!CreatePipe (&r, &w, &sec_attr, 0)) + return -1; + + if (!DuplicateHandle (GetCurrentProcess(), r, + GetCurrentProcess(), &h, 0, + TRUE, DUPLICATE_SAME_ACCESS )) + { + log_error ("DuplicateHandle failed: %s\n", w32_strerror (-1)); + CloseHandle (r); + CloseHandle (w); + return -1; + } + CloseHandle (r); + r = h; + + filedes[0] = handle_to_fd (r); + filedes[1] = handle_to_fd (w); + return 0; +} #endif /*HAVE_W32_SYSTEM*/ @@ -425,7 +456,51 @@ gnupg_create_inbound_pipe (int filedes[2]) filedes[0] = filedes[1] = -1; err = gpg_error (GPG_ERR_GENERAL); - if (!create_inheritable_pipe (fds)) + if (!create_inheritable_pipe_w (fds)) + { + filedes[0] = _open_osfhandle (fds[0], 0); + if (filedes[0] == -1) + { + log_error ("failed to translate osfhandle %p\n", (void*)fds[0]); + CloseHandle (fd_to_handle (fds[1])); + } + else + { + filedes[1] = _open_osfhandle (fds[1], 1); + if (filedes[1] == -1) + { + log_error ("failed to translate osfhandle %p\n", (void*)fds[1]); + close (filedes[0]); + filedes[0] = -1; + CloseHandle (fd_to_handle (fds[1])); + } + else + err = 0; + } + } +#else + if (pipe (filedes) == -1) + { + err = gpg_error_from_syserror (); + filedes[0] = filedes[1] = -1; + } +#endif + return err; +} + + +/* Portable function to create a pipe. Under Windows the read end is + inheritable. */ +gpg_error_t +gnupg_create_outbound_pipe (int filedes[2]) +{ + gpg_error_t err = 0; +#if HAVE_W32_SYSTEM + int fds[2]; + + filedes[0] = filedes[1] = -1; + err = gpg_error (GPG_ERR_GENERAL); + if (!create_inheritable_pipe_r (fds)) { filedes[0] = _open_osfhandle (fds[0], 0); if (filedes[0] == -1) @@ -522,7 +597,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[], return err; /* Create a pipe. */ - if (create_inheritable_pipe (rp)) + if (create_inheritable_pipe_w (rp)) { err = gpg_error (GPG_ERR_GENERAL); log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); diff --git a/common/exechelp.h b/common/exechelp.h index 0efee294c..3d70e1096 100644 --- a/common/exechelp.h +++ b/common/exechelp.h @@ -44,6 +44,10 @@ int *get_all_open_fds (void); inheritable. */ gpg_error_t gnupg_create_inbound_pipe (int filedes[2]); +/* Portable function to create a pipe. Under Windows the read end is + inheritable. */ +gpg_error_t gnupg_create_outbound_pipe (int filedes[2]); + /* Fork and exec the PGMNAME, connect the file descriptor of INFILE to stdin, write the output to OUTFILE, return a new stream in diff --git a/common/iobuf.c b/common/iobuf.c index 4ec151f5f..e3ea0b4cb 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -1260,6 +1260,32 @@ iobuf_is_pipe_filename (const char *fname) return check_special_filename (fname) != -1; } + +/* Either open the file specified by the file descriptor FD or - if FD + is GNUPG_INVALID_FD - the file with name FNAME. As of now MODE is + assumed to be "rb" if FNAME is used. In contrast to iobuf_fdopen + the fiel descriptor FD will not be closed during an iobuf_close. */ +iobuf_t +iobuf_open_fd_or_name (gnupg_fd_t fd, const char *fname, const char *mode) +{ + iobuf_t a; + + if (fd == GNUPG_INVALID_FD) + a = iobuf_open (fname); + else + { + gnupg_fd_t fd2; + + fd2 = dup (fd); + if (fd2 == GNUPG_INVALID_FD) + a = NULL; + else + a = iobuf_fdopen (fd2, mode); + } + return a; +} + + /**************** * Create a head iobuf for reading from a file * returns: NULL if an error occures and sets errno @@ -1306,8 +1332,8 @@ iobuf_open (const char *fname) } /**************** - * Create a head iobuf for reading from a file - * returns: NULL if an error occures and sets errno + * Create a head iobuf for reading or writing from/to a file + * Returns: NULL if an error occures and sets ERRNO. */ iobuf_t iobuf_fdopen (int fd, const char *mode) @@ -2355,7 +2381,9 @@ iobuf_seek (iobuf_t a, off_t newpos) /**************** - * Retrieve the real filename + * Retrieve the real filename. This is the filename actually used on + * disk and not a made up one. Returns NULL if no real filename is + * available. */ const char * iobuf_get_real_fname (iobuf_t a) @@ -2376,7 +2404,7 @@ iobuf_get_real_fname (iobuf_t a) /**************** - * Retrieve the filename + * Retrieve the filename. This name should only be used in diagnostics. */ const char * iobuf_get_fname (iobuf_t a) @@ -2390,6 +2418,16 @@ iobuf_get_fname (iobuf_t a) return NULL; } +/* Same as iobuf_get_fname but never returns NULL. */ +const char * +iobuf_get_fname_nonnull (iobuf_t a) +{ + const char *fname; + + fname = iobuf_get_fname (a); + return fname? fname : "[?]"; +} + /**************** * enable partial block mode as described in the OpenPGP draft. diff --git a/common/iobuf.h b/common/iobuf.h index 8a3671ebc..936481fc1 100644 --- a/common/iobuf.h +++ b/common/iobuf.h @@ -21,7 +21,7 @@ #define GNUPG_COMMON_IOBUF_H #include "../include/types.h" /* fixme: should be moved elsewhere. */ - +#include "../common/sysutils.h" #define DBG_IOBUF iobuf_debug_mode @@ -85,6 +85,8 @@ int iobuf_is_pipe_filename (const char *fname); iobuf_t iobuf_alloc (int use, size_t bufsize); iobuf_t iobuf_temp (void); iobuf_t iobuf_temp_with_content (const char *buffer, size_t length); +iobuf_t iobuf_open_fd_or_name (gnupg_fd_t fd, const char *fname, + const char *mode); iobuf_t iobuf_open (const char *fname); iobuf_t iobuf_fdopen (int fd, const char *mode); iobuf_t iobuf_sockopen (int fd, const char *mode); @@ -131,6 +133,7 @@ off_t iobuf_get_filelength (iobuf_t a, int *overflow); int iobuf_get_fd (iobuf_t a); const char *iobuf_get_real_fname (iobuf_t a); const char *iobuf_get_fname (iobuf_t a); +const char *iobuf_get_fname_nonnull (iobuf_t a); void iobuf_set_partial_block_mode (iobuf_t a, size_t len); 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 + + * parse-packet.c (skip_packet, parse_gpg_control) : Take + care of premature EOFs. + + * gpg.c (main): Remove obsolete GCRYCTL_DISABLE_INTERNAL_LOCKING. + +2009-09-29 Werner Koch + + * 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 + * 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; diff --git a/g10/gpg.c b/g10/gpg.c index 6771986d9..55ba2cd9d 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -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 ( 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( access( fname, F_OK ) ) - return 1; /* does not exist */ + if (opt.answer_yes) + return 1; + if (opt.answer_no || opt.batch) + return 0; /* Do not overwrite. */ -#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; + 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( opt.verbose ) - log_info(_("writing to stdout\n")); - } - else { - char *buf = NULL; - const char *name; + 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 + { + 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 { + if (opt.dry_run) + name = NAME_OF_DEV_NULL; + else if (opt.outfile) + name = opt.outfile; + else + { #ifdef USE_ONLY_8DOT3 - if (opt.mangle_dos_filenames) - { - /* 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"; - - 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) ) + if (opt.mangle_dos_filenames) { - strcpy(dot, newsfx ); + /* 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) ) + strcpy (dot, newsfx); + else if (dot && !dot[1]) /* Do not duplicate a dot. */ + strcpy (dot, newsfx+1); + else + strcat (buf, newsfx); } - else if ( dot && !dot[1] ) /* don't duplicate a dot */ - strcpy( dot, newsfx+1 ); - else - strcat ( buf, newsfx ); - } - if (!buf) + if (!buf) #endif /* USE_ONLY_8DOT3 */ - { - buf = xmalloc(strlen(iname)+4+1); - strcpy(stpcpy(buf,iname), mode==1 ? EXTSEP_S "asc" : - mode==2 ? EXTSEP_S "sig" : EXTSEP_S "gpg"); + { + buf = xstrconcat (iname, + (mode==1 ? EXTSEP_S "asc" : + mode==2 ? EXTSEP_S "sig" : EXTSEP_S "gpg"), + NULL); + } + 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; } - 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 +/* RECIPIENT [--hidden] Set the recipient for the encryption. 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. + 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. - 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. */ + 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; diff --git a/g13/Makefile.am b/g13/Makefile.am index dce2f0b04..44f546eb7 100644 --- a/g13/Makefile.am +++ b/g13/Makefile.am @@ -24,12 +24,19 @@ AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common include $(top_srcdir)/am/cmacros.am -AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) +AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_PTH_CFLAGS) $(PTH_CFLAGS) g13_SOURCES = \ - g13.c g13.h + g13.c g13.h \ + keyblob.h \ + utils.c utils.h \ + create.c create.h \ + call-gpg.c call-gpg.h \ + backend.c backend.h \ + be-encfs.c be-encfs.h \ + be-truecrypt.c be-truecrypt.h -g13_LDADD = $(libcommon) ../jnlib/libjnlib.a ../gl/libgnu.a \ - $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \ - $(LIBINTL) +g13_LDADD = $(libcommonpth) ../jnlib/libjnlib.a ../gl/libgnu.a \ + $(LIBGCRYPT_LIBS) $(LIBASSUAN_PTH_LIBS) $(PTH_LIBS) \ + $(GPG_ERROR_LIBS) $(LIBINTL) diff --git a/g13/backend.c b/g13/backend.c new file mode 100644 index 000000000..a6f38719a --- /dev/null +++ b/g13/backend.c @@ -0,0 +1,83 @@ +/* backend.c - Dispatcher to the various backends. + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "g13.h" +#include "i18n.h" +#include "keyblob.h" +#include "backend.h" +#include "be-encfs.h" +#include "be-truecrypt.h" + + +static gpg_error_t +no_such_backend (int conttype) +{ + log_error ("invalid backend %d given - this is most likely a bug\n", + conttype); + return gpg_error (GPG_ERR_INTERNAL); +} + + +/* If the backend requires a separate file or directory for the + container, return its name by computing it from FNAME which gives + the g13 filename. The new file name is allocated and stored at + R_NAME, if this is expected to be a directory true is stored at + R_ISDIR. If no detached name is expected or an error occurs NULL + is stored at R_NAME. The function returns 0 on success or an error + code. */ +gpg_error_t +be_get_detached_name (int conttype, const char *fname, + char **r_name, int *r_isdir) +{ + *r_name = NULL; + *r_isdir = 0; + switch (conttype) + { + case CONTTYPE_ENCFS: + return be_encfs_get_detached_name (fname, r_name, r_isdir); + + default: + return no_such_backend (conttype); + } +} + + +gpg_error_t +be_create_new_keys (int conttype, membuf_t *mb) +{ + switch (conttype) + { + case CONTTYPE_ENCFS: + return be_encfs_create_new_keys (mb); + + case CONTTYPE_TRUECRYPT: + return be_truecrypt_create_new_keys (mb); + + default: + return no_such_backend (conttype); + } +} + diff --git a/g13/backend.h b/g13/backend.h new file mode 100644 index 000000000..ffd03d3f5 --- /dev/null +++ b/g13/backend.h @@ -0,0 +1,32 @@ +/* backend.h - Defs for the dispatcher to the various backends. + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef G13_BACKEND_H +#define G13_BACKEND_H + +#include "../common/membuf.h" + + +gpg_error_t be_get_detached_name (int conttype, const char *fname, + char **r_name, int *r_isdir); +gpg_error_t be_create_new_keys (int conttype, membuf_t *mb); + + +#endif /*G13_BACKEND_H*/ + diff --git a/g13/be-encfs.c b/g13/be-encfs.c new file mode 100644 index 000000000..18030b80e --- /dev/null +++ b/g13/be-encfs.c @@ -0,0 +1,58 @@ +/* be-encfs.c - The EncFS based backend + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "g13.h" +#include "i18n.h" +#include "keyblob.h" +#include "be-encfs.h" + +/* See be_get_detached_name for a description. Note that the + dispatcher code makes sure that NULL is stored at R_NAME before + calling us. */ +gpg_error_t +be_encfs_get_detached_name (const char *fname, char **r_name, int *r_isdir) +{ + char *result; + + if (!fname || !*fname) + return gpg_error (GPG_ERR_INV_ARG); + + result = strconcat (fname, ".d", NULL); + if (!result) + return gpg_error_from_syserror (); + *r_name = result; + *r_isdir = 1; + return 0; +} + + +gpg_error_t +be_encfs_create_new_keys (membuf_t *mb) +{ + return 0; +} + + diff --git a/g13/be-encfs.h b/g13/be-encfs.h new file mode 100644 index 000000000..061385345 --- /dev/null +++ b/g13/be-encfs.h @@ -0,0 +1,31 @@ +/* be-encfs.h - Public defs for the EncFS based backend + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef G13_BE_ENCFS_H +#define G13_BE_ENCFS_H + +#include "backend.h" + +gpg_error_t be_encfs_get_detached_name (const char *fname, + char **r_name, int *r_isdir); +gpg_error_t be_encfs_create_new_keys (membuf_t *mb); + + +#endif /*G13_BE_ENCFS_H*/ + diff --git a/g13/be-truecrypt.c b/g13/be-truecrypt.c new file mode 100644 index 000000000..6f51321f4 --- /dev/null +++ b/g13/be-truecrypt.c @@ -0,0 +1,39 @@ +/* be-truecrypt.c - The Truecrypt based backend + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "g13.h" +#include "i18n.h" +#include "be-truecrypt.h" + + +gpg_error_t +be_truecrypt_create_new_keys (membuf_t *mb) +{ + (void)mb; + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); +} + + diff --git a/g13/be-truecrypt.h b/g13/be-truecrypt.h new file mode 100644 index 000000000..ef2c5675b --- /dev/null +++ b/g13/be-truecrypt.h @@ -0,0 +1,29 @@ +/* be-truecrypt.h - Public defs for the Truecrypt based backend + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef G13_BE_TRUECRYPT_H +#define G13_BE_TRUECRYPT_H + +#include "backend.h" + +gpg_error_t be_truecrypt_create_new_keys (membuf_t *mb); + + +#endif /*G13_BE_TRUECRYPT_H*/ + diff --git a/g13/call-gpg.c b/g13/call-gpg.c new file mode 100644 index 000000000..2399058b0 --- /dev/null +++ b/g13/call-gpg.c @@ -0,0 +1,466 @@ +/* call-gpg.c - Communication with the GPG + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "g13.h" +#include +#include "i18n.h" +#include "call-gpg.h" +#include "utils.h" +#include "../common/exechelp.h" + + + +/* Fire up a new GPG. Handle the server's initial greeting. Returns + 0 on success and stores the assuan context at R_CTX. */ +static gpg_error_t +start_gpg (ctrl_t ctrl, int input_fd, int output_fd, assuan_context_t *r_ctx) +{ + gpg_error_t err; + assuan_context_t ctx = NULL; + const char *pgmname; + const char *argv[6]; + int no_close_list[5]; + int i; + char line[ASSUAN_LINELENGTH]; + + (void)ctrl; + + *r_ctx = NULL; + + err = assuan_new (&ctx); + if (err) + { + log_error ("can't allocate assuan context: %s\n", gpg_strerror (err)); + return err; + } + + /* The first time we are used, intialize the gpg_program variable. */ + if ( !opt.gpg_program || !*opt.gpg_program ) + opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG); + + if (opt.verbose) + log_info (_("no running gpg - starting `%s'\n"), opt.gpg_program); + + /* Compute argv[0]. */ + if ( !(pgmname = strrchr (opt.gpg_program, '/'))) + pgmname = opt.gpg_program; + else + pgmname++; + + if (fflush (NULL)) + { + err = gpg_error_from_syserror (); + log_error ("error flushing pending output: %s\n", gpg_strerror (err)); + return err; + } + + i = 0; + argv[i++] = pgmname; + argv[i++] = "--server"; + if ((opt.debug & 1024)) + argv[i++] = "--debug=1024"; + argv[i++] = "-z"; + argv[i++] = "0"; + argv[i++] = NULL; + + i = 0; + if (log_get_fd () != -1) + no_close_list[i++] = log_get_fd (); + no_close_list[i++] = fileno (stderr); + if (input_fd != -1) + no_close_list[i++] = input_fd; + if (output_fd != -1) + no_close_list[i++] = output_fd; + no_close_list[i] = -1; + + /* Connect to GPG and perform initial handshaking. */ + err = assuan_pipe_connect (ctx, opt.gpg_program, argv, no_close_list); + + /* if (!err) */ + /* err = assuan_transact (ctx, "OPTION audit-events=1", */ + /* NULL, NULL, NULL, NULL, NULL, NULL); */ + /* audit_log_ok (ctrl->audit, AUDIT_GPG_READY, err); */ + + if (err) + { + assuan_release (ctx); + log_error ("can't connect to GPG: %s\n", gpg_strerror (err)); + return gpg_error (GPG_ERR_NO_ENGINE); + } + + if (input_fd != -1) + { + snprintf (line, sizeof line, "INPUT FD=%d", input_fd); + err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); + if (err) + { + assuan_release (ctx); + log_error ("error sending INPUT command: %s\n", gpg_strerror (err)); + return err; + } + } + + if (output_fd != -1) + { + snprintf (line, sizeof line, "OUTPUT FD=%d", output_fd); + err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); + if (err) + { + assuan_release (ctx); + log_error ("error sending OUTPUT command: %s\n", gpg_strerror (err)); + return err; + } + } + + *r_ctx = ctx; + + if (DBG_ASSUAN) + log_debug ("connection to GPG established\n"); + return 0; +} + + +/* Release the assuan context created by start_gpg. */ +static void +release_gpg (assuan_context_t ctx) +{ + assuan_release (ctx); +} + + + +/* The data passed to the writer_thread. */ +struct writer_thread_parms +{ + int fd; + const void *data; + size_t datalen; + gpg_error_t *err_addr; +}; + + +/* The thread started by start_writer. */ +static void * +writer_thread (void *arg) +{ + struct writer_thread_parms *parm = arg; + const char *buffer = parm->data; + size_t length = parm->datalen; + + while (length) + { + ssize_t nwritten; + + nwritten = pth_write (parm->fd, buffer, length < 4096? length:4096); + if (nwritten < 0) + { + if (errno == EINTR) + continue; + *parm->err_addr = gpg_error_from_syserror (); + break; /* Write error. */ + } + length -= nwritten; + buffer += nwritten; + } + + if (close (parm->fd)) + log_error ("closing writer fd %d failed: %s\n", parm->fd, strerror (errno)); + xfree (parm); + return NULL; +} + + +/* Fire up a thread to send (DATA,DATALEN) to the file descriptor FD. + On success the thread receives the ownership over FD. The thread + ID is stored at R_TID. WRITER_ERR is the address of an gpg_error_t + variable to receive a possible write error after the thread has + finished. */ +static gpg_error_t +start_writer (int fd, const void *data, size_t datalen, + pth_t *r_tid, gpg_error_t *err_addr) +{ + gpg_error_t err; + struct writer_thread_parms *parm; + pth_attr_t tattr; + pth_t tid; + + *r_tid = NULL; + *err_addr = 0; + + parm = xtrymalloc (sizeof *parm); + if (!parm) + return gpg_error_from_syserror (); + parm->fd = fd; + parm->data = data; + parm->datalen = datalen; + parm->err_addr = err_addr; + + tattr = pth_attr_new (); + pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1); + pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024); + pth_attr_set (tattr, PTH_ATTR_NAME, "fd-writer"); + + tid = pth_spawn (tattr, writer_thread, parm); + if (!tid) + { + err = gpg_error_from_syserror (); + log_error ("error spawning writer thread: %s\n", gpg_strerror (err)); + } + else + { + err = 0; + *r_tid = tid; + } + pth_attr_destroy (tattr); + + return err; +} + + + +/* The data passed to the reader_thread. */ +struct reader_thread_parms +{ + int fd; + membuf_t *mb; + gpg_error_t *err_addr; +}; + + +/* The thread started by start_reader. */ +static void * +reader_thread (void *arg) +{ + struct reader_thread_parms *parm = arg; + char buffer[4096]; + int nread; + + while ( (nread = pth_read (parm->fd, buffer, sizeof buffer)) ) + { + if (nread < 0) + { + if (errno == EINTR) + continue; + *parm->err_addr = gpg_error_from_syserror (); + break; /* Read error. */ + } + + put_membuf (parm->mb, buffer, nread); + } + + if (close (parm->fd)) + log_error ("closing reader fd %d failed: %s\n", parm->fd, strerror (errno)); + xfree (parm); + return NULL; +} + + +/* Fire up a thread to receive data from the file descriptor FD. On + success the thread receives the ownership over FD. The thread ID + is stored at R_TID. After the thread has finished an error from + the thread will be stored at ERR_ADDR. */ +static gpg_error_t +start_reader (int fd, membuf_t *mb, pth_t *r_tid, gpg_error_t *err_addr) +{ + gpg_error_t err; + struct reader_thread_parms *parm; + pth_attr_t tattr; + pth_t tid; + + *r_tid = NULL; + *err_addr = 0; + + parm = xtrymalloc (sizeof *parm); + if (!parm) + return gpg_error_from_syserror (); + parm->fd = fd; + parm->mb = mb; + parm->err_addr = err_addr; + + tattr = pth_attr_new (); + pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1); + pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024); + pth_attr_set (tattr, PTH_ATTR_NAME, "fd-reader"); + + tid = pth_spawn (tattr, reader_thread, parm); + if (!tid) + { + err = gpg_error_from_syserror (); + log_error ("error spawning reader thread: %s\n", gpg_strerror (err)); + } + else + { + err = 0; + *r_tid = tid; + } + pth_attr_destroy (tattr); + + return err; +} + + + + +/* Call GPG to encrypt a block of data. + + + */ +gpg_error_t +gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen, + void **r_ciph, size_t *r_ciphlen) +{ + gpg_error_t err; + assuan_context_t ctx; + int outbound_fds[2] = { -1, -1 }; + int inbound_fds[2] = { -1, -1 }; + pth_t writer_tid = NULL; + pth_t reader_tid = NULL; + gpg_error_t writer_err, reader_err; + membuf_t reader_mb; + + *r_ciph = NULL; + *r_ciphlen = 0; + + /* Init the memory buffer to receive the encrypted stuff. */ + init_membuf (&reader_mb, 4096); + + /* Create two pipes. */ + err = gnupg_create_outbound_pipe (outbound_fds); + if (!err) + err = gnupg_create_inbound_pipe (inbound_fds); + if (err) + { + log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); + goto leave; + } + + /* Start GPG and send the INPUT and OUTPUT commands. */ + err = start_gpg (ctrl, outbound_fds[0], inbound_fds[1], &ctx); + if (err) + goto leave; + close (outbound_fds[0]); outbound_fds[0] = -1; + close (inbound_fds[1]); inbound_fds[1] = -1; + + /* Start a writer thread to feed the INPUT command of the server. */ + err = start_writer (outbound_fds[1], plain, plainlen, + &writer_tid, &writer_err); + if (err) + return err; + outbound_fds[1] = -1; /* The thread owns the FD now. */ + + /* Start a reader thread to eat from the OUTPUT command of the + server. */ + err = start_reader (inbound_fds[0], &reader_mb, + &reader_tid, &reader_err); + if (err) + return err; + outbound_fds[0] = -1; /* The thread owns the FD now. */ + + /* Run the encryption. */ + err = assuan_transact (ctx, "RECIPIENT alpha@example.net", + NULL, NULL, NULL, NULL, NULL, NULL); + if (err) + { + log_error ("the engine's RECIPIENT command failed: %s <%s>\n", + gpg_strerror (err), gpg_strsource (err)); + goto leave; + } + + err = assuan_transact (ctx, "ENCRYPT", NULL, NULL, NULL, NULL, NULL, NULL); + if (err) + { + log_error ("the engine's ENCRYPT command failed: %s <%s>\n", + gpg_strerror (err), gpg_strsource (err)); + goto leave; + } + + /* Wait for reader and return the data. */ + if (!pth_join (reader_tid, NULL)) + { + err = gpg_error_from_syserror (); + log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err)); + goto leave; + } + reader_tid = NULL; + if (reader_err) + { + err = reader_err; + log_error ("read error in reader thread: %s\n", gpg_strerror (err)); + goto leave; + } + + /* Wait for the writer to catch a writer error. */ + if (!pth_join (writer_tid, NULL)) + { + err = gpg_error_from_syserror (); + log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err)); + goto leave; + } + writer_tid = NULL; + if (writer_err) + { + err = writer_err; + log_error ("write error in writer thread: %s\n", gpg_strerror (err)); + goto leave; + } + + /* Return the data. */ + *r_ciph = get_membuf (&reader_mb, r_ciphlen); + if (!*r_ciph) + { + err = gpg_error_from_syserror (); + log_error ("error while storing the data in the reader thread: %s\n", + gpg_strerror (err)); + goto leave; + } + + leave: + if (reader_tid) + { + pth_cancel (reader_tid); + pth_join (reader_tid, NULL); + } + if (writer_tid) + { + pth_cancel (writer_tid); + pth_join (writer_tid, NULL); + } + if (outbound_fds[0] != -1) + close (outbound_fds[0]); + if (outbound_fds[1] != -1) + close (outbound_fds[1]); + if (inbound_fds[0] != -1) + close (inbound_fds[0]); + if (inbound_fds[1] != -1) + close (inbound_fds[1]); + release_gpg (ctx); + xfree (get_membuf (&reader_mb, NULL)); + return err; +} + + diff --git a/g13/call-gpg.h b/g13/call-gpg.h new file mode 100644 index 000000000..3e801be3b --- /dev/null +++ b/g13/call-gpg.h @@ -0,0 +1,29 @@ +/* call-gpg.h - Defs for the communication with GPG + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef G13_CALL_GPG_H +#define G13_CALL_GPG_H + +gpg_error_t gpg_encrypt_blob (ctrl_t ctrl, + const void *plain, size_t plainlen, + void **r_ciph, size_t *r_ciphlen); + + + +#endif /*G13_CALL_GPG_H*/ diff --git a/g13/create.c b/g13/create.c new file mode 100644 index 000000000..0c6735b80 --- /dev/null +++ b/g13/create.c @@ -0,0 +1,306 @@ +/* create.c - Create a new crypto container + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "g13.h" +#include "i18n.h" +#include "create.h" + +#include "keyblob.h" +#include "backend.h" +#include "utils.h" +#include "call-gpg.h" +#include "estream.h" + +/* Create a new blob with all the session keys and other meta + information which are to be stored encrypted in the crypto + container header. On success the malloced blob is stored at R_BLOB + and its length at R_BLOBLEN. On error en error ocde is returned + and (R_BLOB,R_BLOBLEN) are set to (NULL,0). + + The format of this blob is a sequence of tag-length-value tuples. + All tuples have this format: + + 2 byte TAG Big endian unsigned integer (0..65535) + described by the KEYBLOB_TAG_ constants. + 2 byte LENGTH Big endian unsigned integer (0..65535) + giving the length of the value. + length bytes VALUE The value described by the tag. + + The first tag in a keyblob must be a BLOBVERSION. The other tags + depend on the type of the container as described by the CONTTYPE + tag. See keyblob.h for details. */ +static gpg_error_t +create_new_keyblob (ctrl_t ctrl, int is_detached, + void **r_blob, size_t *r_bloblen) +{ + gpg_error_t err; + unsigned char twobyte[2]; + membuf_t mb; + + *r_blob = NULL; + *r_bloblen = 0; + + init_membuf_secure (&mb, 512); + + append_tuple (&mb, KEYBLOB_TAG_BLOBVERSION, "\x01", 1); + + twobyte[0] = (ctrl->conttype >> 8); + twobyte[1] = (ctrl->conttype); + append_tuple (&mb, KEYBLOB_TAG_CONTTYPE, twobyte, 2); + if (is_detached) + append_tuple (&mb, KEYBLOB_TAG_DETACHED, NULL, 0); + + err = be_create_new_keys (ctrl->conttype, &mb); + if (err) + goto leave; + + append_tuple (&mb, KEYBLOB_TAG_FILLER, "filler", 6); + + + *r_blob = get_membuf (&mb, r_bloblen); + if (!*r_blob) + { + err = gpg_error_from_syserror (); + *r_bloblen = 0; + } + else + log_debug ("used keyblob size is %zu\n", *r_bloblen); + + leave: + xfree (get_membuf (&mb, NULL)); + return err; +} + + + +/* Encrypt the keyblob (KEYBLOB,KEYBLOBLEN) and store the result at + (R_ENCBLOB, R_ENCBLOBLEN). Returns 0 on success or an error code. + On error R_EKYBLOB is set to NULL. Depending on the keys set in + CTRL the result is a single OpenPGP binary message, a single + special OpenPGP packet encapsulating a CMS message or a + concatenation of both with the CMS packet being the last. */ +static gpg_error_t +encrypt_keyblob (ctrl_t ctrl, void *keyblob, size_t keybloblen, + void **r_encblob, size_t *r_encbloblen) +{ + gpg_error_t err; + + /* FIXME: For now we only implement OpenPGP. */ + err = gpg_encrypt_blob (ctrl, keyblob, keybloblen, + r_encblob, r_encbloblen); + + return err; +} + + +/* Write a new file under the name FILENAME with the keyblob and an + appropriate header. This fucntion is called with a lock file in + place and after checking that the filename does not exists. */ +static gpg_error_t +write_keyblob (ctrl_t ctrl, const char *filename, + const void *keyblob, size_t keybloblen) +{ + gpg_error_t err; + estream_t fp; + unsigned char packet[32]; + size_t headerlen, paddinglen; + + fp = es_fopen (filename, "wbx"); + if (!fp) + { + err = gpg_error_from_syserror (); + log_error ("error creating new container `%s': %s\n", + filename, gpg_strerror (err)); + return err; + } + + /* Allow for an least 8 times larger keyblob to accommodate for + future key changes. Round it up to 4096 byte. */ + headerlen = ((32 + 8 * keybloblen + 16) + 4095) / 4096 * 4096; + paddinglen = headerlen - 32 - keybloblen; + assert (paddinglen >= 16); + + packet[0] = (0xc0|61); /* CTB for the private packet type 0x61. */ + packet[1] = 0xff; /* 5 byte length packet, value 20. */ + packet[2] = 0; + packet[3] = 0; + packet[4] = 0; + packet[5] = 26; + memcpy (packet+6, "GnuPG/G13", 10); /* Packet subtype. */ + packet[16] = 1; /* G13 packet format. */ + packet[17] = 0; /* Reserved. */ + packet[18] = 0; /* Reserved. */ + packet[19] = 0; /* OS Flag. */ + packet[20] = (headerlen >> 24); /* Total length of header. */ + packet[21] = (headerlen >> 16); + packet[22] = (headerlen >> 8); + packet[23] = (headerlen); + packet[24] = 1; /* Number of header copies. */ + packet[25] = 0; /* Number of header copies at the end. */ + packet[26] = 0; /* Reserved. */ + packet[27] = 0; /* Reserved. */ + packet[28] = 0; /* Reserved. */ + packet[29] = 0; /* Reserved. */ + packet[30] = 0; /* Reserved. */ + packet[31] = 0; /* Reserved. */ + + if (es_fwrite (packet, 32, 1, fp) != 1) + goto writeerr; + + if (es_fwrite (keyblob, keybloblen, 1, fp) != 1) + goto writeerr; + + /* Write the padding. */ + packet[0] = (0xc0|61); /* CTB for Private packet type 0x61. */ + packet[1] = 0xff; /* 5 byte length packet, value 20. */ + packet[2] = (paddinglen-6) >> 24; + packet[3] = (paddinglen-6) >> 16; + packet[4] = (paddinglen-6) >> 8; + packet[5] = (paddinglen-6); + memcpy (packet+6, "GnuPG/PAD", 10); /* Packet subtype. */ + if (es_fwrite (packet, 16, 1, fp) != 1) + goto writeerr; + memset (packet, 0, 32); + for (paddinglen-=16; paddinglen >= 32; paddinglen -= 32) + if (es_fwrite (packet, 32, 1, fp) != 1) + goto writeerr; + if (paddinglen) + if (es_fwrite (packet, paddinglen, 1, fp) != 1) + goto writeerr; + + if (es_fclose (fp)) + { + err = gpg_error_from_syserror (); + log_error ("error closing `%s': %s\n", + filename, gpg_strerror (err)); + remove (filename); + return err; + } + + return err; + + + writeerr: + err = gpg_error_from_syserror (); + log_error ("error writing header to `%s': %s\n", + filename, gpg_strerror (err)); + es_fclose (fp); + remove (filename); + return err; +} + + + +/* Create a new container under the name FILENAME and intialize it + using the current settings. If the file already exists an error is + returned. */ +gpg_error_t +create_new_container (ctrl_t ctrl, const char *filename) +{ + gpg_error_t err; + dotlock_t lock; + void *keyblob = NULL; + size_t keybloblen; + void *enckeyblob = NULL; + size_t enckeybloblen; + char *detachedname = NULL; + int detachedisdir; + + /* A quick check to see that no container with that name already + exists. */ + if (!access (filename, F_OK)) + return gpg_error (GPG_ERR_EEXIST); + + /* Take a lock and proceed with the creation. If there is a lock we + immediately return an error because for creation it does not make + sense to wait. */ + lock = create_dotlock (filename); + if (!lock) + return gpg_error_from_syserror (); + if (make_dotlock (lock, 0)) + { + err = gpg_error_from_syserror (); + goto leave; + } + else + err = 0; + + /* Check again that the file does not exist. */ + { + struct stat sb; + + if (!stat (filename, &sb)) + { + err = gpg_error (GPG_ERR_EEXIST); + goto leave; + } + } + /* And a possible detached file or directory may not exist either. */ + err = be_get_detached_name (ctrl->conttype, filename, + &detachedname, &detachedisdir); + if (err) + goto leave; + if (detachedname) + { + struct stat sb; + + if (!stat (detachedname, &sb)) + { + err = gpg_error (GPG_ERR_EEXIST); + goto leave; + } + } + + /* Create a new keyblob. */ + err = create_new_keyblob (ctrl, !!detachedname, &keyblob, &keybloblen); + if (err) + goto leave; + + /* Encrypt that keyblob. */ + err = encrypt_keyblob (ctrl, keyblob, keybloblen, + &enckeyblob, &enckeybloblen); + if (err) + goto leave; + + /* Write out the header, the encrypted keyblob and some padding. */ + err = write_keyblob (ctrl, filename, enckeyblob, enckeybloblen); + if (err) + goto leave; + + /* Create and append the container. */ + + + + leave: + xfree (detachedname); + xfree (enckeyblob); + xfree (keyblob); + destroy_dotlock (lock); + + return err; +} diff --git a/g13/g13.c b/g13/g13.c index 85805d3aa..d6a31673d 100644 --- a/g13/g13.c +++ b/g13/g13.c @@ -25,14 +25,18 @@ #include #include #include +#include #include "g13.h" #include +#include #include "i18n.h" #include "sysutils.h" #include "gc-opt-flags.h" +#include "create.h" +#include "keyblob.h" enum cmd_and_opt_values { @@ -60,6 +64,8 @@ enum cmd_and_opt_values { oOutput, oAgentProgram, + oGpgProgram, + oDisplay, oTTYname, oTTYtype, @@ -141,6 +147,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oNoOptions, "no-options", "@"), ARGPARSE_s_s (oHomedir, "homedir", "@"), ARGPARSE_s_s (oAgentProgram, "agent-program", "@"), + ARGPARSE_s_s (oGpgProgram, "gpg-program", "@"), ARGPARSE_s_s (oDisplay, "display", "@"), ARGPARSE_s_s (oTTYname, "ttyname", "@"), ARGPARSE_s_s (oTTYtype, "ttytype", "@"), @@ -172,6 +179,14 @@ static void set_cmd (enum cmd_and_opt_values *ret_cmd, static void emergency_cleanup (void); +/* Begin Pth wrapper functions. */ +GCRY_THREAD_OPTION_PTH_IMPL; +static int fixed_gcry_pth_init (void) +{ + return pth_self ()? 0 : (pth_init () == FALSE) ? errno : 0; +} +/* End Pth wrapper functions. */ + static const char * my_strusage( int level ) @@ -299,6 +314,7 @@ main ( int argc, char **argv) ARGPARSE_ARGS pargs; int orig_argc; char **orig_argv; + gpg_error_t err; const char *fname; int may_coredump; FILE *configfp = NULL; @@ -324,14 +340,23 @@ main ( int argc, char **argv) gnupg_reopen_std ("g13"); set_strusage (my_strusage); gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); - gcry_control (GCRYCTL_DISABLE_INTERNAL_LOCKING); log_set_prefix ("g13", 1); /* Make sure that our subsystems are ready. */ - i18n_init(); + i18n_init (); init_common_subsystems (); + /* Libgcrypt requires us to register the threading model first. + Note that this will also do the pth_init. */ + gcry_threads_pth.init = fixed_gcry_pth_init; + err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth); + if (err) + { + log_fatal ("can't register GNU Pth with Libgcrypt: %s\n", + gpg_strerror (err)); + } + /* Check that the Libgcrypt is suitable. */ if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) ) log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt", @@ -378,6 +403,20 @@ main ( int argc, char **argv) Now we are now working under our real uid */ + /* Setup malloc hooks. */ + { + struct assuan_malloc_hooks malloc_hooks; + + malloc_hooks.malloc = gcry_malloc; + malloc_hooks.realloc = gcry_realloc; + malloc_hooks.free = gcry_free; + assuan_set_malloc_hooks (&malloc_hooks); + } + + /* Prepare libassuan. */ + assuan_set_assuan_log_prefix (log_get_prefix (NULL)); + assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT); + /* Setup a default control structure for command line mode. */ memset (&ctrl, 0, sizeof ctrl); @@ -394,29 +433,31 @@ main ( int argc, char **argv) pargs.flags = 1; /* Do not remove the args. */ next_pass: - if (configname) { - configlineno = 0; - configfp = fopen (configname, "r"); - if (!configfp) - { - if (default_config) - { - if (parse_debug) - log_info (_("NOTE: no default option file `%s'\n"), configname); - } - else - { - log_error (_("option file `%s': %s\n"), configname, strerror(errno)); - g13_exit(2); - } - xfree (configname); - configname = NULL; - } - if (parse_debug && configname) - log_info (_("reading options from `%s'\n"), configname); - default_config = 0; - } - + if (configname) + { + configlineno = 0; + configfp = fopen (configname, "r"); + if (!configfp) + { + if (default_config) + { + if (parse_debug) + log_info (_("NOTE: no default option file `%s'\n"), configname); + } + else + { + log_error (_("option file `%s': %s\n"), + configname, strerror(errno)); + g13_exit(2); + } + xfree (configname); + configname = NULL; + } + if (parse_debug && configname) + log_info (_("reading options from `%s'\n"), configname); + default_config = 0; + } + while (!no_more_options && optfile_parse (configfp, configname, &configlineno, &pargs, opts)) { @@ -484,6 +525,7 @@ main ( int argc, char **argv) case oHomedir: opt.homedir = pargs.r.ret_str; break; case oAgentProgram: opt.agent_program = pargs.r.ret_str; break; + case oGpgProgram: opt.gpg_program = pargs.r.ret_str; break; case oDisplay: opt.display = xstrdup (pargs.r.ret_str); break; case oTTYname: opt.ttyname = xstrdup (pargs.r.ret_str); break; case oTTYtype: opt.ttytype = xstrdup (pargs.r.ret_str); break; @@ -635,7 +677,10 @@ main ( int argc, char **argv) { if (argc != 1) wrong_args ("--create filename"); - + err = create_new_container (&ctrl, argv[0]); + if (err) + log_error ("error creating a new container: %s <%s>\n", + gpg_strerror (err), gpg_strsource (err)); } break; @@ -647,8 +692,8 @@ main ( int argc, char **argv) /* Print the audit result if needed. */ if (auditlog && auditfp) { - audit_print_result (ctrl.audit, auditfp, 0); - audit_release (ctrl.audit); + /* audit_print_result (ctrl.audit, auditfp, 0); */ + /* audit_release (ctrl.audit); */ ctrl.audit = NULL; es_fclose (auditfp); } @@ -686,7 +731,7 @@ g13_exit (int rc) void g13_init_default_ctrl (struct server_control_s *ctrl) { - (void)ctrl; + ctrl->conttype = CONTTYPE_ENCFS; } diff --git a/g13/g13.h b/g13/g13.h index ec0689a9c..5740e5860 100644 --- a/g13/g13.h +++ b/g13/g13.h @@ -41,7 +41,16 @@ struct const char *homedir; /* Configuration directory name. */ const char *config_filename; /* Name of the used config file. */ + + /* Filename of the AGENT program. */ const char *agent_program; + + /* Filename of the GPG program. Unless set via an program option it + is initialzed at the first engine startup to the standard gpg + filename. */ + const char *gpg_program; + + /* Environment variables passed along to the engine. */ char *display; char *ttyname; char *ttytype; @@ -50,7 +59,9 @@ struct char *xauthority; char *pinentry_user_data; - char *outfile; /* Name of the output file. */ + /* Name of the output file - FIXME: what is this? */ + const char *outfile; + } opt; @@ -83,6 +94,10 @@ struct server_control_s accessed. */ int with_colons; /* Use column delimited output format */ + + /* Type of the current container. See the CONTTYPE_ constants. */ + int conttype; + }; diff --git a/g13/keyblob.h b/g13/keyblob.h new file mode 100644 index 000000000..b52919e0c --- /dev/null +++ b/g13/keyblob.h @@ -0,0 +1,126 @@ +/* keyblob.h - Defs to describe a keyblob + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef G13_KEYBLOB_H +#define G13_KEYBLOB_H + +/* The header block is the actual core of G13. Here is the format: + + u8 Packet type. Value is 61 (0x3d). + u8 Constant value 255 (0xff). + u32 Length of the following structure + b10 Value: "GnuPG/G13\x00". + u8 Version. Value is 1. + u8 reserved + u8 reserved + u8 OS Flag: reserved, should be 0. + u32 Length of the entire header. This includes all bytes + starting at the packet type and ending with the last + padding byte of the header. + u8 Number of copies of this header (1..255). + u8 Number of copies of this header at the end of the + container (usually 0). + b6 reserved + n bytes: OpenPGP encrypted and optionally signed message. + n bytes: CMS encrypted and optionally signed packet. Such a CMS + packet will be enclosed in a a private flagged OpenPGP + packet. Either the OpenPGP encrypted packet as described + above, the CMS encrypted or both packets must exist. The + encapsulation packet has this structure: + u8 Packet type. Value is 61 (0x3d). + u8 Constant value 255 (0xff). + u32 Length of the following structure + b10 Value: "GnuPG/CMS\x00". + b(n) Regular CMS structure. + n bytes: Padding. The structure resembles an OpenPGP packet. + u8 Packet type. Value is 61 (0x3d). + u8 Constant value 255 (0xff). + u32 Length of the following structure + b10 Value: "GnuPG/PAD\x00". + b(n) Padding stuff. + Given this structure the minimum padding is 16 bytes. + + n bytes: File system container. + (optionally followed by copies on the header). +*/ + + +#define KEYBLOB_TAG_BLOBVERSION 0 +/* This tag is used to describe the version of the keyblob. It must + be the first tag in a keyblob. Its value is a single byte giving + the blob version. The current version is 1. */ + +#define KEYBLOB_TAG_CONTTYPE 1 +/* This tag gives the type of the container. The value is a two byte + big endian integer giving the type of the container as described by + the CONTTYPE_ constants. */ + +#define KEYBLOB_TAG_DETACHED 2 +/* Indicates that the actual storage is not in the same file as the + keyblob. If a value is given it is expected to be the GUID of the + partition. */ + +#define KEYBLOB_TAG_KEYNO 16 +/* This tag indicates a new key. The value is a 4 byte big endian + integer giving the key number. If the container type does only + need one key this key number should be 0. */ + +#define KEYBLOB_TAG_ENCALGO 17 +/* Describes the algorithm of the key. It must follow a KEYNO tag. + The value is a 2 byte big endian algorithm number. The algorithm + numbers used are those from Libgcrypt (e.g. AES 128 is described by + the value 7). This tag is optional. */ + +#define KEYBLOB_TAG_ENCKEY 18 +/* This tag gives the actual encryption key. It must follow a KEYNO + tag. The value is the plain key. */ + +#define KEYBLOB_TAG_MACALGO 19 +/* Describes the MAC algorithm. It must follow a KEYNO tag. The + value is a 2 byte big endian algorithm number describing the MAC + algorithm with a value of 1 indicating HMAC. It is followed by + data specific to the MAC algorithm. In case of HMAC this data is a + 2 byte big endian integer with the Libgcrypt algorithm id of the + hash algorithm. */ + +#define KEYBLOB_TAG_MACKEY 20 +/* This tag gives the actual MACing key. It must follow a KEYNO tag. + The value is the key used for MACing. */ + + +#define KEYBLOB_TAG_FILLER 0xffff +/* This tag may be used for alignment and padding porposes. The value + has no meaning. */ + + + +#define CONTTYPE_ENCFS 1 +/* A EncFS based backend. This requires a whole directory which + includes the encrypted files. Metadata is not encrypted. */ + + +#define CONTTYPE_TRUECRYPT 21571 +/* A Truecrypt (www.truecrypt.org) based container. Due to the design + of truecrypt this requires a second datafile because it is not + possible to to prepend a truecrypt container with our keyblob. */ + + + + +#endif /*G13_KEYBLOB_H*/ diff --git a/g13/utils.c b/g13/utils.c new file mode 100644 index 000000000..15b4426ef --- /dev/null +++ b/g13/utils.c @@ -0,0 +1,51 @@ +/* utils.c - Utility functions + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "g13.h" +#include "utils.h" + + +/* Append the TAG and the VALUE to the MEMBUF. There is no error + checking here; this is instead done while getting the value back + from the membuf. */ +void +append_tuple (membuf_t *membuf, int tag, const void *value, size_t length) +{ + unsigned char buf[2]; + + assert (tag >= 0 && tag <= 0xffff); + assert (length <= 0xffff); + + buf[0] = tag >> 8; + buf[1] = tag; + put_membuf (membuf, buf, 2); + buf[0] = length >> 8; + buf[1] = length; + put_membuf (membuf, buf, 2); + if (length) + put_membuf (membuf, value, length); +} + diff --git a/g13/utils.h b/g13/utils.h new file mode 100644 index 000000000..c1104f759 --- /dev/null +++ b/g13/utils.h @@ -0,0 +1,32 @@ +/* utils.h - Defs for utility fucthe dispatcher to the various backends.ntions + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef G13_UTILS_H +#define G13_UTILS_H + +#include "../common/membuf.h" + + +void append_tuple (membuf_t *membuf, + int tag, const void *value, size_t length); + + + +#endif /*G13_UTILS_H*/ + diff --git a/sm/ChangeLog b/sm/ChangeLog index f26bcd01a..e68d5a749 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,7 @@ +2009-09-30 Werner Koch + + * gpgsm.c (main): Remove obsolete GCRYCTL_DISABLE_INTERNAL_LOCKING. + 2009-09-23 Marcus Brinkmann * gpgsm.c (main): Update to new assuan API. diff --git a/sm/gpgsm.c b/sm/gpgsm.c index d2f813574..17cc78b38 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -862,9 +862,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); /* Please note that we may running SUID(ROOT), so be very CAREFUL when adding any stuff between here and the call to secmem_init()