#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_accept(const struct security_driver *,
+ char *(*)(char *, void *),
+ int, int,
+ void (*)(security_handle_t *, pkt_t *),
+ void *);
static void bsdudp_close(void *);
/*
tcpm_stream_read_sync,
tcpm_stream_read_cancel,
sec_close_connection_none,
+ NULL,
+ NULL
};
/*
* 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;
+static udp_handle_t netfd4;
+static udp_handle_t netfd6;
+static int not_init4 = 1;
+static int not_init6 = 1;
/* generate new handles from here */
static unsigned int newhandle = 0;
{
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;
+ int result;
+ char *canonname;
+ struct addrinfo *res = NULL, *res_addr;
+ int result_bind;
(void)conf_fn; /* Quiet unused parameter warning */
(void)datap; /* Quiet unused parameter warning */
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;
+ result = resolve_hostname(hostname, SOCK_DGRAM, &res, &canonname);
+ if(result != 0) {
+ 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;
+ }
+ if (canonname == NULL) {
+ dbprintf(_("resolve_hostname(%s) did not return a canonical name\n"), hostname);
+ security_seterror(&bh->sech,
+ _("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;
+ }
+
+ for (res_addr = res; res_addr != NULL; res_addr = res_addr->ai_next) {
+#ifdef WORKING_IPV6
+ /* IPv6 socket already bound */
+ if (res_addr->ai_addr->sa_family == AF_INET6 && not_init6 == 0) {
+ break;
+ }
+ /*
+ * 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);
+ 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;
+ }
+#endif
+
+ /* IPv4 socket already bound */
+ if (res_addr->ai_addr->sa_family == AF_INET && not_init4 == 0) {
+ break;
+ }
+
/*
- * 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_init = 0;
}
- if ((he = gethostbyname(hostname)) == NULL) {
+ if (res_addr == NULL) {
+ dbprintf(_("Can't bind a socket to connect to %s\n"), hostname);
security_seterror(&bh->sech,
- "%s: could not resolve hostname", hostname);
+ _("Can't bind a socket to connect to %s\n"), hostname);
(*fn)(arg, &bh->sech, S_ERROR);
- return;
+ amfree(canonname);
+ return;
}
+
+#ifdef WORKING_IPV6
+ if (res_addr->ai_addr->sa_family == AF_INET6)
+ bh->udp = &netfd6;
+ else
+#endif
+ bh->udp = &netfd4;
+
+ auth_debug(1, _("Resolved hostname=%s\n"), canonname);
if ((se = getservbyname(AMANDA_SERVICE_NAME, "udp")) == NULL)
- port = (in_port_t)htons(AMANDA_SERVICE_DEFAULT);
+ port = AMANDA_SERVICE_DEFAULT;
else
- port = (in_port_t)se->s_port;
- amanda_gettimeofday(&sequence_time, &dontcare);
+ port = (in_port_t)ntohs(se->s_port);
+ 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(&netfd, bh, he, port, handle, sequence) < 0) {
+ g_snprintf(handle,14,"000-%08x", newhandle++);
+ if (udp_inithandle(bh->udp, bh, canonname,
+ (sockaddr_union *)res_addr->ai_addr, port,
+ handle, sequence) < 0) {
(*fn)(arg, &bh->sech, S_ERROR);
amfree(bh->hostname);
amfree(bh);
(*fn)(arg, &bh->sech, S_OK);
}
amfree(handle);
+ amfree(canonname);
+
+ if (res) freeaddrinfo(res);
}
/*
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);
* We assume in and out point to the same socket, and just use
* in.
*/
- dgram_socket(&netfd.dgram, in);
+ dgram_socket(&netfd4.dgram, in);
+ dgram_socket(&netfd6.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;
+ netfd4.accept_fn = fn;
+ netfd4.recv_security_ok = &bsd_recv_security_ok;
+ netfd4.prefix_packet = &bsd_prefix_packet;
+ netfd4.driver = &bsdudp_security_driver;
- udp_addref(&netfd, &udp_netfd_read_callback);
+ udp_addref(&netfd4, &udp_netfd_read_callback);
}
/*
return;
}
- bsdudpprintf(("%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) {
bh->next->prev = bh->prev;
}
else {
- netfd.bh_last = bh->prev;
+ if (!not_init6 && netfd6.bh_last == bh)
+ netfd6.bh_last = bh->prev;
+ else
+ netfd4.bh_last = bh->prev;
}
if(bh->prev) {
bh->prev->next = bh->next;
}
else {
- netfd.bh_first = bh->next;
+ if (!not_init6 && netfd6.bh_first == bh)
+ netfd6.bh_first = bh->next;
+ else
+ netfd4.bh_first = bh->next;
}
amfree(bh->proto_handle);
amfree(bh);
}
-#endif /* BSDUDP_SECURITY */ /* } */
-