]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/bio/bss_acpt.c
Update copyright year
[thirdparty/openssl.git] / crypto / bio / bss_acpt.c
1 /*
2 * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
3 *
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
8 */
9
10 #include <stdio.h>
11 #include <errno.h>
12 #include "bio_lcl.h"
13
14 #ifndef OPENSSL_NO_SOCK
15
16 typedef struct bio_accept_st {
17 int state;
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) */
21 char *param_addr;
22 char *param_serv;
23
24 int accept_sock;
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
33 BIO *bio_chain;
34 } BIO_ACCEPT;
35
36 static int acpt_write(BIO *h, const char *buf, int num);
37 static int acpt_read(BIO *h, char *buf, int size);
38 static int acpt_puts(BIO *h, const char *str);
39 static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2);
40 static int acpt_new(BIO *h);
41 static int acpt_free(BIO *data);
42 static int acpt_state(BIO *b, BIO_ACCEPT *c);
43 static void acpt_close_socket(BIO *data);
44 static BIO_ACCEPT *BIO_ACCEPT_new(void);
45 static void BIO_ACCEPT_free(BIO_ACCEPT *a);
46
47 # define ACPT_S_BEFORE 1
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
53
54 static const BIO_METHOD methods_acceptp = {
55 BIO_TYPE_ACCEPT,
56 "socket accept",
57 /* TODO: Convert to new style write function */
58 bwrite_conv,
59 acpt_write,
60 /* TODO: Convert to new style read function */
61 bread_conv,
62 acpt_read,
63 acpt_puts,
64 NULL, /* connect_gets, */
65 acpt_ctrl,
66 acpt_new,
67 acpt_free,
68 NULL, /* connect_callback_ctrl */
69 };
70
71 const BIO_METHOD *BIO_s_accept(void)
72 {
73 return &methods_acceptp;
74 }
75
76 static int acpt_new(BIO *bi)
77 {
78 BIO_ACCEPT *ba;
79
80 bi->init = 0;
81 bi->num = (int)INVALID_SOCKET;
82 bi->flags = 0;
83 if ((ba = BIO_ACCEPT_new()) == NULL)
84 return 0;
85 bi->ptr = (char *)ba;
86 ba->state = ACPT_S_BEFORE;
87 bi->shutdown = 1;
88 return 1;
89 }
90
91 static BIO_ACCEPT *BIO_ACCEPT_new(void)
92 {
93 BIO_ACCEPT *ret;
94
95 if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)
96 return NULL;
97 ret->accept_family = BIO_FAMILY_IPANY;
98 ret->accept_sock = (int)INVALID_SOCKET;
99 return ret;
100 }
101
102 static void BIO_ACCEPT_free(BIO_ACCEPT *a)
103 {
104 if (a == NULL)
105 return;
106
107 OPENSSL_free(a->param_addr);
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);
114 BIO_free(a->bio_chain);
115 OPENSSL_free(a);
116 }
117
118 static void acpt_close_socket(BIO *bio)
119 {
120 BIO_ACCEPT *c;
121
122 c = (BIO_ACCEPT *)bio->ptr;
123 if (c->accept_sock != (int)INVALID_SOCKET) {
124 shutdown(c->accept_sock, 2);
125 closesocket(c->accept_sock);
126 c->accept_sock = (int)INVALID_SOCKET;
127 bio->num = (int)INVALID_SOCKET;
128 }
129 }
130
131 static int acpt_free(BIO *a)
132 {
133 BIO_ACCEPT *data;
134
135 if (a == NULL)
136 return 0;
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 }
146 return 1;
147 }
148
149 static int acpt_state(BIO *b, BIO_ACCEPT *c)
150 {
151 BIO *bio = NULL, *dbio;
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;
163 }
164
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 }
249
250 {
251 union BIO_sock_info_u info;
252
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 }
260
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
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
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 }
295 }
296
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;
344 }
345 }
346
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;
354 }
355
356 static int acpt_read(BIO *b, char *out, int outl)
357 {
358 int ret = 0;
359 BIO_ACCEPT *data;
360
361 BIO_clear_retry_flags(b);
362 data = (BIO_ACCEPT *)b->ptr;
363
364 while (b->next_bio == NULL) {
365 ret = acpt_state(b, data);
366 if (ret <= 0)
367 return ret;
368 }
369
370 ret = BIO_read(b->next_bio, out, outl);
371 BIO_copy_next_retry(b);
372 return ret;
373 }
374
375 static int acpt_write(BIO *b, const char *in, int inl)
376 {
377 int ret;
378 BIO_ACCEPT *data;
379
380 BIO_clear_retry_flags(b);
381 data = (BIO_ACCEPT *)b->ptr;
382
383 while (b->next_bio == NULL) {
384 ret = acpt_state(b, data);
385 if (ret <= 0)
386 return ret;
387 }
388
389 ret = BIO_write(b->next_bio, in, inl);
390 BIO_copy_next_retry(b);
391 return ret;
392 }
393
394 static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
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);
408 BIO_ADDRINFO_free(data->addr_first);
409 data->addr_first = NULL;
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) {
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 */
424 OPENSSL_free(data->param_addr);
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;
433 } else if (num == 1) {
434 OPENSSL_free(data->param_serv);
435 data->param_serv = BUF_strdup(ptr);
436 b->init = 1;
437 } else if (num == 2) {
438 data->bind_mode |= BIO_SOCK_NONBLOCK;
439 } else if (num == 3) {
440 BIO_free(data->bio_chain);
441 data->bio_chain = (BIO *)ptr;
442 } else if (num == 4) {
443 data->accept_family = *(int *)ptr;
444 }
445 } else {
446 if (num == 2) {
447 data->bind_mode &= ~BIO_SOCK_NONBLOCK;
448 }
449 }
450 break;
451 case BIO_C_SET_NBIO:
452 if (num != 0)
453 data->accepted_mode |= BIO_SOCK_NONBLOCK;
454 else
455 data->accepted_mode &= ~BIO_SOCK_NONBLOCK;
456 break;
457 case BIO_C_SET_FD:
458 b->num = *((int *)ptr);
459 data->accept_sock = b->num;
460 data->state = ACPT_S_ACCEPT;
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) {
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) {
485 pp = (char **)ptr;
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 }
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:
528 break;
529
530 default:
531 ret = 0;
532 break;
533 }
534 return ret;
535 }
536
537 static int acpt_puts(BIO *bp, const char *str)
538 {
539 int n, ret;
540
541 n = strlen(str);
542 ret = acpt_write(bp, str, n);
543 return ret;
544 }
545
546 BIO *BIO_new_accept(const char *str)
547 {
548 BIO *ret;
549
550 ret = BIO_new(BIO_s_accept());
551 if (ret == NULL)
552 return NULL;
553 if (BIO_set_accept_name(ret, str))
554 return ret;
555 BIO_free(ret);
556 return NULL;
557 }
558
559 #endif