Imported Upstream version 2.6.0
[debian/amanda] / common-src / bsdudp-security.c
index 9a3949d5ad8bb5a0ff5d71d8946a00b3945053d6..2ae9e4edb1cb26ed063c82f9a7e1182601640bec 100644 (file)
 #include "stream.h"
 #include "version.h"
 
-#ifdef BSDUDP_SECURITY
-
 #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
-
 /*
  * 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_accept(const struct security_driver *,
+    char *(*)(char *, void *),
+    int, int,
+    void (*)(security_handle_t *, pkt_t *),
+    void *);
 static void bsdudp_close(void *);
 
 /*
@@ -114,12 +110,12 @@ bsdudp_connect(
     struct servent *se;
     in_port_t port;
     struct timeval sequence_time;
-    amanda_timezone dontcare;
     int sequence;
     char *handle;
     int result;
-    struct addrinfo hints;
-    struct addrinfo *res = NULL;
+    char *canonname;
+    struct addrinfo *res = NULL, *res_addr;
+    int result_bind;
 
     (void)conf_fn;     /* Quiet unused parameter warning */
     (void)datap;       /* Quiet unused parameter warning */
@@ -130,117 +126,142 @@ bsdudp_connect(
     bh->rc = NULL;
     security_handleinit(&bh->sech, &bsdudp_security_driver);
 
-#ifdef WORKING_IPV6
-    hints.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ALL;
-    hints.ai_family = AF_INET6;
-#else
-    hints.ai_flags = AI_CANONNAME;
-    hints.ai_family = AF_INET;
-#endif
-    hints.ai_socktype = SOCK_DGRAM;
-    hints.ai_protocol = IPPROTO_UDP;
-    hints.ai_addrlen = 0;
-    hints.ai_addr = NULL;
-    hints.ai_canonname = NULL;
-    hints.ai_next = NULL;
-    result = getaddrinfo(hostname, NULL, &hints, &res);
-#ifdef WORKING_IPV6
-    if (result != 0) {
-       hints.ai_flags = AI_CANONNAME;
-       hints.ai_family = AF_UNSPEC;
-       result = getaddrinfo(hostname, NULL, &hints, &res);
-    }
-#endif
+    result = resolve_hostname(hostname, SOCK_DGRAM, &res, &canonname);
     if(result != 0) {
-        dbprintf(("getaddrinfo: %s\n", gai_strerror(result)));
-       security_seterror(&bh->sech, "getaddrinfo(%s): %s\n", hostname,
+       dbprintf(_("resolve_hostname(%s): %s\n"), hostname, gai_strerror(result));
+       security_seterror(&bh->sech, _("resolve_hostname(%s): %s\n"), hostname,
                          gai_strerror(result));
        (*fn)(arg, &bh->sech, S_ERROR);
-        return;
+       return;
     }
-    if (res->ai_canonname == NULL) {
-       dbprintf(("getaddrinfo(%s) did not return a canonical name\n", hostname));
+    if (canonname == NULL) {
+       dbprintf(_("resolve_hostname(%s) did not return a canonical name\n"), hostname);
        security_seterror(&bh->sech,
-               _("getaddrinfo(%s) did not return a canonical name\n"), hostname);
+               _("resolve_hostname(%s) did not return a canonical name\n"), hostname);
        (*fn)(arg, &bh->sech, S_ERROR);
        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;
+    }
 
-    /*
-     * Only init the socket once
-     */
+    for (res_addr = res; res_addr != NULL; res_addr = res_addr->ai_next) {
 #ifdef WORKING_IPV6
-    if (res->ai_addr->sa_family == AF_INET6 && not_init6 == 1) {
-       uid_t euid;
-       dgram_zero(&netfd6.dgram);
-       
-       euid = geteuid();
-       seteuid(0);
-       dgram_bind(&netfd6.dgram, res->ai_addr->sa_family, &port);
-       seteuid(euid);
-       netfd6.handle = NULL;
-       netfd6.pkt.body = NULL;
-       netfd6.recv_security_ok = &bsd_recv_security_ok;
-       netfd6.prefix_packet = &bsd_prefix_packet;
+       /* IPv6 socket already bound */
+       if (res_addr->ai_addr->sa_family == AF_INET6 && not_init6 == 0) {
+           break;
+       }
        /*
-        * We must have a reserved port.  Bomb if we didn't get one.
+        * Only init the IPv6 socket once
         */
-       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;
+       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);
+           set_root_privs(0);
+           if (result_bind != 0) {
+               continue;
+           }
+           netfd6.handle = NULL;
+           netfd6.pkt.body = NULL;
+           netfd6.recv_security_ok = &bsd_recv_security_ok;
+           netfd6.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);
+               freeaddrinfo(res);
+               amfree(canonname);
+               return;
+           }
+           not_init6 = 0;
+           bh->udp = &netfd6;
+           break;
        }
-       not_init6 = 0;
-       bh->udp = &netfd6;
-    }
 #endif
 
-    if (res->ai_addr->sa_family == AF_INET && not_init4 == 1) {
-       uid_t euid;
-       dgram_zero(&netfd4.dgram);
+       /* IPv4 socket already bound */
+       if (res_addr->ai_addr->sa_family == AF_INET && not_init4 == 0) {
+           break;
+       }
 
-       euid = geteuid();
-       seteuid((uid_t)0);
-       dgram_bind(&netfd4.dgram, res->ai_addr->sa_family, &port);
-       seteuid(euid);
-       netfd4.handle = NULL;
-       netfd4.pkt.body = NULL;
-       netfd4.recv_security_ok = &bsd_recv_security_ok;
-       netfd4.prefix_packet = &bsd_prefix_packet;
        /*
-        * We must have a reserved port.  Bomb if we didn't get one.
+        * Only init the IPv4 socket once
         */
-       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;
+       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);
+           set_root_privs(0);
+           if (result_bind != 0) {
+               continue;
+           }
+           netfd4.handle = NULL;
+           netfd4.pkt.body = NULL;
+           netfd4.recv_security_ok = &bsd_recv_security_ok;
+           netfd4.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);
+               freeaddrinfo(res);
+               amfree(canonname);
+               return;
+           }
+           not_init4 = 0;
+           bh->udp = &netfd4;
+           break;
        }
-       not_init4 = 0;
-       bh->udp = &netfd4;
+    }
+
+    if (res_addr == NULL) {
+       dbprintf(_("Can't bind a socket to connect to %s\n"), hostname);
+       security_seterror(&bh->sech,
+               _("Can't bind a socket to connect to %s\n"), hostname);
+       (*fn)(arg, &bh->sech, S_ERROR);
+       amfree(canonname);
+       return;
     }
 
 #ifdef WORKING_IPV6
-    if (res->ai_addr->sa_family == AF_INET6)
+    if (res_addr->ai_addr->sa_family == AF_INET6)
        bh->udp = &netfd6;
     else
 #endif
        bh->udp = &netfd4;
 
-    auth_debug(1, ("Resolved hostname=%s\n", res->ai_canonname));
+    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);
-    amanda_gettimeofday(&sequence_time, &dontcare);
+    amanda_gettimeofday(&sequence_time);
     sequence = (int)sequence_time.tv_sec ^ (int)sequence_time.tv_usec;
     handle=alloc(15);
-    snprintf(handle,14,"000-%08x", newhandle++);
-    if (udp_inithandle(bh->udp, bh, res->ai_canonname,
-                      (struct sockaddr_storage *)res->ai_addr, port,
+    g_snprintf(handle,14,"000-%08x", newhandle++);
+    if (udp_inithandle(bh->udp, bh, canonname,
+                      (struct sockaddr_storage *)res_addr->ai_addr, port,
                       handle, sequence) < 0) {
        (*fn)(arg, &bh->sech, S_ERROR);
        amfree(bh->hostname);
@@ -249,8 +270,9 @@ bsdudp_connect(
        (*fn)(arg, &bh->sech, S_OK);
     }
     amfree(handle);
+    amfree(canonname);
 
-    freeaddrinfo(res);
+    if (res) freeaddrinfo(res);
 }
 
 /*
@@ -259,12 +281,16 @@ bsdudp_connect(
 static void
 bsdudp_accept(
     const struct security_driver *driver,
+    char *      (*conf_fn)(char *, void *),
     int                in,
     int                out,
-    void       (*fn)(security_handle_t *, pkt_t *))
+    void       (*fn)(security_handle_t *, pkt_t *),
+    void       *datap)
 {
     (void)driver;      /* Quiet unused parameter warning */
     (void)out;         /* Quiet unused parameter warning */
+    (void)conf_fn;
+    (void)datap;
 
     assert(in >= 0 && out >= 0);
     assert(fn != NULL);
@@ -303,8 +329,7 @@ bsdudp_close(
        return;
     }
 
-    auth_debug(1, ("%s: bsdudp: close handle '%s'\n",
-                  debug_prefix_time(NULL), bh->proto_handle));
+    auth_debug(1, _("bsdudp: close handle '%s'\n"), bh->proto_handle);
 
     udp_recvpkt_cancel(bh);
     if(bh->next) {
@@ -331,5 +356,3 @@ bsdudp_close(
     amfree(bh);
 }
 
-#endif /* BSDUDP_SECURITY */                                   /* } */
-