1 /* $OpenBSD: bss_acpt.c,v 1.24 2014/07/13 16:03:09 beck 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 if (a->bio_chain != NULL) 157 BIO_free(a->bio_chain); 158 free(a); 159 } 160 161 static void 162 acpt_close_socket(BIO *bio) 163 { 164 BIO_ACCEPT *c; 165 166 c = (BIO_ACCEPT *)bio->ptr; 167 if (c->accept_sock != -1) { 168 shutdown(c->accept_sock, SHUT_RDWR); 169 close(c->accept_sock); 170 c->accept_sock = -1; 171 bio->num = -1; 172 } 173 } 174 175 static int 176 acpt_free(BIO *a) 177 { 178 BIO_ACCEPT *data; 179 180 if (a == NULL) 181 return (0); 182 data = (BIO_ACCEPT *)a->ptr; 183 184 if (a->shutdown) { 185 acpt_close_socket(a); 186 BIO_ACCEPT_free(data); 187 a->ptr = NULL; 188 a->flags = 0; 189 a->init = 0; 190 } 191 return (1); 192 } 193 194 static int 195 acpt_state(BIO *b, BIO_ACCEPT *c) 196 { 197 BIO *bio = NULL, *dbio; 198 int s = -1; 199 int i; 200 201 again: 202 switch (c->state) { 203 case ACPT_S_BEFORE: 204 if (c->param_addr == NULL) { 205 BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_PORT_SPECIFIED); 206 return (-1); 207 } 208 s = BIO_get_accept_socket(c->param_addr, c->bind_mode); 209 if (s == -1) 210 return (-1); 211 212 if (c->accept_nbio) { 213 if (!BIO_socket_nbio(s, 1)) { 214 close(s); 215 BIOerr(BIO_F_ACPT_STATE, BIO_R_ERROR_SETTING_NBIO_ON_ACCEPT_SOCKET); 216 return (-1); 217 } 218 } 219 c->accept_sock = s; 220 b->num = s; 221 c->state = ACPT_S_GET_ACCEPT_SOCKET; 222 return (1); 223 /* break; */ 224 case ACPT_S_GET_ACCEPT_SOCKET: 225 if (b->next_bio != NULL) { 226 c->state = ACPT_S_OK; 227 goto again; 228 } 229 BIO_clear_retry_flags(b); 230 b->retry_reason = 0; 231 i = BIO_accept(c->accept_sock, &(c->addr)); 232 233 /* -2 return means we should retry */ 234 if (i == -2) { 235 BIO_set_retry_special(b); 236 b->retry_reason = BIO_RR_ACCEPT; 237 return -1; 238 } 239 240 if (i < 0) 241 return (i); 242 243 bio = BIO_new_socket(i, BIO_CLOSE); 244 if (bio == NULL) 245 goto err; 246 247 BIO_set_callback(bio, BIO_get_callback(b)); 248 BIO_set_callback_arg(bio, BIO_get_callback_arg(b)); 249 250 if (c->nbio) { 251 if (!BIO_socket_nbio(i, 1)) { 252 BIOerr(BIO_F_ACPT_STATE, BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET); 253 goto err; 254 } 255 } 256 257 /* If the accept BIO has an bio_chain, we dup it and 258 * put the new socket at the end. */ 259 if (c->bio_chain != NULL) { 260 if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL) 261 goto err; 262 if (!BIO_push(dbio, bio)) goto err; 263 bio = dbio; 264 } 265 if (BIO_push(b, bio) 266 == NULL) goto err; 267 268 c->state = ACPT_S_OK; 269 return (1); 270 271 err: 272 if (bio != NULL) 273 BIO_free(bio); 274 else if (s >= 0) 275 close(s); 276 return (0); 277 /* break; */ 278 case ACPT_S_OK: 279 if (b->next_bio == NULL) { 280 c->state = ACPT_S_GET_ACCEPT_SOCKET; 281 goto again; 282 } 283 return (1); 284 /* break; */ 285 default: 286 return (0); 287 /* break; */ 288 } 289 } 290 291 static int 292 acpt_read(BIO *b, char *out, int outl) 293 { 294 int ret = 0; 295 BIO_ACCEPT *data; 296 297 BIO_clear_retry_flags(b); 298 data = (BIO_ACCEPT *)b->ptr; 299 300 while (b->next_bio == NULL) { 301 ret = acpt_state(b, data); 302 if (ret <= 0) 303 return (ret); 304 } 305 306 ret = BIO_read(b->next_bio, out, outl); 307 BIO_copy_next_retry(b); 308 return (ret); 309 } 310 311 static int 312 acpt_write(BIO *b, const char *in, int inl) 313 { 314 int ret; 315 BIO_ACCEPT *data; 316 317 BIO_clear_retry_flags(b); 318 data = (BIO_ACCEPT *)b->ptr; 319 320 while (b->next_bio == NULL) { 321 ret = acpt_state(b, data); 322 if (ret <= 0) 323 return (ret); 324 } 325 326 ret = BIO_write(b->next_bio, in, inl); 327 BIO_copy_next_retry(b); 328 return (ret); 329 } 330 331 static long 332 acpt_ctrl(BIO *b, int cmd, long num, void *ptr) 333 { 334 int *ip; 335 long ret = 1; 336 BIO_ACCEPT *data; 337 char **pp; 338 339 data = (BIO_ACCEPT *)b->ptr; 340 341 switch (cmd) { 342 case BIO_CTRL_RESET: 343 ret = 0; 344 data->state = ACPT_S_BEFORE; 345 acpt_close_socket(b); 346 b->flags = 0; 347 break; 348 case BIO_C_DO_STATE_MACHINE: 349 /* use this one to start the connection */ 350 ret = (long)acpt_state(b, data); 351 break; 352 case BIO_C_SET_ACCEPT: 353 if (ptr != NULL) { 354 if (num == 0) { 355 b->init = 1; 356 free(data->param_addr); 357 data->param_addr = strdup(ptr); 358 } else if (num == 1) { 359 data->accept_nbio = (ptr != NULL); 360 } else if (num == 2) { 361 if (data->bio_chain != NULL) 362 BIO_free(data->bio_chain); 363 data->bio_chain = (BIO *)ptr; 364 } 365 } 366 break; 367 case BIO_C_SET_NBIO: 368 data->nbio = (int)num; 369 break; 370 case BIO_C_SET_FD: 371 b->init = 1; 372 b->num= *((int *)ptr); 373 data->accept_sock = b->num; 374 data->state = ACPT_S_GET_ACCEPT_SOCKET; 375 b->shutdown = (int)num; 376 b->init = 1; 377 break; 378 case BIO_C_GET_FD: 379 if (b->init) { 380 ip = (int *)ptr; 381 if (ip != NULL) 382 *ip = data->accept_sock; 383 ret = data->accept_sock; 384 } else 385 ret = -1; 386 break; 387 case BIO_C_GET_ACCEPT: 388 if (b->init) { 389 if (ptr != NULL) { 390 pp = (char **)ptr; 391 *pp = data->param_addr; 392 } else 393 ret = -1; 394 } else 395 ret = -1; 396 break; 397 case BIO_CTRL_GET_CLOSE: 398 ret = b->shutdown; 399 break; 400 case BIO_CTRL_SET_CLOSE: 401 b->shutdown = (int)num; 402 break; 403 case BIO_CTRL_PENDING: 404 case BIO_CTRL_WPENDING: 405 ret = 0; 406 break; 407 case BIO_CTRL_FLUSH: 408 break; 409 case BIO_C_SET_BIND_MODE: 410 data->bind_mode = (int)num; 411 break; 412 case BIO_C_GET_BIND_MODE: 413 ret = (long)data->bind_mode; 414 break; 415 case BIO_CTRL_DUP: 416 /* dbio=(BIO *)ptr; 417 if (data->param_port) EAY EAY 418 BIO_set_port(dbio,data->param_port); 419 if (data->param_hostname) 420 BIO_set_hostname(dbio,data->param_hostname); 421 BIO_set_nbio(dbio,data->nbio); 422 */ 423 break; 424 425 default: 426 ret = 0; 427 break; 428 } 429 return (ret); 430 } 431 432 static int 433 acpt_puts(BIO *bp, const char *str) 434 { 435 int n, ret; 436 437 n = strlen(str); 438 ret = acpt_write(bp, str, n); 439 return (ret); 440 } 441 442 BIO * 443 BIO_new_accept(char *str) 444 { 445 BIO *ret; 446 447 ret = BIO_new(BIO_s_accept()); 448 if (ret == NULL) 449 return (NULL); 450 if (BIO_set_accept_port(ret, str)) 451 return (ret); 452 else { 453 BIO_free(ret); 454 return (NULL); 455 } 456 } 457 458