VirtualBox

source: vbox/trunk/src/libs/openssl-1.1.1l/crypto/bio/bss_acpt.c@ 91977

最後變更 在這個檔案從91977是 91772,由 vboxsync 提交於 3 年 前

openssl-1.1.1l: Applied and adjusted our OpenSSL changes to 1.1.1l. bugref:10126

檔案大小: 16.1 KB
 
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
16typedef 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
36static int acpt_write(BIO *h, const char *buf, int num);
37static int acpt_read(BIO *h, char *buf, int size);
38static int acpt_puts(BIO *h, const char *str);
39static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2);
40static int acpt_new(BIO *h);
41static int acpt_free(BIO *data);
42static int acpt_state(BIO *b, BIO_ACCEPT *c);
43static void acpt_close_socket(BIO *data);
44static BIO_ACCEPT *BIO_ACCEPT_new(void);
45static 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
54static 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
71const BIO_METHOD *BIO_s_accept(void)
72{
73 return &methods_acceptp;
74}
75
76static 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
91static 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
104static 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
119static 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
132static 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
150static 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
358static 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
377static 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
396static 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 if ((data->param_serv = OPENSSL_strdup(ptr)) == NULL)
438 ret = 0;
439 else
440 b->init = 1;
441 } else if (num == 2) {
442 data->bind_mode |= BIO_SOCK_NONBLOCK;
443 } else if (num == 3) {
444 BIO_free(data->bio_chain);
445 data->bio_chain = (BIO *)ptr;
446 } else if (num == 4) {
447 data->accept_family = *(int *)ptr;
448 }
449 } else {
450 if (num == 2) {
451 data->bind_mode &= ~BIO_SOCK_NONBLOCK;
452 }
453 }
454 break;
455 case BIO_C_SET_NBIO:
456 if (num != 0)
457 data->accepted_mode |= BIO_SOCK_NONBLOCK;
458 else
459 data->accepted_mode &= ~BIO_SOCK_NONBLOCK;
460 break;
461 case BIO_C_SET_FD:
462 b->num = *((int *)ptr);
463 data->accept_sock = b->num;
464 data->state = ACPT_S_ACCEPT;
465 b->shutdown = (int)num;
466 b->init = 1;
467 break;
468 case BIO_C_GET_FD:
469 if (b->init) {
470 ip = (int *)ptr;
471 if (ip != NULL)
472 *ip = data->accept_sock;
473 ret = data->accept_sock;
474 } else
475 ret = -1;
476 break;
477 case BIO_C_GET_ACCEPT:
478 if (b->init) {
479 if (num == 0 && ptr != NULL) {
480 pp = (char **)ptr;
481 *pp = data->cache_accepting_name;
482 } else if (num == 1 && ptr != NULL) {
483 pp = (char **)ptr;
484 *pp = data->cache_accepting_serv;
485 } else if (num == 2 && ptr != NULL) {
486 pp = (char **)ptr;
487 *pp = data->cache_peer_name;
488 } else if (num == 3 && ptr != NULL) {
489 pp = (char **)ptr;
490 *pp = data->cache_peer_serv;
491 } else if (num == 4) {
492 switch (BIO_ADDRINFO_family(data->addr_iter)) {
493#ifdef AF_INET6
494 case AF_INET6:
495 ret = BIO_FAMILY_IPV6;
496 break;
497#endif
498 case AF_INET:
499 ret = BIO_FAMILY_IPV4;
500 break;
501 case 0:
502 ret = data->accept_family;
503 break;
504 default:
505 ret = -1;
506 break;
507 }
508 } else
509 ret = -1;
510 } else
511 ret = -1;
512 break;
513 case BIO_CTRL_GET_CLOSE:
514 ret = b->shutdown;
515 break;
516 case BIO_CTRL_SET_CLOSE:
517 b->shutdown = (int)num;
518 break;
519 case BIO_CTRL_PENDING:
520 case BIO_CTRL_WPENDING:
521 ret = 0;
522 break;
523 case BIO_CTRL_FLUSH:
524 break;
525 case BIO_C_SET_BIND_MODE:
526 data->bind_mode = (int)num;
527 break;
528 case BIO_C_GET_BIND_MODE:
529 ret = (long)data->bind_mode;
530 break;
531 case BIO_CTRL_DUP:
532 break;
533 case BIO_CTRL_EOF:
534 if (b->next_bio == NULL)
535 ret = 0;
536 else
537 ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
538 break;
539 default:
540 ret = 0;
541 break;
542 }
543 return ret;
544}
545
546static int acpt_puts(BIO *bp, const char *str)
547{
548 int n, ret;
549
550 n = strlen(str);
551 ret = acpt_write(bp, str, n);
552 return ret;
553}
554
555BIO *BIO_new_accept(const char *str)
556{
557 BIO *ret;
558
559 ret = BIO_new(BIO_s_accept());
560 if (ret == NULL)
561 return NULL;
562 if (BIO_set_accept_name(ret, str))
563 return ret;
564 BIO_free(ret);
565 return NULL;
566}
567
568#endif
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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