/* * Setup to handle new incoming connections */ static void krb5_accept( const struct security_driver *driver, char *(*conf_fn)(char *, void *), int in, int out, void (*fn)(security_handle_t *, pkt_t *), void *datap) { sockaddr_union sin; socklen_t_equiv len; struct tcp_conn *rc; char hostname[NI_MAXHOST]; int result; char *errmsg = NULL; krb5_init(); len = sizeof(sin); if (getpeername(in, (struct sockaddr *)&sin, &len) < 0) { dbprintf(_("getpeername returned: %s\n"), strerror(errno)); return; } if ((result = getnameinfo((struct sockaddr *)&sin, len, hostname, NI_MAXHOST, NULL, 0, 0) != 0)) { dbprintf(_("getnameinfo failed: %s\n"), gai_strerror(result)); return; } if (check_name_give_sockaddr(hostname, (struct sockaddr *)&sin, &errmsg) < 0) { dbprintf(_("check_name_give_sockaddr(%s): %s\n"), hostname, errmsg); amfree(errmsg); return; } rc = sec_tcp_conn_get(hostname, 0); rc->conf_fn = conf_fn; rc->datap = datap; rc->recv_security_ok = NULL; rc->prefix_packet = NULL; copy_sockaddr(&rc->peer, &sin); rc->read = in; rc->write = out; rc->driver = driver; if (gss_server(rc) < 0) error("gss_server failed: %s\n", rc->errmsg); rc->accept_fn = fn; sec_tcp_conn_read(rc); }
/* like sec_accept, but first it gets the remote system's hostname */ static void ssh_accept( const security_driver_t *driver, char *(*conf_fn)(char *, void *), int in, int out, void (*fn)(security_handle_t *, pkt_t *), void *datap) { struct sec_handle *rh; struct tcp_conn *rc = sec_tcp_conn_get(NULL, "", 0); char *ssh_connection, *p; char *errmsg = NULL; sockaddr_union addr; int result; /* "Accepting" an SSH connection means that amandad was invoked via sshd, so * we should have anSSH_CONNECTION env var. If not, then this probably isn't * a real SSH connection and we should bail out. */ ssh_connection = getenv("SSH_CONNECTION"); if (!ssh_connection) { errmsg = g_strdup("$SSH_CONNECTION not set - was amandad started by sshd?"); goto error; } /* make a local copy, to munge */ ssh_connection = g_strdup(ssh_connection); /* strip off the first component - the ASCII IP address */ if ((p = strchr(ssh_connection, ' ')) == NULL) { errmsg = g_strdup("$SSH_CONNECTION malformed"); goto error; } *p = '\0'; /* ---- everything from here on is just a warning, leaving hostname at "" */ SU_INIT(&addr, AF_INET); /* turn the string address into a sockaddr */ if ((result = str_to_sockaddr(ssh_connection, &addr)) != 1) { if (result == 0) { g_warning("Could not parse peer address %s", ssh_connection); } else { g_warning("Parsing peer address %s: %s", ssh_connection, gai_strerror(result)); } goto done; } /* find the hostname */ result = getnameinfo((struct sockaddr *)&addr, SS_LEN(&addr), rc->hostname, sizeof(rc->hostname), NULL, 0, 0); if (result != 0) { g_warning("Could not get hostname for SSH client %s: %s", ssh_connection, gai_strerror(result)); goto done; } /* and verify it */ if (check_name_give_sockaddr(rc->hostname, (struct sockaddr *)&addr, &errmsg) < 0) { rc->hostname[0] = '\0'; /* null out the bad hostname */ g_warning("Checking SSH client DNS: %s", errmsg); amfree(errmsg); goto done; } done: g_free(ssh_connection); rc->read = in; rc->write = out; rc->accept_fn = fn; rc->driver = driver; rc->conf_fn = conf_fn; rc->datap = datap; sec_tcp_conn_read(rc); return; error: if (ssh_connection) g_free(ssh_connection); /* make up a fake handle for the error */ rh = g_new0(struct sec_handle, 1); security_handleinit(&rh->sech, driver); security_seterror((security_handle_t*)rh, "ssh_accept: %s", errmsg); amfree(errmsg); (*fn)(&rh->sech, NULL); }
/* * Setup to handle new incoming connections */ static void ssl_accept( const struct security_driver *driver, char * (*conf_fn)(char *, void *), int in, int out, void (*fn)(security_handle_t *, pkt_t *), void *datap) { sockaddr_union sin; socklen_t_equiv len = sizeof(struct sockaddr); struct tcp_conn *rc; char hostname[NI_MAXHOST]; int result; char *errmsg = NULL; int err; X509 *remote_cert; char *str; X509_NAME *x509_name; char *cert_hostname; SSL_CTX *ctx; SSL *ssl; int loc; char *ssl_dir = getconf_str(CNF_SSL_DIR); char *ssl_fingerprint_file = conf_fn("ssl_fingerprint_file", datap); char *ssl_cert_file = conf_fn("ssl_cert_file", datap); char *ssl_key_file = conf_fn("ssl_key_file", datap); char *ssl_ca_cert_file = conf_fn("ssl_ca_cert_file", datap); char *ssl_cipher_list = conf_fn("ssl_cipher_list", datap); int ssl_check_host = atoi(conf_fn("ssl_check_host", datap)); int ssl_check_certificate_host = atoi(conf_fn("ssl_check_certificate_host", datap)); if (getpeername(in, (struct sockaddr *)&sin, &len) < 0) { g_debug(_("getpeername returned: %s"), strerror(errno)); return; } if ((result = getnameinfo((struct sockaddr *)&sin, len, hostname, NI_MAXHOST, NULL, 0, 0) != 0)) { g_debug(_("getnameinfo failed: %s"), gai_strerror(result)); return; } if (ssl_check_host && check_name_give_sockaddr(hostname, (struct sockaddr *)&sin, &errmsg) < 0) { amfree(errmsg); return; } 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_cert_file) { g_debug(_("ssl-cert-file must be set in amanda-remote.conf")); return; } if (!ssl_key_file) { g_debug(_("ssl-key-file must be set in amanda-remote.conf")); return; } if (!ssl_ca_cert_file) { g_debug(_("ssl_ca_cert_file must be set in amanda-remote.conf")); return; } len = sizeof(sin); init_ssl(); /* Create a SSL_CTX structure */ ctx = SSL_CTX_new(SSLv3_server_method()); if (!ctx) { g_debug(_("SSL_CTX_new failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); if (ssl_cipher_list) { g_debug("Set ssl_cipher_list to %s", ssl_cipher_list); if (SSL_CTX_set_cipher_list(ctx, ssl_cipher_list) == 0) { g_debug(_("SSL_CTX_set_cipher_list failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } } /* Load the me certificate into the SSL_CTX structure */ g_debug(_("Loading ssl-cert-file certificate %s"), ssl_cert_file); if (SSL_CTX_use_certificate_file(ctx, ssl_cert_file, SSL_FILETYPE_PEM) <= 0) { g_debug(_("Load ssl-cert-file failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } /* Load the private-key corresponding to the me certificate */ g_debug(_("Loading ssl-key-file private-key %s"), ssl_key_file); if (SSL_CTX_use_PrivateKey_file(ctx, ssl_key_file, SSL_FILETYPE_PEM) <= 0) { g_debug(_("Load ssl-key-file failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } if (ssl_ca_cert_file) { /* Load the RSA CA certificate into the SSL_CTX structure */ g_debug(_("Loading ssl-ca-cert-file ca certificate %s"), ssl_ca_cert_file); if (!SSL_CTX_load_verify_locations(ctx, ssl_ca_cert_file, NULL)) { g_debug(_("Load ssl-ca-cert-file failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } /* Set to require peer (remote) certificate verification */ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); /* Set the verification depth to 1 */ SSL_CTX_set_verify_depth(ctx,1); } ssl = SSL_new(ctx); if (!ssl) { g_debug(_("SSL_new failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } SSL_set_accept_state(ssl); /* Assign the socket into the SSL structure (SSL and socket without BIO) */ SSL_set_fd(ssl, in); /* Perform SSL Handshake on the SSL me */ err = SSL_accept(ssl); if (err == -1) { g_debug(_("SSL_accept failed: %s"), ERR_error_string(ERR_get_error(), NULL)); return; } /* Get the me's certificate (optional) */ remote_cert = SSL_get_peer_certificate (ssl); if (remote_cert == NULL) { g_debug(_("remote doesn't sent a certificate")); return; } x509_name = X509_get_subject_name(remote_cert); str = X509_NAME_oneline(X509_get_subject_name(remote_cert), 0, 0); auth_debug(1, _("\t subject: %s\n"), str); amfree (str); str = X509_NAME_oneline(X509_get_issuer_name(remote_cert), 0, 0); auth_debug(1, _("\t issuer: %s\n"), str); amfree(str); loc = -1; loc = X509_NAME_get_index_by_NID(x509_name, NID_commonName, loc); if (loc != -1) { X509_NAME_ENTRY *x509_entry = X509_NAME_get_entry(x509_name, loc); ASN1_STRING *asn1_string = X509_NAME_ENTRY_get_data(x509_entry); cert_hostname = (char *)ASN1_STRING_data(asn1_string); auth_debug(1, "common_name: %s\n", cert_hostname); if (ssl_check_certificate_host && check_name_give_sockaddr((char*)cert_hostname, (struct sockaddr *)&sin, &errmsg) < 0) { g_debug("Common name of certicate (%s) doesn't resolv to IP (%s)", cert_hostname, str_sockaddr(&sin)); amfree(errmsg); X509_free(remote_cert); return; } } else { g_debug("Certificate have no common name"); X509_free(remote_cert); return; } if (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, cert_hostname); if (stat(ssl_fingerprint_file, &statbuf) == -1) { g_free(ssl_fingerprint_file); ssl_fingerprint_file = NULL; } } } if (ssl_fingerprint_file) { g_debug(_("Loading ssl-fingerprint-file %s"), ssl_fingerprint_file); str = validate_fingerprints(remote_cert, ssl_fingerprint_file); if (str) { g_debug("%s", str); amfree(str); X509_free(remote_cert); return; } } X509_free(remote_cert); rc = sec_tcp_conn_get(hostname, 0); rc->recv_security_ok = &bsd_recv_security_ok; rc->prefix_packet = &bsd_prefix_packet; rc->need_priv_port = 0; copy_sockaddr(&rc->peer, &sin); rc->read = in; rc->write = out; rc->accept_fn = fn; rc->driver = driver; rc->conf_fn = conf_fn; rc->datap = datap; rc->ctx = ctx; rc->ssl = ssl; strncpy(rc->hostname, cert_hostname, sizeof(rc->hostname)-1); g_debug(_("SSL_cipher: %s"), SSL_get_cipher(rc->ssl)); sec_tcp_conn_read(rc); }