1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <stdio.h> 11e1051a39Sopenharmony_ci#include <errno.h> 12e1051a39Sopenharmony_ci#include "bio_local.h" 13e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 14e1051a39Sopenharmony_ci 15e1051a39Sopenharmony_cistatic int buffer_write(BIO *h, const char *buf, int num); 16e1051a39Sopenharmony_cistatic int buffer_read(BIO *h, char *buf, int size); 17e1051a39Sopenharmony_cistatic int buffer_puts(BIO *h, const char *str); 18e1051a39Sopenharmony_cistatic int buffer_gets(BIO *h, char *str, int size); 19e1051a39Sopenharmony_cistatic long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 20e1051a39Sopenharmony_cistatic int buffer_new(BIO *h); 21e1051a39Sopenharmony_cistatic int buffer_free(BIO *data); 22e1051a39Sopenharmony_cistatic long buffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); 23e1051a39Sopenharmony_ci#define DEFAULT_BUFFER_SIZE 4096 24e1051a39Sopenharmony_ci 25e1051a39Sopenharmony_cistatic const BIO_METHOD methods_buffer = { 26e1051a39Sopenharmony_ci BIO_TYPE_BUFFER, 27e1051a39Sopenharmony_ci "buffer", 28e1051a39Sopenharmony_ci bwrite_conv, 29e1051a39Sopenharmony_ci buffer_write, 30e1051a39Sopenharmony_ci bread_conv, 31e1051a39Sopenharmony_ci buffer_read, 32e1051a39Sopenharmony_ci buffer_puts, 33e1051a39Sopenharmony_ci buffer_gets, 34e1051a39Sopenharmony_ci buffer_ctrl, 35e1051a39Sopenharmony_ci buffer_new, 36e1051a39Sopenharmony_ci buffer_free, 37e1051a39Sopenharmony_ci buffer_callback_ctrl, 38e1051a39Sopenharmony_ci}; 39e1051a39Sopenharmony_ci 40e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_f_buffer(void) 41e1051a39Sopenharmony_ci{ 42e1051a39Sopenharmony_ci return &methods_buffer; 43e1051a39Sopenharmony_ci} 44e1051a39Sopenharmony_ci 45e1051a39Sopenharmony_cistatic int buffer_new(BIO *bi) 46e1051a39Sopenharmony_ci{ 47e1051a39Sopenharmony_ci BIO_F_BUFFER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); 48e1051a39Sopenharmony_ci 49e1051a39Sopenharmony_ci if (ctx == NULL) 50e1051a39Sopenharmony_ci return 0; 51e1051a39Sopenharmony_ci ctx->ibuf_size = DEFAULT_BUFFER_SIZE; 52e1051a39Sopenharmony_ci ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); 53e1051a39Sopenharmony_ci if (ctx->ibuf == NULL) { 54e1051a39Sopenharmony_ci OPENSSL_free(ctx); 55e1051a39Sopenharmony_ci return 0; 56e1051a39Sopenharmony_ci } 57e1051a39Sopenharmony_ci ctx->obuf_size = DEFAULT_BUFFER_SIZE; 58e1051a39Sopenharmony_ci ctx->obuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); 59e1051a39Sopenharmony_ci if (ctx->obuf == NULL) { 60e1051a39Sopenharmony_ci OPENSSL_free(ctx->ibuf); 61e1051a39Sopenharmony_ci OPENSSL_free(ctx); 62e1051a39Sopenharmony_ci return 0; 63e1051a39Sopenharmony_ci } 64e1051a39Sopenharmony_ci 65e1051a39Sopenharmony_ci bi->init = 1; 66e1051a39Sopenharmony_ci bi->ptr = (char *)ctx; 67e1051a39Sopenharmony_ci bi->flags = 0; 68e1051a39Sopenharmony_ci return 1; 69e1051a39Sopenharmony_ci} 70e1051a39Sopenharmony_ci 71e1051a39Sopenharmony_cistatic int buffer_free(BIO *a) 72e1051a39Sopenharmony_ci{ 73e1051a39Sopenharmony_ci BIO_F_BUFFER_CTX *b; 74e1051a39Sopenharmony_ci 75e1051a39Sopenharmony_ci if (a == NULL) 76e1051a39Sopenharmony_ci return 0; 77e1051a39Sopenharmony_ci b = (BIO_F_BUFFER_CTX *)a->ptr; 78e1051a39Sopenharmony_ci OPENSSL_free(b->ibuf); 79e1051a39Sopenharmony_ci OPENSSL_free(b->obuf); 80e1051a39Sopenharmony_ci OPENSSL_free(a->ptr); 81e1051a39Sopenharmony_ci a->ptr = NULL; 82e1051a39Sopenharmony_ci a->init = 0; 83e1051a39Sopenharmony_ci a->flags = 0; 84e1051a39Sopenharmony_ci return 1; 85e1051a39Sopenharmony_ci} 86e1051a39Sopenharmony_ci 87e1051a39Sopenharmony_cistatic int buffer_read(BIO *b, char *out, int outl) 88e1051a39Sopenharmony_ci{ 89e1051a39Sopenharmony_ci int i, num = 0; 90e1051a39Sopenharmony_ci BIO_F_BUFFER_CTX *ctx; 91e1051a39Sopenharmony_ci 92e1051a39Sopenharmony_ci if (out == NULL) 93e1051a39Sopenharmony_ci return 0; 94e1051a39Sopenharmony_ci ctx = (BIO_F_BUFFER_CTX *)b->ptr; 95e1051a39Sopenharmony_ci 96e1051a39Sopenharmony_ci if ((ctx == NULL) || (b->next_bio == NULL)) 97e1051a39Sopenharmony_ci return 0; 98e1051a39Sopenharmony_ci num = 0; 99e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 100e1051a39Sopenharmony_ci 101e1051a39Sopenharmony_ci start: 102e1051a39Sopenharmony_ci i = ctx->ibuf_len; 103e1051a39Sopenharmony_ci /* If there is stuff left over, grab it */ 104e1051a39Sopenharmony_ci if (i != 0) { 105e1051a39Sopenharmony_ci if (i > outl) 106e1051a39Sopenharmony_ci i = outl; 107e1051a39Sopenharmony_ci memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i); 108e1051a39Sopenharmony_ci ctx->ibuf_off += i; 109e1051a39Sopenharmony_ci ctx->ibuf_len -= i; 110e1051a39Sopenharmony_ci num += i; 111e1051a39Sopenharmony_ci if (outl == i) 112e1051a39Sopenharmony_ci return num; 113e1051a39Sopenharmony_ci outl -= i; 114e1051a39Sopenharmony_ci out += i; 115e1051a39Sopenharmony_ci } 116e1051a39Sopenharmony_ci 117e1051a39Sopenharmony_ci /* 118e1051a39Sopenharmony_ci * We may have done a partial read. try to do more. We have nothing in 119e1051a39Sopenharmony_ci * the buffer. If we get an error and have read some data, just return it 120e1051a39Sopenharmony_ci * and let them retry to get the error again. copy direct to parent 121e1051a39Sopenharmony_ci * address space 122e1051a39Sopenharmony_ci */ 123e1051a39Sopenharmony_ci if (outl > ctx->ibuf_size) { 124e1051a39Sopenharmony_ci for (;;) { 125e1051a39Sopenharmony_ci i = BIO_read(b->next_bio, out, outl); 126e1051a39Sopenharmony_ci if (i <= 0) { 127e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 128e1051a39Sopenharmony_ci if (i < 0) 129e1051a39Sopenharmony_ci return ((num > 0) ? num : i); 130e1051a39Sopenharmony_ci if (i == 0) 131e1051a39Sopenharmony_ci return num; 132e1051a39Sopenharmony_ci } 133e1051a39Sopenharmony_ci num += i; 134e1051a39Sopenharmony_ci if (outl == i) 135e1051a39Sopenharmony_ci return num; 136e1051a39Sopenharmony_ci out += i; 137e1051a39Sopenharmony_ci outl -= i; 138e1051a39Sopenharmony_ci } 139e1051a39Sopenharmony_ci } 140e1051a39Sopenharmony_ci /* else */ 141e1051a39Sopenharmony_ci 142e1051a39Sopenharmony_ci /* we are going to be doing some buffering */ 143e1051a39Sopenharmony_ci i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); 144e1051a39Sopenharmony_ci if (i <= 0) { 145e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 146e1051a39Sopenharmony_ci if (i < 0) 147e1051a39Sopenharmony_ci return ((num > 0) ? num : i); 148e1051a39Sopenharmony_ci if (i == 0) 149e1051a39Sopenharmony_ci return num; 150e1051a39Sopenharmony_ci } 151e1051a39Sopenharmony_ci ctx->ibuf_off = 0; 152e1051a39Sopenharmony_ci ctx->ibuf_len = i; 153e1051a39Sopenharmony_ci 154e1051a39Sopenharmony_ci /* Lets re-read using ourselves :-) */ 155e1051a39Sopenharmony_ci goto start; 156e1051a39Sopenharmony_ci} 157e1051a39Sopenharmony_ci 158e1051a39Sopenharmony_cistatic int buffer_write(BIO *b, const char *in, int inl) 159e1051a39Sopenharmony_ci{ 160e1051a39Sopenharmony_ci int i, num = 0; 161e1051a39Sopenharmony_ci BIO_F_BUFFER_CTX *ctx; 162e1051a39Sopenharmony_ci 163e1051a39Sopenharmony_ci if ((in == NULL) || (inl <= 0)) 164e1051a39Sopenharmony_ci return 0; 165e1051a39Sopenharmony_ci ctx = (BIO_F_BUFFER_CTX *)b->ptr; 166e1051a39Sopenharmony_ci if ((ctx == NULL) || (b->next_bio == NULL)) 167e1051a39Sopenharmony_ci return 0; 168e1051a39Sopenharmony_ci 169e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 170e1051a39Sopenharmony_ci start: 171e1051a39Sopenharmony_ci i = ctx->obuf_size - (ctx->obuf_len + ctx->obuf_off); 172e1051a39Sopenharmony_ci /* add to buffer and return */ 173e1051a39Sopenharmony_ci if (i >= inl) { 174e1051a39Sopenharmony_ci memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, inl); 175e1051a39Sopenharmony_ci ctx->obuf_len += inl; 176e1051a39Sopenharmony_ci return (num + inl); 177e1051a39Sopenharmony_ci } 178e1051a39Sopenharmony_ci /* else */ 179e1051a39Sopenharmony_ci /* stuff already in buffer, so add to it first, then flush */ 180e1051a39Sopenharmony_ci if (ctx->obuf_len != 0) { 181e1051a39Sopenharmony_ci if (i > 0) { /* lets fill it up if we can */ 182e1051a39Sopenharmony_ci memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, i); 183e1051a39Sopenharmony_ci in += i; 184e1051a39Sopenharmony_ci inl -= i; 185e1051a39Sopenharmony_ci num += i; 186e1051a39Sopenharmony_ci ctx->obuf_len += i; 187e1051a39Sopenharmony_ci } 188e1051a39Sopenharmony_ci /* we now have a full buffer needing flushing */ 189e1051a39Sopenharmony_ci for (;;) { 190e1051a39Sopenharmony_ci i = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]), 191e1051a39Sopenharmony_ci ctx->obuf_len); 192e1051a39Sopenharmony_ci if (i <= 0) { 193e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 194e1051a39Sopenharmony_ci 195e1051a39Sopenharmony_ci if (i < 0) 196e1051a39Sopenharmony_ci return ((num > 0) ? num : i); 197e1051a39Sopenharmony_ci if (i == 0) 198e1051a39Sopenharmony_ci return num; 199e1051a39Sopenharmony_ci } 200e1051a39Sopenharmony_ci ctx->obuf_off += i; 201e1051a39Sopenharmony_ci ctx->obuf_len -= i; 202e1051a39Sopenharmony_ci if (ctx->obuf_len == 0) 203e1051a39Sopenharmony_ci break; 204e1051a39Sopenharmony_ci } 205e1051a39Sopenharmony_ci } 206e1051a39Sopenharmony_ci /* 207e1051a39Sopenharmony_ci * we only get here if the buffer has been flushed and we still have 208e1051a39Sopenharmony_ci * stuff to write 209e1051a39Sopenharmony_ci */ 210e1051a39Sopenharmony_ci ctx->obuf_off = 0; 211e1051a39Sopenharmony_ci 212e1051a39Sopenharmony_ci /* we now have inl bytes to write */ 213e1051a39Sopenharmony_ci while (inl >= ctx->obuf_size) { 214e1051a39Sopenharmony_ci i = BIO_write(b->next_bio, in, inl); 215e1051a39Sopenharmony_ci if (i <= 0) { 216e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 217e1051a39Sopenharmony_ci if (i < 0) 218e1051a39Sopenharmony_ci return ((num > 0) ? num : i); 219e1051a39Sopenharmony_ci if (i == 0) 220e1051a39Sopenharmony_ci return num; 221e1051a39Sopenharmony_ci } 222e1051a39Sopenharmony_ci num += i; 223e1051a39Sopenharmony_ci in += i; 224e1051a39Sopenharmony_ci inl -= i; 225e1051a39Sopenharmony_ci if (inl == 0) 226e1051a39Sopenharmony_ci return num; 227e1051a39Sopenharmony_ci } 228e1051a39Sopenharmony_ci 229e1051a39Sopenharmony_ci /* 230e1051a39Sopenharmony_ci * copy the rest into the buffer since we have only a small amount left 231e1051a39Sopenharmony_ci */ 232e1051a39Sopenharmony_ci goto start; 233e1051a39Sopenharmony_ci} 234e1051a39Sopenharmony_ci 235e1051a39Sopenharmony_cistatic long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) 236e1051a39Sopenharmony_ci{ 237e1051a39Sopenharmony_ci BIO *dbio; 238e1051a39Sopenharmony_ci BIO_F_BUFFER_CTX *ctx; 239e1051a39Sopenharmony_ci long ret = 1; 240e1051a39Sopenharmony_ci char *p1, *p2; 241e1051a39Sopenharmony_ci int r, i, *ip; 242e1051a39Sopenharmony_ci int ibs, obs; 243e1051a39Sopenharmony_ci 244e1051a39Sopenharmony_ci ctx = (BIO_F_BUFFER_CTX *)b->ptr; 245e1051a39Sopenharmony_ci 246e1051a39Sopenharmony_ci switch (cmd) { 247e1051a39Sopenharmony_ci case BIO_CTRL_RESET: 248e1051a39Sopenharmony_ci ctx->ibuf_off = 0; 249e1051a39Sopenharmony_ci ctx->ibuf_len = 0; 250e1051a39Sopenharmony_ci ctx->obuf_off = 0; 251e1051a39Sopenharmony_ci ctx->obuf_len = 0; 252e1051a39Sopenharmony_ci if (b->next_bio == NULL) 253e1051a39Sopenharmony_ci return 0; 254e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 255e1051a39Sopenharmony_ci break; 256e1051a39Sopenharmony_ci case BIO_CTRL_EOF: 257e1051a39Sopenharmony_ci if (ctx->ibuf_len > 0) 258e1051a39Sopenharmony_ci return 0; 259e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 260e1051a39Sopenharmony_ci break; 261e1051a39Sopenharmony_ci case BIO_CTRL_INFO: 262e1051a39Sopenharmony_ci ret = (long)ctx->obuf_len; 263e1051a39Sopenharmony_ci break; 264e1051a39Sopenharmony_ci case BIO_C_GET_BUFF_NUM_LINES: 265e1051a39Sopenharmony_ci ret = 0; 266e1051a39Sopenharmony_ci p1 = ctx->ibuf; 267e1051a39Sopenharmony_ci for (i = 0; i < ctx->ibuf_len; i++) { 268e1051a39Sopenharmony_ci if (p1[ctx->ibuf_off + i] == '\n') 269e1051a39Sopenharmony_ci ret++; 270e1051a39Sopenharmony_ci } 271e1051a39Sopenharmony_ci break; 272e1051a39Sopenharmony_ci case BIO_CTRL_WPENDING: 273e1051a39Sopenharmony_ci ret = (long)ctx->obuf_len; 274e1051a39Sopenharmony_ci if (ret == 0) { 275e1051a39Sopenharmony_ci if (b->next_bio == NULL) 276e1051a39Sopenharmony_ci return 0; 277e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 278e1051a39Sopenharmony_ci } 279e1051a39Sopenharmony_ci break; 280e1051a39Sopenharmony_ci case BIO_CTRL_PENDING: 281e1051a39Sopenharmony_ci ret = (long)ctx->ibuf_len; 282e1051a39Sopenharmony_ci if (ret == 0) { 283e1051a39Sopenharmony_ci if (b->next_bio == NULL) 284e1051a39Sopenharmony_ci return 0; 285e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 286e1051a39Sopenharmony_ci } 287e1051a39Sopenharmony_ci break; 288e1051a39Sopenharmony_ci case BIO_C_SET_BUFF_READ_DATA: 289e1051a39Sopenharmony_ci if (num > ctx->ibuf_size) { 290e1051a39Sopenharmony_ci if (num <= 0) 291e1051a39Sopenharmony_ci return 0; 292e1051a39Sopenharmony_ci p1 = OPENSSL_malloc((size_t)num); 293e1051a39Sopenharmony_ci if (p1 == NULL) 294e1051a39Sopenharmony_ci goto malloc_error; 295e1051a39Sopenharmony_ci OPENSSL_free(ctx->ibuf); 296e1051a39Sopenharmony_ci ctx->ibuf = p1; 297e1051a39Sopenharmony_ci } 298e1051a39Sopenharmony_ci ctx->ibuf_off = 0; 299e1051a39Sopenharmony_ci ctx->ibuf_len = (int)num; 300e1051a39Sopenharmony_ci memcpy(ctx->ibuf, ptr, (int)num); 301e1051a39Sopenharmony_ci ret = 1; 302e1051a39Sopenharmony_ci break; 303e1051a39Sopenharmony_ci case BIO_C_SET_BUFF_SIZE: 304e1051a39Sopenharmony_ci if (ptr != NULL) { 305e1051a39Sopenharmony_ci ip = (int *)ptr; 306e1051a39Sopenharmony_ci if (*ip == 0) { 307e1051a39Sopenharmony_ci ibs = (int)num; 308e1051a39Sopenharmony_ci obs = ctx->obuf_size; 309e1051a39Sopenharmony_ci } else { /* if (*ip == 1) */ 310e1051a39Sopenharmony_ci 311e1051a39Sopenharmony_ci ibs = ctx->ibuf_size; 312e1051a39Sopenharmony_ci obs = (int)num; 313e1051a39Sopenharmony_ci } 314e1051a39Sopenharmony_ci } else { 315e1051a39Sopenharmony_ci ibs = (int)num; 316e1051a39Sopenharmony_ci obs = (int)num; 317e1051a39Sopenharmony_ci } 318e1051a39Sopenharmony_ci p1 = ctx->ibuf; 319e1051a39Sopenharmony_ci p2 = ctx->obuf; 320e1051a39Sopenharmony_ci if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) { 321e1051a39Sopenharmony_ci if (num <= 0) 322e1051a39Sopenharmony_ci return 0; 323e1051a39Sopenharmony_ci p1 = OPENSSL_malloc((size_t)num); 324e1051a39Sopenharmony_ci if (p1 == NULL) 325e1051a39Sopenharmony_ci goto malloc_error; 326e1051a39Sopenharmony_ci } 327e1051a39Sopenharmony_ci if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) { 328e1051a39Sopenharmony_ci p2 = OPENSSL_malloc((size_t)num); 329e1051a39Sopenharmony_ci if (p2 == NULL) { 330e1051a39Sopenharmony_ci if (p1 != ctx->ibuf) 331e1051a39Sopenharmony_ci OPENSSL_free(p1); 332e1051a39Sopenharmony_ci goto malloc_error; 333e1051a39Sopenharmony_ci } 334e1051a39Sopenharmony_ci } 335e1051a39Sopenharmony_ci if (ctx->ibuf != p1) { 336e1051a39Sopenharmony_ci OPENSSL_free(ctx->ibuf); 337e1051a39Sopenharmony_ci ctx->ibuf = p1; 338e1051a39Sopenharmony_ci ctx->ibuf_off = 0; 339e1051a39Sopenharmony_ci ctx->ibuf_len = 0; 340e1051a39Sopenharmony_ci ctx->ibuf_size = ibs; 341e1051a39Sopenharmony_ci } 342e1051a39Sopenharmony_ci if (ctx->obuf != p2) { 343e1051a39Sopenharmony_ci OPENSSL_free(ctx->obuf); 344e1051a39Sopenharmony_ci ctx->obuf = p2; 345e1051a39Sopenharmony_ci ctx->obuf_off = 0; 346e1051a39Sopenharmony_ci ctx->obuf_len = 0; 347e1051a39Sopenharmony_ci ctx->obuf_size = obs; 348e1051a39Sopenharmony_ci } 349e1051a39Sopenharmony_ci break; 350e1051a39Sopenharmony_ci case BIO_C_DO_STATE_MACHINE: 351e1051a39Sopenharmony_ci if (b->next_bio == NULL) 352e1051a39Sopenharmony_ci return 0; 353e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 354e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 355e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 356e1051a39Sopenharmony_ci break; 357e1051a39Sopenharmony_ci 358e1051a39Sopenharmony_ci case BIO_CTRL_FLUSH: 359e1051a39Sopenharmony_ci if (b->next_bio == NULL) 360e1051a39Sopenharmony_ci return 0; 361e1051a39Sopenharmony_ci if (ctx->obuf_len <= 0) { 362e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 363e1051a39Sopenharmony_ci break; 364e1051a39Sopenharmony_ci } 365e1051a39Sopenharmony_ci 366e1051a39Sopenharmony_ci for (;;) { 367e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 368e1051a39Sopenharmony_ci if (ctx->obuf_len > 0) { 369e1051a39Sopenharmony_ci r = BIO_write(b->next_bio, 370e1051a39Sopenharmony_ci &(ctx->obuf[ctx->obuf_off]), ctx->obuf_len); 371e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 372e1051a39Sopenharmony_ci if (r <= 0) 373e1051a39Sopenharmony_ci return (long)r; 374e1051a39Sopenharmony_ci ctx->obuf_off += r; 375e1051a39Sopenharmony_ci ctx->obuf_len -= r; 376e1051a39Sopenharmony_ci } else { 377e1051a39Sopenharmony_ci ctx->obuf_len = 0; 378e1051a39Sopenharmony_ci ctx->obuf_off = 0; 379e1051a39Sopenharmony_ci break; 380e1051a39Sopenharmony_ci } 381e1051a39Sopenharmony_ci } 382e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 383e1051a39Sopenharmony_ci break; 384e1051a39Sopenharmony_ci case BIO_CTRL_DUP: 385e1051a39Sopenharmony_ci dbio = (BIO *)ptr; 386e1051a39Sopenharmony_ci if (BIO_set_read_buffer_size(dbio, ctx->ibuf_size) <= 0 || 387e1051a39Sopenharmony_ci BIO_set_write_buffer_size(dbio, ctx->obuf_size) <= 0) 388e1051a39Sopenharmony_ci ret = 0; 389e1051a39Sopenharmony_ci break; 390e1051a39Sopenharmony_ci case BIO_CTRL_PEEK: 391e1051a39Sopenharmony_ci /* Ensure there's stuff in the input buffer */ 392e1051a39Sopenharmony_ci { 393e1051a39Sopenharmony_ci char fake_buf[1]; 394e1051a39Sopenharmony_ci (void)buffer_read(b, fake_buf, 0); 395e1051a39Sopenharmony_ci } 396e1051a39Sopenharmony_ci if (num > ctx->ibuf_len) 397e1051a39Sopenharmony_ci num = ctx->ibuf_len; 398e1051a39Sopenharmony_ci memcpy(ptr, &(ctx->ibuf[ctx->ibuf_off]), num); 399e1051a39Sopenharmony_ci ret = num; 400e1051a39Sopenharmony_ci break; 401e1051a39Sopenharmony_ci default: 402e1051a39Sopenharmony_ci if (b->next_bio == NULL) 403e1051a39Sopenharmony_ci return 0; 404e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 405e1051a39Sopenharmony_ci break; 406e1051a39Sopenharmony_ci } 407e1051a39Sopenharmony_ci return ret; 408e1051a39Sopenharmony_ci malloc_error: 409e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE); 410e1051a39Sopenharmony_ci return 0; 411e1051a39Sopenharmony_ci} 412e1051a39Sopenharmony_ci 413e1051a39Sopenharmony_cistatic long buffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) 414e1051a39Sopenharmony_ci{ 415e1051a39Sopenharmony_ci if (b->next_bio == NULL) 416e1051a39Sopenharmony_ci return 0; 417e1051a39Sopenharmony_ci return BIO_callback_ctrl(b->next_bio, cmd, fp); 418e1051a39Sopenharmony_ci} 419e1051a39Sopenharmony_ci 420e1051a39Sopenharmony_cistatic int buffer_gets(BIO *b, char *buf, int size) 421e1051a39Sopenharmony_ci{ 422e1051a39Sopenharmony_ci BIO_F_BUFFER_CTX *ctx; 423e1051a39Sopenharmony_ci int num = 0, i, flag; 424e1051a39Sopenharmony_ci char *p; 425e1051a39Sopenharmony_ci 426e1051a39Sopenharmony_ci ctx = (BIO_F_BUFFER_CTX *)b->ptr; 427e1051a39Sopenharmony_ci size--; /* reserve space for a '\0' */ 428e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 429e1051a39Sopenharmony_ci 430e1051a39Sopenharmony_ci for (;;) { 431e1051a39Sopenharmony_ci if (ctx->ibuf_len > 0) { 432e1051a39Sopenharmony_ci p = &(ctx->ibuf[ctx->ibuf_off]); 433e1051a39Sopenharmony_ci flag = 0; 434e1051a39Sopenharmony_ci for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) { 435e1051a39Sopenharmony_ci *(buf++) = p[i]; 436e1051a39Sopenharmony_ci if (p[i] == '\n') { 437e1051a39Sopenharmony_ci flag = 1; 438e1051a39Sopenharmony_ci i++; 439e1051a39Sopenharmony_ci break; 440e1051a39Sopenharmony_ci } 441e1051a39Sopenharmony_ci } 442e1051a39Sopenharmony_ci num += i; 443e1051a39Sopenharmony_ci size -= i; 444e1051a39Sopenharmony_ci ctx->ibuf_len -= i; 445e1051a39Sopenharmony_ci ctx->ibuf_off += i; 446e1051a39Sopenharmony_ci if (flag || size == 0) { 447e1051a39Sopenharmony_ci *buf = '\0'; 448e1051a39Sopenharmony_ci return num; 449e1051a39Sopenharmony_ci } 450e1051a39Sopenharmony_ci } else { /* read another chunk */ 451e1051a39Sopenharmony_ci 452e1051a39Sopenharmony_ci i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); 453e1051a39Sopenharmony_ci if (i <= 0) { 454e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 455e1051a39Sopenharmony_ci *buf = '\0'; 456e1051a39Sopenharmony_ci if (i < 0) 457e1051a39Sopenharmony_ci return ((num > 0) ? num : i); 458e1051a39Sopenharmony_ci if (i == 0) 459e1051a39Sopenharmony_ci return num; 460e1051a39Sopenharmony_ci } 461e1051a39Sopenharmony_ci ctx->ibuf_len = i; 462e1051a39Sopenharmony_ci ctx->ibuf_off = 0; 463e1051a39Sopenharmony_ci } 464e1051a39Sopenharmony_ci } 465e1051a39Sopenharmony_ci} 466e1051a39Sopenharmony_ci 467e1051a39Sopenharmony_cistatic int buffer_puts(BIO *b, const char *str) 468e1051a39Sopenharmony_ci{ 469e1051a39Sopenharmony_ci return buffer_write(b, str, strlen(str)); 470e1051a39Sopenharmony_ci} 471