Some changes to suport g13.
authorWerner Koch <wk@gnupg.org>
Wed, 30 Sep 2009 15:28:38 +0000 (15:28 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 30 Sep 2009 15:28:38 +0000 (15:28 +0000)
37 files changed:
common/ChangeLog
common/audit.h
common/exechelp.c
common/exechelp.h
common/iobuf.c
common/iobuf.h
g10/ChangeLog
g10/compress.c
g10/dearmor.c
g10/encrypt.c
g10/export.c
g10/gpg.c
g10/keydb.h
g10/main.h
g10/openfile.c
g10/parse-packet.c
g10/pkclist.c
g10/revoke.c
g10/server.c
g10/sign.c
g13/Makefile.am
g13/backend.c [new file with mode: 0644]
g13/backend.h [new file with mode: 0644]
g13/be-encfs.c [new file with mode: 0644]
g13/be-encfs.h [new file with mode: 0644]
g13/be-truecrypt.c [new file with mode: 0644]
g13/be-truecrypt.h [new file with mode: 0644]
g13/call-gpg.c [new file with mode: 0644]
g13/call-gpg.h [new file with mode: 0644]
g13/create.c [new file with mode: 0644]
g13/g13.c
g13/g13.h
g13/keyblob.h [new file with mode: 0644]
g13/utils.c [new file with mode: 0644]
g13/utils.h [new file with mode: 0644]
sm/ChangeLog
sm/gpgsm.c

index 34894ef..575c9ed 100644 (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
index 4917107..5f5aff4 100644 (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.  */
 
index a5e25fd..8960490 100644 (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));
index 0efee29..3d70e10 100644 (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
index 4ec151f..e3ea0b4 100644 (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.
index 8a3671e..936481f 100644 (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);
 
index a44dac6..043da49 100644 (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)
index a91dd23..6a29c0a 100644 (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;
index da888ad..00bdf7b 100644 (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;
index 90a2065..bb3f243 100644 (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 );
index 09faa03..9b87e59 100644 (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;
 
index 6771986..55ba2cd 100644 (file)
--- 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) );
          }
index ca3ca77..c58a101 100644 (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,
index 4ed878d..4971154 100644 (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 );
 
index 55dd42c..5908b2e 100644 (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.
  *
 #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
 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;
 }
index 16ca751..74f7ae8 100644 (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);
     }
index 3203a7e..1683592 100644 (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.
  *
 
 #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;
         }
     }
   
index cce6d69..b34684e 100644 (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;
index b228595..87a52d2 100644 (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)));
+}
+
+
+
+
 \f
 /* 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)
 
 
 \f
-/*  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;
 }
index 0528427..92617a9 100644 (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;
 
index dce2f0b..44f546e 100644 (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_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 (file)
index 0000000..a6f3871
--- /dev/null
@@ -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 (file)
index 0000000..ffd03d3
--- /dev/null
@@ -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 (file)
index 0000000..18030b8
--- /dev/null
@@ -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 (file)
index 0000000..0613853
--- /dev/null
@@ -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 (file)
index 0000000..6f51321
--- /dev/null
@@ -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 (file)
index 0000000..ef2c567
--- /dev/null
@@ -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 (file)
index 0000000..2399058
--- /dev/null
@@ -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"
+
+
+\f
+/* 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);
+}
+
+
+\f
+/* 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;
+}
+
+
+\f
+/* 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;
+}
+
+
+
+\f
+/* 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 (file)
index 0000000..3e801be
--- /dev/null
@@ -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 (file)
index 0000000..0c6735b
--- /dev/null
@@ -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;
+}
index 85805d3..d6a3167 100644 (file)
--- a/g13/g13.c
+++ b/g13/g13.c
 #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;
 }
 
 
index ec0689a..5740e58 100644 (file)
--- 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 (file)
index 0000000..b52919e
--- /dev/null
@@ -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).
+*/
+
+\f
+#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.  */
+
+
+\f
+#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 (file)
index 0000000..15b4426
--- /dev/null
@@ -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 (file)
index 0000000..c1104f7
--- /dev/null
@@ -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*/
+
index f26bcd0..e68d5a7 100644 (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.
index d2f8135..17cc78b 100644 (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()