lintian doesn't like orphan packages with uploaders...
[debian/amanda] / common-src / bsd-security.c
index 4be79482bb6bc036871bcc539bab6b8c6d133dd2..82348ed98241b0c849658696826267eb0188bc95 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
  * Copyright (c) 1991-1999 University of Maryland at College Park
+ * Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
  * All Rights Reserved.
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
@@ -39,7 +40,6 @@
 #include "security-util.h"
 #include "sockaddr-util.h"
 #include "stream.h"
-#include "version.h"
 
 #ifndef SO_RCVBUF
 #undef DUMPER_SOCKET_BUFFERING
@@ -74,6 +74,7 @@ const security_driver_t bsd_security_driver = {
     "BSD",
     bsd_connect,
     bsd_accept,
+    sec_get_authenticated_peer_name_hostname,
     bsd_close,
     udpbsd_sendpkt,
     udp_recvpkt,
@@ -124,7 +125,6 @@ bsd_connect(
     void *             datap)
 {
     struct sec_handle *bh;
-    struct servent *se;
     in_port_t port = 0;
     struct timeval sequence_time;
     int sequence;
@@ -133,13 +133,14 @@ bsd_connect(
     struct addrinfo *res, *res_addr;
     char *canonname;
     int result_bind;
+    char *service;
 
     assert(hostname != NULL);
 
     (void)conf_fn;     /* Quiet unused parameter warning */
     (void)datap;        /* Quiet unused parameter warning */
 
-    bh = alloc(SIZEOF(*bh));
+    bh = g_new0(struct sec_handle, 1);
     bh->proto_handle=NULL;
     security_handleinit(&bh->sech, &bsd_security_driver);
 
@@ -156,15 +157,16 @@ bsd_connect(
        security_seterror(&bh->sech,
                _("resolve_hostname(%s) did not return a canonical name\n"), hostname);
        (*fn)(arg, &bh->sech, S_ERROR);
-       return;
+       if (res) freeaddrinfo(res);
+       return;
     }
     if (res == NULL) {
        dbprintf(_("resolve_hostname(%s): no results\n"), hostname);
        security_seterror(&bh->sech,
                _("resolve_hostname(%s): no results\n"), hostname);
        (*fn)(arg, &bh->sech, S_ERROR);
-       amfree(canonname);
-       return;
+       amfree(canonname);
+       return;
     }
 
     for (res_addr = res; res_addr != NULL; res_addr = res_addr->ai_next) {
@@ -177,10 +179,8 @@ bsd_connect(
         * Only init the IPv6 socket once
         */
        if (res_addr->ai_addr->sa_family == AF_INET6 && not_init6 == 1) {
-           uid_t euid;
            dgram_zero(&netfd6.dgram);
 
-           euid = geteuid();
            set_root_privs(1);
            result_bind = dgram_bind(&netfd6.dgram,
                                     res_addr->ai_addr->sa_family, &port);
@@ -219,10 +219,8 @@ bsd_connect(
         * Only init the IPv4 socket once
         */
        if (res_addr->ai_addr->sa_family == AF_INET && not_init4 == 1) {
-           uid_t euid;
            dgram_zero(&netfd4.dgram);
 
-           euid = geteuid();
            set_root_privs(1);
            result_bind = dgram_bind(&netfd4.dgram,
                                     res_addr->ai_addr->sa_family, &port);
@@ -269,10 +267,22 @@ bsd_connect(
        bh->udp = &netfd4;
 
     auth_debug(1, _("Resolved hostname=%s\n"), canonname);
-    if ((se = getservbyname(AMANDA_SERVICE_NAME, "udp")) == NULL)
-       port = AMANDA_SERVICE_DEFAULT;
-    else
-       port = (in_port_t)ntohs(se->s_port);
+
+    if (conf_fn) {
+        service = conf_fn("client_port", datap);
+        if (!service || strlen(service) <= 1)
+            service = "amanda";
+    } else {
+        service = "amanda";
+    }
+    port = find_port_for_service(service, "udp");
+    if (port == 0) {
+        security_seterror(&bh->sech, _("%s/udp unknown protocol"), service);
+       (*fn)(arg, &bh->sech, S_ERROR);
+        amfree(canonname);
+       return;
+    }
+
     amanda_gettimeofday(&sequence_time);
     sequence = (int)sequence_time.tv_sec ^ (int)sequence_time.tv_usec;
     handle=alloc(15);
@@ -304,6 +314,7 @@ bsd_accept(
     void       (*fn)(security_handle_t *, pkt_t *),
     void       *datap)
 {
+    struct stat sbuf;
 
     assert(in >= 0 && out >= 0);
     assert(fn != NULL);
@@ -330,7 +341,13 @@ bsd_accept(
     netfd4.prefix_packet = &bsd_prefix_packet;
     netfd4.driver = &bsd_security_driver;
 
-    udp_addref(&netfd4, &udp_netfd_read_callback);
+    /* check if in is a socket */
+    fstat(in, &sbuf);
+    if (S_ISSOCK(sbuf.st_mode)) {
+       udp_addref(&netfd4, &udp_netfd_read_callback);
+    } else {
+       g_warning("input file descriptor is not a socket; cannot use BSD auth");
+    }
 }
 
 /*
@@ -386,7 +403,7 @@ bsd_stream_server(
 
     assert(bh != NULL);
 
-    bs = alloc(SIZEOF(*bs));
+    bs = g_new0(struct sec_stream, 1);
     security_streaminit(&bs->secstr, &bsd_security_driver);
     bs->socket = stream_server(SU_GET_FAMILY(&bh->udp->peer), &bs->port,
                               (size_t)STREAM_BUFSIZE, (size_t)STREAM_BUFSIZE,
@@ -441,7 +458,7 @@ bsd_stream_client(
 
     assert(bh != NULL);
 
-    bs = alloc(SIZEOF(*bs));
+    bs = g_new0(struct sec_stream, 1);
     security_streaminit(&bs->secstr, &bsd_security_driver);
     bs->fd = stream_client(bh->hostname, (in_port_t)id,
        STREAM_BUFSIZE, STREAM_BUFSIZE, &bs->port, 0);
@@ -528,6 +545,10 @@ bsd_stream_read(
     bs->arg = arg;
 }
 
+/* buffer for bsd_stream_read_sync function */
+static ssize_t  sync_pktlen;
+static void    *sync_pkt;
+
 /*
  * Read a chunk of data to a stream.  Blocks until completion.
  */
@@ -546,11 +567,13 @@ bsd_stream_read_sync(
     if(bs->ev_read != NULL) {
         return -1;
     }
+    sync_pktlen = 0;
+    sync_pkt = NULL;
     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);
+    *buf = sync_pkt;
+    return (sync_pktlen);
 }
 
 
@@ -576,8 +599,15 @@ stream_read_sync_callback(
        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));
+        security_stream_seterror(&bs->secstr, "%s", strerror(errno));
     bs->len = n;
+    sync_pktlen = bs->len;
+    if (sync_pktlen > 0) {
+       sync_pkt = malloc(sync_pktlen);
+       memcpy(sync_pkt, bs->databuf, sync_pktlen);
+    } else {
+       sync_pkt = NULL;
+    }
 }
 
 /*
@@ -609,16 +639,14 @@ stream_read_callback(
 
     assert(bs != NULL);
 
-    /*
-     * 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)));
 
+    if (n <= 0)
+       bsd_stream_read_cancel(bs);
     if (n < 0)
-       security_stream_seterror(&bs->secstr, strerror(errno));
+       security_stream_seterror(&bs->secstr, "%s", strerror(errno));
 
     (*bs->fn)(bs->arg, bs->databuf, n);
 }