1 /* $OpenBSD: bss_acpt.c,v 1.25 2014/07/25 06:05:32 doug 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 <errno.h> 62 #include <stdio.h> 63 #include <string.h> 64 #include <unistd.h> 65 66 #include <openssl/bio.h> 67 #include <openssl/buffer.h> 68 #include <openssl/err.h> 69 70 #define SOCKET_PROTOCOL IPPROTO_TCP 71 72 typedef struct bio_accept_st { 73 int state; 74 char *param_addr; 75 76 int accept_sock; 77 int accept_nbio; 78 79 char *addr; 80 int nbio; 81 /* If 0, it means normal, if 1, do a connect on bind failure, 82 * and if there is no-one listening, bind with SO_REUSEADDR. 83 * If 2, always use SO_REUSEADDR. */ 84 int bind_mode; 85 BIO *bio_chain; 86 } BIO_ACCEPT; 87 88 static int acpt_write(BIO *h, const char *buf, int num); 89 static int acpt_read(BIO *h, char *buf, int size); 90 static int acpt_puts(BIO *h, const char *str); 91 static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2); 92 static int acpt_new(BIO *h); 93 static int acpt_free(BIO *data); 94 static int acpt_state(BIO *b, BIO_ACCEPT *c); 95 static void acpt_close_socket(BIO *data); 96 static BIO_ACCEPT *BIO_ACCEPT_new(void ); 97 static void BIO_ACCEPT_free(BIO_ACCEPT *a); 98 99 #define ACPT_S_BEFORE 1 100 #define ACPT_S_GET_ACCEPT_SOCKET 2 101 #define ACPT_S_OK 3 102 103 static BIO_METHOD methods_acceptp = { 104 .type = BIO_TYPE_ACCEPT, 105 .name = "socket accept", 106 .bwrite = acpt_write, 107 .bread = acpt_read, 108 .bputs = acpt_puts, 109 .ctrl = acpt_ctrl, 110 .create = acpt_new, 111 .destroy = acpt_free 112 }; 113 114 BIO_METHOD * 115 BIO_s_accept(void) 116 { 117 return (&methods_acceptp); 118 } 119 120 static int 121 acpt_new(BIO *bi) 122 { 123 BIO_ACCEPT *ba; 124 125 bi->init = 0; 126 bi->num = -1; 127 bi->flags = 0; 128 if ((ba = BIO_ACCEPT_new()) == NULL) 129 return (0); 130 bi->ptr = (char *)ba; 131 ba->state = ACPT_S_BEFORE; 132 bi->shutdown = 1; 133 return (1); 134 } 135 136 static BIO_ACCEPT * 137 BIO_ACCEPT_new(void) 138 { 139 BIO_ACCEPT *ret; 140 141 if ((ret = calloc(1, sizeof(BIO_ACCEPT))) == NULL) 142 return (NULL); 143 ret->accept_sock = -1; 144 ret->bind_mode = BIO_BIND_NORMAL; 145 return (ret); 146 } 147 148 static void 149 BIO_ACCEPT_free(BIO_ACCEPT *a) 150 { 151 if (a == NULL) 152 return; 153 154 free(a->param_addr); 155 free(a->addr); 156 BIO_free(a->bio_chain); 157 free(a); 158 } 159 160 static void 161 acpt_close_socket(BIO *bio) 162 { 163 BIO_ACCEPT *c; 164 165 c = (BIO_ACCEPT *)bio->ptr; 166 if (c->accept_sock != -1) { 167 shutdown(c->accept_sock, SHUT_RDWR); 168 close(c->accept_sock); 169 c->accept_sock = -1; 170 bio->num = -1; 171 } 172 } 173 174 static int 175 acpt_free(BIO *a) 176 { 177 BIO_ACCEPT *data; 178 179 if (a == NULL) 180 return (0); 181 data = (BIO_ACCEPT *)a->ptr; 182 183 if (a->shutdown) { 184 acpt_close_socket(a); 185 BIO_ACCEPT_free(data); 186 a->ptr = NULL; 187 a->flags = 0; 188 a->init = 0; 189 } 190 return (1); 191 } 192 193 static int 194 acpt_state(BIO *b, BIO_ACCEPT *c) 195 { 196 BIO *bio = NULL, *dbio; 197 int s = -1; 198 int i; 199 200 again: 201 switch (c->state) { 202 case ACPT_S_BEFORE: 203 if (c->param_addr == NULL) { 204 BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_PORT_SPECIFIED); 205 return (-1); 206 } 207 s = BIO_get_accept_socket(c->param_addr, c->bind_mode); 208 if (s == -1) 209 return (-1); 210 211 if (c->accept_nbio) { 212 if (!BIO_socket_nbio(s, 1)) { 213 close(s); 214 BIOerr(BIO_F_ACPT_STATE, BIO_R_ERROR_SETTING_NBIO_ON_ACCEPT_SOCKET); 215 return (-1); 216 } 217 } 218 c->accept_sock = s; 219 b->num = s; 220 c->state = ACPT_S_GET_ACCEPT_SOCKET; 221 return (1); 222 /* break; */ 223 case ACPT_S_GET_ACCEPT_SOCKET: 224 if (b->next_bio != NULL) { 225 c->state = ACPT_S_OK; 226 goto again; 227 } 228 BIO_clear_retry_flags(b); 229 b->retry_reason = 0; 230 i = BIO_accept(c->accept_sock, &(c->addr)); 231 232 /* -2 return means we should retry */ 233 if (i == -2) { 234 BIO_set_retry_special(b); 235 b->retry_reason = BIO_RR_ACCEPT; 236 return -1; 237 } 238 239 if (i < 0) 240 return (i); 241 242 bio = BIO_new_socket(i, BIO_CLOSE); 243 if (bio == NULL) 244 goto err; 245 246 BIO_set_callback(bio, BIO_get_callback(b)); 247 BIO_set_callback_arg(bio, BIO_get_callback_arg(b)); 248 249 if (c->nbio) { 250 if (!BIO_socket_nbio(i, 1)) { 251 BIOerr(BIO_F_ACPT_STATE, BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET); 252 goto err; 253 } 254 } 255 256 /* If the accept BIO has an bio_chain, we dup it and 257 * put the new socket at the end. */ 258 if (c->bio_chain != NULL) { 259 if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL) 260 goto err; 261 if (!BIO_push(dbio, bio)) goto err; 262 bio = dbio; 263 } 264 if (BIO_push(b, bio) 265 == NULL) goto err; 266 267 c->state = ACPT_S_OK; 268 return (1); 269 270 err: 271 if (bio != NULL) 272 BIO_free(bio); 273 else if (s >= 0) 274 close(s); 275 return (0); 276 /* break; */ 277 case ACPT_S_OK: 278 if (b->next_bio == NULL) { 279 c->state = ACPT_S_GET_ACCEPT_SOCKET; 280 goto again; 281 } 282 return (1); 283 /* break; */ 284 default: 285 return (0); 286 /* break; */ 287 } 288 } 289 290 static int 291 acpt_read(BIO *b, char *out, int outl) 292 { 293 int ret = 0; 294 BIO_ACCEPT *data; 295 296 BIO_clear_retry_flags(b); 297 data = (BIO_ACCEPT *)b->ptr; 298 299 while (b->next_bio == NULL) { 300 ret = acpt_state(b, data); 301 if (ret <= 0) 302 return (ret); 303 } 304 305 ret = BIO_read(b->next_bio, out, outl); 306 BIO_copy_next_retry(b); 307 return (ret); 308 } 309 310 static int 311 acpt_write(BIO *b, const char *in, int inl) 312 { 313 int ret; 314 BIO_ACCEPT *data; 315 316 BIO_clear_retry_flags(b); 317 data = (BIO_ACCEPT *)b->ptr; 318 319 while (b->next_bio == NULL) { 320 ret = acpt_state(b, data); 321 if (ret <= 0) 322 return (ret); 323 } 324 325 ret = BIO_write(b->next_bio, in, inl); 326 BIO_copy_next_retry(b); 327 return (ret); 328 } 329 330 static long 331 acpt_ctrl(BIO *b, int cmd, long num, void *ptr) 332 { 333 int *ip; 334 long ret = 1; 335 BIO_ACCEPT *data; 336 char **pp; 337 338 data = (BIO_ACCEPT *)b->ptr; 339 340 switch (cmd) { 341 case BIO_CTRL_RESET: 342 ret = 0; 343 data->state = ACPT_S_BEFORE; 344 acpt_close_socket(b); 345 b->flags = 0; 346 break; 347 case BIO_C_DO_STATE_MACHINE: 348 /* use this one to start the connection */ 349 ret = (long)acpt_state(b, data); 350 break; 351 case BIO_C_SET_ACCEPT: 352 if (ptr != NULL) { 353 if (num == 0) { 354 b->init = 1; 355 free(data->param_addr); 356 data->param_addr = strdup(ptr); 357 } else if (num == 1) { 358 data->accept_nbio = (ptr != NULL); 359 } else if (num == 2) { 360 BIO_free(data->bio_chain); 361 data->bio_chain = (BIO *)ptr; 362 } 363 } 364 break; 365 case BIO_C_SET_NBIO: 366 data->nbio = (int)num; 367 break; 368 case BIO_C_SET_FD: 369 b->init = 1; 370 b->num= *((int *)ptr); 371 data->accept_sock = b->num; 372 data->state = ACPT_S_GET_ACCEPT_SOCKET; 373 b->shutdown = (int)num; 374 b->init = 1; 375 break; 376 case BIO_C_GET_FD: 377 if (b->init) { 378 ip = (int *)ptr; 379 if (ip != NULL) 380 *ip = data->accept_sock; 381 ret = data->accept_sock; 382 } else 383 ret = -1; 384 break; 385 case BIO_C_GET_ACCEPT: 386 if (b->init) { 387 if (ptr != NULL) { 388 pp = (char **)ptr; 389 *pp = data->param_addr; 390 } else 391 ret = -1; 392 } else 393 ret = -1; 394 break; 395 case BIO_CTRL_GET_CLOSE: 396 ret = b->shutdown; 397 break; 398 case BIO_CTRL_SET_CLOSE: 399 b->shutdown = (int)num; 400 break; 401 case BIO_CTRL_PENDING: 402 case BIO_CTRL_WPENDING: 403 ret = 0; 404 break; 405 case BIO_CTRL_FLUSH: 406 break; 407 case BIO_C_SET_BIND_MODE: 408 data->bind_mode = (int)num; 409 break; 410 case BIO_C_GET_BIND_MODE: 411 ret = (long)data->bind_mode; 412 break; 413 case BIO_CTRL_DUP: 414 /* dbio=(BIO *)ptr; 415 if (data->param_port) EAY EAY 416 BIO_set_port(dbio,data->param_port); 417 if (data->param_hostname) 418 BIO_set_hostname(dbio,data->param_hostname); 419 BIO_set_nbio(dbio,data->nbio); 420 */ 421 break; 422 423 default: 424 ret = 0; 425 break; 426 } 427 return (ret); 428 } 429 430 static int 431 acpt_puts(BIO *bp, const char *str) 432 { 433 int n, ret; 434 435 n = strlen(str); 436 ret = acpt_write(bp, str, n); 437 return (ret); 438 } 439 440 BIO * 441 BIO_new_accept(char *str) 442 { 443 BIO *ret; 444 445 ret = BIO_new(BIO_s_accept()); 446 if (ret == NULL) 447 return (NULL); 448 if (BIO_set_accept_port(ret, str)) 449 return (ret); 450 else { 451 BIO_free(ret); 452 return (NULL); 453 } 454 } 455 456