VirtualBox

source: vbox/trunk/src/libs/openssl-1.1.1g/crypto/bio/bss_conn.c@ 84032

Last change on this file since 84032 was 83916, checked in by vboxsync, 5 years ago

openssl-1.1.1g: Applied and adjusted our OpenSSL changes to 1.1.1g. bugref:9719

File size: 15.6 KB
Line 
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
13#include "bio_local.h"
14
15#ifndef OPENSSL_NO_SOCK
16
17typedef struct bio_connect_st {
18 int state;
19 int connect_family;
20 char *param_hostname;
21 char *param_service;
22 int connect_mode;
23
24 BIO_ADDRINFO *addr_first;
25 const BIO_ADDRINFO *addr_iter;
26 /*
27 * int socket; this will be kept in bio->num so that it is compatible
28 * with the bss_sock bio
29 */
30 /*
31 * called when the connection is initially made callback(BIO,state,ret);
32 * The callback should return 'ret'. state is for compatibility with the
33 * ssl info_callback
34 */
35 BIO_info_cb *info_callback;
36} BIO_CONNECT;
37
38static int conn_write(BIO *h, const char *buf, int num);
39static int conn_read(BIO *h, char *buf, int size);
40static int conn_puts(BIO *h, const char *str);
41static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2);
42static int conn_new(BIO *h);
43static int conn_free(BIO *data);
44static long conn_callback_ctrl(BIO *h, int cmd, BIO_info_cb *);
45
46static int conn_state(BIO *b, BIO_CONNECT *c);
47static void conn_close_socket(BIO *data);
48BIO_CONNECT *BIO_CONNECT_new(void);
49void BIO_CONNECT_free(BIO_CONNECT *a);
50
51#define BIO_CONN_S_BEFORE 1
52#define BIO_CONN_S_GET_ADDR 2
53#define BIO_CONN_S_CREATE_SOCKET 3
54#define BIO_CONN_S_CONNECT 4
55#define BIO_CONN_S_OK 5
56#define BIO_CONN_S_BLOCKED_CONNECT 6
57#define BIO_CONN_S_CONNECT_ERROR 7
58
59static const BIO_METHOD methods_connectp = {
60 BIO_TYPE_CONNECT,
61 "socket connect",
62 /* TODO: Convert to new style write function */
63 bwrite_conv,
64 conn_write,
65 /* TODO: Convert to new style read function */
66 bread_conv,
67 conn_read,
68 conn_puts,
69 NULL, /* conn_gets, */
70 conn_ctrl,
71 conn_new,
72 conn_free,
73 conn_callback_ctrl,
74};
75
76static int conn_state(BIO *b, BIO_CONNECT *c)
77{
78 int ret = -1, i;
79 BIO_info_cb *cb = NULL;
80
81 if (c->info_callback != NULL)
82 cb = c->info_callback;
83
84 for (;;) {
85 switch (c->state) {
86 case BIO_CONN_S_BEFORE:
87 if (c->param_hostname == NULL && c->param_service == NULL) {
88 BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED);
89 ERR_add_error_data(4,
90 "hostname=", c->param_hostname,
91 " service=", c->param_service);
92 goto exit_loop;
93 }
94 c->state = BIO_CONN_S_GET_ADDR;
95 break;
96
97 case BIO_CONN_S_GET_ADDR:
98 {
99 int family = AF_UNSPEC;
100 switch (c->connect_family) {
101 case BIO_FAMILY_IPV6:
102 if (1) { /* This is a trick we use to avoid bit rot.
103 * at least the "else" part will always be
104 * compiled.
105 */
106#ifdef AF_INET6
107 family = AF_INET6;
108 } else {
109#endif
110 BIOerr(BIO_F_CONN_STATE, BIO_R_UNAVAILABLE_IP_FAMILY);
111 goto exit_loop;
112 }
113 break;
114 case BIO_FAMILY_IPV4:
115 family = AF_INET;
116 break;
117 case BIO_FAMILY_IPANY:
118 family = AF_UNSPEC;
119 break;
120 default:
121 BIOerr(BIO_F_CONN_STATE, BIO_R_UNSUPPORTED_IP_FAMILY);
122 goto exit_loop;
123 }
124 if (BIO_lookup(c->param_hostname, c->param_service,
125 BIO_LOOKUP_CLIENT,
126 family, SOCK_STREAM, &c->addr_first) == 0)
127 goto exit_loop;
128 }
129 if (c->addr_first == NULL) {
130 BIOerr(BIO_F_CONN_STATE, BIO_R_LOOKUP_RETURNED_NOTHING);
131 goto exit_loop;
132 }
133 c->addr_iter = c->addr_first;
134 c->state = BIO_CONN_S_CREATE_SOCKET;
135 break;
136
137 case BIO_CONN_S_CREATE_SOCKET:
138 ret = BIO_socket(BIO_ADDRINFO_family(c->addr_iter),
139 BIO_ADDRINFO_socktype(c->addr_iter),
140 BIO_ADDRINFO_protocol(c->addr_iter), 0);
141 if (ret == (int)INVALID_SOCKET) {
142 SYSerr(SYS_F_SOCKET, get_last_socket_error());
143 ERR_add_error_data(4,
144 "hostname=", c->param_hostname,
145 " service=", c->param_service);
146 BIOerr(BIO_F_CONN_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET);
147 goto exit_loop;
148 }
149 b->num = ret;
150 c->state = BIO_CONN_S_CONNECT;
151 break;
152
153 case BIO_CONN_S_CONNECT:
154 BIO_clear_retry_flags(b);
155 ret = BIO_connect(b->num, BIO_ADDRINFO_address(c->addr_iter),
156 BIO_SOCK_KEEPALIVE | c->connect_mode);
157 b->retry_reason = 0;
158 if (ret == 0) {
159 if (BIO_sock_should_retry(ret)) {
160 BIO_set_retry_special(b);
161 c->state = BIO_CONN_S_BLOCKED_CONNECT;
162 b->retry_reason = BIO_RR_CONNECT;
163 ERR_clear_error();
164 } else if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter))
165 != NULL) {
166 /*
167 * if there are more addresses to try, do that first
168 */
169 BIO_closesocket(b->num);
170 c->state = BIO_CONN_S_CREATE_SOCKET;
171 ERR_clear_error();
172 break;
173 } else {
174 SYSerr(SYS_F_CONNECT, get_last_socket_error());
175 ERR_add_error_data(4,
176 "hostname=", c->param_hostname,
177 " service=", c->param_service);
178 c->state = BIO_CONN_S_CONNECT_ERROR;
179 break;
180 }
181 goto exit_loop;
182 } else {
183 c->state = BIO_CONN_S_OK;
184 }
185 break;
186
187 case BIO_CONN_S_BLOCKED_CONNECT:
188 i = BIO_sock_error(b->num);
189 if (i) {
190 BIO_clear_retry_flags(b);
191 SYSerr(SYS_F_CONNECT, i);
192 ERR_add_error_data(4,
193 "hostname=", c->param_hostname,
194 " service=", c->param_service);
195 BIOerr(BIO_F_CONN_STATE, BIO_R_NBIO_CONNECT_ERROR);
196 ret = 0;
197 goto exit_loop;
198 } else
199 c->state = BIO_CONN_S_OK;
200 break;
201
202 case BIO_CONN_S_CONNECT_ERROR:
203 BIOerr(BIO_F_CONN_STATE, BIO_R_CONNECT_ERROR);
204 ret = 0;
205 goto exit_loop;
206
207 case BIO_CONN_S_OK:
208 ret = 1;
209 goto exit_loop;
210 default:
211 /* abort(); */
212 goto exit_loop;
213 }
214
215 if (cb != NULL) {
216 if ((ret = cb((BIO *)b, c->state, ret)) == 0)
217 goto end;
218 }
219 }
220
221 /* Loop does not exit */
222 exit_loop:
223 if (cb != NULL)
224 ret = cb((BIO *)b, c->state, ret);
225 end:
226 return ret;
227}
228
229BIO_CONNECT *BIO_CONNECT_new(void)
230{
231 BIO_CONNECT *ret;
232
233 if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
234 BIOerr(BIO_F_BIO_CONNECT_NEW, ERR_R_MALLOC_FAILURE);
235 return NULL;
236 }
237 ret->state = BIO_CONN_S_BEFORE;
238 ret->connect_family = BIO_FAMILY_IPANY;
239 return ret;
240}
241
242void BIO_CONNECT_free(BIO_CONNECT *a)
243{
244 if (a == NULL)
245 return;
246 OPENSSL_free(a->param_hostname);
247 OPENSSL_free(a->param_service);
248 BIO_ADDRINFO_free(a->addr_first);
249 OPENSSL_free(a);
250}
251
252const BIO_METHOD *BIO_s_connect(void)
253{
254 return &methods_connectp;
255}
256
257static int conn_new(BIO *bi)
258{
259 bi->init = 0;
260 bi->num = (int)INVALID_SOCKET;
261 bi->flags = 0;
262 if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL)
263 return 0;
264 else
265 return 1;
266}
267
268static void conn_close_socket(BIO *bio)
269{
270 BIO_CONNECT *c;
271
272 c = (BIO_CONNECT *)bio->ptr;
273 if (bio->num != (int)INVALID_SOCKET) {
274 /* Only do a shutdown if things were established */
275 if (c->state == BIO_CONN_S_OK)
276 shutdown(bio->num, 2);
277 BIO_closesocket(bio->num);
278 bio->num = (int)INVALID_SOCKET;
279 }
280}
281
282static int conn_free(BIO *a)
283{
284 BIO_CONNECT *data;
285
286 if (a == NULL)
287 return 0;
288 data = (BIO_CONNECT *)a->ptr;
289
290 if (a->shutdown) {
291 conn_close_socket(a);
292 BIO_CONNECT_free(data);
293 a->ptr = NULL;
294 a->flags = 0;
295 a->init = 0;
296 }
297 return 1;
298}
299
300static int conn_read(BIO *b, char *out, int outl)
301{
302 int ret = 0;
303 BIO_CONNECT *data;
304
305 data = (BIO_CONNECT *)b->ptr;
306 if (data->state != BIO_CONN_S_OK) {
307 ret = conn_state(b, data);
308 if (ret <= 0)
309 return ret;
310 }
311
312 if (out != NULL) {
313 clear_socket_error();
314 ret = readsocket(b->num, out, outl);
315 BIO_clear_retry_flags(b);
316 if (ret <= 0) {
317 if (BIO_sock_should_retry(ret))
318 BIO_set_retry_read(b);
319 else if (ret == 0)
320 b->flags |= BIO_FLAGS_IN_EOF;
321 }
322 }
323 return ret;
324}
325
326static int conn_write(BIO *b, const char *in, int inl)
327{
328 int ret;
329 BIO_CONNECT *data;
330
331 data = (BIO_CONNECT *)b->ptr;
332 if (data->state != BIO_CONN_S_OK) {
333 ret = conn_state(b, data);
334 if (ret <= 0)
335 return ret;
336 }
337
338 clear_socket_error();
339 ret = writesocket(b->num, in, inl);
340 BIO_clear_retry_flags(b);
341 if (ret <= 0) {
342 if (BIO_sock_should_retry(ret))
343 BIO_set_retry_write(b);
344 }
345 return ret;
346}
347
348static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
349{
350 BIO *dbio;
351 int *ip;
352 const char **pptr = NULL;
353 long ret = 1;
354 BIO_CONNECT *data;
355
356 data = (BIO_CONNECT *)b->ptr;
357
358 switch (cmd) {
359 case BIO_CTRL_RESET:
360 ret = 0;
361 data->state = BIO_CONN_S_BEFORE;
362 conn_close_socket(b);
363 BIO_ADDRINFO_free(data->addr_first);
364 data->addr_first = NULL;
365 b->flags = 0;
366 break;
367 case BIO_C_DO_STATE_MACHINE:
368 /* use this one to start the connection */
369 if (data->state != BIO_CONN_S_OK)
370 ret = (long)conn_state(b, data);
371 else
372 ret = 1;
373 break;
374 case BIO_C_GET_CONNECT:
375 if (ptr != NULL) {
376 pptr = (const char **)ptr;
377 if (num == 0) {
378 *pptr = data->param_hostname;
379 } else if (num == 1) {
380 *pptr = data->param_service;
381 } else if (num == 2) {
382 *pptr = (const char *)BIO_ADDRINFO_address(data->addr_iter);
383 } else if (num == 3) {
384 switch (BIO_ADDRINFO_family(data->addr_iter)) {
385# ifdef AF_INET6
386 case AF_INET6:
387 ret = BIO_FAMILY_IPV6;
388 break;
389# endif
390 case AF_INET:
391 ret = BIO_FAMILY_IPV4;
392 break;
393 case 0:
394 ret = data->connect_family;
395 break;
396 default:
397 ret = -1;
398 break;
399 }
400 } else {
401 ret = 0;
402 }
403 } else {
404 ret = 0;
405 }
406 break;
407 case BIO_C_SET_CONNECT:
408 if (ptr != NULL) {
409 b->init = 1;
410 if (num == 0) {
411 char *hold_service = data->param_service;
412 /* We affect the hostname regardless. However, the input
413 * string might contain a host:service spec, so we must
414 * parse it, which might or might not affect the service
415 */
416 OPENSSL_free(data->param_hostname);
417 data->param_hostname = NULL;
418 ret = BIO_parse_hostserv(ptr,
419 &data->param_hostname,
420 &data->param_service,
421 BIO_PARSE_PRIO_HOST);
422 if (hold_service != data->param_service)
423 OPENSSL_free(hold_service);
424 } else if (num == 1) {
425 OPENSSL_free(data->param_service);
426 data->param_service = BUF_strdup(ptr);
427 } else if (num == 2) {
428 const BIO_ADDR *addr = (const BIO_ADDR *)ptr;
429 if (ret) {
430 data->param_hostname = BIO_ADDR_hostname_string(addr, 1);
431 data->param_service = BIO_ADDR_service_string(addr, 1);
432 BIO_ADDRINFO_free(data->addr_first);
433 data->addr_first = NULL;
434 data->addr_iter = NULL;
435 }
436 } else if (num == 3) {
437 data->connect_family = *(int *)ptr;
438 } else {
439 ret = 0;
440 }
441 }
442 break;
443 case BIO_C_SET_NBIO:
444 if (num != 0)
445 data->connect_mode |= BIO_SOCK_NONBLOCK;
446 else
447 data->connect_mode &= ~BIO_SOCK_NONBLOCK;
448 break;
449 case BIO_C_SET_CONNECT_MODE:
450 data->connect_mode = (int)num;
451 break;
452 case BIO_C_GET_FD:
453 if (b->init) {
454 ip = (int *)ptr;
455 if (ip != NULL)
456 *ip = b->num;
457 ret = b->num;
458 } else
459 ret = -1;
460 break;
461 case BIO_CTRL_GET_CLOSE:
462 ret = b->shutdown;
463 break;
464 case BIO_CTRL_SET_CLOSE:
465 b->shutdown = (int)num;
466 break;
467 case BIO_CTRL_PENDING:
468 case BIO_CTRL_WPENDING:
469 ret = 0;
470 break;
471 case BIO_CTRL_FLUSH:
472 break;
473 case BIO_CTRL_DUP:
474 {
475 dbio = (BIO *)ptr;
476 if (data->param_hostname)
477 BIO_set_conn_hostname(dbio, data->param_hostname);
478 if (data->param_service)
479 BIO_set_conn_port(dbio, data->param_service);
480 BIO_set_conn_ip_family(dbio, data->connect_family);
481 BIO_set_conn_mode(dbio, data->connect_mode);
482 /*
483 * FIXME: the cast of the function seems unlikely to be a good
484 * idea
485 */
486 (void)BIO_set_info_callback(dbio, data->info_callback);
487 }
488 break;
489 case BIO_CTRL_SET_CALLBACK:
490 ret = 0; /* use callback ctrl */
491 break;
492 case BIO_CTRL_GET_CALLBACK:
493 {
494 BIO_info_cb **fptr;
495
496 fptr = (BIO_info_cb **)ptr;
497 *fptr = data->info_callback;
498 }
499 break;
500 case BIO_CTRL_EOF:
501 ret = (b->flags & BIO_FLAGS_IN_EOF) != 0 ? 1 : 0;
502 break;
503 default:
504 ret = 0;
505 break;
506 }
507 return ret;
508}
509
510static long conn_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
511{
512 long ret = 1;
513 BIO_CONNECT *data;
514
515 data = (BIO_CONNECT *)b->ptr;
516
517 switch (cmd) {
518 case BIO_CTRL_SET_CALLBACK:
519 {
520 data->info_callback = fp;
521 }
522 break;
523 default:
524 ret = 0;
525 break;
526 }
527 return ret;
528}
529
530static int conn_puts(BIO *bp, const char *str)
531{
532 int n, ret;
533
534 n = strlen(str);
535 ret = conn_write(bp, str, n);
536 return ret;
537}
538
539BIO *BIO_new_connect(const char *str)
540{
541 BIO *ret;
542
543 ret = BIO_new(BIO_s_connect());
544 if (ret == NULL)
545 return NULL;
546 if (BIO_set_conn_hostname(ret, str))
547 return ret;
548 BIO_free(ret);
549 return NULL;
550}
551
552#endif
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette