Imported Upstream version 3.1.0
[debian/amanda] / common-src / krb4-security.c
diff --git a/common-src/krb4-security.c b/common-src/krb4-security.c
deleted file mode 100644 (file)
index 69bf2d3..0000000
+++ /dev/null
@@ -1,1796 +0,0 @@
-/*
- * Amanda, The Advanced Maryland Automatic Network Disk Archiver
- * Copyright (c) 1993,1999 University of Maryland
- * All Rights Reserved.
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of U.M. not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  U.M. makes no representations about the
- * suitability of this software for any purpose.  It is provided "as is"
- * without express or implied warranty.
- *
- * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
- * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Authors: the Amanda Development Team.  Its members are listed in a
- * file named AUTHORS, in the root directory of this distribution.
- */
-
-/*
- * $Id: krb4-security.c,v 1.18 2006/07/13 03:22:20 paddy_s Exp $
- *
- * krb4-security.c - helper functions for kerberos v4 security.
- */
-
-#include "config.h"
-
-#include <des.h>
-#include <krb.h>
-
-#include "amanda.h"
-#include "dgram.h"
-#include "event.h"
-#include "packet.h"
-#include "queue.h"
-#include "security.h"
-#include "security-util.h"
-#include "protocol.h"
-#include "stream.h"
-#include "version.h"
-
-
-/*
- * If you don't have atexit() or on_exit(), you could just consider
- * making atexit() empty and clean up your ticket files some other
- * way
- */
-#ifndef HAVE_ATEXIT
-#ifdef HAVE_ON_EXIT
-#define        atexit(func)    on_exit(func, 0)
-#else
-#define        atexit(func)    (you must to resolve lack of atexit)
-#endif /* HAVE_ON_EXIT */
-#endif /* ! HAVE_ATEXIT */
-
-/*
- * This is the tcp stream buffer size
- */
-#ifndef STREAM_BUFSIZE
-#define        STREAM_BUFSIZE  (32768*2)
-#endif
-
-int krb_set_lifetime(int);
-int kuserok(AUTH_DAT *, char *);
-
-/*
- * This is the private handle data
- */
-struct krb4_handle {
-    security_handle_t sech;    /* MUST be first */
-    struct sockaddr_in6 peer;  /* host on other side */
-    char hostname[MAX_HOSTNAME_LENGTH+1];      /* human form of above */
-    char proto_handle[32];     /* protocol handle for this req */
-    int sequence;              /* last sequence number we received */
-    char inst[INST_SZ];                /* krb4 instance form of above */
-    char realm[REALM_SZ];      /* krb4 realm of this host */
-    unsigned long cksum;       /* cksum of the req packet we sent */
-    des_cblock session_key;    /* session key */
-
-    /*
-     * The rest is used for the async recvpkt/recvpkt_cancel
-     * interface.
-     */
-    void (*fn)(void *, pkt_t *, security_status_t);
-                                       /* func to call when packet recvd */
-    void *arg;                         /* argument to pass function */
-    event_handle_t *ev_timeout;                /* timeout handle for recv */
-    TAILQ_ENTRY(krb4_handle) tq;       /* queue handle */
-};
-
-/*
- * This is the internal security_stream data for krb4.
- */
-struct krb4_stream {
-    security_stream_t secstr;          /* MUST be first */
-    struct krb4_handle *krb4_handle;   /* pointer into above */
-    int fd;                            /* io file descriptor */
-    in_port_t port;                    /* local port this is bound to */
-    int socket;                                /* fd for server-side accepts */
-    event_handle_t *ev_read;           /* read event handle */
-    char databuf[STREAM_BUFSIZE];      /* read buffer */
-    int len;                           /* */
-    void (*fn)(void *, void *, ssize_t);/* read event fn */
-    void *arg;                         /* arg for previous */
-};
-
-/*
- * Interface functions
- */
-static void    krb4_connect(const char *, char *(*)(char *, void *),  
-                       void (*)(void *, security_handle_t *, security_status_t),
-                       void *, void *);
-static void    krb4_accept(const struct security_driver *, int, int, void (*)(security_handle_t *, pkt_t *));
-static void    krb4_close(void *);
-static int     krb4_sendpkt(void *, pkt_t *);
-static void    krb4_recvpkt(void *, void (*)(void *, pkt_t *, security_status_t),
-                       void *, int);
-static void    krb4_recvpkt_cancel(void *);
-static void *  krb4_stream_server(void *);
-static int     krb4_stream_accept(void *);
-static void *  krb4_stream_client(void *, int);
-static void    krb4_stream_close(void *);
-static int     krb4_stream_auth(void *);
-static int     krb4_stream_id(void *);
-static int     krb4_stream_write(void *, const void *, size_t);
-static void    krb4_stream_read(void *, void (*)(void *, void *, int), void *);
-static int     krb4_stream_read_sync(void *, void **);
-static void    krb4_stream_read_cancel(void *);
-
-
-/*
- * This is our interface to the outside world.
- */
-const security_driver_t krb4_security_driver = {
-    "KRB4",
-    krb4_connect,
-    krb4_accept,
-    krb4_close,
-    krb4_sendpkt,
-    krb4_recvpkt,
-    krb4_recvpkt_cancel,
-    krb4_stream_server,
-    krb4_stream_accept,
-    krb4_stream_client,
-    krb4_stream_close,
-    krb4_stream_auth,
-    krb4_stream_id,
-    krb4_stream_write,
-    krb4_stream_read,
-    krb4_stream_read_sync,
-    krb4_stream_read_cancel,
-    sec_close_connection_none,
-    NULL,
-    NULL
-};
-
-/*
- * Cache the local hostname
- */
-static char hostname[MAX_HOSTNAME_LENGTH+1];
-
-/*
- * This is the dgram_t that we use to send and recv protocol packets
- * over the net.  There is only one per process, so it lives globally
- * here.
- */
-static dgram_t netfd;
-
-/*
- * This is a queue of outstanding async requests
- */
-static struct {
-    TAILQ_HEAD(, krb4_handle) tailq;
-    int qlength;
-} handleq = {
-    TAILQ_HEAD_INITIALIZER(handleq.tailq), 0
-};
-
-/*
- * Macros to add or remove krb4_handles from the above queue
- */
-#define        handleq_add(kh) do {                    \
-    assert(handleq.qlength == 0 ? TAILQ_FIRST(&handleq.tailq) == NULL : 1); \
-    TAILQ_INSERT_TAIL(&handleq.tailq, kh, tq); \
-    handleq.qlength++;                         \
-} while (0)
-
-#define        handleq_remove(kh)      do {                    \
-    assert(handleq.qlength > 0);                       \
-    assert(TAILQ_FIRST(&handleq.tailq) != NULL);       \
-    TAILQ_REMOVE(&handleq.tailq, kh, tq);              \
-    handleq.qlength--;                                 \
-    assert((handleq.qlength == 0) ^ (TAILQ_FIRST(&handleq.tailq) != NULL)); \
-} while (0)
-
-#define        handleq_first()         TAILQ_FIRST(&handleq.tailq)
-#define        handleq_next(kh)        TAILQ_NEXT(kh, tq)
-
-
-/*
- * This is the event manager's handle for our netfd
- */
-static event_handle_t *ev_netfd;
-
-/*
- * This is a function that should be called if a new security_handle_t is
- * created.  If NULL, no new handles are created.
- * It is passed the new handle and the received pkt
- */
-static void (*accept_fn)(security_handle_t *, pkt_t *);
-
-
-/*
- * This is a structure used in encoding the cksum in a mutual-auth
- * transaction.  The checksum is placed in here first before encryption
- * because encryption requires at least 8 bytes of data, and an unsigned
- * long on most machines (32 bit ones) is 4 bytes.
- */
-union mutual {
-    char pad[8];
-    unsigned long cksum;
-};
-
-/*
- * Private functions
- */
-static unsigned long krb4_cksum(const char *);
-static void krb4_getinst(const char *, char *, size_t);
-static void host2key(const char *, const char *, des_cblock *);
-static void init(void);
-static void inithandle(struct krb4_handle *, struct hostent *, int,
-    const char *);
-static void get_tgt(void);
-static void killtickets(void);
-static void recvpkt_callback(void *);
-static void recvpkt_timeout(void *);
-static int recv_security_ok(struct krb4_handle *, pkt_t *);
-static void stream_read_callback(void *);
-static void stream_read_sync_callback(void *);
-static int knet_write(int, const void *, size_t);
-static int knet_read(int, void *, size_t, int);
-
-static int add_ticket(struct krb4_handle *, const pkt_t *, dgram_t *);
-static void add_mutual_auth(struct krb4_handle *, dgram_t *);
-static int check_ticket(struct krb4_handle *, const pkt_t *,
-    const char *, unsigned long);
-static int check_mutual_auth(struct krb4_handle *, const char *);
-
-static const char *kpkthdr2str(const struct krb4_handle *, const pkt_t *);
-static int str2kpkthdr(const char *, pkt_t *, char *, size_t, int *);
-
-static const char *bin2astr(const unsigned char *, int);
-static void astr2bin(const unsigned char *, unsigned char *, int *);
-
-static void encrypt_data(void *, size_t, des_cblock *);
-static void decrypt_data(void *, size_t, des_cblock *);
-
-#define HOSTNAME_INSTANCE inst
-
-static char *ticketfilename = NULL;
-
-static void
-killtickets(void)
-{
-    if (ticketfilename != NULL)
-       unlink(ticketfilename);
-    amfree(ticketfilename);
-}
-
-/*
- * Setup some things about krb4.  This should only be called once.
- */
-static void
-init(void)
-{
-    char tktfile[256];
-    in_port_t port;
-    static int beenhere = 0;
-
-    if (beenhere)
-       return;
-    beenhere = 1;
-
-    gethostname(hostname, SIZEOF(hostname) - 1);
-    hostname[SIZEOF(hostname) - 1] = '\0';
-
-    if (atexit(killtickets) < 0)
-       error(_("could not setup krb4 exit handler: %s"), strerror(errno));
-
-    /*
-     * [XXX] It could be argued that if KRBTKFILE is set outside of amanda,
-     * that it's value should be used instead of us setting one up.
-     * This file also needs to be removed so that no extra tickets are
-     * hanging around.
-     */
-    g_snprintf(tktfile, SIZEOF(tktfile), "/tmp/tkt%ld-%ld.amanda",
-       (long)getuid(), (long)getpid());
-    ticketfilename = stralloc(tktfile);
-    unlink(ticketfilename);
-    krb_set_tkt_string(ticketfilename);
-#if defined(HAVE_PUTENV)
-    {
-       char *tkt_env = stralloc2("KRBTKFILE=", ticketfilename);
-       putenv(tkt_env);
-    }
-#else
-    setenv("KRBTKFILE", ticketfile, 1);
-#endif
-
-    dgram_zero(&netfd);
-    dgram_bind(&netfd, &port);
-}
-
-/*
- * Get a ticket granting ticket and stuff it in the cache
- */
-static void
-get_tgt(void)
-{
-    char realm[REALM_SZ];
-    int rc;
-
-    strncpy(realm, krb_realmofhost(hostname), SIZEOF(realm) - 1);
-    realm[SIZEOF(realm) - 1] = '\0';
-
-    rc = krb_get_svc_in_tkt(SERVER_HOST_PRINCIPAL, SERVER_HOST_INSTANCE,
-       realm, "krbtgt", realm, TICKET_LIFETIME, SERVER_HOST_KEY_FILE);
-
-    if (rc != 0) {
-       error(_("could not get krbtgt for %s.%s@%s from %s: %s"),
-           SERVER_HOST_PRINCIPAL, SERVER_HOST_INSTANCE, realm,
-           SERVER_HOST_KEY_FILE, krb_err_txt[rc]);
-    }
-
-    krb_set_lifetime(TICKET_LIFETIME);
-}
-
-
-/*
- * krb4 version of a security handle allocator.  Logically sets
- * up a network "connection".
- */
-static void
-krb4_connect(
-    const char *hostname,
-    char *     (*conf_fn)(char *, void *),
-    void       (*fn)(void *, security_handle_t *, security_status_t),
-    void *     arg,
-    void *     datap)
-{
-    struct krb4_handle *kh;
-    char handle[32];
-    struct servent *se;
-    struct hostent *he;
-    in_port_t port;
-
-    (void)conf_fn;     /* Quiet unused parameter warning */
-    (void)datap;       /* Quiet unused parameter warning */
-
-    assert(hostname != NULL);
-
-    /*
-     * Make sure we're initted
-     */
-    init();
-
-    kh = alloc(SIZEOF(*kh));
-    security_handleinit(&kh->sech, &krb4_security_driver);
-
-    if ((he = gethostbyname(hostname)) == NULL) {
-       security_seterror(&kh->sech,
-           _("%s: could not resolve hostname"), hostname);
-       (*fn)(arg, &kh->sech, S_ERROR);
-       return;
-    }
-    if ((se = getservbyname(KAMANDA_SERVICE_NAME, "udp")) == NULL)
-       port = (int)KAMANDA_SERVICE_DEFAULT;
-    else
-       port = ntohs(se->s_port);
-    g_snprintf(handle, SIZEOF(handle), "%ld", (long)time(NULL));
-    inithandle(kh, he, (int)port, handle);
-    (*fn)(arg, &kh->sech, S_OK);
-}
-
-/*
- * Setup to handle new incoming connections
- */
-static void
-krb4_accept(
-    const struct security_driver *driver,
-    int                in,
-    int                out,
-    void       (*fn)(security_handle_t *, pkt_t *))
-{
-    (void)driver;      /* Quiet unused parameter warning */
-    (void)out;         /* Quiet unused parameter warning */
-
-    /*
-     * Make sure we're initted
-     */
-    init();
-
-    /*
-     * We assume that in and out both point to the same socket
-     */
-    dgram_socket(&netfd, in);
-
-    /*
-     * Assign the function and return.  When they call recvpkt later,
-     * the recvpkt callback will call this function when it discovers
-     * new incoming connections
-     */
-    accept_fn = fn;
-
-    if (ev_netfd == NULL)
-       ev_netfd = event_register((event_id_t)netfd.socket, EV_READFD,
-                           recvpkt_callback, NULL);
-}
-
-/*
- * Given a hostname and a port, setup a krb4_handle
- */
-static void
-inithandle(
-    struct krb4_handle *kh,
-    struct hostent *   he,
-    int                        port,
-    const char *       handle)
-{
-
-    /*
-     * Get the instance and realm for this host
-     * (krb_realmofhost always returns something)
-     */
-    krb4_getinst(he->h_name, kh->inst, SIZEOF(kh->inst));
-    strncpy(kh->realm, krb_realmofhost(he->h_name), SIZEOF(kh->realm) - 1);
-    kh->realm[SIZEOF(kh->realm) - 1] = '\0';
-
-    /*
-     * Save a copy of the hostname
-     */
-    strncpy(kh->hostname, he->h_name, SIZEOF(kh->hostname) - 1);
-    kh->hostname[SIZEOF(kh->hostname) - 1] = '\0';
-
-    /*
-     * We have no checksum or session key at this point
-     */
-    kh->cksum = 0;
-    memset(kh->session_key, 0, SIZEOF(kh->session_key));
-
-    /*
-     * Setup our peer info.  We don't do anything with the sequence yet,
-     * so just leave it at 0.
-     */
-    kh->peer.sin6_family = (sa_family_t)AF_INET6;
-    kh->peer.sin6_port = (in_port_t)port;
-    kh->peer.sin6_addr = *(struct in6_addr *)he->h_addr;
-    strncpy(kh->proto_handle, handle, SIZEOF(kh->proto_handle) - 1);
-    kh->proto_handle[SIZEOF(kh->proto_handle) - 1] = '\0';
-    kh->sequence = 0;
-    kh->fn = NULL;
-    kh->arg = NULL;
-    kh->ev_timeout = NULL;
-}
-
-/*
- * frees a handle allocated by the above
- */
-static void
-krb4_close(
-    void *     inst)
-{
-
-    krb4_recvpkt_cancel(inst);
-    amfree(inst);
-}
-
-/*
- * Transmit a packet.  Add security information first.
- */
-static ssize_t
-krb4_sendpkt(
-    void *     cookie,
-    pkt_t *    pkt)
-{
-    struct krb4_handle *kh = cookie;
-
-    assert(kh != NULL);
-    assert(pkt != NULL);
-
-    /*
-     * Initialize this datagram
-     */
-    dgram_zero(&netfd);
-
-    /*
-     * Add the header to the packet
-     */
-    dgram_cat(&netfd, kpkthdr2str(kh, 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 a ticket embedded in the header.  The
-        * checksum is generated from the contents of the body.
-        */
-       if (add_ticket(kh, pkt, &netfd) < 0)
-           return (-1);
-       break;
-    case P_REP:
-       /*
-        * Replies get sent with a mutual authenticator added.  The
-        * mutual authenticator is the encrypted checksum from the
-        * ticket + 1
-        */
-       add_mutual_auth(kh, &netfd);
-       break;
-    case P_ACK:
-    case P_NAK:
-    default:
-       /*
-        * The other types have no security stuff added for krb4.
-        * Shamefull.
-        */
-       break;
-    }
-
-    /*
-     * Add the body, and send it
-     */
-    dgram_cat(&netfd, pkt->body);
-    if (dgram_send_addr(&kh->peer, &netfd) != 0) {
-       security_seterror(&kh->sech,
-           _("send %s to %s failed: %s"), pkt_type2str(pkt->type),
-           kh->hostname, strerror(errno));
-       return (-1);
-    }
-    return (0);
-}
-
-/*
- * Set up to receive a packet asyncronously, and call back when
- * it has been read.
- */
-static void
-krb4_recvpkt(
-    void *     cookie,
-    void       (*fn)(void *, pkt_t *, security_status_t),
-    void *     arg,
-    int                timeout)
-{
-    struct krb4_handle *kh = cookie;
-
-    assert(netfd.socket >= 0);
-    assert(kh != NULL);
-
-    /*
-     * 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.
-     */
-    if (ev_netfd == NULL) {
-       assert(handleq.qlength == 0);
-       ev_netfd = event_register((event_id_t)netfd.socket, EV_READFD,
-                           recvpkt_callback, NULL);
-    }
-
-    /*
-     * Multiple recvpkt calls override previous ones
-     * If kh->fn is NULL then it is not in the queue.
-     */
-    if (kh->fn == NULL)
-       handleq_add(kh);
-    if (kh->ev_timeout != NULL)
-       event_release(kh->ev_timeout);
-    if (timeout < 0)
-       kh->ev_timeout = NULL;
-    else
-       kh->ev_timeout = event_register((event_id_t)timeout, EV_TIME,
-                               recvpkt_timeout, kh);
-    kh->fn = fn;
-    kh->arg = arg;
-}
-
-/*
- * Remove a async receive request from the queue
- * If it is the last one to be removed, then remove the event handler
- * for our network fd.
- */
-static void
-krb4_recvpkt_cancel(
-    void *     cookie)
-{
-    struct krb4_handle *kh = cookie;
-
-    assert(kh != NULL);
-
-    if (kh->fn != NULL) {
-       handleq_remove(kh);
-       kh->fn = NULL;
-       kh->arg = NULL;
-    }
-    if (kh->ev_timeout != NULL)
-       event_release(kh->ev_timeout);
-    kh->ev_timeout = NULL;
-
-    if (handleq.qlength == 0 && accept_fn == NULL &&
-       ev_netfd != NULL) {
-       event_release(ev_netfd);
-       ev_netfd = NULL;
-    }
-}
-
-/*
- * Create the server end of a stream.  For krb4, this means setup a tcp
- * socket for receiving a connection.
- */
-static void *
-krb4_stream_server(
-    void *     h)
-{
-    struct krb4_handle *kh = h;
-    struct krb4_stream *ks;
-
-    assert(kh != NULL);
-
-    ks = alloc(SIZEOF(*ks));
-    security_streaminit(&ks->secstr, &krb4_security_driver);
-    ks->socket = stream_server(&ks->port, STREAM_BUFSIZE, STREAM_BUFSIZE, 1);
-    if (ks->socket < 0) {
-       security_seterror(&kh->sech,
-           _("can't create server stream: %s"), strerror(errno));
-       amfree(ks);
-       return (NULL);
-    }
-    ks->fd = -1;
-    ks->krb4_handle = kh;
-    ks->ev_read = NULL;
-    return (ks);
-}
-
-/*
- * Accept an incoming connection on a stream_server socket
- */
-static int
-krb4_stream_accept(
-    void *     s)
-{
-    struct krb4_stream *ks = s;
-    struct krb4_handle *kh;
-
-    assert(ks != NULL);
-    kh = ks->krb4_handle;
-    assert(kh != NULL);
-    assert(ks->socket >= 0);
-    assert(ks->fd == -1);
-
-    ks->fd = stream_accept(ks->socket, 30, STREAM_BUFSIZE, STREAM_BUFSIZE);
-    if (ks->fd < 0) {
-       security_stream_seterror(&ks->secstr,
-           _("can't accept new stream connection: %s"), strerror(errno));
-       return (-1);
-    }
-    return (0);
-}
-
-/*
- * Return a connected stream.
- */
-static void *
-krb4_stream_client(
-    void *     h,
-    int                id)
-{
-    struct krb4_handle *kh = h;
-    struct krb4_stream *ks;
-
-    assert(kh != NULL);
-
-    ks = alloc(SIZEOF(*ks));
-    security_streaminit(&ks->secstr, &krb4_security_driver);
-    ks->fd = stream_client(kh->hostname, id, STREAM_BUFSIZE, STREAM_BUFSIZE,
-       &ks->port, 0);
-    if (ks->fd < 0) {
-       security_seterror(&kh->sech,
-           _("can't connect stream to %s port %d: %s"), kh->hostname, id,
-           strerror(errno));
-       amfree(ks);
-       return (NULL);
-    }
-
-    ks->socket = -1;   /* we're a client */
-    ks->krb4_handle = kh;
-    ks->ev_read = NULL;
-    return (ks);
-}
-
-/*
- * Close and unallocate resources for a stream.
- */
-static void
-krb4_stream_close(
-    void *     s)
-{
-    struct krb4_stream *ks = s;
-
-    assert(ks != NULL);
-
-    if (ks->fd != -1)
-       aclose(ks->fd);
-    if (ks->socket != -1)
-       aclose(ks->socket);
-    krb4_stream_read_cancel(ks);
-    amfree(ks);
-}
-
-/*
- * Authenticate a stream
- *
- * XXX this whole thing assumes the size of struct timeval is consistent,
- * which is may not be!  We need to extract the network byte order data
- * into byte arrays and send those.
- */
-static int
-krb4_stream_auth(
-    void *     s)
-{
-    struct krb4_stream *ks = s;
-    struct krb4_handle *kh;
-    int fd;
-    struct timeval local, enc;
-    struct timezone tz;
-
-    assert(ks != NULL);
-    assert(ks->fd >= 0);
-
-    fd = ks->fd;
-    kh = ks->krb4_handle;
-
-    /* make sure we're open */
-    assert(fd >= 0);
-
-    /* make sure our timeval is what we're expecting, see above */
-    assert(SIZEOF(struct timeval) == 8);
-
-    /*
-     * Get the current time, put it in network byte order, encrypt it
-     * and present it to the other side.
-     */
-    gettimeofday(&local, &tz);
-    enc.tv_sec = (long)htonl((guint32)local.tv_sec);
-    enc.tv_usec = (long)htonl((guint32)local.tv_usec);
-    encrypt_data(&enc, SIZEOF(enc), &kh->session_key);
-    if (knet_write(fd, &enc, SIZEOF(enc)) < 0) {
-       security_stream_seterror(&ks->secstr,
-           _("krb4 stream handshake write error: %s"), strerror(errno));
-       return (-1);
-    }
-
-    /*
-     * Read back the other side's presentation.  Increment the seconds
-     * and useconds by one.  Reencrypt, and present to the other side.
-     * Timeout in 10 seconds.
-     */
-    if (knet_read(fd, &enc, SIZEOF(enc), 60) < 0) {
-       security_stream_seterror(&ks->secstr,
-           _("krb4 stream handshake read error: %s"), strerror(errno));
-       return (-1);
-    }
-    decrypt_data(&enc, SIZEOF(enc), &kh->session_key);
-    /* XXX do timestamp checking here */
-    enc.tv_sec = (long)htonl(ntohl((guint32)enc.tv_sec) + 1);
-    enc.tv_usec =(long)htonl(ntohl((guint32)enc.tv_usec) + 1);
-    encrypt_data(&enc, SIZEOF(enc), &kh->session_key);
-
-    if (knet_write(fd, &enc, SIZEOF(enc)) < 0) {
-       security_stream_seterror(&ks->secstr,
-           _("krb4 stream handshake write error: %s"), strerror(errno));
-       return (-1);
-    }
-
-    /*
-     * Read back the other side's processing of our data.
-     * If they incremented it properly, then succeed.
-     * Timeout in 10 seconds.
-     */
-    if (knet_read(fd, &enc, SIZEOF(enc), 60) < 0) {
-       security_stream_seterror(&ks->secstr,
-           _("krb4 stream handshake read error: %s"), strerror(errno));
-       return (-1);
-    }
-    decrypt_data(&enc, SIZEOF(enc), &kh->session_key);
-    if ((ntohl((guint32)enc.tv_sec)  == (uint32_t)(local.tv_sec + 1)) &&
-       (ntohl((guint32)enc.tv_usec) == (uint32_t)(local.tv_usec + 1)))
-           return (0);
-
-    security_stream_seterror(&ks->secstr,
-       _("krb4 handshake failed: sent %ld,%ld - recv %ld,%ld"),
-           (long)(local.tv_sec + 1), (long)(local.tv_usec + 1),
-           (long)ntohl((guint32)enc.tv_sec),
-           (long)ntohl((guint32)enc.tv_usec));
-    return (-1);
-}
-
-/*
- * Returns the stream id for this stream.  This is just the local
- * port.
- */
-static int
-krb4_stream_id(
-    void *     s)
-{
-    struct krb4_stream *ks = s;
-
-    assert(ks != NULL);
-
-    return (ks->port);
-}
-
-/*
- * Write a chunk of data to a stream.  Blocks until completion.
- */
-static int
-krb4_stream_write(
-    void *     s,
-    const void *buf,
-    size_t     size)
-{
-    struct krb4_stream *ks = s;
-
-    assert(ks != NULL);
-
-    if (knet_write(ks->fd, buf, size) < 0) {
-       security_stream_seterror(&ks->secstr,
-           _("write error on stream %d: %s"), ks->fd, strerror(errno));
-       return (-1);
-    }
-    return (0);
-}
-
-/*
- * Submit a request to read some data.  Calls back with the given
- * function and arg when completed.
- */
-static void
-krb4_stream_read(
-    void *     s,
-    void       (*fn)(void *, void *, ssize_t),
-    void *     arg)
-{
-    struct krb4_stream *ks = s;
-
-    assert(ks != NULL);
-
-    /*
-     * Only one read request can be active per stream.
-     */
-    if (ks->ev_read != NULL)
-       event_release(ks->ev_read);
-
-    ks->ev_read = event_register((event_id_t)ks->fd, EV_READFD,
-                       stream_read_callback, ks);
-    ks->fn = fn;
-    ks->arg = arg;
-}
-
-/*
- * Write a chunk of data to a stream.  Blocks until completion.
- */
-static ssize_t
-krb4_stream_read_sync(
-    void *     s,
-    void **    buf)
-{
-    struct krb4_stream *ks = s;
-
-    (void)buf; /* Quiet unused variable warning */
-    assert(ks != NULL);
-
-    if (ks->ev_read != NULL)
-       event_release(ks->ev_read);
-
-    ks->ev_read = event_register((event_id_t)ks->fd, EV_READFD,
-                       stream_read_sync_callback, ks);
-    event_wait(ks->ev_read);
-    return((ssize_t)ks->len);
-}
-
-/*
- * Callback for krb4_stream_read_sync
- */
-static void
-stream_read_sync_callback(
-    void *     arg)
-{
-    struct krb4_stream *ks = arg;
-    ssize_t n;
-
-    assert(ks != NULL);
-    assert(ks->fd != -1);
-
-    /*
-     * Remove the event first, and then call the callback.
-     * We remove it first because we don't want to get in their
-     * way if they reschedule it.
-     */
-    krb4_stream_read_cancel(ks);
-    n = read(ks->fd, ks->databuf, sizeof(ks->databuf));
-    if (n < 0)
-       security_stream_seterror(&ks->secstr,
-           strerror(errno));
-    ks->len = (int)n;
-}
-
-/*
- * Cancel a previous stream read request.  It's ok if we didn't have a read
- * scheduled.
- */
-static void
-krb4_stream_read_cancel(
-    void *     s)
-{
-    struct krb4_stream *ks = s;
-
-    assert(ks != NULL);
-
-    if (ks->ev_read != NULL) {
-       event_release(ks->ev_read);
-       ks->ev_read = NULL;
-    }
-}
-
-/*
- * Callback for krb4_stream_read
- */
-static void
-stream_read_callback(
-    void *     arg)
-{
-    struct krb4_stream *ks = arg;
-    ssize_t n;
-
-    assert(ks != NULL);
-    assert(ks->fd != -1);
-
-    /*
-     * Remove the event first, and then call the callback.
-     * We remove it first because we don't want to get in their
-     * way if they reschedule it.
-     */
-    krb4_stream_read_cancel(ks);
-    n = read(ks->fd, ks->databuf, SIZEOF(ks->databuf));
-    if (n < 0)
-       security_stream_seterror(&ks->secstr,
-           strerror(errno));
-    (*ks->fn)(ks->arg, ks->databuf, n);
-}
-
-/*
- * The callback for recvpkt() for the event handler
- * Determines if this packet is for this security handle,
- * and does the real callback if so.
- */
-static void
-recvpkt_callback(
-    void *     cookie)
-{
-    char handle[32];
-    struct sockaddr_in6 peer;
-    pkt_t pkt;
-    int sequence;
-    struct krb4_handle *kh;
-    struct hostent *he;
-    void (*fn)(void *, pkt_t *, security_status_t);
-    void *arg;
-
-    (void)cookie;              /* Quiet unused parameter warning */
-    assert(cookie == NULL);
-
-    /*
-     * Find the handle that this packet is associated with.  We
-     * need to peek at the packet to see what is in it, but we
-     * want to save the actual reading for later.
-     */
-    dgram_zero(&netfd);
-    if (dgram_recv(&netfd, 0, &peer) < 0)
-       return;
-    if (str2kpkthdr(netfd.cur, &pkt, handle, SIZEOF(handle), &sequence) < 0)
-       return;
-
-    for (kh = handleq_first(); kh != NULL; kh = handleq_next(kh)) {
-       if (strcmp(kh->proto_handle, handle) == 0 &&
-           cmp_sockaddr(&kh->peer, &peer, 0) == 0) {
-           kh->sequence = sequence;
-
-           /*
-            * We need to cancel the recvpkt request before calling
-            * the callback because the callback may reschedule us.
-            */
-           fn = kh->fn;
-           arg = kh->arg;
-           krb4_recvpkt_cancel(kh);
-           if (recv_security_ok(kh, &pkt) < 0)
-               (*fn)(arg, NULL, S_ERROR);
-           else
-               (*fn)(arg, &pkt, S_OK);
-           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 *)&peer.sin6_addr, SIZEOF(peer.sin6_addr), AF_INET6);
-    if (he == NULL)
-       return;
-    kh = alloc(SIZEOF(*kh));
-    security_handleinit(&kh->sech, &krb4_security_driver);
-    inithandle(kh, he, (int)peer.sin6_port, handle);
-
-    /*
-     * 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(kh, &pkt) < 0)
-       (*accept_fn)(&kh->sech, NULL);
-    else
-       (*accept_fn)(&kh->sech, &pkt);
-}
-
-/*
- * This is called when a handle times out before receiving a packet.
- */
-static void
-recvpkt_timeout(
-    void *     cookie)
-{
-    struct krb4_handle *kh = cookie;
-    void (*fn)(void *, pkt_t *, security_status_t);
-    void *arg;
-
-    assert(kh != NULL);
-
-    assert(kh->ev_timeout != NULL);
-    fn = kh->fn;
-    arg = kh->arg;
-    krb4_recvpkt_cancel(kh);
-    (*fn)(arg, NULL, S_TIMEOUT);
-}
-
-/*
- * Add a ticket to the message
- */
-static int
-add_ticket(
-    struct krb4_handle *kh,
-    const pkt_t *      pkt,
-    dgram_t *          msg)
-{
-    char inst[INST_SZ];
-    KTEXT_ST ticket;
-    char *security;
-    int rc;
-
-    kh->cksum = (long)krb4_cksum(pkt->body);
-#if CLIENT_HOST_INSTANCE == HOSTNAME_INSTANCE
-    /*
-     * User requested that all instances be based on the target
-     * hostname.
-     */
-    strncpy(inst, kh->inst, SIZEOF(inst) - 1);
-#else
-    /*
-     * User requested a fixed instance.
-     */
-    strncpy(inst, CLIENT_HOST_INSTANCE, SIZEOF(inst) - 1);
-#endif
-    inst[SIZEOF(inst) - 1] = '\0';
-
-    /*
-     * Get a ticket with the user-defined service and instance,
-     * and using the checksum of the body of the request packet.
-     */
-    rc = krb_mk_req(&ticket, CLIENT_HOST_PRINCIPAL, inst, kh->realm,
-       kh->cksum);
-    if (rc == NO_TKT_FIL) {
-       /* It's been kdestroyed.  Get a new one and try again */
-       get_tgt();
-       rc = krb_mk_req(&ticket, CLIENT_HOST_PRINCIPAL, inst, kh->realm,
-           kh->cksum);
-    }
-    if (rc != 0) {
-       security_seterror(&kh->sech,
-           _("krb_mk_req failed: %s (%d)"), error_message(rc), rc);
-       return (-1);
-    }
-    /*
-     * We now have the ticket.  Put it into the packet, and send
-     * it.
-     */
-    security = vstralloc("SECURITY TICKET ",
-       bin2astr(ticket.dat, ticket.length), "\n", NULL);
-    dgram_cat(msg, security);
-    amfree(security);
-
-    return (0);
-}
-
-/*
- * Add the mutual authenticator.  This is the checksum from
- * the req, + 1
- */
-static void
-add_mutual_auth(
-    struct krb4_handle *kh,
-    dgram_t *          msg)
-{
-    union mutual mutual;
-    char *security;
-
-    assert(kh != NULL);
-    assert(msg != NULL);
-    assert(kh->cksum != 0);
-    assert(kh->session_key[0] != '\0');
-
-    memset(&mutual, 0, SIZEOF(mutual));
-    mutual.cksum = (unsigned long)htonl((guint32)kh->cksum + 1);
-    encrypt_data(&mutual, SIZEOF(mutual), &kh->session_key);
-
-    security = vstralloc("SECURITY MUTUAL-AUTH ",
-       bin2astr((unsigned char *)mutual.pad,
-                       (int)sizeof(mutual.pad)), "\n", NULL);
-    dgram_cat(msg, security);
-    amfree(security);
-}
-
-/*
- * Check the security of a received packet.  Returns negative on error
- * or security violation and otherwise returns 0 and fills in the
- * passed packet.
- */
-static int
-recv_security_ok(
-    struct krb4_handle *kh,
-    pkt_t *            pkt)
-{
-    char *tok, *security, *body;
-    unsigned long cksum;
-
-    assert(kh != NULL);
-    assert(pkt != NULL);
-
-    /*
-     * Set this preemptively before we mangle the body.
-     */
-    security_seterror(&kh->sech,
-       _("bad %s SECURITY line from %s: '%s'"), pkt_type2str(pkt->type),
-       kh->hostname, pkt->body);
-
-
-    /*
-     * The first part of the body should be the security info.  Deal with it.
-     * We only need to do this on a few packet types.
-     *
-     * First, parse the SECURITY line in the packet, if it exists.
-     * Increment the cur pointer past it to the data section after
-     * parsing is finished.
-     */
-    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;
-    }
-
-    /*
-     * Get a checksum of the non-security parts of the body
-     */
-    cksum = krb4_cksum(body);
-
-    /*
-     * Now deal with the data we did (or didn't) parse above
-     */
-    switch (pkt->type) {
-    case P_REQ:
-       /*
-        * Request packets have a ticket after the security tag
-        * Get the ticket, make sure the checksum agrees with the
-        * checksum of the request we sent.
-        *
-        * Must look like: SECURITY TICKET [ticket str]
-        */
-
-       /* there must be some security info */
-       if (security == NULL)
-           return (-1);
-
-       /* second word must be TICKET */
-       if ((tok = strtok(security, " ")) == NULL)
-           return (-1);
-       if (strcmp(tok, "TICKET") != 0) {
-           security_seterror(&kh->sech,
-               _("REQ SECURITY line parse error, expecting TICKET, got %s"), tok);
-           return (-1);
-       }
-
-       /* the third word is the encoded ticket */
-       if ((tok = strtok(NULL, "")) == NULL)
-           return (-1);
-       if (check_ticket(kh, pkt, tok, cksum) < 0)
-           return (-1);
-
-       /* we're good to go */
-       break;
-
-    case P_REP:
-       /*
-        * Reply packets check the mutual authenticator for this host.
-        *
-        * Must look like: SECURITY MUTUAL-AUTH [mutual auth str]
-        */
-       if (security == NULL)
-           return (-1);
-       if ((tok = strtok(security, " ")) == NULL)
-           return (-1);
-       if (strcmp(tok, "MUTUAL-AUTH") != 0)  {
-           security_seterror(&kh->sech,
-               "REP SECURITY line parse error, expecting MUTUAL-AUTH, got %s",
-               tok);
-           return (-1);
-       }
-       if ((tok = strtok(NULL, "")) == NULL)
-           return (-1);
-       if (check_mutual_auth(kh, tok) < 0)
-           return (-1);
-
-    case P_ACK:
-    case P_NAK:
-    default:
-       /*
-        * These packets have no security.  They should, but such
-        * is life.  We can't change it without breaking compatibility.
-        *
-        * XXX Should we complain if argc > 0? (ie, some security info was
-        * sent?)
-        */
-       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);
-}
-
-/*
- * Check the ticket in a REQ packet for authenticity
- */
-static int
-check_ticket(
-    struct krb4_handle *kh,
-    const pkt_t *      pkt,
-    const char *       ticket_str,
-    unsigned long      cksum)
-{
-    char inst[INST_SZ];
-    KTEXT_ST ticket;
-    AUTH_DAT auth;
-    struct passwd *pwd;
-    char *user;
-    int rc;
-
-    (void)pkt;         /* Quiet unused parameter warning */
-
-    assert(kh != NULL);
-    assert(pkt != NULL);
-    assert(ticket_str != NULL);
-
-    ticket.length = (int)sizeof(ticket.dat);
-    astr2bin((unsigned char *)ticket_str, ticket.dat, &ticket.length);
-    assert(ticket.length > 0);
-
-    /* get a copy of the instance into writable memory */
-#if CLIENT_HOST_INSTANCE == HOSTNAME_INSTANCE
-    strncpy(inst, krb_get_phost(hostname), SIZEOF(inst) - 1);
-#else
-    strncpy(inst, CLIENT_HOST_INSTANCE, SIZEOF(inst) - 1);
-#endif
-    inst[SIZEOF(inst) - 1] = '\0';
-
-    /* get the checksum out of the ticket */
-    rc = krb_rd_req(&ticket, CLIENT_HOST_PRINCIPAL, inst,
-       kh->peer.sin6_addr.s_addr, &auth, CLIENT_HOST_KEY_FILE);
-    if (rc != 0) {
-       security_seterror(&kh->sech,
-           _("krb_rd_req failed for %s: %s (%d)"), kh->hostname,
-           error_message(rc), rc);
-       return (-1);
-    }
-
-    /* verify and save the checksum and session key */
-    if (auth.checksum != cksum) {
-       security_seterror(&kh->sech,
-           _("krb4 checksum mismatch for %s (remote=%lu, local=%lu)"),
-           kh->hostname, (long)auth.checksum, cksum);
-       return (-1);
-    }
-    kh->cksum = (unsigned long)cksum;
-    memcpy(kh->session_key, auth.session, SIZEOF(kh->session_key));
-
-    /*
-     * If CHECK_USERID is set, then we need to specifically
-     * check the userid we're forcing ourself to.  Otherwise,
-     * just check the login we're currently setuid to.
-     */
-#ifdef CHECK_USERID
-    if ((pwd = getpwnam(CLIENT_LOGIN)) == NULL)
-       error(_("error [getpwnam(%s) fails]"), CLIENT_LOGIN);
-#else
-    if ((pwd = getpwuid(getuid())) == NULL)
-       error(_("error  [getpwuid(%d) fails]"), getuid());
-#endif
-
-    /* save the username in case it's overwritten */
-    user = stralloc(pwd->pw_name);
-
-    /* check the klogin file */
-    if (kuserok(&auth, user)) {
-       security_seterror(&kh->sech,
-           _("access as %s not allowed from %s.%s@%s"), user, auth.pname,
-           auth.pinst, auth.prealm);
-       amfree(user);
-       return (-1);
-    }
-    amfree(user);
-
-    /* it's good */
-    return (0);
-}
-
-/*
- * Verify that the packet received is secure by verifying that it has
- * the same checksum as our request + 1.
- */
-static int
-check_mutual_auth(
-    struct krb4_handle *kh,
-    const char *       mutual_auth_str)
-{
-    union mutual mutual;
-    int len;
-
-    assert(kh != NULL);
-    assert(mutual_auth_str != NULL);
-    assert(kh->inst[0] != '\0');
-    /* we had better have a checksum from a request we sent */
-    assert(kh->cksum != 0);
-
-    /* convert the encoded string into binary data */
-    len = (int)sizeof(mutual);
-    astr2bin((unsigned char *)mutual_auth_str, (unsigned char *)&mutual, &len);
-
-    /* unencrypt the string using the key in the ticket file */
-    host2key(kh->hostname, kh->inst, &kh->session_key);
-    decrypt_data(&mutual, (size_t)len, &kh->session_key);
-    mutual.cksum = (unsigned long)ntohl((guint32)mutual.cksum);
-
-    /* the data must be the same as our request cksum + 1 */
-    if (mutual.cksum != (kh->cksum + 1)) {
-       security_seterror(&kh->sech,
-           _("krb4 checksum mismatch from %s (remote=%lu, local=%lu)"),
-           kh->hostname, mutual.cksum, kh->cksum + 1);
-       return (-1);
-    }
-
-    return (0);
-}
-
-/*
- * Convert a pkt_t into a header string for our packet
- */
-static const char *
-kpkthdr2str(
-    const struct krb4_handle * kh,
-    const pkt_t *              pkt)
-{
-    static char retbuf[256];
-
-    assert(kh != NULL);
-    assert(pkt != NULL);
-
-    g_snprintf(retbuf, SIZEOF(retbuf), "Amanda %d.%d %s HANDLE %s SEQ %d\n",
-       VERSION_MAJOR, VERSION_MINOR, pkt_type2str(pkt->type),
-       kh->proto_handle, kh->sequence);
-
-    /* check for truncation.  If only we had asprintf()... */
-    assert(retbuf[strlen(retbuf) - 1] == '\n');
-
-    return (retbuf);
-}
-
-/*
- * Parses out the header line in 'str' into the pkt and handle
- * Returns negative on parse error.
- */
-static int
-str2kpkthdr(
-    const char *origstr,
-    pkt_t *    pkt,
-    char *     handle,
-    size_t     handlesize,
-    int *      sequence)
-{
-    char *str;
-    const char *tok;
-
-    assert(origstr != NULL);
-    assert(pkt != NULL);
-
-    str = stralloc(origstr);
-
-    /* "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;
-    strncpy(handle, tok, handlesize - 1);
-    handle[handlesize - 1] = '\0';
-
-    /* Read in "SEQ" */
-    if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "SEQ") != 0)
-       goto parse_error;
-
-    /* parse the sequence number */
-    if ((tok = strtok(NULL, "\n")) == NULL)
-       goto parse_error;
-    *sequence = atoi(tok);
-
-    /* Save the body, if any */
-    if ((tok = strtok(NULL, "")) != NULL)
-       pkt_cat(pkt, tok);
-
-    amfree(str);
-    return (0);
-
-parse_error:
-#if 0 /* XXX we have no way of passing this back up */
-    security_seterror(&kh->sech,
-       _("parse error in packet header : '%s'"), origstr);
-#endif
-    amfree(str);
-    return (-1);
-}
-
-static void
-host2key(
-    const char *hostname,
-    const char *inst,
-    des_cblock *key)
-{
-    char realm[256];
-    CREDENTIALS cred;
-
-    strncpy(realm, krb_realmofhost((char *)hostname), SIZEOF(realm) - 1);
-    realm[SIZEOF(realm) - 1] = '\0';
-#if CLIENT_HOST_INSTANCE != HOSTNAME_INSTANCE
-    inst = CLIENT_HOST_INSTANCE
-#endif
-    krb_get_cred(CLIENT_HOST_PRINCIPAL, (char *)inst, realm, &cred);
-    memcpy(key, cred.session, SIZEOF(des_cblock));
-}
-
-
-/*
- * Convert a chunk of data into a string.
- */
-static const char *
-bin2astr(
-    const unsigned char *buf,
-    int                        len)
-{
-    static const char tohex[] = "0123456789ABCDEF";
-    static char *str = NULL;
-    char *q;
-    const unsigned char *p;
-    size_t slen;
-    int        i;
-
-    /*
-     * calculate output string len
-     * We quote everything, so each input byte == 3 output chars, plus
-     * two more for quotes
-     */
-    slen = ((size_t)len * 3) + 2;
-
-    /* allocate string and fill it in */
-    if (str != NULL)
-       amfree(str);
-    str = alloc(slen + 1);
-    p = buf;
-    q = str;
-    *q++ = '"';
-    for (i = 0; i < len; i++) {
-       *q++ = '$';
-       *q++ = tohex[(*p >> 4) & 0xF];
-       *q++ = tohex[*p & 0xF];
-       p++;
-    }
-    *q++ = '"';
-    *q = '\0';
-
-    /* make sure we didn't overrun our allocated buffer */
-    assert((size_t)(q - str) == slen);
-
-    return (str);
-}
-
-/*
- * Convert an encoded string into a block of data bytes
- */
-static void
-astr2bin(
-    const unsigned char *astr,
-    unsigned char *    buf,
-    int *              lenp)
-{
-    const unsigned char *p;
-    unsigned char *q;
-#define fromhex(h)     (isdigit((int)h) ? (h) - '0' : (h) - 'A' + 10)
-
-    /*
-     * Skip leading quote, if any
-     */
-    if (*astr == '"')
-       astr++;
-
-    /*
-     * Run through the string.  Anything starting with a $ is a three
-     * char representation of this byte.  Everything else is literal.
-     */
-    for (p = astr, q = buf; *p != '"' && *p != '\0'; ) {
-       if (*p != '$') {
-           *q++ = *p++;
-       } else {
-           *q++ = (fromhex(p[1]) << 4) + fromhex(p[2]);
-            p += 3;
-       }
-       if ((int)(q - buf) >= *lenp)
-           break;
-    }
-    *lenp = q - buf;
-}
-
-static unsigned long
-krb4_cksum(
-    const char *str)
-{
-    des_cblock seed;
-
-    memset(seed, 0, SIZEOF(seed));
-    /*
-     * The first arg is an unsigned char * in some krb4 implementations,
-     * and in others, it's a des_cblock *.  Just make it void here
-     * to shut them all up.
-     */
-    return (quad_cksum((void *)str, NULL, (long)strlen(str), 1, &seed));
-}
-
-static void
-krb4_getinst(
-    const char *hname,
-    char *     inst,
-    size_t     size)
-{
-
-    /*
-     * Copy the first part of the hostname up to the first '.' into
-     * the buffer provided.  Leave room for a NULL.
-     */
-    while (size > 1 && *hname != '\0' && *hname != '.') {
-       *inst++ = isupper((int)*hname) ? tolower((int)*hname) : *hname;
-       hname++;
-       size--;
-    }
-    *inst = '\0';
-}
-
-static void
-encrypt_data(
-    void *     data,
-    size_t     length,
-    des_cblock *key)
-{
-    des_key_schedule sched;
-
-    /*
-     * First arg is des_cblock * in some places, and just des_cblock in
-     * others.  Since des_cblock is a char array, they are equivalent.
-     * Just cast it to void * to keep both compilers quiet.  typedefing
-     * arrays should be outlawed.
-     */
-    des_key_sched((void *)key, sched);
-    des_pcbc_encrypt(data, data, (long)length, sched, key, DES_ENCRYPT);
-}
-
-
-static void
-decrypt_data(
-    void *     data,
-    size_t     length,
-    des_cblock *key)
-{
-    des_key_schedule sched;
-
-    des_key_sched((void *)key, sched);
-    des_pcbc_encrypt(data, data, (long)length, sched, key, DES_DECRYPT);
-}
-
-/*
- * like write(), but always writes out the entire buffer.
- */
-static int
-knet_write(
-    int                fd,
-    const void *vbuf,
-    size_t     size)
-{
-    const char *buf = vbuf;    /* so we can do ptr arith */
-    ssize_t n;
-
-    while (size > 0) {
-       n = write(fd, buf, size);
-       if (n < 0)
-           return (-1);
-       buf += n;
-       size -= n;
-    }
-    return (0);
-}
-
-/*
- * Like read(), but waits until the entire buffer has been filled.
- */
-static int
-knet_read(
-    int                fd,
-    void *     vbuf,
-    size_t     size,
-    int                timeout)
-{
-    char *buf = vbuf;  /* ptr arith */
-    ssize_t n;
-    int neof = 0;
-    SELECT_ARG_TYPE readfds;
-    struct timeval tv;
-
-    while (size > 0) {
-       FD_ZERO(&readfds);
-       FD_SET(fd, &readfds);
-       tv.tv_sec = timeout;
-       tv.tv_usec = 0;
-       switch (select(fd + 1, &readfds, NULL, NULL, &tv)) {
-       case 0:
-           errno = ETIMEDOUT;
-           /* FALLTHROUGH */
-       case -1:
-           return (-1);
-       case 1:
-           assert(FD_ISSET(fd, &readfds));
-           break;
-       default:
-           assert(0);
-           break;
-       }
-       n = read(fd, buf, size);
-       if (n < 0)
-           return (-1);
-       /* we only tolerate so many eof's */
-       if (n == 0 && ++neof > 1024) {
-           errno = EIO;
-           return (-1);
-       }
-       buf += n;
-       size -= n;
-    }
-    return (0);
-}
-
-#if 0
-/* -------------------------- */
-/* debug routines */
-
-static void
-print_hex(
-    const char *               str,
-    const unsigned char *      buf,
-    size_t                     len)
-{
-    int i;
-
-    dbprintf("%s:", str);
-    for(i=0;i<len;i++) {
-       if(i%25 == 0)
-               dbprintf("\n");
-       dbprintf(" %02X", buf[i]);
-    }
-    dbprintf("\n");
-}
-
-static void
-print_ticket(
-    const char *str,
-    KTEXT      tktp)
-{
-    dbprintf(_("%s: length %d chk %lX\n"), str, tktp->length, tktp->mbz);
-    print_hex(_("ticket data"), tktp->dat, tktp->length);
-    fflush(stdout);
-}
-
-static void
-print_auth(
-    AUTH_DAT *authp)
-{
-    g_printf("\nAuth Data:\n");
-    g_printf("  Principal \"%s\" Instance \"%s\" Realm \"%s\"\n",
-          authp->pname, authp->pinst, authp->prealm);
-    g_printf("  cksum %d life %d keylen %ld\n", authp->checksum,
-          authp->life, SIZEOF(authp->session));
-    print_hex("session key", authp->session, SIZEOF(authp->session));
-    fflush(stdout);
-}
-
-static void
-print_credentials(
-    CREDENTIALS *credp)
-{
-    g_printf("\nCredentials:\n");
-    g_printf("  service \"%s\" instance \"%s\" realm \"%s\" life %d kvno %d\n",
-          credp->service, credp->instance, credp->realm, credp->lifetime,
-          credp->kvno);
-    print_hex("session key", credp->session, SIZEOF(credp->session));
-    print_hex("ticket", credp->ticket_st.dat, credp->ticket_st.length);
-    fflush(stdout);
-}
-#endif