/* * krb5 version of a security handle allocator. Logically sets * up a network "connection". */ static void krb5_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; assert(fn != NULL); assert(hostname != NULL); auth_debug(1, "krb5: krb5_connect: %s\n", hostname); krb5_init(); rh = alloc(sizeof(*rh)); security_handleinit(&rh->sech, &krb5_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->conf_fn = conf_fn; rh->rc->datap = datap; rh->rc->recv_security_ok = NULL; rh->rc->prefix_packet = NULL; if (rh->rs == NULL) goto error; amfree(rh->hostname); rh->hostname = stralloc(rh->rs->rc->hostname); #ifdef AMANDA_KEYTAB keytab_name = AMANDA_KEYTAB; #else if(conf_fn) { keytab_name = conf_fn("krb5keytab", datap); } #endif #ifdef AMANDA_PRINCIPAL principal_name = AMANDA_PRINCIPAL; #else if(conf_fn) { principal_name = conf_fn("krb5principal", datap); } #endif /* * We need to open a new connection. * * XXX need to eventually limit number of outgoing connections here. */ if(rh->rc->read == -1) { if (runkrb5(rh) < 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); amfree(canonname); return; error: amfree(canonname); (*fn)(arg, &rh->sech, S_ERROR); }
/* * ssh version of a security handle allocator. Logically sets * up a network "connection". */ static void ssh_connect( const char * hostname, char * (*conf_fn)(char *, void *), void (*fn)(void *, security_handle_t *, security_status_t), void * arg, void * datap) { int result; struct sec_handle *rh; char *amandad_path=NULL, *client_username=NULL, *ssh_keys=NULL; assert(fn != NULL); assert(hostname != NULL); auth_debug(1, "ssh_connect: %s\n", hostname); rh = alloc(SIZEOF(*rh)); security_handleinit(&rh->sech, &ssh_security_driver); rh->hostname = NULL; rh->rs = NULL; rh->ev_timeout = NULL; rh->rc = NULL; /* get the canonical hostname */ rh->hostname = NULL; if ((result = resolve_hostname(hostname, 0, NULL, &rh->hostname)) != 0 || rh->hostname == NULL) { security_seterror(&rh->sech, _("ssh_security could not find canonical name for '%s': %s"), hostname, gai_strerror(result)); (*fn)(arg, &rh->sech, S_ERROR); return; } rh->rs = tcpma_stream_client(rh, newhandle++); rh->rc->conf_fn = conf_fn; rh->rc->datap = datap; if (rh->rs == NULL) goto error; amfree(rh->hostname); rh->hostname = stralloc(rh->rs->rc->hostname); /* * We need to open a new connection. * * XXX need to eventually limit number of outgoing connections here. */ if(conf_fn) { amandad_path = conf_fn("amandad_path", datap); client_username = conf_fn("client_username", datap); ssh_keys = conf_fn("ssh_keys", datap); } if(rh->rc->read == -1) { if (runssh(rh->rs->rc, amandad_path, client_username, ssh_keys) < 0) { security_seterror(&rh->sech, _("can't connect to %s: %s"), hostname, rh->rs->rc->errmsg); 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((event_id_t)CONNECT_TIMEOUT, EV_TIME, sec_connect_timeout, rh); return; error: (*fn)(arg, &rh->sech, S_ERROR); }
/* * ssh version of a security handle allocator. Logically sets * up a network "connection". */ static void ssh_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; char *amandad_path=NULL, *client_username=NULL, *ssh_keys=NULL; char *client_port = NULL; assert(fn != NULL); assert(hostname != NULL); auth_debug(1, "ssh_connect: %s\n", hostname); rh = g_new0(struct sec_handle, 1); security_handleinit(&rh->sech, &ssh_security_driver); rh->dle_hostname = g_strdup(hostname); rh->hostname = NULL; rh->rs = NULL; rh->ev_timeout = NULL; rh->rc = NULL; rh->hostname = g_strdup(hostname); rh->rs = tcpma_stream_client(rh, newhandle++); if (rh->rc == NULL) goto error; rh->rc->conf_fn = conf_fn; rh->rc->datap = datap; if (rh->rs == NULL) goto error; amfree(rh->hostname); rh->hostname = g_strdup(rh->rs->rc->hostname); /* * We need to open a new connection. * * XXX need to eventually limit number of outgoing connections here. */ if(conf_fn) { char *port_str; amandad_path = conf_fn("amandad_path", datap); client_username = conf_fn("client_username", datap); ssh_keys = conf_fn("ssh_keys", datap); port_str = conf_fn("client_port", datap); if (port_str && strlen(port_str) >= 1) { client_port = port_str; } } if(rh->rc->read == -1) { if (runssh(rh->rs->rc, amandad_path, client_username, ssh_keys, client_port) < 0) { security_seterror(&rh->sech, _("can't connect to %s: %s"), hostname, rh->rs->rc->errmsg); 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->rc->ev_write = event_register((event_id_t)rh->rs->rc->write, EV_WRITEFD, sec_connect_callback, rh); rh->ev_timeout = event_register((event_id_t)CONNECT_TIMEOUT, EV_TIME, sec_connect_timeout, rh); return; error: (*fn)(arg, &rh->sech, S_ERROR); }
/* * ssl version of a security handle allocator. Logically sets * up a network "connection". */ static void ssl_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; char *src_ip = NULL; char *ssl_dir = NULL; char *ssl_fingerprint_file = NULL; char *ssl_cert_file = NULL; char *ssl_key_file = NULL; char *ssl_ca_cert_file = NULL; char *ssl_cipher_list = NULL; int ssl_check_certificate_host = 1; assert(fn != NULL); assert(hostname != NULL); auth_debug(1, _("ssl: ssl_connect: %s\n"), hostname); rh = g_new0(struct sec_handle, 1); security_handleinit(&rh->sech, &ssl_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) { g_debug(_("resolve_hostname(%s): %s"), 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) { g_debug(_("resolve_hostname(%s) did not return a canonical name"), 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; rh->rc->need_priv_port = 0; if (rh->rs == NULL) goto error; amfree(rh->hostname); rh->hostname = g_strdup(rh->rs->rc->hostname); ssl_dir = getconf_str(CNF_SSL_DIR); if (conf_fn) { service = conf_fn("remote_port", datap); if (!service || strlen(service) <= 1) service = AMANDA_SERVICE_NAME; g_debug("Connecting to service '%s'", service); src_ip = conf_fn("src_ip", datap); ssl_fingerprint_file = g_strdup(conf_fn("ssl_fingerprint_file", datap)); ssl_cert_file = g_strdup(conf_fn("ssl_cert_file", datap)); ssl_key_file = g_strdup(conf_fn("ssl_key_file", datap)); ssl_ca_cert_file = g_strdup(conf_fn("ssl_ca_cert_file", datap)); ssl_cipher_list = conf_fn("ssl_cipher_list", datap); ssl_check_certificate_host = atoi(conf_fn("ssl_check_certificate_host", datap)); } else { service = AMANDA_SERVICE_NAME; } if (ssl_dir) { if (!ssl_cert_file || ssl_cert_file == '\0') { ssl_cert_file = g_strdup_printf("%s/me/crt.pem", ssl_dir); } if (!ssl_key_file || ssl_key_file == '\0') { ssl_key_file = g_strdup_printf("%s/me/private/key.pem", ssl_dir); } if (!ssl_ca_cert_file || ssl_ca_cert_file == '\0') { ssl_ca_cert_file = g_strdup_printf("%s/CA/crt.pem", ssl_dir); } if (!ssl_fingerprint_file || ssl_fingerprint_file == '\0') { struct stat statbuf; ssl_fingerprint_file = g_strdup_printf("%s/remote/%s/fingerprint", ssl_dir, rh->hostname); if (stat(ssl_fingerprint_file, &statbuf) == -1) { g_free(ssl_fingerprint_file); ssl_fingerprint_file = 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. */ if(rh->rc->read == -1) { if (runssl(rh, port, src_ip, ssl_fingerprint_file, ssl_cert_file, ssl_key_file, ssl_ca_cert_file, ssl_cipher_list, ssl_check_certificate_host) < 0) goto error; rh->rc->refcnt++; } g_free(ssl_fingerprint_file); g_free(ssl_cert_file); g_free(ssl_key_file); g_free(ssl_ca_cert_file); /* * 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; 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); }
/* * local version of a security handle allocator. Logically sets * up a network "connection". */ static void local_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; char *amandad_path=NULL; char *client_username=NULL; char myhostname[MAX_HOSTNAME_LENGTH+1]; assert(fn != NULL); assert(hostname != NULL); auth_debug(1, _("local: local_connect: %s\n"), hostname); rh = g_new0(struct sec_handle, 1); security_handleinit(&rh->sech, &local_security_driver); rh->hostname = NULL; rh->rs = NULL; rh->ev_timeout = NULL; rh->rc = NULL; if (gethostname(myhostname, MAX_HOSTNAME_LENGTH) == -1) { security_seterror(&rh->sech, _("gethostname failed")); (*fn)(arg, &rh->sech, S_ERROR); return; } myhostname[SIZEOF(myhostname)-1] = '\0'; if (strcmp(hostname, myhostname) != 0 && match("^localhost(\\.localdomain)?$", hostname) == 0) { security_seterror(&rh->sech, _("%s: is not local"), hostname); (*fn)(arg, &rh->sech, S_ERROR); return; } rh->hostname = stralloc(hostname); rh->rs = tcpma_stream_client(rh, newhandle++); if (rh->rs == NULL) goto error; amfree(rh->hostname); rh->hostname = stralloc(rh->rs->rc->hostname); /* * We need to open a new connection. * * XXX need to eventually limit number of outgoing connections here. */ if(conf_fn) { amandad_path = conf_fn("amandad_path", datap); client_username = conf_fn("client_username", datap); } if(rh->rc->read == -1) { if (runlocal(rh->rs->rc, amandad_path, client_username) < 0) { security_seterror(&rh->sech, _("can't connect to %s: %s"), hostname, rh->rs->rc->errmsg); 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((event_id_t)CONNECT_TIMEOUT, EV_TIME, sec_connect_timeout, rh); return; error: (*fn)(arg, &rh->sech, S_ERROR); amfree(rh->hostname); }