1 /* $OpenBSD: bss_acpt.c,v 1.29 2018/05/12 18:51:59 tb 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 const 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 const 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 BIOerror(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 BIOerror(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 BIOerror(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 return (0); 274 /* break; */ 275 case ACPT_S_OK: 276 if (b->next_bio == NULL) { 277 c->state = ACPT_S_GET_ACCEPT_SOCKET; 278 goto again; 279 } 280 return (1); 281 /* break; */ 282 default: 283 return (0); 284 /* break; */ 285 } 286 } 287 288 static int 289 acpt_read(BIO *b, char *out, int outl) 290 { 291 int ret = 0; 292 BIO_ACCEPT *data; 293 294 BIO_clear_retry_flags(b); 295 data = (BIO_ACCEPT *)b->ptr; 296 297 while (b->next_bio == NULL) { 298 ret = acpt_state(b, data); 299 if (ret <= 0) 300 return (ret); 301 } 302 303 ret = BIO_read(b->next_bio, out, outl); 304 BIO_copy_next_retry(b); 305 return (ret); 306 } 307 308 static int 309 acpt_write(BIO *b, const char *in, int inl) 310 { 311 int ret; 312 BIO_ACCEPT *data; 313 314 BIO_clear_retry_flags(b); 315 data = (BIO_ACCEPT *)b->ptr; 316 317 while (b->next_bio == NULL) { 318 ret = acpt_state(b, data); 319 if (ret <= 0) 320 return (ret); 321 } 322 323 ret = BIO_write(b->next_bio, in, inl); 324 BIO_copy_next_retry(b); 325 return (ret); 326 } 327 328 static long 329 acpt_ctrl(BIO *b, int cmd, long num, void *ptr) 330 { 331 int *ip; 332 long ret = 1; 333 BIO_ACCEPT *data; 334 char **pp; 335 336 data = (BIO_ACCEPT *)b->ptr; 337 338 switch (cmd) { 339 case BIO_CTRL_RESET: 340 ret = 0; 341 data->state = ACPT_S_BEFORE; 342 acpt_close_socket(b); 343 b->flags = 0; 344 break; 345 case BIO_C_DO_STATE_MACHINE: 346 /* use this one to start the connection */ 347 ret = (long)acpt_state(b, data); 348 break; 349 case BIO_C_SET_ACCEPT: 350 if (ptr != NULL) { 351 if (num == 0) { 352 b->init = 1; 353 free(data->param_addr); 354 data->param_addr = strdup(ptr); 355 } else if (num == 1) { 356 data->accept_nbio = (ptr != NULL); 357 } else if (num == 2) { 358 BIO_free(data->bio_chain); 359 data->bio_chain = (BIO *)ptr; 360 } 361 } 362 break; 363 case BIO_C_SET_NBIO: 364 data->nbio = (int)num; 365 break; 366 case BIO_C_SET_FD: 367 b->init = 1; 368 b->num= *((int *)ptr); 369 data->accept_sock = b->num; 370 data->state = ACPT_S_GET_ACCEPT_SOCKET; 371 b->shutdown = (int)num; 372 b->init = 1; 373 break; 374 case BIO_C_GET_FD: 375 if (b->init) { 376 ip = (int *)ptr; 377 if (ip != NULL) 378 *ip = data->accept_sock; 379 ret = data->accept_sock; 380 } else 381 ret = -1; 382 break; 383 case BIO_C_GET_ACCEPT: 384 if (b->init) { 385 if (ptr != NULL) { 386 pp = (char **)ptr; 387 *pp = data->param_addr; 388 } else 389 ret = -1; 390 } else 391 ret = -1; 392 break; 393 case BIO_CTRL_GET_CLOSE: 394 ret = b->shutdown; 395 break; 396 case BIO_CTRL_SET_CLOSE: 397 b->shutdown = (int)num; 398 break; 399 case BIO_CTRL_PENDING: 400 case BIO_CTRL_WPENDING: 401 ret = 0; 402 break; 403 case BIO_CTRL_FLUSH: 404 break; 405 case BIO_C_SET_BIND_MODE: 406 data->bind_mode = (int)num; 407 break; 408 case BIO_C_GET_BIND_MODE: 409 ret = (long)data->bind_mode; 410 break; 411 case BIO_CTRL_DUP: 412 /* dbio=(BIO *)ptr; 413 if (data->param_port) EAY EAY 414 BIO_set_port(dbio,data->param_port); 415 if (data->param_hostname) 416 BIO_set_hostname(dbio,data->param_hostname); 417 BIO_set_nbio(dbio,data->nbio); 418 */ 419 break; 420 421 default: 422 ret = 0; 423 break; 424 } 425 return (ret); 426 } 427 428 static int 429 acpt_puts(BIO *bp, const char *str) 430 { 431 int n, ret; 432 433 n = strlen(str); 434 ret = acpt_write(bp, str, n); 435 return (ret); 436 } 437 438 BIO * 439 BIO_new_accept(const char *str) 440 { 441 BIO *ret; 442 443 ret = BIO_new(BIO_s_accept()); 444 if (ret == NULL) 445 return (NULL); 446 if (BIO_set_accept_port(ret, str)) 447 return (ret); 448 else { 449 BIO_free(ret); 450 return (NULL); 451 } 452 } 453 454