| // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include <openssl/bio.h> |
| |
| #if !defined(OPENSSL_NO_SOCK) |
| |
| #include <fcntl.h> |
| #include <string.h> |
| |
| #if !defined(OPENSSL_WINDOWS) |
| #include <unistd.h> |
| #else |
| #include <winsock2.h> |
| OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib")) |
| #endif |
| |
| #include "internal.h" |
| |
| |
| #if !defined(OPENSSL_WINDOWS) |
| static int closesocket(int sock) { |
| return close(sock); |
| } |
| #endif |
| |
| static int sock_free(BIO *bio) { |
| if (bio->shutdown) { |
| if (bio->init) { |
| closesocket(bio->num); |
| } |
| bio->init = 0; |
| bio->flags = 0; |
| } |
| return 1; |
| } |
| |
| static int sock_read(BIO *b, char *out, int outl) { |
| if (out == NULL) { |
| return 0; |
| } |
| |
| bio_clear_socket_error(); |
| #if defined(OPENSSL_WINDOWS) |
| int ret = recv(b->num, out, outl, 0); |
| #else |
| int ret = (int)read(b->num, out, outl); |
| #endif |
| BIO_clear_retry_flags(b); |
| if (ret <= 0) { |
| if (bio_socket_should_retry(ret)) { |
| BIO_set_retry_read(b); |
| } |
| } |
| return ret; |
| } |
| |
| static int sock_write(BIO *b, const char *in, int inl) { |
| bio_clear_socket_error(); |
| #if defined(OPENSSL_WINDOWS) |
| int ret = send(b->num, in, inl, 0); |
| #else |
| int ret = (int)write(b->num, in, inl); |
| #endif |
| BIO_clear_retry_flags(b); |
| if (ret <= 0) { |
| if (bio_socket_should_retry(ret)) { |
| BIO_set_retry_write(b); |
| } |
| } |
| return ret; |
| } |
| |
| static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) { |
| switch (cmd) { |
| case BIO_C_SET_FD: |
| sock_free(b); |
| b->num = *static_cast<int *>(ptr); |
| b->shutdown = static_cast<int>(num); |
| b->init = 1; |
| return 1; |
| case BIO_C_GET_FD: |
| if (b->init) { |
| int *out = static_cast<int*>(ptr); |
| if (out != nullptr) { |
| *out = b->num; |
| } |
| return b->num; |
| } |
| return -1; |
| case BIO_CTRL_GET_CLOSE: |
| return b->shutdown; |
| case BIO_CTRL_SET_CLOSE: |
| b->shutdown = static_cast<int>(num); |
| return 1; |
| case BIO_CTRL_FLUSH: |
| return 1; |
| default: |
| return 0; |
| } |
| } |
| |
| static const BIO_METHOD methods_sockp = { |
| BIO_TYPE_SOCKET, "socket", |
| sock_write, sock_read, |
| NULL /* puts */, NULL /* gets, */, |
| sock_ctrl, NULL /* create */, |
| sock_free, NULL /* callback_ctrl */, |
| }; |
| |
| const BIO_METHOD *BIO_s_socket(void) { return &methods_sockp; } |
| |
| BIO *BIO_new_socket(int fd, int close_flag) { |
| BIO *ret; |
| |
| ret = BIO_new(BIO_s_socket()); |
| if (ret == NULL) { |
| return NULL; |
| } |
| BIO_set_fd(ret, fd, close_flag); |
| return ret; |
| } |
| |
| // These functions are provided solely for compatibility with older versions of |
| // PostgreSQL. See bio.h for details. PostgreSQL's use makes several fragile |
| // assumptions on |BIO_s_socket|: |
| // |
| // - We do not store anything in |BIO_set_data|. (Broken in upstream OpenSSL, |
| // which broke PostgreSQL.) |
| // - We do not store anything in |BIO_set_app_data|. |
| // - |BIO_METHOD| never gains another function pointer that is used in concert |
| // with any of the functions here. |
| // |
| // Some other projects doing similar things use |BIO_meth_get_read| and |
| // |BIO_meth_get_write| and in turn assume that |BIO_s_socket| has not been |
| // ported to the |size_t|-clean |BIO_read_ex| and |BIO_write_ex|. (Not yet |
| // implemented in BoringSSL.) |
| // |
| // This is hopelessly fragile. PostgreSQL 18 will include a fix to stop using |
| // these APIs, but older versions remain impact, so we implement these |
| // functions, but only support |BIO_s_socket|. For now they just return the |
| // underlying functions, but if we ever need to break the above assumptions, we |
| // can return an older, frozen version of |BIO_s_socket|. Limiting to exactly |
| // one allowed |BIO_METHOD| lets us do this. |
| // |
| // These functions are also deprecated in upstream OpenSSL. See |
| // https://github.com/openssl/openssl/issues/26047 |
| // |
| // TODO(davidben): Once all versions of PostgreSQL we care about are updated or |
| // patched, remove these functions. |
| |
| int (*BIO_meth_get_gets(const BIO_METHOD *method))(BIO *, char *, int) { |
| BSSL_CHECK(method == BIO_s_socket()); |
| return method->bgets; |
| } |
| |
| int (*BIO_meth_get_puts(const BIO_METHOD *method))(BIO *, const char *) { |
| BSSL_CHECK(method == BIO_s_socket()); |
| return method->bputs; |
| } |
| |
| long (*BIO_meth_get_ctrl(const BIO_METHOD *method))(BIO *, int, long, void *) { |
| BSSL_CHECK(method == BIO_s_socket()); |
| return method->ctrl; |
| } |
| |
| int (*BIO_meth_get_create(const BIO_METHOD *method))(BIO *) { |
| BSSL_CHECK(method == BIO_s_socket()); |
| return method->create; |
| } |
| |
| int (*BIO_meth_get_destroy(const BIO_METHOD *method))(BIO *) { |
| BSSL_CHECK(method == BIO_s_socket()); |
| return method->destroy; |
| } |
| |
| long (*BIO_meth_get_callback_ctrl(const BIO_METHOD *method))(BIO *, int, |
| bio_info_cb) { |
| BSSL_CHECK(method == BIO_s_socket()); |
| return method->callback_ctrl; |
| } |
| |
| #endif // OPENSSL_NO_SOCK |