Imported Upstream version 3.3.2
[debian/amanda] / common-src / security-util.c
index 531ec867b19e033466a53405b8a4c719d44a58f9..e3942e649f433492d843d9c4a1115bfb57ad2715 100644 (file)
 #include "util.h"
 #include "event.h"
 #include "packet.h"
-#include "queue.h"
 #include "security.h"
 #include "security-util.h"
 #include "stream.h"
-#include "version.h"
-
-/* #define     SEC_DEBUG */
-#define        SHOW_SECURITY_DETAIL
-
-#ifdef SEC_DEBUG
-#  define      secprintf(x)    dbprintf(x)
-#else
-#  ifdef __lint
-#    define    secprintf(x)    (void)(x)
-#  else
-#    define    secprintf(x)
-#  endif
-#endif
-
-/*
- * Magic values for sec_conn->handle
- */
-#define        H_TAKEN -1              /* sec_conn->tok was already read */
-#define        H_EOF   -2              /* this connection has been shut down */
+#include "sockaddr-util.h"
 
 /*
  * This is a queue of open connections
  */
-struct connq_s connq = {
-    TAILQ_HEAD_INITIALIZER(connq.tailq), 0
-};
+GSList *connq = NULL;
 static int newhandle = 1;
 static int newevent = 1;
 
@@ -116,17 +94,21 @@ sec_stream_id(
 void
 sec_accept(
     const security_driver_t *driver,
+    char       *(*conf_fn)(char *, void *),
     int                in,
     int                out,
-    void       (*fn)(security_handle_t *, pkt_t *))
+    void       (*fn)(security_handle_t *, pkt_t *),
+    void       *datap)
 {
     struct tcp_conn *rc;
 
-    rc = sec_tcp_conn_get("unknown",0);
+    rc = sec_tcp_conn_get("",0); /* no hostname yet */
     rc->read = in;
     rc->write = out;
     rc->accept_fn = fn;
     rc->driver = driver;
+    rc->conf_fn = conf_fn;
+    rc->datap = datap;
     sec_tcp_conn_read(rc);
 }
 
@@ -141,8 +123,7 @@ sec_close(
 
     assert(rh != NULL);
 
-    secprintf(("%s: sec: closing handle to %s\n", debug_prefix_time(NULL),
-              rh->hostname));
+    auth_debug(1, _("sec: closing handle to %s\n"), rh->hostname);
 
     if (rh->rs != NULL) {
        /* This may be null if we get here on an error */
@@ -219,7 +200,7 @@ stream_sendpkt(
     assert(rh != NULL);
     assert(pkt != NULL);
 
-    secprintf(("%s: sec: stream_sendpkt: enter\n", debug_prefix_time(NULL)));
+    auth_debug(1, _("sec: stream_sendpkt: enter\n"));
 
     if (rh->rc->prefix_packet)
        s = rh->rc->prefix_packet(rh, pkt);
@@ -233,13 +214,13 @@ stream_sendpkt(
     if (strlen(s) > 0)
        amfree(s);
 
-    secprintf((
-           "%s: sec: stream_sendpkt: %s (%d) pkt_t (len %d) contains:\n\n\"%s\"\n\n",
-           debug_prefix_time(NULL), pkt_type2str(pkt->type), pkt->type,
-           strlen(pkt->body), pkt->body));
+    auth_debug(1,
+     _("sec: stream_sendpkt: %s (%d) pkt_t (len %zu) contains:\n\n\"%s\"\n\n"),
+      pkt_type2str(pkt->type), pkt->type, strlen(pkt->body), pkt->body);
 
     if (security_stream_write(&rh->rs->secstr, buf, len) < 0) {
-       security_seterror(&rh->sech, security_stream_geterror(&rh->rs->secstr));
+       security_seterror(&rh->sech, "%s", security_stream_geterror(&rh->rs->secstr));
+       amfree(buf);
        return (-1);
     }
     amfree(buf);
@@ -261,8 +242,7 @@ stream_recvpkt(
 
     assert(rh != NULL);
 
-    secprintf(("%s: sec: recvpkt registered for %s\n",
-              debug_prefix_time(NULL), rh->hostname));
+    auth_debug(1, _("sec: recvpkt registered for %s\n"), rh->hostname);
 
     /*
      * Reset any pending timeout on this handle
@@ -295,8 +275,7 @@ stream_recvpkt_timeout(
 
     assert(rh != NULL);
 
-    secprintf(("%s: sec: recvpkt timeout for %s\n",
-              debug_prefix_time(NULL), rh->hostname));
+    auth_debug(1, _("sec: recvpkt timeout for %s\n"), rh->hostname);
 
     stream_recvpkt_cancel(rh);
     (*rh->fn.recvpkt)(rh->arg, NULL, S_TIMEOUT);
@@ -311,8 +290,7 @@ stream_recvpkt_cancel(
 {
     struct sec_handle *rh = cookie;
 
-    secprintf(("%s: sec: cancelling recvpkt for %s\n",
-              debug_prefix_time(NULL), rh->hostname));
+    auth_debug(1, _("sec: cancelling recvpkt for %s\n"), rh->hostname);
 
     assert(rh != NULL);
 
@@ -337,13 +315,13 @@ tcpm_stream_write(
     assert(rs != NULL);
     assert(rs->rc != NULL);
 
-    secprintf(("%s: sec: stream_write: writing %d bytes to %s:%d %d\n",
-              debug_prefix_time(NULL), size, rs->rc->hostname, rs->handle,
-              rs->rc->write));
+    auth_debug(1, _("sec: stream_write: writing %zu bytes to %s:%d %d\n"),
+                  size, rs->rc->hostname, rs->handle,
+                  rs->rc->write);
 
-    if (tcpm_send_token(rs->rc->write, rs->handle, &rs->rc->errmsg,
+    if (tcpm_send_token(rs->rc, rs->rc->write, rs->handle, &rs->rc->errmsg,
                             buf, size)) {
-       security_stream_seterror(&rs->secstr, rs->rc->errmsg);
+       security_stream_seterror(&rs->secstr, "%s", rs->rc->errmsg);
        return (-1);
     }
     return (0);
@@ -367,7 +345,7 @@ tcpm_stream_read(
      * Only one read request can be active per stream.
      */
     if (rs->ev_read == NULL) {
-       rs->ev_read = event_register((event_id_t)rs->rc, EV_WAIT,
+       rs->ev_read = event_register((event_id_t)rs->rc->event_id, EV_WAIT,
            stream_read_callback, rs);
        sec_tcp_conn_read(rs->rc);
     }
@@ -375,6 +353,10 @@ tcpm_stream_read(
     rs->arg = arg;
 }
 
+/* buffer for tcpm_stream_read_sync function */
+static ssize_t  sync_pktlen;
+static void    *sync_pkt;
+
 /*
  * Write a chunk of data to a stream.  Blocks until completion.
  */
@@ -393,12 +375,15 @@ tcpm_stream_read_sync(
     if (rs->ev_read != NULL) {
        return -1;
     }
-    rs->ev_read = event_register((event_id_t)rs->rc, EV_WAIT,
+    sync_pktlen = 0;
+    sync_pkt = NULL;
+    rs->ev_read = event_register((event_id_t)rs->rc->event_id, EV_WAIT,
         stream_read_sync_callback, rs);
     sec_tcp_conn_read(rs->rc);
     event_wait(rs->ev_read);
-    *buf = rs->rc->pkt;
-    return (rs->rc->pktlen);
+    /* Can't use rs or rc, they can be freed */
+    *buf = sync_pkt;
+    return (sync_pktlen);
 }
 
 /*
@@ -426,19 +411,33 @@ tcpm_stream_read_cancel(
  */
 ssize_t
 tcpm_send_token(
+    struct tcp_conn *rc,
     int                fd,
     int                handle,
     char **    errmsg,
     const void *buf,
     size_t     len)
 {
-    uint32_t           nethandle;
-    uint32_t           netlength;
+    guint32            nethandle;
+    guint32            netlength;
     struct iovec       iov[3];
     int                        nb_iov = 3;
+    int                        rval;
+    char               *encbuf;
+    ssize_t            encsize;
+    int                        save_errno;
+    time_t             logtime;
 
     assert(SIZEOF(netlength) == 4);
 
+    logtime = time(NULL);
+    if (rc && logtime > rc->logstamp + 10) {
+       g_debug("tcpm_send_token: data is still flowing");
+        rc->logstamp = logtime;
+    }
+
+    auth_debug(1, "tcpm_send_token: write %zd bytes to handle %d\n",
+              len, handle);
     /*
      * Format is:
      *   32 bit length (network byte order)
@@ -449,29 +448,47 @@ tcpm_send_token(
     iov[0].iov_base = (void *)&netlength;
     iov[0].iov_len = SIZEOF(netlength);
 
-    nethandle = htonl((uint32_t)handle);
+    nethandle = htonl((guint32)handle);
     iov[1].iov_base = (void *)&nethandle;
     iov[1].iov_len = SIZEOF(nethandle);
 
+    encbuf = (char *)buf;
+    encsize = len;
+
     if(len == 0) {
        nb_iov = 2;
     }
     else {
-       iov[2].iov_base = (void *)buf;
-       iov[2].iov_len = len;
+       if (rc->driver->data_encrypt == NULL) {
+           iov[2].iov_base = (void *)buf;
+           iov[2].iov_len = len;
+       } else {
+           /* (the extra (void *) cast is to quiet type-punning warnings) */
+           rc->driver->data_encrypt(rc, (void *)buf, len, (void **)(void *)&encbuf, &encsize);
+           iov[2].iov_base = (void *)encbuf;
+           iov[2].iov_len = encsize;
+           netlength = htonl(encsize);
+       }
         nb_iov = 3;
     }
 
-    if (net_writev(fd, iov, nb_iov) < 0) {
+    rval = full_writev(fd, iov, nb_iov);
+    save_errno = errno;
+    if (len != 0 && rc->driver->data_encrypt != NULL && buf != encbuf) {
+       amfree(encbuf);
+    }
+
+    if (rval < 0) {
        if (errmsg)
-            *errmsg = newvstralloc(*errmsg, "write error to ",
-                                  ": ", strerror(errno), NULL);
+            *errmsg = newvstrallocf(*errmsg, _("write error to: %s"),
+                                  strerror(save_errno));
         return (-1);
     }
     return (0);
 }
 
 /*
+ *  return -2 for incomplete packet
  *  return -1 on error
  *  return  0 on EOF:   *handle = H_EOF  && *size = 0    if socket closed
  *  return  0 on EOF:   *handle = handle && *size = 0    if stream closed
@@ -480,76 +497,137 @@ tcpm_send_token(
 
 ssize_t
 tcpm_recv_token(
+    struct tcp_conn    *rc,
     int                fd,
     int *      handle,
     char **    errmsg,
     char **    buf,
-    ssize_t *  size,
-    int                timeout)
+    ssize_t *  size)
 {
-    unsigned int netint[2];
+    ssize_t     rval;
+
+    assert(SIZEOF(rc->netint) == 8);
+    if (rc->size_header_read < (ssize_t)SIZEOF(rc->netint)) {
+       rval = read(fd, ((char *)&rc->netint) + rc->size_header_read,
+                       SIZEOF(rc->netint) - rc->size_header_read);
+       if (rval == -1) {
+           if (errmsg)
+               *errmsg = newvstrallocf(*errmsg, _("recv error: %s"),
+                                       strerror(errno));
+           auth_debug(1, _("tcpm_recv_token: A return(-1)\n"));
+           return(-1);
+       } else if (rval == 0) {
+           *size = 0;
+           *handle = H_EOF;
+           *errmsg = newvstrallocf(*errmsg, _("SOCKET_EOF"));
+           auth_debug(1, _("tcpm_recv_token: A return(0)\n"));
+           return(0);
+       } else if (rval < (ssize_t)SIZEOF(rc->netint) - rc->size_header_read) {
+           rc->size_header_read += rval;
+           return(-2);
+       }
+       rc->size_header_read += rval;
+        amfree(rc->buffer);
+       *size = (ssize_t)ntohl(rc->netint[0]);
+       *handle = (int)ntohl(rc->netint[1]);
+        rc->buffer = NULL;
+       rc->size_buffer_read = 0;
+
+       /* amanda protocol packet can be above NETWORK_BLOCK_BYTES */
+       if (*size > 128*NETWORK_BLOCK_BYTES || *size < 0) {
+           if (isprint((int)(*size        ) & 0xFF) &&
+               isprint((int)(*size   >> 8 ) & 0xFF) &&
+               isprint((int)(*size   >> 16) & 0xFF) &&
+               isprint((int)(*size   >> 24) & 0xFF) &&
+               isprint((*handle      ) & 0xFF) &&
+               isprint((*handle >> 8 ) & 0xFF) &&
+               isprint((*handle >> 16) & 0xFF) &&
+               isprint((*handle >> 24) & 0xFF)) {
+               char s[201];
+               char *s1;
+               int i;
+               s[0] = ((int)(*size)  >> 24) & 0xFF;
+               s[1] = ((int)(*size)  >> 16) & 0xFF;
+               s[2] = ((int)(*size)  >>  8) & 0xFF;
+               s[3] = ((int)(*size)       ) & 0xFF;
+               s[4] = (*handle >> 24) & 0xFF;
+               s[5] = (*handle >> 16) & 0xFF;
+               s[6] = (*handle >> 8 ) & 0xFF;
+               s[7] = (*handle      ) & 0xFF;
+               i = 8; s[i] = ' ';
+               while(i<200 && isprint((int)s[i]) && s[i] != '\n') {
+                   switch(net_read(fd, &s[i], 1, 0)) {
+                   case -1: s[i] = '\0'; break;
+                   case  0: s[i] = '\0'; break;
+                   default:
+                        dbprintf(_("read: %c\n"), s[i]); i++; s[i]=' ';
+                        break;
+                   }
+               }
+               s[i] = '\0';
+               s1 = quote_string(s);
+               *errmsg = newvstrallocf(*errmsg,
+                               _("tcpm_recv_token: invalid size: %s"), s1);
+               dbprintf(_("tcpm_recv_token: invalid size %s\n"), s1);
+               amfree(s1);
+           } else {
+               *errmsg = newvstrallocf(*errmsg,
+                                       _("tcpm_recv_token: invalid size"));
+               dbprintf(_("tcpm_recv_token: invalid size %zd\n"), *size);
+           }
+           *size = -1;
+           return -1;
+       }
+        rc->buffer = alloc((size_t)*size);
+
+       if (*size == 0) {
+           auth_debug(1, _("tcpm_recv_token: read EOF from %d\n"), *handle);
+           *errmsg = newvstrallocf(*errmsg, _("EOF"));
+           rc->size_header_read = 0;
+           return 0;
+       }
+    }
 
-    assert(SIZEOF(netint) == 8);
+    *size = (ssize_t)ntohl(rc->netint[0]);
+    *handle = (int)ntohl(rc->netint[1]);
 
-    switch (net_read(fd, &netint, SIZEOF(netint), timeout)) {
-    case -1:
+    rval = read(fd, rc->buffer + rc->size_buffer_read,
+                   (size_t)*size - rc->size_buffer_read);
+    if (rval == -1) {
        if (errmsg)
-           *errmsg = newvstralloc(*errmsg, "recv error: ", strerror(errno),
-                                  NULL);
-       secprintf(("%s: tcpm_recv_token: A return(-1)\n",
-                  debug_prefix_time(NULL)));
+           *errmsg = newvstrallocf(*errmsg, _("recv error: %s"),
+                                   strerror(errno));
+       auth_debug(1, _("tcpm_recv_token: B return(-1)\n"));
        return (-1);
-    case 0:
+    } else if (rval == 0) {
        *size = 0;
-       *handle = H_EOF;
-       *errmsg = newvstralloc(*errmsg, "SOCKET_EOF", NULL);
-       secprintf(("%s: tcpm_recv_token: A return(0)\n",
-                  debug_prefix_time(NULL)));
+       *errmsg = newvstrallocf(*errmsg, _("SOCKET_EOF"));
+       auth_debug(1, _("tcpm_recv_token: B return(0)\n"));
        return (0);
-    default:
-       break;
-    }
-
-    *size = (ssize_t)ntohl(netint[0]);
-    if (*size > NETWORK_BLOCK_BYTES) {
-       *errmsg = newvstralloc(*errmsg, "tcpm_recv_token: invalid size",
-                                  NULL);
-       dbprintf(("%s: tcpm_recv_token: invalid size %d\n",
-                  debug_prefix_time(NULL), *size));
-       *size = -1;
-       return -1;
+    } else if (rval < (ssize_t)*size - rc->size_buffer_read) {
+       rc->size_buffer_read += rval;
+       return (-2);
     }
+    rc->size_buffer_read += rval;
     amfree(*buf);
-    *buf = alloc((size_t)*size);
-    *handle = (int)ntohl(netint[1]);
-
-    if(*size == 0) {
-       secprintf(("%s: tcpm_recv_token: read EOF from %d\n",
-                  debug_prefix_time(NULL), *handle));
-       *errmsg = newvstralloc(*errmsg, "EOF",
-                                  NULL);
-       return 0;
-    }
-    switch (net_read(fd, *buf, (size_t)*size, timeout)) {
-    case -1:
-       if (errmsg)
-           *errmsg = newvstralloc(*errmsg, "recv error: ", strerror(errno),
-                                  NULL);
-       secprintf(("%s: tcpm_recv_token: B return(-1)\n",
-                  debug_prefix_time(NULL)));
-       return (-1);
-    case 0:
-       *size = 0;
-       *errmsg = newvstralloc(*errmsg, "SOCKET_EOF", NULL);
-       secprintf(("%s: tcpm_recv_token: B return(0)\n",
-                  debug_prefix_time(NULL)));
-       return (0);
-    default:
-       break;
+    *buf = rc->buffer;
+    rc->size_header_read = 0;
+    rc->size_buffer_read = 0;
+    rc->buffer = NULL;
+
+    auth_debug(1, _("tcpm_recv_token: read %zd bytes from %d\n"), *size, *handle);
+
+    if (*size > 0 && rc->driver->data_decrypt != NULL) {
+       void *decbuf;
+       ssize_t decsize;
+       rc->driver->data_decrypt(rc, *buf, *size, &decbuf, &decsize);
+       if (*buf != (char *)decbuf) {
+           amfree(*buf);
+           *buf = (char *)decbuf;
+       }
+       *size = decsize;
     }
 
-    secprintf(("%s: tcpm_recv_token: read %ld bytes from %d\n",
-              debug_prefix_time(NULL), *size, *handle));
     return((*size));
 }
 
@@ -560,9 +638,9 @@ tcpm_close_connection(
 {
     struct sec_handle *rh = h;
 
-    hostname = hostname;
+    (void)hostname;
 
-    if(rh->rc->toclose == 0) {
+    if (rh && rh->rc && rh->rc->read >= 0 && rh->rc->toclose == 0) {
        rh->rc->toclose = 1;
        sec_tcp_conn_put(rh->rc);
     }
@@ -599,11 +677,11 @@ tcpma_stream_client(
 
     if (id <= 0) {
        security_seterror(&rh->sech,
-           "%hd: invalid security stream id", id);
+           _("%d: invalid security stream id"), id);
        return (NULL);
     }
 
-    rs = alloc(SIZEOF(*rs));
+    rs = g_new0(struct sec_stream, 1);
     security_streaminit(&rs->secstr, rh->sech.driver);
     rs->handle = id;
     rs->ev_read = NULL;
@@ -619,8 +697,7 @@ tcpma_stream_client(
        rh->rc = rs->rc;
     }
 
-    secprintf(("%s: sec: stream_client: connected to stream %hd\n",
-              debug_prefix_time(NULL), id));
+    auth_debug(1, _("sec: stream_client: connected to stream %d\n"), id);
 
     return (rs);
 }
@@ -638,7 +715,7 @@ tcpma_stream_server(
 
     assert(rh != NULL);
 
-    rs = alloc(SIZEOF(*rs));
+    rs = g_new0(struct sec_stream, 1);
     security_streaminit(&rs->secstr, rh->sech.driver);
     rs->closed_by_me = 0;
     rs->closed_by_network = 0;
@@ -657,20 +734,17 @@ tcpma_stream_server(
     if (rs->rc->read < 0) {
        sec_tcp_conn_put(rs->rc);
        amfree(rs);
-       security_seterror(&rh->sech, "lost connection to %s", rh->hostname);
+       security_seterror(&rh->sech, _("lost connection to %s"), rh->hostname);
        return (NULL);
     }
     assert(strcmp(rh->hostname, rs->rc->hostname) == 0);
-    //amfree(rh->hostname);
-    //rh->hostname = stralloc(rs->rc->hostname);
     /*
      * so as not to conflict with the amanda server's handle numbers,
      * we start at 500000 and work down
      */
     rs->handle = 500000 - newhandle++;
     rs->ev_read = NULL;
-    secprintf(("%s: sec: stream_server: created stream %d\n",
-              debug_prefix_time(NULL), rs->handle));
+    auth_debug(1, _("sec: stream_server: created stream %d\n"), rs->handle);
     return (rs);
 }
 
@@ -686,14 +760,14 @@ tcpma_stream_close(
 
     assert(rs != NULL);
 
-    secprintf(("%s: sec: tcpma_stream_close: closing stream %d\n",
-              debug_prefix_time(NULL), rs->handle));
+    auth_debug(1, _("sec: tcpma_stream_close: closing stream %d\n"), rs->handle);
 
     if(rs->closed_by_network == 0 && rs->rc->write != -1)
        tcpm_stream_write(rs, &buf, 0);
     security_stream_read_cancel(&rs->secstr);
     if(rs->closed_by_network == 0)
        sec_tcp_conn_put(rs->rc);
+    amfree(((security_stream_t *)rs)->error);
     amfree(rs);
 }
 
@@ -710,7 +784,7 @@ tcp1_stream_server(
 
     assert(rh != NULL);
 
-    rs = alloc(SIZEOF(*rs));
+    rs = g_new0(struct sec_stream, 1);
     security_streaminit(&rs->secstr, rh->sech.driver);
     rs->closed_by_me = 0;
     rs->closed_by_network = 0;
@@ -724,11 +798,11 @@ tcp1_stream_server(
        rh->rc = sec_tcp_conn_get(rh->hostname, 1);
        rh->rc->driver = rh->sech.driver;
        rs->rc = rh->rc;
-       rs->socket = stream_server(&rs->port, STREAM_BUFSIZE, 
-               STREAM_BUFSIZE, 0);
+       rs->socket = stream_server(SU_GET_FAMILY(&rh->udp->peer), &rs->port,
+                                  STREAM_BUFSIZE, STREAM_BUFSIZE, 0);
        if (rs->socket < 0) {
            security_seterror(&rh->sech,
-                           "can't create server stream: %s", strerror(errno));
+                           _("can't create server stream: %s"), strerror(errno));
            amfree(rs);
            return (NULL);
        }
@@ -759,7 +833,7 @@ tcp1_stream_accept(
        bs->fd = stream_accept(bs->socket, 30, STREAM_BUFSIZE, STREAM_BUFSIZE);
        if (bs->fd < 0) {
            security_stream_seterror(&bs->secstr,
-                                    "can't accept new stream connection: %s",
+                                    _("can't accept new stream connection: %s"),
                                     strerror(errno));
            return (-1);
        }
@@ -782,7 +856,7 @@ tcp1_stream_client(
 
     assert(rh != NULL);
 
-    rs = alloc(SIZEOF(*rs));
+    rs = g_new0(struct sec_stream, 1);
     security_streaminit(&rs->secstr, rh->sech.driver);
     rs->handle = id;
     rs->ev_read = NULL;
@@ -794,12 +868,13 @@ tcp1_stream_client(
     }
     else {
        rh->rc = sec_tcp_conn_get(rh->hostname, 1);
+       rh->rc->driver = rh->sech.driver;
        rs->rc = rh->rc;
        rh->rc->read = stream_client(rh->hostname, (in_port_t)id,
                        STREAM_BUFSIZE, STREAM_BUFSIZE, &rs->port, 0);
        if (rh->rc->read < 0) {
            security_seterror(&rh->sech,
-                             "can't connect stream to %s port %d: %s",
+                             _("can't connect stream to %s port %d: %s"),
                               rh->hostname, id, strerror(errno));
            amfree(rs);
            return (NULL);
@@ -818,12 +893,19 @@ tcp_stream_write(
     size_t     size)
 {
     struct sec_stream *rs = s;
+    time_t             logtime;
 
     assert(rs != NULL);
 
-    if (fullwrite(rs->fd, buf, size) < 0) {
+    logtime = time(NULL);
+    if (rs && rs->rc && logtime > rs->rc->logstamp + 10) {
+       g_debug("tcp_stream_write: data is still flowing");
+       rs->rc->logstamp = logtime;
+    }
+
+    if (full_write(rs->fd, buf, size) < size) {
         security_stream_seterror(&rs->secstr,
-            "write error on stream %d: %s", rs->port, strerror(errno));
+            _("write error on stream %d: %s"), rs->port, strerror(errno));
         return (-1);
     }
     return (0);
@@ -841,11 +923,11 @@ bsd_prefix_packet(
     if (pkt->type != P_REQ)
        return "";
 
-    if ((pwd = getpwuid(getuid())) == NULL) {
+    if ((pwd = getpwuid(geteuid())) == NULL) {
        security_seterror(&rh->sech,
-                         "can't get login name for my uid %ld",
-                         (long)getuid());
-       return(NULL);
+                         _("can't get login name for my uid %ld"),
+                         (long)geteuid());
+       return "";
     }
     buf = alloc(16+strlen(pwd->pw_name));
     strncpy(buf, "SECURITY USER ", (16 + strlen(pwd->pw_name)));
@@ -869,13 +951,15 @@ bsd_recv_security_ok(
     char *tok, *security, *body, *result;
     char *service = NULL, *serviceX, *serviceY;
     char *security_line;
+    char *s, ch;
     size_t len;
+    in_port_t port;
 
     /*
      * Now, find the SECURITY line in the body, and parse it out
      * into an argv.
      */
-    if (strncmp(pkt->body, "SECURITY ", SIZEOF("SECURITY ") - 1) == 0) {
+    if (strncmp_const(pkt->body, "SECURITY ") == 0) {
        security = pkt->body;
        len = 0;
        while(*security != '\n' && len < pkt->size) {
@@ -902,8 +986,10 @@ bsd_recv_security_ok(
      * Now, find the SERVICE line in the body, and parse it out
      * into an argv.
      */
-    if (strncmp(body, "SERVICE", SIZEOF("SERVICE") - 1) == 0) {
-       serviceX = stralloc(body + strlen("SERVICE "));
+    s = body;
+    if (strncmp_const_skip(s, "SERVICE ", s, ch) == 0) {
+       ch=ch;
+       serviceX = stralloc(s);
        serviceY = strtok(serviceX, "\n");
        if (serviceY)
            service  = stralloc(serviceY);
@@ -919,10 +1005,11 @@ bsd_recv_security_ok(
        /*
         * Request packets must come from a reserved port
         */
-       if (ntohs(rh->peer.sin_port) >= IPPORT_RESERVED) {
+    port = SU_GET_PORT(&rh->peer);
+       if (port >= IPPORT_RESERVED) {
            security_seterror(&rh->sech,
-               "host %s: port %d not secure", rh->hostname,
-               ntohs(rh->peer.sin_port));
+               _("host %s: port %u not secure"), rh->hostname,
+               (unsigned int)port);
            amfree(service);
            amfree(security_line);
            return (-1);
@@ -930,7 +1017,7 @@ bsd_recv_security_ok(
 
        if (!service) {
            security_seterror(&rh->sech,
-                             "packet as no SERVICE line");
+                             _("packet as no SERVICE line"));
            amfree(security_line);
            return (-1);
        }
@@ -946,7 +1033,7 @@ bsd_recv_security_ok(
        /* there must be some security info */
        if (security == NULL) {
            security_seterror(&rh->sech,
-               "no bsd SECURITY for P_REQ");
+               _("no bsd SECURITY for P_REQ"));
            amfree(service);
            return (-1);
        }
@@ -954,14 +1041,14 @@ bsd_recv_security_ok(
        /* second word must be USER */
        if ((tok = strtok(security, " ")) == NULL) {
            security_seterror(&rh->sech,
-               "SECURITY line: %s", security_line);
+               _("SECURITY line: %s"), security_line);
            amfree(service);
            amfree(security_line);
            return (-1);        /* default errmsg */
        }
        if (strcmp(tok, "USER") != 0) {
            security_seterror(&rh->sech,
-               "REQ SECURITY line parse error, expecting USER, got %s", tok);
+               _("REQ SECURITY line parse error, expecting USER, got %s"), tok);
            amfree(service);
            amfree(security_line);
            return (-1);
@@ -970,7 +1057,8 @@ bsd_recv_security_ok(
        /* the third word is the username */
        if ((tok = strtok(NULL, "")) == NULL) {
            security_seterror(&rh->sech,
-               "SECURITY line: %s", security_line);
+               _("SECURITY line: %s"), security_line);
+           amfree(service);
            amfree(security_line);
            return (-1);        /* default errmsg */
        }
@@ -1013,12 +1101,12 @@ udpbsd_sendpkt(
     assert(rh != NULL);
     assert(pkt != NULL);
 
-    secprintf(("%s: udpbsd_sendpkt: enter\n", get_pname()));
+    auth_debug(1, _("udpbsd_sendpkt: enter\n"));
     /*
      * Initialize this datagram, and add the header
      */
     dgram_zero(&rh->udp->dgram);
-    dgram_cat(&rh->udp->dgram, pkthdr2str(rh, pkt));
+    dgram_cat(&rh->udp->dgram, "%s", pkthdr2str(rh, pkt));
 
     /*
      * Add the security info.  This depends on which kind of packet we're
@@ -1031,10 +1119,10 @@ udpbsd_sendpkt(
         */
        if ((pwd = getpwuid(geteuid())) == NULL) {
            security_seterror(&rh->sech,
-               "can't get login name for my uid %ld", (long)getuid());
+               _("can't get login name for my uid %ld"), (long)getuid());
            return (-1);
        }
-       dgram_cat(&rh->udp->dgram, "SECURITY USER %s\n", pwd->pw_name);
+       dgram_cat(&rh->udp->dgram, _("SECURITY USER %s\n"), pwd->pw_name);
        break;
 
     default:
@@ -1044,16 +1132,15 @@ udpbsd_sendpkt(
     /*
      * Add the body, and send it
      */
-    dgram_cat(&rh->udp->dgram, pkt->body);
+    dgram_cat(&rh->udp->dgram, "%s", pkt->body);
 
-    secprintf((
-           "%s: sec: udpbsd_sendpkt: %s (%d) pkt_t (len %d) contains:\n\n\"%s\"\n\n",
-           debug_prefix_time(NULL), pkt_type2str(pkt->type), pkt->type,
-           strlen(pkt->body), pkt->body));
+    auth_debug(1,
+     _("sec: udpbsd_sendpkt: %s (%d) pkt_t (len %zu) contains:\n\n\"%s\"\n\n"),
+      pkt_type2str(pkt->type), pkt->type, strlen(pkt->body), pkt->body);
 
-    if (dgram_send_addr(rh->peer, &rh->udp->dgram) != 0) {
+    if (dgram_send_addr(&rh->peer, &rh->udp->dgram) != 0) {
        security_seterror(&rh->sech,
-           "send %s to %s failed: %s", pkt_type2str(pkt->type),
+           _("send %s to %s failed: %s"), pkt_type2str(pkt->type),
            rh->hostname, strerror(errno));
        return (-1);
     }
@@ -1070,8 +1157,7 @@ udp_close(
        return;
     }
 
-    secprintf(("%s: udp: close handle '%s'\n",
-              debug_prefix_time(NULL), rh->proto_handle));
+    auth_debug(1, _("udp: close handle '%s'\n"), rh->proto_handle);
 
     udp_recvpkt_cancel(rh);
     if (rh->next) {
@@ -1105,8 +1191,8 @@ udp_recvpkt(
 {
     struct sec_handle *rh = cookie;
 
-    secprintf(("%s: udp_recvpkt(cookie=%p, fn=%p, arg=%p, timeout=%u)\n",
-       debug_prefix(NULL), cookie, fn, arg, timeout));
+    auth_debug(1, _("udp_recvpkt(cookie=%p, fn=%p, arg=%p, timeout=%u)\n"),
+                  cookie, fn, arg, timeout);
     assert(rh != NULL);
     assert(fn != NULL);
 
@@ -1167,17 +1253,19 @@ udp_recvpkt_callback(
     void (*fn)(void *, pkt_t *, security_status_t);
     void *arg;
 
-    secprintf(("%s: udp: receive handle '%s' netfd '%s'\n",
-              debug_prefix_time(NULL), rh->proto_handle, rh->udp->handle));
+    auth_debug(1, _("udp: receive handle '%s' netfd '%s'\n"),
+                  rh->proto_handle, rh->udp->handle);
     assert(rh != NULL);
 
-    if (strcmp(rh->proto_handle, rh->udp->handle) != 0) assert(1);
+    /* if it doesn't correspond to this handle, something is wrong */
+    assert(strcmp(rh->proto_handle, rh->udp->handle) == 0);
+
     /* if it didn't come from the same host/port, forget it */
-    if (memcmp(&rh->peer.sin_addr, &rh->udp->peer.sin_addr,
-       SIZEOF(rh->udp->peer.sin_addr)) != 0 ||
-       rh->peer.sin_port != rh->udp->peer.sin_port) {
+    if (cmp_sockaddr(&rh->peer, &rh->udp->peer, 0) != 0) {
        amfree(rh->udp->handle);
-       //rh->udp->handle = NULL;
+       dbprintf(_("not from same host\n"));
+       dump_sockaddr(&rh->peer);
+       dump_sockaddr(&rh->udp->peer);
        return;
     }
 
@@ -1194,10 +1282,11 @@ udp_recvpkt_callback(
      * to the packet handling function instead of a packet.
      */
     if (rh->udp->recv_security_ok &&
-       rh->udp->recv_security_ok(rh, &rh->udp->pkt) < 0)
+       rh->udp->recv_security_ok(rh, &rh->udp->pkt) < 0) {
        (*fn)(arg, NULL, S_ERROR);
-    else
+    } else {
        (*fn)(arg, &rh->udp->pkt, S_OK);
+    }
 }
 
 /*
@@ -1227,81 +1316,23 @@ int
 udp_inithandle(
     udp_handle_t *     udp,
     struct sec_handle *        rh,
-    struct hostent *   he,
+    char *              hostname,
+    sockaddr_union *addr,
     in_port_t          port,
     char *             handle,
     int                        sequence)
 {
-    int i;
-
     /*
      * Save the hostname and port info
      */
-    secprintf(("%s: udp_inithandle port %hd handle %s sequence %d\n",
-              debug_prefix_time(NULL), ntohs(port),
-              handle, sequence));
-    assert(he != NULL);
+    auth_debug(1, _("udp_inithandle port %u handle %s sequence %d\n"),
+                  (unsigned int)ntohs(port), handle, sequence);
+    assert(addr != NULL);
 
-    rh->hostname = stralloc(he->h_name);
-    memcpy(&rh->peer.sin_addr, he->h_addr, SIZEOF(rh->peer.sin_addr));
-    rh->peer.sin_port = port;
-    rh->peer.sin_family = (sa_family_t)AF_INET;
+    rh->hostname = stralloc(hostname);
+    copy_sockaddr(&rh->peer, addr);
+    SU_SET_PORT(&rh->peer, port);
 
-    /*
-     * Do a forward lookup of the hostname.  This is unnecessary if we
-     * are initiating the connection, but is very serious if we are
-     * receiving.  We want to make sure the hostname
-     * resolves back to the remote ip for security reasons.
-     */
-    if ((he = gethostbyname(rh->hostname)) == NULL) {
-    secprintf(("%s: udp: bb\n", debug_prefix_time(NULL)));
-       security_seterror(&rh->sech,
-           "%s: could not resolve hostname", rh->hostname);
-       return (-1);
-    }
-
-    /*
-     * Make sure the hostname matches.  This should always work.
-     */
-    if (strncasecmp(rh->hostname, he->h_name, strlen(rh->hostname)) != 0) {
-    secprintf(("%s: udp: cc\n", debug_prefix_time(NULL)));
-       security_seterror(&rh->sech,
-                         "%s: did not resolve to itself, it resolv to",
-                         rh->hostname, he->h_name);
-       return (-1);
-    }
-
-    /*
-     * Now look for a matching ip address.
-     */
-    for (i = 0; he->h_addr_list[i] != NULL; i++) {
-       if (memcmp(&rh->peer.sin_addr, he->h_addr_list[i],
-           SIZEOF(struct in_addr)) == 0) {
-           break;
-       }
-    }
-
-    /*
-     * If we didn't find it, try the aliases.  This is a workaround for
-     * Solaris if DNS goes over NIS.
-     */
-    if (he->h_addr_list[i] == NULL) {
-       const char *ipstr = inet_ntoa(rh->peer.sin_addr);
-       for (i = 0; he->h_aliases[i] != NULL; i++) {
-           if (strcmp(he->h_aliases[i], ipstr) == 0)
-               break;
-       }
-       /*
-        * No aliases either.  Failure.  Someone is fooling with us or
-        * DNS is messed up.
-        */
-       if (he->h_aliases[i] == NULL) {
-           security_seterror(&rh->sech,
-               "DNS check failed: no matching ip address for %s",
-               rh->hostname);
-           return (-1);
-       }
-    }
 
     rh->prev = udp->bh_last;
     if (udp->bh_last) {
@@ -1322,8 +1353,7 @@ udp_inithandle(
     rh->ev_read = NULL;
     rh->ev_timeout = NULL;
 
-    secprintf(("%s: udp: adding handle '%s'\n",
-              debug_prefix_time(NULL), rh->proto_handle));
+    auth_debug(1, _("udp: adding handle '%s'\n"), rh->proto_handle);
 
     return(0);
 }
@@ -1340,11 +1370,13 @@ udp_netfd_read_callback(
 {
     struct udp_handle *udp = cookie;
     struct sec_handle *rh;
-    struct hostent *he;
     int a;
+    char hostname[NI_MAXHOST];
+    in_port_t port;
+    char *errmsg = NULL;
+    int result;
 
-    secprintf(("%s: udp_netfd_read_callback(cookie=%p)\n",
-               debug_prefix(NULL), cookie));
+    auth_debug(1, _("udp_netfd_read_callback(cookie=%p)\n"), cookie);
     assert(udp != NULL);
     
 #ifndef TEST                                                   /* { */
@@ -1368,8 +1400,7 @@ udp_netfd_read_callback(
     rh = udp->bh_first;
     while(rh != NULL && (strcmp(rh->proto_handle, udp->handle) != 0 ||
                         rh->sequence != udp->sequence ||
-                        rh->peer.sin_addr.s_addr != udp->peer.sin_addr.s_addr ||
-                        rh->peer.sin_port != udp->peer.sin_port)) {
+                        cmp_sockaddr(&rh->peer, &udp->peer, 0) != 0)) {
        rh = rh->next;
     }
     if (rh && event_wakeup(rh->event_id) > 0)
@@ -1379,26 +1410,43 @@ udp_netfd_read_callback(
      * If we didn't find a handle, then check for a new incoming packet.
      * If no accept handler was setup, then just return.
      */
-    if (udp->accept_fn == NULL)
+    if (udp->accept_fn == NULL) {
+       dbprintf(_("Receive packet from unknown source"));
        return;
+    }
 
-    he = gethostbyaddr((void *)&udp->peer.sin_addr,
-       (socklen_t)sizeof(udp->peer.sin_addr), AF_INET);
-    if (he == NULL)
-       return;
-    rh = alloc(SIZEOF(*rh));
+    rh = g_new0(struct sec_handle, 1);
     rh->proto_handle=NULL;
     rh->udp = udp;
     rh->rc = NULL;
     security_handleinit(&rh->sech, udp->driver);
+
+    result = getnameinfo((struct sockaddr *)&udp->peer, SS_LEN(&udp->peer),
+                        hostname, sizeof(hostname), NULL, 0, 0);
+    if (result != 0) {
+       dbprintf("getnameinfo failed: %s\n",
+                 gai_strerror(result));
+       security_seterror(&rh->sech, "getnameinfo failed: %s",
+                         gai_strerror(result));
+       return;
+    }
+    if (check_name_give_sockaddr(hostname,
+                                (struct sockaddr *)&udp->peer, &errmsg) < 0) {
+       security_seterror(&rh->sech, "%s",errmsg);
+       amfree(errmsg);
+       amfree(rh);
+       return;
+    }
+
+    port = SU_GET_PORT(&udp->peer);
     a = udp_inithandle(udp, rh,
-                  he,
-                  udp->peer.sin_port,
+                  hostname,
+                  &udp->peer,
+                  port,
                   udp->handle,
                   udp->sequence);
     if (a < 0) {
-       secprintf(("%s: bsd: closeX handle '%s'\n",
-                 debug_prefix_time(NULL), rh->proto_handle));
+       auth_debug(1, _("bsd: closeX handle '%s'\n"), rh->proto_handle);
 
        amfree(rh);
        return;
@@ -1423,31 +1471,32 @@ sec_tcp_conn_get(
     const char *hostname,
     int                want_new)
 {
-    struct tcp_conn *rc;
+    GSList *iter;
+    struct tcp_conn *rc = NULL;
 
-    secprintf(("%s: sec_tcp_conn_get: %s\n", debug_prefix_time(NULL), hostname));
+    auth_debug(1, _("sec_tcp_conn_get: %s\n"), hostname);
 
     if (want_new == 0) {
-    for (rc = connq_first(); rc != NULL; rc = connq_next(rc)) {
-       if (strcasecmp(hostname, rc->hostname) == 0)
-           break;
-    }
+       for (iter = connq; iter != NULL; iter = iter->next) {
+           rc = (struct tcp_conn *)iter->data;
+           if (strcasecmp(hostname, rc->hostname) == 0)
+               break;
+       }
 
-    if (rc != NULL) {
-       rc->refcnt++;
-       secprintf(("%s: sec_tcp_conn_get: exists, refcnt to %s is now %d\n",
-                  debug_prefix_time(NULL),
-                  rc->hostname, rc->refcnt));
-       return (rc);
-    }
+       if (iter != NULL) {
+           rc->refcnt++;
+           auth_debug(1,
+                     _("sec_tcp_conn_get: exists, refcnt to %s is now %d\n"),
+                      rc->hostname, rc->refcnt);
+           return (rc);
+       }
     }
 
-    secprintf(("%s: sec_tcp_conn_get: creating new handle\n",
-              debug_prefix_time(NULL)));
+    auth_debug(1, _("sec_tcp_conn_get: creating new handle\n"));
     /*
      * We can't be creating a new handle if we are the client
      */
-    rc = alloc(SIZEOF(*rc));
+    rc = g_new0(struct tcp_conn, 1);
     rc->read = rc->write = -1;
     rc->driver = NULL;
     rc->pid = -1;
@@ -1463,7 +1512,11 @@ sec_tcp_conn_get(
     rc->accept_fn = NULL;
     rc->recv_security_ok = NULL;
     rc->prefix_packet = NULL;
-    connq_append(rc);
+    rc->auth = 0;
+    rc->conf_fn = NULL;
+    rc->datap = NULL;
+    rc->event_id = newevent++;
+    connq = g_slist_append(connq, rc);
     return (rc);
 }
 
@@ -1479,14 +1532,12 @@ sec_tcp_conn_put(
 
     assert(rc->refcnt > 0);
     --rc->refcnt;
-    secprintf(("%s: sec_tcp_conn_put: decrementing refcnt for %s to %d\n",
-              debug_prefix_time(NULL),
-       rc->hostname, rc->refcnt));
+    auth_debug(1, _("sec_tcp_conn_put: decrementing refcnt for %s to %d\n"),
+                  rc->hostname, rc->refcnt);
     if (rc->refcnt > 0) {
        return;
     }
-    secprintf(("%s: sec_tcp_conn_put: closing connection to %s\n",
-              debug_prefix_time(NULL), rc->hostname));
+    auth_debug(1, _("sec_tcp_conn_put: closing connection to %s\n"), rc->hostname);
     if (rc->read != -1)
        aclose(rc->read);
     if (rc->write != -1)
@@ -1498,12 +1549,15 @@ sec_tcp_conn_put(
        event_release(rc->ev_read);
     if (rc->errmsg != NULL)
        amfree(rc->errmsg);
-    connq_remove(rc);
+    connq = g_slist_remove(connq, rc);
     amfree(rc->pkt);
-    if(!rc->donotclose)
-       amfree(rc); /* someone might still use it           */
-                   /* eg. in sec_tcp_conn_read_callback if */
-                   /*     event_wakeup call us.            */
+    if(!rc->donotclose) {
+       /* amfree(rc) */
+       /* a memory leak occurs, but freeing it lead to memory
+        * corruption because it can still be used.
+        * We need to find a good place to free 'rc'.
+        */
+    }
 }
 
 /*
@@ -1518,13 +1572,13 @@ sec_tcp_conn_read(
 
     if (rc->ev_read != NULL) {
        rc->ev_read_refcnt++;
-       secprintf((
-              "%s: sec: conn_read: incremented ev_read_refcnt to %d for %s\n",
-              debug_prefix_time(NULL), rc->ev_read_refcnt, rc->hostname));
+       auth_debug(1,
+             _("sec: conn_read: incremented ev_read_refcnt to %d for %s\n"),
+              rc->ev_read_refcnt, rc->hostname);
        return;
     }
-    secprintf(("%s: sec: conn_read registering event handler for %s\n",
-              debug_prefix_time(NULL), rc->hostname));
+    auth_debug(1, _("sec: conn_read registering event handler for %s\n"),
+                  rc->hostname);
     rc->ev_read = event_register((event_id_t)rc->read, EV_READFD,
                sec_tcp_conn_read_callback, rc);
     rc->ev_read_refcnt = 1;
@@ -1536,15 +1590,15 @@ sec_tcp_conn_read_cancel(
 {
 
     --rc->ev_read_refcnt;
-    secprintf((
-       "%s: sec: conn_read_cancel: decremented ev_read_refcnt to %d for %s\n",
-       debug_prefix_time(NULL),
-       rc->ev_read_refcnt, rc->hostname));
+    auth_debug(1,
+       _("sec: conn_read_cancel: decremented ev_read_refcnt to %d for %s\n"),
+       rc->ev_read_refcnt, rc->hostname);
     if (rc->ev_read_refcnt > 0) {
        return;
     }
-    secprintf(("%s: sec: conn_read_cancel: releasing event handler for %s\n",
-              debug_prefix_time(NULL), rc->hostname));
+    auth_debug(1,
+                _("sec: conn_read_cancel: releasing event handler for %s\n"),
+                rc->hostname);
     event_release(rc->ev_read);
     rc->ev_read = NULL;
 }
@@ -1564,8 +1618,7 @@ recvpkt_callback(
 
     assert(rh != NULL);
 
-    secprintf(("%s: sec: recvpkt_callback: %d\n",
-              debug_prefix_time(NULL), bufsize));
+    auth_debug(1, _("sec: recvpkt_callback: %zd\n"), bufsize);
     /*
      * We need to cancel the recvpkt request before calling
      * the callback because the callback may reschedule us.
@@ -1575,11 +1628,11 @@ recvpkt_callback(
     switch (bufsize) {
     case 0:
        security_seterror(&rh->sech,
-           "EOF on read from %s", rh->hostname);
+           _("EOF on read from %s"), rh->hostname);
        (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
        return;
     case -1:
-       security_seterror(&rh->sech, security_stream_geterror(&rh->rs->secstr));
+       security_seterror(&rh->sech, "%s", security_stream_geterror(&rh->rs->secstr));
        (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
        return;
     default:
@@ -1587,10 +1640,10 @@ recvpkt_callback(
     }
 
     parse_pkt(&pkt, buf, (size_t)bufsize);
-    secprintf((
-          "%s: sec: received %s packet (%d) from %s, contains:\n\n\"%s\"\n\n",
-          debug_prefix_time(NULL), pkt_type2str(pkt.type), pkt.type,
-          rh->hostname, pkt.body));
+    auth_debug(1,
+         _("sec: received %s packet (%d) from %s, contains:\n\n\"%s\"\n\n"),
+          pkt_type2str(pkt.type), pkt.type,
+          rh->hostname, pkt.body);
     if (rh->rc->recv_security_ok && (rh->rc->recv_security_ok)(rh, &pkt) < 0)
        (*rh->fn.recvpkt)(rh->arg, NULL, S_ERROR);
     else
@@ -1608,8 +1661,7 @@ stream_read_sync_callback(
     struct sec_stream *rs = s;
     assert(rs != NULL);
 
-    secprintf(("%s: sec: stream_read_callback_sync: handle %d\n",
-              debug_prefix_time(NULL), rs->handle));
+    auth_debug(1, _("sec: stream_read_callback_sync: handle %d\n"), rs->handle);
 
     /*
      * Make sure this was for us.  If it was, then blow away the handle
@@ -1618,12 +1670,10 @@ stream_read_sync_callback(
      * If the handle is EOF, pass that up to our callback.
      */
     if (rs->rc->handle == rs->handle) {
-        secprintf(("%s: sec: stream_read_callback_sync: it was for us\n",
-                  debug_prefix_time(NULL)));
+        auth_debug(1, _("sec: stream_read_callback_sync: it was for us\n"));
         rs->rc->handle = H_TAKEN;
     } else if (rs->rc->handle != H_EOF) {
-        secprintf(("%s: sec: stream_read_callback_sync: not for us\n",
-                  debug_prefix_time(NULL)));
+        auth_debug(1, _("sec: stream_read_callback_sync: not for us\n"));
         return;
     }
 
@@ -1634,19 +1684,21 @@ stream_read_sync_callback(
      */
     tcpm_stream_read_cancel(rs);
 
+    sync_pktlen = rs->rc->pktlen;
+    sync_pkt = malloc(sync_pktlen);
+    memcpy(sync_pkt, rs->rc->pkt, sync_pktlen);
+
     if (rs->rc->pktlen <= 0) {
-       secprintf(("%s: sec: stream_read_sync_callback: %s\n",
-                  debug_prefix_time(NULL), rs->rc->errmsg));
-       security_stream_seterror(&rs->secstr, rs->rc->errmsg);
+       auth_debug(1, _("sec: stream_read_sync_callback: %s\n"), rs->rc->errmsg);
+       security_stream_seterror(&rs->secstr, "%s", rs->rc->errmsg);
        if(rs->closed_by_me == 0 && rs->closed_by_network == 0)
            sec_tcp_conn_put(rs->rc);
        rs->closed_by_network = 1;
        return;
     }
-    secprintf((
-            "%s: sec: stream_read_callback_sync: read %ld bytes from %s:%d\n",
-            debug_prefix_time(NULL),
-        rs->rc->pktlen, rs->rc->hostname, rs->handle));
+    auth_debug(1,
+           _("sec: stream_read_callback_sync: read %zd bytes from %s:%d\n"),
+           rs->rc->pktlen, rs->rc->hostname, rs->handle);
 }
 
 /*
@@ -1657,10 +1709,16 @@ stream_read_callback(
     void *     arg)
 {
     struct sec_stream *rs = arg;
+    time_t             logtime;
+
     assert(rs != NULL);
 
-    secprintf(("%s: sec: stream_read_callback: handle %d\n",
-              debug_prefix_time(NULL), rs->handle));
+    logtime = time(NULL);
+    if (rs && rs->rc && logtime > rs->rc->logstamp + 10) {
+       g_debug("stream_read_callback: data is still flowing");
+       rs->rc->logstamp = logtime;
+    }
+    auth_debug(1, _("sec: stream_read_callback: handle %d\n"), rs->handle);
 
     /*
      * Make sure this was for us.  If it was, then blow away the handle
@@ -1669,12 +1727,10 @@ stream_read_callback(
      * If the handle is EOF, pass that up to our callback.
      */
     if (rs->rc->handle == rs->handle) {
-       secprintf(("%s: sec: stream_read_callback: it was for us\n",
-                  debug_prefix_time(NULL)));
+       auth_debug(1, _("sec: stream_read_callback: it was for us\n"));
        rs->rc->handle = H_TAKEN;
     } else if (rs->rc->handle != H_EOF) {
-       secprintf(("%s: sec: stream_read_callback: not for us\n",
-                  debug_prefix_time(NULL)));
+       auth_debug(1, _("sec: stream_read_callback: not for us\n"));
        return;
     }
 
@@ -1686,21 +1742,18 @@ stream_read_callback(
     tcpm_stream_read_cancel(rs);
 
     if (rs->rc->pktlen <= 0) {
-       secprintf(("%s: sec: stream_read_callback: %s\n",
-                  debug_prefix_time(NULL), rs->rc->errmsg));
-       security_stream_seterror(&rs->secstr, rs->rc->errmsg);
+       auth_debug(1, _("sec: stream_read_callback: %s\n"), rs->rc->errmsg);
+       security_stream_seterror(&rs->secstr, "%s", rs->rc->errmsg);
        if(rs->closed_by_me == 0 && rs->closed_by_network == 0)
            sec_tcp_conn_put(rs->rc);
        rs->closed_by_network = 1;
        (*rs->fn)(rs->arg, NULL, rs->rc->pktlen);
        return;
     }
-    secprintf(("%s: sec: stream_read_callback: read %ld bytes from %s:%d\n",
-              debug_prefix_time(NULL),
-       rs->rc->pktlen, rs->rc->hostname, rs->handle));
+    auth_debug(1, _("sec: stream_read_callback: read %zd bytes from %s:%d\n"),
+                  rs->rc->pktlen, rs->rc->hostname, rs->handle);
     (*rs->fn)(rs->arg, rs->rc->pkt, rs->rc->pktlen);
-    secprintf(("%s: sec: after callback stream_read_callback\n",
-              debug_prefix_time(NULL)));
+    auth_debug(1, _("sec: after callback stream_read_callback\n"));
 }
 
 /*
@@ -1720,23 +1773,29 @@ sec_tcp_conn_read_callback(
 
     assert(cookie != NULL);
 
-    secprintf(("%s: sec: conn_read_callback\n", debug_prefix_time(NULL)));
+    auth_debug(1, _("sec: conn_read_callback\n"));
 
     /* Read the data off the wire.  If we get errors, shut down. */
-    rval = tcpm_recv_token(rc->read, &rc->handle, &rc->errmsg, &rc->pkt,
-                               &rc->pktlen, 60);
-    secprintf(("%s: sec: conn_read_callback: tcpm_recv_token returned %d\n",
-              debug_prefix_time(NULL), rval));
+    rval = tcpm_recv_token(rc, rc->read, &rc->handle, &rc->errmsg, &rc->pkt,
+                               &rc->pktlen);
+    auth_debug(1, _("sec: conn_read_callback: tcpm_recv_token returned %zd\n"),
+                  rval);
+
+    if (rval == -2) {
+       return;
+    }
+
     if (rval < 0 || rc->handle == H_EOF) {
        rc->pktlen = rval;
        rc->handle = H_EOF;
-       revent = event_wakeup((event_id_t)rc);
-       secprintf(("%s: sec: conn_read_callback: event_wakeup return %d\n",
-                  debug_prefix_time(NULL), revent));
+       revent = event_wakeup((event_id_t)rc->event_id);
+       auth_debug(1, _("sec: conn_read_callback: event_wakeup return %d\n"),
+                      revent);
        /* delete our 'accept' reference */
        if (rc->accept_fn != NULL) {
            if(rc->refcnt != 1) {
-               dbprintf(("STRANGE, rc->refcnt should be 1"));
+               dbprintf(_("STRANGE, rc->refcnt should be 1, it is %d\n"),
+                         rc->refcnt);
                rc->refcnt=1;
            }
            rc->accept_fn = NULL;
@@ -1747,17 +1806,16 @@ sec_tcp_conn_read_callback(
 
     if(rval == 0) {
        rc->pktlen = 0;
-       revent = event_wakeup((event_id_t)rc);
-       secprintf(("%s: 0 sec: conn_read_callback: event_wakeup return %d\n",
-                  debug_prefix_time(NULL), revent));
+       revent = event_wakeup((event_id_t)rc->event_id);
+       auth_debug(1,
+                  _("sec: conn_read_callback: event_wakeup return %d\n"), revent);
        return;
     }
 
     /* If there are events waiting on this handle, we're done */
     rc->donotclose = 1;
-    revent = event_wakeup((event_id_t)rc);
-    secprintf(("%s: sec: conn_read_callback: event_wakeup return %d\n",
-              debug_prefix_time(NULL), rval));
+    revent = event_wakeup((event_id_t)rc->event_id);
+    auth_debug(1, _("sec: conn_read_callback: event_wakeup return %d\n"), revent);
     rc->donotclose = 0;
     if (rc->handle == H_TAKEN || rc->pktlen == 0) {
        if(rc->refcnt == 0) amfree(rc);
@@ -1767,10 +1825,14 @@ sec_tcp_conn_read_callback(
     assert(rc->refcnt > 0);
 
     /* If there is no accept fn registered, then drop the packet */
-    if (rc->accept_fn == NULL)
+    if (rc->accept_fn == NULL) {
+       g_warning(
+         _("sec: conn_read_callback: %zd bytes for handle %d went unclaimed!"),
+         rc->pktlen, rc->handle);
        return;
+    }
 
-    rh = alloc(SIZEOF(*rh));
+    rh = g_new0(struct sec_handle, 1);
     security_handleinit(&rh->sech, rc->driver);
     rh->hostname = stralloc(rc->hostname);
     rh->ev_timeout = NULL;
@@ -1778,10 +1840,10 @@ sec_tcp_conn_read_callback(
     rh->peer = rc->peer;
     rh->rs = tcpma_stream_client(rh, rc->handle);
 
-    secprintf(("%s: sec: new connection\n", debug_prefix_time(NULL)));
+    auth_debug(1, _("sec: new connection\n"));
     pkt.body = NULL;
     parse_pkt(&pkt, rc->pkt, (size_t)rc->pktlen);
-    secprintf(("%s: sec: calling accept_fn\n", debug_prefix_time(NULL)));
+    auth_debug(1, _("sec: calling accept_fn\n"));
     if (rh->rc->recv_security_ok && (rh->rc->recv_security_ok)(rh, &pkt) < 0)
        (*rc->accept_fn)(&rh->sech, NULL);
     else
@@ -1797,8 +1859,7 @@ parse_pkt(
 {
     const unsigned char *bufp = buf;
 
-    secprintf(("%s: sec: parse_pkt: parsing buffer of %d bytes\n",
-              debug_prefix_time(NULL), bufsize));
+    auth_debug(1, _("sec: parse_pkt: parsing buffer of %zu bytes\n"), bufsize);
 
     pkt->type = (pktype_t)*bufp++;
     bufsize--;
@@ -1813,9 +1874,8 @@ parse_pkt(
     }
     pkt->size = strlen(pkt->body);
 
-    secprintf(("%s: sec: parse_pkt: %s (%d): \"%s\"\n",
-              debug_prefix_time(NULL), pkt_type2str(pkt->type),
-              pkt->type, pkt->body));
+    auth_debug(1, _("sec: parse_pkt: %s (%d): \"%s\"\n"), pkt_type2str(pkt->type),
+                  pkt->type, pkt->body);
 }
 
 /*
@@ -1831,12 +1891,11 @@ pkthdr2str(
     assert(rh != NULL);
     assert(pkt != NULL);
 
-    snprintf(retbuf, SIZEOF(retbuf), "Amanda %d.%d %s HANDLE %s SEQ %d\n",
+    g_snprintf(retbuf, SIZEOF(retbuf), _("Amanda %d.%d %s HANDLE %s SEQ %d\n"),
        VERSION_MAJOR, VERSION_MINOR, pkt_type2str(pkt->type),
        rh->proto_handle, rh->sequence);
 
-    secprintf(("%s: bsd: pkthdr2str handle '%s'\n",
-              debug_prefix_time(NULL), rh->proto_handle));
+    auth_debug(1, _("bsd: pkthdr2str handle '%s'\n"), rh->proto_handle);
 
     /* check for truncation.  If only we had asprintf()... */
     assert(retbuf[strlen(retbuf) - 1] == '\n');
@@ -1875,7 +1934,7 @@ str2pkthdr(
     if ((tok = strtok(NULL, " ")) == NULL)
        goto parse_error;
     amfree(pkt->body);
-    pkt_init(pkt, pkt_str2type(tok), "");
+    pkt_init_empty(pkt, pkt_str2type(tok));
     if (pkt->type == (pktype_t)-1)    
        goto parse_error;
 
@@ -1927,7 +1986,7 @@ check_user(
 
     /* lookup our local user name */
     if ((pwd = getpwnam(CLIENT_LOGIN)) == NULL) {
-       return vstralloc("getpwnam(", CLIENT_LOGIN, ") fails", NULL);
+       return vstrallocf(_("getpwnam(%s) failed."), CLIENT_LOGIN);
     }
 
     /*
@@ -1939,12 +1998,12 @@ check_user(
 #ifndef USE_AMANDAHOSTS
     r = check_user_ruserok(rh->hostname, pwd, remoteuser);
 #else
-    r = check_user_amandahosts(rh->hostname, rh->peer.sin_addr, pwd, remoteuser, service);
+    r = check_user_amandahosts(rh->hostname, &rh->peer, pwd, remoteuser, service);
 #endif
     if (r != NULL) {
-       result = vstralloc("user ", remoteuser, " from ", rh->hostname,
-                          " is not allowed to execute the service ",
-                          service, ": ", r, NULL);
+       result = vstrallocf(
+               _("user %s from %s is not allowed to execute the service %s: %s"),
+               remoteuser, rh->hostname, service, r);
        amfree(r);
     }
     amfree(localuser);
@@ -1955,7 +2014,7 @@ check_user(
  * See if a remote user is allowed in.  This version uses ruserok()
  * and friends.
  *
- * Returns 0 on success, or negative on error.
+ * Returns NULL on success, or error message on error.
  */
 char *
 check_user_ruserok(
@@ -1972,7 +2031,6 @@ check_user_ruserok(
     char *es;
     char *result;
     int ok;
-    char number[NUM_STR_SIZE];
     uid_t myuid = getuid();
 
     /*
@@ -1987,51 +2045,46 @@ check_user_ruserok(
      * problem and is expected.  Thanks a lot.  Not.
      */
     if (pipe(fd) != 0) {
-       return stralloc2("pipe() fails: ", strerror(errno));
+       return stralloc2(_("pipe() fails: "), strerror(errno));
     }
     if ((ruserok_pid = fork()) < 0) {
-       return stralloc2("fork() fails: ", strerror(errno));
+       return stralloc2(_("fork() fails: "), strerror(errno));
     } else if (ruserok_pid == 0) {
        int ec;
 
        close(fd[0]);
        fError = fdopen(fd[1], "w");
        if (!fError) {
-           error("Can't fdopen: %s", strerror(errno));
+           error(_("Can't fdopen: %s"), strerror(errno));
            /*NOTREACHED*/
        }
        /* pamper braindead ruserok's */
        if (chdir(pwd->pw_dir) != 0) {
-           fprintf(fError, "chdir(%s) failed: %s",
+           g_fprintf(fError, _("chdir(%s) failed: %s"),
                    pwd->pw_dir, strerror(errno));
            fclose(fError);
            exit(1);
        }
 
-#if defined(SHOW_SECURITY_DETAIL)                              /* { */
-       {
-       char *dir = stralloc(pwd->pw_dir);
-
-       secprintf(("%s: bsd: calling ruserok(%s, %d, %s, %s)\n",
-                  debug_prefix_time(NULL),
-                  host, ((myuid == 0) ? 1 : 0), remoteuser, pwd->pw_name));
-       if (myuid == 0) {
-           secprintf(("%s: bsd: because you are running as root, ",
-                      debug_prefix(NULL)));
-           secprintf(("/etc/hosts.equiv will not be used\n"));
-       } else {
-           show_stat_info("/etc/hosts.equiv", NULL);
-       }
-       show_stat_info(dir, "/.rhosts");
-       amfree(dir);
+       if (debug_auth >= 9) {
+           char *dir = stralloc(pwd->pw_dir);
+
+           auth_debug(9, _("bsd: calling ruserok(%s, %d, %s, %s)\n"), host,
+                          ((myuid == 0) ? 1 : 0), remoteuser, pwd->pw_name);
+           if (myuid == 0) {
+               auth_debug(9, _("bsd: because you are running as root, "));
+               auth_debug(9, _("/etc/hosts.equiv will not be used\n"));
+           } else {
+               show_stat_info("/etc/hosts.equiv", NULL);
+           }
+           show_stat_info(dir, "/.rhosts");
+           amfree(dir);
        }
-#endif                                                         /* } */
 
        saved_stderr = dup(2);
        close(2);
        if (open("/dev/null", O_RDWR) == -1) {
-            secprintf(("%s: Could not open /dev/null: %s\n",
-                     debug_prefix(NULL), strerror(errno)));
+            auth_debug(1, _("Could not open /dev/null: %s\n"), strerror(errno));
            ec = 1;
        } else {
            ok = ruserok(host, myuid == 0, remoteuser, CLIENT_LOGIN);
@@ -2048,7 +2101,7 @@ check_user_ruserok(
     close(fd[1]);
     fError = fdopen(fd[0], "r");
     if (!fError) {
-       error("Can't fdopen: %s", strerror(errno));
+       error(_("Can't fdopen: %s"), strerror(errno));
        /*NOTREACHED*/
     }
 
@@ -2072,19 +2125,15 @@ check_user_ruserok(
     while (pid != ruserok_pid) {
        if ((pid == (pid_t) -1) && (errno != EINTR)) {
            amfree(result);
-           return stralloc2("ruserok wait failed: %s", strerror(errno));
+           return vstrallocf(_("ruserok wait failed: %s"), strerror(errno));
        }
        pid = wait(&exitcode);
     }
-    if (WIFSIGNALED(exitcode)) {
+    if (!WIFEXITED(exitcode) || WEXITSTATUS(exitcode) != 0) {
        amfree(result);
-       snprintf(number, SIZEOF(number), "%d", WTERMSIG(exitcode));
-       return stralloc2("ruserok child got signal ", number);
-    }
-    if (WEXITSTATUS(exitcode) == 0) {
+       result = str_exit_status("ruserok child", exitcode);
+    } else {
        amfree(result);
-    } else if (result == NULL) {
-       result = stralloc("ruserok failed");
     }
 
     return result;
@@ -2092,12 +2141,12 @@ check_user_ruserok(
 
 /*
  * Check to see if a user is allowed in.  This version uses .amandahosts
- * Returns -1 on failure, or 0 on success.
+ * Returns an error message on failure, or NULL on success.
  */
 char *
 check_user_amandahosts(
     const char *       host,
-    struct in_addr      addr,
+    sockaddr_union *addr,
     struct passwd *    pwd,
     const char *       remoteuser,
     const char *       service)
@@ -2110,22 +2159,25 @@ check_user_amandahosts(
     FILE *fp = NULL;
     int found;
     struct stat sbuf;
-    char n1[NUM_STR_SIZE];
-    char n2[NUM_STR_SIZE];
     int hostmatch;
     int usermatch;
     char *aservice = NULL;
+#ifdef WORKING_IPV6
+    char ipstr[INET6_ADDRSTRLEN];
+#else
+    char ipstr[INET_ADDRSTRLEN];
+#endif
 
-    secprintf(("check_user_amandahosts(host=%s, pwd=%p, "
-               "remoteuser=%s, service=%s)\n",
-               host, pwd, remoteuser, service));
+    auth_debug(1, _("check_user_amandahosts(host=%s, pwd=%p, "
+                  "remoteuser=%s, service=%s)\n"),
+                  host, pwd, remoteuser, service);
 
     ptmp = stralloc2(pwd->pw_dir, "/.amandahosts");
-#if defined(SHOW_SECURITY_DETAIL)                              /* { */
-    show_stat_info(ptmp, "");;
-#endif                                                         /* } */
+    if (debug_auth >= 9) {
+       show_stat_info(ptmp, "");;
+    }
     if ((fp = fopen(ptmp, "r")) == NULL) {
-       result = vstralloc("cannot open ", ptmp, ": ", strerror(errno), NULL);
+       result = vstrallocf(_("cannot open %s: %s"), ptmp, strerror(errno));
        amfree(ptmp);
        return result;
     }
@@ -2135,21 +2187,16 @@ check_user_amandahosts(
      * have any group/other access allowed.
      */
     if (fstat(fileno(fp), &sbuf) != 0) {
-       result = vstralloc("cannot fstat ", ptmp, ": ", strerror(errno), NULL);
+       result = vstrallocf(_("cannot fstat %s: %s"), ptmp, strerror(errno));
        goto common_exit;
     }
     if (sbuf.st_uid != pwd->pw_uid) {
-       snprintf(n1, SIZEOF(n1), "%ld", (long)sbuf.st_uid);
-       snprintf(n2, SIZEOF(n2), "%ld", (long)pwd->pw_uid);
-       result = vstralloc(ptmp, ": ",
-                          "owned by id ", n1,
-                          ", should be ", n2,
-                          NULL);
+       result = vstrallocf(_("%s: owned by id %ld, should be %ld"),
+                       ptmp, (long)sbuf.st_uid, (long)pwd->pw_uid);
        goto common_exit;
     }
     if ((sbuf.st_mode & 077) != 0) {
-       result = stralloc2(ptmp,
-         ": incorrect permissions; file must be accessible only by its owner");
+       result = vstrallocf(_("%s: incorrect permissions; file must be accessible only by its owner"), ptmp);
        goto common_exit;
     }
 
@@ -2163,9 +2210,7 @@ check_user_amandahosts(
            continue;
        }
 
-#if defined(SHOW_SECURITY_DETAIL)                              /* { */
-       secprintf(("%s: bsd: processing line: <%s>\n", debug_prefix(NULL), line));
-#endif                                                         /* } */
+       auth_debug(9, _("bsd: processing line: <%s>\n"), line);
        /* get the host out of the file */
        if ((filehost = strtok(line, " \t")) == NULL) {
            amfree(line);
@@ -2179,24 +2224,29 @@ check_user_amandahosts(
 
        hostmatch = (strcasecmp(filehost, host) == 0);
        /*  ok if addr=127.0.0.1 and
-        *  either localhost or localhost.domain is in .amandahost */
-       if ( !hostmatch ) {
-         if (strcmp(inet_ntoa(addr), "127.0.0.1")== 0  &&
-             (strcasecmp(filehost, "localhost")== 0 ||
-             strcasecmp(filehost, "localhost.localdomain")== 0))
-           {
-             hostmatch = 1;
-           }
-       }
+        *  either localhost or localhost.domain is in .amandahost */
+       if (!hostmatch  &&
+           (strcasecmp(filehost, "localhost")== 0 ||
+            strcasecmp(filehost, "localhost.localdomain")== 0)) {
+#ifdef WORKING_IPV6
+           if (SU_GET_FAMILY(addr) == (sa_family_t)AF_INET6)
+               inet_ntop(AF_INET6, &addr->sin6.sin6_addr,
+                         ipstr, sizeof(ipstr));
+           else
+#endif
+               inet_ntop(AF_INET, &addr->sin.sin_addr,
+                         ipstr, sizeof(ipstr));
+           if (strcmp(ipstr, "127.0.0.1") == 0 ||
+               strcmp(ipstr, "::1") == 0)
+               hostmatch = 1;
+       }
        usermatch = (strcasecmp(fileuser, remoteuser) == 0);
-#if defined(SHOW_SECURITY_DETAIL)                              /* { */
-       secprintf(("%s: bsd: comparing \"%s\" with\n", debug_prefix(NULL), filehost));
-       secprintf(("%s: bsd:           \"%s\" (%s)\n", host,
-                 debug_prefix(NULL), hostmatch ? "match" : "no match"));
-       secprintf(("%s: bsd:       and \"%s\" with\n", fileuser, debug_prefix(NULL)));
-       secprintf(("%s: bsd:           \"%s\" (%s)\n", remoteuser,
-                 debug_prefix(NULL), usermatch ? "match" : "no match"));
-#endif                                                         /* } */
+       auth_debug(9, _("bsd: comparing \"%s\" with\n"), filehost);
+       auth_debug(9, _("bsd:           \"%s\" (%s)\n"), host,
+                      hostmatch ? _("match") : _("no match"));
+       auth_debug(9, _("bsd:       and \"%s\" with\n"), fileuser);
+       auth_debug(9, _("bsd:           \"%s\" (%s)\n"), remoteuser,
+                      usermatch ? _("match") : _("no match"));
        /* compare */
        if (!hostmatch || !usermatch) {
            amfree(line);
@@ -2256,18 +2306,15 @@ check_user_amandahosts(
     if (! found) {
        if (strcmp(service, "amindexd") == 0 ||
            strcmp(service, "amidxtaped") == 0) {
-           result = vstralloc("Please add \"amindexd amidxtaped\" to "
-                              "the line in ", ptmp, NULL);
+           result = vstrallocf(_("Please add the line \"%s %s amindexd amidxtaped\" to %s on the server"), host, remoteuser, ptmp);
        } else if (strcmp(service, "amdump") == 0 ||
                   strcmp(service, "noop") == 0 ||
                   strcmp(service, "selfcheck") == 0 ||
                   strcmp(service, "sendsize") == 0 ||
                   strcmp(service, "sendbackup") == 0) {
-           result = vstralloc("Please add \"amdump\" to the line in ",
-                              ptmp, NULL);
+           result = vstrallocf(_("Please add the line \"%s %s amdump\" to %s on the client"), host, remoteuser, ptmp);
        } else {
-           result = vstralloc(ptmp, ": ",
-                              "invalid service ", service, NULL);
+           result = vstrallocf(_("%s: invalid service %s"), ptmp, service);
        }
     }
 
@@ -2282,108 +2329,54 @@ common_exit:
 /* return 1 on success, 0 on failure */
 int
 check_security(
-    struct sockaddr_in *addr,
+    sockaddr_union *addr,
     char *             str,
     unsigned long      cksum,
     char **            errstr)
 {
     char *             remotehost = NULL, *remoteuser = NULL;
     char *             bad_bsd = NULL;
-    struct hostent *   hp;
     struct passwd *    pwptr;
     uid_t              myuid;
-    int                        i;
-    int                        j;
     char *             s;
     char *             fp;
     int                        ch;
+    char               hostname[NI_MAXHOST];
+    in_port_t          port;
+    int                        result;
 
     (void)cksum;       /* Quiet unused parameter warning */
 
-    secprintf(("%s: check_security(addr=%p, str='%s', cksum=%ul, errstr=%p\n",
-               debug_prefix(NULL), addr, str, cksum, errstr));
+    auth_debug(1,
+              _("check_security(addr=%p, str='%s', cksum=%lu, errstr=%p\n"),
+               addr, str, cksum, errstr);
     dump_sockaddr(addr);
 
     *errstr = NULL;
 
     /* what host is making the request? */
-
-    hp = gethostbyaddr((char *)&addr->sin_addr, SIZEOF(addr->sin_addr),
-                      AF_INET);
-    if (hp == NULL) {
-       /* XXX include remote address in message */
-       *errstr = vstralloc("[",
-                           "addr ", inet_ntoa(addr->sin_addr), ": ",
-                           "hostname lookup failed",
-                           "]", NULL);
-       return 0;
-    }
-    remotehost = stralloc(hp->h_name);
-
-    /* Now let's get the hostent for that hostname */
-    hp = gethostbyname( remotehost );
-    if (hp == NULL) {
-       /* XXX include remote hostname in message */
-       *errstr = vstralloc("[",
-                           "host ", remotehost, ": ",
-                           "hostname lookup failed",
+    if ((result = getnameinfo((struct sockaddr *)addr, SS_LEN(addr),
+                             hostname, NI_MAXHOST, NULL, 0, 0)) != 0) {
+       dbprintf(_("getnameinfo failed: %s\n"),
+                 gai_strerror(result));
+       *errstr = vstralloc("[", "addr ", str_sockaddr(addr), ": ",
+                           "getnameinfo failed: ", gai_strerror(result),
                            "]", NULL);
-       amfree(remotehost);
        return 0;
     }
-
-    /* Verify that the hostnames match -- they should theoretically */
-    if (strncasecmp( remotehost, hp->h_name, strlen(remotehost)+1 ) != 0 ) {
-       *errstr = vstralloc("[",
-                           "hostnames do not match: ",
-                           remotehost, " ", hp->h_name,
-                           "]", NULL);
+    remotehost = stralloc(hostname);
+    if( check_name_give_sockaddr(hostname,
+                                (struct sockaddr *)addr, errstr) < 0) {
        amfree(remotehost);
        return 0;
     }
 
-    /* Now let's verify that the ip which gave us this hostname
-     * is really an ip for this hostname; or is someone trying to
-     * break in? (THIS IS THE CRUCIAL STEP)
-     */
-    for (i = 0; hp->h_addr_list[i]; i++) {
-       if (memcmp(hp->h_addr_list[i],
-                  (char *) &addr->sin_addr, SIZEOF(addr->sin_addr)) == 0)
-           break;                     /* name is good, keep it */
-    }
-
-    /* If we did not find it, your DNS is messed up or someone is trying
-     * to pull a fast one on you. :(
-     */
-
-   /*   Check even the aliases list. Work around for Solaris if dns goes over NIS */
-
-    if (!hp->h_addr_list[i] ) {
-        for (j = 0; hp->h_aliases[j] !=0 ; j++) {
-            if (strcmp(hp->h_aliases[j],inet_ntoa(addr->sin_addr)) == 0)
-                break;                          /* name is good, keep it */
-        }
-       if (!hp->h_aliases[j] ) {
-           *errstr = vstralloc("[",
-                               "ip address ", inet_ntoa(addr->sin_addr),
-                               " is not in the ip list for ", remotehost,
-                               "]",
-                               NULL);
-           amfree(remotehost);
-           return 0;
-       }
-    }
 
     /* next, make sure the remote port is a "reserved" one */
-
-    if (ntohs(addr->sin_port) >= IPPORT_RESERVED) {
-       char number[NUM_STR_SIZE];
-
-       snprintf(number, SIZEOF(number), "%hd", (short)ntohs(addr->sin_port));
-       *errstr = vstralloc("[",
-                           "host ", remotehost, ": ",
-                           "port ", number, " not secure",
-                           "]", NULL);
+    port = SU_GET_PORT(addr);
+    if (port >= IPPORT_RESERVED) {
+       *errstr = vstrallocf(_("[host %s: port %u not secure]"),
+                       remotehost, (unsigned int)port);
        amfree(remotehost);
        return 0;
     }
@@ -2393,21 +2386,14 @@ check_security(
     s = str;
     ch = *s++;
 
-    bad_bsd = vstralloc("[",
-                       "host ", remotehost, ": ",
-                       "bad bsd security line",
-                       "]", NULL);
+    bad_bsd = vstrallocf(_("[host %s: bad bsd security line]"), remotehost);
 
-#define sc "USER "
-    if (strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
+    if (strncmp_const_skip(s - 1, "USER ", s, ch) != 0) {
        *errstr = bad_bsd;
        bad_bsd = NULL;
        amfree(remotehost);
        return 0;
     }
-    s += SIZEOF(sc)-1;
-    ch = s[-1];
-#undef sc
 
     skip_whitespace(s, ch);
     if (ch == '\0') {
@@ -2427,22 +2413,20 @@ check_security(
 
     myuid = getuid();
     if ((pwptr = getpwuid(myuid)) == NULL)
-        error("error [getpwuid(%d) fails]", myuid);
+        error(_("error [getpwuid(%d) fails]"), (int)myuid);
 
-    secprintf(("%s: bsd security: remote host %s user %s local user %s\n",
-             debug_prefix(NULL), remotehost, remoteuser, pwptr->pw_name));
+    auth_debug(1, _("bsd security: remote host %s user %s local user %s\n"),
+                  remotehost, remoteuser, pwptr->pw_name);
 
 #ifndef USE_AMANDAHOSTS
     s = check_user_ruserok(remotehost, pwptr, remoteuser);
 #else
-    s = check_user_amandahosts(remotehost, addr->sin_addr, pwptr, remoteuser, NULL);
+    s = check_user_amandahosts(remotehost, addr, pwptr, remoteuser, NULL);
 #endif
 
     if (s != NULL) {
-       *errstr = vstralloc("[",
-                           "access as ", pwptr->pw_name, " not allowed",
-                           " from ", remoteuser, "@", remotehost,
-                           ": ", s, "]", NULL);
+       *errstr = vstrallocf(_("[access as %s not allowed from %s@%s: %s]"),
+                           pwptr->pw_name, remoteuser, remotehost, s);
     }
     amfree(s);
     amfree(remotehost);
@@ -2450,58 +2434,6 @@ check_security(
     return *errstr == NULL;
 }
 
-/*
- * Writes out the entire iovec
- */
-ssize_t
-net_writev(
-    int                        fd,
-    struct iovec *     iov,
-    int                        iovcnt)
-{
-    ssize_t delta, n, total;
-
-    assert(iov != NULL);
-
-    total = 0;
-    while (iovcnt > 0) {
-       /*
-        * Write the iovec
-        */
-       n = writev(fd, iov, iovcnt);
-       if (n < 0) {
-           if (errno != EINTR)
-               return (-1);
-           secprintf(("%s: net_writev got EINTR\n",
-                      debug_prefix(NULL)));
-       }
-       else if (n == 0) {
-           errno = EIO;
-           return (-1);
-       } else {
-           total += n;
-           /*
-            * Iterate through each iov.  Figure out what we still need
-            * to write out.
-            */
-           for (; n > 0; iovcnt--, iov++) {
-               /* 'delta' is the bytes written from this iovec */
-               delta = ((size_t)n < iov->iov_len) ? n : (ssize_t)iov->iov_len;
-               /* subtract from the total num bytes written */
-               n -= delta;
-               assert(n >= 0);
-               /* subtract from this iovec */
-               iov->iov_len -= delta;
-               iov->iov_base = (char *)iov->iov_base + delta;
-               /* if this iovec isn't empty, run the writev again */
-               if (iov->iov_len > 0)
-                   break;
-           }
-       }
-    }
-    return (total);
-}
-
 /*
  * Like read(), but waits until the entire buffer has been filled.
  */
@@ -2516,27 +2448,23 @@ net_read(
     ssize_t nread;
     size_t size = origsize;
 
-    secprintf(("%s: net_read: begin %d\n", debug_prefix_time(NULL), origsize));
+    auth_debug(1, _("net_read: begin %zu\n"), origsize);
 
     while (size > 0) {
-       secprintf(("%s: net_read: while %d\n",
-                  debug_prefix_time(NULL), size));
+       auth_debug(1, _("net_read: while %zu\n"), size);
        nread = net_read_fillbuf(fd, timeout, buf, size);
        if (nread < 0) {
-           secprintf(("%s: db: net_read: end return(-1)\n",
-                      debug_prefix_time(NULL)));
+           auth_debug(1, _("db: net_read: end return(-1)\n"));
            return (-1);
        }
        if (nread == 0) {
-           secprintf(("%s: net_read: end return(0)\n",
-                      debug_prefix_time(NULL)));
+           auth_debug(1, _("net_read: end return(0)\n"));
            return (0);
        }
        buf += nread;
        size -= nread;
     }
-    secprintf(("%s: net_read: end %d\n",
-              debug_prefix_time(NULL), origsize));
+    auth_debug(1, _("net_read: end %zu\n"), origsize);
     return ((ssize_t)origsize);
 }
 
@@ -2550,11 +2478,11 @@ net_read_fillbuf(
     void *     buf,
     size_t     size)
 {
-    fd_set readfds;
+    SELECT_ARG_TYPE readfds;
     struct timeval tv;
     ssize_t nread;
 
-    secprintf(("%s: net_read_fillbuf: begin\n", debug_prefix_time(NULL)));
+    auth_debug(1, _("net_read_fillbuf: begin\n"));
     FD_ZERO(&readfds);
     FD_SET(fd, &readfds);
     tv.tv_sec = timeout;
@@ -2564,25 +2492,21 @@ net_read_fillbuf(
        errno = ETIMEDOUT;
        /* FALLTHROUGH */
     case -1:
-       secprintf(("%s: net_read_fillbuf: case -1\n",
-                  debug_prefix_time(NULL)));
+       auth_debug(1, _("net_read_fillbuf: case -1\n"));
        return (-1);
     case 1:
-       secprintf(("%s: net_read_fillbuf: case 1\n",
-                  debug_prefix_time(NULL)));
+       auth_debug(1, _("net_read_fillbuf: case 1\n"));
        assert(FD_ISSET(fd, &readfds));
        break;
     default:
-       secprintf(("%s: net_read_fillbuf: case default\n",
-                  debug_prefix_time(NULL)));
+       auth_debug(1, _("net_read_fillbuf: case default\n"));
        assert(0);
        break;
     }
     nread = read(fd, buf, size);
     if (nread < 0)
        return (-1);
-    secprintf(("%s: net_read_fillbuf: end %d\n",
-              debug_prefix_time(NULL), nread));
+    auth_debug(1, _("net_read_fillbuf: end %zd\n"), nread);
     return (nread);
 }
 
@@ -2598,33 +2522,165 @@ show_stat_info(
 {
     char *name = vstralloc(a, b, NULL);
     struct stat sbuf;
-    struct passwd *pwptr;
+    struct passwd *pwptr G_GNUC_UNUSED;
+    struct passwd pw G_GNUC_UNUSED;
     char *owner;
-    struct group *grptr;
+    struct group *grptr G_GNUC_UNUSED;
+    struct group gr G_GNUC_UNUSED;
     char *group;
+    int buflen G_GNUC_UNUSED;
+    char *buf G_GNUC_UNUSED;
 
     if (stat(name, &sbuf) != 0) {
-       secprintf(("%s: bsd: cannot stat %s: %s\n",
-                  debug_prefix_time(NULL), name, strerror(errno)));
+       auth_debug(1, _("bsd: cannot stat %s: %s\n"), name, strerror(errno));
        amfree(name);
        return;
     }
-    if ((pwptr = getpwuid(sbuf.st_uid)) == NULL) {
-       owner = alloc(NUM_STR_SIZE + 1);
-       snprintf(owner, NUM_STR_SIZE, "%ld", (long)sbuf.st_uid);
-    } else {
+
+#ifdef _SC_GETPW_R_SIZE_MAX
+    buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+    if (buflen == -1)
+       buflen = 1024;
+#else
+    buflen = 1024;
+#endif
+    buf = malloc(buflen);
+
+#ifdef HAVE_GETPWUID_R
+    if (getpwuid_r(sbuf.st_uid, &pw, buf, buflen, &pwptr) == 0 &&
+       pwptr != NULL) {
        owner = stralloc(pwptr->pw_name);
+    } else
+#endif
+    {
+       owner = alloc(NUM_STR_SIZE + 1);
+       g_snprintf(owner, NUM_STR_SIZE, "%ld", (long)sbuf.st_uid);
     }
-    if ((grptr = getgrgid(sbuf.st_gid)) == NULL) {
-       group = alloc(NUM_STR_SIZE + 1);
-       snprintf(owner, NUM_STR_SIZE, "%ld", (long)sbuf.st_gid);
-    } else {
+#ifdef HAVE_GETGRGID_R
+    if (getgrgid_r(sbuf.st_gid, &gr, buf, buflen, &grptr) == 0 &&
+       grptr != NULL) {
        group = stralloc(grptr->gr_name);
+    } else
+#endif
+    {
+       group = alloc(NUM_STR_SIZE + 1);
+       g_snprintf(group, NUM_STR_SIZE, "%ld", (long)sbuf.st_gid);
     }
-    secprintf(("%s: bsd: processing file: %s\n", debug_prefix(NULL), name));
-    secprintf(("%s: bsd:                  owner=%s group=%s mode=%03o\n",
-              debug_prefix(NULL), owner, group, (int) (sbuf.st_mode & 0777)));
+
+    auth_debug(1, _("bsd: processing file: %s\n"), name);
+    auth_debug(1, _("bsd:                  owner=%s group=%s mode=%03o\n"),
+                  owner, group,
+                  (int) (sbuf.st_mode & 0777));
     amfree(name);
     amfree(owner);
     amfree(group);
+    amfree(buf);
+}
+
+int
+check_name_give_sockaddr(
+    const char *hostname,
+    struct sockaddr *addr,
+    char **errstr)
+{
+    int result;
+    struct addrinfo *res = NULL, *res1;
+    char *canonname;
+
+    result = resolve_hostname(hostname, 0, &res, &canonname);
+    if (result != 0) {
+       dbprintf(_("check_name_give_sockaddr: resolve_hostname('%s'): %s\n"), hostname, gai_strerror(result));
+       *errstr = newvstrallocf(*errstr,
+                              _("check_name_give_sockaddr: resolve_hostname('%s'): %s"),
+                              hostname, gai_strerror(result));
+       goto error;
+    }
+    if (canonname == NULL) {
+       dbprintf(_("resolve_hostname('%s') did not return a canonical name\n"), hostname);
+       *errstr = newvstrallocf(*errstr,
+               _("check_name_give_sockaddr: resolve_hostname('%s') did not return a canonical name"),
+               hostname);
+       goto error;
+    }
+
+    if (strncasecmp(hostname, canonname, strlen(hostname)) != 0) {
+       dbprintf(_("%s doesn't resolve to itself, it resolves to %s\n"),
+                      hostname, canonname);
+       *errstr = newvstrallocf(*errstr,
+                              _("%s doesn't resolve to itself, it resolves to %s"),
+                              hostname, canonname);
+       goto error;
+    }
+
+    for(res1=res; res1 != NULL; res1 = res1->ai_next) {
+       if (cmp_sockaddr((sockaddr_union *)res1->ai_addr, (sockaddr_union *)addr, 1) == 0) {
+           freeaddrinfo(res);
+           amfree(canonname);
+           return 0;
+       }
+    }
+
+    g_debug("%s doesn't resolve to %s",
+           hostname, str_sockaddr((sockaddr_union *)addr));
+    *errstr = newvstrallocf(*errstr,
+                          "%s doesn't resolve to %s",
+                          hostname, str_sockaddr((sockaddr_union *)addr));
+error:
+    if (res) freeaddrinfo(res);
+    amfree(canonname);
+    return -1;
+}
+
+in_port_t
+find_port_for_service(
+    char *service,
+    char *proto)
+{
+    in_port_t  port;
+    char      *s;
+    int        all_numeric = 1;
+
+    for (s=service; *s != '\0'; s++) {
+       if (!isdigit((int)*s)) {
+           all_numeric = 0;
+       }
+    }
+
+    if (all_numeric == 1) {
+       port = atoi(service);
+    } else {
+        struct servent *sp;
+
+       if ((sp = getservbyname(service, proto)) == NULL) {
+           port = 0;
+       } else {
+           port = (in_port_t)(ntohs((in_port_t)sp->s_port));
+       }
+    }
+
+    return port;
+}
+
+char *
+sec_get_authenticated_peer_name_gethostname(
+    security_handle_t *hdl G_GNUC_UNUSED)
+{
+    char *server_hostname;
+    server_hostname = malloc(1024);
+    if (gethostname(server_hostname, 1024) == 0) {
+       server_hostname[1023] = '\0';
+       return server_hostname;
+    }
+    amfree(server_hostname);
+    return strdup("localhost");
+}
+
+char *
+sec_get_authenticated_peer_name_hostname(
+    security_handle_t *hdl)
+{
+    char *hostname = ((struct sec_handle *)hdl)->hostname;
+    if (!hostname)
+       hostname = "";
+    return strdup(hostname);
 }