summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2009-09-30 17:28:38 +0200
committerWerner Koch <wk@gnupg.org>2009-09-30 17:28:38 +0200
commit27c1b4bef84dcb3a77147887817f228ced8c1b31 (patch)
tree27817fb6ac1ae22d6bba472de9f55e998534c3df
parentRename encode.c to encrypt.c. (diff)
downloadgnupg2-27c1b4bef84dcb3a77147887817f228ced8c1b31.tar.xz
gnupg2-27c1b4bef84dcb3a77147887817f228ced8c1b31.zip
Some changes to suport g13.
-rw-r--r--common/ChangeLog12
-rw-r--r--common/audit.h9
-rw-r--r--common/exechelp.c81
-rw-r--r--common/exechelp.h4
-rw-r--r--common/iobuf.c46
-rw-r--r--common/iobuf.h5
-rw-r--r--g10/ChangeLog28
-rw-r--r--g10/compress.c3
-rw-r--r--g10/dearmor.c4
-rw-r--r--g10/encrypt.c81
-rw-r--r--g10/export.c2
-rw-r--r--g10/gpg.c9
-rw-r--r--g10/keydb.h22
-rw-r--r--g10/main.h6
-rw-r--r--g10/openfile.c256
-rw-r--r--g10/parse-packet.c12
-rw-r--r--g10/pkclist.c211
-rw-r--r--g10/revoke.c4
-rw-r--r--g10/server.c167
-rw-r--r--g10/sign.c7
-rw-r--r--g13/Makefile.am19
-rw-r--r--g13/backend.c83
-rw-r--r--g13/backend.h32
-rw-r--r--g13/be-encfs.c58
-rw-r--r--g13/be-encfs.h31
-rw-r--r--g13/be-truecrypt.c39
-rw-r--r--g13/be-truecrypt.h29
-rw-r--r--g13/call-gpg.c466
-rw-r--r--g13/call-gpg.h29
-rw-r--r--g13/create.c306
-rw-r--r--g13/g13.c103
-rw-r--r--g13/g13.h17
-rw-r--r--g13/keyblob.h126
-rw-r--r--g13/utils.c51
-rw-r--r--g13/utils.h32
-rw-r--r--sm/ChangeLog4
-rw-r--r--sm/gpgsm.c3
37 files changed, 2071 insertions, 326 deletions
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 <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
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 <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)
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( access( fname, F_OK ) )
- return 1; /* does not exist */
-
-#ifndef HAVE_DOSISH_SYSTEM
- if ( !strcmp ( fname, "/dev/null" ) )
- return 1; /* does not do any harm */
-#endif
-#ifdef HAVE_W32_SYSTEM
- if ( !strcmp ( fname, "nul" ) )
- return 1;
-#endif
-
- /* fixme: add some backup stuff in case of overwrite */
- if( opt.answer_yes )
- return 1;
- if( opt.answer_no || opt.batch )
- return 0; /* do not overwrite */
-
- tty_printf(_("File `%s' exists. "), fname);
- if( cpr_enabled () )
- tty_printf ("\n");
- if( cpr_get_answer_is_yes("openfile.overwrite.okay",
- _("Overwrite? (y/N) ")) )
- return 1;
- return 0;
+ if ( iobuf_is_pipe_filename (fname) )
+ return 1; /* Writing to stdout is always okay. */
+
+ if ( access( fname, F_OK ) )
+ return 1; /* Does not exist. */
+
+ if ( !compare_filenames (fname, NAME_OF_DEV_NULL) )
+ return 1; /* Does not do any harm. */
+
+ if (opt.answer_yes)
+ return 1;
+ if (opt.answer_no || opt.batch)
+ return 0; /* Do not overwrite. */
+
+ tty_printf (_("File `%s' exists. "), fname);
+ if (cpr_enabled ())
+ tty_printf ("\n");
+ if (cpr_get_answer_is_yes ("openfile.overwrite.okay",
+ _("Overwrite? (y/N) ")) )
+ return 1;
+ return 0;
}
@@ -178,110 +178,134 @@ ask_outfile_name( const char *name, size_t namelen )
* Mode 0 = use ".gpg"
* 1 = use ".asc"
* 2 = use ".sig"
+
+ * If INP_FD is not GNUPG_INVALID_FD the function will simply create
+ * an IOBUF for that file descriptor and ignore a INAME and MODE.
+ * Note that INP_FD won't be closed if the returned IOBUF is closed.
*/
int
-open_outfile( const char *iname, int mode, IOBUF *a )
+open_outfile (gnupg_fd_t inp_fd, const char *iname, int mode, iobuf_t *a)
{
int rc = 0;
*a = NULL;
- if( iobuf_is_pipe_filename (iname) && !opt.outfile ) {
- *a = iobuf_create(NULL);
- if( !*a ) {
- rc = gpg_error_from_syserror ();
- log_error(_("can't open `%s': %s\n"), "[stdout]", strerror(errno) );
+ if (inp_fd != GNUPG_INVALID_FD)
+ {
+ char xname[64];
+ gnupg_fd_t fd2;
+
+ fd2 = INT2FD (dup (FD2INT (inp_fd)));
+ if (fd2 == GNUPG_INVALID_FD)
+ *a = NULL;
+ else
+ *a = iobuf_fdopen (fd2, "wb");
+ if (!*a)
+ {
+ rc = gpg_error_from_syserror ();
+ snprintf (xname, sizeof xname, "[fd %d]", inp_fd);
+ log_error (_("can't open `%s': %s\n"), xname, gpg_strerror (rc));
+ }
+ else if (opt.verbose)
+ {
+ snprintf (xname, sizeof xname, "[fd %d]", inp_fd);
+ log_info (_("writing to `%s'\n"), xname);
+ }
+ }
+ else if (iobuf_is_pipe_filename (iname) && !opt.outfile)
+ {
+ *a = iobuf_create(NULL);
+ if ( !*a )
+ {
+ rc = gpg_error_from_syserror ();
+ log_error (_("can't open `%s': %s\n"), "[stdout]", strerror(errno) );
+ }
+ else if ( opt.verbose )
+ log_info (_("writing to stdout\n"));
}
- else if( opt.verbose )
- log_info(_("writing to stdout\n"));
- }
- else {
- char *buf = NULL;
- const char *name;
+ else
+ {
+ char *buf = NULL;
+ const char *name;
- if ( opt.dry_run )
- {
-#ifdef HAVE_W32_SYSTEM
- name = "nul";
-#else
- name = "/dev/null";
-#endif
- }
- else if( opt.outfile )
- name = opt.outfile;
- else {
-#ifdef USE_ONLY_8DOT3
- if (opt.mangle_dos_filenames)
+ if (opt.dry_run)
+ name = NAME_OF_DEV_NULL;
+ else if (opt.outfile)
+ name = opt.outfile;
+ else
{
- /* It is quite common DOS system to have only one dot in a
- * a filename So if we have something like this, we simple
- * replace the suffix execpt in cases where the suffix is
- * larger than 3 characters and not the same as.
- * We should really map the filenames to 8.3 but this tends to
- * be more complicated and is probaly a duty of the filesystem
- */
- char *dot;
- const char *newsfx = mode==1 ? ".asc" :
- mode==2 ? ".sig" : ".gpg";
+#ifdef USE_ONLY_8DOT3
+ if (opt.mangle_dos_filenames)
+ {
+ /* It is quite common for DOS systems to have only one
+ dot in a filename. If we have something like this,
+ we simple replace the suffix except in cases where
+ the suffix is larger than 3 characters and not the
+ same as the new one. We don't map the filenames to
+ 8.3 because this is a duty of the file system. */
+ char *dot;
+ const char *newsfx;
+
+ newsfx = (mode==1 ? ".asc" :
+ mode==2 ? ".sig" : ".gpg");
- buf = xmalloc(strlen(iname)+4+1);
- strcpy(buf,iname);
- dot = strchr(buf, '.' );
- if ( dot && dot > buf && dot[1] && strlen(dot) <= 4
- && CMP_FILENAME(newsfx, dot) )
+ buf = xmalloc (strlen(iname)+4+1);
+ strcpy (buf, iname);
+ dot = strchr (buf, '.' );
+ if ( dot && dot > buf && dot[1] && strlen(dot) <= 4
+ && CMP_FILENAME (newsfx, dot) )
+ strcpy (dot, newsfx);
+ else if (dot && !dot[1]) /* Do not duplicate a dot. */
+ strcpy (dot, newsfx+1);
+ else
+ strcat (buf, newsfx);
+ }
+ if (!buf)
+#endif /* USE_ONLY_8DOT3 */
{
- strcpy(dot, newsfx );
+ buf = xstrconcat (iname,
+ (mode==1 ? EXTSEP_S "asc" :
+ mode==2 ? EXTSEP_S "sig" : EXTSEP_S "gpg"),
+ NULL);
}
- else if ( dot && !dot[1] ) /* don't duplicate a dot */
- strcpy( dot, newsfx+1 );
- else
- strcat ( buf, newsfx );
+ name = buf;
}
- if (!buf)
-#endif /* USE_ONLY_8DOT3 */
+
+ rc = 0;
+ while ( !overwrite_filep (name) )
{
- buf = xmalloc(strlen(iname)+4+1);
- strcpy(stpcpy(buf,iname), mode==1 ? EXTSEP_S "asc" :
- mode==2 ? EXTSEP_S "sig" : EXTSEP_S "gpg");
+ char *tmp = ask_outfile_name (NULL, 0);
+ if ( !tmp || !*tmp )
+ {
+ xfree (tmp);
+ rc = gpg_error (GPG_ERR_EEXIST);
+ break;
+ }
+ xfree (buf);
+ name = buf = tmp;
}
- name = buf;
- }
-
- rc = 0;
- while( !overwrite_filep (name) )
- {
- char *tmp = ask_outfile_name (NULL, 0);
- if ( !tmp || !*tmp )
- {
- xfree (tmp);
- rc = gpg_error (GPG_ERR_EEXIST);
- break;
- }
- xfree (buf);
- name = buf = tmp;
- }
- if( !rc )
- {
- if (is_secured_filename (name) )
- {
- *a = NULL;
- errno = EPERM;
- }
- else
- *a = iobuf_create( name );
- if( !*a )
- {
- rc = gpg_error_from_syserror ();
- log_error(_("can't create `%s': %s\n"), name, strerror(errno) );
- }
- else if( opt.verbose )
- log_info(_("writing to `%s'\n"), name );
- }
- xfree(buf);
- }
-
+ if ( !rc )
+ {
+ if (is_secured_filename (name) )
+ {
+ *a = NULL;
+ errno = EPERM;
+ }
+ else
+ *a = iobuf_create (name);
+ if (!*a)
+ {
+ rc = gpg_error_from_syserror ();
+ log_error(_("can't create `%s': %s\n"), name, strerror(errno) );
+ }
+ else if( opt.verbose )
+ log_info (_("writing to `%s'\n"), name );
+ }
+ xfree(buf);
+ }
+
if (*a)
- iobuf_ioctl (*a,3,1,NULL); /* disable fd caching */
+ iobuf_ioctl (*a, 3, 1, NULL); /* Disable fd caching. */
return rc;
}
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 16ca7514f..74f7ae840 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -682,7 +682,11 @@ skip_packet( IOBUF inp, int pkttype, unsigned long pktlen, int partial )
else
{
for( ; pktlen; pktlen-- )
- dump_hex_line(iobuf_get(inp), &i);
+ {
+ dump_hex_line( (c=iobuf_get(inp)), &i);
+ if (c == -1)
+ break;
+ }
}
putc ('\n', listfp);
return;
@@ -2529,7 +2533,11 @@ parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen,
}
else {
for( ; pktlen; pktlen-- )
- dump_hex_line(iobuf_get(inp), &i);
+ {
+ dump_hex_line ((c=iobuf_get (inp)), &i);
+ if (c == -1)
+ break;
+ }
}
putc ('\n', listfp);
}
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 3203a7ea6..16835926e 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -1,6 +1,6 @@
/* pkclist.c - create a list of public keys
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- * 2008 Free Software Foundation, Inc.
+ * 2008, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -40,6 +40,18 @@
#define CONTROL_D ('D' - 'A' + 1)
+static void
+send_status_inv_recp (int reason, const char *name)
+{
+ char buf[40];
+
+ snprintf (buf, sizeof buf, "%d ", reason);
+ write_status_text_and_buffer (STATUS_INV_RECP, buf,
+ name, strlen (name),
+ -1);
+}
+
+
/****************
* Show the revocation reason as it is stored with the given signature
*/
@@ -656,14 +668,15 @@ check_signatures_trust( PKT_signature *sig )
void
-release_pk_list( PK_LIST pk_list )
+release_pk_list (pk_list_t pk_list)
{
- PK_LIST pk_rover;
-
- for( ; pk_list; pk_list = pk_rover ) {
- pk_rover = pk_list->next;
- free_public_key( pk_list->pk );
- xfree( pk_list );
+ PK_LIST pk_rover;
+
+ for ( ; pk_list; pk_list = pk_rover)
+ {
+ pk_rover = pk_list->next;
+ free_public_key ( pk_list->pk );
+ xfree ( pk_list );
}
}
@@ -680,7 +693,7 @@ key_present_in_pk_list(PK_LIST pk_list, PKT_public_key *pk)
/****************
- * Return a malloced string with a default reciepient if there is any
+ * Return a malloced string with a default recipient if there is any
*/
static char *
default_recipient(void)
@@ -760,6 +773,96 @@ expand_group(strlist_t input)
}
+/* Helper for build_pk_list to find and check one key. This helper is
+ also used directly in server mode by the RECIPIENTS command. On
+ success the new key is added to PK_LIST_ADDR. NAME is the user id
+ of the key. USE the requested usage and a set MARK_HIDDEN will mark
+ the key in the updated list as a hidden recipient. */
+gpg_error_t
+find_and_check_key (const char *name, unsigned int use,
+ int mark_hidden, pk_list_t *pk_list_addr)
+{
+ int rc;
+ PKT_public_key *pk;
+ int trustlevel;
+
+ if (!name || !*name)
+ return gpg_error (GPG_ERR_INV_NAME);
+
+ pk = xtrycalloc (1, sizeof *pk);
+ if (!pk)
+ return gpg_error_from_syserror ();
+ pk->req_usage = use;
+
+ rc = get_pubkey_byname (NULL, pk, name, NULL, NULL, 0, 0);
+ if (rc)
+ {
+ /* Key not found or other error. */
+ log_error (_("%s: skipped: %s\n"), name, g10_errstr(rc) );
+ send_status_inv_recp (0, name);
+ free_public_key (pk);
+ return rc;
+ }
+
+ rc = openpgp_pk_test_algo2 (pk->pubkey_algo, use);
+ if (rc)
+ {
+ /* Key found but not usable for us (e.g. sign-only key). */
+ send_status_inv_recp (0, name);
+ log_error (_("%s: skipped: %s\n"), name, g10_errstr(rc) );
+ free_public_key (pk);
+ return rc;
+ }
+
+ /* Key found and usable. Check validity. */
+ trustlevel = get_validity (pk, pk->user_id);
+ if ( (trustlevel & TRUST_FLAG_DISABLED) )
+ {
+ /* Key has been disabled. */
+ send_status_inv_recp (0, name);
+ log_info (_("%s: skipped: public key is disabled\n"), name);
+ free_public_key (pk);
+ return G10ERR_UNU_PUBKEY;
+ }
+
+ if ( !do_we_trust_pre (pk, trustlevel) )
+ {
+ /* We don't trust this key. */
+ send_status_inv_recp (10, name);
+ free_public_key (pk);
+ return G10ERR_UNU_PUBKEY;
+ }
+ /* Note: do_we_trust may have changed the trustlevel. */
+
+ /* Skip the actual key if the key is already present in the
+ list. */
+ if (!key_present_in_pk_list (*pk_list_addr, pk))
+ {
+ log_info (_("%s: skipped: public key already present\n"), name);
+ free_public_key (pk);
+ }
+ else
+ {
+ pk_list_t r;
+
+ r = xtrymalloc (sizeof *r);
+ if (!r)
+ {
+ rc = gpg_error_from_syserror ();
+ free_public_key (pk);
+ return rc;
+ }
+ r->pk = pk;
+ r->next = *pk_list_addr;
+ r->flags = mark_hidden? 1:0;
+ *pk_list_addr = r;
+ }
+
+ return 0;
+}
+
+
+
/* This is the central function to collect the keys for recipients.
It is thus used to prepare a public key encryption. encrypt-to
keys, default keys and the keys for the actual recipients are all
@@ -831,8 +934,7 @@ build_pk_list( strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use )
{
free_public_key ( pk ); pk = NULL;
log_error (_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
- write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
- rov->d, strlen (rov->d), -1);
+ send_status_inv_recp (0, rov->d);
goto fail;
}
else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo, use)) )
@@ -873,8 +975,7 @@ build_pk_list( strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use )
available. */
free_public_key( pk ); pk = NULL;
log_error(_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
- write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
- rov->d, strlen (rov->d), -1);
+ send_status_inv_recp (0, rov->d);
goto fail;
}
}
@@ -1078,85 +1179,11 @@ build_pk_list( strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use )
if ( (remusr->flags & 1) )
continue; /* encrypt-to keys are already handled. */
- pk = xmalloc_clear( sizeof *pk );
- pk->req_usage = use;
- if ((rc = get_pubkey_byname (NULL, pk, remusr->d, NULL, NULL, 0, 0)))
- {
- /* Key not found or other error. */
- free_public_key( pk ); pk = NULL;
- log_error(_("%s: skipped: %s\n"), remusr->d, g10_errstr(rc) );
- write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
- remusr->d, strlen (remusr->d),
- -1);
- goto fail;
- }
- else if ( !(rc=openpgp_pk_test_algo2(pk->pubkey_algo, use )) )
- {
- /* Key found and usable. Check validity. */
- int trustlevel;
-
- trustlevel = get_validity (pk, pk->user_id);
- if ( (trustlevel & TRUST_FLAG_DISABLED) )
- {
- /*Key has been disabled. */
- free_public_key(pk); pk = NULL;
- log_info(_("%s: skipped: public key is disabled\n"),
- remusr->d);
- write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
- remusr->d,
- strlen (remusr->d),
- -1);
- rc=G10ERR_UNU_PUBKEY;
- goto fail;
- }
- else if ( do_we_trust_pre( pk, trustlevel ) )
- {
- /* Note: do_we_trust may have changed the trustlevel */
-
- /* We have at least one valid recipient. It doesn't
- * matters if this recipient is already present. */
- any_recipients = 1;
-
- /* Skip the actual key if the key is already present
- * in the list */
- if (!key_present_in_pk_list(pk_list, pk))
- {
- free_public_key(pk); pk = NULL;
- log_info(_("%s: skipped: public key already present\n"),
- remusr->d);
- }
- else
- {
- PK_LIST r;
- r = xmalloc( sizeof *r );
- r->pk = pk; pk = NULL;
- r->next = pk_list;
- r->flags = (remusr->flags&2)?1:0;
- pk_list = r;
- }
- }
- else
- { /* We don't trust this key. */
- free_public_key( pk ); pk = NULL;
- write_status_text_and_buffer (STATUS_INV_RECP, "10 ",
- remusr->d,
- strlen (remusr->d),
- -1);
- rc=G10ERR_UNU_PUBKEY;
- goto fail;
- }
- }
- else
- {
- /* Key found but not usable for us (e.g. sign-only key). */
- free_public_key( pk ); pk = NULL;
- write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
- remusr->d,
- strlen (remusr->d),
- -1);
- log_error(_("%s: skipped: %s\n"), remusr->d, g10_errstr(rc) );
- goto fail;
- }
+ rc = find_and_check_key (remusr->d, use, !!(remusr->flags&2),
+ &pk_list);
+ if (rc)
+ goto fail;
+ any_recipients = 1;
}
}
diff --git a/g10/revoke.c b/g10/revoke.c
index cce6d69f6..b34684ecd 100644
--- a/g10/revoke.c
+++ b/g10/revoke.c
@@ -326,7 +326,7 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
if( !opt.armor )
tty_printf(_("ASCII armored output forced.\n"));
- if( (rc = open_outfile( NULL, 0, &out )) )
+ if( (rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out )) )
goto leave;
afx->what = 1;
@@ -550,7 +550,7 @@ gen_revoke( const char *uname )
if( !opt.armor )
tty_printf(_("ASCII armored output forced.\n"));
- if( (rc = open_outfile( NULL, 0, &out )) )
+ if( (rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out )) )
goto leave;
afx->what = 1;
diff --git a/g10/server.c b/g10/server.c
index b2285955e..87a52d21f 100644
--- a/g10/server.c
+++ b/g10/server.c
@@ -33,6 +33,7 @@
#include "i18n.h"
#include "options.h"
#include "../common/sysutils.h"
+#include "status.h"
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
@@ -45,6 +46,10 @@ struct server_local_s
assuan_context_t assuan_ctx;
/* File descriptor as set by the MESSAGE command. */
gnupg_fd_t message_fd;
+
+ /* List of prepared recipients. */
+ pk_list_t recplist;
+
};
@@ -61,6 +66,39 @@ close_message_fd (ctrl_t ctrl)
}
+/* Skip over options. Blanks after the options are also removed. */
+static char *
+skip_options (const char *line)
+{
+ while (spacep (line))
+ line++;
+ while ( *line == '-' && line[1] == '-' )
+ {
+ while (*line && !spacep (line))
+ line++;
+ while (spacep (line))
+ line++;
+ }
+ return (char*)line;
+}
+
+
+/* Check whether the option NAME appears in LINE. */
+static int
+has_option (const char *line, const char *name)
+{
+ const char *s;
+ int n = strlen (name);
+
+ s = strstr (line, name);
+ if (s && s >= skip_options (line))
+ return 0;
+ return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
+}
+
+
+
+
/* Called by libassuan for Assuan options. See the Assuan manual for
details. */
@@ -111,6 +149,9 @@ reset_notify (assuan_context_t ctx)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
+ release_pk_list (ctrl->server_local->recplist);
+ ctrl->server_local->recplist = NULL;
+
close_message_fd (ctrl);
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
@@ -157,7 +198,7 @@ output_notify (assuan_context_t ctx, const char *line)
-/* RECIPIENT <userID>
+/* RECIPIENT [--hidden] <userID>
Set the recipient for the encryption. <userID> should be the
internal representation of the key; the server may accept any other
@@ -171,9 +212,26 @@ output_notify (assuan_context_t ctx, const char *line)
static gpg_error_t
cmd_recipient (assuan_context_t ctx, char *line)
{
- (void)ctx;
- (void)line;
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err;
+ int hidden;
+
+ hidden = has_option (line,"--hidden");
+ line = skip_options (line);
+
+ /* FIXME: Expand groups
+ if (opt.grouplist)
+ remusr = expand_group (rcpts);
+ else
+ remusr = rcpts;
+ */
+
+ err = find_and_check_key (line, PUBKEY_USAGE_ENC, hidden,
+ &ctrl->server_local->recplist);
+
+ if (err)
+ log_error ("command '%s' failed: %s\n", "RECIPIENT", gpg_strerror (err));
+ return err;
}
@@ -206,22 +264,81 @@ cmd_signer (assuan_context_t ctx, char *line)
/* ENCRYPT
Do the actual encryption process. Takes the plaintext from the
- INPUT command, writes to the ciphertext to the file descriptor set
- with the OUTPUT command, take the recipients form all the
- recipients set so far. If this command fails the clients should
- try to delete all output currently done or otherwise mark it as
- invalid. GPG does ensure that there won't be any security problem
- with leftover data on the output in this case.
-
- This command should in general not fail, as all necessary checks
- have been done while setting the recipients. The input and output
- pipes are closed. */
+ INPUT command, writes the ciphertext to the file descriptor set
+ with the OUTPUT command, take the recipients from all the
+ recipients set so far with RECIPIENTS.
+
+ If this command fails the clients should try to delete all output
+ currently done or otherwise mark it as invalid. GPG does ensure
+ that there won't be any security problem with leftover data on the
+ output in this case.
+
+ In most cases this command won't fail because most necessary checks
+ have been done while setting the recipients. However some checks
+ can only be done right here and thus error may occur anyway (for
+ example, no recipients at all).
+
+ The input, output and message pipes are closed after this
+ command. */
static gpg_error_t
cmd_encrypt (assuan_context_t ctx, char *line)
{
- (void)ctx;
- (void)line;
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err;
+ int inp_fd, out_fd;
+
+ (void)line; /* LINE is not used. */
+
+ if ( !ctrl->server_local->recplist )
+ {
+ write_status_text (STATUS_NO_RECP, "0");
+ err = gpg_error (GPG_ERR_NO_USER_ID);
+ goto leave;
+ }
+
+ inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
+ if (inp_fd == -1)
+ {
+ err = set_error (GPG_ERR_ASS_NO_INPUT, NULL);
+ goto leave;
+ }
+ out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
+ if (out_fd == -1)
+ {
+ err = set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
+ goto leave;
+ }
+
+ /* Fixme: Check that we are using real files and not pipes if in
+ PGP-2 mode. Do all the other checks we do in gpg.c for aEncr.
+ Maybe we should drop the PGP2 compatibility. */
+
+
+ /* FIXME: GPGSM does this here: Add all encrypt-to marked recipients
+ from the default list. */
+
+ /* fixme: err = ctrl->audit? 0 : start_audit_session (ctrl);*/
+
+ err = encrypt_crypt (inp_fd, NULL, NULL, 0,
+ ctrl->server_local->recplist,
+ out_fd);
+
+ leave:
+ /* Release the recipient list on success. */
+ if (!err)
+ {
+ release_pk_list (ctrl->server_local->recplist);
+ ctrl->server_local->recplist = NULL;
+ }
+
+ /* Close and reset the fds. */
+ close_message_fd (ctrl);
+ assuan_close_input_fd (ctx);
+ assuan_close_output_fd (ctx);
+
+ if (err)
+ log_error ("command '%s' failed: %s\n", "ENCRYPT", gpg_strerror (err));
+ return err;
}
@@ -258,6 +375,9 @@ cmd_verify (assuan_context_t ctx, char *line)
gnupg_fd_t out_fd = assuan_get_output_fd (ctx);
FILE *out_fp = NULL;
+ /* FIXME: Revamp this code it is nearly to 3 years old and was only
+ intended as a quick test. */
+
(void)line;
if (fd == GNUPG_INVALID_FD)
@@ -270,8 +390,8 @@ cmd_verify (assuan_context_t ctx, char *line)
return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
}
- log_debug ("WARNING: The server mode work "
- "in progress and not ready for use\n");
+ log_debug ("WARNING: The server mode is WORK "
+ "iN PROGRESS and not ready for use\n");
/* Need to dup it because it might get closed and libassuan won't
know about it then. */
@@ -596,8 +716,13 @@ gpg_server (ctrl_t ctrl)
}
leave:
- xfree (ctrl->server_local);
- ctrl->server_local = NULL;
+ if (ctrl->server_local)
+ {
+ release_pk_list (ctrl->server_local->recplist);
+
+ xfree (ctrl->server_local);
+ ctrl->server_local = NULL;
+ }
assuan_release (ctx);
return rc;
}
diff --git a/g10/sign.c b/g10/sign.c
index 0528427db..92617a981 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -801,7 +801,8 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr,
else if( opt.verbose )
log_info(_("writing to `%s'\n"), outfile );
}
- else if( (rc = open_outfile( fname, opt.armor? 1: detached? 2:0, &out )))
+ else if( (rc = open_outfile (GNUPG_INVALID_FD, fname,
+ opt.armor? 1: detached? 2:0, &out )))
goto leave;
/* prepare to calculate the MD over the input */
@@ -1110,7 +1111,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
else if( opt.verbose )
log_info(_("writing to `%s'\n"), outfile );
}
- else if( (rc = open_outfile( fname, 1, &out )) )
+ else if( (rc = open_outfile (GNUPG_INVALID_FD, fname, 1, &out )) )
goto leave;
iobuf_writestr(out, "-----BEGIN PGP SIGNED MESSAGE-----" LF );
@@ -1275,7 +1276,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
cfx.dek->use_mdc=1;
/* now create the outfile */
- rc = open_outfile (fname, opt.armor? 1:0, &out);
+ rc = open_outfile (GNUPG_INVALID_FD, fname, opt.armor? 1:0, &out);
if (rc)
goto leave;
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_LDADD = $(libcommon) ../jnlib/libjnlib.a ../gl/libgnu.a \
- $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
- $(LIBINTL)
+ 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 = $(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 <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);
+ }
+}
+
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 <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*/
+
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 <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;
+}
+
+
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 <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*/
+
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 <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);
+}
+
+
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 <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*/
+
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 <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;
+}
+
+
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 <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*/
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 <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;
+}
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 <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;
}
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 <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*/
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 <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);
+}
+
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 <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*/
+
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 <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.
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()