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