Stop raising ERR_R_MALLOC_FAILURE in most places
[openssl.git] / crypto / bio / bio_lib.c
index 575107634cbe134a526584790af9cab5897215af..a0a83da8cb74d9f0fa5912e192ed851f795ab2ae 100644 (file)
@@ -7,11 +7,13 @@
  * 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.
@@ -31,12 +38,15 @@ static long bio_call_callback(BIO *b, int oper, const char *argp, size_t len,
                               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;
 
@@ -64,7 +74,7 @@ static long bio_call_callback(BIO *b, int oper, const char *argp, size_t len,
         *processed = (size_t)ret;
         ret = 1;
     }
-
+#endif
     return ret;
 }
 
@@ -72,10 +82,8 @@ BIO *BIO_new_ex(OSSL_LIB_CTX *libctx, const BIO_METHOD *method)
 {
     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;
@@ -87,7 +95,7 @@ BIO *BIO_new_ex(OSSL_LIB_CTX *libctx, const 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;
     }
@@ -128,10 +136,10 @@ int BIO_free(BIO *a)
         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))
@@ -208,6 +216,7 @@ void BIO_set_flags(BIO *b, int flags)
     b->flags |= flags;
 }
 
+#ifndef OPENSSL_NO_DEPRECATED_3_0
 BIO_callback_fn BIO_get_callback(const BIO *b)
 {
     return b->callback;
@@ -217,6 +226,7 @@ void BIO_set_callback(BIO *b, BIO_callback_fn cb)
 {
     b->callback = cb;
 }
+#endif
 
 BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b)
 {
@@ -267,7 +277,7 @@ static int bio_read_intern(BIO *b, void *data, size_t dlen, size_t *readbytes)
         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;
@@ -282,7 +292,7 @@ static int bio_read_intern(BIO *b, void *data, size_t dlen, size_t *readbytes)
     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);
 
@@ -321,18 +331,24 @@ int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *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;
@@ -342,15 +358,17 @@ static int bio_write_intern(BIO *b, const void *data, size_t dlen,
         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;
 }
 
@@ -359,13 +377,13 @@ int BIO_write(BIO *b, const void *data, int dlen)
     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;
     }
 
@@ -374,7 +392,102 @@ int BIO_write(BIO *b, const void *data, int dlen)
 
 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)
@@ -391,7 +504,7 @@ 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;
@@ -410,7 +523,7 @@ int BIO_puts(BIO *b, const char *buf)
         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);
 
@@ -445,7 +558,7 @@ int BIO_gets(BIO *b, char *buf, int size)
         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;
@@ -463,7 +576,7 @@ int BIO_gets(BIO *b, char *buf, int size)
         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);
 
@@ -478,6 +591,37 @@ int BIO_gets(BIO *b, char *buf, int size)
     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)
@@ -512,16 +656,14 @@ long BIO_ctrl(BIO *b, int cmd, long larg, void *parg)
 {
     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;
@@ -529,7 +671,7 @@ long BIO_ctrl(BIO *b, int cmd, long larg, void *parg)
 
     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);
 
@@ -540,17 +682,15 @@ long BIO_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
 {
     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)
@@ -559,7 +699,7 @@ long BIO_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
 
     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);
 
@@ -573,12 +713,28 @@ long BIO_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
  */
 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 */
@@ -604,10 +760,8 @@ BIO *BIO_pop(BIO *b)
 {
     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);
@@ -677,10 +831,8 @@ BIO *BIO_find_type(BIO *bio, int type)
 
 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;
 }
 
@@ -712,7 +864,9 @@ BIO *BIO_dup_chain(BIO *in)
     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;
@@ -795,7 +949,7 @@ void bio_cleanup(void)
     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
@@ -833,7 +987,7 @@ static int bio_wait(BIO *bio, time_t max_time, unsigned int nap_milliseconds)
  * 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)