1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#define OPENSSL_SUPPRESS_DEPRECATED 11e1051a39Sopenharmony_ci 12e1051a39Sopenharmony_ci#include <stdio.h> 13e1051a39Sopenharmony_ci#include <errno.h> 14e1051a39Sopenharmony_ci#include "bio_local.h" 15e1051a39Sopenharmony_ci 16e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SOCK 17e1051a39Sopenharmony_ci 18e1051a39Sopenharmony_citypedef struct bio_accept_st { 19e1051a39Sopenharmony_ci int state; 20e1051a39Sopenharmony_ci int accept_family; 21e1051a39Sopenharmony_ci int bind_mode; /* Socket mode for BIO_listen */ 22e1051a39Sopenharmony_ci int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */ 23e1051a39Sopenharmony_ci char *param_addr; 24e1051a39Sopenharmony_ci char *param_serv; 25e1051a39Sopenharmony_ci 26e1051a39Sopenharmony_ci int accept_sock; 27e1051a39Sopenharmony_ci 28e1051a39Sopenharmony_ci BIO_ADDRINFO *addr_first; 29e1051a39Sopenharmony_ci const BIO_ADDRINFO *addr_iter; 30e1051a39Sopenharmony_ci BIO_ADDR cache_accepting_addr; /* Useful if we asked for port 0 */ 31e1051a39Sopenharmony_ci char *cache_accepting_name, *cache_accepting_serv; 32e1051a39Sopenharmony_ci BIO_ADDR cache_peer_addr; 33e1051a39Sopenharmony_ci char *cache_peer_name, *cache_peer_serv; 34e1051a39Sopenharmony_ci 35e1051a39Sopenharmony_ci BIO *bio_chain; 36e1051a39Sopenharmony_ci} BIO_ACCEPT; 37e1051a39Sopenharmony_ci 38e1051a39Sopenharmony_cistatic int acpt_write(BIO *h, const char *buf, int num); 39e1051a39Sopenharmony_cistatic int acpt_read(BIO *h, char *buf, int size); 40e1051a39Sopenharmony_cistatic int acpt_puts(BIO *h, const char *str); 41e1051a39Sopenharmony_cistatic long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2); 42e1051a39Sopenharmony_cistatic int acpt_new(BIO *h); 43e1051a39Sopenharmony_cistatic int acpt_free(BIO *data); 44e1051a39Sopenharmony_cistatic int acpt_state(BIO *b, BIO_ACCEPT *c); 45e1051a39Sopenharmony_cistatic void acpt_close_socket(BIO *data); 46e1051a39Sopenharmony_cistatic BIO_ACCEPT *BIO_ACCEPT_new(void); 47e1051a39Sopenharmony_cistatic void BIO_ACCEPT_free(BIO_ACCEPT *a); 48e1051a39Sopenharmony_ci 49e1051a39Sopenharmony_ci# define ACPT_S_BEFORE 1 50e1051a39Sopenharmony_ci# define ACPT_S_GET_ADDR 2 51e1051a39Sopenharmony_ci# define ACPT_S_CREATE_SOCKET 3 52e1051a39Sopenharmony_ci# define ACPT_S_LISTEN 4 53e1051a39Sopenharmony_ci# define ACPT_S_ACCEPT 5 54e1051a39Sopenharmony_ci# define ACPT_S_OK 6 55e1051a39Sopenharmony_ci 56e1051a39Sopenharmony_cistatic const BIO_METHOD methods_acceptp = { 57e1051a39Sopenharmony_ci BIO_TYPE_ACCEPT, 58e1051a39Sopenharmony_ci "socket accept", 59e1051a39Sopenharmony_ci bwrite_conv, 60e1051a39Sopenharmony_ci acpt_write, 61e1051a39Sopenharmony_ci bread_conv, 62e1051a39Sopenharmony_ci acpt_read, 63e1051a39Sopenharmony_ci acpt_puts, 64e1051a39Sopenharmony_ci NULL, /* connect_gets, */ 65e1051a39Sopenharmony_ci acpt_ctrl, 66e1051a39Sopenharmony_ci acpt_new, 67e1051a39Sopenharmony_ci acpt_free, 68e1051a39Sopenharmony_ci NULL, /* connect_callback_ctrl */ 69e1051a39Sopenharmony_ci}; 70e1051a39Sopenharmony_ci 71e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_s_accept(void) 72e1051a39Sopenharmony_ci{ 73e1051a39Sopenharmony_ci return &methods_acceptp; 74e1051a39Sopenharmony_ci} 75e1051a39Sopenharmony_ci 76e1051a39Sopenharmony_cistatic int acpt_new(BIO *bi) 77e1051a39Sopenharmony_ci{ 78e1051a39Sopenharmony_ci BIO_ACCEPT *ba; 79e1051a39Sopenharmony_ci 80e1051a39Sopenharmony_ci bi->init = 0; 81e1051a39Sopenharmony_ci bi->num = (int)INVALID_SOCKET; 82e1051a39Sopenharmony_ci bi->flags = 0; 83e1051a39Sopenharmony_ci if ((ba = BIO_ACCEPT_new()) == NULL) 84e1051a39Sopenharmony_ci return 0; 85e1051a39Sopenharmony_ci bi->ptr = (char *)ba; 86e1051a39Sopenharmony_ci ba->state = ACPT_S_BEFORE; 87e1051a39Sopenharmony_ci bi->shutdown = 1; 88e1051a39Sopenharmony_ci return 1; 89e1051a39Sopenharmony_ci} 90e1051a39Sopenharmony_ci 91e1051a39Sopenharmony_cistatic BIO_ACCEPT *BIO_ACCEPT_new(void) 92e1051a39Sopenharmony_ci{ 93e1051a39Sopenharmony_ci BIO_ACCEPT *ret; 94e1051a39Sopenharmony_ci 95e1051a39Sopenharmony_ci if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) { 96e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE); 97e1051a39Sopenharmony_ci return NULL; 98e1051a39Sopenharmony_ci } 99e1051a39Sopenharmony_ci ret->accept_family = BIO_FAMILY_IPANY; 100e1051a39Sopenharmony_ci ret->accept_sock = (int)INVALID_SOCKET; 101e1051a39Sopenharmony_ci return ret; 102e1051a39Sopenharmony_ci} 103e1051a39Sopenharmony_ci 104e1051a39Sopenharmony_cistatic void BIO_ACCEPT_free(BIO_ACCEPT *a) 105e1051a39Sopenharmony_ci{ 106e1051a39Sopenharmony_ci if (a == NULL) 107e1051a39Sopenharmony_ci return; 108e1051a39Sopenharmony_ci OPENSSL_free(a->param_addr); 109e1051a39Sopenharmony_ci OPENSSL_free(a->param_serv); 110e1051a39Sopenharmony_ci BIO_ADDRINFO_free(a->addr_first); 111e1051a39Sopenharmony_ci OPENSSL_free(a->cache_accepting_name); 112e1051a39Sopenharmony_ci OPENSSL_free(a->cache_accepting_serv); 113e1051a39Sopenharmony_ci OPENSSL_free(a->cache_peer_name); 114e1051a39Sopenharmony_ci OPENSSL_free(a->cache_peer_serv); 115e1051a39Sopenharmony_ci BIO_free(a->bio_chain); 116e1051a39Sopenharmony_ci OPENSSL_free(a); 117e1051a39Sopenharmony_ci} 118e1051a39Sopenharmony_ci 119e1051a39Sopenharmony_cistatic void acpt_close_socket(BIO *bio) 120e1051a39Sopenharmony_ci{ 121e1051a39Sopenharmony_ci BIO_ACCEPT *c; 122e1051a39Sopenharmony_ci 123e1051a39Sopenharmony_ci c = (BIO_ACCEPT *)bio->ptr; 124e1051a39Sopenharmony_ci if (c->accept_sock != (int)INVALID_SOCKET) { 125e1051a39Sopenharmony_ci shutdown(c->accept_sock, 2); 126e1051a39Sopenharmony_ci closesocket(c->accept_sock); 127e1051a39Sopenharmony_ci c->accept_sock = (int)INVALID_SOCKET; 128e1051a39Sopenharmony_ci bio->num = (int)INVALID_SOCKET; 129e1051a39Sopenharmony_ci } 130e1051a39Sopenharmony_ci} 131e1051a39Sopenharmony_ci 132e1051a39Sopenharmony_cistatic int acpt_free(BIO *a) 133e1051a39Sopenharmony_ci{ 134e1051a39Sopenharmony_ci BIO_ACCEPT *data; 135e1051a39Sopenharmony_ci 136e1051a39Sopenharmony_ci if (a == NULL) 137e1051a39Sopenharmony_ci return 0; 138e1051a39Sopenharmony_ci data = (BIO_ACCEPT *)a->ptr; 139e1051a39Sopenharmony_ci 140e1051a39Sopenharmony_ci if (a->shutdown) { 141e1051a39Sopenharmony_ci acpt_close_socket(a); 142e1051a39Sopenharmony_ci BIO_ACCEPT_free(data); 143e1051a39Sopenharmony_ci a->ptr = NULL; 144e1051a39Sopenharmony_ci a->flags = 0; 145e1051a39Sopenharmony_ci a->init = 0; 146e1051a39Sopenharmony_ci } 147e1051a39Sopenharmony_ci return 1; 148e1051a39Sopenharmony_ci} 149e1051a39Sopenharmony_ci 150e1051a39Sopenharmony_cistatic int acpt_state(BIO *b, BIO_ACCEPT *c) 151e1051a39Sopenharmony_ci{ 152e1051a39Sopenharmony_ci BIO *bio = NULL, *dbio; 153e1051a39Sopenharmony_ci int s = -1, ret = -1; 154e1051a39Sopenharmony_ci 155e1051a39Sopenharmony_ci for (;;) { 156e1051a39Sopenharmony_ci switch (c->state) { 157e1051a39Sopenharmony_ci case ACPT_S_BEFORE: 158e1051a39Sopenharmony_ci if (c->param_addr == NULL && c->param_serv == NULL) { 159e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_BIO, 160e1051a39Sopenharmony_ci BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED, 161e1051a39Sopenharmony_ci "hostname=%s, service=%s", 162e1051a39Sopenharmony_ci c->param_addr, c->param_serv); 163e1051a39Sopenharmony_ci goto exit_loop; 164e1051a39Sopenharmony_ci } 165e1051a39Sopenharmony_ci 166e1051a39Sopenharmony_ci /* Because we're starting a new bind, any cached name and serv 167e1051a39Sopenharmony_ci * are now obsolete and need to be cleaned out. 168e1051a39Sopenharmony_ci * QUESTION: should this be done in acpt_close_socket() instead? 169e1051a39Sopenharmony_ci */ 170e1051a39Sopenharmony_ci OPENSSL_free(c->cache_accepting_name); 171e1051a39Sopenharmony_ci c->cache_accepting_name = NULL; 172e1051a39Sopenharmony_ci OPENSSL_free(c->cache_accepting_serv); 173e1051a39Sopenharmony_ci c->cache_accepting_serv = NULL; 174e1051a39Sopenharmony_ci OPENSSL_free(c->cache_peer_name); 175e1051a39Sopenharmony_ci c->cache_peer_name = NULL; 176e1051a39Sopenharmony_ci OPENSSL_free(c->cache_peer_serv); 177e1051a39Sopenharmony_ci c->cache_peer_serv = NULL; 178e1051a39Sopenharmony_ci 179e1051a39Sopenharmony_ci c->state = ACPT_S_GET_ADDR; 180e1051a39Sopenharmony_ci break; 181e1051a39Sopenharmony_ci 182e1051a39Sopenharmony_ci case ACPT_S_GET_ADDR: 183e1051a39Sopenharmony_ci { 184e1051a39Sopenharmony_ci int family = AF_UNSPEC; 185e1051a39Sopenharmony_ci switch (c->accept_family) { 186e1051a39Sopenharmony_ci case BIO_FAMILY_IPV6: 187e1051a39Sopenharmony_ci if (1) { /* This is a trick we use to avoid bit rot. 188e1051a39Sopenharmony_ci * at least the "else" part will always be 189e1051a39Sopenharmony_ci * compiled. 190e1051a39Sopenharmony_ci */ 191e1051a39Sopenharmony_ci#ifdef AF_INET6 192e1051a39Sopenharmony_ci family = AF_INET6; 193e1051a39Sopenharmony_ci } else { 194e1051a39Sopenharmony_ci#endif 195e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_BIO, BIO_R_UNAVAILABLE_IP_FAMILY); 196e1051a39Sopenharmony_ci goto exit_loop; 197e1051a39Sopenharmony_ci } 198e1051a39Sopenharmony_ci break; 199e1051a39Sopenharmony_ci case BIO_FAMILY_IPV4: 200e1051a39Sopenharmony_ci family = AF_INET; 201e1051a39Sopenharmony_ci break; 202e1051a39Sopenharmony_ci case BIO_FAMILY_IPANY: 203e1051a39Sopenharmony_ci family = AF_UNSPEC; 204e1051a39Sopenharmony_ci break; 205e1051a39Sopenharmony_ci default: 206e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_IP_FAMILY); 207e1051a39Sopenharmony_ci goto exit_loop; 208e1051a39Sopenharmony_ci } 209e1051a39Sopenharmony_ci if (BIO_lookup(c->param_addr, c->param_serv, BIO_LOOKUP_SERVER, 210e1051a39Sopenharmony_ci family, SOCK_STREAM, &c->addr_first) == 0) 211e1051a39Sopenharmony_ci goto exit_loop; 212e1051a39Sopenharmony_ci } 213e1051a39Sopenharmony_ci if (c->addr_first == NULL) { 214e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_BIO, BIO_R_LOOKUP_RETURNED_NOTHING); 215e1051a39Sopenharmony_ci goto exit_loop; 216e1051a39Sopenharmony_ci } 217e1051a39Sopenharmony_ci c->addr_iter = c->addr_first; 218e1051a39Sopenharmony_ci c->state = ACPT_S_CREATE_SOCKET; 219e1051a39Sopenharmony_ci break; 220e1051a39Sopenharmony_ci 221e1051a39Sopenharmony_ci case ACPT_S_CREATE_SOCKET: 222e1051a39Sopenharmony_ci ERR_set_mark(); 223e1051a39Sopenharmony_ci s = BIO_socket(BIO_ADDRINFO_family(c->addr_iter), 224e1051a39Sopenharmony_ci BIO_ADDRINFO_socktype(c->addr_iter), 225e1051a39Sopenharmony_ci BIO_ADDRINFO_protocol(c->addr_iter), 0); 226e1051a39Sopenharmony_ci if (s == (int)INVALID_SOCKET) { 227e1051a39Sopenharmony_ci if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter)) != NULL) { 228e1051a39Sopenharmony_ci /* 229e1051a39Sopenharmony_ci * if there are more addresses to try, do that first 230e1051a39Sopenharmony_ci */ 231e1051a39Sopenharmony_ci ERR_pop_to_mark(); 232e1051a39Sopenharmony_ci break; 233e1051a39Sopenharmony_ci } 234e1051a39Sopenharmony_ci ERR_clear_last_mark(); 235e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(), 236e1051a39Sopenharmony_ci "calling socket(%s, %s)", 237e1051a39Sopenharmony_ci c->param_addr, c->param_serv); 238e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_BIO, BIO_R_UNABLE_TO_CREATE_SOCKET); 239e1051a39Sopenharmony_ci goto exit_loop; 240e1051a39Sopenharmony_ci } 241e1051a39Sopenharmony_ci c->accept_sock = s; 242e1051a39Sopenharmony_ci b->num = s; 243e1051a39Sopenharmony_ci c->state = ACPT_S_LISTEN; 244e1051a39Sopenharmony_ci s = -1; 245e1051a39Sopenharmony_ci break; 246e1051a39Sopenharmony_ci 247e1051a39Sopenharmony_ci case ACPT_S_LISTEN: 248e1051a39Sopenharmony_ci { 249e1051a39Sopenharmony_ci if (!BIO_listen(c->accept_sock, 250e1051a39Sopenharmony_ci BIO_ADDRINFO_address(c->addr_iter), 251e1051a39Sopenharmony_ci c->bind_mode)) { 252e1051a39Sopenharmony_ci BIO_closesocket(c->accept_sock); 253e1051a39Sopenharmony_ci goto exit_loop; 254e1051a39Sopenharmony_ci } 255e1051a39Sopenharmony_ci } 256e1051a39Sopenharmony_ci 257e1051a39Sopenharmony_ci { 258e1051a39Sopenharmony_ci union BIO_sock_info_u info; 259e1051a39Sopenharmony_ci 260e1051a39Sopenharmony_ci info.addr = &c->cache_accepting_addr; 261e1051a39Sopenharmony_ci if (!BIO_sock_info(c->accept_sock, BIO_SOCK_INFO_ADDRESS, 262e1051a39Sopenharmony_ci &info)) { 263e1051a39Sopenharmony_ci BIO_closesocket(c->accept_sock); 264e1051a39Sopenharmony_ci goto exit_loop; 265e1051a39Sopenharmony_ci } 266e1051a39Sopenharmony_ci } 267e1051a39Sopenharmony_ci 268e1051a39Sopenharmony_ci c->cache_accepting_name = 269e1051a39Sopenharmony_ci BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1); 270e1051a39Sopenharmony_ci c->cache_accepting_serv = 271e1051a39Sopenharmony_ci BIO_ADDR_service_string(&c->cache_accepting_addr, 1); 272e1051a39Sopenharmony_ci c->state = ACPT_S_ACCEPT; 273e1051a39Sopenharmony_ci s = -1; 274e1051a39Sopenharmony_ci ret = 1; 275e1051a39Sopenharmony_ci goto end; 276e1051a39Sopenharmony_ci 277e1051a39Sopenharmony_ci case ACPT_S_ACCEPT: 278e1051a39Sopenharmony_ci if (b->next_bio != NULL) { 279e1051a39Sopenharmony_ci c->state = ACPT_S_OK; 280e1051a39Sopenharmony_ci break; 281e1051a39Sopenharmony_ci } 282e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 283e1051a39Sopenharmony_ci b->retry_reason = 0; 284e1051a39Sopenharmony_ci 285e1051a39Sopenharmony_ci OPENSSL_free(c->cache_peer_name); 286e1051a39Sopenharmony_ci c->cache_peer_name = NULL; 287e1051a39Sopenharmony_ci OPENSSL_free(c->cache_peer_serv); 288e1051a39Sopenharmony_ci c->cache_peer_serv = NULL; 289e1051a39Sopenharmony_ci 290e1051a39Sopenharmony_ci s = BIO_accept_ex(c->accept_sock, &c->cache_peer_addr, 291e1051a39Sopenharmony_ci c->accepted_mode); 292e1051a39Sopenharmony_ci 293e1051a39Sopenharmony_ci /* If the returned socket is invalid, this might still be 294e1051a39Sopenharmony_ci * retryable 295e1051a39Sopenharmony_ci */ 296e1051a39Sopenharmony_ci if (s < 0) { 297e1051a39Sopenharmony_ci if (BIO_sock_should_retry(s)) { 298e1051a39Sopenharmony_ci BIO_set_retry_special(b); 299e1051a39Sopenharmony_ci b->retry_reason = BIO_RR_ACCEPT; 300e1051a39Sopenharmony_ci goto end; 301e1051a39Sopenharmony_ci } 302e1051a39Sopenharmony_ci } 303e1051a39Sopenharmony_ci 304e1051a39Sopenharmony_ci /* If it wasn't retryable, we fail */ 305e1051a39Sopenharmony_ci if (s < 0) { 306e1051a39Sopenharmony_ci ret = s; 307e1051a39Sopenharmony_ci goto exit_loop; 308e1051a39Sopenharmony_ci } 309e1051a39Sopenharmony_ci 310e1051a39Sopenharmony_ci bio = BIO_new_socket(s, BIO_CLOSE); 311e1051a39Sopenharmony_ci if (bio == NULL) 312e1051a39Sopenharmony_ci goto exit_loop; 313e1051a39Sopenharmony_ci 314e1051a39Sopenharmony_ci BIO_set_callback_ex(bio, BIO_get_callback_ex(b)); 315e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DEPRECATED_3_0 316e1051a39Sopenharmony_ci BIO_set_callback(bio, BIO_get_callback(b)); 317e1051a39Sopenharmony_ci#endif 318e1051a39Sopenharmony_ci BIO_set_callback_arg(bio, BIO_get_callback_arg(b)); 319e1051a39Sopenharmony_ci /* 320e1051a39Sopenharmony_ci * If the accept BIO has an bio_chain, we dup it and put the new 321e1051a39Sopenharmony_ci * socket at the end. 322e1051a39Sopenharmony_ci */ 323e1051a39Sopenharmony_ci if (c->bio_chain != NULL) { 324e1051a39Sopenharmony_ci if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL) 325e1051a39Sopenharmony_ci goto exit_loop; 326e1051a39Sopenharmony_ci if (!BIO_push(dbio, bio)) 327e1051a39Sopenharmony_ci goto exit_loop; 328e1051a39Sopenharmony_ci bio = dbio; 329e1051a39Sopenharmony_ci } 330e1051a39Sopenharmony_ci if (BIO_push(b, bio) == NULL) 331e1051a39Sopenharmony_ci goto exit_loop; 332e1051a39Sopenharmony_ci 333e1051a39Sopenharmony_ci c->cache_peer_name = 334e1051a39Sopenharmony_ci BIO_ADDR_hostname_string(&c->cache_peer_addr, 1); 335e1051a39Sopenharmony_ci c->cache_peer_serv = 336e1051a39Sopenharmony_ci BIO_ADDR_service_string(&c->cache_peer_addr, 1); 337e1051a39Sopenharmony_ci c->state = ACPT_S_OK; 338e1051a39Sopenharmony_ci bio = NULL; 339e1051a39Sopenharmony_ci ret = 1; 340e1051a39Sopenharmony_ci goto end; 341e1051a39Sopenharmony_ci 342e1051a39Sopenharmony_ci case ACPT_S_OK: 343e1051a39Sopenharmony_ci if (b->next_bio == NULL) { 344e1051a39Sopenharmony_ci c->state = ACPT_S_ACCEPT; 345e1051a39Sopenharmony_ci break; 346e1051a39Sopenharmony_ci } 347e1051a39Sopenharmony_ci ret = 1; 348e1051a39Sopenharmony_ci goto end; 349e1051a39Sopenharmony_ci 350e1051a39Sopenharmony_ci default: 351e1051a39Sopenharmony_ci ret = 0; 352e1051a39Sopenharmony_ci goto end; 353e1051a39Sopenharmony_ci } 354e1051a39Sopenharmony_ci } 355e1051a39Sopenharmony_ci 356e1051a39Sopenharmony_ci exit_loop: 357e1051a39Sopenharmony_ci if (bio != NULL) 358e1051a39Sopenharmony_ci BIO_free(bio); 359e1051a39Sopenharmony_ci else if (s >= 0) 360e1051a39Sopenharmony_ci BIO_closesocket(s); 361e1051a39Sopenharmony_ci end: 362e1051a39Sopenharmony_ci return ret; 363e1051a39Sopenharmony_ci} 364e1051a39Sopenharmony_ci 365e1051a39Sopenharmony_cistatic int acpt_read(BIO *b, char *out, int outl) 366e1051a39Sopenharmony_ci{ 367e1051a39Sopenharmony_ci int ret = 0; 368e1051a39Sopenharmony_ci BIO_ACCEPT *data; 369e1051a39Sopenharmony_ci 370e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 371e1051a39Sopenharmony_ci data = (BIO_ACCEPT *)b->ptr; 372e1051a39Sopenharmony_ci 373e1051a39Sopenharmony_ci while (b->next_bio == NULL) { 374e1051a39Sopenharmony_ci ret = acpt_state(b, data); 375e1051a39Sopenharmony_ci if (ret <= 0) 376e1051a39Sopenharmony_ci return ret; 377e1051a39Sopenharmony_ci } 378e1051a39Sopenharmony_ci 379e1051a39Sopenharmony_ci ret = BIO_read(b->next_bio, out, outl); 380e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 381e1051a39Sopenharmony_ci return ret; 382e1051a39Sopenharmony_ci} 383e1051a39Sopenharmony_ci 384e1051a39Sopenharmony_cistatic int acpt_write(BIO *b, const char *in, int inl) 385e1051a39Sopenharmony_ci{ 386e1051a39Sopenharmony_ci int ret; 387e1051a39Sopenharmony_ci BIO_ACCEPT *data; 388e1051a39Sopenharmony_ci 389e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 390e1051a39Sopenharmony_ci data = (BIO_ACCEPT *)b->ptr; 391e1051a39Sopenharmony_ci 392e1051a39Sopenharmony_ci while (b->next_bio == NULL) { 393e1051a39Sopenharmony_ci ret = acpt_state(b, data); 394e1051a39Sopenharmony_ci if (ret <= 0) 395e1051a39Sopenharmony_ci return ret; 396e1051a39Sopenharmony_ci } 397e1051a39Sopenharmony_ci 398e1051a39Sopenharmony_ci ret = BIO_write(b->next_bio, in, inl); 399e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 400e1051a39Sopenharmony_ci return ret; 401e1051a39Sopenharmony_ci} 402e1051a39Sopenharmony_ci 403e1051a39Sopenharmony_cistatic long acpt_ctrl(BIO *b, int cmd, long num, void *ptr) 404e1051a39Sopenharmony_ci{ 405e1051a39Sopenharmony_ci int *ip; 406e1051a39Sopenharmony_ci long ret = 1; 407e1051a39Sopenharmony_ci BIO_ACCEPT *data; 408e1051a39Sopenharmony_ci char **pp; 409e1051a39Sopenharmony_ci 410e1051a39Sopenharmony_ci data = (BIO_ACCEPT *)b->ptr; 411e1051a39Sopenharmony_ci 412e1051a39Sopenharmony_ci switch (cmd) { 413e1051a39Sopenharmony_ci case BIO_CTRL_RESET: 414e1051a39Sopenharmony_ci ret = 0; 415e1051a39Sopenharmony_ci data->state = ACPT_S_BEFORE; 416e1051a39Sopenharmony_ci acpt_close_socket(b); 417e1051a39Sopenharmony_ci BIO_ADDRINFO_free(data->addr_first); 418e1051a39Sopenharmony_ci data->addr_first = NULL; 419e1051a39Sopenharmony_ci b->flags = 0; 420e1051a39Sopenharmony_ci break; 421e1051a39Sopenharmony_ci case BIO_C_DO_STATE_MACHINE: 422e1051a39Sopenharmony_ci /* use this one to start the connection */ 423e1051a39Sopenharmony_ci ret = (long)acpt_state(b, data); 424e1051a39Sopenharmony_ci break; 425e1051a39Sopenharmony_ci case BIO_C_SET_ACCEPT: 426e1051a39Sopenharmony_ci if (ptr != NULL) { 427e1051a39Sopenharmony_ci if (num == 0) { 428e1051a39Sopenharmony_ci char *hold_serv = data->param_serv; 429e1051a39Sopenharmony_ci /* We affect the hostname regardless. However, the input 430e1051a39Sopenharmony_ci * string might contain a host:service spec, so we must 431e1051a39Sopenharmony_ci * parse it, which might or might not affect the service 432e1051a39Sopenharmony_ci */ 433e1051a39Sopenharmony_ci OPENSSL_free(data->param_addr); 434e1051a39Sopenharmony_ci data->param_addr = NULL; 435e1051a39Sopenharmony_ci ret = BIO_parse_hostserv(ptr, 436e1051a39Sopenharmony_ci &data->param_addr, 437e1051a39Sopenharmony_ci &data->param_serv, 438e1051a39Sopenharmony_ci BIO_PARSE_PRIO_SERV); 439e1051a39Sopenharmony_ci if (hold_serv != data->param_serv) 440e1051a39Sopenharmony_ci OPENSSL_free(hold_serv); 441e1051a39Sopenharmony_ci b->init = 1; 442e1051a39Sopenharmony_ci } else if (num == 1) { 443e1051a39Sopenharmony_ci OPENSSL_free(data->param_serv); 444e1051a39Sopenharmony_ci if ((data->param_serv = OPENSSL_strdup(ptr)) == NULL) 445e1051a39Sopenharmony_ci ret = 0; 446e1051a39Sopenharmony_ci else 447e1051a39Sopenharmony_ci b->init = 1; 448e1051a39Sopenharmony_ci } else if (num == 2) { 449e1051a39Sopenharmony_ci data->bind_mode |= BIO_SOCK_NONBLOCK; 450e1051a39Sopenharmony_ci } else if (num == 3) { 451e1051a39Sopenharmony_ci BIO_free(data->bio_chain); 452e1051a39Sopenharmony_ci data->bio_chain = (BIO *)ptr; 453e1051a39Sopenharmony_ci } else if (num == 4) { 454e1051a39Sopenharmony_ci data->accept_family = *(int *)ptr; 455e1051a39Sopenharmony_ci } 456e1051a39Sopenharmony_ci } else { 457e1051a39Sopenharmony_ci if (num == 2) { 458e1051a39Sopenharmony_ci data->bind_mode &= ~BIO_SOCK_NONBLOCK; 459e1051a39Sopenharmony_ci } 460e1051a39Sopenharmony_ci } 461e1051a39Sopenharmony_ci break; 462e1051a39Sopenharmony_ci case BIO_C_SET_NBIO: 463e1051a39Sopenharmony_ci if (num != 0) 464e1051a39Sopenharmony_ci data->accepted_mode |= BIO_SOCK_NONBLOCK; 465e1051a39Sopenharmony_ci else 466e1051a39Sopenharmony_ci data->accepted_mode &= ~BIO_SOCK_NONBLOCK; 467e1051a39Sopenharmony_ci break; 468e1051a39Sopenharmony_ci case BIO_C_SET_FD: 469e1051a39Sopenharmony_ci b->num = *((int *)ptr); 470e1051a39Sopenharmony_ci data->accept_sock = b->num; 471e1051a39Sopenharmony_ci data->state = ACPT_S_ACCEPT; 472e1051a39Sopenharmony_ci b->shutdown = (int)num; 473e1051a39Sopenharmony_ci b->init = 1; 474e1051a39Sopenharmony_ci break; 475e1051a39Sopenharmony_ci case BIO_C_GET_FD: 476e1051a39Sopenharmony_ci if (b->init) { 477e1051a39Sopenharmony_ci ip = (int *)ptr; 478e1051a39Sopenharmony_ci if (ip != NULL) 479e1051a39Sopenharmony_ci *ip = data->accept_sock; 480e1051a39Sopenharmony_ci ret = data->accept_sock; 481e1051a39Sopenharmony_ci } else 482e1051a39Sopenharmony_ci ret = -1; 483e1051a39Sopenharmony_ci break; 484e1051a39Sopenharmony_ci case BIO_C_GET_ACCEPT: 485e1051a39Sopenharmony_ci if (b->init) { 486e1051a39Sopenharmony_ci if (num == 0 && ptr != NULL) { 487e1051a39Sopenharmony_ci pp = (char **)ptr; 488e1051a39Sopenharmony_ci *pp = data->cache_accepting_name; 489e1051a39Sopenharmony_ci } else if (num == 1 && ptr != NULL) { 490e1051a39Sopenharmony_ci pp = (char **)ptr; 491e1051a39Sopenharmony_ci *pp = data->cache_accepting_serv; 492e1051a39Sopenharmony_ci } else if (num == 2 && ptr != NULL) { 493e1051a39Sopenharmony_ci pp = (char **)ptr; 494e1051a39Sopenharmony_ci *pp = data->cache_peer_name; 495e1051a39Sopenharmony_ci } else if (num == 3 && ptr != NULL) { 496e1051a39Sopenharmony_ci pp = (char **)ptr; 497e1051a39Sopenharmony_ci *pp = data->cache_peer_serv; 498e1051a39Sopenharmony_ci } else if (num == 4) { 499e1051a39Sopenharmony_ci switch (BIO_ADDRINFO_family(data->addr_iter)) { 500e1051a39Sopenharmony_ci#ifdef AF_INET6 501e1051a39Sopenharmony_ci case AF_INET6: 502e1051a39Sopenharmony_ci ret = BIO_FAMILY_IPV6; 503e1051a39Sopenharmony_ci break; 504e1051a39Sopenharmony_ci#endif 505e1051a39Sopenharmony_ci case AF_INET: 506e1051a39Sopenharmony_ci ret = BIO_FAMILY_IPV4; 507e1051a39Sopenharmony_ci break; 508e1051a39Sopenharmony_ci case 0: 509e1051a39Sopenharmony_ci ret = data->accept_family; 510e1051a39Sopenharmony_ci break; 511e1051a39Sopenharmony_ci default: 512e1051a39Sopenharmony_ci ret = -1; 513e1051a39Sopenharmony_ci break; 514e1051a39Sopenharmony_ci } 515e1051a39Sopenharmony_ci } else 516e1051a39Sopenharmony_ci ret = -1; 517e1051a39Sopenharmony_ci } else 518e1051a39Sopenharmony_ci ret = -1; 519e1051a39Sopenharmony_ci break; 520e1051a39Sopenharmony_ci case BIO_CTRL_GET_CLOSE: 521e1051a39Sopenharmony_ci ret = b->shutdown; 522e1051a39Sopenharmony_ci break; 523e1051a39Sopenharmony_ci case BIO_CTRL_SET_CLOSE: 524e1051a39Sopenharmony_ci b->shutdown = (int)num; 525e1051a39Sopenharmony_ci break; 526e1051a39Sopenharmony_ci case BIO_CTRL_PENDING: 527e1051a39Sopenharmony_ci case BIO_CTRL_WPENDING: 528e1051a39Sopenharmony_ci ret = 0; 529e1051a39Sopenharmony_ci break; 530e1051a39Sopenharmony_ci case BIO_CTRL_FLUSH: 531e1051a39Sopenharmony_ci break; 532e1051a39Sopenharmony_ci case BIO_C_SET_BIND_MODE: 533e1051a39Sopenharmony_ci data->bind_mode = (int)num; 534e1051a39Sopenharmony_ci break; 535e1051a39Sopenharmony_ci case BIO_C_GET_BIND_MODE: 536e1051a39Sopenharmony_ci ret = (long)data->bind_mode; 537e1051a39Sopenharmony_ci break; 538e1051a39Sopenharmony_ci case BIO_CTRL_DUP: 539e1051a39Sopenharmony_ci break; 540e1051a39Sopenharmony_ci case BIO_CTRL_EOF: 541e1051a39Sopenharmony_ci if (b->next_bio == NULL) 542e1051a39Sopenharmony_ci ret = 0; 543e1051a39Sopenharmony_ci else 544e1051a39Sopenharmony_ci ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 545e1051a39Sopenharmony_ci break; 546e1051a39Sopenharmony_ci default: 547e1051a39Sopenharmony_ci ret = 0; 548e1051a39Sopenharmony_ci break; 549e1051a39Sopenharmony_ci } 550e1051a39Sopenharmony_ci return ret; 551e1051a39Sopenharmony_ci} 552e1051a39Sopenharmony_ci 553e1051a39Sopenharmony_cistatic int acpt_puts(BIO *bp, const char *str) 554e1051a39Sopenharmony_ci{ 555e1051a39Sopenharmony_ci int n, ret; 556e1051a39Sopenharmony_ci 557e1051a39Sopenharmony_ci n = strlen(str); 558e1051a39Sopenharmony_ci ret = acpt_write(bp, str, n); 559e1051a39Sopenharmony_ci return ret; 560e1051a39Sopenharmony_ci} 561e1051a39Sopenharmony_ci 562e1051a39Sopenharmony_ciBIO *BIO_new_accept(const char *str) 563e1051a39Sopenharmony_ci{ 564e1051a39Sopenharmony_ci BIO *ret; 565e1051a39Sopenharmony_ci 566e1051a39Sopenharmony_ci ret = BIO_new(BIO_s_accept()); 567e1051a39Sopenharmony_ci if (ret == NULL) 568e1051a39Sopenharmony_ci return NULL; 569e1051a39Sopenharmony_ci if (BIO_set_accept_name(ret, str) > 0) 570e1051a39Sopenharmony_ci return ret; 571e1051a39Sopenharmony_ci BIO_free(ret); 572e1051a39Sopenharmony_ci return NULL; 573e1051a39Sopenharmony_ci} 574e1051a39Sopenharmony_ci 575e1051a39Sopenharmony_ci#endif 576