1 /* $OpenBSD: bss_conn.c,v 1.31 2014/11/21 18:15:40 deraadt Exp $ */ 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 <sys/socket.h> 60 61 #include <netinet/in.h> 62 63 #include <errno.h> 64 #include <netdb.h> 65 #include <stdio.h> 66 #include <string.h> 67 #include <unistd.h> 68 69 #include <openssl/bio.h> 70 #include <openssl/buffer.h> 71 #include <openssl/err.h> 72 73 #define SOCKET_PROTOCOL IPPROTO_TCP 74 75 typedef struct bio_connect_st { 76 int state; 77 78 char *param_hostname; 79 char *param_port; 80 int nbio; 81 82 unsigned char ip[4]; 83 unsigned short port; 84 85 struct sockaddr_in them; 86 87 /* int socket; this will be kept in bio->num so that it is 88 * compatible with the bss_sock bio */ 89 90 /* called when the connection is initially made 91 * callback(BIO,state,ret); The callback should return 92 * 'ret'. state is for compatibility with the ssl info_callback */ 93 int (*info_callback)(const BIO *bio, int state, int ret); 94 } BIO_CONNECT; 95 96 static int conn_write(BIO *h, const char *buf, int num); 97 static int conn_read(BIO *h, char *buf, int size); 98 static int conn_puts(BIO *h, const char *str); 99 static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2); 100 static int conn_new(BIO *h); 101 static int conn_free(BIO *data); 102 static long conn_callback_ctrl(BIO *h, int cmd, bio_info_cb *); 103 104 static int conn_state(BIO *b, BIO_CONNECT *c); 105 static void conn_close_socket(BIO *data); 106 BIO_CONNECT *BIO_CONNECT_new(void); 107 void BIO_CONNECT_free(BIO_CONNECT *a); 108 109 static BIO_METHOD methods_connectp = { 110 .type = BIO_TYPE_CONNECT, 111 .name = "socket connect", 112 .bwrite = conn_write, 113 .bread = conn_read, 114 .bputs = conn_puts, 115 .ctrl = conn_ctrl, 116 .create = conn_new, 117 .destroy = conn_free, 118 .callback_ctrl = conn_callback_ctrl 119 }; 120 121 static int 122 conn_state(BIO *b, BIO_CONNECT *c) 123 { 124 int ret = -1, i; 125 unsigned long l; 126 char *p, *q; 127 int (*cb)(const BIO *, int, int) = NULL; 128 129 if (c->info_callback != NULL) 130 cb = c->info_callback; 131 132 for (;;) { 133 switch (c->state) { 134 case BIO_CONN_S_BEFORE: 135 p = c->param_hostname; 136 if (p == NULL) { 137 BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_SPECIFIED); 138 goto exit_loop; 139 } 140 for (; *p != '\0'; p++) { 141 if ((*p == ':') || (*p == '/')) 142 break; 143 } 144 145 i= *p; 146 if ((i == ':') || (i == '/')) { 147 *(p++) = '\0'; 148 if (i == ':') { 149 for (q = p; *q; q++) 150 if (*q == '/') { 151 *q = '\0'; 152 break; 153 } 154 free(c->param_port); 155 c->param_port = strdup(p); 156 } 157 } 158 159 if (c->param_port == NULL) { 160 BIOerr(BIO_F_CONN_STATE, BIO_R_NO_PORT_SPECIFIED); 161 ERR_asprintf_error_data("host=%s", 162 c->param_hostname); 163 goto exit_loop; 164 } 165 c->state = BIO_CONN_S_GET_IP; 166 break; 167 168 case BIO_CONN_S_GET_IP: 169 if (BIO_get_host_ip(c->param_hostname, &(c->ip[0])) <= 0) 170 goto exit_loop; 171 c->state = BIO_CONN_S_GET_PORT; 172 break; 173 174 case BIO_CONN_S_GET_PORT: 175 if (c->param_port == NULL) { 176 /* abort(); */ 177 goto exit_loop; 178 } else if (BIO_get_port(c->param_port, &c->port) <= 0) 179 goto exit_loop; 180 c->state = BIO_CONN_S_CREATE_SOCKET; 181 break; 182 183 case BIO_CONN_S_CREATE_SOCKET: 184 /* now setup address */ 185 memset((char *)&c->them, 0, sizeof(c->them)); 186 c->them.sin_family = AF_INET; 187 c->them.sin_port = htons((unsigned short)c->port); 188 l = (unsigned long) 189 ((unsigned long)c->ip[0] << 24L)| 190 ((unsigned long)c->ip[1] << 16L)| 191 ((unsigned long)c->ip[2] << 8L)| 192 ((unsigned long)c->ip[3]); 193 c->them.sin_addr.s_addr = htonl(l); 194 c->state = BIO_CONN_S_CREATE_SOCKET; 195 196 ret = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); 197 if (ret == -1) { 198 SYSerr(SYS_F_SOCKET, errno); 199 ERR_asprintf_error_data("host=%s:%s", 200 c->param_hostname, c->param_port); 201 BIOerr(BIO_F_CONN_STATE, 202 BIO_R_UNABLE_TO_CREATE_SOCKET); 203 goto exit_loop; 204 } 205 b->num = ret; 206 c->state = BIO_CONN_S_NBIO; 207 break; 208 209 case BIO_CONN_S_NBIO: 210 if (c->nbio) { 211 if (!BIO_socket_nbio(b->num, 1)) { 212 BIOerr(BIO_F_CONN_STATE, 213 BIO_R_ERROR_SETTING_NBIO); 214 ERR_asprintf_error_data("host=%s:%s", 215 c->param_hostname, c->param_port); 216 goto exit_loop; 217 } 218 } 219 c->state = BIO_CONN_S_CONNECT; 220 221 #if defined(SO_KEEPALIVE) 222 i = 1; 223 i = setsockopt(b->num, SOL_SOCKET, SO_KEEPALIVE, &i, sizeof(i)); 224 if (i < 0) { 225 SYSerr(SYS_F_SOCKET, errno); 226 ERR_asprintf_error_data("host=%s:%s", 227 c->param_hostname, c->param_port); 228 BIOerr(BIO_F_CONN_STATE, BIO_R_KEEPALIVE); 229 goto exit_loop; 230 } 231 #endif 232 break; 233 234 case BIO_CONN_S_CONNECT: 235 BIO_clear_retry_flags(b); 236 ret = connect(b->num, 237 (struct sockaddr *)&c->them, 238 sizeof(c->them)); 239 b->retry_reason = 0; 240 if (ret < 0) { 241 if (BIO_sock_should_retry(ret)) { 242 BIO_set_retry_special(b); 243 c->state = BIO_CONN_S_BLOCKED_CONNECT; 244 b->retry_reason = BIO_RR_CONNECT; 245 } else { 246 SYSerr(SYS_F_CONNECT, errno); 247 ERR_asprintf_error_data("host=%s:%s", 248 c->param_hostname, c->param_port); 249 BIOerr(BIO_F_CONN_STATE, 250 BIO_R_CONNECT_ERROR); 251 } 252 goto exit_loop; 253 } else 254 c->state = BIO_CONN_S_OK; 255 break; 256 257 case BIO_CONN_S_BLOCKED_CONNECT: 258 i = BIO_sock_error(b->num); 259 if (i) { 260 BIO_clear_retry_flags(b); 261 SYSerr(SYS_F_CONNECT, i); 262 ERR_asprintf_error_data("host=%s:%s", 263 c->param_hostname, c->param_port); 264 BIOerr(BIO_F_CONN_STATE, 265 BIO_R_NBIO_CONNECT_ERROR); 266 ret = 0; 267 goto exit_loop; 268 } else 269 c->state = BIO_CONN_S_OK; 270 break; 271 272 case BIO_CONN_S_OK: 273 ret = 1; 274 goto exit_loop; 275 default: 276 /* abort(); */ 277 goto exit_loop; 278 } 279 280 if (cb != NULL) { 281 if (!(ret = cb((BIO *)b, c->state, ret))) 282 goto end; 283 } 284 } 285 286 /* Loop does not exit */ 287 exit_loop: 288 if (cb != NULL) 289 ret = cb((BIO *)b, c->state, ret); 290 end: 291 return (ret); 292 } 293 294 BIO_CONNECT * 295 BIO_CONNECT_new(void) 296 { 297 BIO_CONNECT *ret; 298 299 if ((ret = malloc(sizeof(BIO_CONNECT))) == NULL) 300 return (NULL); 301 ret->state = BIO_CONN_S_BEFORE; 302 ret->param_hostname = NULL; 303 ret->param_port = NULL; 304 ret->info_callback = NULL; 305 ret->nbio = 0; 306 ret->ip[0] = 0; 307 ret->ip[1] = 0; 308 ret->ip[2] = 0; 309 ret->ip[3] = 0; 310 ret->port = 0; 311 memset((char *)&ret->them, 0, sizeof(ret->them)); 312 return (ret); 313 } 314 315 void 316 BIO_CONNECT_free(BIO_CONNECT *a) 317 { 318 if (a == NULL) 319 return; 320 321 free(a->param_hostname); 322 free(a->param_port); 323 free(a); 324 } 325 326 BIO_METHOD * 327 BIO_s_connect(void) 328 { 329 return (&methods_connectp); 330 } 331 332 static int 333 conn_new(BIO *bi) 334 { 335 bi->init = 0; 336 bi->num = -1; 337 bi->flags = 0; 338 if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL) 339 return (0); 340 else 341 return (1); 342 } 343 344 static void 345 conn_close_socket(BIO *bio) 346 { 347 BIO_CONNECT *c; 348 349 c = (BIO_CONNECT *)bio->ptr; 350 if (bio->num != -1) { 351 /* Only do a shutdown if things were established */ 352 if (c->state == BIO_CONN_S_OK) 353 shutdown(bio->num, SHUT_RDWR); 354 close(bio->num); 355 bio->num = -1; 356 } 357 } 358 359 static int 360 conn_free(BIO *a) 361 { 362 BIO_CONNECT *data; 363 364 if (a == NULL) 365 return (0); 366 data = (BIO_CONNECT *)a->ptr; 367 368 if (a->shutdown) { 369 conn_close_socket(a); 370 BIO_CONNECT_free(data); 371 a->ptr = NULL; 372 a->flags = 0; 373 a->init = 0; 374 } 375 return (1); 376 } 377 378 static int 379 conn_read(BIO *b, char *out, int outl) 380 { 381 int ret = 0; 382 BIO_CONNECT *data; 383 384 data = (BIO_CONNECT *)b->ptr; 385 if (data->state != BIO_CONN_S_OK) { 386 ret = conn_state(b, data); 387 if (ret <= 0) 388 return (ret); 389 } 390 391 if (out != NULL) { 392 errno = 0; 393 ret = read(b->num, out, outl); 394 BIO_clear_retry_flags(b); 395 if (ret <= 0) { 396 if (BIO_sock_should_retry(ret)) 397 BIO_set_retry_read(b); 398 } 399 } 400 return (ret); 401 } 402 403 static int 404 conn_write(BIO *b, const char *in, int inl) 405 { 406 int ret; 407 BIO_CONNECT *data; 408 409 data = (BIO_CONNECT *)b->ptr; 410 if (data->state != BIO_CONN_S_OK) { 411 ret = conn_state(b, data); 412 if (ret <= 0) 413 return (ret); 414 } 415 416 errno = 0; 417 ret = write(b->num, in, inl); 418 BIO_clear_retry_flags(b); 419 if (ret <= 0) { 420 if (BIO_sock_should_retry(ret)) 421 BIO_set_retry_write(b); 422 } 423 return (ret); 424 } 425 426 static long 427 conn_ctrl(BIO *b, int cmd, long num, void *ptr) 428 { 429 BIO *dbio; 430 int *ip; 431 const char **pptr; 432 long ret = 1; 433 BIO_CONNECT *data; 434 435 data = (BIO_CONNECT *)b->ptr; 436 437 switch (cmd) { 438 case BIO_CTRL_RESET: 439 ret = 0; 440 data->state = BIO_CONN_S_BEFORE; 441 conn_close_socket(b); 442 b->flags = 0; 443 break; 444 case BIO_C_DO_STATE_MACHINE: 445 /* use this one to start the connection */ 446 if (data->state != BIO_CONN_S_OK) 447 ret = (long)conn_state(b, data); 448 else 449 ret = 1; 450 break; 451 case BIO_C_GET_CONNECT: 452 if (ptr != NULL) { 453 pptr = (const char **)ptr; 454 if (num == 0) { 455 *pptr = data->param_hostname; 456 457 } else if (num == 1) { 458 *pptr = data->param_port; 459 } else if (num == 2) { 460 *pptr = (char *)&(data->ip[0]); 461 } else if (num == 3) { 462 *((int *)ptr) = data->port; 463 } 464 if ((!b->init) || (ptr == NULL)) 465 *pptr = "not initialized"; 466 ret = 1; 467 } 468 break; 469 case BIO_C_SET_CONNECT: 470 if (ptr != NULL) { 471 b->init = 1; 472 if (num == 0) { 473 free(data->param_hostname); 474 data->param_hostname = strdup(ptr); 475 } else if (num == 1) { 476 free(data->param_port); 477 data->param_port = strdup(ptr); 478 } else if (num == 2) { 479 unsigned char *p = ptr; 480 free(data->param_hostname); 481 if (asprintf(&data->param_hostname, 482 "%u.%u.%u.%u", p[0], p[1], 483 p[2], p[3]) == -1) 484 data->param_hostname = NULL; 485 memcpy(&(data->ip[0]), ptr, 4); 486 } else if (num == 3) { 487 free(data->param_port); 488 data->port= *(int *)ptr; 489 if (asprintf(&data->param_port, "%d", 490 data->port) == -1) 491 data->param_port = NULL; 492 } 493 } 494 break; 495 case BIO_C_SET_NBIO: 496 data->nbio = (int)num; 497 break; 498 case BIO_C_GET_FD: 499 if (b->init) { 500 ip = (int *)ptr; 501 if (ip != NULL) 502 *ip = b->num; 503 ret = b->num; 504 } else 505 ret = -1; 506 break; 507 case BIO_CTRL_GET_CLOSE: 508 ret = b->shutdown; 509 break; 510 case BIO_CTRL_SET_CLOSE: 511 b->shutdown = (int)num; 512 break; 513 case BIO_CTRL_PENDING: 514 case BIO_CTRL_WPENDING: 515 ret = 0; 516 break; 517 case BIO_CTRL_FLUSH: 518 break; 519 case BIO_CTRL_DUP: 520 { 521 dbio = (BIO *)ptr; 522 if (data->param_port) 523 BIO_set_conn_port(dbio, data->param_port); 524 if (data->param_hostname) 525 BIO_set_conn_hostname(dbio, 526 data->param_hostname); 527 BIO_set_nbio(dbio, data->nbio); 528 /* FIXME: the cast of the function seems unlikely to be a good idea */ 529 (void)BIO_set_info_callback(dbio, 530 (bio_info_cb *)data->info_callback); 531 } 532 break; 533 case BIO_CTRL_SET_CALLBACK: 534 { 535 #if 0 /* FIXME: Should this be used? -- Richard Levitte */ 536 BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 537 ret = -1; 538 #else 539 ret = 0; 540 #endif 541 } 542 break; 543 case BIO_CTRL_GET_CALLBACK: 544 { 545 int (**fptr)(const BIO *bio, int state, int xret); 546 547 fptr = (int (**)(const BIO *bio, int state, int xret))ptr; 548 *fptr = data->info_callback; 549 } 550 break; 551 default: 552 ret = 0; 553 break; 554 } 555 return (ret); 556 } 557 558 static long 559 conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 560 { 561 long ret = 1; 562 BIO_CONNECT *data; 563 564 data = (BIO_CONNECT *)b->ptr; 565 566 switch (cmd) { 567 case BIO_CTRL_SET_CALLBACK: 568 { 569 data->info_callback = (int (*)(const struct bio_st *, int, int))fp; 570 } 571 break; 572 default: 573 ret = 0; 574 break; 575 } 576 return (ret); 577 } 578 579 static int 580 conn_puts(BIO *bp, const char *str) 581 { 582 int n, ret; 583 584 n = strlen(str); 585 ret = conn_write(bp, str, n); 586 return (ret); 587 } 588 589 BIO * 590 BIO_new_connect(char *str) 591 { 592 BIO *ret; 593 594 ret = BIO_new(BIO_s_connect()); 595 if (ret == NULL) 596 return (NULL); 597 if (BIO_set_conn_hostname(ret, str)) 598 return (ret); 599 else { 600 BIO_free(ret); 601 return (NULL); 602 } 603 } 604 605