Some changes to suport g13.

This commit is contained in:
Werner Koch 2009-09-30 15:28:38 +00:00
parent c11c23b6ac
commit 27c1b4bef8
37 changed files with 2069 additions and 324 deletions

View File

@ -1,3 +1,15 @@
2009-09-29 Werner Koch <wk@g10code.com>
* 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 <marcus@g10code.de>
* asshelp.c (start_new_gpg_agent): Allocate assuan context before

View File

@ -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. */

View File

@ -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));

View File

@ -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

View File

@ -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.

View File

@ -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);

View File

@ -1,5 +1,33 @@
2009-09-30 Werner Koch <wk@g10code.com>
* 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 <wk@g10code.com>
* 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 <wk@g10code.com>
* 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)

View File

@ -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;

View File

@ -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;

View File

@ -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 );

View File

@ -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;

View File

@ -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) );
}

View File

@ -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,

View File

@ -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 );

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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.
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;
}

View File

@ -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;

View File

@ -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)

83
g13/backend.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#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);
}
}

32
g13/backend.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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*/

58
g13/be-encfs.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#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;
}

31
g13/be-encfs.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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*/

39
g13/be-truecrypt.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#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);
}

29
g13/be-truecrypt.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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*/

466
g13/call-gpg.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <assert.h>
#include <pth.h>
#include "g13.h"
#include <assuan.h>
#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;
}

29
g13/call-gpg.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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*/

306
g13/create.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <assert.h>
#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;
}

103
g13/g13.c
View File

@ -25,14 +25,18 @@
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <pth.h>
#include "g13.h"
#include <gcrypt.h>
#include <assuan.h>
#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;
}

View File

@ -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;
};

126
g13/keyblob.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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*/

51
g13/utils.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#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);
}

32
g13/utils.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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*/

View File

@ -1,3 +1,7 @@
2009-09-30 Werner Koch <wk@g10code.com>
* gpgsm.c (main): Remove obsolete GCRYCTL_DISABLE_INTERNAL_LOCKING.
2009-09-23 Marcus Brinkmann <marcus@g10code.de>
* gpgsm.c (main): Update to new assuan API.

View File

@ -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()