xref: /freebsd/crypto/openssl/crypto/bio/bio_lib.c (revision 17f01e99)
1e71b7053SJung-uk Kim /*
2e71b7053SJung-uk Kim  * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
374664626SKris Kennaway  *
4e71b7053SJung-uk Kim  * Licensed under the OpenSSL license (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
874664626SKris Kennaway  */
974664626SKris Kennaway 
1074664626SKris Kennaway #include <stdio.h>
1174664626SKris Kennaway #include <errno.h>
1274664626SKris Kennaway #include <openssl/crypto.h>
1317f01e99SJung-uk Kim #include "bio_local.h"
14e71b7053SJung-uk Kim #include "internal/cryptlib.h"
1574664626SKris Kennaway 
16e71b7053SJung-uk Kim 
17e71b7053SJung-uk Kim /*
18e71b7053SJung-uk Kim  * Helper macro for the callback to determine whether an operator expects a
19e71b7053SJung-uk Kim  * len parameter or not
20e71b7053SJung-uk Kim  */
21e71b7053SJung-uk Kim #define HAS_LEN_OPER(o)        ((o) == BIO_CB_READ || (o) == BIO_CB_WRITE || \
22e71b7053SJung-uk Kim                                 (o) == BIO_CB_GETS)
23e71b7053SJung-uk Kim 
24e71b7053SJung-uk Kim /*
25e71b7053SJung-uk Kim  * Helper function to work out whether to call the new style callback or the old
26e71b7053SJung-uk Kim  * one, and translate between the two.
27e71b7053SJung-uk Kim  *
28e71b7053SJung-uk Kim  * This has a long return type for consistency with the old callback. Similarly
29e71b7053SJung-uk Kim  * for the "long" used for "inret"
30e71b7053SJung-uk Kim  */
31e71b7053SJung-uk Kim static long bio_call_callback(BIO *b, int oper, const char *argp, size_t len,
32e71b7053SJung-uk Kim                               int argi, long argl, long inret, size_t *processed)
3374664626SKris Kennaway {
34e71b7053SJung-uk Kim     long ret;
35e71b7053SJung-uk Kim     int bareoper;
3674664626SKris Kennaway 
37e71b7053SJung-uk Kim     if (b->callback_ex != NULL)
38e71b7053SJung-uk Kim         return b->callback_ex(b, oper, argp, len, argi, argl, inret, processed);
39e71b7053SJung-uk Kim 
40e71b7053SJung-uk Kim     /* Strip off any BIO_CB_RETURN flag */
41e71b7053SJung-uk Kim     bareoper = oper & ~BIO_CB_RETURN;
42e71b7053SJung-uk Kim 
43e71b7053SJung-uk Kim     /*
44e71b7053SJung-uk Kim      * We have an old style callback, so we will have to do nasty casts and
45e71b7053SJung-uk Kim      * check for overflows.
46e71b7053SJung-uk Kim      */
47e71b7053SJung-uk Kim     if (HAS_LEN_OPER(bareoper)) {
48e71b7053SJung-uk Kim         /* In this case |len| is set, and should be used instead of |argi| */
49e71b7053SJung-uk Kim         if (len > INT_MAX)
50e71b7053SJung-uk Kim             return -1;
51e71b7053SJung-uk Kim 
52e71b7053SJung-uk Kim         argi = (int)len;
53e71b7053SJung-uk Kim     }
54e71b7053SJung-uk Kim 
55c9cf7b5cSJung-uk Kim     if (inret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) {
56e71b7053SJung-uk Kim         if (*processed > INT_MAX)
57e71b7053SJung-uk Kim             return -1;
58e71b7053SJung-uk Kim         inret = *processed;
59e71b7053SJung-uk Kim     }
60e71b7053SJung-uk Kim 
61e71b7053SJung-uk Kim     ret = b->callback(b, oper, argp, argi, argl, inret);
62e71b7053SJung-uk Kim 
63c9cf7b5cSJung-uk Kim     if (ret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) {
64e71b7053SJung-uk Kim         *processed = (size_t)ret;
65e71b7053SJung-uk Kim         ret = 1;
66e71b7053SJung-uk Kim     }
67e71b7053SJung-uk Kim 
68e71b7053SJung-uk Kim     return ret;
69e71b7053SJung-uk Kim }
70e71b7053SJung-uk Kim 
71e71b7053SJung-uk Kim BIO *BIO_new(const BIO_METHOD *method)
72e71b7053SJung-uk Kim {
73e71b7053SJung-uk Kim     BIO *bio = OPENSSL_zalloc(sizeof(*bio));
74e71b7053SJung-uk Kim 
75e71b7053SJung-uk Kim     if (bio == NULL) {
7674664626SKris Kennaway         BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE);
77e71b7053SJung-uk Kim         return NULL;
7874664626SKris Kennaway     }
7974664626SKris Kennaway 
8074664626SKris Kennaway     bio->method = method;
8174664626SKris Kennaway     bio->shutdown = 1;
8274664626SKris Kennaway     bio->references = 1;
83e71b7053SJung-uk Kim 
84e71b7053SJung-uk Kim     if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data))
85e71b7053SJung-uk Kim         goto err;
86e71b7053SJung-uk Kim 
87e71b7053SJung-uk Kim     bio->lock = CRYPTO_THREAD_lock_new();
88e71b7053SJung-uk Kim     if (bio->lock == NULL) {
89e71b7053SJung-uk Kim         BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE);
906f9291ceSJung-uk Kim         CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data);
91e71b7053SJung-uk Kim         goto err;
925c87c606SMark Murray     }
93e71b7053SJung-uk Kim 
94e71b7053SJung-uk Kim     if (method->create != NULL && !method->create(bio)) {
95e71b7053SJung-uk Kim         BIOerr(BIO_F_BIO_NEW, ERR_R_INIT_FAIL);
96e71b7053SJung-uk Kim         CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data);
97e71b7053SJung-uk Kim         CRYPTO_THREAD_lock_free(bio->lock);
98e71b7053SJung-uk Kim         goto err;
99e71b7053SJung-uk Kim     }
100e71b7053SJung-uk Kim     if (method->create == NULL)
101e71b7053SJung-uk Kim         bio->init = 1;
102e71b7053SJung-uk Kim 
103e71b7053SJung-uk Kim     return bio;
104e71b7053SJung-uk Kim 
105e71b7053SJung-uk Kim err:
106e71b7053SJung-uk Kim     OPENSSL_free(bio);
107e71b7053SJung-uk Kim     return NULL;
10874664626SKris Kennaway }
10974664626SKris Kennaway 
11074664626SKris Kennaway int BIO_free(BIO *a)
11174664626SKris Kennaway {
112e71b7053SJung-uk Kim     int ret;
11374664626SKris Kennaway 
1146f9291ceSJung-uk Kim     if (a == NULL)
115e71b7053SJung-uk Kim         return 0;
11674664626SKris Kennaway 
117e71b7053SJung-uk Kim     if (CRYPTO_DOWN_REF(&a->references, &ret, a->lock) <= 0)
118e71b7053SJung-uk Kim         return 0;
119e71b7053SJung-uk Kim 
120e71b7053SJung-uk Kim     REF_PRINT_COUNT("BIO", a);
121e71b7053SJung-uk Kim     if (ret > 0)
122e71b7053SJung-uk Kim         return 1;
123e71b7053SJung-uk Kim     REF_ASSERT_ISNT(ret < 0);
124e71b7053SJung-uk Kim 
125e71b7053SJung-uk Kim     if (a->callback != NULL || a->callback_ex != NULL) {
126e71b7053SJung-uk Kim         ret = (int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL);
127e71b7053SJung-uk Kim         if (ret <= 0)
128e71b7053SJung-uk Kim             return ret;
12974664626SKris Kennaway     }
13074664626SKris Kennaway 
131a93cbc2bSJung-uk Kim     if ((a->method != NULL) && (a->method->destroy != NULL))
132a3ddd25aSSimon L. B. Nielsen         a->method->destroy(a);
133e71b7053SJung-uk Kim 
134e71b7053SJung-uk Kim     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, a, &a->ex_data);
135e71b7053SJung-uk Kim 
136e71b7053SJung-uk Kim     CRYPTO_THREAD_lock_free(a->lock);
137e71b7053SJung-uk Kim 
138ddd58736SKris Kennaway     OPENSSL_free(a);
139e71b7053SJung-uk Kim 
140e71b7053SJung-uk Kim     return 1;
141e71b7053SJung-uk Kim }
142e71b7053SJung-uk Kim 
143e71b7053SJung-uk Kim void BIO_set_data(BIO *a, void *ptr)
144e71b7053SJung-uk Kim {
145e71b7053SJung-uk Kim     a->ptr = ptr;
146e71b7053SJung-uk Kim }
147e71b7053SJung-uk Kim 
148e71b7053SJung-uk Kim void *BIO_get_data(BIO *a)
149e71b7053SJung-uk Kim {
150e71b7053SJung-uk Kim     return a->ptr;
151e71b7053SJung-uk Kim }
152e71b7053SJung-uk Kim 
153e71b7053SJung-uk Kim void BIO_set_init(BIO *a, int init)
154e71b7053SJung-uk Kim {
155e71b7053SJung-uk Kim     a->init = init;
156e71b7053SJung-uk Kim }
157e71b7053SJung-uk Kim 
158e71b7053SJung-uk Kim int BIO_get_init(BIO *a)
159e71b7053SJung-uk Kim {
160e71b7053SJung-uk Kim     return a->init;
161e71b7053SJung-uk Kim }
162e71b7053SJung-uk Kim 
163e71b7053SJung-uk Kim void BIO_set_shutdown(BIO *a, int shut)
164e71b7053SJung-uk Kim {
165e71b7053SJung-uk Kim     a->shutdown = shut;
166e71b7053SJung-uk Kim }
167e71b7053SJung-uk Kim 
168e71b7053SJung-uk Kim int BIO_get_shutdown(BIO *a)
169e71b7053SJung-uk Kim {
170e71b7053SJung-uk Kim     return a->shutdown;
17174664626SKris Kennaway }
17274664626SKris Kennaway 
173ddd58736SKris Kennaway void BIO_vfree(BIO *a)
1746f9291ceSJung-uk Kim {
1756f9291ceSJung-uk Kim     BIO_free(a);
1766f9291ceSJung-uk Kim }
177ddd58736SKris Kennaway 
178e71b7053SJung-uk Kim int BIO_up_ref(BIO *a)
179e71b7053SJung-uk Kim {
180e71b7053SJung-uk Kim     int i;
181e71b7053SJung-uk Kim 
182e71b7053SJung-uk Kim     if (CRYPTO_UP_REF(&a->references, &i, a->lock) <= 0)
183e71b7053SJung-uk Kim         return 0;
184e71b7053SJung-uk Kim 
185e71b7053SJung-uk Kim     REF_PRINT_COUNT("BIO", a);
186e71b7053SJung-uk Kim     REF_ASSERT_ISNT(i < 2);
187e71b7053SJung-uk Kim     return ((i > 1) ? 1 : 0);
188e71b7053SJung-uk Kim }
189e71b7053SJung-uk Kim 
1905471f83eSSimon L. B. Nielsen void BIO_clear_flags(BIO *b, int flags)
1915471f83eSSimon L. B. Nielsen {
1925471f83eSSimon L. B. Nielsen     b->flags &= ~flags;
1935471f83eSSimon L. B. Nielsen }
1945471f83eSSimon L. B. Nielsen 
1955471f83eSSimon L. B. Nielsen int BIO_test_flags(const BIO *b, int flags)
1965471f83eSSimon L. B. Nielsen {
1975471f83eSSimon L. B. Nielsen     return (b->flags & flags);
1985471f83eSSimon L. B. Nielsen }
1995471f83eSSimon L. B. Nielsen 
2005471f83eSSimon L. B. Nielsen void BIO_set_flags(BIO *b, int flags)
2015471f83eSSimon L. B. Nielsen {
2025471f83eSSimon L. B. Nielsen     b->flags |= flags;
2035471f83eSSimon L. B. Nielsen }
2045471f83eSSimon L. B. Nielsen 
205e71b7053SJung-uk Kim BIO_callback_fn BIO_get_callback(const BIO *b)
206e71b7053SJung-uk Kim {
2075471f83eSSimon L. B. Nielsen     return b->callback;
2085471f83eSSimon L. B. Nielsen }
2095471f83eSSimon L. B. Nielsen 
210e71b7053SJung-uk Kim void BIO_set_callback(BIO *b, BIO_callback_fn cb)
2115471f83eSSimon L. B. Nielsen {
2125471f83eSSimon L. B. Nielsen     b->callback = cb;
2135471f83eSSimon L. B. Nielsen }
2145471f83eSSimon L. B. Nielsen 
215e71b7053SJung-uk Kim BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b)
216e71b7053SJung-uk Kim {
217e71b7053SJung-uk Kim     return b->callback_ex;
218e71b7053SJung-uk Kim }
219e71b7053SJung-uk Kim 
220e71b7053SJung-uk Kim void BIO_set_callback_ex(BIO *b, BIO_callback_fn_ex cb)
221e71b7053SJung-uk Kim {
222e71b7053SJung-uk Kim     b->callback_ex = cb;
223e71b7053SJung-uk Kim }
224e71b7053SJung-uk Kim 
2255471f83eSSimon L. B. Nielsen void BIO_set_callback_arg(BIO *b, char *arg)
2265471f83eSSimon L. B. Nielsen {
2275471f83eSSimon L. B. Nielsen     b->cb_arg = arg;
2285471f83eSSimon L. B. Nielsen }
2295471f83eSSimon L. B. Nielsen 
2305471f83eSSimon L. B. Nielsen char *BIO_get_callback_arg(const BIO *b)
2315471f83eSSimon L. B. Nielsen {
2325471f83eSSimon L. B. Nielsen     return b->cb_arg;
2335471f83eSSimon L. B. Nielsen }
2345471f83eSSimon L. B. Nielsen 
2355471f83eSSimon L. B. Nielsen const char *BIO_method_name(const BIO *b)
2365471f83eSSimon L. B. Nielsen {
2375471f83eSSimon L. B. Nielsen     return b->method->name;
2385471f83eSSimon L. B. Nielsen }
2395471f83eSSimon L. B. Nielsen 
2405471f83eSSimon L. B. Nielsen int BIO_method_type(const BIO *b)
2415471f83eSSimon L. B. Nielsen {
2425471f83eSSimon L. B. Nielsen     return b->method->type;
2435471f83eSSimon L. B. Nielsen }
2445471f83eSSimon L. B. Nielsen 
245e71b7053SJung-uk Kim /*
246e71b7053SJung-uk Kim  * This is essentially the same as BIO_read_ex() except that it allows
247e71b7053SJung-uk Kim  * 0 or a negative value to indicate failure (retryable or not) in the return.
248e71b7053SJung-uk Kim  * This is for compatibility with the old style BIO_read(), where existing code
249e71b7053SJung-uk Kim  * may make assumptions about the return value that it might get.
250e71b7053SJung-uk Kim  */
251e71b7053SJung-uk Kim static int bio_read_intern(BIO *b, void *data, size_t dlen, size_t *readbytes)
25274664626SKris Kennaway {
253e71b7053SJung-uk Kim     int ret;
25474664626SKris Kennaway 
2556f9291ceSJung-uk Kim     if ((b == NULL) || (b->method == NULL) || (b->method->bread == NULL)) {
256e71b7053SJung-uk Kim         BIOerr(BIO_F_BIO_READ_INTERN, BIO_R_UNSUPPORTED_METHOD);
257e71b7053SJung-uk Kim         return -2;
25874664626SKris Kennaway     }
25974664626SKris Kennaway 
260e71b7053SJung-uk Kim     if ((b->callback != NULL || b->callback_ex != NULL) &&
261e71b7053SJung-uk Kim         ((ret = (int)bio_call_callback(b, BIO_CB_READ, data, dlen, 0, 0L, 1L,
262e71b7053SJung-uk Kim                                        NULL)) <= 0))
263e71b7053SJung-uk Kim         return ret;
26474664626SKris Kennaway 
2656f9291ceSJung-uk Kim     if (!b->init) {
266e71b7053SJung-uk Kim         BIOerr(BIO_F_BIO_READ_INTERN, BIO_R_UNINITIALIZED);
267e71b7053SJung-uk Kim         return -2;
26874664626SKris Kennaway     }
26974664626SKris Kennaway 
270e71b7053SJung-uk Kim     ret = b->method->bread(b, data, dlen, readbytes);
27174664626SKris Kennaway 
272e71b7053SJung-uk Kim     if (ret > 0)
273e71b7053SJung-uk Kim         b->num_read += (uint64_t)*readbytes;
27474664626SKris Kennaway 
275e71b7053SJung-uk Kim     if (b->callback != NULL || b->callback_ex != NULL)
276e71b7053SJung-uk Kim         ret = (int)bio_call_callback(b, BIO_CB_READ | BIO_CB_RETURN, data,
277e71b7053SJung-uk Kim                                      dlen, 0, 0L, ret, readbytes);
278e71b7053SJung-uk Kim 
279e71b7053SJung-uk Kim     /* Shouldn't happen */
280e71b7053SJung-uk Kim     if (ret > 0 && *readbytes > dlen) {
281e71b7053SJung-uk Kim         BIOerr(BIO_F_BIO_READ_INTERN, ERR_R_INTERNAL_ERROR);
282e71b7053SJung-uk Kim         return -1;
28374664626SKris Kennaway     }
28474664626SKris Kennaway 
285e71b7053SJung-uk Kim     return ret;
286e71b7053SJung-uk Kim }
287e71b7053SJung-uk Kim 
288e71b7053SJung-uk Kim int BIO_read(BIO *b, void *data, int dlen)
28974664626SKris Kennaway {
290e71b7053SJung-uk Kim     size_t readbytes;
291e71b7053SJung-uk Kim     int ret;
292e71b7053SJung-uk Kim 
293e71b7053SJung-uk Kim     if (dlen < 0)
294e71b7053SJung-uk Kim         return 0;
295e71b7053SJung-uk Kim 
296e71b7053SJung-uk Kim     ret = bio_read_intern(b, data, (size_t)dlen, &readbytes);
297e71b7053SJung-uk Kim 
298e71b7053SJung-uk Kim     if (ret > 0) {
299e71b7053SJung-uk Kim         /* *readbytes should always be <= dlen */
300e71b7053SJung-uk Kim         ret = (int)readbytes;
301e71b7053SJung-uk Kim     }
302e71b7053SJung-uk Kim 
303e71b7053SJung-uk Kim     return ret;
304e71b7053SJung-uk Kim }
305e71b7053SJung-uk Kim 
306e71b7053SJung-uk Kim int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes)
307e71b7053SJung-uk Kim {
308e71b7053SJung-uk Kim     int ret;
309e71b7053SJung-uk Kim 
310e71b7053SJung-uk Kim     ret = bio_read_intern(b, data, dlen, readbytes);
311e71b7053SJung-uk Kim 
312e71b7053SJung-uk Kim     if (ret > 0)
313e71b7053SJung-uk Kim         ret = 1;
314e71b7053SJung-uk Kim     else
315e71b7053SJung-uk Kim         ret = 0;
316e71b7053SJung-uk Kim 
317e71b7053SJung-uk Kim     return ret;
318e71b7053SJung-uk Kim }
319e71b7053SJung-uk Kim 
320e71b7053SJung-uk Kim static int bio_write_intern(BIO *b, const void *data, size_t dlen,
321e71b7053SJung-uk Kim                             size_t *written)
322e71b7053SJung-uk Kim {
323e71b7053SJung-uk Kim     int ret;
32474664626SKris Kennaway 
32574664626SKris Kennaway     if (b == NULL)
326e71b7053SJung-uk Kim         return 0;
32774664626SKris Kennaway 
3286f9291ceSJung-uk Kim     if ((b->method == NULL) || (b->method->bwrite == NULL)) {
329e71b7053SJung-uk Kim         BIOerr(BIO_F_BIO_WRITE_INTERN, BIO_R_UNSUPPORTED_METHOD);
330e71b7053SJung-uk Kim         return -2;
33174664626SKris Kennaway     }
33274664626SKris Kennaway 
333e71b7053SJung-uk Kim     if ((b->callback != NULL || b->callback_ex != NULL) &&
334e71b7053SJung-uk Kim         ((ret = (int)bio_call_callback(b, BIO_CB_WRITE, data, dlen, 0, 0L, 1L,
335e71b7053SJung-uk Kim                                        NULL)) <= 0))
336e71b7053SJung-uk Kim         return ret;
33774664626SKris Kennaway 
3386f9291ceSJung-uk Kim     if (!b->init) {
339e71b7053SJung-uk Kim         BIOerr(BIO_F_BIO_WRITE_INTERN, BIO_R_UNINITIALIZED);
340e71b7053SJung-uk Kim         return -2;
34174664626SKris Kennaway     }
34274664626SKris Kennaway 
343e71b7053SJung-uk Kim     ret = b->method->bwrite(b, data, dlen, written);
34474664626SKris Kennaway 
345e71b7053SJung-uk Kim     if (ret > 0)
346e71b7053SJung-uk Kim         b->num_write += (uint64_t)*written;
34774664626SKris Kennaway 
348e71b7053SJung-uk Kim     if (b->callback != NULL || b->callback_ex != NULL)
349e71b7053SJung-uk Kim         ret = (int)bio_call_callback(b, BIO_CB_WRITE | BIO_CB_RETURN, data,
350e71b7053SJung-uk Kim                                      dlen, 0, 0L, ret, written);
351e71b7053SJung-uk Kim 
352e71b7053SJung-uk Kim     return ret;
35374664626SKris Kennaway }
35474664626SKris Kennaway 
355e71b7053SJung-uk Kim int BIO_write(BIO *b, const void *data, int dlen)
35674664626SKris Kennaway {
357e71b7053SJung-uk Kim     size_t written;
358e71b7053SJung-uk Kim     int ret;
359e71b7053SJung-uk Kim 
360e71b7053SJung-uk Kim     if (dlen < 0)
361e71b7053SJung-uk Kim         return 0;
362e71b7053SJung-uk Kim 
363e71b7053SJung-uk Kim     ret = bio_write_intern(b, data, (size_t)dlen, &written);
364e71b7053SJung-uk Kim 
365e71b7053SJung-uk Kim     if (ret > 0) {
366e71b7053SJung-uk Kim         /* *written should always be <= dlen */
367e71b7053SJung-uk Kim         ret = (int)written;
368e71b7053SJung-uk Kim     }
369e71b7053SJung-uk Kim 
370e71b7053SJung-uk Kim     return ret;
371e71b7053SJung-uk Kim }
372e71b7053SJung-uk Kim 
373e71b7053SJung-uk Kim int BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written)
374e71b7053SJung-uk Kim {
375e71b7053SJung-uk Kim     int ret;
376e71b7053SJung-uk Kim 
377e71b7053SJung-uk Kim     ret = bio_write_intern(b, data, dlen, written);
378e71b7053SJung-uk Kim 
379e71b7053SJung-uk Kim     if (ret > 0)
380e71b7053SJung-uk Kim         ret = 1;
381e71b7053SJung-uk Kim     else
382e71b7053SJung-uk Kim         ret = 0;
383e71b7053SJung-uk Kim 
384e71b7053SJung-uk Kim     return ret;
385e71b7053SJung-uk Kim }
386e71b7053SJung-uk Kim 
387e71b7053SJung-uk Kim int BIO_puts(BIO *b, const char *buf)
388e71b7053SJung-uk Kim {
389e71b7053SJung-uk Kim     int ret;
390e71b7053SJung-uk Kim     size_t written = 0;
39174664626SKris Kennaway 
3926f9291ceSJung-uk Kim     if ((b == NULL) || (b->method == NULL) || (b->method->bputs == NULL)) {
39374664626SKris Kennaway         BIOerr(BIO_F_BIO_PUTS, BIO_R_UNSUPPORTED_METHOD);
394e71b7053SJung-uk Kim         return -2;
39574664626SKris Kennaway     }
39674664626SKris Kennaway 
397e71b7053SJung-uk Kim     if (b->callback != NULL || b->callback_ex != NULL) {
398e71b7053SJung-uk Kim         ret = (int)bio_call_callback(b, BIO_CB_PUTS, buf, 0, 0, 0L, 1L, NULL);
399e71b7053SJung-uk Kim         if (ret <= 0)
400e71b7053SJung-uk Kim             return ret;
401e71b7053SJung-uk Kim     }
40274664626SKris Kennaway 
4036f9291ceSJung-uk Kim     if (!b->init) {
40474664626SKris Kennaway         BIOerr(BIO_F_BIO_PUTS, BIO_R_UNINITIALIZED);
405e71b7053SJung-uk Kim         return -2;
40674664626SKris Kennaway     }
40774664626SKris Kennaway 
408e71b7053SJung-uk Kim     ret = b->method->bputs(b, buf);
40974664626SKris Kennaway 
410e71b7053SJung-uk Kim     if (ret > 0) {
411e71b7053SJung-uk Kim         b->num_write += (uint64_t)ret;
412e71b7053SJung-uk Kim         written = ret;
413e71b7053SJung-uk Kim         ret = 1;
41474664626SKris Kennaway     }
41574664626SKris Kennaway 
416e71b7053SJung-uk Kim     if (b->callback != NULL || b->callback_ex != NULL)
417e71b7053SJung-uk Kim         ret = (int)bio_call_callback(b, BIO_CB_PUTS | BIO_CB_RETURN, buf, 0, 0,
418e71b7053SJung-uk Kim                                      0L, ret, &written);
419e71b7053SJung-uk Kim 
420e71b7053SJung-uk Kim     if (ret > 0) {
421e71b7053SJung-uk Kim         if (written > INT_MAX) {
422e71b7053SJung-uk Kim             BIOerr(BIO_F_BIO_PUTS, BIO_R_LENGTH_TOO_LONG);
423e71b7053SJung-uk Kim             ret = -1;
424e71b7053SJung-uk Kim         } else {
425e71b7053SJung-uk Kim             ret = (int)written;
426e71b7053SJung-uk Kim         }
427e71b7053SJung-uk Kim     }
428e71b7053SJung-uk Kim 
429e71b7053SJung-uk Kim     return ret;
430e71b7053SJung-uk Kim }
431e71b7053SJung-uk Kim 
432e71b7053SJung-uk Kim int BIO_gets(BIO *b, char *buf, int size)
43374664626SKris Kennaway {
434e71b7053SJung-uk Kim     int ret;
435e71b7053SJung-uk Kim     size_t readbytes = 0;
43674664626SKris Kennaway 
4376f9291ceSJung-uk Kim     if ((b == NULL) || (b->method == NULL) || (b->method->bgets == NULL)) {
43874664626SKris Kennaway         BIOerr(BIO_F_BIO_GETS, BIO_R_UNSUPPORTED_METHOD);
439e71b7053SJung-uk Kim         return -2;
44074664626SKris Kennaway     }
44174664626SKris Kennaway 
442e71b7053SJung-uk Kim     if (size < 0) {
443e71b7053SJung-uk Kim         BIOerr(BIO_F_BIO_GETS, BIO_R_INVALID_ARGUMENT);
444e71b7053SJung-uk Kim         return 0;
445e71b7053SJung-uk Kim     }
44674664626SKris Kennaway 
447e71b7053SJung-uk Kim     if (b->callback != NULL || b->callback_ex != NULL) {
448e71b7053SJung-uk Kim         ret = (int)bio_call_callback(b, BIO_CB_GETS, buf, size, 0, 0L, 1, NULL);
449e71b7053SJung-uk Kim         if (ret <= 0)
450e71b7053SJung-uk Kim             return ret;
451e71b7053SJung-uk Kim     }
45274664626SKris Kennaway 
4536f9291ceSJung-uk Kim     if (!b->init) {
45474664626SKris Kennaway         BIOerr(BIO_F_BIO_GETS, BIO_R_UNINITIALIZED);
455e71b7053SJung-uk Kim         return -2;
45674664626SKris Kennaway     }
45774664626SKris Kennaway 
458e71b7053SJung-uk Kim     ret = b->method->bgets(b, buf, size);
45974664626SKris Kennaway 
460e71b7053SJung-uk Kim     if (ret > 0) {
461e71b7053SJung-uk Kim         readbytes = ret;
462e71b7053SJung-uk Kim         ret = 1;
463e71b7053SJung-uk Kim     }
464e71b7053SJung-uk Kim 
465e71b7053SJung-uk Kim     if (b->callback != NULL || b->callback_ex != NULL)
466e71b7053SJung-uk Kim         ret = (int)bio_call_callback(b, BIO_CB_GETS | BIO_CB_RETURN, buf, size,
467e71b7053SJung-uk Kim                                      0, 0L, ret, &readbytes);
468e71b7053SJung-uk Kim 
469e71b7053SJung-uk Kim     if (ret > 0) {
470e71b7053SJung-uk Kim         /* Shouldn't happen */
471e71b7053SJung-uk Kim         if (readbytes > (size_t)size)
472e71b7053SJung-uk Kim             ret = -1;
473e71b7053SJung-uk Kim         else
474e71b7053SJung-uk Kim             ret = (int)readbytes;
475e71b7053SJung-uk Kim     }
476e71b7053SJung-uk Kim 
477e71b7053SJung-uk Kim     return ret;
47874664626SKris Kennaway }
47974664626SKris Kennaway 
4805c87c606SMark Murray int BIO_indent(BIO *b, int indent, int max)
4815c87c606SMark Murray {
4825c87c606SMark Murray     if (indent < 0)
4835c87c606SMark Murray         indent = 0;
4845c87c606SMark Murray     if (indent > max)
4855c87c606SMark Murray         indent = max;
4865c87c606SMark Murray     while (indent--)
4875c87c606SMark Murray         if (BIO_puts(b, " ") != 1)
4885c87c606SMark Murray             return 0;
4895c87c606SMark Murray     return 1;
4905c87c606SMark Murray }
4915c87c606SMark Murray 
49274664626SKris Kennaway long BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg)
49374664626SKris Kennaway {
49474664626SKris Kennaway     int i;
49574664626SKris Kennaway 
49674664626SKris Kennaway     i = iarg;
497e71b7053SJung-uk Kim     return BIO_ctrl(b, cmd, larg, (char *)&i);
49874664626SKris Kennaway }
49974664626SKris Kennaway 
500e71b7053SJung-uk Kim void *BIO_ptr_ctrl(BIO *b, int cmd, long larg)
50174664626SKris Kennaway {
502e71b7053SJung-uk Kim     void *p = NULL;
50374664626SKris Kennaway 
50474664626SKris Kennaway     if (BIO_ctrl(b, cmd, larg, (char *)&p) <= 0)
505e71b7053SJung-uk Kim         return NULL;
50674664626SKris Kennaway     else
507e71b7053SJung-uk Kim         return p;
50874664626SKris Kennaway }
50974664626SKris Kennaway 
51074664626SKris Kennaway long BIO_ctrl(BIO *b, int cmd, long larg, void *parg)
51174664626SKris Kennaway {
51274664626SKris Kennaway     long ret;
51374664626SKris Kennaway 
5146f9291ceSJung-uk Kim     if (b == NULL)
515e71b7053SJung-uk Kim         return 0;
51674664626SKris Kennaway 
5176f9291ceSJung-uk Kim     if ((b->method == NULL) || (b->method->ctrl == NULL)) {
51874664626SKris Kennaway         BIOerr(BIO_F_BIO_CTRL, BIO_R_UNSUPPORTED_METHOD);
519e71b7053SJung-uk Kim         return -2;
52074664626SKris Kennaway     }
52174664626SKris Kennaway 
522e71b7053SJung-uk Kim     if (b->callback != NULL || b->callback_ex != NULL) {
523e71b7053SJung-uk Kim         ret = bio_call_callback(b, BIO_CB_CTRL, parg, 0, cmd, larg, 1L, NULL);
524e71b7053SJung-uk Kim         if (ret <= 0)
525e71b7053SJung-uk Kim             return ret;
526e71b7053SJung-uk Kim     }
52774664626SKris Kennaway 
52874664626SKris Kennaway     ret = b->method->ctrl(b, cmd, larg, parg);
52974664626SKris Kennaway 
530e71b7053SJung-uk Kim     if (b->callback != NULL || b->callback_ex != NULL)
531e71b7053SJung-uk Kim         ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, parg, 0, cmd,
532e71b7053SJung-uk Kim                                 larg, ret, NULL);
533e71b7053SJung-uk Kim 
534e71b7053SJung-uk Kim     return ret;
53574664626SKris Kennaway }
53674664626SKris Kennaway 
537e71b7053SJung-uk Kim long BIO_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
538f579bf8eSKris Kennaway {
539f579bf8eSKris Kennaway     long ret;
540f579bf8eSKris Kennaway 
5416f9291ceSJung-uk Kim     if (b == NULL)
542e71b7053SJung-uk Kim         return 0;
543f579bf8eSKris Kennaway 
544e71b7053SJung-uk Kim     if ((b->method == NULL) || (b->method->callback_ctrl == NULL)
545e71b7053SJung-uk Kim             || (cmd != BIO_CTRL_SET_CALLBACK)) {
5463b4e3dcbSSimon L. B. Nielsen         BIOerr(BIO_F_BIO_CALLBACK_CTRL, BIO_R_UNSUPPORTED_METHOD);
547e71b7053SJung-uk Kim         return -2;
548f579bf8eSKris Kennaway     }
549f579bf8eSKris Kennaway 
550e71b7053SJung-uk Kim     if (b->callback != NULL || b->callback_ex != NULL) {
551e71b7053SJung-uk Kim         ret = bio_call_callback(b, BIO_CB_CTRL, (void *)&fp, 0, cmd, 0, 1L,
552e71b7053SJung-uk Kim                                 NULL);
553e71b7053SJung-uk Kim         if (ret <= 0)
554e71b7053SJung-uk Kim             return ret;
555e71b7053SJung-uk Kim     }
556f579bf8eSKris Kennaway 
557f579bf8eSKris Kennaway     ret = b->method->callback_ctrl(b, cmd, fp);
558f579bf8eSKris Kennaway 
559e71b7053SJung-uk Kim     if (b->callback != NULL || b->callback_ex != NULL)
560e71b7053SJung-uk Kim         ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, 0,
561e71b7053SJung-uk Kim                                 cmd, 0, ret, NULL);
562e71b7053SJung-uk Kim 
563e71b7053SJung-uk Kim     return ret;
564f579bf8eSKris Kennaway }
565f579bf8eSKris Kennaway 
5666f9291ceSJung-uk Kim /*
5676f9291ceSJung-uk Kim  * It is unfortunate to duplicate in functions what the BIO_(w)pending macros
56874664626SKris Kennaway  * do; but those macros have inappropriate return type, and for interfacing
5696f9291ceSJung-uk Kim  * from other programming languages, C macros aren't much of a help anyway.
5706f9291ceSJung-uk Kim  */
57174664626SKris Kennaway size_t BIO_ctrl_pending(BIO *bio)
57274664626SKris Kennaway {
57374664626SKris Kennaway     return BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL);
57474664626SKris Kennaway }
57574664626SKris Kennaway 
57674664626SKris Kennaway size_t BIO_ctrl_wpending(BIO *bio)
57774664626SKris Kennaway {
57874664626SKris Kennaway     return BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL);
57974664626SKris Kennaway }
58074664626SKris Kennaway 
58174664626SKris Kennaway /* put the 'bio' on the end of b's list of operators */
58274664626SKris Kennaway BIO *BIO_push(BIO *b, BIO *bio)
58374664626SKris Kennaway {
58474664626SKris Kennaway     BIO *lb;
58574664626SKris Kennaway 
5866f9291ceSJung-uk Kim     if (b == NULL)
587e71b7053SJung-uk Kim         return bio;
58874664626SKris Kennaway     lb = b;
58974664626SKris Kennaway     while (lb->next_bio != NULL)
59074664626SKris Kennaway         lb = lb->next_bio;
59174664626SKris Kennaway     lb->next_bio = bio;
59274664626SKris Kennaway     if (bio != NULL)
59374664626SKris Kennaway         bio->prev_bio = lb;
59474664626SKris Kennaway     /* called to do internal processing */
5951f13597dSJung-uk Kim     BIO_ctrl(b, BIO_CTRL_PUSH, 0, lb);
596e71b7053SJung-uk Kim     return b;
59774664626SKris Kennaway }
59874664626SKris Kennaway 
59974664626SKris Kennaway /* Remove the first and return the rest */
60074664626SKris Kennaway BIO *BIO_pop(BIO *b)
60174664626SKris Kennaway {
60274664626SKris Kennaway     BIO *ret;
60374664626SKris Kennaway 
6046f9291ceSJung-uk Kim     if (b == NULL)
605e71b7053SJung-uk Kim         return NULL;
60674664626SKris Kennaway     ret = b->next_bio;
60774664626SKris Kennaway 
6081f13597dSJung-uk Kim     BIO_ctrl(b, BIO_CTRL_POP, 0, b);
609fceca8a3SJacques Vidrine 
61074664626SKris Kennaway     if (b->prev_bio != NULL)
61174664626SKris Kennaway         b->prev_bio->next_bio = b->next_bio;
61274664626SKris Kennaway     if (b->next_bio != NULL)
61374664626SKris Kennaway         b->next_bio->prev_bio = b->prev_bio;
61474664626SKris Kennaway 
61574664626SKris Kennaway     b->next_bio = NULL;
61674664626SKris Kennaway     b->prev_bio = NULL;
617e71b7053SJung-uk Kim     return ret;
61874664626SKris Kennaway }
61974664626SKris Kennaway 
62074664626SKris Kennaway BIO *BIO_get_retry_BIO(BIO *bio, int *reason)
62174664626SKris Kennaway {
62274664626SKris Kennaway     BIO *b, *last;
62374664626SKris Kennaway 
62474664626SKris Kennaway     b = last = bio;
6256f9291ceSJung-uk Kim     for (;;) {
6266f9291ceSJung-uk Kim         if (!BIO_should_retry(b))
6276f9291ceSJung-uk Kim             break;
62874664626SKris Kennaway         last = b;
62974664626SKris Kennaway         b = b->next_bio;
6306f9291ceSJung-uk Kim         if (b == NULL)
6316f9291ceSJung-uk Kim             break;
63274664626SKris Kennaway     }
6336f9291ceSJung-uk Kim     if (reason != NULL)
6346f9291ceSJung-uk Kim         *reason = last->retry_reason;
635e71b7053SJung-uk Kim     return last;
63674664626SKris Kennaway }
63774664626SKris Kennaway 
63874664626SKris Kennaway int BIO_get_retry_reason(BIO *bio)
63974664626SKris Kennaway {
640e71b7053SJung-uk Kim     return bio->retry_reason;
641e71b7053SJung-uk Kim }
642e71b7053SJung-uk Kim 
643e71b7053SJung-uk Kim void BIO_set_retry_reason(BIO *bio, int reason)
644e71b7053SJung-uk Kim {
645e71b7053SJung-uk Kim     bio->retry_reason = reason;
64674664626SKris Kennaway }
64774664626SKris Kennaway 
64874664626SKris Kennaway BIO *BIO_find_type(BIO *bio, int type)
64974664626SKris Kennaway {
65074664626SKris Kennaway     int mt, mask;
65174664626SKris Kennaway 
652e71b7053SJung-uk Kim     if (bio == NULL)
6536f9291ceSJung-uk Kim         return NULL;
65474664626SKris Kennaway     mask = type & 0xff;
65574664626SKris Kennaway     do {
6566f9291ceSJung-uk Kim         if (bio->method != NULL) {
65774664626SKris Kennaway             mt = bio->method->type;
65874664626SKris Kennaway 
6596f9291ceSJung-uk Kim             if (!mask) {
6606f9291ceSJung-uk Kim                 if (mt & type)
661e71b7053SJung-uk Kim                     return bio;
6626f9291ceSJung-uk Kim             } else if (mt == type)
663e71b7053SJung-uk Kim                 return bio;
66474664626SKris Kennaway         }
66574664626SKris Kennaway         bio = bio->next_bio;
66674664626SKris Kennaway     } while (bio != NULL);
667e71b7053SJung-uk Kim     return NULL;
66874664626SKris Kennaway }
66974664626SKris Kennaway 
670ddd58736SKris Kennaway BIO *BIO_next(BIO *b)
671ddd58736SKris Kennaway {
672e71b7053SJung-uk Kim     if (b == NULL)
6736f9291ceSJung-uk Kim         return NULL;
674ddd58736SKris Kennaway     return b->next_bio;
675ddd58736SKris Kennaway }
676ddd58736SKris Kennaway 
677e71b7053SJung-uk Kim void BIO_set_next(BIO *b, BIO *next)
678e71b7053SJung-uk Kim {
679e71b7053SJung-uk Kim     b->next_bio = next;
680e71b7053SJung-uk Kim }
681e71b7053SJung-uk Kim 
68274664626SKris Kennaway void BIO_free_all(BIO *bio)
68374664626SKris Kennaway {
68474664626SKris Kennaway     BIO *b;
68574664626SKris Kennaway     int ref;
68674664626SKris Kennaway 
6876f9291ceSJung-uk Kim     while (bio != NULL) {
68874664626SKris Kennaway         b = bio;
68974664626SKris Kennaway         ref = b->references;
69074664626SKris Kennaway         bio = bio->next_bio;
69174664626SKris Kennaway         BIO_free(b);
69274664626SKris Kennaway         /* Since ref count > 1, don't free anyone else. */
6936f9291ceSJung-uk Kim         if (ref > 1)
6946f9291ceSJung-uk Kim             break;
69574664626SKris Kennaway     }
69674664626SKris Kennaway }
69774664626SKris Kennaway 
69874664626SKris Kennaway BIO *BIO_dup_chain(BIO *in)
69974664626SKris Kennaway {
7001f13597dSJung-uk Kim     BIO *ret = NULL, *eoc = NULL, *bio, *new_bio;
70174664626SKris Kennaway 
7026f9291ceSJung-uk Kim     for (bio = in; bio != NULL; bio = bio->next_bio) {
7036f9291ceSJung-uk Kim         if ((new_bio = BIO_new(bio->method)) == NULL)
7046f9291ceSJung-uk Kim             goto err;
7051f13597dSJung-uk Kim         new_bio->callback = bio->callback;
706e71b7053SJung-uk Kim         new_bio->callback_ex = bio->callback_ex;
7071f13597dSJung-uk Kim         new_bio->cb_arg = bio->cb_arg;
7081f13597dSJung-uk Kim         new_bio->init = bio->init;
7091f13597dSJung-uk Kim         new_bio->shutdown = bio->shutdown;
7101f13597dSJung-uk Kim         new_bio->flags = bio->flags;
71174664626SKris Kennaway 
71274664626SKris Kennaway         /* This will let SSL_s_sock() work with stdin/stdout */
7131f13597dSJung-uk Kim         new_bio->num = bio->num;
71474664626SKris Kennaway 
7156f9291ceSJung-uk Kim         if (!BIO_dup_state(bio, (char *)new_bio)) {
7161f13597dSJung-uk Kim             BIO_free(new_bio);
71774664626SKris Kennaway             goto err;
71874664626SKris Kennaway         }
71974664626SKris Kennaway 
72074664626SKris Kennaway         /* copy app data */
7211f13597dSJung-uk Kim         if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_BIO, &new_bio->ex_data,
722ed6b93beSJung-uk Kim                                 &bio->ex_data)) {
723ed6b93beSJung-uk Kim             BIO_free(new_bio);
72474664626SKris Kennaway             goto err;
725ed6b93beSJung-uk Kim         }
72674664626SKris Kennaway 
7276f9291ceSJung-uk Kim         if (ret == NULL) {
7281f13597dSJung-uk Kim             eoc = new_bio;
72974664626SKris Kennaway             ret = eoc;
7306f9291ceSJung-uk Kim         } else {
7311f13597dSJung-uk Kim             BIO_push(eoc, new_bio);
7321f13597dSJung-uk Kim             eoc = new_bio;
73374664626SKris Kennaway         }
73474664626SKris Kennaway     }
735e71b7053SJung-uk Kim     return ret;
73674664626SKris Kennaway  err:
737ed6b93beSJung-uk Kim     BIO_free_all(ret);
738ed6b93beSJung-uk Kim 
739e71b7053SJung-uk Kim     return NULL;
74074664626SKris Kennaway }
74174664626SKris Kennaway 
74274664626SKris Kennaway void BIO_copy_next_retry(BIO *b)
74374664626SKris Kennaway {
74474664626SKris Kennaway     BIO_set_flags(b, BIO_get_retry_flags(b->next_bio));
74574664626SKris Kennaway     b->retry_reason = b->next_bio->retry_reason;
74674664626SKris Kennaway }
74774664626SKris Kennaway 
748f579bf8eSKris Kennaway int BIO_set_ex_data(BIO *bio, int idx, void *data)
74974664626SKris Kennaway {
750e71b7053SJung-uk Kim     return CRYPTO_set_ex_data(&(bio->ex_data), idx, data);
75174664626SKris Kennaway }
75274664626SKris Kennaway 
753f579bf8eSKris Kennaway void *BIO_get_ex_data(BIO *bio, int idx)
75474664626SKris Kennaway {
755e71b7053SJung-uk Kim     return CRYPTO_get_ex_data(&(bio->ex_data), idx);
75674664626SKris Kennaway }
75774664626SKris Kennaway 
758e71b7053SJung-uk Kim uint64_t BIO_number_read(BIO *bio)
759f579bf8eSKris Kennaway {
7606f9291ceSJung-uk Kim     if (bio)
7616f9291ceSJung-uk Kim         return bio->num_read;
762f579bf8eSKris Kennaway     return 0;
763f579bf8eSKris Kennaway }
764f579bf8eSKris Kennaway 
765e71b7053SJung-uk Kim uint64_t BIO_number_written(BIO *bio)
766f579bf8eSKris Kennaway {
7676f9291ceSJung-uk Kim     if (bio)
7686f9291ceSJung-uk Kim         return bio->num_write;
769f579bf8eSKris Kennaway     return 0;
770f579bf8eSKris Kennaway }
771ddd58736SKris Kennaway 
772e71b7053SJung-uk Kim void bio_free_ex_data(BIO *bio)
773e71b7053SJung-uk Kim {
774e71b7053SJung-uk Kim     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data);
775e71b7053SJung-uk Kim }
776e71b7053SJung-uk Kim 
777e71b7053SJung-uk Kim void bio_cleanup(void)
778e71b7053SJung-uk Kim {
779e71b7053SJung-uk Kim #ifndef OPENSSL_NO_SOCK
780e71b7053SJung-uk Kim     bio_sock_cleanup_int();
781e71b7053SJung-uk Kim     CRYPTO_THREAD_lock_free(bio_lookup_lock);
782e71b7053SJung-uk Kim     bio_lookup_lock = NULL;
783e71b7053SJung-uk Kim #endif
784e71b7053SJung-uk Kim     CRYPTO_THREAD_lock_free(bio_type_lock);
785e71b7053SJung-uk Kim     bio_type_lock = NULL;
786e71b7053SJung-uk Kim }
787