Changes to make use of code taken from libassuan. This replaces the
authorWerner Koch <wk@gnupg.org>
Tue, 5 Apr 2005 17:09:13 +0000 (17:09 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 5 Apr 2005 17:09:13 +0000 (17:09 +0000)
old ad-hoc connection code to gpg-agent.  We do need this for the
forthcoming diversion of card code to an already running gpg-agent
with card-support.

23 files changed:
ChangeLog
README
THANKS
configure.ac
g10/ChangeLog
g10/g10.c
g10/passphrase.c
include/ChangeLog
include/assuan.h [new file with mode: 0644]
include/memory.h
util/ChangeLog
util/Makefile.am
util/assuan-buffer.c [new file with mode: 0644]
util/assuan-client.c [new file with mode: 0644]
util/assuan-connect.c [new file with mode: 0644]
util/assuan-defs.h [new file with mode: 0644]
util/assuan-errors.c [new file with mode: 0644]
util/assuan-logging.c [new file with mode: 0644]
util/assuan-socket-connect.c [new file with mode: 0644]
util/assuan-socket.c [new file with mode: 0644]
util/assuan-util.c [new file with mode: 0644]
util/isascii.c [new file with mode: 0644]
util/memory.c

index cba2695..0f3a0d5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2005-03-31  Werner Koch  <wk@g10code.com>
+
+       * configure.ac: New option --disable-agent-support. Define
+       ENABLE_AGENT_SUPPORT as AC_DEFINE and AM_CONDITIONAL.
+       Disable support for card and agent with --enable-minimal.
+       (AC_REPLACE_FUNCS): Add isascii.
+       (g10defs.h): Define PATHSEP_C and PATHSEP_S.
+
+       * README: Changed the instruction on how to verify a signature to
+       show a .sig extension and not the .asc we used to use ages ago.
+
 2005-03-16  David Shaw  <dshaw@jabberwocky.com>
 
        * configure.ac: Move the LDAP detecting code to m4/ldap.m4.
diff --git a/README b/README
index ff482c7..9d9c8a3 100644 (file)
--- a/README
+++ b/README
     a) If you already have a trusted Version of GnuPG installed, you
        can simply check the supplied signature:
 
-       $ gpg --verify gnupg-x.y.z.tar.gz.asc
+       $ gpg --verify gnupg-x.y.z.tar.gz.sig
 
-       This checks that the detached signature gnupg-x.y.z.tar.gz.asc
-       is indeed a signature of gnupg-x.y.z.tar.gz.  The key used to
+       This checks that the detached signature gnupg-x.y.z.tar.gz.sig
+       is indeed a signature of gnupg-x.y.z.tar.gz.  The key used to
        create this signature is:
 
        "pub  1024D/57548DCD 1998-07-07 Werner Koch (gnupg sig) <dd9jn@gnu.org>"
                    --disable-cast5, --disable-blowfish,
                    --disable-aes, --disable-twofish,
                    --disable-sha256, --disable-sha512,
-                   --without-bzip2, and --disable-exec.  Configure
-                   command lines are read from left to right, so if
-                   you want to have an "almost minimal"
+                   --without-bzip2, --disable-exec, 
+                    --disable-card-support and
+                   --disable-agent-support.
+                    Configure command lines are read from left to
+                   right, so if you want to have an "almost minimal"
                    configuration, you can do (for example)
                    "--enable-minimal --enable-rsa" to have RSA added
                    to the minimal build.
                     to include support if all required libraries are
                     available.
 
+     --disable-agent-support
+                    Do not include support for the gpg-agent.  The
+                    default is to include support.
+
      --enable-selinux-support
                     This prevents access to certain files and won't
                     allow import or export of secret keys. 
diff --git a/THANKS b/THANKS
index ca62224..6958e5e 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -181,6 +181,7 @@ Russell Coker              russell@coker.com.au
 Ryan Malayter              rmalayter@bai.org
 Sam Roberts               sam@cogent.ca
 Sami Tolvanen              sami@tolvanen.com
+Sascha Kiefer              sk@intertivity.com
 Sean MacLennan            seanm@netwinder.org
 Sebastian Klemke           packet@convergence.de
 Serge Munhoven            munhoven@mema.ucl.ac.be
index 7c91ddc..fd2d271 100644 (file)
@@ -122,13 +122,6 @@ AC_ARG_ENABLE(selinux-support,
 AC_MSG_RESULT($selinux_support)
 
 
-AC_MSG_CHECKING([whether OpenPGP card support is requested])
-AC_ARG_ENABLE(card-support,
-              AC_HELP_STRING([--disable-card-support],
-                             [disable OpenPGP card support]),
-              card_support=$enableval, card_support=yes)
-AC_MSG_RESULT($card_support)
-
 AC_MSG_CHECKING([whether the new iconv based code is requested])
 AC_ARG_ENABLE(gnupg-iconv,
               AC_HELP_STRING([--disable-gnupg-iconv],
@@ -158,6 +151,8 @@ use_sha256=yes
 use_sha512=yes
 use_bzip2=yes
 use_exec=yes
+card_support=yes
+agent_support=yes
 
 AC_ARG_ENABLE(minimal,
    AC_HELP_STRING([--enable-minimal],[build the smallest gpg binary possible]),
@@ -170,7 +165,27 @@ AC_ARG_ENABLE(minimal,
    use_sha256=no
    use_sha512=no
    use_bzip2=no
-   use_exec=no)
+   use_exec=no
+   card_support=no
+   agent_support=no)
+
+
+AC_MSG_CHECKING([whether OpenPGP card support is requested])
+AC_ARG_ENABLE(card-support,
+              AC_HELP_STRING([--disable-card-support],
+                             [disable OpenPGP card support]),
+              card_support=$enableval)
+AC_MSG_RESULT($card_support)
+
+
+# Note that we may later disable the agent support based on the platform.
+AC_MSG_CHECKING([whether gpg-agent support is requested])
+AC_ARG_ENABLE(agent-support,
+              AC_HELP_STRING([--disable-agent-support],
+                             [disable gpg-agent support]),
+              agent_support=$enableval)
+AC_MSG_RESULT($agent_support)
+
 
 AC_MSG_CHECKING([whether to enable the RSA public key algorithm])
 AC_ARG_ENABLE(rsa,
@@ -471,6 +486,7 @@ case "${host}" in
         have_dosish_system=yes
         need_dlopen=no
         try_gettext="no"
+        agent_support=no
         ;;
     i?86-emx-os2 | i?86-*-os2*emx )
         # OS/2 with the EMX environment
@@ -478,6 +494,7 @@ case "${host}" in
         AC_DEFINE(HAVE_DRIVE_LETTERS)
         have_dosish_system=yes
         try_gettext="no"
+        agent_support=no
         ;;
 
     i?86-*-msdosdjgpp*)
@@ -486,6 +503,7 @@ case "${host}" in
         AC_DEFINE(HAVE_DRIVE_LETTERS)
         have_dosish_system=yes
         try_gettext="no"
+        agent_support=no
         ;;
 
     *-*-freebsd*)
@@ -754,6 +772,10 @@ if test "$card_support" = yes ; then
   AC_DEFINE(ENABLE_CARD_SUPPORT,1,[Define to include OpenPGP card support])
 fi
 
+if test "$agent_support" = yes ; then
+  AC_DEFINE(ENABLE_AGENT_SUPPORT,1,[Define to include gpg-agent support])
+fi
+
 if test "$try_extensions" = yes ; then
   AC_DEFINE(USE_DYNAMIC_LINKING,1,[Define to enable the use of extensions])
 fi
@@ -771,6 +793,7 @@ if test "$do_backsigs" = yes ; then
 fi
 
 AM_CONDITIONAL(ENABLE_CARD_SUPPORT, test "$card_support" = yes)
+AM_CONDITIONAL(ENABLE_AGENT_SUPPORT, test "$agent_support" = yes)
 
 dnl Checks for header files.
 AC_HEADER_STDC
@@ -841,6 +864,7 @@ AC_CHECK_FUNCS(memmove gettimeofday getrusage setrlimit clock_gettime)
 AC_CHECK_FUNCS(atexit raise getpagesize strftime nl_langinfo setlocale)
 AC_CHECK_FUNCS(waitpid wait4 sigaction sigprocmask rand pipe stat getaddrinfo)
 AC_REPLACE_FUNCS(mkdtemp timegm)
+AC_REPLACE_FUNCS(isascii)
 
 AC_CHECK_TYPES([struct sigaction, sigset_t],,,[#include <signal.h>])
 
@@ -1260,11 +1284,15 @@ cat >g10defs.tmp <<G10EOF
 #define EXTSEP_C '.'
 #define DIRSEP_S "\\\\"
 #define EXTSEP_S "."
+#define PATHSEP_C ';'
+#define PATHSEP_S ";"
 #else
 #define DIRSEP_C '/'
 #define EXTSEP_C '.'
 #define DIRSEP_S "/"
 #define EXTSEP_S "."
+#define PATHSEP_C ':'
+#define PATHSEP_S ":"
 #endif
 /* This is the same as VERSION, but should be overridden if the
    platform cannot handle things like dots'.' in filenames.  Set
index f5a6a43..0501c69 100644 (file)
@@ -1,3 +1,8 @@
+2005-04-01  Werner Koch  <wk@g10code.com>
+
+       * keygen.c (keygen_set_std_prefs): Explain the chosen order of
+       AES key sizes. 
+
 2005-04-01  David Shaw  <dshaw@jabberwocky.com>
 
        * mainproc.c (proc_plaintext): Properly handle SIG+LITERAL
 
 2005-03-31  Werner Koch  <wk@g10code.com>
 
+       * passphrase.c (agent_open): Dropped support for W32 - is was
+       never actually used.  Removed support for the old non-assuan
+       protocol; there has never been a matured implementation and
+       gpg-agent is now arround for quite some time.  Rewritten to make
+       use of the Assuan code from ../util.
+       (gpga_protocol_codes): Removed.
+       (readn): Removed.
+       (agent_close): Simplified for use with Assuan.
+       (agent_get_passphrase, passphrase_clear_cache): Removed support
+       for old protocol.  Use only with ENABLE_CARD_SUPPORT defined.
+       (agent_send_all_options): Take assuan context instead of a file
+       descriptor.
+       (agent_send_option): Likewise. Use assuan_transact.
+       * passphrase.c (writen, readaline): Removed.
+
+       * g10.c (main): Print a warning if --use-agent has been used but
+       it has not been build with support for it.
+
        * keydb.c (keydb_add_resource): Clarify meaning of flags.  Add new
        flag 4.  Use log_info for errors registering the default secret key.
        * g10.c (main): Flag the default keyrings.
index 79a1e20..fefb8ab 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -2591,6 +2591,14 @@ main( int argc, char **argv )
                        "--no-literal" );
     }
 
+#ifndef ENABLE_AGENT_SUPPORT   
+    if (opt.use_agent) {
+      log_info(_("NOTE: %s is not available in this version\n"),
+               "--use-agent");
+      opt.use_agent = 0;
+    }
+#endif /*!ENABLE_AGENT_SUPPORT*/
+
     if (opt.set_filesize)
        log_info(_("NOTE: %s is not for normal use!\n"), "--set-filesize");
     if( opt.batch )
index da2820b..c309904 100644 (file)
 #include "main.h"
 #include "i18n.h"
 #include "status.h"
-
-
-enum gpga_protocol_codes {
-    /* Request codes */
-    GPGA_PROT_GET_VERSION     = 1,
-    GPGA_PROT_GET_PASSPHRASE  = 2,
-    GPGA_PROT_CLEAR_PASSPHRASE= 3,
-    GPGA_PROT_SHUTDOWN        = 4,
-    GPGA_PROT_FLUSH           = 5,
-
-    /* Reply codes */
-    GPGA_PROT_REPLY_BASE     = 0x10000,
-    GPGA_PROT_OKAY           = 0x10001,
-    GPGA_PROT_GOT_PASSPHRASE = 0x10002,
-
-    /* Error codes */
-    GPGA_PROT_ERROR_BASE     = 0x20000,
-    GPGA_PROT_PROTOCOL_ERROR = 0x20001,
-    GPGA_PROT_INVALID_REQUEST= 0x20002,
-    GPGA_PROT_CANCELED       = 0x20003,    
-    GPGA_PROT_NO_PASSPHRASE  = 0x20004,    
-    GPGA_PROT_BAD_PASSPHRASE = 0x20005,
-    GPGA_PROT_INVALID_DATA   = 0x20006,
-    GPGA_PROT_NOT_IMPLEMENTED= 0x20007,
-    GPGA_PROT_UI_PROBLEM     = 0x20008
-};
+#ifdef ENABLE_AGENT_SUPPORT
+#include "assuan.h"
+#endif /*ENABLE_AGENT_SUPPORT*/
 
 
 #define buftou32( p )  ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \
@@ -191,187 +168,29 @@ read_passphrase_from_fd( int fd )
   fd_passwd = pw;
 }
 
-static int
-writen (int fd, const void *buf, size_t nbytes)
-{
-#if defined (_WIN32)
-  DWORD nwritten, nleft = nbytes;
-    
-  while (nleft > 0)
-    {
-      if (!WriteFile ((HANDLE)write_fd, buf, nleft, &nwritten, NULL))
-        {
-          log_error ("write failed: %s\n", w32_strerror (0));
-          return -1;
-        }
-      /*log_info ("** WriteFile fd=%d nytes=%d nwritten=%d\n",
-        write_fd, nbytes, (int)nwritten);*/
-      Sleep (100);
-       
-      nleft -= nwritten;
-      buf = (const BYTE *)buf + nwritten;
-    }
-#elif defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
-  /* not implemented */
-#else
-  size_t nleft = nbytes;
-  int nwritten;
-
-  while (nleft > 0)
-    {
-      nwritten = write (fd, buf, nleft);
-      if (nwritten < 0)
-        {
-          if (errno == EINTR)
-            nwritten = 0;
-          else
-            {
-              log_error ("write() failed: %s\n", strerror (errno));
-              return -1;
-            }
-        }
-      nleft -= nwritten;
-      buf = (const char*)buf + nwritten;
-    }
-#endif
-    
-  return 0;
-}
-
-
-static int
-readn (int fd, void *buf, size_t buflen, size_t *ret_nread)
-{
-#if defined (_WIN32)
-  DWORD nread, nleft = buflen;
-    
-  while (nleft > 0)
-    {
-      if (!ReadFile ((HANDLE)read_fd, buf, nleft, &nread, NULL))
-        {
-          log_error ("read() error: %s\n", w32_strerror (0));
-          return -1;
-       }
-      if (!nread || GetLastError() == ERROR_BROKEN_PIPE)
-        break;
-      /*log_info ("** ReadFile fd=%d buflen=%d nread=%d\n",
-        read_fd, buflen, (int)nread);*/
-      Sleep (100);
-       
-      nleft -= nread;
-      buf = (BYTE *)buf + nread;
-    }          
-  if (ret_nread)
-    *ret_nread = buflen - nleft;
-
-#elif defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
-  /* not implemented */
-#else
-  size_t nleft = buflen;
-  int nread;
-  char *p;
-  
-  p = buf;
-  while( nleft > 0 )
-    {
-      nread = read ( fd, buf, nleft );
-      if( nread < 0 ) 
-        {
-          if (errno == EINTR)
-            nread = 0;
-          else 
-            {
-              log_error ( "read() error: %s\n", strerror (errno) );
-              return -1;
-            }
-        }
-      else if (!nread)
-        break; /* EOF */
-      nleft -= nread;
-      buf = (char*)buf + nread;
-    }
-  if (ret_nread)
-    *ret_nread = buflen - nleft;
-#endif
-    
-  return 0;
-}
-
-/* read an entire line */
-static int
-readaline (int fd, char *buf, size_t buflen)
-{
-  size_t nleft = buflen;
-  char *p;
-  int nread = 0;
-
-  while (nleft > 0)
-    {
-      int n = read (fd, buf, nleft);
-      if (n < 0)
-        {
-          if (errno == EINTR)
-            continue;
-          return -1; /* read error */
-        }
-      else if (!n)
-        {
-          return -1; /* incomplete line */
-        }
-      p = buf;
-      nleft -= n;
-      buf += n;
-      nread += n;
-      
-      for (; n && *p != '\n'; n--, p++)
-        ;
-      if (n)
-        {
-          break; /* at least one full line available - that's enough.
-                    This function is just a temporary hack until we use
-                    the assuna lib in gpg.  So it is okay to forget
-                    about pending bytes */
-        }
-    }
-
-  return nread; 
-}
-
-
 
-#if !defined (__riscos__)
 
-#if !defined (_WIN32)
-/* For the new Assuan protocol we may have to send options */
+#ifdef ENABLE_AGENT_SUPPORT
+/* Send one option to the gpg-agent.  */
 static int
-agent_send_option (int fd, const char *name, const char *value)
+agent_send_option (assuan_context_t ctx, const char *name, const char *value)
 {
-  char buf[200];
-  int nread;
   char *line;
-  int i; 
-  
-  line = m_alloc (7 + strlen (name) + 1 + strlen (value) + 2);
-  strcpy (stpcpy (stpcpy (stpcpy (
-                     stpcpy (line, "OPTION "), name), "="), value), "\n");
-  i = writen (fd, line, strlen (line));
-  m_free (line);
-  if (i)
-    return -1;
+  int rc; 
   
-  /* get response */
-  nread = readaline (fd, buf, DIM(buf)-1);
-  if (nread < 3)
-    return -1;
-  
-  if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n')) 
-    return 0; /* okay */
-
-  return -1;
+  if (!value || !*value)
+    return 0; /* Avoid sending empty option values. */
+
+  line = xmalloc (7 + strlen (name) + 1 + strlen (value) + 1);
+  strcpy (stpcpy (stpcpy (stpcpy (line, "OPTION "), name), "="), value);
+  rc = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+  xfree (line);
+  return rc? -1 : 0;
 }
 
+/* Send all required options to the gpg-agent.  */
 static int 
-agent_send_all_options (int fd)
+agent_send_all_options (assuan_context_t ctx)
 {
   char *dft_display = NULL;
   const char *dft_ttyname = NULL;
@@ -383,7 +202,7 @@ agent_send_all_options (int fd)
   dft_display = getenv ("DISPLAY");
   if (opt.display || dft_display)
     {
-      if (agent_send_option (fd, "display",
+      if (agent_send_option (ctx, "display",
                              opt.display ? opt.display : dft_display))
         return -1;
     }
@@ -400,7 +219,7 @@ agent_send_all_options (int fd)
     }
   if (opt.ttyname || dft_ttyname)
     {
-      if (agent_send_option (fd, "ttyname",
+      if (agent_send_option (ctx, "ttyname",
                              opt.ttyname ? opt.ttyname : dft_ttyname))
         return -1;
     }
@@ -408,7 +227,7 @@ agent_send_all_options (int fd)
   dft_ttytype = getenv ("TERM");
   if (opt.ttytype || (dft_ttyname && dft_ttytype))
     {
-      if (agent_send_option (fd, "ttytype",
+      if (agent_send_option (ctx, "ttytype",
                              opt.ttyname ? opt.ttytype : dft_ttytype))
         return -1;
     }
@@ -421,7 +240,7 @@ agent_send_all_options (int fd)
 #endif
   if (opt.lc_ctype || (dft_ttyname && dft_lc))
     {
-      rc = agent_send_option (fd, "lc-ctype",
+      rc = agent_send_option (ctx, "lc-ctype",
                               opt.lc_ctype ? opt.lc_ctype : dft_lc);
     }
 #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
@@ -442,7 +261,7 @@ agent_send_all_options (int fd)
 #endif
   if (opt.lc_messages || (dft_ttyname && dft_lc))
     {
-      rc = agent_send_option (fd, "lc-messages",
+      rc = agent_send_option (ctx, "lc-messages",
                               opt.lc_messages ? opt.lc_messages : dft_lc);
     }
 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
@@ -454,170 +273,147 @@ agent_send_all_options (int fd)
 #endif
   return rc;
 }
-#endif /*!_WIN32*/
+#endif /*ENABLE_AGENT_SUPPORT*/
 
 
 /*
- * Open a connection to the agent and send the magic string
- * Returns: -1 on error or an filedescriptor for urther processing
+ * Open a connection to the agent and initializes the connection.
+ * Returns: -1 on error; on success a file descriptor for that
+ * connection is returned.
  */
-
-static int
-agent_open (int *ret_prot)
+#ifdef ENABLE_AGENT_SUPPORT
+static assuan_context_t
+agent_open (void)
 {
-#if defined (_WIN32)
-    int fd;
-    char *infostr, *p;
-    HANDLE h;
-    char pidstr[128];
-
-    *ret_prot = 0;
-    if ( !(infostr = read_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
-                                              "agentPID")) 
-         || *infostr == '0') {
-       log_error( _("gpg-agent is not available in this session\n"));
-       return -1;
-    }
-    free(infostr);
-    
-    sprintf(pidstr, "%u", (unsigned int)GetCurrentProcessId());
-    if (write_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
-                                  "agentCID", pidstr)) {
-        log_error( _("can't set client pid for the agent\n") );
-        return -1;
-    }
-    h = OpenEvent(EVENT_ALL_ACCESS, FALSE, "gpg_agent");
-    SetEvent(h);
-    Sleep(50); /* some time for the server */ 
-    if ( !(p = read_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
-                                        "agentReadFD")) ) {
-       log_error( _("can't get server read FD for the agent\n") );
-       return -1;
-    }
-    read_fd = atol(p);
-    free(p);    
-    if ( !(p = read_w32_registry_string(NULL, "Software\\GNU\\GnuPG",
-                                        "agentWriteFD")) ) {
-       log_error ( _("can't get server write FD for the agent\n") );
-       return -1;
-    }
-    write_fd = atol(p);
-    free(p);
-    fd = 0;
-
-    if ( writen ( fd, "GPGA\0\0\0\x01", 8 ) ) {
-        fd = -1;
-    }
-#else /* Posix */
-
-    int fd;
-    char *infostr, *p;
-    struct sockaddr_un client_addr;
-    size_t len;
-    int prot;
+  int rc;
+  assuan_context_t ctx;
+  char *infostr, *p;
+  int prot;
+  int pid;
 
-    if (opt.gpg_agent_info)
-      infostr = m_strdup (opt.gpg_agent_info);
-    else
-      {
-        infostr = getenv ( "GPG_AGENT_INFO" );
-        if ( !infostr ) {
+  if (opt.gpg_agent_info)
+    infostr = xstrdup (opt.gpg_agent_info);
+  else
+    {
+      infostr = getenv ( "GPG_AGENT_INFO" );
+      if (!infostr || !*infostr) 
+        {
           log_error (_("gpg-agent is not available in this session\n"));
           opt.use_agent = 0;
-          return -1;
+          return NULL;
         }
-        infostr = m_strdup ( infostr );
-      }
-
-    if ( !(p = strchr ( infostr, ':')) || p == infostr
-         || (p-infostr)+1 >= sizeof client_addr.sun_path ) {
-        log_error( _("malformed GPG_AGENT_INFO environment variable\n"));
-        m_free (infostr );
-        opt.use_agent = 0;
-        return -1;
-    }
-    *p++ = 0;
-    /* See whether this is the new gpg-agent using the Assuna protocl.
-       This agent identifies itself by have an info string with a
-       version number in the 3rd field. */
-    while (*p && *p != ':')
-      p++;
-    prot = *p? atoi (p+1) : 0;
-    if ( prot < 0 || prot > 1) {
-        log_error (_("gpg-agent protocol version %d is not supported\n"),prot);
-        m_free (infostr );
-        opt.use_agent = 0;
-        return -1;
-    }
-    *ret_prot = prot;
-       
-    if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 ) {
-        log_error ("can't create socket: %s\n", strerror(errno) );
-        m_free (infostr );
-        opt.use_agent = 0;
-        return -1;
+      infostr = xstrdup ( infostr );
     }
-    
-    memset( &client_addr, 0, sizeof client_addr );
-    client_addr.sun_family = AF_UNIX;
-    strcpy( client_addr.sun_path, infostr );
-    len = offsetof (struct sockaddr_un, sun_path)
-        + strlen(client_addr.sun_path) + 1;
-    
-    if( connect( fd, (struct sockaddr*)&client_addr, len ) == -1 ) {
-        log_error ( _("can't connect to `%s': %s\n"), 
-                    infostr, strerror (errno) );
-        m_free (infostr );
-        close (fd );
-        opt.use_agent = 0;
-        return -1;
+  
+  if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
+    {
+      log_error ( _("malformed GPG_AGENT_INFO environment variable\n"));
+      xfree (infostr);
+      opt.use_agent = 0;
+      return NULL;
+    }
+  *p++ = 0;
+  pid = atoi (p);
+  while (*p && *p != PATHSEP_C)
+    p++;
+  prot = *p? atoi (p+1) : 0;
+  if (prot != 1)
+    {
+      log_error (_("gpg-agent protocol version %d is not supported\n"), prot);
+      xfree (infostr);
+      opt.use_agent = 0;
+      return NULL;
     }
-    m_free (infostr);
-
-    if (!prot) {
-        if ( writen ( fd, "GPGA\0\0\0\x01", 8 ) ) {
-          close (fd);
-          fd = -1;
-        }
+     
+  rc = assuan_socket_connect (&ctx, infostr, pid);
+  if (rc)
+    {
+      log_error ( _("can't connect to `%s': %s\n"), 
+                  infostr, assuan_strerror (rc));
+      xfree (infostr );
+      opt.use_agent = 0;
+      return NULL;
     }
-    else { /* assuan based gpg-agent */
-      char line[200];
-      int nread;
-
-      nread = readaline (fd, line, DIM(line));
-      if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
-                         && (line[2] == '\n' || line[2] == ' ')) ) {
-        log_error ( _("communication problem with gpg-agent\n"));
-        close (fd );
-        opt.use_agent = 0;
-        return -1;
-      }
+  xfree (infostr);
 
-      if (agent_send_all_options (fd)) {
-        log_error (_("problem with the agent - disabling agent use\n"));
-        close (fd);
-        opt.use_agent = 0;
-        return -1;
-      }
-        
+  if (agent_send_all_options (ctx))
+    {
+      log_error (_("problem with the agent - disabling agent use\n"));
+      assuan_disconnect (ctx);
+      opt.use_agent = 0;
+      return NULL;
     }
-#endif
 
-    return fd;
+  return ctx;
 }
+#endif/*ENABLE_AGENT_SUPPORT*/
 
 
+#ifdef ENABLE_AGENT_SUPPORT
 static void
-agent_close ( int fd )
+agent_close (assuan_context_t ctx)
 {
-#if defined (_WIN32)
-    HANDLE h = OpenEvent(EVENT_ALL_ACCESS, FALSE, "gpg_agent");
-    ResetEvent(h);
-#else
-    close (fd);
-#endif
+  assuan_disconnect (ctx);
 }
-#endif /* !__riscos__ */
+#endif /*ENABLE_AGENT_SUPPORT*/
+
+
+/* Copy the text ATEXT into the buffer P and do plus '+' and percent
+   escaping.  Note that the provided buffer needs to be 3 times the
+   size of ATEXT plus 1.  Returns a pointer to the leading Nul in P. */
+#ifdef ENABLE_AGENT_SUPPORT
+static char *
+percent_plus_escape (char *p, const char *atext)
+{
+  const unsigned char *s;
+
+  for (s=atext; *s; s++)
+    {
+      if (*s < ' ' || *s == '+')
+        {
+          sprintf (p, "%%%02X", *s);
+          p += 3;
+        }
+      else if (*s == ' ')
+        *p++ = '+';
+      else
+        *p++ = *s;
+    }
+  *p = 0;
+  return p;
+}
+#endif /*ENABLE_AGENT_SUPPORT*/
+
+
+#ifdef ENABLE_AGENT_SUPPORT
+
+/* Object for the agent_okay_cb function.  */
+struct agent_okay_cb_s {
+  char *pw;
+};
+
+/* A callback used to get the passphrase from the okay line.  See
+   agent-get_passphrase for details.  LINE is the rest of the OK
+   status line without leading white spaces. */
+static assuan_error_t
+agent_okay_cb (void *opaque, const char *line)
+{ 
+  struct agent_okay_cb_s *parm = opaque;
+  int i;
+
+  /* Note: If the malloc below fails we won't be able to wipe the
+     memory at LINE given the current implementation of the Assuan
+     code. There is no easy ay around this w/o adding a lot of more
+     memory function code to allow wiping arbitrary stuff on memory
+     failure. */
+  parm->pw = xmalloc_secure (strlen (line)/2+2);
+  
+  for (i=0; hexdigitp (line) && hexdigitp (line+1); line += 2)
+    parm->pw[i++] = xtoi_2 (line);
+  parm->pw[i] = 0; 
+  return 0;
+}
+#endif /*ENABLE_AGENT_SUPPORT*/
 
 
 
@@ -636,19 +432,13 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
                        const char *custom_description,
                        const char *custom_prompt, int *canceled)
 {
-#if defined(__riscos__)
-  return NULL;
-#else
-  size_t n;
+#ifdef ENABLE_AGENT_SUPPORT
   char *atext = NULL;
-  char buf[50];
-  int fd = -1;
-  u32 reply;
+  assuan_context_t ctx = NULL;
   char *pw = NULL;
   PKT_public_key *pk = m_alloc_clear( sizeof *pk );
   byte fpr[MAX_FINGERPRINT_LEN];
   int have_fpr = 0;
-  int prot;
   char *orig_codeset = NULL;
 
   if (canceled)
@@ -667,7 +457,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
     }
   
 #ifdef ENABLE_NLS
-  /* The Assuan agent protol requires us to transmit utf-8 strings */
+  /* The Assuan agent protocol requires us to transmit utf-8 strings */
   orig_codeset = bind_textdomain_codeset (PACKAGE, NULL);
 #ifdef HAVE_LANGINFO_CODESET
   if (!orig_codeset)
@@ -681,7 +471,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
     }
 #endif
 
-  if ( (fd = agent_open (&prot)) == -1 ) 
+  if ( !(ctx = agent_open ()) ) 
     goto failure;
 
   if (custom_description)
@@ -740,100 +530,23 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
   else
     atext = m_strdup ( _("Enter passphrase\n") );
                 
-  if (!prot)
-    { /* old style protocol */
-      size_t nread;
-
-      n = 4 + 20 + strlen (atext);
-      u32tobuf (buf, n );
-      u32tobuf (buf+4, GPGA_PROT_GET_PASSPHRASE );
-      memcpy (buf+8, fpr, 20 );
-      if ( writen ( fd, buf, 28 ) || writen ( fd, atext, strlen (atext) ) ) 
-        goto failure;
-      m_free (atext); atext = NULL;
-      
-      /* get response */
-      if ( readn ( fd, buf, 12, &nread ) ) 
-        goto failure;
-      
-      if ( nread < 8 ) 
-        {
-          log_error ( "response from agent too short\n" );
-          goto failure;
-        }
-      n = buftou32 ( buf );
-      reply = buftou32 ( buf + 4 );
-      if ( reply == GPGA_PROT_GOT_PASSPHRASE ) 
-        {
-          size_t pwlen;
-          size_t nn;
-          
-          if ( nread < 12 || n < 8 ) 
-            {
-              log_error ( "response from agent too short\n" );
-              goto failure;
-            }
-          pwlen = buftou32 ( buf + 8 );
-          nread -= 12;
-          n -= 8;
-          if ( pwlen > n || n > 1000 ) 
-            {
-              log_error (_("passphrase too long\n"));
-              /* or protocol error */
-              goto failure;
-            }
-          /* we read the whole block in one chunk to give no hints
-           * on how long the passhrase actually is - this wastes some bytes
-           * but because we already have this padding we should not loosen
-           * this by issuing 2 read calls */
-          pw = m_alloc_secure ( n+1 );
-          if ( readn ( fd, pw, n, &nn ) )
-            goto failure;
-          if ( n != nn ) 
-            {
-              log_error (_("invalid response from agent\n"));
-              goto failure;           
-            }
-          pw[pwlen] = 0; /* make a C String */
-          agent_close (fd);
-          if (pk)
-            free_public_key( pk );
-#ifdef ENABLE_NLS
-          if (orig_codeset)
-            bind_textdomain_codeset (PACKAGE, orig_codeset);
-#endif
-          m_free (orig_codeset);
-          return pw;
-        }
-      else if ( reply == GPGA_PROT_CANCELED ) 
-        {
-          log_info ( _("cancelled by user\n") );
-          if (canceled)
-            *canceled = 1;
-        }
-      else 
-        log_error ( _("problem with the agent: agent returns 0x%lx\n"),
-                    (ulong)reply );
-    }
-  else
-    { /* The new Assuan protocol */
-      int nread;
+  { 
       char *line, *p;
-      const unsigned char *s;
-      int i; 
+      int i, rc; 
+      struct agent_okay_cb_s okay_cb_parm;
 
       if (!tryagain_text)
         tryagain_text = "X";
       else
         tryagain_text = _(tryagain_text);
 
-      /* We allocate 2 time the needed space for atext so that there
-         is enough space for escaping */
-      line = m_alloc (15 + 46 
-                      + 3*strlen (tryagain_text)
+      /* We allocate 23 times the needed space for thye texts so that
+         there is enough space for escaping. */
+      line = xmalloc (15 + 46 
                       + 3*strlen (atext)
                       + 3*strlen (custom_prompt? custom_prompt:"")
-                      + 2);
+                      + 3*strlen (tryagain_text)
+                      + 1);
       strcpy (line, "GET_PASSPHRASE ");
       p = line+15;
       if (!mode && have_fpr)
@@ -842,92 +555,50 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
             sprintf (p, "%02X", fpr[i]);
         }
       else
-        *p++ = 'X'; /* no caching */
+        *p++ = 'X'; /* No caching. */
       *p++ = ' ';
-      for (i=0, s=tryagain_text; *s; s++)
-        {
-          if (*s < ' ' || *s == '+')
-            {
-              sprintf (p, "%%%02X", *s);
-              p += 3;
-            }
-          else if (*s == ' ')
-            *p++ = '+';
-          else
-            *p++ = *s;
-        }
+
+      p = percent_plus_escape (p, tryagain_text);
       *p++ = ' ';
 
       /* The prompt.  */
       if (custom_prompt)
         {
           char *tmp = native_to_utf8 (custom_prompt);
-          for (i=0, s=tmp; *s; s++)
-            {
-              if (*s < ' ' || *s == '+')
-                {
-                  sprintf (p, "%%%02X", *s);
-                  p += 3;
-                }
-              else if (*s == ' ')
-                *p++ = '+';
-              else
-                *p++ = *s;
-            }
+          p = percent_plus_escape (p, tmp);
           xfree (tmp);
         }
       else
-        *p++ = 'X'; /* Use the standard prompt */
-
+        *p++ = 'X'; /* Use the standard prompt. */
       *p++ = ' ';
-      /* copy description */
-      for (i=0, s= atext; *s; s++)
+
+      /* Copy description. */
+      percent_plus_escape (p, atext);
+
+      /* Call gpg-agent.  */
+      memset (&okay_cb_parm, 0, sizeof okay_cb_parm);
+      rc = assuan_transact2 (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL,
+                             agent_okay_cb, &okay_cb_parm);
+
+      xfree (line);
+      xfree (atext); atext = NULL;
+      if (!rc)
         {
-          if (*s < ' ' || *s == '+')
-            {
-              sprintf (p, "%%%02X", *s);
-              p += 3;
-            }
-          else if (*s == ' ')
-            *p++ = '+';
-          else
-            *p++ = *s;
-        }
-      *p++ = '\n';
-      i = writen (fd, line, p - line);
-      m_free (line);
-      if (i)
-        goto failure;
-      m_free (atext); atext = NULL;
-      
-      /* get response */
-      pw = m_alloc_secure (500);
-      nread = readaline (fd, pw, 499);
-      if (nread < 3)
-        goto failure;
-      
-      if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ') 
-        { /* we got a passphrase - convert it back from hex */
-          size_t pwlen = 0;
-
-          for (i=3; i < nread && hexdigitp (pw+i); i+=2)
-            pw[pwlen++] = xtoi_2 (pw+i);
-          pw[pwlen] = 0; /* make a C String */
-          agent_close (fd);
+          assert (okay_cb_parm.pw);
+          pw = okay_cb_parm.pw;
+          agent_close (ctx);
           if (pk)
             free_public_key( pk );
 #ifdef ENABLE_NLS
           if (orig_codeset)
             bind_textdomain_codeset (PACKAGE, orig_codeset);
 #endif
-          m_free (orig_codeset);
+          xfree (orig_codeset);
           return pw;
         }
-      else if (nread > 4 && !memcmp (pw, "ERR ", 4)
-              && (0xffff & strtoul (&pw[4], NULL, 0)) == 99)
+      else if (rc && (rc & 0xffff) == 99)
        {
-         /* 99 is GPG_ERR_CANCELED.  FIXME: Check tail and overflow,
-            and use gpg-error.  */
+         /* 99 is GPG_ERR_CANCELED. */
           log_info (_("cancelled by user\n") );
           if (canceled)
             *canceled = 1;
@@ -937,7 +608,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
           log_error (_("problem with the agent - disabling agent use\n"));
           opt.use_agent = 0;
         }
-    }
+  }
       
         
  failure:
@@ -945,34 +616,28 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
   if (orig_codeset)
     bind_textdomain_codeset (PACKAGE, orig_codeset);
 #endif
-  m_free (atext);
-  if ( fd != -1 )
-    agent_close (fd);
-  m_free (pw );
+  xfree (atext);
+  agent_close (ctx);
+  xfree (pw );
   if (pk)
     free_public_key( pk );
-  
+
+#endif /*ENABLE_AGENT_SUPPORT*/
+
   return NULL;
-#endif /* Posix or W32 */
 }
 
+
 /*
  * Clear the cached passphrase
  */
 void
 passphrase_clear_cache ( u32 *keyid, int algo )
 {
-#if defined(__riscos__)
-  return ;
-#else
-  size_t n;
-  char buf[200];
-  int fd = -1;
-  size_t nread;
-  u32 reply;
+#ifdef ENABLE_AGENT_SUPPORT
+  assuan_context_t ctx = NULL;
   PKT_public_key *pk;
   byte fpr[MAX_FINGERPRINT_LEN];
-  int prot;
   
 #if MAX_FINGERPRINT_LEN < 20
 #error agent needs a 20 byte fingerprint
@@ -981,7 +646,7 @@ passphrase_clear_cache ( u32 *keyid, int algo )
   if (!opt.use_agent)
     return;
   
-  pk = m_alloc_clear ( sizeof *pk );
+  pk = xcalloc (1, sizeof *pk);
   memset (fpr, 0, MAX_FINGERPRINT_LEN );
   if( !keyid || get_pubkey( pk, keyid ) )
     {
@@ -993,58 +658,23 @@ passphrase_clear_cache ( u32 *keyid, int algo )
     fingerprint_from_pk( pk, fpr, &dummy );
   }
     
-  if ( (fd = agent_open (&prot)) == -1 ) 
+  if ( !(ctx = agent_open ()) ) 
     goto failure;
 
-  if (!prot)
-    {
-      n = 4 + 20;
-      u32tobuf (buf, n );
-      u32tobuf (buf+4, GPGA_PROT_CLEAR_PASSPHRASE );
-      memcpy (buf+8, fpr, 20 );
-      if ( writen ( fd, buf, 28 ) )  
-        goto failure;
-      
-      /* get response */
-      if ( readn ( fd, buf, 8, &nread ) ) 
-        goto failure;
-      
-      if ( nread < 8 ) {
-        log_error ( "response from agent too short\n" );
-        goto failure;
-      }
-      
-      reply = buftou32 ( buf + 4 );
-      if ( reply != GPGA_PROT_OKAY && reply != GPGA_PROT_NO_PASSPHRASE )
-        {
-          log_error ( _("problem with the agent: agent returns 0x%lx\n"),
-                      (ulong)reply );
-        }
-    }
-  else 
-    { /* The assuan protocol */
+  { 
       char *line, *p;
-      int i; 
+      int i, rc
 
-      line = m_alloc (17 + 40 + 2);
+      line = xmalloc (17 + 40 + 2);
       strcpy (line, "CLEAR_PASSPHRASE ");
       p = line+17;
       for (i=0; i < 20; i++, p +=2 )
         sprintf (p, "%02X", fpr[i]);
-      *p++ = '\n';
-      i = writen (fd, line, p - line);
-      m_free (line);
-      if (i)
-        goto failure;
-      
-      /* get response */
-      nread = readaline (fd, buf, DIM(buf)-1);
-      if (nread < 3)
-        goto failure;
-      
-      if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n')) 
-        ;
-      else 
+      *p = 0;
+
+      rc = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+      xfree (line);
+      if (rc)
         {
           log_error (_("problem with the agent - disabling agent use\n"));
           opt.use_agent = 0;
@@ -1052,11 +682,10 @@ passphrase_clear_cache ( u32 *keyid, int algo )
     }
         
  failure:
-  if (fd != -1)
-    agent_close (fd);
+  agent_close (ctx);
   if (pk)
     free_public_key( pk );
-#endif /* Posix or W32 */
+#endif /*ENABLE_AGENT_SUPPORT*/
 }
 
 
index d922d6e..ae62bcf 100644 (file)
@@ -1,3 +1,11 @@
+2005-04-04  Werner Koch  <wk@g10code.com>
+
+       * memory.h (xcalloc, xcalloc_secure): Replaced macros by functions.
+
+2005-03-31  Werner Koch  <wk@g10code.com>
+
+       * assuan.h: New.  Taken from libassuan 0.6.9.
+
 2005-03-18  David Shaw  <dshaw@jabberwocky.com>
 
        * ttyio.h: Prototype tty_enable_completion(), and
@@ -506,7 +514,7 @@ Tue Mar  3 15:11:21 1998  Werner Koch  (wk@isil.d.shuttle.de)
 
 
  Copyright 1998, 1999, 2000, 2001, 2002, 2003,
-          2004 Free Software Foundation, Inc.
+          2004, 2005 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
diff --git a/include/assuan.h b/include/assuan.h
new file mode 100644 (file)
index 0000000..d39b774
--- /dev/null
@@ -0,0 +1,261 @@
+/* assuan.c - Definitions for the Assuan protocol
+ *     Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+ *     Copyright (C) 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of Assuan.
+ *
+ * Assuan is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Assuan 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 
+ */
+
+/* Please note that this is a stripped down and modified version of
+   the orginal Assuan code from libassuan.  For the standalone version
+   of gnupg we only need the ability to connect to a server, so we
+   dropped everything else and maintain this separate copy. */
+
+#ifndef ASSUAN_H
+#define ASSUAN_H
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+typedef enum
+{
+  ASSUAN_No_Error = 0,
+  ASSUAN_General_Error = 1,
+  ASSUAN_Out_Of_Core = 2,
+  ASSUAN_Invalid_Value = 3,
+  ASSUAN_Timeout = 4,
+  ASSUAN_Read_Error = 5,
+  ASSUAN_Write_Error = 6,
+  ASSUAN_Problem_Starting_Server = 7,
+  ASSUAN_Not_A_Server = 8,
+  ASSUAN_Not_A_Client = 9,
+  ASSUAN_Nested_Commands = 10,
+  ASSUAN_Invalid_Response = 11,
+  ASSUAN_No_Data_Callback = 12,
+  ASSUAN_No_Inquire_Callback = 13,
+  ASSUAN_Connect_Failed = 14,
+  ASSUAN_Accept_Failed = 15,
+
+  /* Error codes above 99 are meant as status codes */
+  ASSUAN_Not_Implemented = 100,
+  ASSUAN_Server_Fault    = 101,
+  ASSUAN_Invalid_Command = 102,
+  ASSUAN_Unknown_Command = 103,
+  ASSUAN_Syntax_Error    = 104,
+  ASSUAN_Parameter_Error = 105,
+  ASSUAN_Parameter_Conflict = 106,
+  ASSUAN_Line_Too_Long = 107,
+  ASSUAN_Line_Not_Terminated = 108,
+  ASSUAN_No_Input = 109,
+  ASSUAN_No_Output = 110,
+  ASSUAN_Canceled = 111,
+  ASSUAN_Unsupported_Algorithm = 112,
+  ASSUAN_Server_Resource_Problem = 113,
+  ASSUAN_Server_IO_Error = 114,
+  ASSUAN_Server_Bug = 115,
+  ASSUAN_No_Data_Available = 116,
+  ASSUAN_Invalid_Data = 117,
+  ASSUAN_Unexpected_Command = 118,
+  ASSUAN_Too_Much_Data = 119,
+  ASSUAN_Inquire_Unknown = 120,
+  ASSUAN_Inquire_Error = 121,
+  ASSUAN_Invalid_Option = 122,
+  ASSUAN_Invalid_Index = 123,
+  ASSUAN_Unexpected_Status = 124,
+  ASSUAN_Unexpected_Data = 125,
+  ASSUAN_Invalid_Status = 126,
+  ASSUAN_Locale_Problem = 127,
+  ASSUAN_Not_Confirmed = 128,
+
+  /* Error codes in the range 1000 to 9999 may be used by applications
+     at their own discretion. */
+  ASSUAN_USER_ERROR_FIRST = 1000,
+  ASSUAN_USER_ERROR_LAST = 9999
+
+} assuan_error_t;
+
+
+#define ASSUAN_LINELENGTH 1002 /* 1000 + [CR,]LF */
+
+struct assuan_context_s;
+typedef struct assuan_context_s *assuan_context_t;
+
+/*-- assuan-handler.c --*/
+int assuan_register_command (assuan_context_t ctx,
+                             const char *cmd_string,
+                             int (*handler)(assuan_context_t, char *));
+int assuan_register_bye_notify (assuan_context_t ctx,
+                                void (*fnc)(assuan_context_t));
+int assuan_register_reset_notify (assuan_context_t ctx,
+                                  void (*fnc)(assuan_context_t));
+int assuan_register_cancel_notify (assuan_context_t ctx,
+                                   void (*fnc)(assuan_context_t));
+int assuan_register_input_notify (assuan_context_t ctx,
+                                  void (*fnc)(assuan_context_t, const char *));
+int assuan_register_output_notify (assuan_context_t ctx,
+                                  void (*fnc)(assuan_context_t, const char *));
+
+int assuan_register_option_handler (assuan_context_t ctx,
+                                    int (*fnc)(assuan_context_t,
+                                               const char*, const char*));
+
+int assuan_process (assuan_context_t ctx);
+int assuan_process_next (assuan_context_t ctx);
+int assuan_get_active_fds (assuan_context_t ctx, int what,
+                           int *fdarray, int fdarraysize);
+
+
+FILE *assuan_get_data_fp (assuan_context_t ctx);
+assuan_error_t assuan_set_okay_line (assuan_context_t ctx, const char *line);
+assuan_error_t assuan_write_status (assuan_context_t ctx,
+                                    const char *keyword, const char *text);
+
+/* Negotiate a file descriptor.  If LINE contains "FD=N", returns N
+   assuming a local file descriptor.  If LINE contains "FD" reads a
+   file descriptor via CTX and stores it in *RDF (the CTX must be
+   capable of passing file descriptors).  */
+assuan_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line,
+                                    int *rfd);
+
+/*-- assuan-listen.c --*/
+assuan_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line);
+assuan_error_t assuan_accept (assuan_context_t ctx);
+int assuan_get_input_fd (assuan_context_t ctx);
+int assuan_get_output_fd (assuan_context_t ctx);
+assuan_error_t assuan_close_input_fd (assuan_context_t ctx);
+assuan_error_t assuan_close_output_fd (assuan_context_t ctx);
+
+
+/*-- assuan-pipe-server.c --*/
+int assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]);
+void assuan_deinit_server (assuan_context_t ctx);
+
+/*-- assuan-socket-server.c --*/
+int assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd);
+int assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd);
+
+
+/*-- assuan-pipe-connect.c --*/
+assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, const char *name,
+                                 char *const argv[], int *fd_child_list);
+assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx, const char *name,
+                                     char *const argv[], int *fd_child_list,
+                                     void (*atfork) (void*, int),
+                                     void *atforkvalue);
+/*-- assuan-socket-connect.c --*/
+assuan_error_t assuan_socket_connect (assuan_context_t *ctx, const char *name,
+                                      pid_t server_pid);
+
+/*-- assuan-domain-connect.c --*/
+
+/* Connect to a Unix domain socket server.  RENDEZVOUSFD is
+   bidirectional file descriptor (normally returned via socketpair)
+   which the client can use to rendezvous with the server.  SERVER s
+   the server's pid.  */
+assuan_error_t assuan_domain_connect (assuan_context_t *r_ctx,
+                                  int rendezvousfd,
+                                  pid_t server);
+
+/*-- assuan-domain-server.c --*/
+
+/* RENDEZVOUSFD is a bidirectional file descriptor (normally returned
+   via socketpair) that the domain server can use to rendezvous with
+   the client.  CLIENT is the client's pid.  */
+assuan_error_t assuan_init_domain_server (assuan_context_t *r_ctx,
+                                      int rendezvousfd,
+                                      pid_t client);
+
+
+/*-- assuan-connect.c --*/
+void assuan_disconnect (assuan_context_t ctx);
+pid_t assuan_get_pid (assuan_context_t ctx);
+
+/*-- assuan-client.c --*/
+assuan_error_t 
+assuan_transact (assuan_context_t ctx,
+                 const char *command,
+                 assuan_error_t (*data_cb)(void *, const void *, size_t),
+                 void *data_cb_arg,
+                 assuan_error_t (*inquire_cb)(void*, const char *),
+                 void *inquire_cb_arg,
+                 assuan_error_t (*status_cb)(void*, const char *),
+                 void *status_cb_arg);
+assuan_error_t 
+assuan_transact2 (assuan_context_t ctx,
+                  const char *command,
+                  assuan_error_t (*data_cb)(void *, const void *, size_t),
+                  void *data_cb_arg,
+                  assuan_error_t (*inquire_cb)(void*, const char *),
+                  void *inquire_cb_arg,
+                  assuan_error_t (*status_cb)(void*, const char *),
+                  void *status_cb_arg,
+                  assuan_error_t (*okay_cb)(void*, const char *),
+                  void *okay_cb_arg);
+
+
+/*-- assuan-inquire.c --*/
+assuan_error_t assuan_inquire (assuan_context_t ctx, const char *keyword,
+                            unsigned char **r_buffer, size_t *r_length,
+                            size_t maxlen);
+
+/*-- assuan-buffer.c --*/
+assuan_error_t assuan_read_line (assuan_context_t ctx,
+                              char **line, size_t *linelen);
+int assuan_pending_line (assuan_context_t ctx);
+assuan_error_t assuan_write_line (assuan_context_t ctx, const char *line );
+assuan_error_t assuan_send_data (assuan_context_t ctx,
+                              const void *buffer, size_t length);
+
+/*-- assuan-util.c --*/
+void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
+                               void *(*new_realloc_func)(void *p, size_t n),
+                               void (*new_free_func)(void*) );
+void assuan_set_log_stream (assuan_context_t ctx, FILE *fp);
+int assuan_set_error (assuan_context_t ctx, int err, const char *text);
+void assuan_set_pointer (assuan_context_t ctx, void *pointer);
+void *assuan_get_pointer (assuan_context_t ctx);
+
+void assuan_begin_confidential (assuan_context_t ctx);
+void assuan_end_confidential (assuan_context_t ctx);
+
+/*-- assuan-errors.c (built) --*/
+const char *assuan_strerror (assuan_error_t err);
+
+/*-- assuan-logging.c --*/
+
+/* Set the stream to which assuan should log message not associated
+   with a context.  By default, this is stderr.  The default value
+   will be changed when the first log stream is associated with a
+   context.  Note, that this function is not thread-safe and should
+   in general be used right at startup. */
+extern void assuan_set_assuan_log_stream (FILE *fp);
+
+/* Return the stream which is currently being using for global logging.  */
+extern FILE *assuan_get_assuan_log_stream (void);
+
+/* Set the prefix to be used at the start of a line emitted by assuan
+   on the log stream.  The default is the empty string.  Note, that
+   this function is not thread-safe and should in general be used
+   right at startup. */
+void assuan_set_assuan_log_prefix (const char *text);
+
+/* Return a prefix to be used at the start of a line emitted by assuan
+   on the log stream.  The default implementation returns the empty
+   string, i.e. ""  */
+const char *assuan_get_assuan_log_prefix (void);
+
+#endif /* ASSUAN_H */
index 377c2b7..4ab5cc4 100644 (file)
@@ -1,5 +1,5 @@
 /* memory.h - memory allocation
- *     Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GNUPG.
  *
@@ -93,9 +93,9 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
 /* To prepare a migration to the xmalloc suite of function as used in
    1.9 we define a couple of macros. */
 #define xmalloc(n)        m_alloc ((n))
-#define xcalloc(n,m)      m_alloc_clear ((n)*(m))
+void *xcalloc (size_t n, size_t m);
 #define xmalloc_secure(n) m_alloc_secure (n)
-#define xcalloc_secure(n) m_alloc_secure_clear ((n)*(m))
+void *xcalloc_secure (size_t n, size_t m);
 #define xrealloc(a,n)     m_realloc ((a),(n))
 #define xstrdup(a)        m_strdup ((a))
 #define xfree(a)          m_free (a)
index 52b9c31..b6f35d3 100644 (file)
@@ -1,3 +1,22 @@
+2005-04-04  Werner Koch  <wk@g10code.com>
+
+       * memory.c (xcalloc, xcalloc_secure): New wrappers.
+
+       * assuan-client.c (assuan_transact): Factored all code out to ..
+       (assuan_transact2): .. new.  Add arg OKAY_CB.  Wipe the memory
+       processed though that callback.
+
+2005-03-31  Werner Koch  <wk@g10code.com>
+
+       * isascii.c: New.  This is an autoconf replacement function.
+
+       * Makefile.am (assuan_source): New.  Only used when agent support
+       has been requested.
+       * assuan-buffer.c, assuan-client.c, assuan-defs.h,
+       * assuan-errors.c, assuan-logging.c, assuan-socket-connect.c,
+       * assuan-socket.c, assuan-util.c, assuan-connect.c: New.  Taken
+       from libassuan 0.6.9 and adjusted for our limited use of Assuan.
+
 2005-03-18  David Shaw  <dshaw@jabberwocky.com>
 
        * ttyio.c (tty_enable_completion, tty_disable_completion): Enable
index 973f36c..cb241da 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+# Copyright (C) 1998, 1999, 2000, 2001, 2005 Free Software Foundation, Inc.
 #
 # This file is part of GnuPG.
 #
@@ -22,12 +22,24 @@ INCLUDES = -I.. -I$(top_srcdir)/include -I$(top_srcdir)/intl
 
 noinst_LIBRARIES = libutil.a
 
-EXTRA_libutil_a_SOURCES = regcomp.c regex.c regexec.c regex_internal.c regex_internal.h
+EXTRA_libutil_a_SOURCES = regcomp.c regex.c regexec.c regex_internal.c \
+                         regex_internal.h
+
+# We build the assuan support only if it has been requested.
+if ENABLE_AGENT_SUPPORT
+assuan_source = assuan-buffer.c assuan-client.c assuan-defs.h \
+                 assuan-errors.c assuan-logging.c assuan-socket-connect.c \
+                assuan-connect.c assuan-socket.c assuan-util.c
+else
+assuan_source =
+endif
+
 
 #libutil_a_LDFLAGS =
 libutil_a_SOURCES = logger.c fileutil.c miscutil.c strgutil.c  \
                     ttyio.c  argparse.c memory.c secmem.c errors.c iobuf.c \
-                    dotlock.c http.c srv.h srv.c simple-gettext.c w32reg.c
+                    dotlock.c http.c srv.h srv.c simple-gettext.c \
+                    w32reg.c $(assuan_source)
 
 libutil_a_DEPENDENCIES = @LIBOBJS@ @REGEX_O@
 # LIBOBJS is for the replacement functions
diff --git a/util/assuan-buffer.c b/util/assuan-buffer.c
new file mode 100644 (file)
index 0000000..47f4e18
--- /dev/null
@@ -0,0 +1,480 @@
+/* assuan-buffer.c - read and send data
+ *     Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of Assuan.
+ *
+ * Assuan is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Assuan 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 
+ */
+
+/* Please note that this is a stripped down and modified version of
+   the orginal Assuan code from libassuan. */
+
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#ifdef HAVE_W32_SYSTEM
+#include <process.h>
+#endif
+#include "assuan-defs.h"
+
+static int
+writen (assuan_context_t ctx, const char *buffer, size_t length)
+{
+  while (length)
+    {
+      ssize_t nwritten = ctx->io->writefnc (ctx, buffer, length);
+      
+      if (nwritten < 0)
+        {
+          if (errno == EINTR)
+            continue;
+          return -1; /* write error */
+        }
+      length -= nwritten;
+      buffer += nwritten;
+    }
+  return 0;  /* okay */
+}
+
+/* Read an entire line.  */
+static int
+readaline (assuan_context_t ctx, char *buf, size_t buflen,
+         int *r_nread, int *r_eof)
+{
+  size_t nleft = buflen;
+  char *p;
+
+  *r_eof = 0;
+  *r_nread = 0;
+  while (nleft > 0)
+    {
+      ssize_t n = ctx->io->readfnc (ctx, buf, nleft);
+
+      if (n < 0)
+        {
+          if (errno == EINTR)
+            continue;
+          return -1; /* read error */
+        }
+      else if (!n)
+        {
+          *r_eof = 1;
+          break; /* allow incomplete lines */
+        }
+      p = buf;
+      nleft -= n;
+      buf += n;
+      *r_nread += n;
+
+      p = memrchr (p, '\n', n);
+      if (p)
+        break; /* at least one full line available - that's enough for now */
+    }
+
+  return 0;
+}
+
+
+int
+_assuan_read_line (assuan_context_t ctx)
+{
+  char *line = ctx->inbound.line;
+  int nread, atticlen;
+  int rc;
+  char *endp = 0;
+
+  if (ctx->inbound.eof)
+    return -1;
+
+  atticlen = ctx->inbound.attic.linelen;
+  if (atticlen)
+    {
+      memcpy (line, ctx->inbound.attic.line, atticlen);
+      ctx->inbound.attic.linelen = 0;
+
+      endp = memchr (line, '\n', atticlen);
+      if (endp)
+       /* Found another line in the attic.  */
+       {
+         rc = 0;
+         nread = atticlen;
+         atticlen = 0;
+       }
+      else
+       /* There is pending data but not a full line.  */
+        {
+          assert (atticlen < LINELENGTH);
+          rc = readaline (ctx, line + atticlen,
+                        LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
+        }
+    }
+  else
+    /* No pending data.  */
+    rc = readaline (ctx, line, LINELENGTH,
+                   &nread, &ctx->inbound.eof);
+  if (rc)
+    {
+      if (ctx->log_fp)
+       fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [Error: %s]\n",
+                assuan_get_assuan_log_prefix (),
+                 (unsigned int)getpid (), ctx, strerror (errno));
+      return ASSUAN_Read_Error;
+    }
+  if (!nread)
+    {
+      assert (ctx->inbound.eof);
+      if (ctx->log_fp)
+       fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [EOF]\n",
+                assuan_get_assuan_log_prefix (),
+                 (unsigned int)getpid (), ctx);
+      return -1;
+    }
+
+  ctx->inbound.attic.pending = 0;
+  nread += atticlen;
+
+  if (! endp)
+    endp = memchr (line, '\n', nread);
+
+  if (endp)
+    {
+      int n = endp - line + 1;
+      if (n < nread)
+       /* LINE contains more than one line.  We copy it to the attic
+          now as handlers are allowed to modify the passed
+          buffer.  */
+       {
+         int len = nread - n;
+         memcpy (ctx->inbound.attic.line, endp + 1, len);
+         ctx->inbound.attic.pending = memrchr (endp + 1, '\n', len) ? 1 : 0;
+         ctx->inbound.attic.linelen = len;
+       }
+
+      if (endp != line && endp[-1] == '\r')
+       endp --;
+      *endp = 0;
+
+      ctx->inbound.linelen = endp - line;
+      if (ctx->log_fp)
+       {
+         fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- ",
+                  assuan_get_assuan_log_prefix (),
+                   (unsigned int)getpid (), ctx);
+         if (ctx->confidential)
+           fputs ("[Confidential data not shown]", ctx->log_fp);
+         else
+           _assuan_log_print_buffer (ctx->log_fp,
+                                     ctx->inbound.line,
+                                     ctx->inbound.linelen);
+         putc ('\n', ctx->log_fp);
+       }
+      return 0;
+    }
+  else
+    {
+      if (ctx->log_fp)
+       fprintf (ctx->log_fp, "%s[%u.%p] DBG: <- [Invalid line]\n",
+                assuan_get_assuan_log_prefix (),
+                 (unsigned int)getpid (), ctx);
+      *line = 0;
+      ctx->inbound.linelen = 0;
+      return ctx->inbound.eof ? ASSUAN_Line_Not_Terminated
+       : ASSUAN_Line_Too_Long;
+    }
+}
+
+
+/* Read the next line from the client or server and return a pointer
+   in *LINE to a buffer holding the line.  LINELEN is the length of
+   *LINE.  The buffer is valid until the next read operation on it.
+   The caller may modify the buffer.  The buffer is invalid (i.e. must
+   not be used) if an error is returned.
+
+   Returns 0 on success or an assuan error code.
+   See also: assuan_pending_line().
+*/
+assuan_error_t
+assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen)
+{
+  assuan_error_t err;
+
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+
+  err = _assuan_read_line (ctx);
+  *line = ctx->inbound.line;
+  *linelen = ctx->inbound.linelen;
+  return err;
+}
+
+
+/* Return true if a full line is buffered (i.e. an entire line may be
+   read without any I/O).  */
+int
+assuan_pending_line (assuan_context_t ctx)
+{
+  return ctx && ctx->inbound.attic.pending;
+}
+
+
+assuan_error_t 
+_assuan_write_line (assuan_context_t ctx, const char *prefix,
+                    const char *line, size_t len)
+{
+  int rc = 0;
+  size_t prefixlen = prefix? strlen (prefix):0;
+
+  /* Make sure that the line is short enough. */
+  if (len + prefixlen + 2 > ASSUAN_LINELENGTH)
+    {
+      if (ctx->log_fp)
+        fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> "
+                 "[supplied line too long -truncated]\n",
+                 assuan_get_assuan_log_prefix (),
+                 (unsigned int)getpid (), ctx);
+      if (prefixlen > 5)
+        prefixlen = 5;
+      if (len > ASSUAN_LINELENGTH - prefixlen - 2)
+        len = ASSUAN_LINELENGTH - prefixlen - 2 - 1;
+    }
+
+  /* Fixme: we should do some kind of line buffering.  */
+  if (ctx->log_fp)
+    {
+      fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ",
+              assuan_get_assuan_log_prefix (),
+               (unsigned int)getpid (), ctx);
+      if (ctx->confidential)
+       fputs ("[Confidential data not shown]", ctx->log_fp);
+      else
+       _assuan_log_print_buffer (ctx->log_fp, line, len);
+      putc ('\n', ctx->log_fp);
+    }
+
+  if (prefixlen)
+    {
+      rc = writen (ctx, prefix, prefixlen);
+      if (rc)
+        rc = ASSUAN_Write_Error;
+    }
+  if (!rc)
+    {
+      rc = writen (ctx, line, len);
+      if (rc)
+        rc = ASSUAN_Write_Error;
+      if (!rc)
+        {
+          rc = writen (ctx, "\n", 1);
+          if (rc)
+            rc = ASSUAN_Write_Error;
+        }
+    }
+  return rc;
+}
+
+
+assuan_error_t 
+assuan_write_line (assuan_context_t ctx, const char *line)
+{
+  size_t len;
+  const char *s;
+
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+
+  /* Make sure that we never take a LF from the user - this might
+     violate the protocol. */
+  s = strchr (line, '\n');
+  len = s? (s-line) : strlen (line);
+
+  if (ctx->log_fp && s)
+    fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> "
+             "[supplied line contained a LF -truncated]\n",
+             assuan_get_assuan_log_prefix (),
+             (unsigned int)getpid (), ctx);
+
+  return _assuan_write_line (ctx, NULL, line, len);
+}
+
+
+\f
+/* Write out the data in buffer as datalines with line wrapping and
+   percent escaping.  This function is used for GNU's custom streams */
+int
+_assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size)
+{
+  assuan_context_t ctx = cookie;
+  size_t size = orig_size;
+  char *line;
+  size_t linelen;
+
+  if (ctx->outbound.data.error)
+    return 0;
+
+  line = ctx->outbound.data.line;
+  linelen = ctx->outbound.data.linelen;
+  line += linelen;
+  while (size)
+    {
+      /* insert data line header */
+      if (!linelen)
+        {
+          *line++ = 'D';
+          *line++ = ' ';
+          linelen += 2;
+        }
+      
+      /* copy data, keep some space for the CRLF and to escape one character */
+      while (size && linelen < LINELENGTH-2-2)
+        {
+          if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
+            {
+              sprintf (line, "%%%02X", *(unsigned char*)buffer);
+              line += 3;
+              linelen += 3;
+              buffer++;
+            }
+          else
+            {
+              *line++ = *buffer++;
+              linelen++;
+            }
+          size--;
+        }
+      
+      if (linelen >= LINELENGTH-2-2)
+        {
+          if (ctx->log_fp)
+            {
+             fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ",
+                      assuan_get_assuan_log_prefix (),
+                       (unsigned int)getpid (), ctx);
+
+              if (ctx->confidential)
+                fputs ("[Confidential data not shown]", ctx->log_fp);
+              else 
+                _assuan_log_print_buffer (ctx->log_fp, 
+                                          ctx->outbound.data.line,
+                                          linelen);
+              putc ('\n', ctx->log_fp);
+            }
+          *line++ = '\n';
+          linelen++;
+          if (writen (ctx, ctx->outbound.data.line, linelen))
+            {
+              ctx->outbound.data.error = ASSUAN_Write_Error;
+              return 0;
+            }
+          line = ctx->outbound.data.line;
+          linelen = 0;
+        }
+    }
+
+  ctx->outbound.data.linelen = linelen;
+  return (int)orig_size;
+}
+
+
+/* Write out any buffered data 
+   This function is used for GNU's custom streams */
+int
+_assuan_cookie_write_flush (void *cookie)
+{
+  assuan_context_t ctx = cookie;
+  char *line;
+  size_t linelen;
+
+  if (ctx->outbound.data.error)
+    return 0;
+
+  line = ctx->outbound.data.line;
+  linelen = ctx->outbound.data.linelen;
+  line += linelen;
+  if (linelen)
+    {
+      if (ctx->log_fp)
+       {
+         fprintf (ctx->log_fp, "%s[%u.%p] DBG: -> ",
+                  assuan_get_assuan_log_prefix (),
+                   (unsigned int)getpid (), ctx);
+         if (ctx->confidential)
+           fputs ("[Confidential data not shown]", ctx->log_fp);
+         else
+           _assuan_log_print_buffer (ctx->log_fp,
+                                     ctx->outbound.data.line, linelen);
+         putc ('\n', ctx->log_fp);
+       }
+      *line++ = '\n';
+      linelen++;
+      if (writen (ctx, ctx->outbound.data.line, linelen))
+        {
+          ctx->outbound.data.error = ASSUAN_Write_Error;
+          return 0;
+        }
+      ctx->outbound.data.linelen = 0;
+    }
+  return 0;
+}
+
+
+/**
+ * assuan_send_data:
+ * @ctx: An assuan context
+ * @buffer: Data to send or NULL to flush
+ * @length: length of the data to send/
+ * 
+ * This function may be used by the server or the client to send data
+ * lines.  The data will be escaped as required by the Assuan protocol
+ * and may get buffered until a line is full.  To force sending the
+ * data out @buffer may be passed as NULL (in which case @length must
+ * also be 0); however when used by a client this flush operation does
+ * also send the terminating "END" command to terminate the reponse on
+ * a INQUIRE response.  However, when assuan_transact() is used, this
+ * function takes care of sending END itself.
+ * 
+ * Return value: 0 on success or an error code
+ **/
+\f
+assuan_error_t
+assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length)
+{
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+  if (!buffer && length)
+    return ASSUAN_Invalid_Value;
+
+  if (!buffer)
+    { /* flush what we have */
+      _assuan_cookie_write_flush (ctx);
+      if (ctx->outbound.data.error)
+        return ctx->outbound.data.error;
+      if (!ctx->is_server)
+        return assuan_write_line (ctx, "END");
+    }
+  else
+    {
+      _assuan_cookie_write_data (ctx, buffer, length);
+      if (ctx->outbound.data.error)
+        return ctx->outbound.data.error;
+    }
+
+  return 0;
+}
+
diff --git a/util/assuan-client.c b/util/assuan-client.c
new file mode 100644 (file)
index 0000000..08ea0f6
--- /dev/null
@@ -0,0 +1,280 @@
+/* assuan-client.c - client functions
+ *     Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ *     Copyright (C) 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of Assuan.
+ *
+ * Assuan is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Assuan 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 
+ */
+
+/* Please note that this is a stripped down and modified version of
+   the orginal Assuan code from libassuan. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "assuan-defs.h"
+
+#define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
+                     *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+
+
+assuan_error_t
+_assuan_read_from_server (assuan_context_t ctx, int *okay, int *off)
+{
+  char *line;
+  int linelen;
+  assuan_error_t rc;
+
+  *okay = 0;
+  *off = 0;
+  do 
+    {
+      rc = _assuan_read_line (ctx);
+      if (rc)
+        return rc;
+      line = ctx->inbound.line;
+      linelen = ctx->inbound.linelen;
+    }    
+  while (*line == '#' || !linelen);
+
+  if (linelen >= 1
+      && line[0] == 'D' && line[1] == ' ')
+    {
+      *okay = 2; /* data line */
+      *off = 2;
+    }
+  else if (linelen >= 1
+           && line[0] == 'S' 
+           && (line[1] == '\0' || line[1] == ' '))
+    {
+      *okay = 4;
+      *off = 1;
+      while (line[*off] == ' ')
+        ++*off;
+    }  
+  else if (linelen >= 2
+           && line[0] == 'O' && line[1] == 'K'
+           && (line[2] == '\0' || line[2] == ' '))
+    {
+      *okay = 1;
+      *off = 2;
+      while (line[*off] == ' ')
+        ++*off;
+    }
+  else if (linelen >= 3
+           && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
+           && (line[3] == '\0' || line[3] == ' '))
+    {
+      *okay = 0;
+      *off = 3;
+      while (line[*off] == ' ')
+        ++*off;
+    }  
+  else if (linelen >= 7
+           && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
+           && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
+           && line[6] == 'E' 
+           && (line[7] == '\0' || line[7] == ' '))
+    {
+      *okay = 3;
+      *off = 7;
+      while (line[*off] == ' ')
+        ++*off;
+    }
+  else if (linelen >= 3
+           && line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
+           && (line[3] == '\0' || line[3] == ' '))
+    {
+      *okay = 5; /* end line */
+      *off = 3;
+    }
+  else
+    rc = ASSUAN_Invalid_Response;
+  return rc;
+}
+
+
+\f
+assuan_error_t
+assuan_transact (assuan_context_t ctx,
+                 const char *command,
+                 assuan_error_t (*data_cb)(void *, const void *, size_t),
+                 void *data_cb_arg,
+                 assuan_error_t (*inquire_cb)(void*, const char *),
+                 void *inquire_cb_arg,
+                 assuan_error_t (*status_cb)(void*, const char *),
+                 void *status_cb_arg)
+{
+  return assuan_transact2 (ctx, command,
+                           data_cb, data_cb_arg,
+                           inquire_cb, inquire_cb_arg,
+                           status_cb, status_cb_arg,
+                           NULL, NULL);
+}
+
+
+/**
+ * assuan_transact2:
+ * @ctx: The Assuan context
+ * @command: Coimmand line to be send to server
+ * @data_cb: Callback function for data lines
+ * @data_cb_arg: first argument passed to @data_cb
+ * @inquire_cb: Callback function for a inquire response
+ * @inquire_cb_arg: first argument passed to @inquire_cb
+ * @status_cb: Callback function for a status response
+ * @status_cb_arg: first argument passed to @status_cb
+ * @okay_cb: Callback function for the final  OK response
+ * @okay_cb_arg: first argument passed to @okay_cb
+ * 
+ * FIXME: Write documentation
+ * 
+ * Return value: 0 on success or error code.  The error code may be
+ * the one one returned by the server in error lines or from the
+ * callback functions.
+ **/
+assuan_error_t
+assuan_transact2 (assuan_context_t ctx,
+                  const char *command,
+                  assuan_error_t (*data_cb)(void *, const void *, size_t),
+                  void *data_cb_arg,
+                  assuan_error_t (*inquire_cb)(void*, const char *),
+                  void *inquire_cb_arg,
+                  assuan_error_t (*status_cb)(void*, const char *),
+                  void *status_cb_arg,
+                  assuan_error_t (*okay_cb)(void*, const char *),
+                  void *okay_cb_arg)
+{
+  int rc, okay, off;
+  unsigned char *line;
+  int linelen;
+
+  rc = assuan_write_line (ctx, command);
+  if (rc)
+    return rc;
+
+  if (*command == '#' || !*command)
+    return 0; /* Don't expect a response for a comment line.  */
+
+ again:
+  rc = _assuan_read_from_server (ctx, &okay, &off);
+  if (rc)
+    return rc; /* error reading from server */
+
+  line = ctx->inbound.line + off;
+  linelen = ctx->inbound.linelen - off;
+
+  if (!okay)
+    {
+      rc = atoi (line);
+      if (rc < 100)
+        rc = ASSUAN_Server_Fault;
+    }
+  else if (okay == 1) /* Received OK. */
+    {
+      if (okay_cb)
+        {
+          rc = okay_cb (okay_cb_arg, line);
+          /* We better wipe out the buffer after processing it.  This
+             is no real guarantee that it won't get swapped out but at
+             least for the standard cases we can make sure that a
+             passphrase returned with the OK line is rendered
+             unreadable.  In fact the current Assuan interface suffers
+             from the problem that it is not possible to do assuan I/O
+             through secure memory.  There is no easy solution given
+             the current implementation but we need to address it
+             sooner or later.  The problem was introduced with
+             gpg-agent's GET_PASPHRASE command but it might also make
+             sense to have a way to convey sessions keys through
+             secured memory.  Note that the old implementation in gpg
+             for accessing the passphrase in fact used secure memory
+             but had the drawback of using a limited and not fully
+             conforming Assuan implementation - given that pinentry
+             and gpg-agent neither use secured memory for Assuan I/O,
+             it is negligible to drop the old implementation in gpg's
+             passphrase.c and use the wipememory workaround here.  */
+          memset (line, 0, strlen (line));
+        }
+    }
+  else if (okay == 2)
+    {
+      if (!data_cb)
+        rc = ASSUAN_No_Data_Callback;
+      else 
+        {
+          unsigned char *s, *d;
+
+          for (s=d=line; linelen; linelen--)
+            {
+              if (*s == '%' && linelen > 2)
+                { /* handle escaping */
+                  s++;
+                  *d++ = xtoi_2 (s);
+                  s += 2;
+                  linelen -= 2;
+                }
+              else
+                *d++ = *s++;
+            }
+          *d = 0; /* add a hidden string terminator */
+          rc = data_cb (data_cb_arg, line, d - line);
+          if (!rc)
+            goto again;
+        }
+    }
+  else if (okay == 3)
+    {
+      if (!inquire_cb)
+        {
+          assuan_write_line (ctx, "END"); /* get out of inquire mode */
+          _assuan_read_from_server (ctx, &okay, &off); /* dummy read */
+          rc = ASSUAN_No_Inquire_Callback;
+        }
+      else
+        {
+          rc = inquire_cb (inquire_cb_arg, line);
+          if (!rc)
+            rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
+          if (!rc)
+            goto again;
+        }
+    }
+  else if (okay == 4)
+    {
+      if (status_cb)
+        rc = status_cb (status_cb_arg, line);
+      if (!rc)
+        goto again;
+    }
+  else if (okay == 5)
+    {
+      if (!data_cb)
+        rc = ASSUAN_No_Data_Callback;
+      else 
+        {
+          rc = data_cb (data_cb_arg, NULL, 0);
+          if (!rc)
+            goto again;
+        }
+    }
+
+  return rc;
+}
+
diff --git a/util/assuan-connect.c b/util/assuan-connect.c
new file mode 100644 (file)
index 0000000..52c9aa0
--- /dev/null
@@ -0,0 +1,95 @@
+/* assuan-connect.c - Establish a connection (client) 
+ *     Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of Assuan.
+ *
+ * Assuan is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Assuan 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 
+ */
+
+/* Please note that this is a stripped down and modified version of
+   the orginal Assuan code from libassuan. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#ifndef HAVE_W32_SYSTEM
+#include <sys/wait.h>
+#endif
+
+#include "assuan-defs.h"
+
+/* Create a new context.  */
+int
+_assuan_new_context (assuan_context_t *r_ctx)
+{
+  assuan_context_t ctx;
+
+  *r_ctx = NULL;
+  ctx = xcalloc (1, sizeof *ctx);
+
+  ctx->input_fd = -1;
+  ctx->output_fd = -1;
+
+  ctx->inbound.fd = -1;
+  ctx->outbound.fd = -1;
+  ctx->io = NULL;
+
+  ctx->listen_fd = -1;
+  *r_ctx = ctx;
+  return 0;
+}
+
+
+void
+_assuan_release_context (assuan_context_t ctx)
+{
+  if (ctx)
+    {
+      xfree (ctx->hello_line);
+      xfree (ctx->okay_line);
+      xfree (ctx);
+    }
+}
+
+
+/* Disconnect and release the context CTX. */
+void
+assuan_disconnect (assuan_context_t ctx)
+{
+  if (ctx)
+    {
+      assuan_write_line (ctx, "BYE");
+      ctx->finish_handler (ctx);
+      ctx->deinit_handler (ctx);
+      ctx->deinit_handler = NULL;
+      _assuan_release_context (ctx);
+    }
+}
+
+/* Return the PID of the peer or -1 if not known. */
+pid_t
+assuan_get_pid (assuan_context_t ctx)
+{
+  return (ctx && ctx->pid)? ctx->pid : -1;
+}
+
diff --git a/util/assuan-defs.h b/util/assuan-defs.h
new file mode 100644 (file)
index 0000000..06400d8
--- /dev/null
@@ -0,0 +1,243 @@
+/* assuan-defs.c - Internal definitions to Assuan
+ *     Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
+ *     Copyright (C) 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of Assuan.
+ *
+ * Assuan is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Assuan 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 
+ */
+
+/* Please note that this is a stripped down and modified version of
+   the orginal Assuan code from libassuan. */
+
+
+#ifndef ASSUAN_DEFS_H
+#define ASSUAN_DEFS_H
+
+#include <sys/types.h>
+#ifndef HAVE_W32_SYSTEM
+#include <sys/socket.h>
+#include <sys/un.h>
+#else
+#include <windows.h>
+#endif
+#include <unistd.h>
+
+#include "assuan.h"
+#include "memory.h"
+
+#ifndef HAVE_W32_SYSTEM
+#define DIRSEP_C '/'
+#else
+#define DIRSEP_C '\\'
+#endif
+
+#ifdef HAVE_W32_SYSTEM
+#define AF_LOCAL AF_UNIX
+/* We need to prefix the structure with a sockaddr_in header so we can
+   use it later for sendto and recvfrom. */
+struct sockaddr_un
+{
+  short          sun_family;
+  unsigned short sun_port;
+  struct         in_addr sun_addr;
+  char           sun_path[108-2-4]; /* Path name.  */
+};
+
+/* Not needed anymore because the current mingw32 defines this in
+   sys/types.h */
+/* typedef int ssize_t; */
+
+/* Missing W32 functions */
+int putc_unlocked (int c, FILE *stream);
+void * memrchr (const void *block, int c, size_t size);
+char * stpcpy (char *dest, const char *src);
+#endif
+
+#define LINELENGTH ASSUAN_LINELENGTH
+
+struct cmdtbl_s
+{
+  const char *name;
+  int (*handler)(assuan_context_t, char *line);
+};
+
+struct assuan_io
+{
+  /* Routine to read from input_fd.  */
+  ssize_t (*readfnc) (assuan_context_t, void *, size_t);
+  /* Routine to write to output_fd.  */
+  ssize_t (*writefnc) (assuan_context_t, const void *, size_t);
+  /* Send a file descriptor.  */
+  assuan_error_t (*sendfd) (assuan_context_t, int);
+  /* Receive a file descriptor.  */
+  assuan_error_t (*receivefd) (assuan_context_t, int *);
+};  
+
+struct assuan_context_s
+{
+  assuan_error_t err_no;
+  const char *err_str;
+  int os_errno;  /* last system error number used with certain error codes*/
+
+  int confidential;
+  int is_server;  /* set if this is context belongs to a server */
+  int in_inquire;
+  char *hello_line;
+  char *okay_line; /* see assan_set_okay_line() */
+  
+  void *user_pointer;  /* for assuan_[gs]et_pointer () */
+
+  FILE *log_fp;
+
+  struct {
+    int fd;
+    int eof;
+    char line[LINELENGTH];
+    int linelen;  /* w/o CR, LF - might not be the same as
+                     strlen(line) due to embedded nuls. However a nul
+                     is always written at this pos */
+    struct {
+      char line[LINELENGTH];
+      int linelen ;
+      int pending; /* i.e. at least one line is available in the attic */
+    } attic;
+  } inbound;
+
+  struct {
+    int fd;
+    struct {
+      FILE *fp;
+      char line[LINELENGTH];
+      int linelen; 
+      int error;
+    } data; 
+  } outbound;
+
+  int pipe_mode;  /* We are in pipe mode, i.e. we can handle just one
+                     connection and must terminate then */
+  pid_t pid;     /* The the pid of the peer. */
+  int listen_fd;  /* The fd we are listening on (used by socket servers) */
+  int connected_fd; /* helper */
+
+  /* Used for Unix domain sockets.  */
+  struct sockaddr_un myaddr;
+  struct sockaddr_un serveraddr;
+  /* When reading from datagram sockets, we must read an entire
+     message at a time.  This means that we have to do our own
+     buffering to be able to get the semantics of read.  */
+  void *domainbuffer;
+  /* Offset of start of buffer.  */
+  int domainbufferoffset;
+  /* Bytes buffered.  */
+  int domainbuffersize;
+  /* Memory allocated.  */
+  int domainbufferallocated;
+
+  int *pendingfds;
+  int pendingfdscount;
+
+  void (*deinit_handler)(assuan_context_t);  
+  int (*accept_handler)(assuan_context_t);
+  int (*finish_handler)(assuan_context_t);
+
+  struct cmdtbl_s *cmdtbl;
+  size_t cmdtbl_used; /* used entries */
+  size_t cmdtbl_size; /* allocated size of table */
+
+  void (*bye_notify_fnc)(assuan_context_t);
+  void (*reset_notify_fnc)(assuan_context_t);
+  void (*cancel_notify_fnc)(assuan_context_t);
+  int  (*option_handler_fnc)(assuan_context_t,const char*, const char*);
+  void (*input_notify_fnc)(assuan_context_t, const char *);
+  void (*output_notify_fnc)(assuan_context_t, const char *);
+
+  int input_fd;   /* set by INPUT command */
+  int output_fd;  /* set by OUTPUT command */
+
+  /* io routines.  */
+  struct assuan_io *io;
+};
+
+/*-- assuan-pipe-server.c --*/
+int _assuan_new_context (assuan_context_t *r_ctx);
+void _assuan_release_context (assuan_context_t ctx);
+
+/*-- assuan-domain-connect.c --*/
+/* Make a connection to the Unix domain socket NAME and return a new
+   Assuan context in CTX.  SERVER_PID is currently not used but may
+   become handy in the future.  */
+assuan_error_t _assuan_domain_init (assuan_context_t *r_ctx,
+                                int rendezvousfd,
+                                pid_t peer);
+
+/*-- assuan-handler.c --*/
+int _assuan_register_std_commands (assuan_context_t ctx);
+
+/*-- assuan-buffer.c --*/
+int _assuan_read_line (assuan_context_t ctx);
+int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size);
+int _assuan_cookie_write_flush (void *cookie);
+assuan_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix,
+                                   const char *line, size_t len);
+
+/*-- assuan-client.c --*/
+assuan_error_t _assuan_read_from_server (assuan_context_t ctx, int *okay, int *off);
+
+
+/*-- assuan-util.c --*/
+
+#define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t))
+
+void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t  length);
+void _assuan_log_sanitized_string (const char *string);
+
+#ifdef HAVE_W32_SYSTEM
+const char *_assuan_w32_strerror (int ec);
+#define w32_strerror(e) _assuan_w32_strerror ((e))
+#endif /*HAVE_W32_SYSTEM*/
+
+
+/*-- assuan-logging.c --*/
+void _assuan_set_default_log_stream (FILE *fp);
+
+void _assuan_log_printf (const char *format, ...)
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
+ __attribute__ ((format (printf,1,2)))
+#endif
+     ;
+
+/*-- assuan-io.c --*/
+ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size);
+ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer,
+                             size_t size);
+
+/*-- assuan-socket.c --*/
+int _assuan_close (int fd);
+int _assuan_sock_new (int domain, int type, int proto);
+int _assuan_sock_connect (int sockfd, struct sockaddr *addr, int addrlen);
+
+#ifdef HAVE_FOPENCOOKIE
+/* We have to implement funopen in terms of glibc's fopencookie. */
+FILE *_assuan_funopen(void *cookie,
+                      cookie_read_function_t *readfn,
+                      cookie_write_function_t *writefn,
+                      cookie_seek_function_t *seekfn,
+                      cookie_close_function_t *closefn);
+#define funopen(a,r,w,s,c) _assuan_funopen ((a), (r), (w), (s), (c))
+#endif /*HAVE_FOPENCOOKIE*/
+
+#endif /*ASSUAN_DEFS_H*/
+
diff --git a/util/assuan-errors.c b/util/assuan-errors.c
new file mode 100644 (file)
index 0000000..01f718c
--- /dev/null
@@ -0,0 +1,104 @@
+/* assuan-errors.c - error codes
+ *     Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+ *     Copyright (C) 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of Assuan.
+ *
+ * Assuan is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Assuan 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 
+ */
+
+/* Please note that this is a stripped down and modified version of
+   the orginal Assuan code from libassuan. */ 
+
+#include <stdio.h>
+#include "assuan.h"
+
+/* This function returns a textual representaion of the given error
+   code.  If this is an unknown value, a string with the value is
+   returned (Beware: it is hold in a static buffer).  Return value:
+   String with the error description.
+ */
+const char *
+assuan_strerror (assuan_error_t err)
+{
+  const char *s;
+  static char buf[50];
+
+  switch (err)
+    {
+    case ASSUAN_No_Error: s="no error"; break;
+    case ASSUAN_General_Error: s="general error"; break;
+    case ASSUAN_Out_Of_Core: s="out of core"; break;
+    case ASSUAN_Invalid_Value: s="invalid value"; break;
+    case ASSUAN_Timeout: s="timeout"; break;
+    case ASSUAN_Read_Error: s="read error"; break;
+    case ASSUAN_Write_Error: s="write error"; break;
+    case ASSUAN_Problem_Starting_Server: s="problem starting server"; break;
+    case ASSUAN_Not_A_Server: s="not a server"; break;
+    case ASSUAN_Not_A_Client: s="not a client"; break;
+    case ASSUAN_Nested_Commands: s="nested commands"; break;
+    case ASSUAN_Invalid_Response: s="invalid response"; break;
+    case ASSUAN_No_Data_Callback: s="no data callback"; break;
+    case ASSUAN_No_Inquire_Callback: s="no inquire callback"; break;
+    case ASSUAN_Connect_Failed: s="connect failed"; break;
+    case ASSUAN_Accept_Failed: s="accept failed"; break;
+    case ASSUAN_Not_Implemented: s="not implemented"; break;
+    case ASSUAN_Server_Fault: s="server fault"; break;
+    case ASSUAN_Invalid_Command: s="invalid command"; break;
+    case ASSUAN_Unknown_Command: s="unknown command"; break;
+    case ASSUAN_Syntax_Error: s="syntax error"; break;
+    case ASSUAN_Parameter_Error: s="parameter error"; break;
+    case ASSUAN_Parameter_Conflict: s="parameter conflict"; break;
+    case ASSUAN_Line_Too_Long: s="line too long"; break;
+    case ASSUAN_Line_Not_Terminated: s="line not terminated"; break;
+    case ASSUAN_No_Input: s="no input"; break;
+    case ASSUAN_No_Output: s="no output"; break;
+    case ASSUAN_Canceled: s="canceled"; break;
+    case ASSUAN_Unsupported_Algorithm: s="unsupported algorithm"; break;
+    case ASSUAN_Server_Resource_Problem: s="server resource problem"; break;
+    case ASSUAN_Server_IO_Error: s="server io error"; break;
+    case ASSUAN_Server_Bug: s="server bug"; break;
+    case ASSUAN_No_Data_Available: s="no data available"; break;
+    case ASSUAN_Invalid_Data: s="invalid data"; break;
+    case ASSUAN_Unexpected_Command: s="unexpected command"; break;
+    case ASSUAN_Too_Much_Data: s="too much data"; break;
+    case ASSUAN_Inquire_Unknown: s="inquire unknown"; break;
+    case ASSUAN_Inquire_Error: s="inquire error"; break;
+    case ASSUAN_Invalid_Option: s="invalid option"; break;
+    case ASSUAN_Invalid_Index: s="invalid index"; break;
+    case ASSUAN_Unexpected_Status: s="unexpected status"; break;
+    case ASSUAN_Unexpected_Data: s="unexpected data"; break;
+    case ASSUAN_Invalid_Status: s="invalid status"; break;
+    case ASSUAN_Locale_Problem: s="locale problem"; break;
+    case ASSUAN_Not_Confirmed: s="not confirmed"; break;
+    case ASSUAN_USER_ERROR_FIRST: s="user error first"; break;
+    case ASSUAN_USER_ERROR_LAST: s="user error last"; break;
+    default: 
+      {
+        unsigned int source, code;
+
+        source = ((err >> 24) & 0xff);
+        code = (err & 0x00ffffff);
+        if (source) /* Assume this is an libgpg-error. */
+          sprintf (buf, "ec=%u.%u", source, code ); 
+        else
+          sprintf (buf, "ec=%d", err ); 
+        s=buf; break;
+      }
+    }
+
+  return s;
+}
+
diff --git a/util/assuan-logging.c b/util/assuan-logging.c
new file mode 100644 (file)
index 0000000..6663e81
--- /dev/null
@@ -0,0 +1,115 @@
+/* assuan-logging.c - Default logging function.
+ *     Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of Assuan.
+ *
+ * Assuan is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Assuan 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 
+ */
+
+/* Please note that this is a stripped down and modified version of
+   the orginal Assuan code from libassuan. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#ifdef HAVE_W32_SYSTEM
+#include <windows.h>
+#endif /*HAVE_W32_SYSTEM*/
+
+#include "assuan-defs.h"
+
+static char prefix_buffer[80];
+static FILE *_assuan_log;
+
+void
+_assuan_set_default_log_stream (FILE *fp)
+{
+  if (!_assuan_log)
+    _assuan_log = fp;
+}
+
+void
+assuan_set_assuan_log_stream (FILE *fp)
+{
+  _assuan_log = fp;
+}
+
+FILE *
+assuan_get_assuan_log_stream (void)
+{
+  return _assuan_log ? _assuan_log : stderr;
+}
+
+
+/* Set the prefix to be used for logging to TEXT or
+   resets it to the default if TEXT is NULL. */
+void
+assuan_set_assuan_log_prefix (const char *text)
+{
+  if (text)
+    {
+      strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
+      prefix_buffer[sizeof (prefix_buffer)-1] = 0;
+    }
+  else
+    *prefix_buffer = 0;
+}
+
+const char *
+assuan_get_assuan_log_prefix (void)
+{
+  return prefix_buffer;
+}
+
+
+void
+_assuan_log_printf (const char *format, ...)
+{
+  va_list arg_ptr;
+  FILE *fp;
+  const char *prf;
+
+  fp = assuan_get_assuan_log_stream ();
+  prf = assuan_get_assuan_log_prefix ();
+  if (*prf)
+    {
+      fputs (prf, fp);
+      fputs (": ", fp);
+    }
+
+  va_start (arg_ptr, format);
+  vfprintf (fp, format, arg_ptr );
+  va_end (arg_ptr);
+}
+
+
+
+#ifdef HAVE_W32_SYSTEM
+const char *
+_assuan_w32_strerror (int ec)
+{
+  static char strerr[256];
+  
+  if (ec == -1)
+    ec = (int)GetLastError ();
+  FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
+                 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+                 strerr, sizeof (strerr)-1, NULL);
+  return strerr;    
+}
+#endif /*HAVE_W32_SYSTEM*/
diff --git a/util/assuan-socket-connect.c b/util/assuan-socket-connect.c
new file mode 100644 (file)
index 0000000..0038591
--- /dev/null
@@ -0,0 +1,190 @@
+/* assuan-socket-connect.c - Assuan socket based client
+ *     Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of Assuan.
+ *
+ * Assuan is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Assuan 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 
+ */
+
+/* Please note that this is a stripped down and modified version of
+   the orginal Assuan code from libassuan. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#ifndef HAVE_W32_SYSTEM
+#include <sys/socket.h>
+#include <sys/un.h>
+#else
+#include <windows.h>
+#endif
+
+#include "assuan-defs.h"
+
+/* Hacks for Slowaris.  */
+#ifndef PF_LOCAL
+# ifdef PF_UNIX
+#  define PF_LOCAL PF_UNIX
+# else
+#  define PF_LOCAL AF_UNIX
+# endif
+#endif
+#ifndef AF_LOCAL
+# define AF_LOCAL AF_UNIX
+#endif
+
+#ifndef SUN_LEN
+# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+                      + strlen ((ptr)->sun_path))
+#endif
+
+static int
+do_finish (assuan_context_t ctx)
+{
+  if (ctx->inbound.fd != -1)
+    {
+      _assuan_close (ctx->inbound.fd);
+    }
+  ctx->inbound.fd = -1;
+  ctx->outbound.fd = -1;
+  return 0;
+}
+
+static void
+do_deinit (assuan_context_t ctx)
+{
+  do_finish (ctx);
+}
+
+
+static ssize_t
+simple_read (assuan_context_t ctx, void *buffer, size_t size)
+{
+#ifndef HAVE_W32_SYSTEM
+  return read (ctx->inbound.fd, buffer, size);
+#else
+  return recv (ctx->inbound.fd, buffer, size, 0);
+#endif
+}
+
+static ssize_t
+simple_write (assuan_context_t ctx, const void *buffer, size_t size)
+{
+#ifndef HAVE_W32_SYSTEM
+  return write (ctx->outbound.fd, buffer, size);
+#else
+  return send (ctx->outbound.fd, buffer, size, 0);
+#endif
+}
+
+
+/* Make a connection to the Unix domain socket NAME and return a new
+   Assuan context in CTX.  SERVER_PID is currently not used but may
+   become handy in the future.  */
+assuan_error_t
+assuan_socket_connect (assuan_context_t *r_ctx,
+                       const char *name, pid_t server_pid)
+{
+  static struct assuan_io io = { simple_read, simple_write };
+
+  assuan_error_t err;
+  assuan_context_t ctx;
+  int fd;
+  struct sockaddr_un srvr_addr;
+  size_t len;
+  const char *s;
+
+  if (!r_ctx || !name)
+    return ASSUAN_Invalid_Value;
+  *r_ctx = NULL;
+
+  /* We require that the name starts with a slash, so that we can
+     alter reuse this function for other socket types.  To make things
+     easier we allow an optional dirver prefix.  */
+  s = name;
+  if (*s && s[1] == ':')
+    s += 2;
+  if (*s != DIRSEP_C && *s != '/')
+    return ASSUAN_Invalid_Value;
+
+  if (strlen (name)+1 >= sizeof srvr_addr.sun_path)
+    return ASSUAN_Invalid_Value;
+
+  err = _assuan_new_context (&ctx); 
+  if (err)
+      return err;
+  ctx->deinit_handler = do_deinit;
+  ctx->finish_handler = do_finish;
+
+
+  fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0);
+  if (fd == -1)
+    {
+      _assuan_log_printf ("can't create socket: %s\n", strerror (errno));
+      _assuan_release_context (ctx);
+      return ASSUAN_General_Error;
+    }
+
+  memset (&srvr_addr, 0, sizeof srvr_addr);
+  srvr_addr.sun_family = AF_LOCAL;
+  strncpy (srvr_addr.sun_path, name, sizeof (srvr_addr.sun_path) - 1);
+  srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0;
+  len = SUN_LEN (&srvr_addr);
+
+
+  if (_assuan_sock_connect (fd, (struct sockaddr *) &srvr_addr, len) == -1)
+    {
+      _assuan_log_printf ("can't connect to `%s': %s\n",
+                          name, strerror (errno));
+      _assuan_release_context (ctx);
+      _assuan_close (fd);
+      return ASSUAN_Connect_Failed;
+    }
+
+  ctx->inbound.fd = fd;
+  ctx->outbound.fd = fd;
+  ctx->io = &io;
+
+  /* initial handshake */
+  {
+    int okay, off;
+
+    err = _assuan_read_from_server (ctx, &okay, &off);
+    if (err)
+      _assuan_log_printf ("can't connect to server: %s\n",
+                          assuan_strerror (err));
+    else if (okay != 1)
+      {
+        /*LOG ("can't connect to server: `");*/
+       _assuan_log_sanitized_string (ctx->inbound.line);
+       fprintf (assuan_get_assuan_log_stream (), "'\n");
+       err = ASSUAN_Connect_Failed;
+      }
+  }
+
+  if (err)
+    {
+      assuan_disconnect (ctx); 
+    }
+  else
+    *r_ctx = ctx;
+  return 0;
+}
diff --git a/util/assuan-socket.c b/util/assuan-socket.c
new file mode 100644 (file)
index 0000000..080eff2
--- /dev/null
@@ -0,0 +1,96 @@
+/* assuan-socket.c
+ * Copyright (C) 2004 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/* Please note that this is a stripped down and modified version of
+   the orginal Assuan code from libassuan. */
+
+#include <config.h>
+#include <stdio.h>
+#ifdef HAVE_W32_SYSTEM
+#include <windows.h>
+#include <io.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+#include "assuan-defs.h"
+
+int
+_assuan_close (int fd)
+{
+#ifndef HAVE_W32_SYSTEM
+  return close (fd);
+#else
+  int rc = closesocket (fd);
+  if (rc && WSAGetLastError () == WSAENOTSOCK)
+      rc = close (fd);
+  return rc;
+#endif
+}
+
+
+int
+_assuan_sock_new (int domain, int type, int proto)
+{
+#ifndef HAVE_W32_SYSTEM
+  return socket (domain, type, proto);
+#else
+  if (domain == AF_UNIX || domain == AF_LOCAL)
+    domain = AF_INET;
+  return socket (domain, type, proto);
+#endif
+}
+
+
+int
+_assuan_sock_connect (int sockfd, struct sockaddr * addr, int addrlen)
+{
+#ifndef HAVE_W32_SYSTEM
+  return connect (sockfd, addr, addrlen);
+#else
+  struct sockaddr_in myaddr;
+  struct sockaddr_un * unaddr;
+  FILE * fp;
+  int port = 0;
+  
+  unaddr = (struct sockaddr_un *)addr;
+  fp = fopen (unaddr->sun_path, "rb");
+  if (!fp)
+      return -1;
+  fscanf (fp, "%d", &port);
+  fclose (fp);
+  /* XXX: set errno in this case */
+  if (port < 0 || port > 65535)
+      return -1;
+  
+  myaddr.sin_family = AF_INET;
+  myaddr.sin_port = port; 
+  myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+  /* we need this later. */
+  unaddr->sun_family = myaddr.sin_family;
+  unaddr->sun_port = myaddr.sin_port;
+  unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr;
+  
+  return connect (sockfd, (struct sockaddr *)&myaddr, sizeof myaddr);
+#endif
+}
+
+
diff --git a/util/assuan-util.c b/util/assuan-util.c
new file mode 100644 (file)
index 0000000..a5ee0b2
--- /dev/null
@@ -0,0 +1,170 @@
+/* assuan-util.c - Utility functions for Assuan 
+ * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of Assuan.
+ *
+ * Assuan is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Assuan 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 
+ */
+
+/* Please note that this is a stripped down and modified version of
+   the orginal Assuan code from libassuan. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "assuan-defs.h"
+
+
+\f
+/* Store the error in the context so that the error sending function
+  can take out a descriptive text.  Inside the assuan code, use the
+  macro set_error instead of this function. */
+int
+assuan_set_error (assuan_context_t ctx, int err, const char *text)
+{
+  ctx->err_no = err;
+  ctx->err_str = text;
+  return err;
+}
+
+void
+assuan_set_pointer (assuan_context_t ctx, void *pointer)
+{
+  if (ctx)
+    ctx->user_pointer = pointer;
+}
+
+void *
+assuan_get_pointer (assuan_context_t ctx)
+{
+  return ctx? ctx->user_pointer : NULL;
+}
+
+
+void
+assuan_set_log_stream (assuan_context_t ctx, FILE *fp)
+{
+  if (ctx)
+    {
+      if (ctx->log_fp)
+        fflush (ctx->log_fp);
+      ctx->log_fp = fp;
+      _assuan_set_default_log_stream (fp);
+    }
+}
+
+
+void
+assuan_begin_confidential (assuan_context_t ctx)
+{
+  if (ctx)
+    {
+      ctx->confidential = 1;
+    }
+}
+
+void
+assuan_end_confidential (assuan_context_t ctx)
+{
+  if (ctx)
+    {
+      ctx->confidential = 0;
+    }
+}
+
+/* Dump a possibly binary string (used for debugging).  Distinguish
+   ascii text from binary and print it accordingly.  */
+void
+_assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length)
+{
+  const unsigned char *s;
+  int n;
+
+  for (n=length,s=buffer; n; n--, s++)
+    if  ((!isascii (*s) || iscntrl (*s) || !isprint (*s)) && !(*s >= 0x80))
+      break;
+
+  s = buffer;
+  if (!n && *s != '[')
+    fwrite (buffer, length, 1, fp);
+  else
+    {
+      putc ('[', fp);
+      for (n=0; n < length; n++, s++)
+          fprintf (fp, " %02x", *s);
+      putc (' ', fp);
+      putc (']', fp);
+    }
+}
+
+/* Log a user supplied string.  Escapes non-printable before
+   printing.  */
+void
+_assuan_log_sanitized_string (const char *string)
+{
+  const unsigned char *s = string;
+  FILE *fp = assuan_get_assuan_log_stream ();
+
+  if (! *s)
+    return;
+
+  for (; *s; s++)
+    {
+      int c = 0;
+
+      switch (*s)
+       {
+       case '\r':
+         c = 'r';
+         break;
+
+       case '\n':
+         c = 'n';
+         break;
+
+       case '\f':
+         c = 'f';
+         break;
+
+       case '\v':
+         c = 'v';
+         break;
+
+       case '\b':
+         c = 'b';
+         break;
+
+       default:
+         if ((isascii (*s) && isprint (*s)) || (*s >= 0x80))
+           putc (*s, fp);
+         else
+           {
+             putc ('\\', fp);
+             fprintf (fp, "x%02x", *s);
+           }
+       }
+
+      if (c)
+       {
+         putc ('\\', fp);
+         putc (c, fp);
+       }
+    }
+}
+
diff --git a/util/isascii.c b/util/isascii.c
new file mode 100644 (file)
index 0000000..565c716
--- /dev/null
@@ -0,0 +1,29 @@
+/* isascii.c - Replacement for isascii.
+ * Copyright (C) 2002 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+int
+isascii (int c)
+{
+  return (((c) & ~0x7f) == 0);
+}
index c062bdd..f84e507 100644 (file)
@@ -1,5 +1,5 @@
 /* memory.c  - memory allocation
- *     Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -603,29 +603,6 @@ m_size( const void *a )
 }
 
 
-#if 0 /* not used */
-/****************
- * Make a copy of the memory block at a
- */
-void *
-FNAME(copy)( const void *a FNAMEPRT )
-{
-    void *b;
-    size_t n;
-
-    if( !a )
-       return NULL;
-
-    n = m_size(a); Aiiiih woher nehmen
-    if( m_is_secure(a) )
-       b = FNAME(alloc_secure)(n FNAMEARG);
-    else
-       b = FNAME(alloc)(n FNAMEARG);
-    memcpy(b, a, n );
-    return b;
-}
-#endif
-
 char *
 FNAME(strdup)( const char *a FNAMEPRT )
 {
@@ -634,3 +611,31 @@ FNAME(strdup)( const char *a FNAMEPRT )
     strcpy(p, a);
     return p;
 }
+
+
+/* Wrapper around m_alloc_clear to take the usual 2 arguments of a
+   calloc style function. */
+void *
+xcalloc (size_t n, size_t m)
+{
+  size_t nbytes;
+
+  nbytes = n * m; 
+  if (m && nbytes / m != n) 
+    out_of_core (nbytes, 0);
+  return m_alloc_clear (nbytes);
+}
+
+/* Wrapper around m_alloc_csecure_lear to take the usual 2 arguments
+   of a calloc style function. */
+void *
+xcalloc_secure (size_t n, size_t m)
+{
+  size_t nbytes;
+
+  nbytes = n * m; 
+  if (m && nbytes / m != n) 
+    out_of_core (nbytes, 1);
+  return m_alloc_secure_clear (nbytes);
+}
+