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