Imported Upstream version 2.5.1
[debian/amanda] / common-src / bsd-security.c
index 60e63d3eecf49868d0f494838892fe2a8c15bfc4..2d0766d6cacfcdc06769f2521221e776c6e38249 100644 (file)
@@ -24,7 +24,7 @@
  * file named AUTHORS, in the root directory of this distribution.
  */
 /*
- * $Id: bsd-security.c,v 1.54 2006/03/09 16:51:41 martinea Exp $
+ * $Id: bsd-security.c,v 1.75 2006/07/19 17:41:14 martinea Exp $
  *
  * "BSD" security module
  */
@@ -36,6 +36,7 @@
 #include "event.h"
 #include "packet.h"
 #include "security.h"
+#include "security-util.h"
 #include "stream.h"
 #include "version.h"
 
 #define bsdprintf(p)   printf p
 #endif                                                         /* } */
 
-/*
- * This is the private handle data
- */
-struct bsd_handle {
-    /*
-     * This must be first.  Instances of bsd_handle will be cast to
-     * security_handle_t's.
-     */
-    security_handle_t sech;
-
-    /*
-     * protocol handle for this request.  Each request gets its own
-     * handle, so we differentiate packets for them with a "handle" header
-     * in each packet.
-     *
-     */
-    int event_id; /* unique event_id */
-    char *proto_handle;
-
-    /*
-     * sequence number.
-     */
-    int sequence;
-
-    /*
-     * The remote host we're transmitting to
-     */
-    char hostname[256];
-    struct sockaddr_in peer;
-
-    /*
-     * Function to call when recvpkt detects new incoming data for this
-     * handle
-     */
-    void (*fn) P((void *, pkt_t *, security_status_t));
-
-    /*
-     * Argument for previous function
-     */
-    void *arg;
-
-    /*
-     * read (EV_WAIT) handle for a recv
-     */
-    event_handle_t *ev_read;
-
-    /*
-     * Timeout handle for a recv
-     */
-    event_handle_t *ev_timeout;
-
-    struct bsd_handle *prev, *next;
-};
-
-struct bsd_handle *bh_first=NULL, *bh_last=NULL;
-
-/*
- * This is the internal security_stream data
- */
-struct bsd_stream {
-    /*
-     * This must be first, because instances of this will be cast
-     * to security_stream_t's outside of this module.
-     */
-    security_stream_t secstr;
-
-    /*
-     * This is the file descriptor which we will do io on
-     */
-    int fd;
-
-    /*
-     * This is the file descriptor which we will listen for incoming
-     * connections on (for streams which receive connections)
-     */
-    int socket;
-
-    /*
-     * This is the local port this stream is bound to
-     */
-    int port;
-
-    /*
-     * This is the read event handle for this data stream
-     */
-    event_handle_t *ev_read;
-
-    /*
-     * This is the function and argument that is called when this stream
-     * is readable.  It is passed a buffer of data read.
-     */
-    void (*fn) P((void *, void *, ssize_t));
-    void *arg;
-
-    /*
-     * This is the buffer that we read data into that will be passed
-     * to the read callback.
-     */
-    char databuf[NETWORK_BLOCK_BYTES];
-};
-
 /*
  * Interface functions
  */
-static void bsd_connect P((const char *,
-    char *(*)(char *, void *), 
-    void (*)(void *, security_handle_t *, security_status_t), void *));
-static void bsd_accept P((int, int, void (*)(security_handle_t *, pkt_t *)));
-static void bsd_close P((void *));
-static int bsd_sendpkt P((void *, pkt_t *));
-static void bsd_recvpkt P((void *,
-    void (*)(void *, pkt_t *, security_status_t), void *, int));
-static void bsd_recvpkt_cancel P((void *));
-
-static void *bsd_stream_server P((void *));
-static int bsd_stream_accept P((void *));
-static void *bsd_stream_client P((void *, int));
-static void bsd_stream_close P((void *));
-static int bsd_stream_auth P((void *));
-static int bsd_stream_id P((void *));
-static int bsd_stream_write P((void *, const void *, size_t));
-static void bsd_stream_read P((void *, void (*)(void *, void *, ssize_t),
-    void *));
-static void bsd_stream_read_cancel P((void *));
+static void    bsd_connect(const char *, char *(*)(char *, void *), 
+                       void (*)(void *, security_handle_t *, security_status_t),
+                       void *, void *);
+static void    bsd_accept(const struct security_driver *, int, int,
+                       void (*)(security_handle_t *, pkt_t *));
+static void    bsd_close(void *);
+static void *  bsd_stream_server(void *);
+static int     bsd_stream_accept(void *);
+static void *  bsd_stream_client(void *, int);
+static void    bsd_stream_close(void *);
+static int     bsd_stream_auth(void *);
+static int     bsd_stream_id(void *);
+static void    bsd_stream_read(void *, void (*)(void *, void *, ssize_t), void *);
+static ssize_t bsd_stream_read_sync(void *, void **);
+static void    bsd_stream_read_cancel(void *);
 
 /*
  * This is our interface to the outside world
@@ -198,142 +93,54 @@ const security_driver_t bsd_security_driver = {
     bsd_connect,
     bsd_accept,
     bsd_close,
-    bsd_sendpkt,
-    bsd_recvpkt,
-    bsd_recvpkt_cancel,
+    udpbsd_sendpkt,
+    udp_recvpkt,
+    udp_recvpkt_cancel,
     bsd_stream_server,
     bsd_stream_accept,
     bsd_stream_client,
     bsd_stream_close,
     bsd_stream_auth,
     bsd_stream_id,
-    bsd_stream_write,
+    tcp_stream_write,
     bsd_stream_read,
+    bsd_stream_read_sync,
     bsd_stream_read_cancel,
+    sec_close_connection_none,
 };
 
 /*
  * This is data local to the datagram socket.  We have one datagram
  * per process, so it is global.
  */
-static struct {
-    dgram_t dgram;             /* datagram to read/write from */
-    struct sockaddr_in peer;   /* who sent it to us */
-    pkt_t pkt;                 /* parsed form of dgram */
-    char *handle;              /* handle from recvd packet */
-    int sequence;              /* seq no of packet */
-    event_handle_t *ev_read;   /* read event handle from dgram */
-    int refcnt;                        /* number of handles blocked for reading */
-} netfd;
+static udp_handle_t netfd;
+static int not_init = 1;
 
 /* generate new handles from here */
 static int newhandle = 0;
-static int newevent = 0;
-
-/*
- * We register one event handler for our network fd which takes
- * care of all of our async requests.  When all async requests
- * have either been satisfied or cancelled, we unregister our
- * network event handler.
- */
-#define        netfd_addref()  do      {                                       \
-    if (netfd.refcnt++ == 0) {                                         \
-       assert(netfd.ev_read == NULL);                                  \
-       netfd.ev_read = event_register(netfd.dgram.socket, EV_READFD,   \
-           netfd_read_callback, NULL);                                 \
-    }                                                                  \
-    assert(netfd.refcnt > 0);                                          \
-} while (0)
-
-/*
- * If this is the last request to be removed, then remove the
- * reader event from the netfd.
- */
-#define        netfd_delref()  do      {                                       \
-    assert(netfd.refcnt > 0);                                          \
-    if (--netfd.refcnt == 0) {                                         \
-       assert(netfd.ev_read != NULL);                                  \
-       event_release(netfd.ev_read);                                   \
-       netfd.ev_read = NULL;                                           \
-    }                                                                  \
-} while (0)
-
-/*
- * This is the function and argument that is called when new requests
- * arrive on the netfd.
- */
-static void (*accept_fn) P((security_handle_t *, pkt_t *));
 
 /*
  * These are the internal helper functions
  */
-static char *check_user P((struct bsd_handle *, const char *));
-static int inithandle P((struct bsd_handle *, struct hostent *,
-                        int, char *, int));
-static const char *pkthdr2str P((const struct bsd_handle *, const pkt_t *));
-static int str2pkthdr P((void));
-static void netfd_read_callback P((void *));
-static void recvpkt_callback P((void *));
-static void recvpkt_timeout P((void *));
-static int recv_security_ok P((struct bsd_handle *));
-static void stream_read_callback P((void *));
-
-
-#if defined(SHOW_SECURITY_DETAIL)                              /* { */
-/*
- * Display stat() information about a file.
- */
-void show_stat_info(a, b)
-    char *a, *b;
-{
-    char *name = vstralloc(a, b, NULL);
-    struct stat sbuf;
-    struct passwd *pwptr;
-    char *owner;
-    struct group *grptr;
-    char *group;
-
-    if (stat(name, &sbuf) != 0) {
-       bsdprintf(("%s: cannot stat %s: %s\n",
-                  debug_prefix_time(NULL), 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 {
-       owner = stralloc(pwptr->pw_name);
-    }
-    if ((grptr = getgrgid(sbuf.st_gid)) == NULL) {
-       group = alloc(NUM_STR_SIZE + 1);
-       snprintf(owner, NUM_STR_SIZE, "%ld", (long)sbuf.st_gid);
-    } else {
-       group = stralloc(grptr->gr_name);
-    }
-    bsdprintf(("%s: processing file: %s\n", debug_prefix(NULL), name));
-    bsdprintf(("%s:                  owner=%s group=%s mode=%03o\n",
-              debug_prefix(NULL), owner, group, (int) (sbuf.st_mode & 0777)));
-    amfree(name);
-    amfree(owner);
-    amfree(group);
-}
-#endif                                                         /* } */
+static void    stream_read_callback(void *);
+static void    stream_read_sync_callback(void *);
 
 /*
  * Setup and return a handle outgoing to a client
  */
+
 static void
-bsd_connect(hostname, conf_fn, fn, arg)
-    const char *hostname;
-    char *(*conf_fn) P((char *, void *));
-    void (*fn) P((void *, security_handle_t *, security_status_t));
-    void *arg;
-{
-    struct bsd_handle *bh;
+bsd_connect(
+    const char *       hostname,
+    char *             (*conf_fn)(char *, void *),
+    void               (*fn)(void *, security_handle_t *, security_status_t),
+    void *             arg,
+    void *             datap)
+{
+    struct sec_handle *bh;
     struct servent *se;
     struct hostent *he;
-    int port;
+    in_port_t port = 0;
     struct timeval sequence_time;
     amanda_timezone dontcare;
     int sequence;
@@ -341,31 +148,40 @@ bsd_connect(hostname, conf_fn, fn, arg)
 
     assert(hostname != NULL);
 
-    bh = alloc(sizeof(*bh));
+    (void)conf_fn;     /* Quiet unused parameter warning */
+    (void)datap;        /* Quiet unused parameter warning */
+
+    bh = alloc(SIZEOF(*bh));
     bh->proto_handle=NULL;
+    bh->udp = &netfd;
     security_handleinit(&bh->sech, &bsd_security_driver);
 
     /*
      * Only init the socket once
      */
-    if (netfd.dgram.socket == 0) {
+    if (not_init == 1) {
        uid_t euid;
        dgram_zero(&netfd.dgram);
-       
+
        euid = geteuid();
-       seteuid(0);
+       seteuid((uid_t)0);
        dgram_bind(&netfd.dgram, &port);
        seteuid(euid);
+       netfd.handle = NULL;
+       netfd.pkt.body = NULL;
+       netfd.recv_security_ok = &bsd_recv_security_ok;
+       netfd.prefix_packet = &bsd_prefix_packet;
        /*
         * We must have a reserved port.  Bomb if we didn't get one.
         */
        if (port >= IPPORT_RESERVED) {
            security_seterror(&bh->sech,
-               "unable to bind to a reserved port (got port %d)",
-               port);
+               "unable to bind to a reserved port (got port %u)",
+               (unsigned int)port);
            (*fn)(arg, &bh->sech, S_ERROR);
            return;
        }
+       not_init = 0;
     }
 
     if ((he = gethostbyname(hostname)) == NULL) {
@@ -374,32 +190,42 @@ bsd_connect(hostname, conf_fn, fn, arg)
        (*fn)(arg, &bh->sech, S_ERROR);
        return;
     }
+    bsdprintf(("Resolved hostname=%s\n", hostname));
     if ((se = getservbyname(AMANDA_SERVICE_NAME, "udp")) == NULL)
-       port = htons(AMANDA_SERVICE_DEFAULT);
+       port = (in_port_t)htons(AMANDA_SERVICE_DEFAULT);
     else
-       port = se->s_port;
+       port = (in_port_t)se->s_port;
     amanda_gettimeofday(&sequence_time, &dontcare);
     sequence = (int)sequence_time.tv_sec ^ (int)sequence_time.tv_usec;
-    handle=malloc(15);
-    snprintf(handle,14,"000-%08x", newhandle++);
-    if (inithandle(bh, he, port, handle, sequence) < 0)
+    handle=alloc(15);
+    snprintf(handle, 14, "000-%08x",  (unsigned)newhandle++);
+    if (udp_inithandle(&netfd, bh, he, port, handle, sequence) < 0) {
        (*fn)(arg, &bh->sech, S_ERROR);
+       amfree(bh->hostname);
+       amfree(bh);
+    }
     else
        (*fn)(arg, &bh->sech, S_OK);
+    amfree(handle);
 }
 
 /*
  * Setup to accept new incoming connections
  */
 static void
-bsd_accept(in, out, fn)
-    int in, out;
-    void (*fn) P((security_handle_t *, pkt_t *));
+bsd_accept(
+    const struct security_driver *     driver,
+    int                in,
+    int                out,
+    void       (*fn)(security_handle_t *, pkt_t *))
 {
 
     assert(in >= 0 && out >= 0);
     assert(fn != NULL);
 
+    (void)out; /* Quiet unused parameter warning */
+    (void)driver; /* Quiet unused parameter warning */
+
     /*
      * We assume in and out point to the same socket, and just use
      * in.
@@ -411,983 +237,67 @@ bsd_accept(in, out, fn)
      * the recvpkt callback will call this function when it discovers
      * new incoming connections
      */
-    accept_fn = fn;
-
-    netfd_addref();
-}
-
-/*
- * Given a hostname and a port, setup a bsd_handle
- */
-static int
-inithandle(bh, he, port, handle, sequence)
-    struct bsd_handle *bh;
-    struct hostent *he;
-    int port;
-    char *handle;
-    int sequence;
-{
-    int i;
-
-    assert(he != NULL);
-    assert(port > 0);
-
-    /*
-     * Save the hostname and port info
-     */
-    strncpy(bh->hostname, he->h_name, sizeof(bh->hostname) - 1);
-    bh->hostname[sizeof(bh->hostname) - 1] = '\0';
-    bh->peer.sin_addr = *(struct in_addr *)he->h_addr;
-    bh->peer.sin_port = port;
-    bh->peer.sin_family = AF_INET;
-
-    bh->prev = bh_last;
-    if(bh_last) {bh->prev->next = bh;}
-    if(!bh_first) {bh_first = bh;}
-    bh->next = NULL;
-    bh_last = bh;
-
-    /*
-     * 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(bh->hostname)) == NULL) {
-       security_seterror(&bh->sech,
-           "%s: could not resolve hostname", bh->hostname);
-       return (-1);
-    }
-    /*
-     * Make sure the hostname matches.  This should always work.
-     */
-    if (strncasecmp(bh->hostname, he->h_name, strlen(bh->hostname)) != 0) {
-       security_seterror(&bh->sech,
-           "%s: did not resolve to %s", bh->hostname, bh->hostname);
-       return (-1);
-    }
-
-    /*
-     * Now look for a matching ip address.
-     */
-    for (i = 0; he->h_addr_list[i] != NULL; i++) {
-       if (memcmp(&bh->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(bh->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(&bh->sech,
-               "DNS check failed: no matching ip address for %s",
-               bh->hostname);
-           return (-1);
-       }
-    }
-
-    bh->sequence = sequence;
-    bh->event_id = newevent++;
-    bh->proto_handle = handle;
-    bh->fn = NULL;
-    bh->arg = NULL;
-    bh->ev_read = NULL;
-    bh->ev_timeout = NULL;
-
-    bsdprintf(("%s: adding handle '%s'\n",
-              debug_prefix_time(NULL), bh->proto_handle));
+    netfd.accept_fn = fn;
+    netfd.recv_security_ok = &bsd_recv_security_ok;
+    netfd.prefix_packet = &bsd_prefix_packet;
+    netfd.driver = &bsd_security_driver;
 
-    return(0);
+    udp_addref(&netfd, &udp_netfd_read_callback);
 }
 
 /*
  * Frees a handle allocated by the above
  */
 static void
-bsd_close(cookie)
-    void *cookie;
+bsd_close(
+    void *     cookie)
 {
-    struct bsd_handle *bh = cookie;
+    struct sec_handle *bh = cookie;
 
     if(bh->proto_handle == NULL) {
        return;
     }
 
-    bsdprintf(("%s: close handle '%s'\n",
+    bsdprintf(("%s: bsd: close handle '%s'\n",
               debug_prefix_time(NULL), bh->proto_handle));
 
-    bsd_recvpkt_cancel(bh);
+    udp_recvpkt_cancel(bh);
     if(bh->next) {
        bh->next->prev = bh->prev;
     }
     else {
-       bh_last = bh->prev;
+       netfd.bh_last = bh->prev;
     }
     if(bh->prev) {
        bh->prev->next = bh->next;
     }
     else {
-       bh_first = bh->next;
+       netfd.bh_first = bh->next;
     }
 
+    amfree(bh->proto_handle);
+    amfree(bh->hostname);
     amfree(bh);
 }
 
-/*
- * Transmit a packet.  Add security information first.
- */
-static int
-bsd_sendpkt(cookie, pkt)
-    void *cookie;
-    pkt_t *pkt;
-{
-    struct bsd_handle *bh = cookie;
-    struct passwd *pwd;
-
-    assert(bh != NULL);
-    assert(pkt != NULL);
-
-    /*
-     * Initialize this datagram, and add the header
-     */
-    dgram_zero(&netfd.dgram);
-    dgram_cat(&netfd.dgram, pkthdr2str(bh, pkt));
-
-    /*
-     * Add the security info.  This depends on which kind of packet we're
-     * sending.
-     */
-    switch (pkt->type) {
-    case P_REQ:
-       /*
-        * Requests get sent with our username in the body
-        */
-       if ((pwd = getpwuid(geteuid())) == NULL) {
-           security_seterror(&bh->sech,
-               "can't get login name for my uid %ld", (long)getuid());
-           return (-1);
-       }
-       dgram_cat(&netfd.dgram, "SECURITY USER %s\n", pwd->pw_name);
-       break;
-
-    default:
-       break;
-    }
-
-    /*
-     * Add the body, and send it
-     */
-    dgram_cat(&netfd.dgram, pkt->body);
-    if (dgram_send_addr(bh->peer, &netfd.dgram) != 0) {
-       security_seterror(&bh->sech,
-           "send %s to %s failed: %s", pkt_type2str(pkt->type),
-           bh->hostname, strerror(errno));
-       return (-1);
-    }
-    return (0);
-}
-
-/*
- * Set up to receive a packet asynchronously, and call back when it has
- * been read.
- */
-static void
-bsd_recvpkt(cookie, fn, arg, timeout)
-    void *cookie, *arg;
-    void (*fn) P((void *, pkt_t *, security_status_t));
-    int timeout;
-{
-    struct bsd_handle *bh = cookie;
-
-    assert(bh != NULL);
-    assert(fn != NULL);
-
-
-    /*
-     * Subsequent recvpkt calls override previous ones
-     */
-    if (bh->ev_read == NULL) {
-       netfd_addref();
-       bh->ev_read = event_register(bh->event_id, EV_WAIT,
-           recvpkt_callback, bh);
-    }
-    if (bh->ev_timeout != NULL)
-       event_release(bh->ev_timeout);
-    if (timeout < 0)
-       bh->ev_timeout = NULL;
-    else
-       bh->ev_timeout = event_register(timeout, EV_TIME, recvpkt_timeout, bh);
-    bh->fn = fn;
-    bh->arg = arg;
-}
-
-/*
- * Remove a async receive request on this handle from the queue.
- * If it is the last one to be removed, then remove the event
- * handler for our network fd
- */
-static void
-bsd_recvpkt_cancel(cookie)
-    void *cookie;
-{
-    struct bsd_handle *bh = cookie;
-
-    assert(bh != NULL);
-
-    if (bh->ev_read != NULL) {
-       netfd_delref();
-       event_release(bh->ev_read);
-       bh->ev_read = NULL;
-    }
-
-    if (bh->ev_timeout != NULL) {
-       event_release(bh->ev_timeout);
-       bh->ev_timeout = NULL;
-    }
-}
-
-/*
- * Callback for received packets.  This is the function bsd_recvpkt
- * registers with the event handler.  It is called when the event handler
- * realizes that data is waiting to be read on the network socket.
- */
-static void
-netfd_read_callback(cookie)
-    void *cookie;
-{
-    struct bsd_handle *bh;
-    struct hostent *he;
-    int a;
-
-    assert(cookie == NULL);
-
-#ifndef TEST                                                   /* { */
-    /*
-     * Receive the packet.
-     */
-    dgram_zero(&netfd.dgram);
-    if (dgram_recv(&netfd.dgram, 0, &netfd.peer) < 0)
-       return;
-#endif /* !TEST */                                             /* } */
-
-    /*
-     * Parse the packet.
-     */
-    if (str2pkthdr() < 0)
-       return;
-
-    /*
-     * If there are events waiting on this handle, we're done
-     */
-    bh = bh_first;
-    while(bh != NULL && (strcmp(bh->proto_handle, netfd.handle) != 0 ||
-                        bh->sequence != netfd.sequence ||
-                        bh->peer.sin_addr.s_addr != netfd.peer.sin_addr.s_addr ||
-                        bh->peer.sin_port != netfd.peer.sin_port)) {
-       bh = bh->next;
-    }
-    if (bh && event_wakeup(bh->event_id) > 0)
-       return;
-
-    /*
-     * If we didn't find a handle, then check for a new incoming packet.
-     * If no accept handler was setup, then just return.
-     */
-    if (accept_fn == NULL)
-       return;
-
-    he = gethostbyaddr((void *)&netfd.peer.sin_addr,
-       (int)sizeof(netfd.peer.sin_addr), AF_INET);
-    if (he == NULL)
-       return;
-    bh = alloc(sizeof(*bh));
-    bh->proto_handle=NULL;
-    security_handleinit(&bh->sech, &bsd_security_driver);
-    a = inithandle(bh,
-                  he,
-                  netfd.peer.sin_port,
-                  netfd.handle,
-                  netfd.sequence);
-    if (a < 0) {
-       if(bh->next) {
-           bh->next->prev = bh->prev;
-       }
-       else {
-           bh_last = bh->prev;
-       }
-       if(bh->prev) {
-           bh->prev->next = bh->next;
-       }
-       else {
-           bh_first = bh->prev;
-       }
-
-       bsdprintf(("%s: closeX handle '%s'\n",
-                 debug_prefix_time(NULL), bh->proto_handle));
-
-       amfree(bh);
-       return;
-    }
-    /*
-     * Check the security of the packet.  If it is bad, then pass NULL
-     * to the accept function instead of a packet.
-     */
-    if (recv_security_ok(bh) < 0)
-       (*accept_fn)(&bh->sech, NULL);
-    else
-       (*accept_fn)(&bh->sech, &netfd.pkt);
-}
-
-/*
- * This is called when a handle is woken up because data read off of the
- * net is for it.
- */
-static void
-recvpkt_callback(cookie)
-    void *cookie;
-{
-    struct bsd_handle *bh = cookie;
-    void (*fn) P((void *, pkt_t *, security_status_t));
-    void *arg;
-
-    assert(bh != NULL);
-    bsdprintf(("%s: receive handle '%s' netfd '%s'\n",
-              debug_prefix_time(NULL), bh->proto_handle,netfd.handle));
-
-    if(strcmp(bh->proto_handle,netfd.handle) != 0) assert(1);
-
-    /* if it didn't come from the same host/port, forget it */
-    if (memcmp(&bh->peer.sin_addr, &netfd.peer.sin_addr,
-       sizeof(netfd.peer.sin_addr)) != 0 ||
-       bh->peer.sin_port != netfd.peer.sin_port) {
-       netfd.handle = NULL;
-       return;
-    }
-
-    /*
-     * We need to cancel the recvpkt request before calling the callback
-     * because the callback may reschedule us.
-     */
-    fn = bh->fn;
-    arg = bh->arg;
-    bsd_recvpkt_cancel(bh);
-
-    /*
-     * Check the security of the packet.  If it is bad, then pass NULL
-     * to the packet handling function instead of a packet.
-     */
-    if (recv_security_ok(bh) < 0)
-       (*fn)(arg, NULL, S_ERROR);
-    else
-       (*fn)(arg, &netfd.pkt, S_OK);
-}
-
-/*
- * This is called when a handle times out before receiving a packet.
- */
-static void
-recvpkt_timeout(cookie)
-    void *cookie;
-{
-    struct bsd_handle *bh = cookie;
-    void (*fn) P((void *, pkt_t *, security_status_t));
-    void *arg;
-
-    assert(bh != NULL);
-
-    assert(bh->ev_timeout != NULL);
-    fn = bh->fn;
-    arg = bh->arg;
-    bsd_recvpkt_cancel(bh);
-    (*fn)(arg, NULL, S_TIMEOUT);
-
-}
-
-/*
- * Check the security of a received packet.  Returns negative on security
- * violation, or returns 0 if ok.  Removes the security info from the pkt_t.
- */
-static int
-recv_security_ok(bh)
-    struct bsd_handle *bh;
-{
-    char *tok, *security, *body, *result;
-    pkt_t *pkt = &netfd.pkt;
-
-    /*
-     * Set this preempively before we mangle the body.  
-     */
-    security_seterror(&bh->sech,
-       "bad SECURITY line: '%s'", pkt->body);
-
-    /*
-     * Now, find the SECURITY line in the body, and parse it out
-     * into an argv.
-     */
-    if (strncmp(pkt->body, "SECURITY", sizeof("SECURITY") - 1) == 0) {
-       tok = strtok(pkt->body, " ");
-       assert(strcmp(tok, "SECURITY") == 0);
-       /* security info goes until the newline */
-       security = strtok(NULL, "\n");
-       body = strtok(NULL, "");
-       /*
-        * If the body is f-ked, then try to recover
-        */
-       if (body == NULL) {
-           if (security != NULL)
-               body = security + strlen(security) + 2;
-           else
-               body = pkt->body;
-       }
-    } else {
-       security = NULL;
-       body = pkt->body;
-    }
-
-    /*
-     * We need to do different things depending on which type of packet
-     * this is.
-     */
-    switch (pkt->type) {
-    case P_REQ:
-       /*
-        * Request packets must come from a reserved port
-        */
-       if (ntohs(bh->peer.sin_port) >= IPPORT_RESERVED) {
-           security_seterror(&bh->sech,
-               "host %s: port %d not secure", bh->hostname,
-               ntohs(bh->peer.sin_port));
-           return (-1);
-       }
-
-       /*
-        * Request packets contain a remote username.  We need to check
-        * that we allow it in.
-        *
-        * They will look like:
-        *      SECURITY USER [username]
-        */
-
-       /* there must be some security info */
-       if (security == NULL) {
-           security_seterror(&bh->sech,
-               "no bsd SECURITY for P_REQ");
-           return (-1);
-       }
-
-       /* second word must be USER */
-       if ((tok = strtok(security, " ")) == NULL)
-           return (-1);        /* default errmsg */
-       if (strcmp(tok, "USER") != 0) {
-           security_seterror(&bh->sech,
-               "REQ SECURITY line parse error, expecting USER, got %s", tok);
-           return (-1);
-       }
-
-       /* the third word is the username */
-       if ((tok = strtok(NULL, "")) == NULL)
-           return (-1);        /* default errmsg */
-       if ((result = check_user(bh, tok)) != NULL) {
-           security_seterror(&bh->sech, "%s", result);
-           amfree(result);
-           return (-1);
-       }
-
-       /* we're good to go */
-       break;
-    default:
-       break;
-    }
-
-    /*
-     * If there is security info at the front of the packet, we need to
-     * shift the rest of the data up and nuke it.
-     */
-    if (body != pkt->body)
-       memmove(pkt->body, body, strlen(body) + 1);
-    return (0);
-}
-
-static char *
-check_user(bh, remoteuser)
-    struct bsd_handle *bh;
-    const char *remoteuser;
-{
-    struct passwd *pwd;
-    char *r;
-    char *result = NULL;
-    char *localuser = NULL;
-
-    /* lookup our local user name */
-    if ((pwd = getpwnam(CLIENT_LOGIN)) == NULL) {
-       return vstralloc("getpwnam(", CLIENT_LOGIN, ") fails", NULL);
-    }
-
-    /*
-     * Make a copy of the user name in case getpw* is called by
-     * any of the lower level routines.
-     */
-    localuser = stralloc(pwd->pw_name);
-
-#ifndef USE_AMANDAHOSTS
-    r = check_user_ruserok(bh->hostname, pwd, remoteuser);
-#else
-    r = check_user_amandahosts(bh->hostname, pwd, remoteuser);
-#endif
-    if (r != NULL) {
-       result = vstralloc("access as ", localuser, " not allowed",
-                          " from ", remoteuser, "@", bh->hostname,
-                          ": ", r,
-                          NULL);
-       amfree(r);
-    }
-    amfree(localuser);
-    return result;
-}
-
-/*
- * See if a remote user is allowed in.  This version uses ruserok()
- * and friends.
- *
- * Returns 0 on success, or negative on error.
- */
-char *
-check_user_ruserok(host, pwd, remoteuser)
-    const char *host;
-    struct passwd *pwd;
-    const char *remoteuser;
-{
-    int saved_stderr;
-    int fd[2];
-    FILE *fError;
-    amwait_t exitcode;
-    pid_t ruserok_pid;
-    pid_t pid;
-    char *es;
-    char *result;
-    int ok;
-    char number[NUM_STR_SIZE];
-    uid_t myuid = getuid();
-
-    /*
-     * note that some versions of ruserok (eg SunOS 3.2) look in
-     * "./.rhosts" rather than "~CLIENT_LOGIN/.rhosts", so we have to
-     * chdir ourselves.  Sigh.
-     *
-     * And, believe it or not, some ruserok()'s try an initgroup just
-     * for the hell of it.  Since we probably aren't root at this point
-     * it'll fail, and initgroup "helpfully" will blatt "Setgroups: Not owner"
-     * into our stderr output even though the initgroup failure is not a
-     * problem and is expected.  Thanks a lot.  Not.
-     */
-    if (pipe(fd) != 0) {
-       return stralloc2("pipe() fails: ", strerror(errno));
-    }
-    if ((ruserok_pid = fork()) < 0) {
-       return stralloc2("fork() fails: ", strerror(errno));
-    } else if (ruserok_pid == 0) {
-       int ec;
-
-       close(fd[0]);
-       fError = fdopen(fd[1], "w");
-       /* pamper braindead ruserok's */
-       if (chdir(pwd->pw_dir) != 0) {
-           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);
-
-       bsdprintf(("%s: calling ruserok(%s, %d, %s, %s)\n",
-                  debug_prefix_time(NULL),
-                  host, myuid == 0, remoteuser, pwd->pw_name));
-       if (myuid == 0) {
-           bsdprintf(("%s: because you are running as root, ",
-                      debug_prefix(NULL)));
-           bsdprintf(("/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) {
-            dbprintf(("Could not open /dev/null: %s\n",
-                     strerror(errno)));
-           ec = 1;
-       } else {
-           ok = ruserok(host, myuid == 0, remoteuser, CLIENT_LOGIN);
-           if (ok < 0) {
-               ec = 1;
-           } else {
-               ec = 0;
-           }
-       }
-       (void)dup2(saved_stderr,2);
-       close(saved_stderr);
-       exit(ec);
-    }
-    close(fd[1]);
-    fError = fdopen(fd[0], "r");
-
-    result = NULL;
-    while ((es = agets(fError)) != NULL) {
-       if (result == NULL) {
-           result = stralloc("");
-       } else {
-           strappend(result, ": ");
-       }
-       strappend(result, es);
-    }
-    close(fd[0]);
-
-    while (1) {
-       if ((pid = wait(&exitcode)) == (pid_t) -1) {
-           if (errno == EINTR) {
-               continue;
-           }
-           amfree(result);
-           return stralloc2("ruserok wait failed: %s", strerror(errno));
-       }
-       if (pid == ruserok_pid) {
-           break;
-       }
-    }
-    if (WIFSIGNALED(exitcode)) {
-       amfree(result);
-       snprintf(number, sizeof(number), "%d", WTERMSIG(exitcode));
-       return stralloc2("ruserok child got signal ", number);
-    }
-    if (WEXITSTATUS(exitcode) == 0) {
-       amfree(result);
-    } else if (result == NULL) {
-       result = stralloc("ruserok failed");
-    }
-
-    return result;
-}
-
-/*
- * Check to see if a user is allowed in.  This version uses .amandahosts
- * Returns -1 on failure, or 0 on success.
- */
-char *
-check_user_amandahosts(host, pwd, remoteuser)
-    const char *host;
-    struct passwd *pwd;
-    const char *remoteuser;
-{
-    char *line = NULL;
-    char *filehost;
-    const char *fileuser;
-    char *ptmp = NULL;
-    char *result = NULL;
-    FILE *fp = NULL;
-    int found;
-    struct stat sbuf;
-    char n1[NUM_STR_SIZE];
-    char n2[NUM_STR_SIZE];
-    int hostmatch;
-    int usermatch;
-    uid_t localuid;
-    char *localuser = NULL;
-
-    /*
-     * Save copies of what we need from the passwd structure in case
-     * any other code calls getpw*.
-     */
-    localuid = pwd->pw_uid;
-    localuser = stralloc(pwd->pw_name);
-
-    ptmp = stralloc2(pwd->pw_dir, "/.amandahosts");
-#if defined(SHOW_SECURITY_DETAIL)                              /* { */
-    show_stat_info(ptmp, "");;
-#endif                                                         /* } */
-    if ((fp = fopen(ptmp, "r")) == NULL) {
-       result = vstralloc("cannot open ", ptmp, ": ", strerror(errno), NULL);
-       amfree(ptmp);
-       amfree(localuser);
-       return result;
-    }
-
-    /*
-     * Make sure the file is owned by the Amanda user and does not
-     * have any group/other access allowed.
-     */
-    if (fstat(fileno(fp), &sbuf) != 0) {
-       result = vstralloc("cannot fstat ", ptmp, ": ", strerror(errno), NULL);
-       goto common_exit;
-    }
-    if (sbuf.st_uid != localuid) {
-       snprintf(n1, sizeof(n1), "%ld", (long)sbuf.st_uid);
-       snprintf(n2, sizeof(n2), "%ld", (long)localuid);
-       result = vstralloc(ptmp, ": ",
-                          "owned by id ", n1,
-                          ", should be ", n2,
-                          NULL);
-       goto common_exit;
-    }
-    if ((sbuf.st_mode & 077) != 0) {
-       result = stralloc2(ptmp,
-         ": incorrect permissions; file must be accessible only by its owner");
-       goto common_exit;
-    }
-
-    /*
-     * Now, scan the file for the host/user.
-     */
-    found = 0;
-    while ((line = agets(fp)) != NULL) {
-#if defined(SHOW_SECURITY_DETAIL)                              /* { */
-       bsdprintf(("%s: processing line: <%s>\n", debug_prefix(NULL), line));
-#endif                                                         /* } */
-       /* get the host out of the file */
-       if ((filehost = strtok(line, " \t")) == NULL) {
-           amfree(line);
-           continue;
-       }
-
-       /* get the username.  If no user specified, then use the local user */
-       if ((fileuser = strtok(NULL, " \t")) == NULL) {
-           fileuser = localuser;
-       }
-
-       hostmatch = (strcasecmp(filehost, host) == 0);
-       usermatch = (strcasecmp(fileuser, remoteuser) == 0);
-#if defined(SHOW_SECURITY_DETAIL)                              /* { */
-       bsdprintf(("%s: comparing \"%s\" with\n", debug_prefix(NULL), filehost));
-       bsdprintf(("%s:           \"%s\" (%s)\n", host,
-                 debug_prefix(NULL), hostmatch ? "match" : "no match"));
-       bsdprintf(("%s:       and \"%s\" with\n", fileuser, debug_prefix(NULL)));
-       bsdprintf(("%s:           \"%s\" (%s)\n", remoteuser,
-                 debug_prefix(NULL), usermatch ? "match" : "no match"));
-#endif                                                         /* } */
-       amfree(line);
-       /* compare */
-       if (hostmatch && usermatch) {
-           /* success */
-           found = 1;
-           break;
-       }
-    }
-    if (! found) {
-       result = vstralloc(ptmp, ": ",
-                          "\"", host, " ", remoteuser, "\"",
-                          " entry not found",
-                          NULL);
-    }
-
-common_exit:
-
-    afclose(fp);
-    amfree(ptmp);
-    amfree(line);
-    amfree(localuser);
-
-    return result;
-}
-
-/* return 1 on success, 0 on failure */
-int
-check_security(addr, str, cksum, errstr)
-struct sockaddr_in *addr;
-char *str;
-unsigned long cksum;
-char **errstr;
-{
-    char *remotehost = NULL, *remoteuser = NULL;
-    char *bad_bsd = NULL;
-    struct hostent *hp;
-    struct passwd *pwptr;
-    int myuid, i, j;
-    char *s, *fp;
-    int ch;
-
-    *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",
-                           "]", 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);
-       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), "%d", ntohs(addr->sin_port));
-       *errstr = vstralloc("[",
-                           "host ", remotehost, ": ",
-                           "port ", number, " not secure",
-                           "]", NULL);
-       amfree(remotehost);
-       return 0;
-    }
-
-    /* extract the remote user name from the message */
-
-    s = str;
-    ch = *s++;
-
-    bad_bsd = vstralloc("[",
-                       "host ", remotehost, ": ",
-                       "bad bsd security line",
-                       "]", NULL);
-
-#define sc "USER "
-    if(strncmp(s - 1, sc, sizeof(sc)-1) != 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') {
-       *errstr = bad_bsd;
-       bad_bsd = NULL;
-       amfree(remotehost);
-       return 0;
-    }
-    fp = s - 1;
-    skip_non_whitespace(s, ch);
-    s[-1] = '\0';
-    remoteuser = stralloc(fp);
-    s[-1] = ch;
-    amfree(bad_bsd);
-
-    /* lookup our local user name */
-
-    myuid = getuid();
-    if((pwptr = getpwuid(myuid)) == NULL)
-        error("error [getpwuid(%d) fails]", myuid);
-
-    dbprintf(("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, pwptr, remoteuser);
-#endif
-
-    if (s != NULL) {
-       *errstr = vstralloc("[",
-                           "access as ", pwptr->pw_name, " not allowed",
-                           " from ", remoteuser, "@", remotehost,
-                           ": ", s, "]", NULL);
-    }
-    amfree(s);
-    amfree(remotehost);
-    amfree(remoteuser);
-    return *errstr == NULL;
-}
-
-
 /*
  * Create the server end of a stream.  For bsd, this means setup a tcp
  * socket for receiving a connection.
  */
 static void *
-bsd_stream_server(h)
-    void *h;
+bsd_stream_server(
+    void *     h)
 {
-    struct bsd_stream *bs = NULL;
 #ifndef TEST                                                   /* { */
-    struct bsd_handle *bh = h;
+    struct sec_stream *bs = NULL;
+    struct sec_handle *bh = h;
 
     assert(bh != NULL);
 
-    bs = alloc(sizeof(*bs));
+    bs = alloc(SIZEOF(*bs));
     security_streaminit(&bs->secstr, &bsd_security_driver);
-    bs->socket = stream_server(&bs->port, STREAM_BUFSIZE, STREAM_BUFSIZE);
+    bs->socket = stream_server(&bs->port, (size_t)STREAM_BUFSIZE, 
+                       (size_t)STREAM_BUFSIZE, 0);
     if (bs->socket < 0) {
        security_seterror(&bh->sech,
            "can't create server stream: %s", strerror(errno));
@@ -1396,8 +306,10 @@ bsd_stream_server(h)
     }
     bs->fd = -1;
     bs->ev_read = NULL;
-#endif /* !TEST */                                             /* } */
     return (bs);
+#else
+    return (NULL);
+#endif /* !TEST */                                             /* } */
 }
 
 /*
@@ -1405,17 +317,17 @@ bsd_stream_server(h)
  * block on accept()
  */
 static int
-bsd_stream_accept(s)
-    void *s;
+bsd_stream_accept(
+    void *     s)
 {
 #ifndef TEST                                                   /* { */
-    struct bsd_stream *bs = s;
+    struct sec_stream *bs = s;
 
     assert(bs != NULL);
     assert(bs->socket != -1);
     assert(bs->fd < 0);
 
-    bs->fd = stream_accept(bs->socket, 30, -1, -1);
+    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", strerror(errno));
@@ -1429,32 +341,26 @@ bsd_stream_accept(s)
  * Return a connected stream
  */
 static void *
-bsd_stream_client(h, id)
-    void *h;
-    int id;
+bsd_stream_client(
+    void *     h,
+    int                id)
 {
-    struct bsd_stream *bs = NULL;
+    struct sec_stream *bs = NULL;
 #ifndef TEST                                                   /* { */
-    struct bsd_handle *bh = h;
+    struct sec_handle *bh = h;
 #ifdef DUMPER_SOCKET_BUFFERING
-    int rcvbuf = sizeof(bs->databuf) * 2;
+    size_t rcvbuf = SIZEOF(bs->databuf) * 2;
 #endif
 
     assert(bh != NULL);
 
-    if (id < 0) {
-       security_seterror(&bh->sech,
-           "%d: invalid security stream id", id);
-       return (NULL);
-    }
-
-    bs = alloc(sizeof(*bs));
+    bs = alloc(SIZEOF(*bs));
     security_streaminit(&bs->secstr, &bsd_security_driver);
-    bs->fd = stream_client(bh->hostname, id, STREAM_BUFSIZE, STREAM_BUFSIZE,
-       &bs->port, 0);
+    bs->fd = stream_client(bh->hostname, (in_port_t)id,
+       STREAM_BUFSIZE, STREAM_BUFSIZE, &bs->port, 0);
     if (bs->fd < 0) {
        security_seterror(&bh->sech,
-           "can't connect stream to %s port %d: %s", bh->hostname,
+           "can't connect stream to %s port %hd: %s", bh->hostname,
            id, strerror(errno));
        amfree(bs);
        return (NULL);
@@ -1462,7 +368,7 @@ bsd_stream_client(h, id)
     bs->socket = -1;   /* we're a client */
     bs->ev_read = NULL;
 #ifdef DUMPER_SOCKET_BUFFERING
-    setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbuf, sizeof(rcvbuf));
+    setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbuf, SIZEOF(rcvbuf));
 #endif
 #endif /* !TEST */                                             /* } */
     return (bs);
@@ -1472,10 +378,10 @@ bsd_stream_client(h, id)
  * Close and unallocate resources for a stream
  */
 static void
-bsd_stream_close(s)
-    void *s;
+bsd_stream_close(
+    void *     s)
 {
-    struct bsd_stream *bs = s;
+    struct sec_stream *bs = s;
 
     assert(bs != NULL);
 
@@ -1491,9 +397,10 @@ bsd_stream_close(s)
  * Authenticate a stream.  bsd streams have no authentication
  */
 static int
-bsd_stream_auth(s)
-    void *s;
+bsd_stream_auth(
+    void *     s)
 {
+    (void)s;           /* Quiet unused parameter warning */
 
     return (0);        /* success */
 }
@@ -1502,37 +409,14 @@ bsd_stream_auth(s)
  * Returns the stream id for this stream.  This is just the local port.
  */
 static int
-bsd_stream_id(s)
-    void *s;
+bsd_stream_id(
+    void *     s)
 {
-    struct bsd_stream *bs = s;
+    struct sec_stream *bs = s;
 
     assert(bs != NULL);
 
-    return (bs->port);
-}
-
-/*
- * Write a chunk of data to a stream.  Blocks until completion.
- */
-static int
-bsd_stream_write(s, buf, size)
-    void *s;
-    const void *buf;
-    size_t size;
-{
-#ifndef TEST                                                   /* { */
-    struct bsd_stream *bs = s;
-
-    assert(bs != NULL);
-
-    if (fullwrite(bs->fd, buf, size) < 0) {
-       security_stream_seterror(&bs->secstr,
-           "write error on stream %d: %s", bs->port, strerror(errno));
-       return (-1);
-    }
-#endif /* !TEST */                                             /* } */
-    return (0);
+    return ((int)bs->port);
 }
 
 /*
@@ -1540,11 +424,12 @@ bsd_stream_write(s, buf, size)
  * and arg when completed.
  */
 static void
-bsd_stream_read(s, fn, arg)
-    void *s, *arg;
-    void (*fn) P((void *, void *, ssize_t));
+bsd_stream_read(
+    void *     s,
+    void       (*fn)(void *, void *, ssize_t),
+    void *     arg)
 {
-    struct bsd_stream *bs = s;
+    struct sec_stream *bs = s;
 
     /*
      * Only one read request can be active per stream.
@@ -1552,41 +437,52 @@ bsd_stream_read(s, fn, arg)
     if (bs->ev_read != NULL)
        event_release(bs->ev_read);
 
-    bs->ev_read = event_register(bs->fd, EV_READFD, stream_read_callback, bs);
+    bs->ev_read = event_register((event_id_t)bs->fd, EV_READFD, stream_read_callback, bs);
     bs->fn = fn;
     bs->arg = arg;
 }
 
 /*
- * Cancel a previous stream read request.  It's ok if we didn't
- * have a read scheduled.
+ * Read a chunk of data to a stream.  Blocks until completion.
  */
-static void
-bsd_stream_read_cancel(s)
-    void *s;
+static ssize_t
+bsd_stream_read_sync(
+    void *     s,
+    void **    buf)
 {
-    struct bsd_stream *bs = s;
+    struct sec_stream *bs = s;
 
     assert(bs != NULL);
 
-    if (bs->ev_read != NULL) {
-       event_release(bs->ev_read);
-       bs->ev_read = NULL;
+    /*
+     * Only one read request can be active per stream.
+     */
+    if(bs->ev_read != NULL) {
+        return -1;
     }
+    bs->ev_read = event_register((event_id_t)bs->fd, EV_READFD,
+                       stream_read_sync_callback, bs);
+    event_wait(bs->ev_read);
+    *buf = bs->databuf;
+    return (bs->len);
 }
 
+
 /*
- * Callback for bsd_stream_read
+ * Callback for bsd_stream_read_sync
  */
 static void
-stream_read_callback(arg)
-    void *arg;
+stream_read_sync_callback(
+    void *     s)
 {
-    struct bsd_stream *bs = arg;
+    struct sec_stream *bs = s;
     ssize_t n;
 
     assert(bs != NULL);
 
+    bsdprintf(("%s: bsd: stream_read_callback_sync: fd %d\n",
+                debug_prefix_time(NULL), bs->fd));
+
     /*
      * Remove the event first, in case they reschedule it in the callback.
      */
@@ -1595,101 +491,51 @@ stream_read_callback(arg)
        n = read(bs->fd, bs->databuf, sizeof(bs->databuf));
     } while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
     if (n < 0)
-       security_stream_seterror(&bs->secstr, strerror(errno));
-    (*bs->fn)(bs->arg, bs->databuf, n);
+        security_stream_seterror(&bs->secstr, strerror(errno));
+    bs->len = n;
 }
 
 /*
- * Convert a packet header into a string
+ * Cancel a previous stream read request.  It's ok if we didn't
+ * have a read scheduled.
  */
-static const char *
-pkthdr2str(bh, pkt)
-    const struct bsd_handle *bh;
-    const pkt_t *pkt;
+static void
+bsd_stream_read_cancel(
+    void *     s)
 {
-    static char retbuf[256];
-
-    assert(bh != NULL);
-    assert(pkt != NULL);
+    struct sec_stream *bs = s;
 
-    snprintf(retbuf, sizeof(retbuf), "Amanda %d.%d %s HANDLE %s SEQ %d\n",
-       VERSION_MAJOR, VERSION_MINOR, pkt_type2str(pkt->type),
-       bh->proto_handle, bh->sequence);
-
-    bsdprintf(("%s: pkthdr2str handle '%s'\n",
-              debug_prefix_time(NULL), bh->proto_handle));
-
-    /* check for truncation.  If only we had asprintf()... */
-    assert(retbuf[strlen(retbuf) - 1] == '\n');
-
-    return (retbuf);
+    assert(bs != NULL);
+    if (bs->ev_read != NULL) {
+       event_release(bs->ev_read);
+       bs->ev_read = NULL;
+    }
 }
 
 /*
- * Parses out the header line in 'str' into the pkt and handle
- * Returns negative on parse error.
+ * Callback for bsd_stream_read
  */
-static int
-str2pkthdr()
+static void
+stream_read_callback(
+    void *     arg)
 {
-    char *str;
-    const char *tok;
-    pkt_t *pkt;
-
-    pkt = &netfd.pkt;
-
-    assert(netfd.dgram.cur != NULL);
-    str = stralloc(netfd.dgram.cur);
-
-    /* "Amanda %d.%d <ACK,NAK,...> HANDLE %s SEQ %d\n" */
-
-    /* Read in "Amanda" */
-    if ((tok = strtok(str, " ")) == NULL || strcmp(tok, "Amanda") != 0)
-       goto parse_error;
-
-    /* nothing is done with the major/minor numbers currently */
-    if ((tok = strtok(NULL, " ")) == NULL || strchr(tok, '.') == NULL)
-       goto parse_error;
-
-    /* Read in the packet type */
-    if ((tok = strtok(NULL, " ")) == NULL)
-       goto parse_error;
-    pkt_init(pkt, pkt_str2type(tok), "");
-    if (pkt->type == (pktype_t)-1)    
-       goto parse_error;
-
-    /* Read in "HANDLE" */
-    if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "HANDLE") != 0)
-       goto parse_error;
-
-    /* parse the handle */
-    if ((tok = strtok(NULL, " ")) == NULL)
-       goto parse_error;
-    netfd.handle = stralloc(tok);
-
-    /* Read in "SEQ" */
-    if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "SEQ") != 0)   
-       goto parse_error;
+    struct sec_stream *bs = arg;
+    ssize_t n;
 
-    /* parse the sequence number */   
-    if ((tok = strtok(NULL, "\n")) == NULL)
-       goto parse_error;
-    netfd.sequence = atoi(tok);
+    assert(bs != NULL);
 
-    /* Save the body, if any */       
-    if ((tok = strtok(NULL, "")) != NULL)
-       pkt_cat(pkt, "%s", tok);
+    /*
+     * Remove the event first, in case they reschedule it in the callback.
+     */
+    bsd_stream_read_cancel(bs);
+    do {
+       n = read(bs->fd, bs->databuf, SIZEOF(bs->databuf));
+    } while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
 
-    amfree(str);
-    return (0);
+    if (n < 0)
+       security_stream_seterror(&bs->secstr, strerror(errno));
 
-parse_error:
-#if 0 /* XXX we have no way of passing this back up */
-    security_seterror(&bh->sech,
-       "parse error in packet header : '%s'", origstr);
-#endif
-    amfree(str);
-    return (-1);
+    (*bs->fn)(bs->arg, bs->databuf, n);
 }
 
 #endif /* BSD_SECURITY */                                      /* } */
@@ -1701,12 +547,19 @@ parse_error:
  * drag in util.o just for the test program.
  */
 int
-bind_portrange(s, addrp, first_port, last_port, proto)
-    int s;
-    struct sockaddr_in *addrp;
-    int first_port, last_port;
-    char *proto;
-{
+bind_portrange(
+    int                        s,
+    struct sockaddr_in *addrp,
+    in_port_t          first_port,
+    in_port_t          last_port,
+    char *             proto)
+{
+    (void)s;           /* Quiet unused parameter warning */
+    (void)addrp;       /* Quiet unused parameter warning */
+    (void)first_port;  /* Quiet unused parameter warning */
+    (void)last_port;   /* Quiet unused parameter warning */
+    (void)proto;       /* Quiet unused parameter warning */
+
     return 0;
 }
 
@@ -1714,8 +567,8 @@ bind_portrange(s, addrp, first_port, last_port, proto)
  * Construct a datestamp (YYYYMMDD) from a time_t.
  */
 char *
-construct_datestamp(t)
-    time_t *t;
+construct_datestamp(
+    time_t *   t)
 {
     struct tm *tm;
     char datestamp[3*NUM_STR_SIZE];
@@ -1727,7 +580,7 @@ construct_datestamp(t)
        when = *t;
     }
     tm = localtime(&when);
-    snprintf(datestamp, sizeof(datestamp),
+    snprintf(datestamp, SIZEOF(datestamp),
              "%04d%02d%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
     return stralloc(datestamp);
 }
@@ -1736,8 +589,8 @@ construct_datestamp(t)
  * Construct a timestamp (YYYYMMDDHHMMSS) from a time_t.
  */
 char *
-construct_timestamp(t)
-    time_t *t;
+construct_timestamp(
+    time_t *   t)
 {
     struct tm *tm;
     char timestamp[6*NUM_STR_SIZE];
@@ -1749,7 +602,7 @@ construct_timestamp(t)
        when = *t;
     }
     tm = localtime(&when);
-    snprintf(timestamp, sizeof(timestamp),
+    snprintf(timestamp, SIZEOF(timestamp),
             "%04d%02d%02d%02d%02d%02d",
             tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
             tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -1763,14 +616,17 @@ construct_timestamp(t)
 const security_driver_t krb4_security_driver = {};
 const security_driver_t krb5_security_driver = {};
 const security_driver_t rsh_security_driver = {};
+const security_driver_t ssh_security_driver = {};
+const security_driver_t bsdtcp_security_driver = {};
+const security_driver_t bsdudp_security_driver = {};
 
 /*
  * This function will be called to accept the connection and is used
  * to report success or failure.
  */
-static void fake_accept_function(handle, pkt)
-    security_handle_t *handle;
-    pkt_t *pkt;
+static void fake_accept_function(
+    security_handle_t *        handle,
+    pkt_t *            pkt)
 {
     if (pkt == NULL) {
        fputs(handle->error, stdout);
@@ -1781,12 +637,14 @@ static void fake_accept_function(handle, pkt)
 }
 
 int
-main (argc, argv)
+main (
+    int                argc,
+    char **    argv)
 {
     char *remoteuser;
     char *remotehost;
     struct hostent *hp;
-    struct bsd_handle *bh;
+    struct sec_handle *bh;
     void *save_cur;
     struct passwd *pwent;
 
@@ -1808,6 +666,7 @@ main (argc, argv)
     if (geteuid() == 0) {
        if(client_uid == (uid_t) -1) {
            error("error [cannot find user %s in passwd file]\n", CLIENT_LOGIN);
+           /*NOTREACHED*/
        }
        initgroups(CLIENT_LOGIN, client_gid);
        setgid(client_gid);
@@ -1820,19 +679,28 @@ main (argc, argv)
        fputs("Remote user: ", stdout);
        fflush(stdout);
     }
-    if ((remoteuser = agets(stdin)) == NULL) {
-       return 0;
-    }
+    do {
+       amfree(remoteuser);
+       remoteuser = agets(stdin);
+       if (remoteuser == NULL)
+           return 0;
+    } while (remoteuser[0] == '\0');
 
     if (isatty(0)) {
        fputs("Remote host: ", stdout);
        fflush(stdout);
     }
-    if ((remotehost = agets(stdin)) == NULL) {
-       return 0;
-    }
+
+    do {
+       amfree(remotehost);
+       remotehost = agets(stdin);
+       if (remotehost == NULL)
+           return 0;
+    } while (remotehost[0] == '\0');
 
     set_pname("security");
+    dbopen(NULL);
+
     startclock();
 
     if ((hp = gethostbyname(remotehost)) == NULL) {
@@ -1841,14 +709,15 @@ main (argc, argv)
     }
     memcpy((char *)&netfd.peer.sin_addr,
           (char *)hp->h_addr,
-          sizeof(hp->h_addr));
+          SIZEOF(hp->h_addr));
     /*
      * Fake that it is coming from a reserved port.
      */
     netfd.peer.sin_port = htons(IPPORT_RESERVED - 1);
 
-    bh = alloc(sizeof(*bh));
+    bh = alloc(SIZEOF(*bh));
     bh->proto_handle=NULL;
+    bh->udp = &netfd;
     netfd.pkt.type = P_REQ;
     dgram_zero(&netfd.dgram);
     save_cur = netfd.dgram.cur;                                /* cheating */
@@ -1856,8 +725,10 @@ main (argc, argv)
     dgram_cat(&netfd.dgram, "SECURITY USER %s\n", remoteuser);
     netfd.dgram.cur = save_cur;                                /* cheating */
 
-    accept_fn = fake_accept_function;
-    netfd_read_callback(NULL);
+    netfd.accept_fn = fake_accept_function;
+    netfd.recv_security_ok = &bsd_recv_security_ok;
+    netfd.prefix_packet = &bsd_prefix_packet;
+    udp_netfd_read_callback(&netfd);
 
     return 0;
 }