Support logging via TCP

This commit is contained in:
Werner Koch 2010-08-09 15:40:29 +00:00
parent 20a58b2596
commit e52f93433c
9 changed files with 258 additions and 60 deletions

View File

@ -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.

View 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

View 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)

View File

@ -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
"

View 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.

View File

@ -29,16 +29,19 @@
#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"
@ -56,6 +59,22 @@
# 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. */

View 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.

View 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.

View 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))