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