1 /* crypto/bio/bio_lib.c */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@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@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@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@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 "crypto.h" 62 #include "cryptlib.h" 63 #include "bio.h" 64 #include "stack.h" 65 66 static STACK *bio_meth=NULL; 67 static int bio_meth_num=0; 68 69 BIO *BIO_new(method) 70 BIO_METHOD *method; 71 { 72 BIO *ret=NULL; 73 74 ret=(BIO *)Malloc(sizeof(BIO)); 75 if (ret == NULL) 76 { 77 BIOerr(BIO_F_BIO_NEW,ERR_R_MALLOC_FAILURE); 78 return(NULL); 79 } 80 if (!BIO_set(ret,method)) 81 { 82 Free(ret); 83 ret=NULL; 84 } 85 return(ret); 86 } 87 88 int BIO_set(bio,method) 89 BIO *bio; 90 BIO_METHOD *method; 91 { 92 bio->method=method; 93 bio->callback=NULL; 94 bio->cb_arg=NULL; 95 bio->init=0; 96 bio->shutdown=1; 97 bio->flags=0; 98 bio->retry_reason=0; 99 bio->num=0; 100 bio->ptr=NULL; 101 bio->prev_bio=NULL; 102 bio->next_bio=NULL; 103 bio->references=1; 104 bio->num_read=0L; 105 bio->num_write=0L; 106 CRYPTO_new_ex_data(bio_meth,(char *)bio,&bio->ex_data); 107 if (method->create != NULL) 108 if (!method->create(bio)) 109 return(0); 110 return(1); 111 } 112 113 int BIO_free(a) 114 BIO *a; 115 { 116 int ret=0,i; 117 118 if (a == NULL) return(0); 119 120 i=CRYPTO_add(&a->references,-1,CRYPTO_LOCK_BIO); 121 #ifdef REF_PRINT 122 REF_PRINT("BIO",a); 123 #endif 124 if (i > 0) return(1); 125 #ifdef REF_CHECK 126 if (i < 0) 127 { 128 fprintf(stderr,"BIO_free, bad reference count\n"); 129 abort(); 130 } 131 #endif 132 if ((a->callback != NULL) && 133 ((i=(int)a->callback(a,BIO_CB_FREE,NULL,0,0L,1L)) <= 0)) 134 return(i); 135 136 CRYPTO_free_ex_data(bio_meth,(char *)a,&a->ex_data); 137 138 if ((a->method == NULL) || (a->method->destroy == NULL)) return(1); 139 ret=a->method->destroy(a); 140 Free(a); 141 return(1); 142 } 143 144 int BIO_read(b,out,outl) 145 BIO *b; 146 char *out; 147 int outl; 148 { 149 int i; 150 long (*cb)(); 151 152 if ((b == NULL) || (b->method == NULL) || (b->method->bread == NULL)) 153 { 154 BIOerr(BIO_F_BIO_READ,BIO_R_UNSUPPORTED_METHOD); 155 return(-2); 156 } 157 158 cb=b->callback; 159 if ((cb != NULL) && 160 ((i=(int)cb(b,BIO_CB_READ,out,outl,0L,1L)) <= 0)) 161 return(i); 162 163 if (!b->init) 164 { 165 BIOerr(BIO_F_BIO_READ,BIO_R_UNINITALISED); 166 return(-2); 167 } 168 169 i=b->method->bread(b,out,outl); 170 if (i > 0) b->num_read+=(unsigned long)i; 171 172 if (cb != NULL) 173 i=(int)cb(b,BIO_CB_READ|BIO_CB_RETURN,out,outl, 174 0L,(long)i); 175 return(i); 176 } 177 178 int BIO_write(b,in,inl) 179 BIO *b; 180 char *in; 181 int inl; 182 { 183 int i; 184 long (*cb)(); 185 186 if (b == NULL) 187 return(0); 188 189 cb=b->callback; 190 if ((b->method == NULL) || (b->method->bwrite == NULL)) 191 { 192 BIOerr(BIO_F_BIO_WRITE,BIO_R_UNSUPPORTED_METHOD); 193 return(-2); 194 } 195 196 if ((cb != NULL) && 197 ((i=(int)cb(b,BIO_CB_WRITE,in,inl,0L,1L)) <= 0)) 198 return(i); 199 200 if (!b->init) 201 { 202 BIOerr(BIO_F_BIO_WRITE,BIO_R_UNINITALISED); 203 return(-2); 204 } 205 206 i=b->method->bwrite(b,in,inl); 207 if (i > 0) b->num_write+=(unsigned long)i; 208 209 if (cb != NULL) 210 i=(int)cb(b,BIO_CB_WRITE|BIO_CB_RETURN,in,inl, 211 0L,(long)i); 212 return(i); 213 } 214 215 int BIO_puts(b,in) 216 BIO *b; 217 char *in; 218 { 219 int i; 220 long (*cb)(); 221 222 if ((b == NULL) || (b->method == NULL) || (b->method->bputs == NULL)) 223 { 224 BIOerr(BIO_F_BIO_PUTS,BIO_R_UNSUPPORTED_METHOD); 225 return(-2); 226 } 227 228 cb=b->callback; 229 230 if ((cb != NULL) && 231 ((i=(int)cb(b,BIO_CB_PUTS,in,0,0L,1L)) <= 0)) 232 return(i); 233 234 if (!b->init) 235 { 236 BIOerr(BIO_F_BIO_PUTS,BIO_R_UNINITALISED); 237 return(-2); 238 } 239 240 i=b->method->bputs(b,in); 241 242 if (cb != NULL) 243 i=(int)cb(b,BIO_CB_PUTS|BIO_CB_RETURN,in,0, 244 0L,(long)i); 245 return(i); 246 } 247 248 int BIO_gets(b,in,inl) 249 BIO *b; 250 char *in; 251 int inl; 252 { 253 int i; 254 long (*cb)(); 255 256 if ((b == NULL) || (b->method == NULL) || (b->method->bgets == NULL)) 257 { 258 BIOerr(BIO_F_BIO_GETS,BIO_R_UNSUPPORTED_METHOD); 259 return(-2); 260 } 261 262 cb=b->callback; 263 264 if ((cb != NULL) && 265 ((i=(int)cb(b,BIO_CB_GETS,in,inl,0L,1L)) <= 0)) 266 return(i); 267 268 if (!b->init) 269 { 270 BIOerr(BIO_F_BIO_GETS,BIO_R_UNINITALISED); 271 return(-2); 272 } 273 274 i=b->method->bgets(b,in,inl); 275 276 if (cb != NULL) 277 i=(int)cb(b,BIO_CB_GETS|BIO_CB_RETURN,in,inl, 278 0L,(long)i); 279 return(i); 280 } 281 282 long BIO_int_ctrl(b,cmd,larg,iarg) 283 BIO *b; 284 int cmd; 285 long larg; 286 int iarg; 287 { 288 int i; 289 290 i=iarg; 291 return(BIO_ctrl(b,cmd,larg,(char *)&i)); 292 } 293 294 char *BIO_ptr_ctrl(b,cmd,larg) 295 BIO *b; 296 int cmd; 297 long larg; 298 { 299 char *p=NULL; 300 301 if (BIO_ctrl(b,cmd,larg,(char *)&p) <= 0) 302 return(NULL); 303 else 304 return(p); 305 } 306 307 long BIO_ctrl(b,cmd,larg,parg) 308 BIO *b; 309 int cmd; 310 long larg; 311 char *parg; 312 { 313 long ret; 314 long (*cb)(); 315 316 if (b == NULL) return(0); 317 318 if ((b->method == NULL) || (b->method->ctrl == NULL)) 319 { 320 BIOerr(BIO_F_BIO_CTRL,BIO_R_UNSUPPORTED_METHOD); 321 return(-2); 322 } 323 324 cb=b->callback; 325 326 if ((cb != NULL) && 327 ((ret=cb(b,BIO_CB_CTRL,parg,cmd,larg,1L)) <= 0)) 328 return(ret); 329 330 ret=b->method->ctrl(b,cmd,larg,parg); 331 332 if (cb != NULL) 333 ret=cb(b,BIO_CB_CTRL|BIO_CB_RETURN,parg,cmd, 334 larg,ret); 335 return(ret); 336 } 337 338 /* put the 'bio' on the end of b's list of operators */ 339 BIO *BIO_push(b,bio) 340 BIO *b,*bio; 341 { 342 BIO *lb; 343 344 if (b == NULL) return(bio); 345 lb=b; 346 while (lb->next_bio != NULL) 347 lb=lb->next_bio; 348 lb->next_bio=bio; 349 if (bio != NULL) 350 bio->prev_bio=lb; 351 /* called to do internal processing */ 352 BIO_ctrl(b,BIO_CTRL_PUSH,0,NULL); 353 return(b); 354 } 355 356 /* Remove the first and return the rest */ 357 BIO *BIO_pop(b) 358 BIO *b; 359 { 360 BIO *ret; 361 362 if (b == NULL) return(NULL); 363 ret=b->next_bio; 364 365 if (b->prev_bio != NULL) 366 b->prev_bio->next_bio=b->next_bio; 367 if (b->next_bio != NULL) 368 b->next_bio->prev_bio=b->prev_bio; 369 370 b->next_bio=NULL; 371 b->prev_bio=NULL; 372 BIO_ctrl(b,BIO_CTRL_POP,0,NULL); 373 return(ret); 374 } 375 376 BIO *BIO_get_retry_BIO(bio,reason) 377 BIO *bio; 378 int *reason; 379 { 380 BIO *b,*last; 381 382 b=last=bio; 383 for (;;) 384 { 385 if (!BIO_should_retry(b)) break; 386 last=b; 387 b=b->next_bio; 388 if (b == NULL) break; 389 } 390 if (reason != NULL) *reason=last->retry_reason; 391 return(last); 392 } 393 394 int BIO_get_retry_reason(bio) 395 BIO *bio; 396 { 397 return(bio->retry_reason); 398 } 399 400 BIO *BIO_find_type(bio,type) 401 BIO *bio; 402 int type; 403 { 404 int mt,mask; 405 406 mask=type&0xff; 407 do { 408 if (bio->method != NULL) 409 { 410 mt=bio->method->type; 411 412 if (!mask) 413 { 414 if (mt & type) return(bio); 415 } 416 else if (mt == type) 417 return(bio); 418 } 419 bio=bio->next_bio; 420 } while (bio != NULL); 421 return(NULL); 422 } 423 424 void BIO_free_all(bio) 425 BIO *bio; 426 { 427 BIO *b; 428 int ref; 429 430 while (bio != NULL) 431 { 432 b=bio; 433 ref=b->references; 434 bio=bio->next_bio; 435 BIO_free(b); 436 /* Since ref count > 1, don't free anyone else. */ 437 if (ref > 1) break; 438 } 439 } 440 441 BIO *BIO_dup_chain(in) 442 BIO *in; 443 { 444 BIO *ret=NULL,*eoc=NULL,*bio,*new; 445 446 for (bio=in; bio != NULL; bio=bio->next_bio) 447 { 448 if ((new=BIO_new(bio->method)) == NULL) goto err; 449 new->callback=bio->callback; 450 new->cb_arg=bio->cb_arg; 451 new->init=bio->init; 452 new->shutdown=bio->shutdown; 453 new->flags=bio->flags; 454 455 /* This will let SSL_s_sock() work with stdin/stdout */ 456 new->num=bio->num; 457 458 if (!BIO_dup_state(bio,(char *)new)) 459 { 460 BIO_free(new); 461 goto err; 462 } 463 464 /* copy app data */ 465 if (!CRYPTO_dup_ex_data(bio_meth,&new->ex_data,&bio->ex_data)) 466 goto err; 467 468 if (ret == NULL) 469 { 470 eoc=new; 471 ret=eoc; 472 } 473 else 474 { 475 BIO_push(eoc,new); 476 eoc=new; 477 } 478 } 479 return(ret); 480 err: 481 if (ret != NULL) 482 BIO_free(ret); 483 return(NULL); 484 } 485 486 void BIO_copy_next_retry(b) 487 BIO *b; 488 { 489 BIO_set_flags(b,BIO_get_retry_flags(b->next_bio)); 490 b->retry_reason=b->next_bio->retry_reason; 491 } 492 493 int BIO_get_ex_new_index(argl,argp,new_func,dup_func,free_func) 494 long argl; 495 char *argp; 496 int (*new_func)(); 497 int (*dup_func)(); 498 void (*free_func)(); 499 { 500 bio_meth_num++; 501 return(CRYPTO_get_ex_new_index(bio_meth_num-1,&bio_meth, 502 argl,argp,new_func,dup_func,free_func)); 503 } 504 505 int BIO_set_ex_data(bio,idx,data) 506 BIO *bio; 507 int idx; 508 char *data; 509 { 510 return(CRYPTO_set_ex_data(&(bio->ex_data),idx,data)); 511 } 512 513 char *BIO_get_ex_data(bio,idx) 514 BIO *bio; 515 int idx; 516 { 517 return(CRYPTO_get_ex_data(&(bio->ex_data),idx)); 518 } 519 520