From: Marko Kreen Date: Tue, 15 Sep 2015 21:14:21 +0000 (+0300) Subject: Sync with TLS API changes X-Git-Tag: pgbouncer_1_7_rc1~6 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ee592154e7c68ca53f1aa9785861bf322253085b;p=pgbouncer Sync with TLS API changes --- diff --git a/lib b/lib index fdbab1c..16249b5 160000 --- a/lib +++ b/lib @@ -1 +1 @@ -Subproject commit fdbab1ce299803bdf59368626848df27e392d330 +Subproject commit 16249b5e76ceb04b46ed596e13001d9fee483e2f diff --git a/src/client.c b/src/client.c index 2b01ff2..5951d39 100644 --- a/src/client.c +++ b/src/client.c @@ -118,41 +118,24 @@ static void start_auth_request(PgSocket *client, const char *username) static bool login_via_cert(PgSocket *client) { struct tls *tls = client->sbuf.tls; - struct tls_cert *cert; - struct tls_cert_dname *subj; if (!tls) { disconnect_client(client, true, "TLS connection required"); return false; } - if (tls_get_peer_cert(client->sbuf.tls, &cert, NULL) < 0 || !cert) { + if (!tls_peer_cert_provided(client->sbuf.tls)) { disconnect_client(client, true, "TLS client certificate required"); return false; } - subj = &cert->subject; - log_debug("TLS cert login: CN=%s/C=%s/L=%s/ST=%s/O=%s/OU=%s", - subj->common_name ? subj->common_name : "(null)", - subj->country_name ? subj->country_name : "(null)", - subj->locality_name ? subj->locality_name : "(null)", - subj->state_or_province_name ? subj->state_or_province_name : "(null)", - subj->organization_name ? subj->organization_name : "(null)", - subj->organizational_unit_name ? subj->organizational_unit_name : "(null)"); - if (!subj->common_name) { - disconnect_client(client, true, "Invalid TLS certificate"); - goto fail; - } - if (strcmp(subj->common_name, client->auth_user->name) != 0) { + log_debug("TLS cert login: %s", tls_peer_cert_subject(client->sbuf.tls)); + if (!tls_peer_cert_contains_name(client->sbuf.tls, client->auth_user->name)) { disconnect_client(client, true, "TLS certificate name mismatch"); - goto fail; + return false; } - tls_cert_free(cert); /* login successful */ return finish_client_login(client); -fail: - tls_cert_free(cert); - return false; } static bool login_as_unix_peer(PgSocket *client) diff --git a/src/sbuf.c b/src/sbuf.c index 6b93bc2..ab69fbf 100644 --- a/src/sbuf.c +++ b/src/sbuf.c @@ -92,8 +92,7 @@ static const SBufIO tls_sbufio_ops = { tls_sbufio_send, tls_sbufio_close }; -static void sbuf_tls_accept_cb(int fd, short flags, void *_sbuf); -static void sbuf_tls_connect_cb(int fd, short flags, void *_sbuf); +static void sbuf_tls_handshake_cb(int fd, short flags, void *_sbuf); #endif /********************************* @@ -863,13 +862,24 @@ static void setup_tls(struct tls_config *conf, const char *pfx, int sslmode, log_error("Invalid %s_cert_file: %s", pfx, certfile); } - if (sslmode == SSLMODE_VERIFY_FULL) { - tls_config_verify(conf); - } else if (sslmode == SSLMODE_VERIFY_CA) { - tls_config_insecure_noverifyname(conf); + if (does_connect) { + /* TLS client, check server? */ + if (sslmode == SSLMODE_VERIFY_FULL) { + tls_config_verify(conf); + } else if (sslmode == SSLMODE_VERIFY_CA) { + tls_config_verify(conf); + tls_config_insecure_noverifyname(conf); + } else { + tls_config_insecure_noverifycert(conf); + tls_config_insecure_noverifyname(conf); + } } else { - tls_config_insecure_noverifycert(conf); - tls_config_insecure_noverifyname(conf); + /* TLS server, check client? */ + if (sslmode == SSLMODE_VERIFY_FULL) { + tls_config_verify_client_optional(conf); + } else if (sslmode == SSLMODE_VERIFY_CA) { + tls_config_verify_client_optional(conf); + } } } @@ -924,73 +934,60 @@ void sbuf_tls_setup(void) } /* - * Accept TLS connection. + * TLS handshake */ -static bool handle_tls_accept(struct SBuf *sbuf) +static bool handle_tls_handshake(SBuf *sbuf) { int err; - err = tls_accept_fds(client_accept_base, &sbuf->tls, sbuf->sock, sbuf->sock); - log_noise("tls_accept_fds: err=%d", err); - if (err == TLS_READ_AGAIN) { - return sbuf_use_callback_once(sbuf, EV_READ, sbuf_tls_accept_cb); - } else if (err == TLS_WRITE_AGAIN) { - return sbuf_use_callback_once(sbuf, EV_WRITE, sbuf_tls_accept_cb); + err = tls_handshake(sbuf->tls); + log_noise("tls_handshake: err=%d", err); + if (err == TLS_WANT_POLLIN) { + return sbuf_use_callback_once(sbuf, EV_READ, sbuf_tls_handshake_cb); + } else if (err == TLS_WANT_POLLOUT) { + return sbuf_use_callback_once(sbuf, EV_WRITE, sbuf_tls_handshake_cb); } else if (err == 0) { sbuf_call_proto(sbuf, SBUF_EV_TLS_READY); return true; } else { - log_warning("TLS accept error: %s", tls_error(sbuf->tls)); + log_warning("TLS handshake error: %s", tls_error(sbuf->tls)); return false; } } -static void sbuf_tls_accept_cb(int fd, short flags, void *_sbuf) +static void sbuf_tls_handshake_cb(int fd, short flags, void *_sbuf) { SBuf *sbuf = _sbuf; sbuf->wait_type = W_NONE; - if (!handle_tls_accept(sbuf)) + if (!handle_tls_handshake(sbuf)) sbuf_call_proto(sbuf, SBUF_EV_RECV_FAILED); } -bool sbuf_tls_accept(SBuf *sbuf) -{ - sbuf->ops = &tls_sbufio_ops; - return handle_tls_accept(sbuf); -} - /* - * Connect to remote TLS host. + * Accept TLS connection. */ -static bool handle_tls_connect(SBuf *sbuf) +bool sbuf_tls_accept(SBuf *sbuf) { int err; - err = tls_connect_fds(sbuf->tls, sbuf->sock, sbuf->sock, sbuf->tls_host); - log_noise("tls_connect_fds: err=%d", err); - if (err == TLS_READ_AGAIN) { - return sbuf_use_callback_once(sbuf, EV_READ, sbuf_tls_connect_cb); - } else if (err == TLS_WRITE_AGAIN) { - return sbuf_use_callback_once(sbuf, EV_WRITE, sbuf_tls_connect_cb); - } else if (err == 0) { - sbuf_call_proto(sbuf, SBUF_EV_TLS_READY); - return true; - } else { - log_warning("TLS connect error: %s", tls_error(sbuf->tls)); + sbuf->ops = &tls_sbufio_ops; + + err = tls_accept_fds(client_accept_base, &sbuf->tls, sbuf->sock, sbuf->sock); + log_noise("tls_accept_fds: err=%d", err); + if (err < 0) { + log_warning("TLS accept error: %s", tls_error(sbuf->tls)); return false; } -} -static void sbuf_tls_connect_cb(int fd, short flags, void *_sbuf) -{ - SBuf *sbuf = _sbuf; - sbuf->wait_type = W_NONE; - if (!handle_tls_connect(sbuf)) - sbuf_call_proto(sbuf, SBUF_EV_RECV_FAILED); + return handle_tls_handshake(sbuf); } +/* + * Connect to remote TLS host. + */ + bool sbuf_tls_connect(SBuf *sbuf, const char *hostname) { struct tls *ctls; @@ -1003,7 +1000,7 @@ bool sbuf_tls_connect(SBuf *sbuf, const char *hostname) if (!ctls) return false; err = tls_configure(ctls, server_connect_conf); - if (err) { + if (err < 0) { log_error("tls client config failed: %s", tls_error(ctls)); tls_free(ctls); return false; @@ -1013,7 +1010,13 @@ bool sbuf_tls_connect(SBuf *sbuf, const char *hostname) sbuf->tls_host = hostname; sbuf->ops = &tls_sbufio_ops; - return handle_tls_connect(sbuf); + err = tls_connect_fds(sbuf->tls, sbuf->sock, sbuf->sock, sbuf->tls_host); + if (err < 0) { + log_warning("TLS connect error: %s", tls_error(sbuf->tls)); + return false; + } + + return handle_tls_handshake(sbuf); } /* @@ -1022,17 +1025,16 @@ bool sbuf_tls_connect(SBuf *sbuf, const char *hostname) static int tls_sbufio_recv(struct SBuf *sbuf, void *dst, unsigned int len) { - int err; - size_t out = 0; + ssize_t out = 0; - err = tls_read(sbuf->tls, dst, len, &out); - log_noise("tls_read: req=%u err=%d out=%d", len, err, (int)out); - if (!err) { + out = tls_read(sbuf->tls, dst, len); + log_noise("tls_read: req=%u out=%d", len, (int)out); + if (out >= 0) { return out; - } else if (err == TLS_READ_AGAIN) { + } else if (out == TLS_WANT_POLLIN) { errno = EAGAIN; - } else if (err == TLS_WRITE_AGAIN) { - log_warning("tls_sbufio_recv: got TLS_WRITE_AGAIN"); + } else if (out == TLS_WANT_POLLOUT) { + log_warning("tls_sbufio_recv: got TLS_WANT_POLLOUT"); errno = EIO; } else { log_warning("tls_sbufio_recv: %s", tls_error(sbuf->tls)); @@ -1043,17 +1045,16 @@ static int tls_sbufio_recv(struct SBuf *sbuf, void *dst, unsigned int len) static int tls_sbufio_send(struct SBuf *sbuf, const void *data, unsigned int len) { - size_t out = 0; - int err; + ssize_t out; - err = tls_write(sbuf->tls, data, len, &out); - log_noise("tls_write: req=%u err=%d out=%d", len, err, (int)out); - if (!err) { + out = tls_write(sbuf->tls, data, len); + log_noise("tls_write: req=%u out=%d", len, (int)out); + if (out >= 0) { return out; - } else if (err == TLS_WRITE_AGAIN) { + } else if (out == TLS_WANT_POLLOUT) { errno = EAGAIN; - } else if (err == TLS_READ_AGAIN) { - log_warning("tls_sbufio_send: got TLS_READ_AGAIN"); + } else if (out == TLS_WANT_POLLIN) { + log_warning("tls_sbufio_send: got TLS_WANT_POLLIN"); errno = EIO; } else { log_warning("tls_sbufio_send: %s", tls_error(sbuf->tls));