1 /* 2 * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 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 8 */ 9 10 /* 11 * This is a read only BIO filter that can be used to add BIO_tell() and 12 * BIO_seek() support to source/sink BIO's (such as a file BIO that uses stdin). 13 * It does this by caching ALL data read from the BIO source/sink into a 14 * resizable memory buffer. 15 */ 16 17 #include <stdio.h> 18 #include <errno.h> 19 #include "bio_local.h" 20 #include "internal/cryptlib.h" 21 22 #define DEFAULT_BUFFER_SIZE 4096 23 24 static int readbuffer_write(BIO *h, const char *buf, int num); 25 static int readbuffer_read(BIO *h, char *buf, int size); 26 static int readbuffer_puts(BIO *h, const char *str); 27 static int readbuffer_gets(BIO *h, char *str, int size); 28 static long readbuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 29 static int readbuffer_new(BIO *h); 30 static int readbuffer_free(BIO *data); 31 static long readbuffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); 32 33 static const BIO_METHOD methods_readbuffer = { 34 BIO_TYPE_BUFFER, 35 "readbuffer", 36 bwrite_conv, 37 readbuffer_write, 38 bread_conv, 39 readbuffer_read, 40 readbuffer_puts, 41 readbuffer_gets, 42 readbuffer_ctrl, 43 readbuffer_new, 44 readbuffer_free, 45 readbuffer_callback_ctrl, 46 }; 47 48 const BIO_METHOD *BIO_f_readbuffer(void) 49 { 50 return &methods_readbuffer; 51 } 52 53 static int readbuffer_new(BIO *bi) 54 { 55 BIO_F_BUFFER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); 56 57 if (ctx == NULL) 58 return 0; 59 ctx->ibuf_size = DEFAULT_BUFFER_SIZE; 60 ctx->ibuf = OPENSSL_zalloc(DEFAULT_BUFFER_SIZE); 61 if (ctx->ibuf == NULL) { 62 OPENSSL_free(ctx); 63 return 0; 64 } 65 66 bi->init = 1; 67 bi->ptr = (char *)ctx; 68 bi->flags = 0; 69 return 1; 70 } 71 72 static int readbuffer_free(BIO *a) 73 { 74 BIO_F_BUFFER_CTX *b; 75 76 if (a == NULL) 77 return 0; 78 b = (BIO_F_BUFFER_CTX *)a->ptr; 79 OPENSSL_free(b->ibuf); 80 OPENSSL_free(a->ptr); 81 a->ptr = NULL; 82 a->init = 0; 83 a->flags = 0; 84 return 1; 85 } 86 87 static int readbuffer_resize(BIO_F_BUFFER_CTX *ctx, int sz) 88 { 89 char *tmp; 90 91 /* Figure out how many blocks are required */ 92 sz += (ctx->ibuf_off + DEFAULT_BUFFER_SIZE - 1); 93 sz = DEFAULT_BUFFER_SIZE * (sz / DEFAULT_BUFFER_SIZE); 94 95 /* Resize if the buffer is not big enough */ 96 if (sz > ctx->ibuf_size) { 97 tmp = OPENSSL_realloc(ctx->ibuf, sz); 98 if (tmp == NULL) 99 return 0; 100 ctx->ibuf = tmp; 101 ctx->ibuf_size = sz; 102 } 103 return 1; 104 } 105 106 static int readbuffer_read(BIO *b, char *out, int outl) 107 { 108 int i, num = 0; 109 BIO_F_BUFFER_CTX *ctx; 110 111 if (out == NULL || outl == 0) 112 return 0; 113 ctx = (BIO_F_BUFFER_CTX *)b->ptr; 114 115 if ((ctx == NULL) || (b->next_bio == NULL)) 116 return 0; 117 BIO_clear_retry_flags(b); 118 119 for (;;) { 120 i = ctx->ibuf_len; 121 /* If there is something in the buffer just read it. */ 122 if (i != 0) { 123 if (i > outl) 124 i = outl; 125 memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i); 126 ctx->ibuf_off += i; 127 ctx->ibuf_len -= i; 128 num += i; 129 /* Exit if we have read the bytes required out of the buffer */ 130 if (outl == i) 131 return num; 132 outl -= i; 133 out += i; 134 } 135 136 /* Only gets here if the buffer has been consumed */ 137 if (!readbuffer_resize(ctx, outl)) 138 return 0; 139 140 /* Do some buffering by reading from the next bio */ 141 i = BIO_read(b->next_bio, ctx->ibuf + ctx->ibuf_off, outl); 142 if (i <= 0) { 143 BIO_copy_next_retry(b); 144 if (i < 0) 145 return ((num > 0) ? num : i); 146 else 147 return num; /* i == 0 */ 148 } 149 ctx->ibuf_len = i; 150 } 151 } 152 153 static int readbuffer_write(BIO *b, const char *in, int inl) 154 { 155 return 0; 156 } 157 static int readbuffer_puts(BIO *b, const char *str) 158 { 159 return 0; 160 } 161 162 static long readbuffer_ctrl(BIO *b, int cmd, long num, void *ptr) 163 { 164 BIO_F_BUFFER_CTX *ctx; 165 long ret = 1, sz; 166 167 ctx = (BIO_F_BUFFER_CTX *)b->ptr; 168 169 switch (cmd) { 170 case BIO_CTRL_EOF: 171 if (ctx->ibuf_len > 0) 172 return 0; 173 if (b->next_bio == NULL) 174 return 1; 175 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 176 break; 177 178 case BIO_C_FILE_SEEK: 179 case BIO_CTRL_RESET: 180 sz = ctx->ibuf_off + ctx->ibuf_len; 181 /* Assume it can only seek backwards */ 182 if (num < 0 || num > sz) 183 return 0; 184 ctx->ibuf_off = num; 185 ctx->ibuf_len = sz - num; 186 break; 187 188 case BIO_C_FILE_TELL: 189 case BIO_CTRL_INFO: 190 ret = (long)ctx->ibuf_off; 191 break; 192 case BIO_CTRL_PENDING: 193 ret = (long)ctx->ibuf_len; 194 if (ret == 0) { 195 if (b->next_bio == NULL) 196 return 0; 197 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 198 } 199 break; 200 case BIO_CTRL_DUP: 201 case BIO_CTRL_FLUSH: 202 ret = 1; 203 break; 204 default: 205 ret = 0; 206 break; 207 } 208 return ret; 209 } 210 211 static long readbuffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) 212 { 213 if (b->next_bio == NULL) 214 return 0; 215 return BIO_callback_ctrl(b->next_bio, cmd, fp); 216 } 217 218 static int readbuffer_gets(BIO *b, char *buf, int size) 219 { 220 BIO_F_BUFFER_CTX *ctx; 221 int num = 0, num_chars, found_newline; 222 char *p; 223 int i, j; 224 225 if (size == 0) 226 return 0; 227 --size; /* the passed in size includes the terminator - so remove it here */ 228 ctx = (BIO_F_BUFFER_CTX *)b->ptr; 229 BIO_clear_retry_flags(b); 230 231 /* If data is already buffered then use this first */ 232 if (ctx->ibuf_len > 0) { 233 p = ctx->ibuf + ctx->ibuf_off; 234 found_newline = 0; 235 for (num_chars = 0; 236 (num_chars < ctx->ibuf_len) && (num_chars < size); 237 num_chars++) { 238 *buf++ = p[num_chars]; 239 if (p[num_chars] == '\n') { 240 found_newline = 1; 241 num_chars++; 242 break; 243 } 244 } 245 num += num_chars; 246 size -= num_chars; 247 ctx->ibuf_len -= num_chars; 248 ctx->ibuf_off += num_chars; 249 if (found_newline || size == 0) { 250 *buf = '\0'; 251 return num; 252 } 253 } 254 /* 255 * If there is no buffered data left then read any remaining data from the 256 * next bio. 257 */ 258 259 /* Resize if we have to */ 260 if (!readbuffer_resize(ctx, 1 + size)) 261 return 0; 262 /* 263 * Read more data from the next bio using BIO_read_ex: 264 * Note we cannot use BIO_gets() here as it does not work on a 265 * binary stream that contains 0x00. (Since strlen() will stop at 266 * any 0x00 not at the last read '\n' in a FILE bio). 267 * Also note that some applications open and close the file bio 268 * multiple times and need to read the next available block when using 269 * stdin - so we need to READ one byte at a time! 270 */ 271 p = ctx->ibuf + ctx->ibuf_off; 272 for (i = 0; i < size; ++i) { 273 j = BIO_read(b->next_bio, p, 1); 274 if (j <= 0) { 275 BIO_copy_next_retry(b); 276 *buf = '\0'; 277 return num > 0 ? num : j; 278 } 279 *buf++ = *p; 280 num++; 281 ctx->ibuf_off++; 282 if (*p == '\n') 283 break; 284 ++p; 285 } 286 *buf = '\0'; 287 return num; 288 } 289