On Fri, Jan 16, 2015 at 12:56:45PM +0100, Alexander Bluhm wrote:
> On Fri, Jan 16, 2015 at 01:46:09AM +0100, Alexander Bluhm wrote:
> > This diff enables sending syslog messages over TLS.
> 
> Updated diff after sys/param.h commit.  Only some context changed.
> 
> bluhm
> 

Despite my scepticism about putting it into libevent -

The diff looks and works fine (lightly tested).

The evbuffer_tls.c code is similar enough to what we have in
relayd/httpd and libevent;  so I don't see any problems here.

Minor comments (not inline):
- The ebuf[100] looks a bit weird, but it is not a problem.
- I would prefer checking return value as -1 instead of < 0
  (tls_init() and other calls below).
- The manpage bits are missing.

I'm fine with putting it in and to improve/discuss the API issues later.

OK

Reyk

> Index: usr.sbin/syslogd/Makefile
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/Makefile,v
> retrieving revision 1.6
> diff -u -p -r1.6 Makefile
> --- usr.sbin/syslogd/Makefile 5 Oct 2014 18:14:01 -0000       1.6
> +++ usr.sbin/syslogd/Makefile 16 Jan 2015 11:45:40 -0000
> @@ -1,9 +1,9 @@
>  #    $OpenBSD: Makefile,v 1.6 2014/10/05 18:14:01 bluhm Exp $
>  
>  PROG=        syslogd
> -SRCS=        syslogd.c ttymsg.c privsep.c privsep_fdpass.c ringbuf.c
> +SRCS=        syslogd.c ttymsg.c privsep.c privsep_fdpass.c ringbuf.c 
> evbuffer_tls.c
>  MAN= syslogd.8 syslog.conf.5
> -LDADD=       -levent
> -DPADD=       ${LIBEVENT}
> +LDADD=       -levent -ltls -lssl -lcrypto
> +DPADD=       ${LIBEVENT} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO}
>  
>  .include <bsd.prog.mk>
> Index: usr.sbin/syslogd/evbuffer_tls.c
> ===================================================================
> RCS file: usr.sbin/syslogd/evbuffer_tls.c
> diff -N usr.sbin/syslogd/evbuffer_tls.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ usr.sbin/syslogd/evbuffer_tls.c   16 Jan 2015 11:45:40 -0000
> @@ -0,0 +1,357 @@
> +/*   $OpenBSD$ */
> +
> +/*
> + * Copyright (c) 2002-2004 Niels Provos <pro...@citi.umich.edu>
> + * Copyright (c) 2014-2015 Alexander Bluhm <bl...@openbsd.org>
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. The name of the author may not be used to endorse or promote products
> + *    derived from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
> + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
> + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
> + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include <sys/types.h>
> +#include <sys/time.h>
> +#include <sys/ioctl.h>
> +
> +#include <errno.h>
> +#include <event.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <stdarg.h>
> +#include <tls.h>
> +
> +#include "evbuffer_tls.h"
> +
> +/* prototypes */
> +
> +void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *);
> +int evtls_read(struct evbuffer *, int, int, struct tls *);
> +int evtls_write(struct evbuffer *, int, struct tls *);
> +
> +static int
> +bufferevent_add(struct event *ev, int timeout)
> +{
> +     struct timeval tv, *ptv = NULL;
> +
> +     if (timeout) {
> +             timerclear(&tv);
> +             tv.tv_sec = timeout;
> +             ptv = &tv;
> +     }
> +
> +     return (event_add(ev, ptv));
> +}
> +
> +static void
> +buffertls_readcb(int fd, short event, void *arg)
> +{
> +     struct buffertls *buftls = arg;
> +     struct bufferevent *bufev = buftls->bt_bufev;
> +     struct tls *ctx = buftls->bt_ctx;
> +     int res = 0;
> +     short what = EVBUFFER_READ;
> +     size_t len;
> +     int howmuch = -1;
> +
> +     if (event == EV_TIMEOUT) {
> +             what |= EVBUFFER_TIMEOUT;
> +             goto error;
> +     }
> +
> +     /*
> +      * If we have a high watermark configured then we don't want to
> +      * read more data than would make us reach the watermark.
> +      */
> +     if (bufev->wm_read.high != 0) {
> +             howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input);
> +             /* we might have lowered the watermark, stop reading */
> +             if (howmuch <= 0) {
> +                     struct evbuffer *buf = bufev->input;
> +                     event_del(&bufev->ev_read);
> +                     evbuffer_setcb(buf,
> +                         bufferevent_read_pressure_cb, bufev);
> +                     return;
> +             }
> +     }
> +
> +     res = evtls_read(bufev->input, fd, howmuch, ctx);
> +     switch (res) {
> +     case TLS_READ_AGAIN:
> +             event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb,
> +                 buftls);
> +             goto reschedule;
> +     case TLS_WRITE_AGAIN:
> +             event_set(&bufev->ev_read, fd, EV_WRITE, buffertls_readcb,
> +                 buftls);
> +             goto reschedule;
> +     case -1:
> +             if (errno == EAGAIN || errno == EINTR)
> +                     goto reschedule;
> +             /* error case */
> +             what |= EVBUFFER_ERROR;
> +             break;
> +     case 0:
> +             /* eof case */
> +             what |= EVBUFFER_EOF;
> +             break;
> +     }
> +     if (res <= 0)
> +             goto error;
> +
> +     event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls);
> +     bufferevent_add(&bufev->ev_read, bufev->timeout_read);
> +
> +     /* See if this callbacks meets the water marks */
> +     len = EVBUFFER_LENGTH(bufev->input);
> +     if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
> +             return;
> +     if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) {
> +             struct evbuffer *buf = bufev->input;
> +             event_del(&bufev->ev_read);
> +
> +             /* Now schedule a callback for us when the buffer changes */
> +             evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
> +     }
> +
> +     /* Invoke the user callback - must always be called last */
> +     if (bufev->readcb != NULL)
> +             (*bufev->readcb)(bufev, bufev->cbarg);
> +     return;
> +
> + reschedule:
> +     bufferevent_add(&bufev->ev_read, bufev->timeout_read);
> +     return;
> +
> + error:
> +     (*bufev->errorcb)(bufev, what, bufev->cbarg);
> +}
> +
> +static void
> +buffertls_writecb(int fd, short event, void *arg)
> +{
> +     struct buffertls *buftls = arg;
> +     struct bufferevent *bufev = buftls->bt_bufev;
> +     struct tls *ctx = buftls->bt_ctx;
> +     int res = 0;
> +     short what = EVBUFFER_WRITE;
> +
> +     if (event == EV_TIMEOUT) {
> +             what |= EVBUFFER_TIMEOUT;
> +             goto error;
> +     }
> +
> +     if (EVBUFFER_LENGTH(bufev->output) != 0) {
> +             res = evtls_write(bufev->output, fd, ctx);
> +             switch (res) {
> +             case TLS_READ_AGAIN:
> +                     event_set(&bufev->ev_write, fd, EV_READ,
> +                         buffertls_writecb, buftls);
> +                     goto reschedule;
> +             case TLS_WRITE_AGAIN:
> +                     event_set(&bufev->ev_write, fd, EV_WRITE,
> +                         buffertls_writecb, buftls);
> +                     goto reschedule;
> +             case -1:
> +                     if (errno == EAGAIN || errno == EINTR ||
> +                         errno == EINPROGRESS)
> +                             goto reschedule;
> +                     /* error case */
> +                     what |= EVBUFFER_ERROR;
> +                     break;
> +             case 0:
> +                     /* eof case */
> +                     what |= EVBUFFER_EOF;
> +                     break;
> +             }
> +             if (res <= 0)
> +                     goto error;
> +     }
> +
> +     event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
> +     if (EVBUFFER_LENGTH(bufev->output) != 0)
> +             bufferevent_add(&bufev->ev_write, bufev->timeout_write);
> +
> +     /*
> +      * Invoke the user callback if our buffer is drained or below the
> +      * low watermark.
> +      */
> +     if (bufev->writecb != NULL &&
> +         EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
> +             (*bufev->writecb)(bufev, bufev->cbarg);
> +
> +     return;
> +
> + reschedule:
> +     if (EVBUFFER_LENGTH(bufev->output) != 0)
> +             bufferevent_add(&bufev->ev_write, bufev->timeout_write);
> +     return;
> +
> + error:
> +     (*bufev->errorcb)(bufev, what, bufev->cbarg);
> +}
> +
> +static void
> +buffertls_connectcb(int fd, short event, void *arg)
> +{
> +     struct buffertls *buftls = arg;
> +     struct bufferevent *bufev = buftls->bt_bufev;
> +     struct tls *ctx = buftls->bt_ctx;
> +     const char *hostname = buftls->bt_hostname;
> +     int res = 0;
> +     short what = EVBUFFER_CONNECT;
> +
> +     if (event == EV_TIMEOUT) {
> +             what |= EVBUFFER_TIMEOUT;
> +             goto error;
> +     }
> +
> +     res = tls_connect_socket(ctx, fd, hostname);
> +     switch (res) {
> +     case TLS_READ_AGAIN:
> +             event_set(&bufev->ev_write, fd, EV_READ,
> +                 buffertls_connectcb, buftls);
> +             goto reschedule;
> +     case TLS_WRITE_AGAIN:
> +             event_set(&bufev->ev_write, fd, EV_WRITE,
> +                 buffertls_connectcb, buftls);
> +             goto reschedule;
> +     case -1:
> +             if (errno == EAGAIN || errno == EINTR ||
> +                 errno == EINPROGRESS)
> +                     goto reschedule;
> +             /* error case */
> +             what |= EVBUFFER_ERROR;
> +             break;
> +     }
> +     if (res < 0)
> +             goto error;
> +
> +     /*
> +      * There might be data available in the tls layer.  Try
> +      * an read operation and setup the callbacks.  Call the read
> +      * callback after enabling the write callback to give the
> +      * read error handler a chance to disable the write event.
> +      */
> +     event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
> +     if (EVBUFFER_LENGTH(bufev->output) != 0)
> +             bufferevent_add(&bufev->ev_write, bufev->timeout_write);
> +     buffertls_readcb(fd, 0, buftls);
> +
> +     return;
> +
> + reschedule:
> +     bufferevent_add(&bufev->ev_write, bufev->timeout_write);
> +     return;
> +
> + error:
> +     (*bufev->errorcb)(bufev, what, bufev->cbarg);
> +}
> +
> +void
> +buffertls_set(struct buffertls *buftls, struct bufferevent *bufev,
> +    struct tls *ctx, int fd)
> +{
> +     bufferevent_setfd(bufev, fd);
> +     event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls);
> +     event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
> +     buftls->bt_bufev = bufev;
> +     buftls->bt_ctx = ctx;
> +}
> +
> +void
> +buffertls_connect(struct buffertls *buftls, int fd, const char *hostname)
> +{
> +     struct bufferevent *bufev = buftls->bt_bufev;
> +
> +     event_del(&bufev->ev_read);
> +     event_del(&bufev->ev_write);
> +
> +     buftls->bt_hostname = hostname;
> +     buffertls_connectcb(fd, 0, buftls);
> +}
> +
> +/*
> + * Reads data from a file descriptor into a buffer.
> + */
> +
> +#define EVBUFFER_MAX_READ    4096
> +
> +int
> +evtls_read(struct evbuffer *buf, int fd, int howmuch, struct tls *ctx)
> +{
> +     u_char *p;
> +     size_t len, oldoff = buf->off;
> +     int n = EVBUFFER_MAX_READ;
> +
> +     if (ioctl(fd, FIONREAD, &n) == -1 || n <= 0) {
> +             n = EVBUFFER_MAX_READ;
> +     } else if (n > EVBUFFER_MAX_READ && n > howmuch) {
> +             /*
> +              * It's possible that a lot of data is available for
> +              * reading.  We do not want to exhaust resources
> +              * before the reader has a chance to do something
> +              * about it.  If the reader does not tell us how much
> +              * data we should read, we artifically limit it.
> +              */
> +             if ((size_t)n > buf->totallen << 2)
> +                     n = buf->totallen << 2;
> +             if (n < EVBUFFER_MAX_READ)
> +                     n = EVBUFFER_MAX_READ;
> +     }
> +     if (howmuch < 0 || howmuch > n)
> +             howmuch = n;
> +
> +     /* If we don't have FIONREAD, we might waste some space here */
> +     if (evbuffer_expand(buf, howmuch) == -1)
> +             return (-1);
> +
> +     /* We can append new data at this point */
> +     p = buf->buffer + buf->off;
> +
> +     n = tls_read(ctx, p, howmuch, &len);
> +     if (n < 0 || len == 0)
> +             return (n);
> +
> +     buf->off += len;
> +
> +     /* Tell someone about changes in this buffer */
> +     if (buf->off != oldoff && buf->cb != NULL)
> +             (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
> +
> +     return (len);
> +}
> +
> +int
> +evtls_write(struct evbuffer *buffer, int fd, struct tls *ctx)
> +{
> +     size_t len;
> +     int n;
> +
> +     n = tls_write(ctx, buffer->buffer, buffer->off, &len);
> +     if (n < 0 || len == 0)
> +             return (n);
> +
> +     evbuffer_drain(buffer, len);
> +
> +     return (len);
> +}
> Index: usr.sbin/syslogd/evbuffer_tls.h
> ===================================================================
> RCS file: usr.sbin/syslogd/evbuffer_tls.h
> diff -N usr.sbin/syslogd/evbuffer_tls.h
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ usr.sbin/syslogd/evbuffer_tls.h   16 Jan 2015 11:45:40 -0000
> @@ -0,0 +1,37 @@
> +/*   $OpenBSD$ */
> +
> +/*
> + * Copyright (c) 2014-2015 Alexander Bluhm <bl...@openbsd.org>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#ifndef _EVBUFFER_TLS_H_
> +#define _EVBUFFER_TLS_H_
> +
> +#define EVBUFFER_CONNECT     0x80
> +
> +struct bufferevent;
> +struct tls;
> +
> +struct buffertls {
> +     struct bufferevent      *bt_bufev;
> +     struct tls              *bt_ctx;
> +     const char              *bt_hostname;
> +};
> +
> +void buffertls_set(struct buffertls *, struct bufferevent *, struct tls *,
> +    int);
> +void buffertls_connect(struct buffertls *, int, const char *);
> +
> +#endif /* _EVBUFFER_TLS_H_ */
> Index: usr.sbin/syslogd/syslogd.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.c,v
> retrieving revision 1.142
> diff -u -p -r1.142 syslogd.c
> --- usr.sbin/syslogd/syslogd.c        16 Jan 2015 06:40:21 -0000      1.142
> +++ usr.sbin/syslogd/syslogd.c        16 Jan 2015 11:45:40 -0000
> @@ -50,7 +50,7 @@
>   * extensive changes by Ralph Campbell
>   * more extensive changes by Eric Allman (again)
>   * memory buffer logging by Damien Miller
> - * IPv6, libevent, sending via TCP by Alexander Bluhm
> + * IPv6, libevent, sending over TCP and TLS by Alexander Bluhm
>   */
>  
>  #define      MAXLINE         1024            /* maximum line length */
> @@ -91,6 +91,7 @@
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
> +#include <tls.h>
>  #include <unistd.h>
>  #include <limits.h>
>  #include <utmp.h>
> @@ -102,6 +103,7 @@
>  #include <sys/syslog.h>
>  
>  #include "syslogd.h"
> +#include "evbuffer_tls.h"
>  
>  char *ConfFile = _PATH_LOGCONF;
>  const char ctty[] = _PATH_CONSOLE;
> @@ -135,9 +137,11 @@ struct filed {
>               struct {
>                       char    f_loghost[1+4+3+1+HOST_NAME_MAX+1+1+NI_MAXSERV];
>                               /* @proto46://[hostname]:servname\0 */
> -                     struct sockaddr_storage f_addr;
> +                     struct sockaddr_storage  f_addr;
> +                     struct buffertls         f_buftls;
>                       struct bufferevent      *f_bufev;
> -                     int     f_reconnectwait;
> +                     struct tls              *f_ctx;
> +                     int                      f_reconnectwait;
>               } f_forw;               /* forwarding address */
>               char    f_fname[PATH_MAX];
>               struct {
> @@ -182,11 +186,12 @@ int     repeatinterval[] = { 30, 120, 600 };
>  #define F_MEMBUF     7               /* memory buffer */
>  #define F_PIPE               8               /* pipe to external program */
>  #define F_FORWTCP    9               /* remote machine via TCP */
> +#define F_FORWTLS    10              /* remote machine via TLS */
>  
>  char *TypeNames[] = {
>       "UNUSED",       "FILE",         "TTY",          "CONSOLE",
>       "FORWUDP",      "USERS",        "WALL",         "MEMBUF",
> -     "PIPE",         "FORWTCP",
> +     "PIPE",         "FORWTCP",      "FORWTLS",
>  };
>  
>  SIMPLEQ_HEAD(filed_list, filed) Files;
> @@ -271,6 +276,7 @@ void       tcp_readcb(struct bufferevent *, v
>  void  tcp_writecb(struct bufferevent *, void *);
>  void  tcp_errorcb(struct bufferevent *, short, void *);
>  void  tcp_connectcb(int, short, void *);
> +struct tls *tls_socket(struct filed *);
>  void  die_signalcb(int, short, void *);
>  void  mark_timercb(int, short, void *);
>  void  init_signalcb(int, short, void *);
> @@ -715,8 +721,7 @@ tcp_readcb(struct bufferevent *bufev, vo
>        * Drop data received from the forward log server.
>        */
>       dprintf("loghost \"%s\" did send %zu bytes back\n",
> -         f->f_un.f_forw.f_loghost,
> -         EVBUFFER_LENGTH(f->f_un.f_forw.f_bufev->input));
> +         f->f_un.f_forw.f_loghost, EVBUFFER_LENGTH(bufev->input));
>       evbuffer_drain(bufev->input, -1);
>  }
>  
> @@ -745,10 +750,16 @@ tcp_errorcb(struct bufferevent *bufev, s
>       else
>               snprintf(ebuf, sizeof(ebuf),
>                   "syslogd: loghost \"%s\" connection error: %s",
> -                 f->f_un.f_forw.f_loghost, strerror(errno));
> +                 f->f_un.f_forw.f_loghost, f->f_un.f_forw.f_ctx ?
> +                 tls_error(f->f_un.f_forw.f_ctx) : strerror(errno));
>       dprintf("%s\n", ebuf);
>  
>       /* The SIGHUP handler may also close the socket, so invalidate it. */
> +     if (f->f_un.f_forw.f_ctx) {
> +             tls_close(f->f_un.f_forw.f_ctx);
> +             tls_free(f->f_un.f_forw.f_ctx);
> +             f->f_un.f_forw.f_ctx = NULL;
> +     }
>       close(f->f_file);
>       f->f_file = -1;
>  
> @@ -768,6 +779,7 @@ tcp_connectcb(int fd, short event, void 
>  {
>       struct filed            *f = arg;
>       struct bufferevent      *bufev = f->f_un.f_forw.f_bufev;
> +     struct tls              *ctx;
>       struct timeval           to;
>       int                      s;
>  
> @@ -780,8 +792,9 @@ tcp_connectcb(int fd, short event, void 
>  
>       if ((s = tcp_socket(f)) == -1)
>               goto retry;
> +     dprintf("tcp connect callback: socket success, event %#x\n", event);
> +     f->f_file = s;
>  
> -     dprintf("tcp connect callback: success, event %#x\n", event);
>       bufferevent_setfd(bufev, s);
>       bufferevent_setcb(bufev, tcp_readcb, tcp_writecb, tcp_errorcb, f);
>       /*
> @@ -789,7 +802,20 @@ tcp_connectcb(int fd, short event, void 
>        * the socket to detect connection close and errors.
>        */
>       bufferevent_enable(bufev, EV_READ|EV_WRITE);
> -     f->f_file = s;
> +
> +     if (f->f_type == F_FORWTLS) {
> +             if ((ctx = tls_socket(f)) == NULL) {
> +                     close(f->f_file);
> +                     f->f_file = -1;
> +                     goto retry;
> +             }
> +             dprintf("tcp connect callback: TLS context success\n");
> +             f->f_un.f_forw.f_ctx = ctx;
> +
> +             buffertls_set(&f->f_un.f_forw.f_buftls, bufev, ctx, s);
> +             /* XXX no host given */
> +             buffertls_connect(&f->f_un.f_forw.f_buftls, s, NULL);
> +     }
>  
>       return;
>  
> @@ -808,6 +834,46 @@ tcp_connectcb(int fd, short event, void 
>       evtimer_add(&bufev->ev_write, &to);
>  }
>  
> +struct tls *
> +tls_socket(struct filed *f)
> +{
> +     static struct tls_config *config;
> +     struct tls      *ctx;
> +     char             ebuf[100];
> +
> +     if (config == NULL) {
> +             if (tls_init() < 0) {
> +                     snprintf(ebuf, sizeof(ebuf), "tls_init \"%s\"",
> +                         f->f_un.f_forw.f_loghost);
> +                     logerror(ebuf);
> +                     return (NULL);
> +             }
> +             if ((config = tls_config_new()) == NULL) {
> +                     snprintf(ebuf, sizeof(ebuf), "tls_config_new \"%s\"",
> +                         f->f_un.f_forw.f_loghost);
> +                     logerror(ebuf);
> +                     return (NULL);
> +             }
> +             /* XXX No verify for now, ca certs are outside of privsep. */
> +             tls_config_insecure_noverifyhost(config);
> +             tls_config_insecure_noverifycert(config);
> +     }
> +     if ((ctx = tls_client()) == NULL) {
> +             snprintf(ebuf, sizeof(ebuf), "tls_client \"%s\"",
> +                 f->f_un.f_forw.f_loghost);
> +             logerror(ebuf);
> +             return (NULL);
> +     }
> +     if (tls_configure(ctx, config) < 0) {
> +             snprintf(ebuf, sizeof(ebuf), "tls_configure \"%s\": %s",
> +                 f->f_un.f_forw.f_loghost, tls_error(ctx));
> +             logerror(ebuf);
> +             tls_free(ctx);
> +             return (NULL);
> +     }
> +     return (ctx);
> +}
> +
>  void
>  usage(void)
>  {
> @@ -1114,6 +1180,7 @@ fprintlog(struct filed *f, int flags, ch
>               break;
>  
>       case F_FORWTCP:
> +     case F_FORWTLS:
>               dprintf(" %s\n", f->f_un.f_forw.f_loghost);
>               if (EVBUFFER_LENGTH(f->f_un.f_forw.f_bufev->output) >=
>                   MAX_TCPBUF)
> @@ -1402,6 +1469,12 @@ init(void)
>                       fprintlog(f, 0, (char *)NULL);
>  
>               switch (f->f_type) {
> +             case F_FORWTLS:
> +                     if (f->f_un.f_forw.f_ctx) {
> +                             tls_close(f->f_un.f_forw.f_ctx);
> +                             tls_free(f->f_un.f_forw.f_ctx);
> +                     }
> +                     /* FALLTHROUGH */
>               case F_FORWTCP:
>                       /* XXX Save messages in output buffer for reconnect. */
>                       bufferevent_free(f->f_un.f_forw.f_bufev);
> @@ -1542,6 +1615,7 @@ init(void)
>  
>                       case F_FORWUDP:
>                       case F_FORWTCP:
> +                     case F_FORWTLS:
>                               printf("%s", f->f_un.f_forw.f_loghost);
>                               break;
>  
> @@ -1604,9 +1678,10 @@ cfline(char *line, char *prog)
>  {
>       int i, pri;
>       size_t rb_len;
> -     char *bp, *p, *q, *proto, *host, *port;
> +     char *bp, *p, *q, *proto, *host, *port, *ipproto;
>       char buf[MAXLINE], ebuf[100];
>       struct filed *xf, *f, *d;
> +     struct timeval to;
>  
>       dprintf("cfline(\"%s\", f, \"%s\")\n", line, prog);
>  
> @@ -1714,11 +1789,13 @@ cfline(char *line, char *prog)
>               }
>               if (proto == NULL)
>                       proto = "udp";
> +             ipproto = proto;
>               if (strcmp(proto, "udp") == 0) {
>                       if (fd_udp == -1)
>                               proto = "udp6";
>                       if (fd_udp6 == -1)
>                               proto = "udp4";
> +                     ipproto = proto;
>               } else if (strcmp(proto, "udp4") == 0) {
>                       if (fd_udp == -1) {
>                               snprintf(ebuf, sizeof(ebuf), "no udp4 \"%s\"",
> @@ -1736,6 +1813,12 @@ cfline(char *line, char *prog)
>               } else if (strcmp(proto, "tcp") == 0 ||
>                   strcmp(proto, "tcp4") == 0 || strcmp(proto, "tcp6") == 0) {
>                       ;
> +             } else if (strcmp(proto, "tls") == 0) {
> +                     ipproto = "tcp";
> +             } else if (strcmp(proto, "tls4") == 0) {
> +                     ipproto = "tcp4";
> +             } else if (strcmp(proto, "tls6") == 0) {
> +                     ipproto = "tcp6";
>               } else {
>                       snprintf(ebuf, sizeof(ebuf), "bad protocol \"%s\"",
>                           f->f_un.f_forw.f_loghost);
> @@ -1749,14 +1832,15 @@ cfline(char *line, char *prog)
>                       break;
>               }
>               if (port == NULL)
> -                     port = "syslog";
> +                     port = strncmp(proto, "tls", 3) == 0 ?
> +                         "syslog-tls" : "syslog";
>               if (strlen(port) >= NI_MAXSERV) {
>                       snprintf(ebuf, sizeof(ebuf), "port too long \"%s\"",
>                           f->f_un.f_forw.f_loghost);
>                       logerror(ebuf);
>                       break;
>               }
> -             if (priv_getaddrinfo(proto, host, port,
> +             if (priv_getaddrinfo(ipproto, host, port,
>                   (struct sockaddr*)&f->f_un.f_forw.f_addr,
>                   sizeof(f->f_un.f_forw.f_addr)) != 0) {
>                       snprintf(ebuf, sizeof(ebuf), "bad hostname \"%s\"",
> @@ -1775,7 +1859,7 @@ cfline(char *line, char *prog)
>                               break;
>                       }
>                       f->f_type = F_FORWUDP;
> -             } else if (strncmp(proto, "tcp", 3) == 0) {
> +             } else if (strncmp(ipproto, "tcp", 3) == 0) {
>                       if ((f->f_un.f_forw.f_bufev = bufferevent_new(-1,
>                           tcp_readcb, tcp_writecb, tcp_errorcb, f)) == NULL) {
>                               snprintf(ebuf, sizeof(ebuf),
> @@ -1784,8 +1868,23 @@ cfline(char *line, char *prog)
>                               logerror(ebuf);
>                               break;
>                       }
> -                     f->f_type = F_FORWTCP;
> -                     tcp_connectcb(-1, 0, f);
> +                     if (strncmp(proto, "tls", 3) == 0) {
> +                             f->f_type = F_FORWTLS;
> +                     } else {
> +                             f->f_type = F_FORWTCP;
> +                     }
> +                     /*
> +                      * If we try to connect to a TLS server immediately
> +                      * syslogd gets an SIGPIPE as the signal handlers have
> +                      * not been set up.  Delay the connection until the
> +                      * event loop is started.  We can reuse the write event
> +                      * for that as bufferevent is still disabled.
> +                      */
> +                     to.tv_sec = 0;
> +                     to.tv_usec = 1;
> +                     evtimer_set(&f->f_un.f_forw.f_bufev->ev_write,
> +                         tcp_connectcb, f);
> +                     evtimer_add(&f->f_un.f_forw.f_bufev->ev_write, &to);
>               }
>               break;
>  
> 

-- 

Reply via email to