/* Format response and send it to peer, via UDP/TCP/TLS, reporting any errors. */ static void kdc_send (struct listenspec *ls) { if (ls->type == SOCK_DGRAM) syslog (LOG_DEBUG, "Sending %d bytes to %s socket %d via UDP", ls->bufpos, ls->str, ls->sockfd); else { syslog (LOG_DEBUG, "Sending %d bytes to %s socket %d via %s", ls->bufpos, ls->str, ls->sockfd, ls->usetls ? "TLS" : "TCP"); if (ls->bufpos + 4 >= sizeof (ls->buf)) ls->bufpos = sizeof (ls->buf) - 4; memmove (ls->buf + 4, ls->buf, ls->bufpos); ls->buf[0] = (ls->bufpos >> 24) & 0xFF; ls->buf[1] = (ls->bufpos >> 16) & 0xFF; ls->buf[2] = (ls->bufpos >> 8) & 0xFF; ls->buf[3] = ls->bufpos & 0xFF; ls->bufpos += 4; } kdc_send1 (ls); ls->bufpos = 0; }
/* Handle the high TCP length bit, currently only used for STARTTLS. */ int kdc_extension (struct listenspec *ls) { int rc; if (ls->usetls || ls->ai.ai_socktype != SOCK_STREAM || ls->bufpos < 4 || (ls->bufpos >= 4 && !(ls->buf[0] & 0x80))) return 0; if (x509cred == NULL || memcmp (ls->buf, STARTTLS_CLIENT_REQUEST, STARTTLS_LEN) != 0) return kdc_extension_reject (ls); /* This message can arguably belong to LOG_AUTH, * but leave it at the default facility. */ syslog (LOG_INFO, "Trying STARTTLS"); memcpy (ls->buf, STARTTLS_SERVER_ACCEPT, STARTTLS_LEN); ls->bufpos = STARTTLS_LEN; kdc_send1 (ls); rc = gnutls_init (&ls->session, GNUTLS_SERVER); if (rc != GNUTLS_E_SUCCESS) { syslog (LOG_ERR | LOG_DAEMON, "TLS initialization failed (%d): %s", rc, gnutls_strerror (rc)); return -1; } rc = gnutls_priority_set_direct (ls->session, "NORMAL:+ANON-DH", NULL); if (rc != GNUTLS_E_SUCCESS) { syslog (LOG_ERR | LOG_DAEMON, "TLS failed, gnutls_psd %d: %s", rc, gnutls_strerror (rc)); return -1; } rc = gnutls_credentials_set (ls->session, GNUTLS_CRD_ANON, anoncred); if (rc != GNUTLS_E_SUCCESS) { syslog (LOG_ERR | LOG_DAEMON, "TLS failed, gnutls_cs %d: %s", rc, gnutls_strerror (rc)); return -1; } rc = gnutls_credentials_set (ls->session, GNUTLS_CRD_CERTIFICATE, x509cred); if (rc != GNUTLS_E_SUCCESS) { syslog (LOG_ERR | LOG_DAEMON, "TLS failed, gnutls_cs X.509 %d: %s", rc, gnutls_strerror (rc)); return -1; } gnutls_certificate_server_set_request (ls->session, GNUTLS_CERT_REQUEST); gnutls_dh_set_prime_bits (ls->session, DH_BITS); gnutls_transport_set_ptr (ls->session, (gnutls_transport_ptr_t) (unsigned long) ls->sockfd); gnutls_db_set_retrieve_function (ls->session, resume_db_fetch); gnutls_db_set_store_function (ls->session, resume_db_store); gnutls_db_set_remove_function (ls->session, resume_db_delete); rc = gnutls_handshake (ls->session); if (rc < 0) { syslog (LOG_ERR | LOG_DAEMON, "TLS handshake failed (%d): %s\n", rc, gnutls_strerror (rc)); return -1; } logtlsinfo (ls->session); ls->bufpos = 0; ls->usetls = 1; return 0; }