#include "security.h"
#include "security-util.h"
#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 *);
/*
"BSDUDP",
bsdudp_connect,
bsdudp_accept,
+ sec_get_authenticated_peer_name_hostname,
bsdudp_close,
udpbsd_sendpkt,
udp_recvpkt,
void * datap)
{
struct sec_handle *bh;
- 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;
+ char *service;
(void)conf_fn; /* Quiet unused parameter warning */
(void)datap; /* Quiet unused parameter warning */
assert(hostname != NULL);
- bh = alloc(sizeof(*bh));
+ bh = g_new0(struct sec_handle, 1);
bh->proto_handle=NULL;
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 (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->ai_canonname == NULL) {
- dbprintf(("getaddrinfo(%s) did not return a canonical name\n", hostname));
+ if (res == NULL) {
+ dbprintf(_("resolve_hostname(%s): no results\n"), hostname);
security_seterror(&bh->sech,
- _("getaddrinfo(%s) did not return a canonical name\n"), hostname);
+ _("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);
-
- 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;
+ /* 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_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));
- 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);
+ auth_debug(1, _("Resolved hostname=%s\n"), canonname);
+ 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);
- 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,
+ (sockaddr_union *)res_addr->ai_addr, port,
handle, sequence) < 0) {
(*fn)(arg, &bh->sech, S_ERROR);
amfree(bh->hostname);
(*fn)(arg, &bh->sech, S_OK);
}
amfree(handle);
+ amfree(canonname);
- freeaddrinfo(res);
+ 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);
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) {
amfree(bh);
}
-#endif /* BSDUDP_SECURITY */ /* } */
-