Imported Upstream version 3.2.0
[debian/amanda] / common-src / security-util.c
index e326258d6dc208ac9633c0ef791917e9bec1f4c9..bc108cdd0fbfcd4747579ce02ce4f933bdd728c9 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"
 #include "sockaddr-util.h"
 
-/*
- * 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 */
-
 /*
  * 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;
 
@@ -112,7 +102,7 @@ sec_accept(
 {
     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;
@@ -229,7 +219,8 @@ stream_sendpkt(
       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);
@@ -330,7 +321,7 @@ tcpm_stream_write(
 
     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);
@@ -354,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);
     }
@@ -362,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.
  */
@@ -380,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);
 }
 
 /*
@@ -427,11 +425,19 @@ tcpm_send_token(
     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);
+              len, handle);
     /*
      * Format is:
      *   32 bit length (network byte order)
@@ -466,7 +472,8 @@ tcpm_send_token(
         nb_iov = 3;
     }
 
-    rval = net_writev(fd, iov, nb_iov);
+    rval = full_writev(fd, iov, nb_iov);
+    save_errno = errno;
     if (len != 0 && rc->driver->data_encrypt != NULL && buf != encbuf) {
        amfree(encbuf);
     }
@@ -474,13 +481,14 @@ tcpm_send_token(
     if (rval < 0) {
        if (errmsg)
             *errmsg = newvstrallocf(*errmsg, _("write error to: %s"),
-                                  strerror(errno));
+                                  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
@@ -494,93 +502,118 @@ tcpm_recv_token(
     int *      handle,
     char **    errmsg,
     char **    buf,
-    ssize_t *  size,
-    int                timeout)
+    ssize_t *  size)
 {
-    unsigned int netint[2];
-
-    assert(SIZEOF(netint) == 8);
-
-    switch (net_read(fd, &netint, SIZEOF(netint), timeout)) {
-    case -1:
-       if (errmsg)
-           *errmsg = newvstrallocf(*errmsg, _("recv error: %s"), strerror(errno));
-       auth_debug(1, _("tcpm_recv_token: A return(-1)\n"));
-       return (-1);
-    case 0:
-       *size = 0;
-       *handle = H_EOF;
-       *errmsg = newvstrallocf(*errmsg, _("SOCKET_EOF"));
-       auth_debug(1, _("tcpm_recv_token: A return(0)\n"));
-       return (0);
-    default:
-       break;
-    }
-
-    *size = (ssize_t)ntohl(netint[0]);
-    *handle = (int)ntohl(netint[1]);
-    /* 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[101];
-           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<100 && 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:
+    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);
            }
-           s[i] = '\0';
-           *errmsg = newvstrallocf(*errmsg, _("tcpm_recv_token: invalid size: %s"), s);
-           dbprintf(_("tcpm_recv_token: invalid size %s\n"), s);
-       } else {
-           *errmsg = newvstrallocf(*errmsg, _("tcpm_recv_token: invalid size"));
-           dbprintf(_("tcpm_recv_token: invalid size %zd\n"), *size);
+           *size = -1;
+           return -1;
        }
-       *size = -1;
-       return -1;
-    }
-    amfree(*buf);
-    *buf = alloc((size_t)*size);
+        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"));
-       return 0;
+       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;
+       }
     }
-    switch (net_read(fd, *buf, (size_t)*size, timeout)) {
-    case -1:
+
+    *size = (ssize_t)ntohl(rc->netint[0]);
+    *handle = (int)ntohl(rc->netint[1]);
+
+    rval = read(fd, rc->buffer + rc->size_buffer_read,
+                   (size_t)*size - rc->size_buffer_read);
+    if (rval == -1) {
        if (errmsg)
-           *errmsg = newvstrallocf(*errmsg, _("recv error: %s"), strerror(errno));
+           *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;
        *errmsg = newvstrallocf(*errmsg, _("SOCKET_EOF"));
        auth_debug(1, _("tcpm_recv_token: B return(0)\n"));
        return (0);
-    default:
-       break;
+    } 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 = 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);
 
@@ -607,7 +640,7 @@ tcpm_close_connection(
 
     (void)hostname;
 
-    if (rh && rh->rc && 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);
     }
@@ -648,7 +681,7 @@ tcpma_stream_client(
        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;
@@ -682,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;
@@ -734,6 +767,7 @@ tcpma_stream_close(
     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);
 }
 
@@ -750,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;
@@ -764,7 +798,7 @@ 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(rh->udp->peer.ss_family, &rs->port,
+       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,
@@ -822,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;
@@ -859,10 +893,17 @@ 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));
         return (-1);
@@ -882,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);
+                         (long)geteuid());
+       return "";
     }
     buf = alloc(16+strlen(pwd->pw_name));
     strncpy(buf, "SECURITY USER ", (16 + strlen(pwd->pw_name)));
@@ -963,7 +1004,7 @@ bsd_recv_security_ok(
        /*
         * Request packets must come from a reserved port
         */
-    port = SS_GET_PORT(&rh->peer);
+    port = SU_GET_PORT(&rh->peer);
        if (port >= IPPORT_RESERVED) {
            security_seterror(&rh->sech,
                _("host %s: port %u not secure"), rh->hostname,
@@ -1016,6 +1057,7 @@ bsd_recv_security_ok(
        if ((tok = strtok(NULL, "")) == NULL) {
            security_seterror(&rh->sech,
                _("SECURITY line: %s"), security_line);
+           amfree(service);
            amfree(security_line);
            return (-1);        /* default errmsg */
        }
@@ -1063,7 +1105,7 @@ udpbsd_sendpkt(
      * 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
@@ -1089,7 +1131,7 @@ udpbsd_sendpkt(
     /*
      * Add the body, and send it
      */
-    dgram_cat(&rh->udp->dgram, pkt->body);
+    dgram_cat(&rh->udp->dgram, "%s", pkt->body);
 
     auth_debug(1,
      _("sec: udpbsd_sendpkt: %s (%d) pkt_t (len %zu) contains:\n\n\"%s\"\n\n"),
@@ -1274,7 +1316,7 @@ udp_inithandle(
     udp_handle_t *     udp,
     struct sec_handle *        rh,
     char *              hostname,
-    struct sockaddr_storage *addr,
+    sockaddr_union *addr,
     in_port_t          port,
     char *             handle,
     int                        sequence)
@@ -1288,7 +1330,7 @@ udp_inithandle(
 
     rh->hostname = stralloc(hostname);
     copy_sockaddr(&rh->peer, addr);
-    SS_SET_PORT(&rh->peer, port);
+    SU_SET_PORT(&rh->peer, port);
 
 
     rh->prev = udp->bh_last;
@@ -1372,7 +1414,7 @@ udp_netfd_read_callback(
        return;
     }
 
-    rh = alloc(SIZEOF(*rh));
+    rh = g_new0(struct sec_handle, 1);
     rh->proto_handle=NULL;
     rh->udp = udp;
     rh->rc = NULL;
@@ -1395,7 +1437,7 @@ udp_netfd_read_callback(
        return;
     }
 
-    port = SS_GET_PORT(&udp->peer);
+    port = SU_GET_PORT(&udp->peer);
     a = udp_inithandle(udp, rh,
                   hostname,
                   &udp->peer,
@@ -1428,17 +1470,19 @@ sec_tcp_conn_get(
     const char *hostname,
     int                want_new)
 {
-    struct tcp_conn *rc;
+    GSList *iter;
+    struct tcp_conn *rc = NULL;
 
     auth_debug(1, _("sec_tcp_conn_get: %s\n"), hostname);
 
     if (want_new == 0) {
-       for (rc = connq_first(); rc != NULL; rc = connq_next(rc)) {
+       for (iter = connq; iter != NULL; iter = iter->next) {
+           rc = (struct tcp_conn *)iter->data;
            if (strcasecmp(hostname, rc->hostname) == 0)
                break;
        }
 
-       if (rc != NULL) {
+       if (iter != NULL) {
            rc->refcnt++;
            auth_debug(1,
                      _("sec_tcp_conn_get: exists, refcnt to %s is now %d\n"),
@@ -1451,7 +1495,7 @@ sec_tcp_conn_get(
     /*
      * 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;
@@ -1470,7 +1514,8 @@ sec_tcp_conn_get(
     rc->auth = 0;
     rc->conf_fn = NULL;
     rc->datap = NULL;
-    connq_append(rc);
+    rc->event_id = newevent++;
+    connq = g_slist_append(connq, rc);
     return (rc);
 }
 
@@ -1503,12 +1548,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'.
+        */
+    }
 }
 
 /*
@@ -1583,7 +1631,7 @@ recvpkt_callback(
        (*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:
@@ -1635,9 +1683,13 @@ 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) {
        auth_debug(1, _("sec: stream_read_sync_callback: %s\n"), rs->rc->errmsg);
-       security_stream_seterror(&rs->secstr, 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;
@@ -1656,8 +1708,15 @@ stream_read_callback(
     void *     arg)
 {
     struct sec_stream *rs = arg;
+    time_t             logtime;
+
     assert(rs != NULL);
 
+    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);
 
     /*
@@ -1683,7 +1742,7 @@ stream_read_callback(
 
     if (rs->rc->pktlen <= 0) {
        auth_debug(1, _("sec: stream_read_callback: %s\n"), rs->rc->errmsg);
-       security_stream_seterror(&rs->secstr, 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;
@@ -1717,13 +1776,18 @@ sec_tcp_conn_read_callback(
 
     /* Read the data off the wire.  If we get errors, shut down. */
     rval = tcpm_recv_token(rc, rc->read, &rc->handle, &rc->errmsg, &rc->pkt,
-                               &rc->pktlen, 60);
+                               &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);
+       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 */
@@ -1741,7 +1805,7 @@ sec_tcp_conn_read_callback(
 
     if(rval == 0) {
        rc->pktlen = 0;
-       revent = event_wakeup((event_id_t)rc);
+       revent = event_wakeup((event_id_t)rc->event_id);
        auth_debug(1,
                   _("sec: conn_read_callback: event_wakeup return %d\n"), revent);
        return;
@@ -1749,8 +1813,8 @@ sec_tcp_conn_read_callback(
 
     /* If there are events waiting on this handle, we're done */
     rc->donotclose = 1;
-    revent = event_wakeup((event_id_t)rc);
-    auth_debug(1, _("sec: conn_read_callback: event_wakeup return %zd\n"), 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);
@@ -1760,10 +1824,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;
@@ -2077,7 +2145,7 @@ check_user_ruserok(
 char *
 check_user_amandahosts(
     const char *       host,
-    struct sockaddr_storage *addr,
+    sockaddr_union *addr,
     struct passwd *    pwd,
     const char *       remoteuser,
     const char *       service)
@@ -2160,12 +2228,12 @@ check_user_amandahosts(
            (strcasecmp(filehost, "localhost")== 0 ||
             strcasecmp(filehost, "localhost.localdomain")== 0)) {
 #ifdef WORKING_IPV6
-           if (addr->ss_family == (sa_family_t)AF_INET6)
-               inet_ntop(AF_INET6, &((struct sockaddr_in6 *)addr)->sin6_addr,
+           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, &((struct sockaddr_in *)addr)->sin_addr,
+               inet_ntop(AF_INET, &addr->sin.sin_addr,
                          ipstr, sizeof(ipstr));
            if (strcmp(ipstr, "127.0.0.1") == 0 ||
                strcmp(ipstr, "::1") == 0)
@@ -2237,7 +2305,7 @@ check_user_amandahosts(
     if (! found) {
        if (strcmp(service, "amindexd") == 0 ||
            strcmp(service, "amidxtaped") == 0) {
-           result = vstrallocf(_("Please add the line \"%s %s amindexd amidxtaped\" to %s on the client"), host, remoteuser, ptmp);
+           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 ||
@@ -2260,7 +2328,7 @@ common_exit:
 /* return 1 on success, 0 on failure */
 int
 check_security(
-    struct sockaddr_storage *addr,
+    sockaddr_union *addr,
     char *             str,
     unsigned long      cksum,
     char **            errstr)
@@ -2304,7 +2372,7 @@ check_security(
 
 
     /* next, make sure the remote port is a "reserved" one */
-    port = SS_GET_PORT(addr);
+    port = SU_GET_PORT(addr);
     if (port >= IPPORT_RESERVED) {
        *errstr = vstrallocf(_("[host %s: port %u not secure]"),
                        remotehost, (unsigned int)port);
@@ -2365,57 +2433,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);
-           auth_debug(1, _("net_writev got EINTR\n"));
-       }
-       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 < (size_t)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.
  */
@@ -2504,14 +2521,14 @@ show_stat_info(
 {
     char *name = vstralloc(a, b, NULL);
     struct stat sbuf;
-    struct passwd *pwptr;
-    struct passwd pw;
+    struct passwd *pwptr G_GNUC_UNUSED;
+    struct passwd pw G_GNUC_UNUSED;
     char *owner;
-    struct group *grptr;
-    struct group gr;
+    struct group *grptr G_GNUC_UNUSED;
+    struct group gr G_GNUC_UNUSED;
     char *group;
-    int buflen;
-    char *buf;
+    int buflen G_GNUC_UNUSED;
+    char *buf G_GNUC_UNUSED;
 
     if (stat(name, &sbuf) != 0) {
        auth_debug(1, _("bsd: cannot stat %s: %s\n"), name, strerror(errno));
@@ -2528,20 +2545,27 @@ show_stat_info(
 #endif
     buf = malloc(buflen);
 
-    if (getpwuid_r(sbuf.st_uid, &pw, buf, buflen, &pwptr) != 0 ||
-       pwptr == NULL) {
+#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);
-    } else {
-       owner = stralloc(pwptr->pw_name);
     }
-    if (getgrgid_r(sbuf.st_gid, &gr, buf, buflen, &grptr) != 0 ||
-       grptr == NULL) {
-       group = alloc(NUM_STR_SIZE + 1);
-       g_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);
     }
+
     auth_debug(1, _("bsd: processing file: %s\n"), name);
     auth_debug(1, _("bsd:                  owner=%s group=%s mode=%03o\n"),
                   owner, group,
@@ -2588,20 +2612,67 @@ check_name_give_sockaddr(
     }
 
     for(res1=res; res1 != NULL; res1 = res1->ai_next) {
-       if (cmp_sockaddr((struct sockaddr_storage *)res1->ai_addr, (struct sockaddr_storage *)addr, 1) == 0) {
+       if (cmp_sockaddr((sockaddr_union *)res1->ai_addr, (sockaddr_union *)addr, 1) == 0) {
            freeaddrinfo(res);
            amfree(canonname);
            return 0;
        }
     }
 
-    dbprintf(_("%s doesn't resolve to %s"),
-           hostname, str_sockaddr((struct sockaddr_storage *)addr));
+    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((struct sockaddr_storage *)addr));
+                          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_localhost(
+    security_handle_t *hdl G_GNUC_UNUSED)
+{
+    return "localhost";
+}
+
+char *
+sec_get_authenticated_peer_name_hostname(
+    security_handle_t *hdl)
+{
+    char *hostname = ((struct sec_handle *)hdl)->hostname;
+    if (!hostname)
+       hostname = "";
+    return hostname;
+}