[git] Assuan - branch, master, updated. libassuan-2.1.2-5-g1f99031

by Werner Koch cvs at cvs.gnupg.org
Fri Nov 28 16:40:49 CET 2014


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "IPC library used by GnuPG".

The branch, master has been updated
       via  1f99031cb55e88840d98dd71381b2bc2618406fc (commit)
      from  2f040c0b7bcfdddf5e3597fbcdae9cc04fafe653 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 1f99031cb55e88840d98dd71381b2bc2618406fc
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Nov 28 16:41:16 2014 +0100

    Implement socket file redirection.
    
    * configure.ac (AC_CHECK_FUNC): Check for stat.
    * src/assuan-socket.c (SUN_LEN): Add.
    (eval_redirection): New.
    (_assuan_sock_connect) [!W32]: Implement socket file redirection.
    (_assuan_sock_set_sockaddr_un): New.
    (assuan_sock_set_sockaddr_un): New.
    --
    
    This feature is useful to allow sockets with standard names even on
    file system which do not supports socket and to help with shared home
    directories.  For example to use GnuPG 2.1 with shared home
    directories one will be abale to do:
    
     rm ~/.gnupg/S.gpg-agent || true
     printf "%%Assuan%%\nsocket=${HOME}/.gnupg/S.gpg-agent_${HOSTNAME}\n" \
           > ~/.gnupg/S.gpg-agent
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index 326196d..a2611db 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,11 @@
 Noteworthy changes in version 2.1.4 (unreleased) [C4/A4/R_]
 ------------------------------------------------
 
+ * Interface changes relative to the 2.1.3 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ assuan_sock_set_sockaddr_un  NEW.
+
+
 Noteworthy changes in version 2.1.3 (2014-11-07) [C4/A4/R3]
 ------------------------------------------------
 
diff --git a/configure.ac b/configure.ac
index d03fd58..2f09e98 100644
--- a/configure.ac
+++ b/configure.ac
@@ -346,7 +346,7 @@ AM_PATH_GPG_ERROR(1.8,, AC_MSG_ERROR([libgpg-error was not found]))
 #
 # Checks for library functions.
 #
-AC_CHECK_FUNCS([flockfile funlockfile inet_pton])
+AC_CHECK_FUNCS([flockfile funlockfile inet_pton stat])
 
 # On some systems (e.g. Solaris) nanosleep requires linking to librl.
 # Given that we use nanosleep only as an optimization over a select
diff --git a/doc/assuan.texi b/doc/assuan.texi
index ddac37a..b932be0 100644
--- a/doc/assuan.texi
+++ b/doc/assuan.texi
@@ -1935,7 +1935,10 @@ Wrapper around socket.
 
 Wrapper around connect.  For Unix domain sockets under Windows this
 function also does a write immediately after the the connect to send the
-nonce as read from the socket's file.
+nonce as read from the socket's file.  Under Unix this function check
+whether the socket file is a redirection file and connects to the
+redirected socket instead; see @code{assuan_sock_set_sockaddr_un} for
+details on the redirection file format.
 @end deftypefun
 
 
@@ -1948,6 +1951,38 @@ Wrapper around bind.  Under Windows this creates a file and writes the
 port number and a random nonce to this file.
 @end deftypefun
 
+ at deftypefun int assuan_sock_set_sockaddr_un ( @
+        @w{const char *@var{fname}}, @
+        @w{struct sockaddr *@var{addr}}, @
+        @w{int *@var{r_redirected}})
+
+This is a helper function to initialize the Unix socket domain address
+structure @var{addr} and store the file name @var{fname} there.  If
+ at var{r_redirected} is not NULL the function checks whether @var{fname}
+already exists, is a regular file, and not a socket.  In that case
+ at var{fname} is read to see whether this is a redirection to a socket
+file.  If that is the case 1 is stored at @var{r_redirected}.  If the
+file does not look like a redirection file 0 will be stored there and
+ at var{fname} will be used in the regular way.
+
+The format of a redirection file is
+
+ at example
+%Assuan%
+socket=@var{name}
+ at end example
+
+With @var{name} being is the actual socket to use.  No white spaces
+are allowed, both lines must be terminated by a single linefeed, and
+extra lines are not allowed.  Environment variables are interpreted in
+ at var{name} if given in @code{$@{VAR@}} notation.  No escape characters
+are defined; if the string @code{$@{} shall be used in file name, an
+environment variable with that content may be used.  The length of the
+redirection file is limited to 511 bytes which is more than sufficient
+for any known implementation of Unix domain sockets.
+ at end deftypefun
+
+
 @deftypefun int assuan_sock_get_nonce ( @
         @w{struct sockaddr *@var{addr}}, @
         @w{int @var{addrlen}}, @
diff --git a/src/assuan-defs.h b/src/assuan-defs.h
index 364510f..3dec3df 100644
--- a/src/assuan-defs.h
+++ b/src/assuan-defs.h
@@ -346,6 +346,8 @@ int _assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
                           struct sockaddr *addr, int addrlen);
 int _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
 		       struct sockaddr *addr, int addrlen);
+int _assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
+                                  int *r_redirected);
 int _assuan_sock_get_nonce (assuan_context_t ctx, struct sockaddr *addr,
 			    int addrlen, assuan_sock_nonce_t *nonce);
 int _assuan_sock_check_nonce (assuan_context_t ctx, assuan_fd_t fd,
diff --git a/src/assuan-socket.c b/src/assuan-socket.c
index 7eba6b4..c8af51b 100644
--- a/src/assuan-socket.c
+++ b/src/assuan-socket.c
@@ -69,6 +69,15 @@
 #endif
 #endif
 
+#ifndef ENAMETOOLONG
+# define ENAMETOOLONG EINVAL
+#endif
+
+#ifndef SUN_LEN
+# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+	               + strlen ((ptr)->sun_path))
+#endif
+
 
 #ifdef HAVE_W32_SYSTEM
 
@@ -88,7 +97,7 @@ utf8_to_wchar (const char *string)
     return NULL;
 
   nbytes = (size_t)(n+1) * sizeof(*result);
-  if (nbytes / sizeof(*result) != (n+1)) 
+  if (nbytes / sizeof(*result) != (n+1))
     {
       SetLastError (ERROR_INVALID_PARAMETER);
       return NULL;
@@ -173,15 +182,15 @@ _assuan_sock_wsa2errno (int err)
 /* W32: Fill BUFFER with LENGTH bytes of random.  Returns -1 on
    failure, 0 on success.  Sets errno on failure.  */
 static int
-get_nonce (char *buffer, size_t nbytes) 
+get_nonce (char *buffer, size_t nbytes)
 {
   HCRYPTPROV prov;
   int ret = -1;
 
-  if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL, 
+  if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL,
                             (CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) )
     gpg_err_set_errno (ENODEV);
-  else 
+  else
     {
       if (!CryptGenRandom (prov, nbytes, (unsigned char *) buffer))
         gpg_err_set_errno (ENODEV);
@@ -235,9 +244,114 @@ read_port_and_nonce (const char *fname, unsigned short *port, char *nonce)
 #endif /*HAVE_W32_SYSTEM*/
 
 
+#ifndef HAVE_W32_SYSTEM
+/* Find a redirected socket name for fname and return a malloced setup
+   filled sockaddr.  If this does not work out NULL is returned and
+   ERRNO is set.  If the file seems to be a redirect True is stored at
+   R_REDIRECT.  Note that this function uses the standard malloc and
+   not the assuan wrapped one.  The format of the file is:
+
+   %Assuan%
+   socket=NAME
+
+   where NAME is the actual socket to use.  No white spaces are
+   allowed, both lines must be terminated by a single LF, extra lines
+   are not allowed.  Environment variables are interpreted in NAME if
+   given in "${VAR} notation; no escape characters are defined, if
+   "${" shall be used verbatim, you need to use an environment
+   variable with that content.
+
+   The use of an absolute NAME is strongly suggested.  The length of
+   the file is limited to 511 bytes which is more than sufficient for
+   that common value of 107 for sun_path.  */
+static struct sockaddr_un *
+eval_redirection (const char *fname, int *r_redirect)
+{
+  FILE *fp;
+  char buffer[512], *name;
+  size_t n;
+  struct sockaddr_un *addr;
+  char *p, *pend;
+  const char *s;
+
+  *r_redirect = 0;
+
+  fp = fopen (fname, "rb");
+  if (!fp)
+    return NULL;
+  n = fread (buffer, 1, sizeof buffer - 1, fp);
+  fclose (fp);
+  if (!n)
+    {
+      gpg_err_set_errno (ENOENT);
+      return NULL;
+    }
+  buffer[n] = 0;
+  if (n < 17 || buffer[n-1] != '\n'
+      || memcmp (buffer, "%Assuan%\nsocket=", 16))
+    {
+      gpg_err_set_errno (EINVAL);
+      return NULL;
+    }
+  buffer[n-1] = 0;
+  name = buffer + 16;
+
+  *r_redirect = 1;
+
+  addr = calloc (1, sizeof *addr);
+  if (!addr)
+    return NULL;
+  addr->sun_family = AF_LOCAL;
+
+  n = 0;
+  for (p=name; *p; p++)
+    {
+      if (*p == '$' && p[1] == '{')
+        {
+          p += 2;
+          pend = strchr (p, '}');
+          if (!pend)
+            {
+              free (addr);
+              gpg_err_set_errno (EINVAL);
+              return NULL;
+            }
+          *pend = 0;
+          if (*p && (s = getenv (p)))
+            {
+              for (; *s; s++)
+                {
+                  if (n < sizeof addr->sun_path - 1)
+                    addr->sun_path[n++] = *s;
+                  else
+                    {
+                      free (addr);
+                      gpg_err_set_errno (ENAMETOOLONG);
+                      return NULL;
+                  }
+                }
+            }
+          p = pend;
+        }
+      else if (n < sizeof addr->sun_path - 1)
+        addr->sun_path[n++] = *p;
+      else
+        {
+          free (addr);
+          gpg_err_set_errno (ENAMETOOLONG);
+          return NULL;
+        }
+    }
+
+  return addr;
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+
 /* Return a new socket.  Note that under W32 we consider a socket the
    same as an System Handle; all functions using such a handle know
-   about this dual use and act accordingly. */ 
+   about this dual use and act accordingly. */
 assuan_fd_t
 _assuan_sock_new (assuan_context_t ctx, int domain, int type, int proto)
 {
@@ -265,21 +379,21 @@ _assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
       unsigned short port;
       char nonce[16];
       int ret;
-      
+
       unaddr = (struct sockaddr_un *)addr;
       if (read_port_and_nonce (unaddr->sun_path, &port, nonce))
         return -1;
-      
+
       myaddr.sin_family = AF_INET;
-      myaddr.sin_port = htons (port); 
+      myaddr.sin_port = htons (port);
       myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-  
+
       /* Set return values.  */
       unaddr->sun_family = myaddr.sin_family;
       unaddr->sun_port = myaddr.sin_port;
       unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr;
-  
-      ret = _assuan_connect (ctx, HANDLE2SOCKET(sockfd), 
+
+      ret = _assuan_connect (ctx, HANDLE2SOCKET(sockfd),
 			    (struct sockaddr *)&myaddr, sizeof myaddr);
       if (!ret)
         {
@@ -298,8 +412,40 @@ _assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
       int res;
       res = _assuan_connect (ctx, HANDLE2SOCKET (sockfd), addr, addrlen);
       return res;
-    }      
+    }
 #else
+# if HAVE_STAT
+  if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
+    {
+      struct sockaddr_un *unaddr;
+      struct stat statbuf;
+      int redirect, res;
+
+      unaddr = (struct sockaddr_un *)addr;
+      if (!stat (unaddr->sun_path, &statbuf)
+          && !S_ISSOCK (statbuf.st_mode)
+          && S_ISREG (statbuf.st_mode))
+        {
+          /* The given socket file is not a socket but a regular file.
+             We use the content of that file to redirect to another
+             socket file.  This can be used to use sockets on file
+             systems which do not support sockets or if for example a
+             home directory is shared by several machines.  */
+          unaddr = eval_redirection (unaddr->sun_path, &redirect);
+          if (unaddr)
+            {
+              res = _assuan_connect (ctx, sockfd, (struct sockaddr *)unaddr,
+                                     SUN_LEN (unaddr));
+              free (unaddr);
+              return res;
+            }
+          if (redirect)
+            return -1;
+          /* Continue using the standard connect.  */
+        }
+
+    }
+# endif /*HAVE_STAT*/
   return _assuan_connect (ctx, sockfd, addr, addrlen);
 #endif
 }
@@ -330,7 +476,7 @@ _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
       myaddr.sin_family = AF_INET;
       myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
 
-      filehd = MyCreateFile (unaddr->sun_path, 
+      filehd = MyCreateFile (unaddr->sun_path,
                              GENERIC_WRITE,
                              FILE_SHARE_READ,
                              NULL,
@@ -346,7 +492,7 @@ _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
 
       rc = bind (HANDLE2SOCKET (sockfd), (struct sockaddr *)&myaddr, len);
       if (!rc)
-        rc = getsockname (HANDLE2SOCKET (sockfd), 
+        rc = getsockname (HANDLE2SOCKET (sockfd),
                           (struct sockaddr *)&myaddr, &len);
       if (rc)
         {
@@ -360,7 +506,7 @@ _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
       len = strlen (tmpbuf);
       memcpy (tmpbuf+len, nonce,16);
       len += 16;
-      
+
       if (!WriteFile (filehd, tmpbuf, len, &nwritten, NULL))
         {
           CloseHandle (filehd);
@@ -384,6 +530,69 @@ _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
 }
 
 
+/* Setup the ADDR structure for a Unix domain socket with the socket
+   name FNAME.  If this is a redirected socket and R_REDIRECTED is not
+   NULL, it will be setup for the real socket.  Returns 0 on success
+   and stores 1 at R_REDIRECTED if it is a redirected socket.  On
+   error -1 is returned and ERRNO will be set.  */
+int
+_assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
+                              int *r_redirected)
+{
+  struct sockaddr_un *unaddr = (struct sockaddr_un *)addr;
+#if !defined(HAVE_W32_SYSTEM) && defined(HAVE_STAT)
+  struct stat statbuf;
+#endif
+
+  if (r_redirected)
+    *r_redirected = 0;
+
+#if !defined(HAVE_W32_SYSTEM) && defined(HAVE_STAT)
+  if (r_redirected
+      && !stat (fname, &statbuf)
+      && !S_ISSOCK (statbuf.st_mode)
+      && S_ISREG (statbuf.st_mode))
+    {
+      /* The given socket file is not a socket but a regular file.  We
+         use the content of that file to redirect to another socket
+         file.  This can be used to use sockets on file systems which
+         do not support sockets or if for example a home directory is
+         shared by several machines.  */
+      struct sockaddr_un *unaddr_new;
+      int redirect;
+
+      unaddr_new = eval_redirection (fname, &redirect);
+      if (unaddr_new)
+        {
+          memcpy (unaddr, unaddr_new, sizeof *unaddr);
+          free (unaddr_new);
+          *r_redirected = 1;
+          return 0;
+        }
+      if (redirect)
+        {
+          *r_redirected = 1;
+          return -1;  /* Error.  */
+        }
+      /* Fallback to standard setup.  */
+    }
+#endif /*!HAVE_W32_SYSTEM && HAVE_STAT*/
+
+  if (strlen (fname)+1 >= sizeof unaddr->sun_path)
+    {
+      gpg_err_set_errno (ENAMETOOLONG);
+      return -1;
+    }
+
+  memset (unaddr, 0, sizeof *unaddr);
+  unaddr->sun_family = AF_LOCAL;
+  strncpy (unaddr->sun_path, fname, sizeof unaddr->sun_path - 1);
+  unaddr->sun_path[sizeof unaddr->sun_path - 1] = 0;
+
+  return 0;
+}
+
+
 int
 _assuan_sock_get_nonce (assuan_context_t ctx, struct sockaddr *addr,
 			int addrlen, assuan_sock_nonce_t *nonce)
@@ -416,8 +625,8 @@ _assuan_sock_get_nonce (assuan_context_t ctx, struct sockaddr *addr,
 #endif
   return 0;
 }
- 
- 
+
+
 int
 _assuan_sock_check_nonce (assuan_context_t ctx, assuan_fd_t fd,
 			  assuan_sock_nonce_t *nonce)
@@ -498,7 +707,7 @@ assuan_sock_init ()
     return 0;
 
   err = assuan_new (&sock_ctx);
-	
+
 #ifdef HAVE_W32_SYSTEM
   if (! err)
     WSAStartup (0x202, &wsadat);
@@ -521,7 +730,7 @@ assuan_sock_deinit ()
   assuan_release (sock_ctx);
   sock_ctx = NULL;
 }
-  
+
 
 int
 assuan_sock_close (assuan_fd_t fd)
@@ -529,7 +738,7 @@ assuan_sock_close (assuan_fd_t fd)
   return _assuan_close (sock_ctx, fd);
 }
 
-assuan_fd_t 
+assuan_fd_t
 assuan_sock_new (int domain, int type, int proto)
 {
   return _assuan_sock_new (sock_ctx, domain, type, proto);
@@ -548,9 +757,16 @@ assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
 }
 
 int
-assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, 
+assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
+                             int *r_redirected)
+{
+  return _assuan_sock_set_sockaddr_un (fname, addr, r_redirected);
+}
+
+int
+assuan_sock_get_nonce (struct sockaddr *addr, int addrlen,
                        assuan_sock_nonce_t *nonce)
-{     
+{
   return _assuan_sock_get_nonce (sock_ctx, addr, addrlen, nonce);
 }
 
diff --git a/src/assuan.h.in b/src/assuan.h.in
index d074a9f..f53c26e 100644
--- a/src/assuan.h.in
+++ b/src/assuan.h.in
@@ -470,6 +470,8 @@ assuan_fd_t assuan_sock_new (int domain, int type, int proto);
 int assuan_sock_connect (assuan_fd_t sockfd,
                          struct sockaddr *addr, int addrlen);
 int assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen);
+int assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
+                                 int *r_redirected);
 int assuan_sock_get_nonce (struct sockaddr *addr, int addrlen,
                            assuan_sock_nonce_t *nonce);
 int assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce);
diff --git a/src/libassuan.def b/src/libassuan.def
index 5636bfc..d9997e3 100644
--- a/src/libassuan.def
+++ b/src/libassuan.def
@@ -111,6 +111,7 @@ EXPORTS
     __assuan_sendmsg			@90
     __assuan_waitpid			@91
     assuan_check_version                @92
+    assuan_sock_set_sockaddr_un         @93
 
 ; END
 
diff --git a/src/libassuan.vers b/src/libassuan.vers
index 700c68c..e36c322 100644
--- a/src/libassuan.vers
+++ b/src/libassuan.vers
@@ -101,6 +101,7 @@ LIBASSUAN_1.0 {
     assuan_free;
     assuan_socket_connect_fd;
     assuan_check_version;
+    assuan_sock_set_sockaddr_un;
 
     __assuan_close;
     __assuan_pipe;

-----------------------------------------------------------------------

Summary of changes:
 NEWS                |    5 +
 configure.ac        |    2 +-
 doc/assuan.texi     |   37 +++++++-
 src/assuan-defs.h   |    2 +
 src/assuan-socket.c |  260 ++++++++++++++++++++++++++++++++++++++++++++++-----
 src/assuan.h.in     |    2 +
 src/libassuan.def   |    1 +
 src/libassuan.vers  |    1 +
 8 files changed, 286 insertions(+), 24 deletions(-)


hooks/post-receive
-- 
IPC library used by GnuPG
http://git.gnupg.org




More information about the Gnupg-commits mailing list