* https://www.openssl.org/source/license.html
*/
+#define OPENSSL_SUPPRESS_DEPRECATED
+
#include <stdio.h>
#include <errno.h>
#include <openssl/crypto.h>
+#include "internal/numbers.h"
#include "bio_local.h"
-#include "internal/cryptlib.h"
/*
* Helper macro for the callback to determine whether an operator expects a
#define HAS_LEN_OPER(o) ((o) == BIO_CB_READ || (o) == BIO_CB_WRITE \
|| (o) == BIO_CB_GETS)
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+# define HAS_CALLBACK(b) ((b)->callback != NULL || (b)->callback_ex != NULL)
+#else
+# define HAS_CALLBACK(b) ((b)->callback_ex != NULL)
+#endif
/*
* Helper function to work out whether to call the new style callback or the old
* one, and translate between the two.
int argi, long argl, long inret,
size_t *processed)
{
- long ret;
+ long ret = inret;
+#ifndef OPENSSL_NO_DEPRECATED_3_0
int bareoper;
if (b->callback_ex != NULL)
+#endif
return b->callback_ex(b, oper, argp, len, argi, argl, inret, processed);
+#ifndef OPENSSL_NO_DEPRECATED_3_0
/* Strip off any BIO_CB_RETURN flag */
bareoper = oper & ~BIO_CB_RETURN;
*processed = (size_t)ret;
ret = 1;
}
-
+#endif
return ret;
}
{
BIO *bio = OPENSSL_zalloc(sizeof(*bio));
- if (bio == NULL) {
- ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
+ if (bio == NULL)
return NULL;
- }
bio->libctx = libctx;
bio->method = method;
bio->lock = CRYPTO_THREAD_lock_new();
if (bio->lock == NULL) {
- ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_BIO, ERR_R_CRYPTO_LIB);
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data);
goto err;
}
return 1;
REF_ASSERT_ISNT(ret < 0);
- if (a->callback != NULL || a->callback_ex != NULL) {
+ if (HAS_CALLBACK(a)) {
ret = (int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL);
if (ret <= 0)
- return ret;
+ return 0;
}
if ((a->method != NULL) && (a->method->destroy != NULL))
b->flags |= flags;
}
+#ifndef OPENSSL_NO_DEPRECATED_3_0
BIO_callback_fn BIO_get_callback(const BIO *b)
{
return b->callback;
{
b->callback = cb;
}
+#endif
BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b)
{
return -2;
}
- if ((b->callback != NULL || b->callback_ex != NULL) &&
+ if (HAS_CALLBACK(b) &&
((ret = (int)bio_call_callback(b, BIO_CB_READ, data, dlen, 0, 0L, 1L,
NULL)) <= 0))
return ret;
if (ret > 0)
b->num_read += (uint64_t)*readbytes;
- if (b->callback != NULL || b->callback_ex != NULL)
+ if (HAS_CALLBACK(b))
ret = (int)bio_call_callback(b, BIO_CB_READ | BIO_CB_RETURN, data,
dlen, 0, 0L, ret, readbytes);
static int bio_write_intern(BIO *b, const void *data, size_t dlen,
size_t *written)
{
+ size_t local_written;
int ret;
- if (b == NULL) {
- ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
- return -1;
- }
+ if (written != NULL)
+ *written = 0;
+ /*
+ * b == NULL is not an error but just means that zero bytes are written.
+ * Do not raise an error here.
+ */
+ if (b == NULL)
+ return 0;
+
if (b->method == NULL || b->method->bwrite == NULL) {
ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD);
return -2;
}
- if ((b->callback != NULL || b->callback_ex != NULL) &&
+ if (HAS_CALLBACK(b) &&
((ret = (int)bio_call_callback(b, BIO_CB_WRITE, data, dlen, 0, 0L, 1L,
NULL)) <= 0))
return ret;
return -1;
}
- ret = b->method->bwrite(b, data, dlen, written);
+ ret = b->method->bwrite(b, data, dlen, &local_written);
if (ret > 0)
- b->num_write += (uint64_t)*written;
+ b->num_write += (uint64_t)local_written;
- if (b->callback != NULL || b->callback_ex != NULL)
+ if (HAS_CALLBACK(b))
ret = (int)bio_call_callback(b, BIO_CB_WRITE | BIO_CB_RETURN, data,
- dlen, 0, 0L, ret, written);
+ dlen, 0, 0L, ret, &local_written);
+ if (written != NULL)
+ *written = local_written;
return ret;
}
size_t written;
int ret;
- if (dlen < 0)
+ if (dlen <= 0)
return 0;
ret = bio_write_intern(b, data, (size_t)dlen, &written);
if (ret > 0) {
- /* *written should always be <= dlen */
+ /* written should always be <= dlen */
ret = (int)written;
}
int BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written)
{
- return bio_write_intern(b, data, dlen, written) > 0;
+ return bio_write_intern(b, data, dlen, written) > 0
+ || (b != NULL && dlen == 0); /* order is important for *written */
+}
+
+int BIO_sendmmsg(BIO *b, BIO_MSG *msg,
+ size_t stride, size_t num_msg, uint64_t flags,
+ size_t *msgs_processed)
+{
+ size_t ret;
+ BIO_MMSG_CB_ARGS args;
+
+ if (b == NULL) {
+ *msgs_processed = 0;
+ ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ if (b->method == NULL || b->method->bsendmmsg == NULL) {
+ *msgs_processed = 0;
+ ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD);
+ return 0;
+ }
+
+ if (HAS_CALLBACK(b)) {
+ args.msg = msg;
+ args.stride = stride;
+ args.num_msg = num_msg;
+ args.flags = flags;
+ args.msgs_processed = msgs_processed;
+
+ ret = (size_t)bio_call_callback(b, BIO_CB_SENDMMSG, (void *)&args,
+ 0, 0, 0, 0, NULL);
+ if (ret == 0)
+ return 0;
+ }
+
+ if (!b->init) {
+ *msgs_processed = 0;
+ ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
+ return 0;
+ }
+
+ ret = b->method->bsendmmsg(b, msg, stride, num_msg, flags, msgs_processed);
+
+ if (HAS_CALLBACK(b))
+ ret = (size_t)bio_call_callback(b, BIO_CB_SENDMMSG | BIO_CB_RETURN,
+ (void *)&args, ret, 0, 0, 0, NULL);
+
+ return ret;
+}
+
+int BIO_recvmmsg(BIO *b, BIO_MSG *msg,
+ size_t stride, size_t num_msg, uint64_t flags,
+ size_t *msgs_processed)
+{
+ size_t ret;
+ BIO_MMSG_CB_ARGS args;
+
+ if (b == NULL) {
+ *msgs_processed = 0;
+ ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ if (b->method == NULL || b->method->brecvmmsg == NULL) {
+ *msgs_processed = 0;
+ ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD);
+ return 0;
+ }
+
+ if (HAS_CALLBACK(b)) {
+ args.msg = msg;
+ args.stride = stride;
+ args.num_msg = num_msg;
+ args.flags = flags;
+ args.msgs_processed = msgs_processed;
+
+ ret = bio_call_callback(b, BIO_CB_RECVMMSG, (void *)&args,
+ 0, 0, 0, 0, NULL);
+ if (ret == 0)
+ return 0;
+ }
+
+ if (!b->init) {
+ *msgs_processed = 0;
+ ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
+ return 0;
+ }
+
+ ret = b->method->brecvmmsg(b, msg, stride, num_msg, flags, msgs_processed);
+
+ if (HAS_CALLBACK(b))
+ ret = (size_t)bio_call_callback(b, BIO_CB_RECVMMSG | BIO_CB_RETURN,
+ (void *)&args, ret, 0, 0, 0, NULL);
+
+ return ret;
}
int BIO_puts(BIO *b, const char *buf)
return -2;
}
- if (b->callback != NULL || b->callback_ex != NULL) {
+ if (HAS_CALLBACK(b)) {
ret = (int)bio_call_callback(b, BIO_CB_PUTS, buf, 0, 0, 0L, 1L, NULL);
if (ret <= 0)
return ret;
ret = 1;
}
- if (b->callback != NULL || b->callback_ex != NULL)
+ if (HAS_CALLBACK(b))
ret = (int)bio_call_callback(b, BIO_CB_PUTS | BIO_CB_RETURN, buf, 0, 0,
0L, ret, &written);
return -1;
}
- if (b->callback != NULL || b->callback_ex != NULL) {
+ if (HAS_CALLBACK(b)) {
ret = (int)bio_call_callback(b, BIO_CB_GETS, buf, size, 0, 0L, 1, NULL);
if (ret <= 0)
return ret;
ret = 1;
}
- if (b->callback != NULL || b->callback_ex != NULL)
+ if (HAS_CALLBACK(b))
ret = (int)bio_call_callback(b, BIO_CB_GETS | BIO_CB_RETURN, buf, size,
0, 0L, ret, &readbytes);
return ret;
}
+int BIO_get_line(BIO *bio, char *buf, int size)
+{
+ int ret = 0;
+ char *ptr = buf;
+
+ if (buf == NULL) {
+ ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
+ return -1;
+ }
+ if (size <= 0) {
+ ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT);
+ return -1;
+ }
+ *buf = '\0';
+
+ if (bio == NULL) {
+ ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
+ return -1;
+ }
+ if (!bio->init) {
+ ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED);
+ return -1;
+ }
+
+ while (size-- > 1 && (ret = BIO_read(bio, ptr, 1)) > 0)
+ if (*ptr++ == '\n')
+ break;
+ *ptr = '\0';
+ return ret > 0 || BIO_eof(bio) ? ptr - buf : ret;
+}
+
int BIO_indent(BIO *b, int indent, int max)
{
if (indent < 0)
{
long ret;
- if (b == NULL) {
- ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
+ if (b == NULL)
return -1;
- }
if (b->method == NULL || b->method->ctrl == NULL) {
ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD);
return -2;
}
- if (b->callback != NULL || b->callback_ex != NULL) {
+ if (HAS_CALLBACK(b)) {
ret = bio_call_callback(b, BIO_CB_CTRL, parg, 0, cmd, larg, 1L, NULL);
if (ret <= 0)
return ret;
ret = b->method->ctrl(b, cmd, larg, parg);
- if (b->callback != NULL || b->callback_ex != NULL)
+ if (HAS_CALLBACK(b))
ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, parg, 0, cmd,
larg, ret, NULL);
{
long ret;
- if (b == NULL) {
- ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
+ if (b == NULL)
return -2;
- }
if (b->method == NULL || b->method->callback_ctrl == NULL
|| cmd != BIO_CTRL_SET_CALLBACK) {
ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD);
return -2;
}
- if (b->callback != NULL || b->callback_ex != NULL) {
+ if (HAS_CALLBACK(b)) {
ret = bio_call_callback(b, BIO_CB_CTRL, (void *)&fp, 0, cmd, 0, 1L,
NULL);
if (ret <= 0)
ret = b->method->callback_ctrl(b, cmd, fp);
- if (b->callback != NULL || b->callback_ex != NULL)
+ if (HAS_CALLBACK(b))
ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, 0,
cmd, 0, ret, NULL);
*/
size_t BIO_ctrl_pending(BIO *bio)
{
- return BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL);
+ long ret = BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL);
+
+ if (ret < 0)
+ ret = 0;
+#if LONG_MAX > SIZE_MAX
+ if (ret > SIZE_MAX)
+ ret = SIZE_MAX;
+#endif
+ return (size_t)ret;
}
size_t BIO_ctrl_wpending(BIO *bio)
{
- return BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL);
+ long ret = BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL);
+
+ if (ret < 0)
+ ret = 0;
+#if LONG_MAX > SIZE_MAX
+ if (ret > SIZE_MAX)
+ ret = SIZE_MAX;
+#endif
+ return (size_t)ret;
}
/* put the 'bio' on the end of b's list of operators */
{
BIO *ret;
- if (b == NULL) {
- ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
+ if (b == NULL)
return NULL;
- }
ret = b->next_bio;
BIO_ctrl(b, BIO_CTRL_POP, 0, b);
BIO *BIO_next(BIO *b)
{
- if (b == NULL) {
- ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER);
+ if (b == NULL)
return NULL;
- }
return b->next_bio;
}
for (bio = in; bio != NULL; bio = bio->next_bio) {
if ((new_bio = BIO_new(bio->method)) == NULL)
goto err;
+#ifndef OPENSSL_NO_DEPRECATED_3_0
new_bio->callback = bio->callback;
+#endif
new_bio->callback_ex = bio->callback_ex;
new_bio->cb_arg = bio->cb_arg;
new_bio->init = bio->init;
bio_type_lock = NULL;
}
-/* Internal variant of the below BIO_wait() not calling BIOerr() */
+/* Internal variant of the below BIO_wait() not calling ERR_raise(...) */
static int bio_wait(BIO *bio, time_t max_time, unsigned int nap_milliseconds)
{
#ifndef OPENSSL_NO_SOCK
* Succeed immediately if max_time == 0.
* If sockets are not available support polling: succeed after waiting at most
* the number of nap_milliseconds in order to avoid a tight busy loop.
- * Call BIOerr(...) on timeout or error.
+ * Call ERR_raise(ERR_LIB_BIO, ...) on timeout or error.
* Returns -1 on error, 0 on timeout, and 1 on success.
*/
int BIO_wait(BIO *bio, time_t max_time, unsigned int nap_milliseconds)