1 /* crypto/bio/bf_buff.c */ 2 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay (at) cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh (at) cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay (at) cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59 #include <stdio.h> 60 #include <errno.h> 61 #include "cryptlib.h" 62 #include <openssl/bio.h> 63 #include <openssl/evp.h> 64 65 static int linebuffer_write(BIO *h, const char *buf,int num); 66 static int linebuffer_read(BIO *h, char *buf, int size); 67 static int linebuffer_puts(BIO *h, const char *str); 68 static int linebuffer_gets(BIO *h, char *str, int size); 69 static long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 70 static int linebuffer_new(BIO *h); 71 static int linebuffer_free(BIO *data); 72 static long linebuffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 73 74 /* A 10k maximum should be enough for most purposes */ 75 #define DEFAULT_LINEBUFFER_SIZE 1024*10 76 77 /* #define DEBUG */ 78 79 static BIO_METHOD methods_linebuffer= 80 { 81 BIO_TYPE_LINEBUFFER, 82 "linebuffer", 83 linebuffer_write, 84 linebuffer_read, 85 linebuffer_puts, 86 linebuffer_gets, 87 linebuffer_ctrl, 88 linebuffer_new, 89 linebuffer_free, 90 linebuffer_callback_ctrl, 91 }; 92 93 BIO_METHOD *BIO_f_linebuffer(void) 94 { 95 return(&methods_linebuffer); 96 } 97 98 typedef struct bio_linebuffer_ctx_struct 99 { 100 char *obuf; /* the output char array */ 101 int obuf_size; /* how big is the output buffer */ 102 int obuf_len; /* how many bytes are in it */ 103 } BIO_LINEBUFFER_CTX; 104 105 static int linebuffer_new(BIO *bi) 106 { 107 BIO_LINEBUFFER_CTX *ctx; 108 109 ctx=(BIO_LINEBUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_LINEBUFFER_CTX)); 110 if (ctx == NULL) return(0); 111 ctx->obuf=(char *)OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); 112 if (ctx->obuf == NULL) { OPENSSL_free(ctx); return(0); } 113 ctx->obuf_size=DEFAULT_LINEBUFFER_SIZE; 114 ctx->obuf_len=0; 115 116 bi->init=1; 117 bi->ptr=(char *)ctx; 118 bi->flags=0; 119 return(1); 120 } 121 122 static int linebuffer_free(BIO *a) 123 { 124 BIO_LINEBUFFER_CTX *b; 125 126 if (a == NULL) return(0); 127 b=(BIO_LINEBUFFER_CTX *)a->ptr; 128 if (b->obuf != NULL) OPENSSL_free(b->obuf); 129 OPENSSL_free(a->ptr); 130 a->ptr=NULL; 131 a->init=0; 132 a->flags=0; 133 return(1); 134 } 135 136 static int linebuffer_read(BIO *b, char *out, int outl) 137 { 138 int ret=0; 139 140 if (out == NULL) return(0); 141 if (b->next_bio == NULL) return(0); 142 ret=BIO_read(b->next_bio,out,outl); 143 BIO_clear_retry_flags(b); 144 BIO_copy_next_retry(b); 145 return(ret); 146 } 147 148 static int linebuffer_write(BIO *b, const char *in, int inl) 149 { 150 int i,num=0,foundnl; 151 BIO_LINEBUFFER_CTX *ctx; 152 153 if ((in == NULL) || (inl <= 0)) return(0); 154 ctx=(BIO_LINEBUFFER_CTX *)b->ptr; 155 if ((ctx == NULL) || (b->next_bio == NULL)) return(0); 156 157 BIO_clear_retry_flags(b); 158 159 do 160 { 161 const char *p; 162 163 for(p = in; p < in + inl && *p != '\n'; p++) 164 ; 165 if (*p == '\n') 166 { 167 p++; 168 foundnl = 1; 169 } 170 else 171 foundnl = 0; 172 173 /* If a NL was found and we already have text in the save 174 buffer, concatenate them and write */ 175 while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) 176 && ctx->obuf_len > 0) 177 { 178 int orig_olen = ctx->obuf_len; 179 180 i = ctx->obuf_size - ctx->obuf_len; 181 if (p - in > 0) 182 { 183 if (i >= p - in) 184 { 185 memcpy(&(ctx->obuf[ctx->obuf_len]), 186 in,p - in); 187 ctx->obuf_len += p - in; 188 inl -= p - in; 189 num += p - in; 190 in = p; 191 } 192 else 193 { 194 memcpy(&(ctx->obuf[ctx->obuf_len]), 195 in,i); 196 ctx->obuf_len += i; 197 inl -= i; 198 in += i; 199 num += i; 200 } 201 } 202 203 #if 0 204 BIO_write(b->next_bio, "<*<", 3); 205 #endif 206 i=BIO_write(b->next_bio, 207 ctx->obuf, ctx->obuf_len); 208 if (i <= 0) 209 { 210 ctx->obuf_len = orig_olen; 211 BIO_copy_next_retry(b); 212 213 #if 0 214 BIO_write(b->next_bio, ">*>", 3); 215 #endif 216 if (i < 0) return((num > 0)?num:i); 217 if (i == 0) return(num); 218 } 219 #if 0 220 BIO_write(b->next_bio, ">*>", 3); 221 #endif 222 if (i < ctx->obuf_len) 223 memmove(ctx->obuf, ctx->obuf + i, 224 ctx->obuf_len - i); 225 ctx->obuf_len-=i; 226 } 227 228 /* Now that the save buffer is emptied, let's write the input 229 buffer if a NL was found and there is anything to write. */ 230 if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) 231 { 232 #if 0 233 BIO_write(b->next_bio, "<*<", 3); 234 #endif 235 i=BIO_write(b->next_bio,in,p - in); 236 if (i <= 0) 237 { 238 BIO_copy_next_retry(b); 239 #if 0 240 BIO_write(b->next_bio, ">*>", 3); 241 #endif 242 if (i < 0) return((num > 0)?num:i); 243 if (i == 0) return(num); 244 } 245 #if 0 246 BIO_write(b->next_bio, ">*>", 3); 247 #endif 248 num+=i; 249 in+=i; 250 inl-=i; 251 } 252 } 253 while(foundnl && inl > 0); 254 /* We've written as much as we can. The rest of the input buffer, if 255 any, is text that doesn't and with a NL and therefore needs to be 256 saved for the next trip. */ 257 if (inl > 0) 258 { 259 memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); 260 ctx->obuf_len += inl; 261 num += inl; 262 } 263 return num; 264 } 265 266 static long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) 267 { 268 BIO *dbio; 269 BIO_LINEBUFFER_CTX *ctx; 270 long ret=1; 271 char *p; 272 int r; 273 int obs; 274 275 ctx=(BIO_LINEBUFFER_CTX *)b->ptr; 276 277 switch (cmd) 278 { 279 case BIO_CTRL_RESET: 280 ctx->obuf_len=0; 281 if (b->next_bio == NULL) return(0); 282 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 283 break; 284 case BIO_CTRL_INFO: 285 ret=(long)ctx->obuf_len; 286 break; 287 case BIO_CTRL_WPENDING: 288 ret=(long)ctx->obuf_len; 289 if (ret == 0) 290 { 291 if (b->next_bio == NULL) return(0); 292 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 293 } 294 break; 295 case BIO_C_SET_BUFF_SIZE: 296 obs=(int)num; 297 p=ctx->obuf; 298 if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) 299 { 300 p=(char *)OPENSSL_malloc((int)num); 301 if (p == NULL) 302 goto malloc_error; 303 } 304 if (ctx->obuf != p) 305 { 306 if (ctx->obuf_len > obs) 307 { 308 ctx->obuf_len = obs; 309 } 310 memcpy(p, ctx->obuf, ctx->obuf_len); 311 OPENSSL_free(ctx->obuf); 312 ctx->obuf=p; 313 ctx->obuf_size=obs; 314 } 315 break; 316 case BIO_C_DO_STATE_MACHINE: 317 if (b->next_bio == NULL) return(0); 318 BIO_clear_retry_flags(b); 319 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 320 BIO_copy_next_retry(b); 321 break; 322 323 case BIO_CTRL_FLUSH: 324 if (b->next_bio == NULL) return(0); 325 if (ctx->obuf_len <= 0) 326 { 327 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 328 break; 329 } 330 331 for (;;) 332 { 333 BIO_clear_retry_flags(b); 334 if (ctx->obuf_len > 0) 335 { 336 r=BIO_write(b->next_bio, 337 ctx->obuf, ctx->obuf_len); 338 #if 0 339 fprintf(stderr,"FLUSH %3d -> %3d\n",ctx->obuf_len,r); 340 #endif 341 BIO_copy_next_retry(b); 342 if (r <= 0) return((long)r); 343 if (r < ctx->obuf_len) 344 memmove(ctx->obuf, ctx->obuf + r, 345 ctx->obuf_len - r); 346 ctx->obuf_len-=r; 347 } 348 else 349 { 350 ctx->obuf_len=0; 351 ret=1; 352 break; 353 } 354 } 355 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 356 break; 357 case BIO_CTRL_DUP: 358 dbio=(BIO *)ptr; 359 if ( !BIO_set_write_buffer_size(dbio,ctx->obuf_size)) 360 ret=0; 361 break; 362 default: 363 if (b->next_bio == NULL) return(0); 364 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 365 break; 366 } 367 return(ret); 368 malloc_error: 369 BIOerr(BIO_F_LINEBUFFER_CTRL,ERR_R_MALLOC_FAILURE); 370 return(0); 371 } 372 373 static long linebuffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 374 { 375 long ret=1; 376 377 if (b->next_bio == NULL) return(0); 378 switch (cmd) 379 { 380 default: 381 ret=BIO_callback_ctrl(b->next_bio,cmd,fp); 382 break; 383 } 384 return(ret); 385 } 386 387 static int linebuffer_gets(BIO *b, char *buf, int size) 388 { 389 if (b->next_bio == NULL) return(0); 390 return(BIO_gets(b->next_bio,buf,size)); 391 } 392 393 static int linebuffer_puts(BIO *b, const char *str) 394 { 395 return(linebuffer_write(b,str,strlen(str))); 396 } 397 398