Coverage Report

Created: 2022-10-16 06:45

/src/openssl/crypto/bio/bss_conn.c
Line
Count
Source (jump to first uncovered line)
1
/* crypto/bio/bss_conn.c */
2
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3
 * All rights reserved.
4
 *
5
 * This package is an SSL implementation written
6
 * by Eric Young (eay@cryptsoft.com).
7
 * The implementation was written so as to conform with Netscapes SSL.
8
 *
9
 * This library is free for commercial and non-commercial use as long as
10
 * the following conditions are aheared to.  The following conditions
11
 * apply to all code found in this distribution, be it the RC4, RSA,
12
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13
 * included with this distribution is covered by the same copyright terms
14
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15
 *
16
 * Copyright remains Eric Young's, and as such any Copyright notices in
17
 * the code are not to be removed.
18
 * If this package is used in a product, Eric Young should be given attribution
19
 * as the author of the parts of the library used.
20
 * This can be in the form of a textual message at program startup or
21
 * in documentation (online or textual) provided with the package.
22
 *
23
 * Redistribution and use in source and binary forms, with or without
24
 * modification, are permitted provided that the following conditions
25
 * are met:
26
 * 1. Redistributions of source code must retain the copyright
27
 *    notice, this list of conditions and the following disclaimer.
28
 * 2. Redistributions in binary form must reproduce the above copyright
29
 *    notice, this list of conditions and the following disclaimer in the
30
 *    documentation and/or other materials provided with the distribution.
31
 * 3. All advertising materials mentioning features or use of this software
32
 *    must display the following acknowledgement:
33
 *    "This product includes cryptographic software written by
34
 *     Eric Young (eay@cryptsoft.com)"
35
 *    The word 'cryptographic' can be left out if the rouines from the library
36
 *    being used are not cryptographic related :-).
37
 * 4. If you include any Windows specific code (or a derivative thereof) from
38
 *    the apps directory (application code) you must include an acknowledgement:
39
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40
 *
41
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51
 * SUCH DAMAGE.
52
 *
53
 * The licence and distribution terms for any publically available version or
54
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55
 * copied and put under another distribution licence
56
 * [including the GNU Public Licence.]
57
 */
58
59
#include <stdio.h>
60
#include <errno.h>
61
#define USE_SOCKETS
62
#include "cryptlib.h"
63
#include <openssl/bio.h>
64
65
#ifndef OPENSSL_NO_SOCK
66
67
# ifdef OPENSSL_SYS_WIN16
68
#  define SOCKET_PROTOCOL 0     /* more microsoft stupidity */
69
# else
70
0
#  define SOCKET_PROTOCOL IPPROTO_TCP
71
# endif
72
73
# if (defined(OPENSSL_SYS_VMS) && __VMS_VER < 70000000)
74
/* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */
75
#  undef FIONBIO
76
# endif
77
78
typedef struct bio_connect_st {
79
    int state;
80
    char *param_hostname;
81
    char *param_port;
82
    int nbio;
83
    unsigned char ip[4];
84
    unsigned short port;
85
    struct sockaddr_in them;
86
    /*
87
     * int socket; this will be kept in bio->num so that it is compatible
88
     * with the bss_sock bio
89
     */
90
    /*
91
     * called when the connection is initially made callback(BIO,state,ret);
92
     * The callback should return 'ret'.  state is for compatibility with the
93
     * ssl info_callback
94
     */
95
    int (*info_callback) (const BIO *bio, int state, int ret);
96
} BIO_CONNECT;
97
98
static int conn_write(BIO *h, const char *buf, int num);
99
static int conn_read(BIO *h, char *buf, int size);
100
static int conn_puts(BIO *h, const char *str);
101
static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2);
102
static int conn_new(BIO *h);
103
static int conn_free(BIO *data);
104
static long conn_callback_ctrl(BIO *h, int cmd, bio_info_cb *);
105
106
static int conn_state(BIO *b, BIO_CONNECT *c);
107
static void conn_close_socket(BIO *data);
108
BIO_CONNECT *BIO_CONNECT_new(void);
109
void BIO_CONNECT_free(BIO_CONNECT *a);
110
111
static BIO_METHOD methods_connectp = {
112
    BIO_TYPE_CONNECT,
113
    "socket connect",
114
    conn_write,
115
    conn_read,
116
    conn_puts,
117
    NULL,                       /* connect_gets, */
118
    conn_ctrl,
119
    conn_new,
120
    conn_free,
121
    conn_callback_ctrl,
122
};
123
124
static int conn_state(BIO *b, BIO_CONNECT *c)
125
0
{
126
0
    int ret = -1, i;
127
0
    unsigned long l;
128
0
    char *p, *q;
129
0
    int (*cb) (const BIO *, int, int) = NULL;
130
131
0
    if (c->info_callback != NULL)
132
0
        cb = c->info_callback;
133
134
0
    for (;;) {
135
0
        switch (c->state) {
136
0
        case BIO_CONN_S_BEFORE:
137
0
            p = c->param_hostname;
138
0
            if (p == NULL) {
139
0
                BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_SPECIFIED);
140
0
                goto exit_loop;
141
0
            }
142
0
            for (; *p != '\0'; p++) {
143
0
                if ((*p == ':') || (*p == '/'))
144
0
                    break;
145
0
            }
146
147
0
            i = *p;
148
0
            if ((i == ':') || (i == '/')) {
149
150
0
                *(p++) = '\0';
151
0
                if (i == ':') {
152
0
                    for (q = p; *q; q++)
153
0
                        if (*q == '/') {
154
0
                            *q = '\0';
155
0
                            break;
156
0
                        }
157
0
                    if (c->param_port != NULL)
158
0
                        OPENSSL_free(c->param_port);
159
0
                    c->param_port = BUF_strdup(p);
160
0
                }
161
0
            }
162
163
0
            if (c->param_port == NULL) {
164
0
                BIOerr(BIO_F_CONN_STATE, BIO_R_NO_PORT_SPECIFIED);
165
0
                ERR_add_error_data(2, "host=", c->param_hostname);
166
0
                goto exit_loop;
167
0
            }
168
0
            c->state = BIO_CONN_S_GET_IP;
169
0
            break;
170
171
0
        case BIO_CONN_S_GET_IP:
172
0
            if (BIO_get_host_ip(c->param_hostname, &(c->ip[0])) <= 0)
173
0
                goto exit_loop;
174
0
            c->state = BIO_CONN_S_GET_PORT;
175
0
            break;
176
177
0
        case BIO_CONN_S_GET_PORT:
178
0
            if (c->param_port == NULL) {
179
                /* abort(); */
180
0
                goto exit_loop;
181
0
            } else if (BIO_get_port(c->param_port, &c->port) <= 0)
182
0
                goto exit_loop;
183
0
            c->state = BIO_CONN_S_CREATE_SOCKET;
184
0
            break;
185
186
0
        case BIO_CONN_S_CREATE_SOCKET:
187
            /* now setup address */
188
0
            memset((char *)&c->them, 0, sizeof(c->them));
189
0
            c->them.sin_family = AF_INET;
190
0
            c->them.sin_port = htons((unsigned short)c->port);
191
0
            l = (unsigned long)
192
0
                ((unsigned long)c->ip[0] << 24L) |
193
0
                ((unsigned long)c->ip[1] << 16L) |
194
0
                ((unsigned long)c->ip[2] << 8L) | ((unsigned long)c->ip[3]);
195
0
            c->them.sin_addr.s_addr = htonl(l);
196
0
            c->state = BIO_CONN_S_CREATE_SOCKET;
197
198
0
            ret = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL);
199
0
            if (ret == INVALID_SOCKET) {
200
0
                SYSerr(SYS_F_SOCKET, get_last_socket_error());
201
0
                ERR_add_error_data(4, "host=", c->param_hostname,
202
0
                                   ":", c->param_port);
203
0
                BIOerr(BIO_F_CONN_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET);
204
0
                goto exit_loop;
205
0
            }
206
0
            b->num = ret;
207
0
            c->state = BIO_CONN_S_NBIO;
208
0
            break;
209
210
0
        case BIO_CONN_S_NBIO:
211
0
            if (c->nbio) {
212
0
                if (!BIO_socket_nbio(b->num, 1)) {
213
0
                    BIOerr(BIO_F_CONN_STATE, BIO_R_ERROR_SETTING_NBIO);
214
0
                    ERR_add_error_data(4, "host=",
215
0
                                       c->param_hostname, ":", c->param_port);
216
0
                    goto exit_loop;
217
0
                }
218
0
            }
219
0
            c->state = BIO_CONN_S_CONNECT;
220
221
0
# if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE)
222
0
            i = 1;
223
0
            i = setsockopt(b->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i,
224
0
                           sizeof(i));
225
0
            if (i < 0) {
226
0
                SYSerr(SYS_F_SOCKET, get_last_socket_error());
227
0
                ERR_add_error_data(4, "host=", c->param_hostname,
228
0
                                   ":", c->param_port);
229
0
                BIOerr(BIO_F_CONN_STATE, BIO_R_KEEPALIVE);
230
0
                goto exit_loop;
231
0
            }
232
0
# endif
233
0
            break;
234
235
0
        case BIO_CONN_S_CONNECT:
236
0
            BIO_clear_retry_flags(b);
237
0
            ret = connect(b->num,
238
0
                          (struct sockaddr *)&c->them, sizeof(c->them));
239
0
            b->retry_reason = 0;
240
0
            if (ret < 0) {
241
0
                if (BIO_sock_should_retry(ret)) {
242
0
                    BIO_set_retry_special(b);
243
0
                    c->state = BIO_CONN_S_BLOCKED_CONNECT;
244
0
                    b->retry_reason = BIO_RR_CONNECT;
245
0
                } else {
246
0
                    SYSerr(SYS_F_CONNECT, get_last_socket_error());
247
0
                    ERR_add_error_data(4, "host=",
248
0
                                       c->param_hostname, ":", c->param_port);
249
0
                    BIOerr(BIO_F_CONN_STATE, BIO_R_CONNECT_ERROR);
250
0
                }
251
0
                goto exit_loop;
252
0
            } else
253
0
                c->state = BIO_CONN_S_OK;
254
0
            break;
255
256
0
        case BIO_CONN_S_BLOCKED_CONNECT:
257
0
            i = BIO_sock_error(b->num);
258
0
            if (i) {
259
0
                BIO_clear_retry_flags(b);
260
0
                SYSerr(SYS_F_CONNECT, i);
261
0
                ERR_add_error_data(4, "host=",
262
0
                                   c->param_hostname, ":", c->param_port);
263
0
                BIOerr(BIO_F_CONN_STATE, BIO_R_NBIO_CONNECT_ERROR);
264
0
                ret = 0;
265
0
                goto exit_loop;
266
0
            } else
267
0
                c->state = BIO_CONN_S_OK;
268
0
            break;
269
270
0
        case BIO_CONN_S_OK:
271
0
            ret = 1;
272
0
            goto exit_loop;
273
0
        default:
274
            /* abort(); */
275
0
            goto exit_loop;
276
0
        }
277
278
0
        if (cb != NULL) {
279
0
            if (!(ret = cb((BIO *)b, c->state, ret)))
280
0
                goto end;
281
0
        }
282
0
    }
283
284
    /* Loop does not exit */
285
0
 exit_loop:
286
0
    if (cb != NULL)
287
0
        ret = cb((BIO *)b, c->state, ret);
288
0
 end:
289
0
    return (ret);
290
0
}
291
292
BIO_CONNECT *BIO_CONNECT_new(void)
293
0
{
294
0
    BIO_CONNECT *ret;
295
296
0
    if ((ret = (BIO_CONNECT *)OPENSSL_malloc(sizeof(BIO_CONNECT))) == NULL)
297
0
        return (NULL);
298
0
    ret->state = BIO_CONN_S_BEFORE;
299
0
    ret->param_hostname = NULL;
300
0
    ret->param_port = NULL;
301
0
    ret->info_callback = NULL;
302
0
    ret->nbio = 0;
303
0
    ret->ip[0] = 0;
304
0
    ret->ip[1] = 0;
305
0
    ret->ip[2] = 0;
306
0
    ret->ip[3] = 0;
307
0
    ret->port = 0;
308
0
    memset((char *)&ret->them, 0, sizeof(ret->them));
309
0
    return (ret);
310
0
}
311
312
void BIO_CONNECT_free(BIO_CONNECT *a)
313
0
{
314
0
    if (a == NULL)
315
0
        return;
316
317
0
    if (a->param_hostname != NULL)
318
0
        OPENSSL_free(a->param_hostname);
319
0
    if (a->param_port != NULL)
320
0
        OPENSSL_free(a->param_port);
321
0
    OPENSSL_free(a);
322
0
}
323
324
BIO_METHOD *BIO_s_connect(void)
325
0
{
326
0
    return (&methods_connectp);
327
0
}
328
329
static int conn_new(BIO *bi)
330
0
{
331
0
    bi->init = 0;
332
0
    bi->num = INVALID_SOCKET;
333
0
    bi->flags = 0;
334
0
    if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL)
335
0
        return (0);
336
0
    else
337
0
        return (1);
338
0
}
339
340
static void conn_close_socket(BIO *bio)
341
0
{
342
0
    BIO_CONNECT *c;
343
344
0
    c = (BIO_CONNECT *)bio->ptr;
345
0
    if (bio->num != INVALID_SOCKET) {
346
        /* Only do a shutdown if things were established */
347
0
        if (c->state == BIO_CONN_S_OK)
348
0
            shutdown(bio->num, 2);
349
0
        closesocket(bio->num);
350
0
        bio->num = INVALID_SOCKET;
351
0
    }
352
0
}
353
354
static int conn_free(BIO *a)
355
0
{
356
0
    BIO_CONNECT *data;
357
358
0
    if (a == NULL)
359
0
        return (0);
360
0
    data = (BIO_CONNECT *)a->ptr;
361
362
0
    if (a->shutdown) {
363
0
        conn_close_socket(a);
364
0
        BIO_CONNECT_free(data);
365
0
        a->ptr = NULL;
366
0
        a->flags = 0;
367
0
        a->init = 0;
368
0
    }
369
0
    return (1);
370
0
}
371
372
static int conn_read(BIO *b, char *out, int outl)
373
0
{
374
0
    int ret = 0;
375
0
    BIO_CONNECT *data;
376
377
0
    data = (BIO_CONNECT *)b->ptr;
378
0
    if (data->state != BIO_CONN_S_OK) {
379
0
        ret = conn_state(b, data);
380
0
        if (ret <= 0)
381
0
            return (ret);
382
0
    }
383
384
0
    if (out != NULL) {
385
0
        clear_socket_error();
386
0
        ret = readsocket(b->num, out, outl);
387
0
        BIO_clear_retry_flags(b);
388
0
        if (ret <= 0) {
389
0
            if (BIO_sock_should_retry(ret))
390
0
                BIO_set_retry_read(b);
391
0
        }
392
0
    }
393
0
    return (ret);
394
0
}
395
396
static int conn_write(BIO *b, const char *in, int inl)
397
0
{
398
0
    int ret;
399
0
    BIO_CONNECT *data;
400
401
0
    data = (BIO_CONNECT *)b->ptr;
402
0
    if (data->state != BIO_CONN_S_OK) {
403
0
        ret = conn_state(b, data);
404
0
        if (ret <= 0)
405
0
            return (ret);
406
0
    }
407
408
0
    clear_socket_error();
409
0
    ret = writesocket(b->num, in, inl);
410
0
    BIO_clear_retry_flags(b);
411
0
    if (ret <= 0) {
412
0
        if (BIO_sock_should_retry(ret))
413
0
            BIO_set_retry_write(b);
414
0
    }
415
0
    return (ret);
416
0
}
417
418
static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
419
0
{
420
0
    BIO *dbio;
421
0
    int *ip;
422
0
    const char **pptr = NULL;
423
0
    long ret = 1;
424
0
    BIO_CONNECT *data;
425
426
0
    data = (BIO_CONNECT *)b->ptr;
427
428
0
    switch (cmd) {
429
0
    case BIO_CTRL_RESET:
430
0
        ret = 0;
431
0
        data->state = BIO_CONN_S_BEFORE;
432
0
        conn_close_socket(b);
433
0
        b->flags = 0;
434
0
        break;
435
0
    case BIO_C_DO_STATE_MACHINE:
436
        /* use this one to start the connection */
437
0
        if (data->state != BIO_CONN_S_OK)
438
0
            ret = (long)conn_state(b, data);
439
0
        else
440
0
            ret = 1;
441
0
        break;
442
0
    case BIO_C_GET_CONNECT:
443
0
        if (ptr != NULL) {
444
0
            pptr = (const char **)ptr;
445
0
        }
446
447
0
        if (b->init) {
448
0
            if (pptr != NULL) {
449
0
                ret = 1;
450
0
                if (num == 0) {
451
0
                    *pptr = data->param_hostname;
452
0
                } else if (num == 1) {
453
0
                    *pptr = data->param_port;
454
0
                } else if (num == 2) {
455
0
                    *pptr = (char *)&(data->ip[0]);
456
0
                } else {
457
0
                    ret = 0;
458
0
                }
459
0
            }
460
0
            if (num == 3) {
461
0
                ret = data->port;
462
0
            }
463
0
        } else {
464
0
            if (pptr != NULL)
465
0
                *pptr = "not initialized";
466
0
            ret = 0;
467
0
        }
468
0
        break;
469
0
    case BIO_C_SET_CONNECT:
470
0
        if (ptr != NULL) {
471
0
            b->init = 1;
472
0
            if (num == 0) {
473
0
                if (data->param_hostname != NULL)
474
0
                    OPENSSL_free(data->param_hostname);
475
0
                data->param_hostname = BUF_strdup(ptr);
476
0
            } else if (num == 1) {
477
0
                if (data->param_port != NULL)
478
0
                    OPENSSL_free(data->param_port);
479
0
                data->param_port = BUF_strdup(ptr);
480
0
            } else if (num == 2) {
481
0
                char buf[16];
482
0
                unsigned char *p = ptr;
483
484
0
                BIO_snprintf(buf, sizeof buf, "%d.%d.%d.%d",
485
0
                             p[0], p[1], p[2], p[3]);
486
0
                if (data->param_hostname != NULL)
487
0
                    OPENSSL_free(data->param_hostname);
488
0
                data->param_hostname = BUF_strdup(buf);
489
0
                memcpy(&(data->ip[0]), ptr, 4);
490
0
            } else if (num == 3) {
491
0
                char buf[DECIMAL_SIZE(int) + 1];
492
493
0
                BIO_snprintf(buf, sizeof buf, "%d", *(int *)ptr);
494
0
                if (data->param_port != NULL)
495
0
                    OPENSSL_free(data->param_port);
496
0
                data->param_port = BUF_strdup(buf);
497
0
                data->port = *(int *)ptr;
498
0
            }
499
0
        }
500
0
        break;
501
0
    case BIO_C_SET_NBIO:
502
0
        data->nbio = (int)num;
503
0
        break;
504
0
    case BIO_C_GET_FD:
505
0
        if (b->init) {
506
0
            ip = (int *)ptr;
507
0
            if (ip != NULL)
508
0
                *ip = b->num;
509
0
            ret = b->num;
510
0
        } else
511
0
            ret = -1;
512
0
        break;
513
0
    case BIO_CTRL_GET_CLOSE:
514
0
        ret = b->shutdown;
515
0
        break;
516
0
    case BIO_CTRL_SET_CLOSE:
517
0
        b->shutdown = (int)num;
518
0
        break;
519
0
    case BIO_CTRL_PENDING:
520
0
    case BIO_CTRL_WPENDING:
521
0
        ret = 0;
522
0
        break;
523
0
    case BIO_CTRL_FLUSH:
524
0
        break;
525
0
    case BIO_CTRL_DUP:
526
0
        {
527
0
            dbio = (BIO *)ptr;
528
0
            if (data->param_port)
529
0
                BIO_set_conn_port(dbio, data->param_port);
530
0
            if (data->param_hostname)
531
0
                BIO_set_conn_hostname(dbio, data->param_hostname);
532
0
            BIO_set_nbio(dbio, data->nbio);
533
            /*
534
             * FIXME: the cast of the function seems unlikely to be a good
535
             * idea
536
             */
537
0
            (void)BIO_set_info_callback(dbio,
538
0
                                        (bio_info_cb *)data->info_callback);
539
0
        }
540
0
        break;
541
0
    case BIO_CTRL_SET_CALLBACK:
542
0
        {
543
# if 0                          /* FIXME: Should this be used? -- Richard
544
                                 * Levitte */
545
            BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
546
            ret = -1;
547
# else
548
0
            ret = 0;
549
0
# endif
550
0
        }
551
0
        break;
552
0
    case BIO_CTRL_GET_CALLBACK:
553
0
        {
554
0
            int (**fptr) (const BIO *bio, int state, int xret);
555
556
0
            fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
557
0
            *fptr = data->info_callback;
558
0
        }
559
0
        break;
560
0
    default:
561
0
        ret = 0;
562
0
        break;
563
0
    }
564
0
    return (ret);
565
0
}
566
567
static long conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
568
0
{
569
0
    long ret = 1;
570
0
    BIO_CONNECT *data;
571
572
0
    data = (BIO_CONNECT *)b->ptr;
573
574
0
    switch (cmd) {
575
0
    case BIO_CTRL_SET_CALLBACK:
576
0
        {
577
0
            data->info_callback =
578
0
                (int (*)(const struct bio_st *, int, int))fp;
579
0
        }
580
0
        break;
581
0
    default:
582
0
        ret = 0;
583
0
        break;
584
0
    }
585
0
    return (ret);
586
0
}
587
588
static int conn_puts(BIO *bp, const char *str)
589
0
{
590
0
    int n, ret;
591
592
0
    n = strlen(str);
593
0
    ret = conn_write(bp, str, n);
594
0
    return (ret);
595
0
}
596
597
BIO *BIO_new_connect(const char *str)
598
0
{
599
0
    BIO *ret;
600
601
0
    ret = BIO_new(BIO_s_connect());
602
0
    if (ret == NULL)
603
0
        return (NULL);
604
0
    if (BIO_set_conn_hostname(ret, str))
605
0
        return (ret);
606
0
    else {
607
0
        BIO_free(ret);
608
0
        return (NULL);
609
0
    }
610
0
}
611
612
#endif