static void bsdtcp_fn_connect( void *cookie, security_handle_t *security_handle, security_status_t status) { struct sec_handle *rh = cookie; int result; if (status == S_OK) { int so_errno; socklen_t error_len = sizeof(so_errno); if (getsockopt(rh->rc->write, SOL_SOCKET, SO_ERROR, &so_errno, &error_len) == -1) { status = S_ERROR; } else if (rh->next_res && so_errno == ECONNREFUSED) { status = S_ERROR; } } switch (status) { case S_TIMEOUT: case S_ERROR: if (rh->next_res) { while (rh->next_res) { result = runbsdtcp(rh, rh->src_ip, rh->port); if (result >= 0) { rh->rc->refcnt++; rh->rs->rc->ev_write = event_create( (event_id_t)(rh->rs->rc->write), EV_WRITEFD, sec_connect_callback, rh); rh->ev_timeout = event_create(CONNECT_TIMEOUT, EV_TIME, sec_connect_timeout, rh); event_activate(rh->rs->rc->ev_write); event_activate(rh->ev_timeout); return; } } } // pass through case S_OK: if (rh->res) freeaddrinfo(rh->res); rh->res = NULL; rh->next_res = NULL; rh->src_ip = NULL; rh->port = 0; rh->connect_callback(rh->connect_arg, security_handle, status); break; default: assert(0); break; } }
/* * bsdtcp version of a security handle allocator. Logically sets * up a network "connection". */ static void bsdtcp_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 *rh; int result; char *canonname; char *service; in_port_t port; assert(fn != NULL); assert(hostname != NULL); (void)conf_fn; /* Quiet unused parameter warning */ (void)datap; /* Quiet unused parameter warning */ auth_debug(1, _("bsdtcp: bsdtcp_connect: %s\n"), hostname); rh = alloc(sizeof(*rh)); security_handleinit(&rh->sech, &bsdtcp_security_driver); rh->hostname = NULL; rh->rs = NULL; rh->ev_timeout = NULL; rh->rc = NULL; result = resolve_hostname(hostname, 0, NULL, &canonname); if(result != 0) { dbprintf(_("resolve_hostname(%s): %s\n"), hostname, gai_strerror(result)); security_seterror(&rh->sech, _("resolve_hostname(%s): %s\n"), hostname, gai_strerror(result)); (*fn)(arg, &rh->sech, S_ERROR); return; } if (canonname == NULL) { dbprintf(_("resolve_hostname(%s) did not return a canonical name\n"), hostname); security_seterror(&rh->sech, _("resolve_hostname(%s) did not return a canonical name\n"), hostname); (*fn)(arg, &rh->sech, S_ERROR); return; } rh->hostname = canonname; /* will be replaced */ canonname = NULL; /* steal reference */ rh->rs = tcpma_stream_client(rh, newhandle++); rh->rc->recv_security_ok = &bsd_recv_security_ok; rh->rc->prefix_packet = &bsd_prefix_packet; if (rh->rs == NULL) goto error; amfree(rh->hostname); rh->hostname = stralloc(rh->rs->rc->hostname); if (conf_fn) { service = conf_fn("client_port", datap); if (strlen(service) <= 1) service = "amanda"; } else { service = "amanda"; } port = find_port_for_service(service, "tcp"); if (port == 0) { security_seterror(&rh->sech, _("%s/tcp unknown protocol"), service); goto error; } /* * We need to open a new connection. * * XXX need to eventually limit number of outgoing connections here. */ if(rh->rc->read == -1) { if (runbsdtcp(rh, port) < 0) goto error; rh->rc->refcnt++; } /* * The socket will be opened async so hosts that are down won't * block everything. We need to register a write event * so we will know when the socket comes alive. * * Overload rh->rs->ev_read to provide a write event handle. * We also register a timeout. */ rh->fn.connect = fn; rh->arg = arg; rh->rs->ev_read = event_register((event_id_t)(rh->rs->rc->write), EV_WRITEFD, sec_connect_callback, rh); rh->ev_timeout = event_register(CONNECT_TIMEOUT, EV_TIME, sec_connect_timeout, rh); return; error: (*fn)(arg, &rh->sech, S_ERROR); }
/* * bsdtcp version of a security handle allocator. Logically sets * up a network "connection". */ static void bsdtcp_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 *rh; int result; char *canonname; char *service; char *src_ip; in_port_t port; struct addrinfo *res = NULL; assert(fn != NULL); assert(hostname != NULL); (void)conf_fn; /* Quiet unused parameter warning */ (void)datap; /* Quiet unused parameter warning */ auth_debug(1, _("bsdtcp: bsdtcp_connect: %s\n"), hostname); rh = g_new0(struct sec_handle, 1); security_handleinit(&rh->sech, &bsdtcp_security_driver); rh->dle_hostname = g_strdup(hostname); rh->hostname = NULL; rh->rs = NULL; rh->ev_timeout = NULL; rh->rc = NULL; result = resolve_hostname(hostname, SOCK_STREAM, &res, &canonname); if(result != 0) { dbprintf(_("resolve_hostname(%s): %s\n"), hostname, gai_strerror(result)); security_seterror(&rh->sech, _("resolve_hostname(%s): %s"), hostname, gai_strerror(result)); (*fn)(arg, &rh->sech, S_ERROR); if (res) freeaddrinfo(res); return; } if (canonname == NULL) { dbprintf(_("resolve_hostname(%s) did not return a canonical name\n"), hostname); security_seterror(&rh->sech, _("resolve_hostname(%s) did not return a canonical name"), hostname); (*fn)(arg, &rh->sech, S_ERROR); if (res) freeaddrinfo(res); return; } rh->hostname = canonname; /* will be replaced */ canonname = NULL; /* steal reference */ rh->rs = tcpma_stream_client(rh, newhandle++); if (rh->rc == NULL) goto error; rh->rc->recv_security_ok = &bsd_recv_security_ok; rh->rc->prefix_packet = &bsd_prefix_packet; rh->rc->need_priv_port = 1; if (rh->rs == NULL) goto error; amfree(rh->hostname); rh->hostname = g_strdup(rh->rs->rc->hostname); if (conf_fn) { service = conf_fn("client_port", datap); if (!service || strlen(service) <= 1) service = AMANDA_SERVICE_NAME; src_ip = conf_fn("src_ip", datap); } else { service = AMANDA_SERVICE_NAME; src_ip = NULL; } port = find_port_for_service(service, "tcp"); if (port == 0) { security_seterror(&rh->sech, _("%s/tcp unknown protocol"), service); goto error; } /* * We need to open a new connection. * * XXX need to eventually limit number of outgoing connections here. */ rh->res = res; rh->next_res = res; rh->src_ip = src_ip; rh->port = port; if(rh->rc->read == -1) { int result = -1; while (rh->next_res) { result = runbsdtcp(rh, rh->src_ip, rh->port); if (result >=0 ) break; } if (result < 0) goto error; rh->rc->refcnt++; } /* * The socket will be opened async so hosts that are down won't * block everything. We need to register a write event * so we will know when the socket comes alive. * * Overload rh->rs->ev_read to provide a write event handle. * We also register a timeout. */ rh->fn.connect = &bsdtcp_fn_connect; rh->arg = rh; rh->connect_callback = fn; rh->connect_arg = arg; g_mutex_lock(security_mutex); rh->rs->rc->ev_write = event_create((event_id_t)(rh->rs->rc->write), EV_WRITEFD, sec_connect_callback, rh); rh->ev_timeout = event_create(CONNECT_TIMEOUT, EV_TIME, sec_connect_timeout, rh); event_activate(rh->rs->rc->ev_write); event_activate(rh->ev_timeout); g_mutex_unlock(security_mutex); return; error: if (res) { freeaddrinfo(res); } rh->res = NULL; rh->next_res = NULL; (*fn)(arg, &rh->sech, S_ERROR); }