1 /* $OpenBSD: bss_acpt.c,v 1.31 2023/07/05 21:23:37 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 #include "bio_local.h" 71 72 #define SOCKET_PROTOCOL IPPROTO_TCP 73 74 typedef struct bio_accept_st { 75 int state; 76 char *param_addr; 77 78 int accept_sock; 79 int accept_nbio; 80 81 char *addr; 82 int nbio; 83 /* If 0, it means normal, if 1, do a connect on bind failure, 84 * and if there is no-one listening, bind with SO_REUSEADDR. 85 * If 2, always use SO_REUSEADDR. */ 86 int bind_mode; 87 BIO *bio_chain; 88 } BIO_ACCEPT; 89 90 static int acpt_write(BIO *h, const char *buf, int num); 91 static int acpt_read(BIO *h, char *buf, int size); 92 static int acpt_puts(BIO *h, const char *str); 93 static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2); 94 static int acpt_new(BIO *h); 95 static int acpt_free(BIO *data); 96 static int acpt_state(BIO *b, BIO_ACCEPT *c); 97 static void acpt_close_socket(BIO *data); 98 static BIO_ACCEPT *BIO_ACCEPT_new(void ); 99 static void BIO_ACCEPT_free(BIO_ACCEPT *a); 100 101 #define ACPT_S_BEFORE 1 102 #define ACPT_S_GET_ACCEPT_SOCKET 2 103 #define ACPT_S_OK 3 104 105 static const BIO_METHOD methods_acceptp = { 106 .type = BIO_TYPE_ACCEPT, 107 .name = "socket accept", 108 .bwrite = acpt_write, 109 .bread = acpt_read, 110 .bputs = acpt_puts, 111 .ctrl = acpt_ctrl, 112 .create = acpt_new, 113 .destroy = acpt_free 114 }; 115 116 const BIO_METHOD * 117 BIO_s_accept(void) 118 { 119 return (&methods_acceptp); 120 } 121 LCRYPTO_ALIAS(BIO_s_accept); 122 123 static int 124 acpt_new(BIO *bi) 125 { 126 BIO_ACCEPT *ba; 127 128 bi->init = 0; 129 bi->num = -1; 130 bi->flags = 0; 131 if ((ba = BIO_ACCEPT_new()) == NULL) 132 return (0); 133 bi->ptr = (char *)ba; 134 ba->state = ACPT_S_BEFORE; 135 bi->shutdown = 1; 136 return (1); 137 } 138 139 static BIO_ACCEPT * 140 BIO_ACCEPT_new(void) 141 { 142 BIO_ACCEPT *ret; 143 144 if ((ret = calloc(1, sizeof(BIO_ACCEPT))) == NULL) 145 return (NULL); 146 ret->accept_sock = -1; 147 ret->bind_mode = BIO_BIND_NORMAL; 148 return (ret); 149 } 150 151 static void 152 BIO_ACCEPT_free(BIO_ACCEPT *a) 153 { 154 if (a == NULL) 155 return; 156 157 free(a->param_addr); 158 free(a->addr); 159 BIO_free(a->bio_chain); 160 free(a); 161 } 162 163 static void 164 acpt_close_socket(BIO *bio) 165 { 166 BIO_ACCEPT *c; 167 168 c = (BIO_ACCEPT *)bio->ptr; 169 if (c->accept_sock != -1) { 170 shutdown(c->accept_sock, SHUT_RDWR); 171 close(c->accept_sock); 172 c->accept_sock = -1; 173 bio->num = -1; 174 } 175 } 176 177 static int 178 acpt_free(BIO *a) 179 { 180 BIO_ACCEPT *data; 181 182 if (a == NULL) 183 return (0); 184 data = (BIO_ACCEPT *)a->ptr; 185 186 if (a->shutdown) { 187 acpt_close_socket(a); 188 BIO_ACCEPT_free(data); 189 a->ptr = NULL; 190 a->flags = 0; 191 a->init = 0; 192 } 193 return (1); 194 } 195 196 static int 197 acpt_state(BIO *b, BIO_ACCEPT *c) 198 { 199 BIO *bio = NULL, *dbio; 200 int s = -1; 201 int i; 202 203 again: 204 switch (c->state) { 205 case ACPT_S_BEFORE: 206 if (c->param_addr == NULL) { 207 BIOerror(BIO_R_NO_ACCEPT_PORT_SPECIFIED); 208 return (-1); 209 } 210 s = BIO_get_accept_socket(c->param_addr, c->bind_mode); 211 if (s == -1) 212 return (-1); 213 214 if (c->accept_nbio) { 215 if (!BIO_socket_nbio(s, 1)) { 216 close(s); 217 BIOerror(BIO_R_ERROR_SETTING_NBIO_ON_ACCEPT_SOCKET); 218 return (-1); 219 } 220 } 221 c->accept_sock = s; 222 b->num = s; 223 c->state = ACPT_S_GET_ACCEPT_SOCKET; 224 return (1); 225 /* break; */ 226 case ACPT_S_GET_ACCEPT_SOCKET: 227 if (b->next_bio != NULL) { 228 c->state = ACPT_S_OK; 229 goto again; 230 } 231 BIO_clear_retry_flags(b); 232 b->retry_reason = 0; 233 i = BIO_accept(c->accept_sock, &(c->addr)); 234 235 /* -2 return means we should retry */ 236 if (i == -2) { 237 BIO_set_retry_special(b); 238 b->retry_reason = BIO_RR_ACCEPT; 239 return -1; 240 } 241 242 if (i < 0) 243 return (i); 244 245 bio = BIO_new_socket(i, BIO_CLOSE); 246 if (bio == NULL) 247 goto err; 248 249 BIO_set_callback(bio, BIO_get_callback(b)); 250 BIO_set_callback_arg(bio, BIO_get_callback_arg(b)); 251 252 if (c->nbio) { 253 if (!BIO_socket_nbio(i, 1)) { 254 BIOerror(BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET); 255 goto err; 256 } 257 } 258 259 /* If the accept BIO has an bio_chain, we dup it and 260 * put the new socket at the end. */ 261 if (c->bio_chain != NULL) { 262 if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL) 263 goto err; 264 if (!BIO_push(dbio, bio)) goto err; 265 bio = dbio; 266 } 267 if (BIO_push(b, bio) 268 == NULL) goto err; 269 270 c->state = ACPT_S_OK; 271 return (1); 272 273 err: 274 if (bio != NULL) 275 BIO_free(bio); 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 BIO_free(data->bio_chain); 362 data->bio_chain = (BIO *)ptr; 363 } 364 } 365 break; 366 case BIO_C_SET_NBIO: 367 data->nbio = (int)num; 368 break; 369 case BIO_C_SET_FD: 370 b->init = 1; 371 b->num= *((int *)ptr); 372 data->accept_sock = b->num; 373 data->state = ACPT_S_GET_ACCEPT_SOCKET; 374 b->shutdown = (int)num; 375 b->init = 1; 376 break; 377 case BIO_C_GET_FD: 378 if (b->init) { 379 ip = (int *)ptr; 380 if (ip != NULL) 381 *ip = data->accept_sock; 382 ret = data->accept_sock; 383 } else 384 ret = -1; 385 break; 386 case BIO_C_GET_ACCEPT: 387 if (b->init) { 388 if (ptr != NULL) { 389 pp = (char **)ptr; 390 *pp = data->param_addr; 391 } else 392 ret = -1; 393 } else 394 ret = -1; 395 break; 396 case BIO_CTRL_GET_CLOSE: 397 ret = b->shutdown; 398 break; 399 case BIO_CTRL_SET_CLOSE: 400 b->shutdown = (int)num; 401 break; 402 case BIO_CTRL_PENDING: 403 case BIO_CTRL_WPENDING: 404 ret = 0; 405 break; 406 case BIO_CTRL_FLUSH: 407 break; 408 case BIO_C_SET_BIND_MODE: 409 data->bind_mode = (int)num; 410 break; 411 case BIO_C_GET_BIND_MODE: 412 ret = (long)data->bind_mode; 413 break; 414 case BIO_CTRL_DUP: 415 /* dbio=(BIO *)ptr; 416 if (data->param_port) EAY EAY 417 BIO_set_port(dbio,data->param_port); 418 if (data->param_hostname) 419 BIO_set_hostname(dbio,data->param_hostname); 420 BIO_set_nbio(dbio,data->nbio); 421 */ 422 break; 423 424 default: 425 ret = 0; 426 break; 427 } 428 return (ret); 429 } 430 431 static int 432 acpt_puts(BIO *bp, const char *str) 433 { 434 int n, ret; 435 436 n = strlen(str); 437 ret = acpt_write(bp, str, n); 438 return (ret); 439 } 440 441 BIO * 442 BIO_new_accept(const char *str) 443 { 444 BIO *ret; 445 446 ret = BIO_new(BIO_s_accept()); 447 if (ret == NULL) 448 return (NULL); 449 if (BIO_set_accept_port(ret, str)) 450 return (ret); 451 else { 452 BIO_free(ret); 453 return (NULL); 454 } 455 } 456 LCRYPTO_ALIAS(BIO_new_accept); 457