]>
Commit | Line | Data |
---|---|---|
b1322259 | 1 | /* |
4333b89f | 2 | * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. |
d02b48c6 | 3 | * |
09abbca1 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
b1322259 RS |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
d02b48c6 RE |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
11 | #include <errno.h> | |
ec577822 | 12 | #include <openssl/crypto.h> |
706457b7 | 13 | #include "bio_local.h" |
b39fc560 | 14 | #include "internal/cryptlib.h" |
58964a49 | 15 | |
98e553d2 MC |
16 | /* |
17 | * Helper macro for the callback to determine whether an operator expects a | |
18 | * len parameter or not | |
19 | */ | |
dc88a039 DDO |
20 | #define HAS_LEN_OPER(o) ((o) == BIO_CB_READ || (o) == BIO_CB_WRITE \ |
21 | || (o) == BIO_CB_GETS) | |
98e553d2 MC |
22 | |
23 | /* | |
24 | * Helper function to work out whether to call the new style callback or the old | |
25 | * one, and translate between the two. | |
26 | * | |
27 | * This has a long return type for consistency with the old callback. Similarly | |
28 | * for the "long" used for "inret" | |
29 | */ | |
30 | static long bio_call_callback(BIO *b, int oper, const char *argp, size_t len, | |
dc88a039 DDO |
31 | int argi, long argl, long inret, |
32 | size_t *processed) | |
98e553d2 MC |
33 | { |
34 | long ret; | |
35 | int bareoper; | |
36 | ||
c911e5da | 37 | if (b->callback_ex != NULL) |
98e553d2 | 38 | return b->callback_ex(b, oper, argp, len, argi, argl, inret, processed); |
98e553d2 MC |
39 | |
40 | /* Strip off any BIO_CB_RETURN flag */ | |
41 | bareoper = oper & ~BIO_CB_RETURN; | |
42 | ||
43 | /* | |
44 | * We have an old style callback, so we will have to do nasty casts and | |
45 | * check for overflows. | |
46 | */ | |
47 | if (HAS_LEN_OPER(bareoper)) { | |
48 | /* In this case |len| is set, and should be used instead of |argi| */ | |
49 | if (len > INT_MAX) | |
50 | return -1; | |
51 | ||
52 | argi = (int)len; | |
c911e5da | 53 | } |
98e553d2 | 54 | |
d97ce8d9 | 55 | if (inret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) { |
c911e5da BE |
56 | if (*processed > INT_MAX) |
57 | return -1; | |
58 | inret = *processed; | |
98e553d2 MC |
59 | } |
60 | ||
61 | ret = b->callback(b, oper, argp, argi, argl, inret); | |
62 | ||
d97ce8d9 | 63 | if (ret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) { |
98e553d2 MC |
64 | *processed = (size_t)ret; |
65 | ret = 1; | |
66 | } | |
67 | ||
68 | return ret; | |
69 | } | |
70 | ||
04f6b0fd | 71 | BIO *BIO_new(const BIO_METHOD *method) |
0f113f3e | 72 | { |
9d7bfb14 | 73 | BIO *bio = OPENSSL_zalloc(sizeof(*bio)); |
0f113f3e | 74 | |
9d7bfb14 | 75 | if (bio == NULL) { |
9311d0c4 | 76 | ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE); |
26a7d938 | 77 | return NULL; |
0f113f3e | 78 | } |
d02b48c6 | 79 | |
0f113f3e | 80 | bio->method = method; |
0f113f3e | 81 | bio->shutdown = 1; |
0f113f3e | 82 | bio->references = 1; |
9d7bfb14 | 83 | |
25a807bc | 84 | if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data)) |
9d7bfb14 | 85 | goto err; |
fb46be03 AG |
86 | |
87 | bio->lock = CRYPTO_THREAD_lock_new(); | |
88 | if (bio->lock == NULL) { | |
9311d0c4 | 89 | ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE); |
fb46be03 | 90 | CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); |
9d7bfb14 | 91 | goto err; |
fb46be03 AG |
92 | } |
93 | ||
9d7bfb14 | 94 | if (method->create != NULL && !method->create(bio)) { |
9311d0c4 | 95 | ERR_raise(ERR_LIB_BIO, ERR_R_INIT_FAIL); |
9d7bfb14 F |
96 | CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); |
97 | CRYPTO_THREAD_lock_free(bio->lock); | |
98 | goto err; | |
fb46be03 | 99 | } |
7f55808f RL |
100 | if (method->create == NULL) |
101 | bio->init = 1; | |
fb46be03 | 102 | |
9d7bfb14 F |
103 | return bio; |
104 | ||
105 | err: | |
106 | OPENSSL_free(bio); | |
107 | return NULL; | |
0f113f3e | 108 | } |
d02b48c6 | 109 | |
6b691a5c | 110 | int BIO_free(BIO *a) |
0f113f3e | 111 | { |
98e553d2 | 112 | int ret; |
d02b48c6 | 113 | |
0f113f3e | 114 | if (a == NULL) |
fb46be03 AG |
115 | return 0; |
116 | ||
2f545ae4 | 117 | if (CRYPTO_DOWN_REF(&a->references, &ret, a->lock) <= 0) |
fb46be03 | 118 | return 0; |
d02b48c6 | 119 | |
f3f1cf84 | 120 | REF_PRINT_COUNT("BIO", a); |
98e553d2 | 121 | if (ret > 0) |
fb46be03 | 122 | return 1; |
98e553d2 MC |
123 | REF_ASSERT_ISNT(ret < 0); |
124 | ||
125 | if (a->callback != NULL || a->callback_ex != NULL) { | |
126 | ret = (int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL); | |
127 | if (ret <= 0) | |
128 | return ret; | |
129 | } | |
d02b48c6 | 130 | |
a14a740d F |
131 | if ((a->method != NULL) && (a->method->destroy != NULL)) |
132 | a->method->destroy(a); | |
133 | ||
0f113f3e | 134 | CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, a, &a->ex_data); |
58964a49 | 135 | |
fb46be03 AG |
136 | CRYPTO_THREAD_lock_free(a->lock); |
137 | ||
0f113f3e | 138 | OPENSSL_free(a); |
fb46be03 AG |
139 | |
140 | return 1; | |
0f113f3e | 141 | } |
d02b48c6 | 142 | |
a146ae55 MC |
143 | void BIO_set_data(BIO *a, void *ptr) |
144 | { | |
145 | a->ptr = ptr; | |
146 | } | |
147 | ||
148 | void *BIO_get_data(BIO *a) | |
149 | { | |
150 | return a->ptr; | |
151 | } | |
152 | ||
153 | void BIO_set_init(BIO *a, int init) | |
154 | { | |
155 | a->init = init; | |
156 | } | |
157 | ||
158 | int BIO_get_init(BIO *a) | |
159 | { | |
160 | return a->init; | |
161 | } | |
162 | ||
163 | void BIO_set_shutdown(BIO *a, int shut) | |
164 | { | |
165 | a->shutdown = shut; | |
166 | } | |
167 | ||
168 | int BIO_get_shutdown(BIO *a) | |
169 | { | |
170 | return a->shutdown; | |
171 | } | |
172 | ||
371acb22 | 173 | void BIO_vfree(BIO *a) |
0f113f3e MC |
174 | { |
175 | BIO_free(a); | |
176 | } | |
371acb22 | 177 | |
fb46be03 AG |
178 | int BIO_up_ref(BIO *a) |
179 | { | |
180 | int i; | |
181 | ||
2f545ae4 | 182 | if (CRYPTO_UP_REF(&a->references, &i, a->lock) <= 0) |
fb46be03 AG |
183 | return 0; |
184 | ||
185 | REF_PRINT_COUNT("BIO", a); | |
186 | REF_ASSERT_ISNT(i < 2); | |
dc88a039 | 187 | return i > 1; |
fb46be03 AG |
188 | } |
189 | ||
7806f3dd | 190 | void BIO_clear_flags(BIO *b, int flags) |
0f113f3e MC |
191 | { |
192 | b->flags &= ~flags; | |
193 | } | |
194 | ||
195 | int BIO_test_flags(const BIO *b, int flags) | |
196 | { | |
197 | return (b->flags & flags); | |
198 | } | |
199 | ||
200 | void BIO_set_flags(BIO *b, int flags) | |
201 | { | |
202 | b->flags |= flags; | |
203 | } | |
204 | ||
d07aee2c MC |
205 | BIO_callback_fn BIO_get_callback(const BIO *b) |
206 | { | |
0f113f3e MC |
207 | return b->callback; |
208 | } | |
209 | ||
d07aee2c | 210 | void BIO_set_callback(BIO *b, BIO_callback_fn cb) |
0f113f3e MC |
211 | { |
212 | b->callback = cb; | |
213 | } | |
7806f3dd | 214 | |
d07aee2c MC |
215 | BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b) |
216 | { | |
217 | return b->callback_ex; | |
218 | } | |
219 | ||
220 | void BIO_set_callback_ex(BIO *b, BIO_callback_fn_ex cb) | |
221 | { | |
222 | b->callback_ex = cb; | |
223 | } | |
224 | ||
7806f3dd | 225 | void BIO_set_callback_arg(BIO *b, char *arg) |
0f113f3e MC |
226 | { |
227 | b->cb_arg = arg; | |
228 | } | |
7806f3dd | 229 | |
0f113f3e MC |
230 | char *BIO_get_callback_arg(const BIO *b) |
231 | { | |
232 | return b->cb_arg; | |
233 | } | |
7806f3dd | 234 | |
0f113f3e MC |
235 | const char *BIO_method_name(const BIO *b) |
236 | { | |
237 | return b->method->name; | |
238 | } | |
7806f3dd NL |
239 | |
240 | int BIO_method_type(const BIO *b) | |
0f113f3e MC |
241 | { |
242 | return b->method->type; | |
243 | } | |
7806f3dd | 244 | |
bb5310be MC |
245 | /* |
246 | * This is essentially the same as BIO_read_ex() except that it allows | |
7bf79e33 MC |
247 | * 0 or a negative value to indicate failure (retryable or not) in the return. |
248 | * This is for compatibility with the old style BIO_read(), where existing code | |
249 | * may make assumptions about the return value that it might get. | |
bb5310be | 250 | */ |
d62bf89c | 251 | static int bio_read_intern(BIO *b, void *data, size_t dlen, size_t *readbytes) |
d07aee2c MC |
252 | { |
253 | int ret; | |
d02b48c6 | 254 | |
dc88a039 | 255 | if (b == NULL) { |
ed4a9b15 | 256 | ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER); |
dc88a039 DDO |
257 | return -1; |
258 | } | |
259 | if (b->method == NULL || b->method->bread == NULL) { | |
9311d0c4 | 260 | ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD); |
bb5310be | 261 | return -2; |
0f113f3e | 262 | } |
d02b48c6 | 263 | |
d07aee2c | 264 | if ((b->callback != NULL || b->callback_ex != NULL) && |
7bf79e33 | 265 | ((ret = (int)bio_call_callback(b, BIO_CB_READ, data, dlen, 0, 0L, 1L, |
c911e5da | 266 | NULL)) <= 0)) |
d07aee2c | 267 | return ret; |
d02b48c6 | 268 | |
0f113f3e | 269 | if (!b->init) { |
9311d0c4 | 270 | ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED); |
dc88a039 | 271 | return -1; |
0f113f3e | 272 | } |
d02b48c6 | 273 | |
d62bf89c | 274 | ret = b->method->bread(b, data, dlen, readbytes); |
dfeab068 | 275 | |
d07aee2c | 276 | if (ret > 0) |
82cb311f | 277 | b->num_read += (uint64_t)*readbytes; |
d07aee2c MC |
278 | |
279 | if (b->callback != NULL || b->callback_ex != NULL) | |
42c60460 | 280 | ret = (int)bio_call_callback(b, BIO_CB_READ | BIO_CB_RETURN, data, |
d62bf89c | 281 | dlen, 0, 0L, ret, readbytes); |
d02b48c6 | 282 | |
fbba62f6 | 283 | /* Shouldn't happen */ |
d62bf89c | 284 | if (ret > 0 && *readbytes > dlen) { |
9311d0c4 | 285 | ERR_raise(ERR_LIB_BIO, ERR_R_INTERNAL_ERROR); |
fbba62f6 | 286 | return -1; |
7bf79e33 | 287 | } |
fbba62f6 | 288 | |
d07aee2c | 289 | return ret; |
0f113f3e | 290 | } |
d02b48c6 | 291 | |
7bf79e33 | 292 | int BIO_read(BIO *b, void *data, int dlen) |
0f113f3e | 293 | { |
d62bf89c | 294 | size_t readbytes; |
3befffa3 MC |
295 | int ret; |
296 | ||
7bf79e33 | 297 | if (dlen < 0) |
3befffa3 MC |
298 | return 0; |
299 | ||
d62bf89c | 300 | ret = bio_read_intern(b, data, (size_t)dlen, &readbytes); |
3befffa3 MC |
301 | |
302 | if (ret > 0) { | |
4e3973b4 | 303 | /* *readbytes should always be <= dlen */ |
d62bf89c | 304 | ret = (int)readbytes; |
3befffa3 MC |
305 | } |
306 | ||
307 | return ret; | |
308 | } | |
309 | ||
d62bf89c | 310 | int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes) |
bb5310be | 311 | { |
dc88a039 | 312 | return bio_read_intern(b, data, dlen, readbytes) > 0; |
bb5310be MC |
313 | } |
314 | ||
7bf79e33 | 315 | static int bio_write_intern(BIO *b, const void *data, size_t dlen, |
42c60460 | 316 | size_t *written) |
3befffa3 MC |
317 | { |
318 | int ret; | |
58964a49 | 319 | |
dc88a039 | 320 | if (b == NULL) { |
ed4a9b15 | 321 | ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER); |
dc88a039 DDO |
322 | return -1; |
323 | } | |
324 | if (b->method == NULL || b->method->bwrite == NULL) { | |
9311d0c4 | 325 | ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD); |
bb5310be | 326 | return -2; |
0f113f3e | 327 | } |
d02b48c6 | 328 | |
3befffa3 | 329 | if ((b->callback != NULL || b->callback_ex != NULL) && |
7bf79e33 | 330 | ((ret = (int)bio_call_callback(b, BIO_CB_WRITE, data, dlen, 0, 0L, 1L, |
c911e5da | 331 | NULL)) <= 0)) |
3befffa3 | 332 | return ret; |
d02b48c6 | 333 | |
0f113f3e | 334 | if (!b->init) { |
9311d0c4 | 335 | ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED); |
dc88a039 | 336 | return -1; |
0f113f3e | 337 | } |
d02b48c6 | 338 | |
7bf79e33 | 339 | ret = b->method->bwrite(b, data, dlen, written); |
dfeab068 | 340 | |
3befffa3 MC |
341 | if (ret > 0) |
342 | b->num_write += (uint64_t)*written; | |
d02b48c6 | 343 | |
3befffa3 | 344 | if (b->callback != NULL || b->callback_ex != NULL) |
42c60460 | 345 | ret = (int)bio_call_callback(b, BIO_CB_WRITE | BIO_CB_RETURN, data, |
7bf79e33 | 346 | dlen, 0, 0L, ret, written); |
3befffa3 MC |
347 | |
348 | return ret; | |
0f113f3e | 349 | } |
d02b48c6 | 350 | |
7bf79e33 | 351 | int BIO_write(BIO *b, const void *data, int dlen) |
bb5310be MC |
352 | { |
353 | size_t written; | |
354 | int ret; | |
355 | ||
7bf79e33 | 356 | if (dlen < 0) |
bb5310be MC |
357 | return 0; |
358 | ||
7bf79e33 | 359 | ret = bio_write_intern(b, data, (size_t)dlen, &written); |
bb5310be MC |
360 | |
361 | if (ret > 0) { | |
4e3973b4 | 362 | /* *written should always be <= dlen */ |
bb5310be MC |
363 | ret = (int)written; |
364 | } | |
365 | ||
366 | return ret; | |
367 | } | |
368 | ||
7bf79e33 | 369 | int BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written) |
bb5310be | 370 | { |
dc88a039 | 371 | return bio_write_intern(b, data, dlen, written) > 0; |
bb5310be MC |
372 | } |
373 | ||
4e3973b4 | 374 | int BIO_puts(BIO *b, const char *buf) |
0f113f3e | 375 | { |
98e553d2 | 376 | int ret; |
47263ace | 377 | size_t written = 0; |
d02b48c6 | 378 | |
dc88a039 | 379 | if (b == NULL) { |
ed4a9b15 | 380 | ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER); |
dc88a039 DDO |
381 | return -1; |
382 | } | |
383 | if (b->method == NULL || b->method->bputs == NULL) { | |
9311d0c4 | 384 | ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD); |
98e553d2 | 385 | return -2; |
0f113f3e | 386 | } |
d02b48c6 | 387 | |
98e553d2 | 388 | if (b->callback != NULL || b->callback_ex != NULL) { |
4e3973b4 | 389 | ret = (int)bio_call_callback(b, BIO_CB_PUTS, buf, 0, 0, 0L, 1L, NULL); |
98e553d2 MC |
390 | if (ret <= 0) |
391 | return ret; | |
392 | } | |
d02b48c6 | 393 | |
0f113f3e | 394 | if (!b->init) { |
9311d0c4 | 395 | ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED); |
dc88a039 | 396 | return -1; |
0f113f3e | 397 | } |
d02b48c6 | 398 | |
4e3973b4 | 399 | ret = b->method->bputs(b, buf); |
d02b48c6 | 400 | |
98e553d2 MC |
401 | if (ret > 0) { |
402 | b->num_write += (uint64_t)ret; | |
403 | written = ret; | |
404 | ret = 1; | |
405 | } | |
406 | ||
407 | if (b->callback != NULL || b->callback_ex != NULL) | |
4e3973b4 | 408 | ret = (int)bio_call_callback(b, BIO_CB_PUTS | BIO_CB_RETURN, buf, 0, 0, |
98e553d2 MC |
409 | 0L, ret, &written); |
410 | ||
411 | if (ret > 0) { | |
7bf79e33 | 412 | if (written > INT_MAX) { |
9311d0c4 | 413 | ERR_raise(ERR_LIB_BIO, BIO_R_LENGTH_TOO_LONG); |
98e553d2 | 414 | ret = -1; |
7bf79e33 | 415 | } else { |
98e553d2 | 416 | ret = (int)written; |
7bf79e33 | 417 | } |
98e553d2 | 418 | } |
7d95ff76 | 419 | |
98e553d2 | 420 | return ret; |
0f113f3e | 421 | } |
d02b48c6 | 422 | |
4e3973b4 | 423 | int BIO_gets(BIO *b, char *buf, int size) |
0f113f3e | 424 | { |
98e553d2 | 425 | int ret; |
d62bf89c | 426 | size_t readbytes = 0; |
0f113f3e | 427 | |
dc88a039 | 428 | if (b == NULL) { |
ed4a9b15 | 429 | ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER); |
dc88a039 DDO |
430 | return -1; |
431 | } | |
432 | if (b->method == NULL || b->method->bgets == NULL) { | |
9311d0c4 | 433 | ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD); |
26a7d938 | 434 | return -2; |
0f113f3e MC |
435 | } |
436 | ||
4e3973b4 | 437 | if (size < 0) { |
9311d0c4 | 438 | ERR_raise(ERR_LIB_BIO, BIO_R_INVALID_ARGUMENT); |
dc88a039 | 439 | return -1; |
fbba62f6 MC |
440 | } |
441 | ||
98e553d2 | 442 | if (b->callback != NULL || b->callback_ex != NULL) { |
4e3973b4 | 443 | ret = (int)bio_call_callback(b, BIO_CB_GETS, buf, size, 0, 0L, 1, NULL); |
98e553d2 MC |
444 | if (ret <= 0) |
445 | return ret; | |
446 | } | |
0f113f3e MC |
447 | |
448 | if (!b->init) { | |
9311d0c4 | 449 | ERR_raise(ERR_LIB_BIO, BIO_R_UNINITIALIZED); |
dc88a039 | 450 | return -1; |
0f113f3e MC |
451 | } |
452 | ||
4e3973b4 | 453 | ret = b->method->bgets(b, buf, size); |
98e553d2 MC |
454 | |
455 | if (ret > 0) { | |
d62bf89c | 456 | readbytes = ret; |
98e553d2 MC |
457 | ret = 1; |
458 | } | |
459 | ||
460 | if (b->callback != NULL || b->callback_ex != NULL) | |
4e3973b4 | 461 | ret = (int)bio_call_callback(b, BIO_CB_GETS | BIO_CB_RETURN, buf, size, |
d62bf89c | 462 | 0, 0L, ret, &readbytes); |
98e553d2 MC |
463 | |
464 | if (ret > 0) { | |
fbba62f6 | 465 | /* Shouldn't happen */ |
4e3973b4 | 466 | if (readbytes > (size_t)size) |
98e553d2 MC |
467 | ret = -1; |
468 | else | |
d62bf89c | 469 | ret = (int)readbytes; |
98e553d2 | 470 | } |
0f113f3e | 471 | |
98e553d2 | 472 | return ret; |
0f113f3e MC |
473 | } |
474 | ||
475 | int BIO_indent(BIO *b, int indent, int max) | |
476 | { | |
477 | if (indent < 0) | |
478 | indent = 0; | |
479 | if (indent > max) | |
480 | indent = max; | |
481 | while (indent--) | |
482 | if (BIO_puts(b, " ") != 1) | |
483 | return 0; | |
484 | return 1; | |
485 | } | |
54a656ef | 486 | |
6b691a5c | 487 | long BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg) |
0f113f3e MC |
488 | { |
489 | int i; | |
d02b48c6 | 490 | |
0f113f3e | 491 | i = iarg; |
26a7d938 | 492 | return BIO_ctrl(b, cmd, larg, (char *)&i); |
0f113f3e | 493 | } |
d02b48c6 | 494 | |
417be660 | 495 | void *BIO_ptr_ctrl(BIO *b, int cmd, long larg) |
0f113f3e | 496 | { |
417be660 | 497 | void *p = NULL; |
58964a49 | 498 | |
0f113f3e | 499 | if (BIO_ctrl(b, cmd, larg, (char *)&p) <= 0) |
26a7d938 | 500 | return NULL; |
0f113f3e | 501 | else |
26a7d938 | 502 | return p; |
0f113f3e | 503 | } |
58964a49 | 504 | |
95d29597 | 505 | long BIO_ctrl(BIO *b, int cmd, long larg, void *parg) |
0f113f3e MC |
506 | { |
507 | long ret; | |
d02b48c6 | 508 | |
dc88a039 | 509 | if (b == NULL) { |
ed4a9b15 | 510 | ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER); |
dc88a039 DDO |
511 | return -1; |
512 | } | |
513 | if (b->method == NULL || b->method->ctrl == NULL) { | |
9311d0c4 | 514 | ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD); |
98e553d2 | 515 | return -2; |
0f113f3e | 516 | } |
d02b48c6 | 517 | |
98e553d2 MC |
518 | if (b->callback != NULL || b->callback_ex != NULL) { |
519 | ret = bio_call_callback(b, BIO_CB_CTRL, parg, 0, cmd, larg, 1L, NULL); | |
520 | if (ret <= 0) | |
521 | return ret; | |
522 | } | |
d02b48c6 | 523 | |
0f113f3e | 524 | ret = b->method->ctrl(b, cmd, larg, parg); |
d02b48c6 | 525 | |
98e553d2 MC |
526 | if (b->callback != NULL || b->callback_ex != NULL) |
527 | ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, parg, 0, cmd, | |
528 | larg, ret, NULL); | |
529 | ||
530 | return ret; | |
0f113f3e | 531 | } |
d02b48c6 | 532 | |
fce78bd4 | 533 | long BIO_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) |
0f113f3e MC |
534 | { |
535 | long ret; | |
d3442bc7 | 536 | |
dc88a039 | 537 | if (b == NULL) { |
ed4a9b15 DDO |
538 | ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER); |
539 | return -2; | |
dc88a039 DDO |
540 | } |
541 | if (b->method == NULL || b->method->callback_ctrl == NULL | |
542 | || cmd != BIO_CTRL_SET_CALLBACK) { | |
9311d0c4 | 543 | ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_METHOD); |
26a7d938 | 544 | return -2; |
0f113f3e | 545 | } |
d3442bc7 | 546 | |
98e553d2 MC |
547 | if (b->callback != NULL || b->callback_ex != NULL) { |
548 | ret = bio_call_callback(b, BIO_CB_CTRL, (void *)&fp, 0, cmd, 0, 1L, | |
549 | NULL); | |
550 | if (ret <= 0) | |
551 | return ret; | |
552 | } | |
d3442bc7 | 553 | |
0f113f3e | 554 | ret = b->method->callback_ctrl(b, cmd, fp); |
d3442bc7 | 555 | |
98e553d2 MC |
556 | if (b->callback != NULL || b->callback_ex != NULL) |
557 | ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, 0, | |
558 | cmd, 0, ret, NULL); | |
559 | ||
560 | return ret; | |
0f113f3e | 561 | } |
d3442bc7 | 562 | |
0f113f3e MC |
563 | /* |
564 | * It is unfortunate to duplicate in functions what the BIO_(w)pending macros | |
95d29597 | 565 | * do; but those macros have inappropriate return type, and for interfacing |
0f113f3e MC |
566 | * from other programming languages, C macros aren't much of a help anyway. |
567 | */ | |
95d29597 | 568 | size_t BIO_ctrl_pending(BIO *bio) |
0f113f3e MC |
569 | { |
570 | return BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL); | |
571 | } | |
95d29597 BM |
572 | |
573 | size_t BIO_ctrl_wpending(BIO *bio) | |
0f113f3e MC |
574 | { |
575 | return BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL); | |
576 | } | |
95d29597 | 577 | |
d02b48c6 | 578 | /* put the 'bio' on the end of b's list of operators */ |
6b691a5c | 579 | BIO *BIO_push(BIO *b, BIO *bio) |
0f113f3e MC |
580 | { |
581 | BIO *lb; | |
582 | ||
583 | if (b == NULL) | |
26a7d938 | 584 | return bio; |
0f113f3e MC |
585 | lb = b; |
586 | while (lb->next_bio != NULL) | |
587 | lb = lb->next_bio; | |
588 | lb->next_bio = bio; | |
589 | if (bio != NULL) | |
590 | bio->prev_bio = lb; | |
591 | /* called to do internal processing */ | |
592 | BIO_ctrl(b, BIO_CTRL_PUSH, 0, lb); | |
26a7d938 | 593 | return b; |
0f113f3e | 594 | } |
d02b48c6 RE |
595 | |
596 | /* Remove the first and return the rest */ | |
6b691a5c | 597 | BIO *BIO_pop(BIO *b) |
0f113f3e MC |
598 | { |
599 | BIO *ret; | |
d02b48c6 | 600 | |
dc88a039 | 601 | if (b == NULL) { |
ed4a9b15 | 602 | ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER); |
26a7d938 | 603 | return NULL; |
dc88a039 | 604 | } |
0f113f3e | 605 | ret = b->next_bio; |
d02b48c6 | 606 | |
0f113f3e | 607 | BIO_ctrl(b, BIO_CTRL_POP, 0, b); |
5d780bab | 608 | |
0f113f3e MC |
609 | if (b->prev_bio != NULL) |
610 | b->prev_bio->next_bio = b->next_bio; | |
611 | if (b->next_bio != NULL) | |
612 | b->next_bio->prev_bio = b->prev_bio; | |
d02b48c6 | 613 | |
0f113f3e MC |
614 | b->next_bio = NULL; |
615 | b->prev_bio = NULL; | |
26a7d938 | 616 | return ret; |
0f113f3e | 617 | } |
d02b48c6 | 618 | |
6b691a5c | 619 | BIO *BIO_get_retry_BIO(BIO *bio, int *reason) |
0f113f3e MC |
620 | { |
621 | BIO *b, *last; | |
622 | ||
623 | b = last = bio; | |
624 | for (;;) { | |
625 | if (!BIO_should_retry(b)) | |
626 | break; | |
627 | last = b; | |
628 | b = b->next_bio; | |
629 | if (b == NULL) | |
630 | break; | |
631 | } | |
632 | if (reason != NULL) | |
633 | *reason = last->retry_reason; | |
26a7d938 | 634 | return last; |
0f113f3e | 635 | } |
d02b48c6 | 636 | |
6b691a5c | 637 | int BIO_get_retry_reason(BIO *bio) |
0f113f3e | 638 | { |
26a7d938 | 639 | return bio->retry_reason; |
0f113f3e | 640 | } |
d02b48c6 | 641 | |
a146ae55 MC |
642 | void BIO_set_retry_reason(BIO *bio, int reason) |
643 | { | |
644 | bio->retry_reason = reason; | |
645 | } | |
646 | ||
6b691a5c | 647 | BIO *BIO_find_type(BIO *bio, int type) |
0f113f3e MC |
648 | { |
649 | int mt, mask; | |
650 | ||
dc88a039 | 651 | if (bio == NULL) { |
ed4a9b15 | 652 | ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER); |
0f113f3e | 653 | return NULL; |
dc88a039 | 654 | } |
0f113f3e MC |
655 | mask = type & 0xff; |
656 | do { | |
657 | if (bio->method != NULL) { | |
658 | mt = bio->method->type; | |
659 | ||
660 | if (!mask) { | |
661 | if (mt & type) | |
26a7d938 | 662 | return bio; |
dc88a039 | 663 | } else if (mt == type) { |
26a7d938 | 664 | return bio; |
dc88a039 | 665 | } |
0f113f3e MC |
666 | } |
667 | bio = bio->next_bio; | |
668 | } while (bio != NULL); | |
26a7d938 | 669 | return NULL; |
0f113f3e | 670 | } |
d02b48c6 | 671 | |
cfd3bb17 | 672 | BIO *BIO_next(BIO *b) |
0f113f3e | 673 | { |
dc88a039 | 674 | if (b == NULL) { |
ed4a9b15 | 675 | ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER); |
0f113f3e | 676 | return NULL; |
dc88a039 | 677 | } |
0f113f3e MC |
678 | return b->next_bio; |
679 | } | |
cfd3bb17 | 680 | |
a146ae55 MC |
681 | void BIO_set_next(BIO *b, BIO *next) |
682 | { | |
683 | b->next_bio = next; | |
684 | } | |
685 | ||
6b691a5c | 686 | void BIO_free_all(BIO *bio) |
0f113f3e MC |
687 | { |
688 | BIO *b; | |
689 | int ref; | |
690 | ||
691 | while (bio != NULL) { | |
692 | b = bio; | |
693 | ref = b->references; | |
694 | bio = bio->next_bio; | |
695 | BIO_free(b); | |
696 | /* Since ref count > 1, don't free anyone else. */ | |
697 | if (ref > 1) | |
698 | break; | |
699 | } | |
700 | } | |
d02b48c6 | 701 | |
6b691a5c | 702 | BIO *BIO_dup_chain(BIO *in) |
0f113f3e MC |
703 | { |
704 | BIO *ret = NULL, *eoc = NULL, *bio, *new_bio; | |
705 | ||
706 | for (bio = in; bio != NULL; bio = bio->next_bio) { | |
707 | if ((new_bio = BIO_new(bio->method)) == NULL) | |
708 | goto err; | |
709 | new_bio->callback = bio->callback; | |
98e553d2 | 710 | new_bio->callback_ex = bio->callback_ex; |
0f113f3e MC |
711 | new_bio->cb_arg = bio->cb_arg; |
712 | new_bio->init = bio->init; | |
713 | new_bio->shutdown = bio->shutdown; | |
714 | new_bio->flags = bio->flags; | |
715 | ||
716 | /* This will let SSL_s_sock() work with stdin/stdout */ | |
717 | new_bio->num = bio->num; | |
718 | ||
719 | if (!BIO_dup_state(bio, (char *)new_bio)) { | |
720 | BIO_free(new_bio); | |
721 | goto err; | |
722 | } | |
723 | ||
724 | /* copy app data */ | |
725 | if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_BIO, &new_bio->ex_data, | |
aec54108 MC |
726 | &bio->ex_data)) { |
727 | BIO_free(new_bio); | |
0f113f3e | 728 | goto err; |
aec54108 | 729 | } |
0f113f3e MC |
730 | |
731 | if (ret == NULL) { | |
732 | eoc = new_bio; | |
733 | ret = eoc; | |
734 | } else { | |
735 | BIO_push(eoc, new_bio); | |
736 | eoc = new_bio; | |
737 | } | |
738 | } | |
26a7d938 | 739 | return ret; |
0f113f3e | 740 | err: |
aec54108 MC |
741 | BIO_free_all(ret); |
742 | ||
26a7d938 | 743 | return NULL; |
0f113f3e | 744 | } |
d02b48c6 | 745 | |
6b691a5c | 746 | void BIO_copy_next_retry(BIO *b) |
0f113f3e MC |
747 | { |
748 | BIO_set_flags(b, BIO_get_retry_flags(b->next_bio)); | |
749 | b->retry_reason = b->next_bio->retry_reason; | |
750 | } | |
d02b48c6 | 751 | |
dd9d233e | 752 | int BIO_set_ex_data(BIO *bio, int idx, void *data) |
0f113f3e | 753 | { |
26a7d938 | 754 | return CRYPTO_set_ex_data(&(bio->ex_data), idx, data); |
0f113f3e | 755 | } |
58964a49 | 756 | |
8cc86b81 | 757 | void *BIO_get_ex_data(const BIO *bio, int idx) |
0f113f3e | 758 | { |
26a7d938 | 759 | return CRYPTO_get_ex_data(&(bio->ex_data), idx); |
0f113f3e | 760 | } |
58964a49 | 761 | |
b8b12aad | 762 | uint64_t BIO_number_read(BIO *bio) |
c3ed3b6e | 763 | { |
0f113f3e MC |
764 | if (bio) |
765 | return bio->num_read; | |
766 | return 0; | |
c3ed3b6e DSH |
767 | } |
768 | ||
b8b12aad | 769 | uint64_t BIO_number_written(BIO *bio) |
c3ed3b6e | 770 | { |
0f113f3e MC |
771 | if (bio) |
772 | return bio->num_write; | |
773 | return 0; | |
c3ed3b6e | 774 | } |
ff234405 | 775 | |
1ee7b8b9 MC |
776 | void bio_free_ex_data(BIO *bio) |
777 | { | |
778 | CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); | |
779 | } | |
ff234405 MC |
780 | |
781 | void bio_cleanup(void) | |
782 | { | |
783 | #ifndef OPENSSL_NO_SOCK | |
784 | bio_sock_cleanup_int(); | |
785 | CRYPTO_THREAD_lock_free(bio_lookup_lock); | |
786 | bio_lookup_lock = NULL; | |
5a7ad1f0 | 787 | #endif |
8b8d963d RS |
788 | CRYPTO_THREAD_lock_free(bio_type_lock); |
789 | bio_type_lock = NULL; | |
ff234405 | 790 | } |
e8d0819d DDO |
791 | |
792 | /* Internal variant of the below BIO_wait() not calling BIOerr() */ | |
e98c7350 | 793 | static int bio_wait(BIO *bio, time_t max_time, unsigned int nap_milliseconds) |
e8d0819d | 794 | { |
d8c78e5f | 795 | #ifndef OPENSSL_NO_SOCK |
e8d0819d | 796 | int fd; |
d8c78e5f | 797 | #endif |
e98c7350 | 798 | long sec_diff; |
e8d0819d | 799 | |
e98c7350 | 800 | if (max_time == 0) /* no timeout */ |
e8d0819d DDO |
801 | return 1; |
802 | ||
803 | #ifndef OPENSSL_NO_SOCK | |
e98c7350 | 804 | if (BIO_get_fd(bio, &fd) > 0 && fd < FD_SETSIZE) |
e8d0819d DDO |
805 | return BIO_socket_wait(fd, BIO_should_read(bio), max_time); |
806 | #endif | |
e98c7350 | 807 | /* fall back to polling since no sockets are available */ |
e8d0819d | 808 | |
e98c7350 DDO |
809 | sec_diff = (long)(max_time - time(NULL)); /* might overflow */ |
810 | if (sec_diff < 0) | |
811 | return 0; /* clearly timeout */ | |
812 | ||
813 | /* now take a nap at most the given number of milliseconds */ | |
814 | if (sec_diff == 0) { /* we are below the 1 seconds resolution of max_time */ | |
815 | if (nap_milliseconds > 1000) | |
816 | nap_milliseconds = 1000; | |
817 | } else { /* for sec_diff > 0, take min(sec_diff * 1000, nap_milliseconds) */ | |
818 | if ((unsigned long)sec_diff * 1000 < nap_milliseconds) | |
819 | nap_milliseconds = (unsigned int)sec_diff * 1000; | |
e8d0819d | 820 | } |
e98c7350 | 821 | ossl_sleep(nap_milliseconds); |
e8d0819d DDO |
822 | return 1; |
823 | } | |
824 | ||
e98c7350 | 825 | /*- |
e8d0819d | 826 | * Wait on (typically socket-based) BIO at most until max_time. |
e98c7350 DDO |
827 | * Succeed immediately if max_time == 0. |
828 | * If sockets are not available support polling: succeed after waiting at most | |
829 | * the number of nap_milliseconds in order to avoid a tight busy loop. | |
830 | * Call BIOerr(...) on timeout or error. | |
e8d0819d DDO |
831 | * Returns -1 on error, 0 on timeout, and 1 on success. |
832 | */ | |
e98c7350 | 833 | int BIO_wait(BIO *bio, time_t max_time, unsigned int nap_milliseconds) |
e8d0819d | 834 | { |
e98c7350 | 835 | int rv = bio_wait(bio, max_time, nap_milliseconds); |
e8d0819d DDO |
836 | |
837 | if (rv <= 0) | |
9311d0c4 RL |
838 | ERR_raise(ERR_LIB_BIO, |
839 | rv == 0 ? BIO_R_TRANSFER_TIMEOUT : BIO_R_TRANSFER_ERROR); | |
e8d0819d DDO |
840 | return rv; |
841 | } | |
842 | ||
843 | /* | |
e98c7350 DDO |
844 | * Connect via given BIO using BIO_do_connect() until success/timeout/error. |
845 | * Parameter timeout == 0 means no timeout, < 0 means exactly one try. | |
846 | * For non-blocking and potentially even non-socket BIOs perform polling with | |
847 | * the given density: between polls sleep nap_milliseconds using BIO_wait() | |
848 | * in order to avoid a tight busy loop. | |
e8d0819d DDO |
849 | * Returns -1 on error, 0 on timeout, and 1 on success. |
850 | */ | |
e98c7350 | 851 | int BIO_do_connect_retry(BIO *bio, int timeout, int nap_milliseconds) |
e8d0819d | 852 | { |
e98c7350 | 853 | int blocking = timeout <= 0; |
e8d0819d DDO |
854 | time_t max_time = timeout > 0 ? time(NULL) + timeout : 0; |
855 | int rv; | |
856 | ||
857 | if (bio == NULL) { | |
ed4a9b15 | 858 | ERR_raise(ERR_LIB_BIO, ERR_R_PASSED_NULL_PARAMETER); |
e8d0819d DDO |
859 | return -1; |
860 | } | |
861 | ||
e98c7350 DDO |
862 | if (nap_milliseconds < 0) |
863 | nap_milliseconds = 100; | |
864 | BIO_set_nbio(bio, !blocking); | |
865 | ||
866 | retry: | |
867 | rv = BIO_do_connect(bio); /* This may indirectly call ERR_clear_error(); */ | |
868 | ||
869 | if (rv <= 0) { /* could be timeout or retryable error or fatal error */ | |
870 | int err = ERR_peek_last_error(); | |
871 | int reason = ERR_GET_REASON(err); | |
872 | int do_retry = BIO_should_retry(bio); /* may be 1 only if !blocking */ | |
873 | ||
874 | if (ERR_GET_LIB(err) == ERR_LIB_BIO) { | |
875 | switch (reason) { | |
876 | case ERR_R_SYS_LIB: | |
877 | /* | |
878 | * likely retryable system error occurred, which may be | |
879 | * EAGAIN (resource temporarily unavailable) some 40 secs after | |
880 | * calling getaddrinfo(): Temporary failure in name resolution | |
881 | * or a premature ETIMEDOUT, some 30 seconds after connect() | |
882 | */ | |
883 | case BIO_R_CONNECT_ERROR: | |
884 | case BIO_R_NBIO_CONNECT_ERROR: | |
885 | /* some likely retryable connection error occurred */ | |
886 | (void)BIO_reset(bio); /* often needed to avoid retry failure */ | |
887 | do_retry = 1; | |
888 | break; | |
889 | default: | |
890 | break; | |
891 | } | |
892 | } | |
893 | if (timeout >= 0 && do_retry) { | |
894 | ERR_clear_error(); /* using ERR_pop_to_mark() would be cleaner */ | |
895 | /* will not actually wait if timeout == 0 (i.e., blocking BIO): */ | |
896 | rv = bio_wait(bio, max_time, nap_milliseconds); | |
e8d0819d DDO |
897 | if (rv > 0) |
898 | goto retry; | |
9311d0c4 RL |
899 | ERR_raise(ERR_LIB_BIO, |
900 | rv == 0 ? BIO_R_CONNECT_TIMEOUT : BIO_R_CONNECT_ERROR); | |
e8d0819d DDO |
901 | } else { |
902 | rv = -1; | |
e98c7350 | 903 | if (err == 0) /* missing error queue entry */ |
dc88a039 DDO |
904 | /* workaround: general error */ |
905 | ERR_raise(ERR_LIB_BIO, BIO_R_CONNECT_ERROR); | |
e8d0819d DDO |
906 | } |
907 | } | |
908 | ||
909 | return rv; | |
910 | } |