1 /* 2 * Copyright 1995-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 #include <stdio.h> 11 #include <errno.h> 12 #include "bio_local.h" 13 #include "internal/cryptlib.h" 14 #include <openssl/evp.h> 15 16 static int linebuffer_write(BIO *h, const char *buf, int num); 17 static int linebuffer_read(BIO *h, char *buf, int size); 18 static int linebuffer_puts(BIO *h, const char *str); 19 static int linebuffer_gets(BIO *h, char *str, int size); 20 static long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 21 static int linebuffer_new(BIO *h); 22 static int linebuffer_free(BIO *data); 23 static long linebuffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); 24 25 /* A 10k maximum should be enough for most purposes */ 26 #define DEFAULT_LINEBUFFER_SIZE 1024*10 27 28 /* #define DEBUG */ 29 30 static const BIO_METHOD methods_linebuffer = { 31 BIO_TYPE_LINEBUFFER, 32 "linebuffer", 33 bwrite_conv, 34 linebuffer_write, 35 bread_conv, 36 linebuffer_read, 37 linebuffer_puts, 38 linebuffer_gets, 39 linebuffer_ctrl, 40 linebuffer_new, 41 linebuffer_free, 42 linebuffer_callback_ctrl, 43 }; 44 45 const BIO_METHOD *BIO_f_linebuffer(void) 46 { 47 return &methods_linebuffer; 48 } 49 50 typedef struct bio_linebuffer_ctx_struct { 51 char *obuf; /* the output char array */ 52 int obuf_size; /* how big is the output buffer */ 53 int obuf_len; /* how many bytes are in it */ 54 } BIO_LINEBUFFER_CTX; 55 56 static int linebuffer_new(BIO *bi) 57 { 58 BIO_LINEBUFFER_CTX *ctx; 59 60 if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL) { 61 ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE); 62 return 0; 63 } 64 ctx->obuf = OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); 65 if (ctx->obuf == NULL) { 66 ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE); 67 OPENSSL_free(ctx); 68 return 0; 69 } 70 ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE; 71 ctx->obuf_len = 0; 72 73 bi->init = 1; 74 bi->ptr = (char *)ctx; 75 bi->flags = 0; 76 return 1; 77 } 78 79 static int linebuffer_free(BIO *a) 80 { 81 BIO_LINEBUFFER_CTX *b; 82 83 if (a == NULL) 84 return 0; 85 b = (BIO_LINEBUFFER_CTX *)a->ptr; 86 OPENSSL_free(b->obuf); 87 OPENSSL_free(a->ptr); 88 a->ptr = NULL; 89 a->init = 0; 90 a->flags = 0; 91 return 1; 92 } 93 94 static int linebuffer_read(BIO *b, char *out, int outl) 95 { 96 int ret = 0; 97 98 if (out == NULL) 99 return 0; 100 if (b->next_bio == NULL) 101 return 0; 102 ret = BIO_read(b->next_bio, out, outl); 103 BIO_clear_retry_flags(b); 104 BIO_copy_next_retry(b); 105 return ret; 106 } 107 108 static int linebuffer_write(BIO *b, const char *in, int inl) 109 { 110 int i, num = 0, foundnl; 111 BIO_LINEBUFFER_CTX *ctx; 112 113 if ((in == NULL) || (inl <= 0)) 114 return 0; 115 ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 116 if ((ctx == NULL) || (b->next_bio == NULL)) 117 return 0; 118 119 BIO_clear_retry_flags(b); 120 121 do { 122 const char *p; 123 char c; 124 125 for (p = in, c = '\0'; p < in + inl && (c = *p) != '\n'; p++) ; 126 if (c == '\n') { 127 p++; 128 foundnl = 1; 129 } else 130 foundnl = 0; 131 132 /* 133 * If a NL was found and we already have text in the save buffer, 134 * concatenate them and write 135 */ 136 while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) 137 && ctx->obuf_len > 0) { 138 int orig_olen = ctx->obuf_len; 139 140 i = ctx->obuf_size - ctx->obuf_len; 141 if (p - in > 0) { 142 if (i >= p - in) { 143 memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); 144 ctx->obuf_len += p - in; 145 inl -= p - in; 146 num += p - in; 147 in = p; 148 } else { 149 memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); 150 ctx->obuf_len += i; 151 inl -= i; 152 in += i; 153 num += i; 154 } 155 } 156 i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 157 if (i <= 0) { 158 ctx->obuf_len = orig_olen; 159 BIO_copy_next_retry(b); 160 161 if (i < 0) 162 return ((num > 0) ? num : i); 163 if (i == 0) 164 return num; 165 } 166 if (i < ctx->obuf_len) 167 memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); 168 ctx->obuf_len -= i; 169 } 170 171 /* 172 * Now that the save buffer is emptied, let's write the input buffer 173 * if a NL was found and there is anything to write. 174 */ 175 if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { 176 i = BIO_write(b->next_bio, in, p - in); 177 if (i <= 0) { 178 BIO_copy_next_retry(b); 179 if (i < 0) 180 return ((num > 0) ? num : i); 181 if (i == 0) 182 return num; 183 } 184 num += i; 185 in += i; 186 inl -= i; 187 } 188 } 189 while (foundnl && inl > 0); 190 /* 191 * We've written as much as we can. The rest of the input buffer, if 192 * any, is text that doesn't and with a NL and therefore needs to be 193 * saved for the next trip. 194 */ 195 if (inl > 0) { 196 memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); 197 ctx->obuf_len += inl; 198 num += inl; 199 } 200 return num; 201 } 202 203 static long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) 204 { 205 BIO *dbio; 206 BIO_LINEBUFFER_CTX *ctx; 207 long ret = 1; 208 char *p; 209 int r; 210 int obs; 211 212 ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 213 214 switch (cmd) { 215 case BIO_CTRL_RESET: 216 ctx->obuf_len = 0; 217 if (b->next_bio == NULL) 218 return 0; 219 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 220 break; 221 case BIO_CTRL_INFO: 222 ret = (long)ctx->obuf_len; 223 break; 224 case BIO_CTRL_WPENDING: 225 ret = (long)ctx->obuf_len; 226 if (ret == 0) { 227 if (b->next_bio == NULL) 228 return 0; 229 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 230 } 231 break; 232 case BIO_C_SET_BUFF_SIZE: 233 if (num > INT_MAX) 234 return 0; 235 obs = (int)num; 236 p = ctx->obuf; 237 if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) { 238 p = OPENSSL_malloc((size_t)obs); 239 if (p == NULL) 240 goto malloc_error; 241 } 242 if (ctx->obuf != p) { 243 if (ctx->obuf_len > obs) { 244 ctx->obuf_len = obs; 245 } 246 memcpy(p, ctx->obuf, ctx->obuf_len); 247 OPENSSL_free(ctx->obuf); 248 ctx->obuf = p; 249 ctx->obuf_size = obs; 250 } 251 break; 252 case BIO_C_DO_STATE_MACHINE: 253 if (b->next_bio == NULL) 254 return 0; 255 BIO_clear_retry_flags(b); 256 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 257 BIO_copy_next_retry(b); 258 break; 259 260 case BIO_CTRL_FLUSH: 261 if (b->next_bio == NULL) 262 return 0; 263 if (ctx->obuf_len <= 0) { 264 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 265 break; 266 } 267 268 for (;;) { 269 BIO_clear_retry_flags(b); 270 if (ctx->obuf_len > 0) { 271 r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 272 BIO_copy_next_retry(b); 273 if (r <= 0) 274 return (long)r; 275 if (r < ctx->obuf_len) 276 memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r); 277 ctx->obuf_len -= r; 278 } else { 279 ctx->obuf_len = 0; 280 break; 281 } 282 } 283 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 284 break; 285 case BIO_CTRL_DUP: 286 dbio = (BIO *)ptr; 287 if (BIO_set_write_buffer_size(dbio, ctx->obuf_size) <= 0) 288 ret = 0; 289 break; 290 default: 291 if (b->next_bio == NULL) 292 return 0; 293 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 294 break; 295 } 296 return ret; 297 malloc_error: 298 ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE); 299 return 0; 300 } 301 302 static long linebuffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) 303 { 304 if (b->next_bio == NULL) 305 return 0; 306 return BIO_callback_ctrl(b->next_bio, cmd, fp); 307 } 308 309 static int linebuffer_gets(BIO *b, char *buf, int size) 310 { 311 if (b->next_bio == NULL) 312 return 0; 313 return BIO_gets(b->next_bio, buf, size); 314 } 315 316 static int linebuffer_puts(BIO *b, const char *str) 317 { 318 return linebuffer_write(b, str, strlen(str)); 319 } 320