Imported Upstream version 2.5.1
[debian/amanda] / common-src / bsdudp-security.c
diff --git a/common-src/bsdudp-security.c b/common-src/bsdudp-security.c
new file mode 100644 (file)
index 0000000..ae2325f
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Amanda, The Advanced Maryland Automatic Network Disk Archiver
+ * Copyright (c) 1991-1999 University of Maryland at College Park
+ * 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: bsdudp-security.c,v 1.7 2006/07/05 13:18:20 martinea Exp $
+ *
+ * "BSD" security module
+ */
+
+#include "amanda.h"
+#include "util.h"
+#include "clock.h"
+#include "dgram.h"
+#include "event.h"
+#include "packet.h"
+#include "security.h"
+#include "security-util.h"
+#include "stream.h"
+#include "version.h"
+
+#ifdef BSDUDP_SECURITY
+
+/*#define       BSDUDP_DEBUG*/
+
+#ifdef BSDUDP_DEBUG
+#define bsdudpprintf(x)    dbprintf(x)
+#else
+#define bsdudpprintf(x)
+#endif
+
+#ifndef SO_RCVBUF
+#undef DUMPER_SOCKET_BUFFERING
+#endif
+
+/*
+ * Change the following from #undef to #define to cause detailed logging
+ * of the security steps, e.g. into /tmp/amanda/amandad*debug.
+ */
+#undef SHOW_SECURITY_DETAIL
+
+#if defined(TEST)                                              /* { */
+#define SHOW_SECURITY_DETAIL
+#undef bsdudpprintf
+#define bsdudpprintf(p)        printf p
+#endif                                                         /* } */
+
+/*
+ * Interface functions
+ */
+static void bsdudp_connect(const char *,
+    char *(*)(char *, void *), 
+    void (*)(void *, security_handle_t *, security_status_t), void *, void *);
+static void bsdudp_accept(const struct security_driver *, int, int, void (*)(security_handle_t *, pkt_t *));
+static void bsdudp_close(void *);
+
+/*
+ * This is our interface to the outside world
+ */
+const security_driver_t bsdudp_security_driver = {
+    "BSDUDP",
+    bsdudp_connect,
+    bsdudp_accept,
+    bsdudp_close,
+    udpbsd_sendpkt,
+    udp_recvpkt,
+    udp_recvpkt_cancel,
+    tcp1_stream_server,
+    tcp1_stream_accept,
+    tcp1_stream_client,
+    tcpma_stream_close,
+    sec_stream_auth,
+    sec_stream_id,
+    tcpm_stream_write,
+    tcpm_stream_read,
+    tcpm_stream_read_sync,
+    tcpm_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 udp_handle_t netfd;
+static int not_init = 1;
+
+/* generate new handles from here */
+static unsigned int newhandle = 0;
+
+/*
+ * Setup and return a handle outgoing to a client
+ */
+static void
+bsdudp_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;
+    in_port_t port;
+    struct timeval sequence_time;
+    amanda_timezone dontcare;
+    int sequence;
+    char *handle;
+
+    (void)conf_fn;     /* Quiet unused parameter warning */
+    (void)datap;       /* Quiet unused parameter warning */
+    assert(hostname != NULL);
+
+    bh = alloc(sizeof(*bh));
+    bh->proto_handle=NULL;
+    bh->udp = &netfd;
+    bh->rc = NULL;
+    security_handleinit(&bh->sech, &bsdudp_security_driver);
+
+    /*
+     * Only init the socket once
+     */
+    if (not_init == 1) {
+       uid_t euid;
+       dgram_zero(&netfd.dgram);
+       
+       euid = geteuid();
+       seteuid(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 %u)",
+               (unsigned int)port);
+           (*fn)(arg, &bh->sech, S_ERROR);
+           return;
+       }
+       not_init = 0;
+    }
+
+    if ((he = gethostbyname(hostname)) == NULL) {
+       security_seterror(&bh->sech,
+           "%s: could not resolve hostname", hostname);
+       (*fn)(arg, &bh->sech, S_ERROR);
+       return;
+    }
+    if ((se = getservbyname(AMANDA_SERVICE_NAME, "udp")) == NULL)
+       port = (in_port_t)htons(AMANDA_SERVICE_DEFAULT);
+    else
+       port = (in_port_t)se->s_port;
+    amanda_gettimeofday(&sequence_time, &dontcare);
+    sequence = (int)sequence_time.tv_sec ^ (int)sequence_time.tv_usec;
+    handle=alloc(15);
+    snprintf(handle,14,"000-%08x", 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
+bsdudp_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 */
+
+    assert(in >= 0 && out >= 0);
+    assert(fn != NULL);
+
+    /*
+     * We assume in and out point to the same socket, and just use
+     * in.
+     */
+    dgram_socket(&netfd.dgram, in);
+
+    /*
+     * Assign the function and return.  When they call recvpkt later,
+     * the recvpkt callback will call this function when it discovers
+     * new incoming connections
+     */
+    netfd.accept_fn = fn;
+    netfd.recv_security_ok = &bsd_recv_security_ok;
+    netfd.prefix_packet = &bsd_prefix_packet;
+    netfd.driver = &bsdudp_security_driver;
+
+
+    udp_addref(&netfd, &udp_netfd_read_callback);
+}
+
+/*
+ * Frees a handle allocated by the above
+ */
+static void
+bsdudp_close(
+    void *cookie)
+{
+    struct sec_handle *bh = cookie;
+
+    if(bh->proto_handle == NULL) {
+       return;
+    }
+
+    bsdudpprintf(("%s: bsdudp: close handle '%s'\n",
+              debug_prefix_time(NULL), bh->proto_handle));
+
+    udp_recvpkt_cancel(bh);
+    if(bh->next) {
+       bh->next->prev = bh->prev;
+    }
+    else {
+       netfd.bh_last = bh->prev;
+    }
+    if(bh->prev) {
+       bh->prev->next = bh->next;
+    }
+    else {
+       netfd.bh_first = bh->next;
+    }
+
+    amfree(bh->proto_handle);
+    amfree(bh->hostname);
+    amfree(bh);
+}
+
+#endif /* BSDUDP_SECURITY */                                   /* } */
+