aboutsummaryrefslogtreecommitdiff
path: root/networking/tls.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/tls.c')
-rw-r--r--networking/tls.c530
1 files changed, 516 insertions, 14 deletions
diff --git a/networking/tls.c b/networking/tls.c
index ac6f0767f..97217f435 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -10,18 +10,19 @@
10//Config.src also defines FEATURE_TLS_SHA1 option 10//Config.src also defines FEATURE_TLS_SHA1 option
11 11
12//kbuild:lib-$(CONFIG_TLS) += tls.o 12//kbuild:lib-$(CONFIG_TLS) += tls.o
13//kbuild:lib-$(CONFIG_TLS) += tls_pstm.o 13//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm.o
14//kbuild:lib-$(CONFIG_TLS) += tls_pstm_montgomery_reduce.o 14//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_montgomery_reduce.o
15//kbuild:lib-$(CONFIG_TLS) += tls_pstm_mul_comba.o 15//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_mul_comba.o
16//kbuild:lib-$(CONFIG_TLS) += tls_pstm_sqr_comba.o 16//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_sqr_comba.o
17//kbuild:lib-$(CONFIG_TLS) += tls_aes.o 17//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_aes.o
18//kbuild:lib-$(CONFIG_TLS) += tls_aesgcm.o 18//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_aesgcm.o
19//kbuild:lib-$(CONFIG_TLS) += tls_rsa.o 19//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_rsa.o
20//kbuild:lib-$(CONFIG_TLS) += tls_fe.o 20//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_fe.o
21//kbuild:lib-$(CONFIG_TLS) += tls_sp_c32.o 21//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_sp_c32.o
22 22
23#include "tls.h" 23#include "tls.h"
24 24
25#if !ENABLE_FEATURE_TLS_SCHANNEL
25// Usually enabled. You can disable some of them to force only 26// Usually enabled. You can disable some of them to force only
26// specific ciphers to be advertized to server. 27// specific ciphers to be advertized to server.
27// (this would not exclude code to handle disabled ciphers, no code size win) 28// (this would not exclude code to handle disabled ciphers, no code size win)
@@ -329,7 +330,7 @@ static void dump_tls_record(const void *vp, int len)
329 330
330void FAST_FUNC tls_get_random(void *buf, unsigned len) 331void FAST_FUNC tls_get_random(void *buf, unsigned len)
331{ 332{
332 if (len != open_read_close("/dev/urandom", buf, len)) 333 if (len != MINGW_SPECIAL(open_read_close)("/dev/urandom", buf, len))
333 xfunc_die(); 334 xfunc_die();
334} 335}
335 336
@@ -417,7 +418,7 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/
417#define SEED label, label_size, seed, seed_size 418#define SEED label, label_size, seed, seed_size
418#define A a, MAC_size 419#define A a, MAC_size
419 420
420 hmac_begin(&ctx, secret, secret_size, sha256_begin); 421 hmac_begin(&ctx, secret, secret_size, sha256_begin_hmac);
421 422
422 /* A(1) = HMAC_hash(secret, seed) */ 423 /* A(1) = HMAC_hash(secret, seed) */
423 hmac_peek_hash(&ctx, a, SEED, NULL); 424 hmac_peek_hash(&ctx, a, SEED, NULL);
@@ -429,6 +430,7 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/
429 /* (use a[] as temp buffer) */ 430 /* (use a[] as temp buffer) */
430 hmac_peek_hash(&ctx, a, A, SEED, NULL); 431 hmac_peek_hash(&ctx, a, A, SEED, NULL);
431 memcpy(out_p, a, outbuf_size); 432 memcpy(out_p, a, outbuf_size);
433 hmac_uninit(&ctx);
432 return; 434 return;
433 } 435 }
434 /* Not last block. Store directly to result buffer */ 436 /* Not last block. Store directly to result buffer */
@@ -512,18 +514,21 @@ static unsigned hmac_blocks(tls_state_t *tls, uint8_t *out, uint8_t *key, unsign
512{ 514{
513 hmac_ctx_t ctx; 515 hmac_ctx_t ctx;
514 va_list va; 516 va_list va;
517 unsigned len;
515 518
516 hmac_begin(&ctx, key, key_size, 519 hmac_begin(&ctx, key, key_size,
517 (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE) 520 (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE)
518 ? sha1_begin 521 ? sha1_begin_hmac
519 : sha256_begin 522 : sha256_begin_hmac
520 ); 523 );
521 524
522 va_start(va, key_size); 525 va_start(va, key_size);
523 hmac_hash_v(&ctx, va); 526 hmac_hash_v(&ctx, va);
524 va_end(va); 527 va_end(va);
525 528
526 return hmac_end(&ctx, out); 529 len = hmac_end(&ctx, out);
530 hmac_uninit(&ctx);
531 return len;
527} 532}
528 533
529static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) 534static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type)
@@ -2357,3 +2362,500 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags)
2357 } 2362 }
2358 } 2363 }
2359} 2364}
2365#else
2366#include <stdbool.h>
2367
2368#if ENABLE_FEATURE_TLS_SCHANNEL_1_3
2369#include <subauth.h>
2370#endif
2371
2372#define SCHANNEL_USE_BLACKLISTS
2373
2374#include <security.h>
2375#include <schannel.h>
2376
2377#ifndef SECBUFFER_ALERT
2378# define SECBUFFER_ALERT 17
2379#endif
2380
2381#ifndef SP_PROT_TLS1_0_CLIENT
2382# define SP_PROT_TLS1_0_CLIENT 0x00000080
2383# define SP_PROT_TLS1_1_CLIENT 0x00000200
2384# define SP_PROT_TLS1_2_CLIENT 0x00000800
2385# define SCH_USE_STRONG_CRYPTO 0x00400000
2386#endif
2387
2388#define BB_SCHANNEL_ISC_FLAGS \
2389 (ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY | ISC_REQ_REPLAY_DETECT | \
2390 ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS)
2391
2392#define SEC_STATUS_FAIL(status) ((status) != SEC_E_OK)
2393
2394static char *hresult_to_error_string(HRESULT result) {
2395 char *output = NULL;
2396
2397 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
2398 | FORMAT_MESSAGE_IGNORE_INSERTS |
2399 FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, result,
2400 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2401 (char *) &output, 0, NULL);
2402 return output;
2403}
2404
2405static void init_sec_buffer(SecBuffer *buffer, void *pvBuffer, unsigned long cbBuffer, unsigned long BufferType) {
2406 buffer->BufferType = BufferType;
2407 buffer->cbBuffer = cbBuffer;
2408 buffer->pvBuffer = pvBuffer;
2409}
2410
2411#define init_sec_buffer_empty(buffer, BufferType) init_sec_buffer(buffer, NULL, 0, BufferType)
2412
2413static void init_sec_buffer_desc(SecBufferDesc *desc, SecBuffer *buffers, unsigned long buffer_count) {
2414 desc->ulVersion = SECBUFFER_VERSION;
2415 desc->cBuffers = buffer_count;
2416 desc->pBuffers = buffers;
2417}
2418
2419static ssize_t tls_read(tls_state_t *state, char *buf, ssize_t len) {
2420 ssize_t amount_read = 0;
2421
2422 if (state->connection_state > BB_SCHANNEL_OPEN) {
2423 goto Success;
2424 }
2425
2426 while (len > 0) {
2427 if (state->out_buffer) {
2428 unsigned long copy_amount =
2429 min(len, (ssize_t)state->out_buffer_length);
2430 memcpy(buf, state->out_buffer, copy_amount);
2431
2432 amount_read += copy_amount;
2433 buf += copy_amount;
2434 len -= copy_amount;
2435
2436 if (copy_amount == state->out_buffer_length) {
2437 if (state->out_buffer_extra > 0) {
2438 memmove(
2439 state->in_buffer,
2440 state->in_buffer +
2441 (state->in_buffer_offset - state->out_buffer_extra),
2442 state->in_buffer_offset - (state->in_buffer_offset -
2443 state->out_buffer_extra));
2444 state->in_buffer_offset = state->out_buffer_extra;
2445 } else {
2446 state->in_buffer_offset = 0;
2447 }
2448
2449 state->out_buffer = NULL;
2450 state->out_buffer_length = 0;
2451 state->out_buffer_extra = 0;
2452
2453 } else {
2454 state->out_buffer_length -= copy_amount;
2455 state->out_buffer += copy_amount;
2456 }
2457 } else {
2458 SecBuffer buffers[4];
2459 SecBufferDesc desc;
2460 SECURITY_STATUS status;
2461
2462 init_sec_buffer(&buffers[0],
2463 state->in_buffer,
2464 state->in_buffer_offset,
2465 SECBUFFER_DATA);
2466 init_sec_buffer_empty(&buffers[1], SECBUFFER_EMPTY);
2467 init_sec_buffer_empty(&buffers[2], SECBUFFER_EMPTY);
2468 init_sec_buffer_empty(&buffers[3], SECBUFFER_EMPTY);
2469
2470 init_sec_buffer_desc(&desc, buffers, _countof(buffers));
2471
2472 status = DecryptMessage(&state->ctx_handle, &desc, 0, NULL);
2473
2474 switch (status) {
2475 case SEC_E_OK: {
2476 state->out_buffer = buffers[1].pvBuffer;
2477 state->out_buffer_length = buffers[1].cbBuffer;
2478 state->out_buffer_extra = state->in_buffer_offset;
2479
2480 if (buffers[3].BufferType == SECBUFFER_EXTRA) {
2481 state->out_buffer_extra = buffers[3].cbBuffer;
2482 } else {
2483 state->out_buffer_extra = 0;
2484 }
2485
2486 continue;
2487 }
2488 case SEC_I_CONTEXT_EXPIRED: {
2489 // Shut down the connection
2490 state->connection_state = BB_SCHANNEL_CLOSED;
2491 goto Success;
2492 }
2493 case SEC_E_INCOMPLETE_MESSAGE: {
2494 int result = safe_read(state->ifd,
2495 state->in_buffer + state->in_buffer_offset,
2496 sizeof(state->in_buffer) - state->in_buffer_offset);
2497 if (result == 0) {
2498 state->connection_state = BB_SCHANNEL_CLOSED;
2499 goto Success;
2500 } else if (result < 0) {
2501 bb_error_msg_and_die("schannel: read() failed");
2502 }
2503
2504 state->in_buffer_offset += result;
2505 continue;
2506 }
2507 case SEC_I_RENEGOTIATE: {
2508 DWORD flags = BB_SCHANNEL_ISC_FLAGS;
2509
2510 SecBuffer in_buffers[2];
2511 SecBufferDesc in_buffers_desc;
2512
2513 SecBuffer out_buffers[2];
2514 SecBufferDesc out_buffers_desc;
2515
2516 init_sec_buffer(&in_buffers[0],
2517 buffers[3].pvBuffer,
2518 buffers[3].cbBuffer,
2519 SECBUFFER_TOKEN);
2520 init_sec_buffer_empty(&in_buffers[1], SECBUFFER_EMPTY);
2521
2522 init_sec_buffer_empty(&out_buffers[0], SECBUFFER_TOKEN);
2523 init_sec_buffer_empty(&out_buffers[1], SECBUFFER_ALERT);
2524
2525 init_sec_buffer_desc(
2526 &in_buffers_desc, in_buffers, _countof(in_buffers));
2527 init_sec_buffer_desc(
2528 &out_buffers_desc, out_buffers, _countof(out_buffers));
2529
2530 status = InitializeSecurityContextA(&state->cred_handle,
2531 &state->ctx_handle,
2532 state->hostname,
2533 flags,
2534 0,
2535 0,
2536 &in_buffers_desc,
2537 0,
2538 &state->ctx_handle,
2539 &out_buffers_desc,
2540 &flags,
2541 0);
2542
2543 if (SEC_STATUS_FAIL(status)) {
2544 bb_error_msg_and_die("schannel: renegotiate failed: (0x%08lx): %s",
2545 status, hresult_to_error_string(status));
2546 }
2547
2548 if (in_buffers[1].BufferType == SECBUFFER_EXTRA) {
2549 memmove(state->in_buffer,
2550 state->in_buffer + (state->in_buffer_offset -
2551 in_buffers[1].cbBuffer),
2552 in_buffers[1].cbBuffer);
2553 state->in_buffer_offset = in_buffers[1].cbBuffer;
2554 } else {
2555 state->in_buffer_offset = 0;
2556 }
2557
2558 continue;
2559 }
2560 default: {
2561 bb_error_msg_and_die("schannel: DecryptMessage failed: (0x%08lx): %s",
2562 status, hresult_to_error_string(status));
2563 }
2564 }
2565 }
2566 }
2567
2568Success:
2569 return amount_read;
2570}
2571
2572static void tls_write(tls_state_t *state, char *buf, size_t len) {
2573 if (state->connection_state > BB_SCHANNEL_OPEN) {
2574 bb_error_msg_and_die("schannel: attempted to write to a closed connection");
2575 }
2576
2577 while (len > 0) {
2578 SECURITY_STATUS status;
2579 unsigned long copy_amount =
2580 min(len, (size_t)state->stream_sizes.cbMaximumMessage);
2581 char *write_buffer = _alloca(sizeof(state->in_buffer));
2582
2583 SecBuffer buffers[4];
2584 SecBufferDesc desc;
2585
2586 init_sec_buffer(&buffers[0],
2587 write_buffer,
2588 state->stream_sizes.cbHeader,
2589 SECBUFFER_STREAM_HEADER);
2590 init_sec_buffer(&buffers[1],
2591 write_buffer + state->stream_sizes.cbHeader,
2592 copy_amount,
2593 SECBUFFER_DATA);
2594 init_sec_buffer(&buffers[2],
2595 write_buffer + state->stream_sizes.cbHeader +
2596 copy_amount,
2597 state->stream_sizes.cbTrailer,
2598 SECBUFFER_STREAM_TRAILER);
2599 init_sec_buffer_empty(&buffers[3], SECBUFFER_EMPTY);
2600
2601 init_sec_buffer_desc(&desc, buffers, _countof(buffers));
2602
2603 memcpy(buffers[1].pvBuffer, buf, copy_amount);
2604
2605 status = EncryptMessage(&state->ctx_handle, 0, &desc, 0);
2606 if (SEC_STATUS_FAIL(status)) {
2607 bb_error_msg_and_die("schannel: EncryptMessage failed: (0x%08lx): %s",
2608 status, hresult_to_error_string(status));
2609 }
2610
2611 xwrite(state->ofd, write_buffer,
2612 buffers[0].cbBuffer + buffers[1].cbBuffer +
2613 buffers[2].cbBuffer);
2614
2615 len -= copy_amount;
2616 }
2617}
2618
2619static void tls_disconnect(tls_state_t * state) {
2620 SECURITY_STATUS status;
2621
2622 DWORD token = SCHANNEL_SHUTDOWN;
2623 DWORD flags = BB_SCHANNEL_ISC_FLAGS;
2624
2625 SecBuffer buf_token;
2626 SecBufferDesc buf_token_desc;
2627
2628 SecBuffer out_buffer;
2629 SecBufferDesc out_buffer_desc;
2630
2631 if (state->connection_state == BB_SCHANNEL_CLOSED_AND_FREED)
2632 return;
2633 state->connection_state = BB_SCHANNEL_CLOSED_AND_FREED;
2634
2635 init_sec_buffer(&buf_token, &token, sizeof(token), SECBUFFER_TOKEN);
2636 init_sec_buffer_desc(&buf_token_desc, &buf_token, 1);
2637
2638 ApplyControlToken(&state->ctx_handle, &buf_token_desc);
2639
2640 init_sec_buffer_empty(&out_buffer, SECBUFFER_TOKEN);
2641 init_sec_buffer_desc(&out_buffer_desc, &out_buffer, 1);
2642
2643 status = InitializeSecurityContextA(&state->cred_handle,
2644 &state->ctx_handle,
2645 state->hostname,
2646 flags,
2647 0,
2648 0,
2649 NULL,
2650 0,
2651 &state->ctx_handle,
2652 &out_buffer_desc,
2653 &flags,
2654 0);
2655
2656 if ((status == SEC_E_OK) || (status == SEC_I_CONTEXT_EXPIRED)) {
2657 write(state->ofd, out_buffer.pvBuffer, out_buffer.cbBuffer);
2658 FreeContextBuffer(out_buffer.pvBuffer);
2659 }
2660
2661 DeleteSecurityContext(&state->ctx_handle);
2662 FreeCredentialsHandle(&state->cred_handle);
2663 free(state->hostname);
2664}
2665
2666
2667void FAST_FUNC tls_handshake(tls_state_t *state, const char *hostname) {
2668 SECURITY_STATUS status;
2669
2670#if ENABLE_FEATURE_TLS_SCHANNEL_1_3
2671 SCH_CREDENTIALS credential = {.dwVersion = SCH_CREDENTIALS_VERSION,
2672 .dwCredFormat = 0,
2673 .cCreds = 0,
2674 .paCred = NULL,
2675 .hRootStore = NULL,
2676 .cMappers = 0,
2677 .aphMappers = NULL,
2678 .dwSessionLifespan = 0,
2679 .dwFlags =
2680 SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS |
2681 SCH_USE_STRONG_CRYPTO,
2682 .cTlsParameters = 0,
2683 .pTlsParameters = NULL
2684 };
2685#else
2686 SCHANNEL_CRED credential = {.dwVersion = SCHANNEL_CRED_VERSION,
2687 .cCreds = 0,
2688 .paCred = NULL,
2689 .hRootStore = NULL,
2690 .cMappers = 0,
2691 .aphMappers = NULL,
2692 .cSupportedAlgs = 0,
2693 .palgSupportedAlgs = NULL,
2694 .grbitEnabledProtocols =
2695 SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT |
2696 SP_PROT_TLS1_2_CLIENT,
2697 .dwMinimumCipherStrength = 0,
2698 .dwMaximumCipherStrength = 0,
2699 .dwSessionLifespan = 0,
2700 .dwFlags =
2701 SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS |
2702 SCH_USE_STRONG_CRYPTO,
2703 .dwCredFormat = 0
2704 };
2705#endif
2706
2707 state->in_buffer_offset = 0;
2708
2709 state->out_buffer = NULL;
2710 state->out_buffer_length = 0;
2711 state->out_buffer_extra = 0;
2712
2713 state->hostname = xstrdup(hostname);
2714 state->initialized = false;
2715 state->connection_state = BB_SCHANNEL_OPEN;
2716
2717 if (SEC_STATUS_FAIL(status = AcquireCredentialsHandleA(NULL,
2718 (SEC_CHAR *)UNISP_NAME_A,
2719 SECPKG_CRED_OUTBOUND,
2720 NULL,
2721 &credential,
2722 NULL,
2723 NULL,
2724 &state->cred_handle,
2725 NULL))) {
2726 bb_error_msg_and_die("schannel: AcquireCredentialsHandleA failed: (0x%08lx): %s",
2727 status, hresult_to_error_string(status));
2728 }
2729
2730 // InitializeSecurityContext loop
2731 while (true) {
2732 DWORD flags = BB_SCHANNEL_ISC_FLAGS;
2733
2734 SecBuffer in_buffers[2];
2735 SecBufferDesc in_buffers_desc;
2736
2737 SecBuffer out_buffers[2];
2738 SecBufferDesc out_buffers_desc;
2739
2740 init_sec_buffer(&in_buffers[0],
2741 state->in_buffer,
2742 state->in_buffer_offset,
2743 SECBUFFER_TOKEN);
2744 init_sec_buffer_empty(&in_buffers[1], SECBUFFER_EMPTY);
2745
2746 init_sec_buffer_empty(&out_buffers[0], SECBUFFER_TOKEN);
2747 init_sec_buffer_empty(&out_buffers[1], SECBUFFER_ALERT);
2748
2749 init_sec_buffer_desc(
2750 &in_buffers_desc, in_buffers, _countof(in_buffers));
2751 init_sec_buffer_desc(
2752 &out_buffers_desc, out_buffers, _countof(out_buffers));
2753
2754 status = InitializeSecurityContextA(
2755 &state->cred_handle,
2756 state->initialized ? &state->ctx_handle : NULL,
2757 state->hostname,
2758 flags,
2759 0,
2760 0,
2761 state->initialized ? &in_buffers_desc : NULL,
2762 0,
2763 &state->ctx_handle,
2764 &out_buffers_desc,
2765 &flags,
2766 0);
2767
2768 state->initialized = true;
2769
2770 if (in_buffers[1].BufferType == SECBUFFER_EXTRA) {
2771 memmove(state->in_buffer,
2772 state->in_buffer +
2773 (state->in_buffer_offset - in_buffers[1].cbBuffer),
2774 in_buffers[1].cbBuffer);
2775 state->in_buffer_offset = in_buffers[1].cbBuffer;
2776 }
2777
2778 switch (status) {
2779 case SEC_E_OK: {
2780 state->in_buffer_offset =
2781 (in_buffers[1].BufferType == SECBUFFER_EXTRA)
2782 ? in_buffers[1].cbBuffer
2783 : 0;
2784
2785 if (out_buffers[0].cbBuffer > 0) {
2786 xwrite(state->ifd, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer);
2787 FreeContextBuffer(out_buffers[0].pvBuffer);
2788 }
2789
2790 goto Success;
2791 }
2792 case SEC_I_CONTINUE_NEEDED: {
2793 xwrite(state->ofd, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer);
2794 FreeContextBuffer(out_buffers[0].pvBuffer);
2795 if (in_buffers[1].BufferType != SECBUFFER_EXTRA) {
2796 state->in_buffer_offset = 0;
2797 }
2798 break;
2799 }
2800 case SEC_E_INCOMPLETE_MESSAGE: {
2801 int amount_read =
2802 safe_read(state->ifd, state->in_buffer + state->in_buffer_offset,
2803 sizeof(state->in_buffer) - state->in_buffer_offset);
2804 if (amount_read <= 0) {
2805 bb_error_msg_and_die("schannel: handshake read() failed");
2806 }
2807
2808 state->in_buffer_offset += amount_read;
2809 continue;
2810 }
2811 default: {
2812 bb_error_msg_and_die("schannel: handshake failed: (0x%08lx): %s",
2813 status, hresult_to_error_string(status));
2814 }
2815 }
2816 }
2817
2818Success:
2819 QueryContextAttributes(
2820 &state->ctx_handle, SECPKG_ATTR_STREAM_SIZES, &state->stream_sizes);
2821 return;
2822}
2823
2824void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags) {
2825 char buffer[65536];
2826
2827 struct pollfd pfds[2];
2828
2829 pfds[0].fd = STDIN_FILENO;
2830 pfds[0].events = POLLIN;
2831 pfds[1].fd = tls->ifd;
2832 pfds[1].events = POLLIN;
2833
2834 for (;;) {
2835 int nread;
2836
2837 if (safe_poll(pfds, 2, -1) < 0)
2838 bb_simple_perror_msg_and_die("poll");
2839
2840 if (pfds[0].revents) {
2841 nread = safe_read(STDIN_FILENO, buffer, sizeof(buffer));
2842 if (nread < 1) {
2843 pfds[0].fd = -1;
2844 tls_disconnect(tls);
2845 if (flags & TLSLOOP_EXIT_ON_LOCAL_EOF)
2846 break;
2847 } else {
2848 tls_write(tls, buffer, nread);
2849 }
2850 }
2851 if (pfds[1].revents) {
2852 nread = tls_read(tls, buffer, sizeof(buffer));
2853 if (nread < 1) {
2854 tls_disconnect(tls);
2855 break;
2856 }
2857 xwrite(STDOUT_FILENO, buffer, nread);
2858 }
2859 }
2860}
2861#endif