Coverage Report

Created: 2025-04-22 06:18

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