Support logging via TCP
authorWerner Koch <wk@gnupg.org>
Mon, 9 Aug 2010 15:40:29 +0000 (15:40 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 9 Aug 2010 15:40:29 +0000 (15:40 +0000)
ChangeLog
agent/ChangeLog
agent/Makefile.am
autogen.sh
common/ChangeLog
common/logging.c
configure.ac
tools/ChangeLog
tools/watchgnupg.c

index 433b50d..c0cf51f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2010-08-09  Werner Koch  <wk@g10code.com>
+
+       * configure.ac (inet_pton): Check for it.
+
 2010-08-05  Werner Koch  <wk@g10code.com>
 
        * configure.ac (AH_BOTTOM): Remove HTTP_USE_ESTREAM.
index c4aa1c2..a9b67a8 100644 (file)
@@ -1,3 +1,8 @@
+2010-08-09  Werner Koch  <wk@g10code.com>
+
+       * Makefile.am (t_common_ldadd): Add NETLIBS for sake of the TCP
+       logging.
+
 2010-06-24  Werner Koch  <wk@g10code.com>
 
        * genkey.c (check_passphrase_pattern): Use HANG option for
index e221536..abd39be 100644 (file)
@@ -105,8 +105,8 @@ $(PROGRAMS): $(common_libs) $(commonpth_libs) $(pwquery_libs)
 #
 TESTS = t-protect
 
-t_common_ldadd = $(common_libs) \
-                 $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV)
+t_common_ldadd = $(common_libs)  $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
+                 $(LIBINTL) $(LIBICONV) $(NETLIBS)
 
 t_protect_SOURCES = t-protect.c protect.c 
 t_protect_LDADD = $(t_common_ldadd)
index ab4c7da..30c2b1a 100755 (executable)
@@ -267,5 +267,5 @@ echo "Running autoconf${FORCE} ..."
 $AUTOCONF${FORCE}
 
 echo "You may now run: 
-  ./configure --sysconfdir=/etc --enable-maintainer-mode --enable-symcryptrun --enable-mailto && make
+  ./configure --sysconfdir=/etc --enable-maintainer-mode --enable-symcryptrun --enable-mailto --enable-gpgtar && make
 "
index d690534..9e69563 100644 (file)
@@ -1,3 +1,10 @@
+2010-08-09  Werner Koch  <wk@g10code.com>
+
+       * logging.c (WITH_IPV6): New macro.
+       (parse_portno): New.  From libassuan.
+       (fun_writer): Support TCP logging on all platforms.
+       (sock_close): New.
+
 2010-08-06  Werner Koch  <wk@g10code.com>
 
        * homedir.c (dirmngr_socket_name) [W32CE]: Base on default homedir.
index dbf9de4..87e335b 100644 (file)
 #include <time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#ifndef HAVE_W32_SYSTEM
+#ifdef HAVE_W32_SYSTEM
+# include <windows.h>
+#else /*!HAVE_W32_SYSTEM*/
 # include <sys/socket.h>
 # include <sys/un.h>
-#endif /*HAVE_W32_SYSTEM*/
+# include <netinet/in.h>
+# include <arpa/inet.h>
+#endif /*!HAVE_W32_SYSTEM*/
 #include <unistd.h>
 #include <fcntl.h>
 #include <assert.h>
 
 
-
 #define JNLIB_NEED_LOG_LOGV 1
 #define JNLIB_NEED_AFLOCAL 1
 #include "libjnlib-config.h"
 # define isatty(a)  (0)
 #endif
 
+#undef WITH_IPV6
+#if defined (AF_INET6) && defined(PF_INET) \
+    && defined (INET6_ADDRSTRLEN) && defined(HAVE_INET_PTON)
+# define WITH_IPV6 1
+#endif
+
+#ifndef EAFNOSUPPORT
+# define EAFNOSUPPORT EINVAL
+#endif
+
+#ifdef HAVE_W32_SYSTEM
+#define sock_close(a)  closesocket(a)
+#else
+#define sock_close(a)  close(a)
+#endif
+
 
 static estream_t logstream;
 static int log_socket = -1;
@@ -109,7 +128,11 @@ writen (int fd, const void *buffer, size_t nbytes)
   
   while (nleft > 0)
     {
+#ifdef HAVE_W32_SYSTEM
+      nwritten = send (fd, buf, nleft, 0);
+#else
       nwritten = write (fd, buf, nleft);
+#endif
       if (nwritten < 0 && errno == EINTR)
         continue;
       if (nwritten < 0)
@@ -122,6 +145,27 @@ writen (int fd, const void *buffer, size_t nbytes)
 }
 
 
+/* Returns true if STR represents a valid port number in decimal
+   notation and no garbage is following.  */
+static int 
+parse_portno (const char *str, unsigned short *r_port)
+{
+  unsigned int value;
+
+  for (value=0; *str && (*str >= '0' && *str <= '9'); str++)
+    {
+      value = value * 10 + (*str - '0');
+      if (value > 65535)
+        return 0;
+    }
+  if (*str || !value)
+    return 0;
+
+  *r_port = value;
+  return 1;
+}
+
+
 static ssize_t 
 fun_writer (void *cookie_arg, const void *buffer, size_t size)
 {
@@ -134,12 +178,129 @@ fun_writer (void *cookie_arg, const void *buffer, size_t size)
      processes often close stderr and by writing to file descriptor 2
      we might send the log message to a file not intended for logging
      (e.g. a pipe or network connection). */
-#ifndef HAVE_W32_SYSTEM
   if (cookie->want_socket && cookie->fd == -1)
     {
+#ifdef WITH_IPV6
+      struct sockaddr_in6 srvr_addr_in6;
+#endif
+      struct sockaddr_in srvr_addr_in;
+#ifndef HAVE_W32_SYSTEM
+      struct sockaddr_un srvr_addr_un;
+#endif
+      size_t addrlen;
+      struct sockaddr *srvr_addr = NULL;
+      unsigned short port = 0;
+      int af = AF_LOCAL;
+      int pf = PF_LOCAL;
+      const char *name = cookie->name;
+
       /* Not yet open or meanwhile closed due to an error. */
       cookie->is_socket = 0;
-      cookie->fd = socket (PF_LOCAL, SOCK_STREAM, 0);
+
+      /* Check whether this is a TCP socket or a local socket.  */
+      if (!strncmp (name, "tcp://", 6) && name[6])
+        {
+          name += 6;
+          af = AF_INET;
+          pf = PF_INET;
+        }
+#ifndef HAVE_W32_SYSTEM
+      else if (!strncmp (name, "socket://", 9) && name[9])
+        name += 9;
+#endif
+      
+      if (af == AF_LOCAL)
+        {
+#ifdef HAVE_W32_SYSTEM
+          addrlen = 0;
+#else
+          memset (&srvr_addr, 0, sizeof srvr_addr);
+          srvr_addr_un.sun_family = af;
+          strncpy (srvr_addr_un.sun_path,
+                   name, sizeof (srvr_addr_un.sun_path)-1);
+          srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path)-1] = 0;
+          srvr_addr = (struct sockaddr *)&srvr_addr_un;
+          addrlen = SUN_LEN (&srvr_addr_un);
+#endif
+        }
+      else
+        {
+          char *addrstr, *p;
+          void *addrbuf = NULL;
+
+          addrstr = jnlib_malloc (strlen (name) + 1);
+          if (!addrstr)
+            addrlen = 0; /* This indicates an error.  */
+          else if (*name == '[')
+            {
+              /* Check for IPv6 literal address.  */
+              strcpy (addrstr, name+1);
+              p = strchr (addrstr, ']');
+              if (!p || p[1] != ':' || !parse_portno (p+2, &port))
+                {
+                  jnlib_set_errno (EINVAL);
+                  addrlen = 0;
+                }
+              else 
+                {
+                  *p = 0;
+#ifdef WITH_IPV6
+                  af = AF_INET6;
+                  pf = PF_INET6;
+                  memset (&srvr_addr_in6, 0, sizeof srvr_addr_in6);
+                  srvr_addr_in6.sin6_family = af;
+                  srvr_addr_in6.sin6_port = htons (port);
+                  addrbuf = &srvr_addr_in6.sin6_addr;
+                  srvr_addr = (struct sockaddr *)&srvr_addr_in6;
+                  addrlen = sizeof srvr_addr_in6;
+#else
+                  jnlib_set_errno (EAFNOSUPPORT);
+                  addrlen = 0;
+#endif
+                }
+            }
+          else
+            {
+              /* Check for IPv4 literal address.  */
+              strcpy (addrstr, name);
+              p = strchr (addrstr, ':');
+              if (!p || !parse_portno (p+1, &port))
+                {
+                  jnlib_set_errno (EINVAL);
+                  addrlen = 0;
+                }
+              else
+                {
+                  *p = 0;
+                  memset (&srvr_addr_in, 0, sizeof srvr_addr_in);
+                  srvr_addr_in.sin_family = af;
+                  srvr_addr_in.sin_port = htons (port);
+                  addrbuf = &srvr_addr_in.sin_addr;
+                  srvr_addr = (struct sockaddr *)&srvr_addr_in;
+                  addrlen = sizeof srvr_addr_in;
+                }
+            }
+
+          if (addrlen)
+            {
+#ifdef HAVE_INET_PTON
+              if (inet_pton (af, addrstr, addrbuf) != 1)
+                addrlen = 0;
+#else /*!HAVE_INET_PTON*/
+              /* We need to use the old function.  If we are here v6
+                 support isn't enabled anyway and thus we can do fine
+                 without.  Note that Windows has a compatible inet_pton
+                 function named inetPton, but only since Vista.  */
+              srvr_addr_in.sin_addr.s_addr = inet_addr (addrstr);
+              if (srvr_addr_in.sin_addr.s_addr == INADDR_NONE)
+                addrlen = 0;
+#endif /*!HAVE_INET_PTON*/
+            }
+      
+          jnlib_free (addrstr);
+        }
+
+      cookie->fd = addrlen? socket (pf, SOCK_STREAM, 0) : -1;
       if (cookie->fd == -1)
         {
           if (!cookie->quiet && !running_detached
@@ -149,22 +310,13 @@ fun_writer (void *cookie_arg, const void *buffer, size_t size)
         }
       else
         {
-          struct sockaddr_un addr;
-          size_t addrlen;
-          
-          memset (&addr, 0, sizeof addr);
-          addr.sun_family = PF_LOCAL;
-          strncpy (addr.sun_path, cookie->name, sizeof (addr.sun_path)-1);
-          addr.sun_path[sizeof (addr.sun_path)-1] = 0;
-          addrlen = SUN_LEN (&addr);
-      
-          if (connect (cookie->fd, (struct sockaddr *) &addr, addrlen) == -1)
+          if (connect (cookie->fd, srvr_addr, addrlen) == -1)
             {
               if (!cookie->quiet && !running_detached
                   && isatty (es_fileno (es_stderr)))
                 es_fprintf (es_stderr, "can't connect to `%s': %s\n",
                             cookie->name, strerror(errno));
-              close (cookie->fd);
+              sock_close (cookie->fd);
               cookie->fd = -1;
             }
         }
@@ -174,9 +326,9 @@ fun_writer (void *cookie_arg, const void *buffer, size_t size)
           if (!running_detached)
             {
               /* Due to all the problems with apps not running
-                 detached but being called with stderr closed or
-                 used for a different purposes, it does not make
-                 sense to switch to stderr.  We therefore disable it. */
+                 detached but being called with stderr closed or used
+                 for a different purposes, it does not make sense to
+                 switch to stderr.  We therefore disable it. */
               if (!cookie->quiet)
                 {
                   /* fputs ("switching logging to stderr\n", stderr);*/
@@ -191,12 +343,11 @@ fun_writer (void *cookie_arg, const void *buffer, size_t size)
           cookie->is_socket = 1;
         }
     }
-#endif /*HAVE_W32_SYSTEM*/
-
+  
   log_socket = cookie->fd;
   if (cookie->fd != -1 && !writen (cookie->fd, buffer, size))
     return (ssize_t)size; /* Okay. */ 
-
+  
   if (!running_detached && cookie->fd != -1
       && isatty (es_fileno (es_stderr)))
     {
@@ -209,11 +360,11 @@ fun_writer (void *cookie_arg, const void *buffer, size_t size)
     }
   if (cookie->is_socket && cookie->fd != -1)
     {
-      close (cookie->fd);
+      sock_close (cookie->fd);
       cookie->fd = -1;
       log_socket = -1;
     }
-
+  
   return (ssize_t)size;
 }
 
@@ -224,7 +375,7 @@ fun_closer (void *cookie_arg)
   struct fun_cookie_s *cookie = cookie_arg;
 
   if (cookie->fd != -1 && cookie->fd != 2)
-    close (cookie->fd);
+    sock_close (cookie->fd);
   jnlib_free (cookie);
   log_socket = -1;
   return 0;
@@ -254,18 +405,13 @@ set_file_fd (const char *name, int fd)
       fd = es_fileno (es_stderr);
     }
 
+  want_socket = 0;
+  if (name && !strncmp (name, "tcp://", 6) && name[6])
+    want_socket = 1;
 #ifndef HAVE_W32_SYSTEM
-  if (name)
-    {
-      want_socket = (!strncmp (name, "socket://", 9) && name[9]);
-      if (want_socket)
-        name += 9;
-    }
-  else
+  else if (name && !strncmp (name, "socket://", 9) && name[9])
+    want_socket = 2;
 #endif /*HAVE_W32_SYSTEM*/
-    {
-      want_socket = 0;
-    }
 
   /* Setup a new stream.  */
 
index ff48ee7..362dd0a 100644 (file)
@@ -1203,7 +1203,7 @@ AC_CHECK_HEADERS([signal.h])
 AC_CHECK_FUNCS([memicmp stpcpy strsep strlwr strtoul memmove stricmp strtol \
                 memrchr isascii timegm getrusage setrlimit stat setlocale   \
                 flockfile funlockfile fopencookie funopen getpwnam getpwuid \
-                getenv ])
+                getenv inet_pton])
 # end jnlib checks.
 
 
index 65bb6f6..252e7f9 100644 (file)
@@ -1,5 +1,8 @@
 2010-08-09  Werner Koch  <wk@g10code.com>
 
+       * watchgnupg.c: Inlcude in.h and inet.h.
+       (main): Support tcp connections.
+
        * gpgtar.c (main): Add options -T and --null.
        * gpgtar-create.c (gpgtar_create): Implement option --null.
 
index 145a76b..fe9e3d6 100644 (file)
@@ -30,6 +30,8 @@
 #include <unistd.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include <fcntl.h>
 #include <time.h>
 
@@ -40,7 +42,7 @@
 #define MYVERSION_LINE PGM " (GnuPG) " VERSION
 #define BUGREPORT_LINE "\nReport bugs to <bug-gnupg@gnu.org>.\n"
 #else
-#define MYVERSION_LINE PGM 
+#define MYVERSION_LINE PGM " (standalone build) " __DATE__
 #define BUGREPORT_LINE ""
 #endif
 #if !defined(SUN_LEN) || !defined(PF_LOCAL) || !defined(AF_LOCAL)
@@ -189,17 +191,19 @@ print_version (int with_help)
 {
   fputs (MYVERSION_LINE "\n"
          "Copyright (C) 2004 Free Software Foundation, Inc.\n"
-         "This program comes with ABSOLUTELY NO WARRANTY.\n"
-         "This is free software, and you are welcome to redistribute it\n"
-         "under certain conditions. See the file COPYING for details.\n",
+         "License GPLv3+: "
+         "GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"
+         "This is free software: you are free to change and redistribute it.\n"
+         "There is NO WARRANTY, to the extent permitted by law.\n",
          stdout);
-        
   if (with_help)
     fputs ("\n"
-          "Usage: " PGM " [OPTIONS] SOCKETNAME\n"
-          "Open the local socket SOCKETNAME and display log messages\n"
+          "Usage: " PGM " [OPTIONS] SOCKETNAME|PORT\n"
+          "Open the local socket SOCKETNAME (or the TCP port PORT)\n"
+          "and display log messages\n"
           "\n"
           "  --force     delete an already existing socket file\n"
+          "  --tcp       listen on a TCP port instead of a local socket\n"
           "  --verbose   enable extra informational output\n"
           "  --version   print version of the program and exit\n"
           "  --help      display this help and exit\n"
@@ -213,9 +217,13 @@ main (int argc, char **argv)
 {
   int last_argc = -1;
   int force = 0;
+  int tcp = 0;
 
-  struct sockaddr_un srvr_addr;
+  struct sockaddr_un srvr_addr_un;
+  struct sockaddr_in srvr_addr_in;
+  struct sockaddr *srvr_addr = NULL;
   socklen_t addrlen;
+  unsigned short port;
   int server;
   int flags;
   client_t client_list = NULL;
@@ -246,6 +254,11 @@ main (int argc, char **argv)
           force = 1;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--tcp"))
+        {
+          tcp = 1;
+          argc--; argv++;
+        }
     }          
  
   if (argc != 1)
@@ -254,13 +267,19 @@ main (int argc, char **argv)
       exit (1);
     }
 
+  port = tcp? atoi (*argv) : 0;
 
   if (verbose)
-    fprintf (stderr, "opening socket `%s'\n", *argv);
+    {
+      if (tcp)
+        fprintf (stderr, "listening on port %hu\n", port);
+      else
+        fprintf (stderr, "opening socket `%s'\n", *argv);
+    }
 
   setvbuf (stdout, NULL, _IOLBF, 0);
 
-  server = socket (PF_LOCAL, SOCK_STREAM, 0);
+  server = socket (tcp? PF_INET : PF_LOCAL, SOCK_STREAM, 0);
   if (server == -1)
     die ("socket() failed: %s\n", strerror (errno));
 
@@ -273,24 +292,38 @@ main (int argc, char **argv)
   if ( fcntl (server, F_SETFL, (flags | O_NONBLOCK)) == -1)
     die ("fcntl (F_SETFL) failed: %s\n", strerror (errno));
   
-
-  memset (&srvr_addr, 0, sizeof srvr_addr);
-  srvr_addr.sun_family = AF_LOCAL;
-  strncpy (srvr_addr.sun_path, *argv, sizeof (srvr_addr.sun_path) - 1);
-  srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0;
-  addrlen = SUN_LEN (&srvr_addr);
-
+  if (tcp)
+    {
+      memset (&srvr_addr_in, 0, sizeof srvr_addr_in);
+      srvr_addr_in.sin_family = AF_INET;
+      srvr_addr_in.sin_port = htons (port);
+      srvr_addr_in.sin_addr.s_addr = htonl (INADDR_ANY);
+      srvr_addr = (struct sockaddr *)&srvr_addr_in;
+      addrlen = sizeof srvr_addr_in;
+    }
+  else
+    {
+      memset (&srvr_addr_un, 0, sizeof srvr_addr_un);
+      srvr_addr_un.sun_family = AF_LOCAL;
+      strncpy (srvr_addr_un.sun_path, *argv, sizeof (srvr_addr_un.sun_path)-1);
+      srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path) - 1] = 0;
+      srvr_addr = (struct sockaddr *)&srvr_addr_un;
+      addrlen = SUN_LEN (&srvr_addr_un);
+    }
   
  again:
-  if (bind (server, (struct sockaddr *) &srvr_addr, addrlen))
+  if (bind (server, srvr_addr, addrlen))
     { 
-      if (errno == EADDRINUSE && force)
+      if (!tcp && errno == EADDRINUSE && force)
         {
           force = 0;
-          remove (srvr_addr.sun_path);
+          remove (srvr_addr_un.sun_path);
           goto again;
         }
-      die ("bind to `%s' failed: %s\n", *argv, strerror (errno));
+      if (tcp)
+        die ("bind to port %hu failed: %s\n", port, strerror (errno));
+      else
+        die ("bind to `%s' failed: %s\n", *argv, strerror (errno));
     }
 
   if (listen (server, 5))