LCOV - code coverage report
Current view: top level - src - handy_extra.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 133 238 55.9 %
Date: 2025-12-23 21:59:50 Functions: 5 6 83.3 %

          Line data    Source code
       1             : #include "burp.h"
       2             : #include "alloc.h"
       3             : #include "asfd.h"
       4             : #include "async.h"
       5             : #include "bfile.h"
       6             : #include "cmd.h"
       7             : #include "handy.h"
       8             : #include "hexmap.h"
       9             : #include "iobuf.h"
      10             : #include "log.h"
      11             : #include "md5.h"
      12             : #include "handy_extra.h"
      13             : #include "sbuf.h"
      14             : 
      15             : #if OPENSSL_VERSION_NUMBER >= 0x30000000L
      16             : #include <openssl/provider.h>
      17             : #endif
      18             : 
      19           0 : static int do_encryption(struct asfd *asfd, EVP_CIPHER_CTX *ctx,
      20             :         uint8_t *inbuf, int inlen, uint8_t *outbuf, int *outlen,
      21             :         struct md5 *md5)
      22             : {
      23           0 :         if(!inlen) return 0;
      24           0 :         if(!EVP_CipherUpdate(ctx, outbuf, outlen, inbuf, inlen))
      25             :         {
      26           0 :                 logp("Encryption failure.\n");
      27           0 :                 return -1;
      28             :         }
      29           0 :         if(*outlen>0)
      30             :         {
      31           0 :                 struct iobuf wbuf;
      32           0 :                 iobuf_set(&wbuf, CMD_APPEND, (char *)outbuf, *outlen);
      33           0 :                 if(asfd->write(asfd, &wbuf))
      34           0 :                         return -1;
      35           0 :                 if(!md5_update(md5, outbuf, *outlen))
      36             :                 {
      37           0 :                         logp("md5_update() failed\n");
      38           0 :                         return -1;
      39             :                 }
      40             :         }
      41             :         return 0;
      42             : }
      43             : 
      44           2 : EVP_CIPHER_CTX *enc_setup(int encrypt, const char *encryption_password,
      45             :         int key_deriv, uint64_t salt)
      46             : {
      47           2 :         uint8_t enc_iv[9];
      48           2 :         uint8_t enc_key[256];
      49           2 :         EVP_CIPHER_CTX *ctx=NULL;
      50           2 :         const EVP_CIPHER *cipher=NULL;
      51           2 :         int key_len;
      52             : 
      53           2 :         switch(key_deriv)
      54             :         {
      55           1 :                 case ENCRYPTION_NONE:
      56             :                 case ENCRYPTION_KEY_DERIVED_BF_CBC:
      57           1 :                         cipher=EVP_bf_cbc();
      58           1 :                         break;
      59           1 :                 case ENCRYPTION_KEY_DERIVED_AES_CBC_256:
      60           1 :                         cipher=EVP_aes_256_cbc();
      61           1 :                         break;
      62           0 :                 default:
      63           0 :                         logp("Could not determine cipher from: %d\n", key_deriv);
      64           0 :                         break;
      65             :         }
      66             : 
      67           2 :         if(!encryption_password)
      68             :         {
      69           1 :                 logp("No encryption password in %s()\n", __func__);
      70           1 :                 goto error;
      71             :         }
      72             : 
      73           1 :         if(key_deriv)
      74             :         {
      75             :                 // New, good way.
      76           1 :                 uint64_t be_salt=htobe64(salt);
      77           1 :                 const EVP_MD *dgst=EVP_sha256();
      78             :                 
      79           1 :                 if(!(key_len=EVP_BytesToKey(cipher, dgst, (uint8_t *)&be_salt,
      80             :                        (const unsigned char *)encryption_password,
      81           1 :                        strlen(encryption_password),
      82             :                        100, enc_key, enc_iv)))
      83             :                 {
      84           0 :                         logp("EVP_BytesToKey failed\n");
      85           0 :                         goto error;
      86             :                 }
      87             :         }
      88             :         else
      89             :         {
      90             :                 // Old, bad way.
      91             :                 // Declare enc_iv with individual characters so that the weird
      92             :                 // last character can be specified as a hex number in order to
      93             :                 // prevent compilation warnings on Macs.
      94           0 :                 uint8_t new_enc[]={
      95             :                         '[', 'l', 'k', 'd', '.', '$', 'G', 0xa3, '\0'
      96             :                 };
      97           0 :                 memcpy(enc_iv, new_enc, 9);
      98           0 :                 strcpy((char*)enc_key, encryption_password);
      99           0 :                 key_len=strlen(encryption_password);
     100             :         }
     101             : 
     102           1 :         if(!(ctx=(EVP_CIPHER_CTX *)EVP_CIPHER_CTX_new()))
     103             :         {
     104           0 :                 logp("EVP_CIPHER_CTX_new() failed\n");
     105           0 :                 goto error;
     106             :         }
     107             : 
     108             :         // Don't set key or IV because we will modify the parameters.
     109           1 :         EVP_CIPHER_CTX_init(ctx);
     110           1 :         if(!(EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, encrypt)))
     111             :         {
     112           0 :                 logp("EVP_CipherInit_ex failed\n");
     113           0 :                 goto error;
     114             :         }
     115           1 :         if(!EVP_CIPHER_CTX_set_key_length(ctx, key_len))
     116             :         {
     117           0 :                 logp("EVP_CIPHER_CTX_set_key_length failed\n");
     118           0 :                 goto error;
     119             :         }
     120             :         // We finished modifying parameters so now we can set key and IV
     121             : 
     122           1 :         if(!EVP_CipherInit_ex(ctx, NULL, NULL,
     123             :                 enc_key, enc_iv, encrypt))
     124             :         {
     125           0 :                 logp("Second EVP_CipherInit_ex failed\n");
     126           0 :                 goto error;
     127             :         }
     128             :         return ctx;
     129           0 : error:
     130           1 :         if(ctx)
     131             :         {
     132           0 :                 EVP_CIPHER_CTX_cleanup(ctx);
     133           0 :                 EVP_CIPHER_CTX_free(ctx);
     134           0 :                 ctx=NULL;
     135             :         }
     136             :         return NULL;
     137             : }
     138             : 
     139        7426 : char *get_endfile_str(uint64_t bytes, uint8_t *checksum)
     140             : {
     141        7426 :         static char endmsg[128]="";
     142        7426 :         snprintf(endmsg, sizeof(endmsg), "%" PRIu64 ":%s",
     143             :                         (uint64_t)bytes,
     144        7426 :                         checksum?bytes_to_md5str(checksum):"");
     145        7426 :         return endmsg;
     146             : }
     147             : 
     148          12 : int write_endfile(struct asfd *asfd, uint64_t bytes, uint8_t *checksum)
     149             : {
     150          12 :         return asfd->write_str(asfd,
     151          12 :                 CMD_END_FILE, get_endfile_str(bytes, checksum));
     152             : }
     153             : 
     154             : /* OK, this function is getting a bit out of control.
     155             :    One problem is that, if you give deflateInit2 compression=0, it still
     156             :    writes gzip headers and footers, so I had to add extra
     157             :    if(compression) and if(!compression) bits all over the place that would
     158             :    skip the actual compression.
     159             :    This is needed for the case where encryption is on and compression is off.
     160             :    Encryption off and compression off uses send_whole_file().
     161             :    Perhaps a separate function is needed for encryption on compression off.
     162             : */
     163           2 : enum send_e send_whole_file_gzl(struct asfd *asfd, const char *datapth,
     164             :         int quick_read, uint64_t *bytes, const char *encpassword,
     165             :         struct cntr *cntr, int compression, struct BFILE *bfd,
     166             :         const char *extrameta, size_t elen, int key_deriv, uint64_t salt)
     167             : {
     168           2 :         enum send_e ret=SEND_OK;
     169           2 :         int zret=0;
     170           2 :         struct md5 *md5=NULL;
     171           2 :         size_t metalen=0;
     172           2 :         const char *metadata=NULL;
     173           2 :         struct iobuf wbuf;
     174             : 
     175           2 :         int have;
     176           2 :         z_stream strm;
     177           2 :         int flush=Z_NO_FLUSH;
     178           2 :         uint8_t in[ZCHUNK];
     179           2 :         uint8_t out[ZCHUNK];
     180           2 :         ssize_t r;
     181             : 
     182           2 :         int eoutlen;
     183           2 :         uint8_t eoutbuf[ZCHUNK+EVP_MAX_BLOCK_LENGTH];
     184             : 
     185           2 :         EVP_CIPHER_CTX *enc_ctx=NULL;
     186             : #ifdef HAVE_WIN32
     187             :         int do_known_byte_count=0;
     188             :         size_t datalen=bfd->datalen;
     189             :         if(datalen>0) do_known_byte_count=1;
     190             : #endif
     191             : 
     192           2 :         if(encpassword
     193           0 :           && !(enc_ctx=enc_setup(1, encpassword, key_deriv, salt)))
     194             :                 return SEND_FATAL;
     195             : 
     196           2 :         if(!(md5=md5_alloc(__func__)))
     197             :                 return SEND_FATAL;
     198             : 
     199           2 :         if(!md5_init(md5))
     200             :         {
     201           0 :                 logp("md5_init() failed\n");
     202           0 :                 md5_free(&md5);
     203           0 :                 return SEND_FATAL;
     204             :         }
     205             : 
     206             : //logp("send_whole_file_gz: %s%s\n", fname, extrameta?" (meta)":"");
     207             : 
     208           2 :         if((metadata=extrameta))
     209             :         {
     210           0 :                 metalen=elen;
     211             :         }
     212             : 
     213             :         /* allocate deflate state */
     214           2 :         strm.zalloc = Z_NULL;
     215           2 :         strm.zfree = Z_NULL;
     216           2 :         strm.opaque = Z_NULL;
     217           2 :         if((zret=deflateInit2(&strm, compression, Z_DEFLATED, (15+16),
     218             :                 8, Z_DEFAULT_STRATEGY))!=Z_OK) {
     219           0 :                         md5_free(&md5);
     220           0 :                         return SEND_FATAL;
     221             :         }
     222             : 
     223           4 :         do
     224             :         {
     225           4 :                 if(metadata)
     226             :                 {
     227           0 :                         if(metalen>ZCHUNK)
     228           0 :                                 strm.avail_in=ZCHUNK;
     229             :                         else
     230           0 :                                 strm.avail_in=metalen;
     231           0 :                         memcpy(in, metadata, strm.avail_in);
     232           0 :                         metadata+=strm.avail_in;
     233           0 :                         metalen-=strm.avail_in;
     234             :                 }
     235             :                 else
     236             :                 {
     237             :                         // Windows VSS headers give us how much data to
     238             :                         // expect to read.
     239             : #ifdef HAVE_WIN32
     240             :                         if(do_known_byte_count)
     241             :                         {
     242             :                                 if(datalen<=0)
     243             :                                         r=0;
     244             :                                 else
     245             :                                 {
     246             :                                         r=bfd->read(bfd, in,
     247             :                                                 min((size_t)ZCHUNK, datalen));
     248             :                                         if(r>0)
     249             :                                                 datalen-=r;
     250             :                                 }
     251             :                         }
     252             :                         else
     253             : #endif
     254           4 :                                 r=bfd->read(bfd, in, ZCHUNK);
     255             : 
     256           4 :                         if(r<0)
     257             :                         {
     258           0 :                                 logw(asfd, cntr,
     259             :                                         "Error when reading %s in %s: %s\n",
     260           0 :                                         bfd->path, __func__, strerror(errno));
     261           0 :                                 ret=SEND_ERROR;
     262           0 :                                 break;
     263             :                         }
     264           4 :                         strm.avail_in=(uint32_t)r;
     265             :                 }
     266           4 :                 if(!compression && !strm.avail_in)
     267             :                         break;
     268             : 
     269           4 :                 *bytes+=strm.avail_in;
     270             : 
     271             :                 // The checksum needs to be later if encryption is being used.
     272           4 :                 if(!enc_ctx)
     273             :                 {
     274           4 :                         if(!md5_update(md5, in, strm.avail_in))
     275             :                         {
     276           0 :                                 logp("md5_update() failed\n");
     277           0 :                                 ret=SEND_FATAL;
     278           0 :                                 break;
     279             :                         }
     280             :                 }
     281             : 
     282             : #ifdef HAVE_WIN32
     283             :                 if(do_known_byte_count && datalen<=0)
     284             :                         flush=Z_FINISH;
     285             :                 else
     286             : #endif
     287           4 :                 if(strm.avail_in) flush=Z_NO_FLUSH;
     288           2 :                 else flush=Z_FINISH;
     289             : 
     290           4 :                 strm.next_in=in;
     291             : 
     292             :                 /* run deflate() on input until output buffer not full, finish
     293             :                         compression if all of source has been read in */
     294           4 :                 do
     295             :                 {
     296           4 :                         if(compression)
     297             :                         {
     298           4 :                                 strm.avail_out = ZCHUNK;
     299           4 :                                 strm.next_out = out;
     300           4 :                                 zret = deflate(&strm, flush); /* no bad return value */
     301           4 :                                 if(zret==Z_STREAM_ERROR) /* state not clobbered */
     302             :                                 {
     303           0 :                                         logw(asfd, cntr, "z_stream_error when reading %s in %s\n", bfd->path, __func__);
     304           0 :                                         ret=SEND_ERROR;
     305           0 :                                         break;
     306             :                                 }
     307           4 :                                 have = ZCHUNK-strm.avail_out;
     308             :                         }
     309             :                         else
     310             :                         {
     311           0 :                                 have=strm.avail_in;
     312           0 :                                 memcpy(out, in, have);
     313             :                         }
     314             : 
     315           4 :                         if(enc_ctx)
     316             :                         {
     317           0 :                                 if(do_encryption(asfd, enc_ctx, out, have,
     318             :                                         eoutbuf, &eoutlen, md5))
     319             :                                 {
     320             :                                         ret=SEND_FATAL;
     321             :                                         break;
     322             :                                 }
     323             :                         }
     324             :                         else
     325             :                         {
     326           4 :                                 iobuf_set(&wbuf, CMD_APPEND, (char *)out, have);
     327           4 :                                 if(asfd->write(asfd, &wbuf))
     328             :                                 {
     329             :                                         ret=SEND_FATAL;
     330             :                                         break;
     331             :                                 }
     332             :                         }
     333           4 :                         if(quick_read && datapth)
     334             :                         {
     335           4 :                                 int qr;
     336           4 :                                 if((qr=do_quick_read(asfd, datapth, cntr))<0)
     337             :                                 {
     338             :                                         ret=SEND_FATAL;
     339             :                                         break;
     340             :                                 }
     341           4 :                                 if(qr) // client wants to interrupt
     342             :                                 {
     343           0 :                                         goto cleanup;
     344             :                                 }
     345             :                         }
     346           4 :                         if(!compression) break;
     347           4 :                 } while (!strm.avail_out);
     348             : 
     349           4 :                 if(ret!=SEND_OK) break;
     350             : 
     351           4 :                 if(!compression) continue;
     352             : 
     353           4 :                 if(strm.avail_in) /* all input will be used */
     354             :                 {
     355           0 :                         ret=SEND_FATAL;
     356           0 :                         logp("strm.avail_in=%d\n", strm.avail_in);
     357           0 :                         break;
     358             :                 }
     359           4 :         } while(flush!=Z_FINISH);
     360             : 
     361           2 :         if(ret==SEND_OK)
     362             :         {
     363           2 :                 if(compression && zret!=Z_STREAM_END)
     364             :                 {
     365           0 :                         logp("ret OK, but zstream not finished: %d\n", zret);
     366           0 :                         ret=SEND_FATAL;
     367             :                 }
     368           2 :                 else if(enc_ctx)
     369             :                 {
     370           0 :                         if(!EVP_CipherFinal_ex(enc_ctx, eoutbuf, &eoutlen))
     371             :                         {
     372           0 :                                 logp("Encryption failure at the end\n");
     373           0 :                                 ret=SEND_FATAL;
     374             :                         }
     375           0 :                         else if(eoutlen>0)
     376             :                         {
     377           0 :                                 iobuf_set(&wbuf, CMD_APPEND,
     378             :                                         (char *)eoutbuf, (size_t)eoutlen);
     379           0 :                                 if(asfd->write(asfd, &wbuf))
     380             :                                         ret=SEND_FATAL;
     381           0 :                                 else if(!md5_update(md5, eoutbuf, eoutlen))
     382             :                                 {
     383           0 :                                         logp("md5_update() failed\n");
     384           0 :                                         ret=SEND_FATAL;
     385             :                                 }
     386             :                         }
     387             :                 }
     388             :         }
     389             : 
     390           2 : cleanup:
     391           2 :         deflateEnd(&strm);
     392             : 
     393           2 :         if(enc_ctx)
     394             :         {
     395           0 :                 EVP_CIPHER_CTX_cleanup(enc_ctx);
     396           0 :                 EVP_CIPHER_CTX_free(enc_ctx);
     397           0 :                 enc_ctx=NULL;
     398             :         }
     399             : 
     400           2 :         if(ret==SEND_OK)
     401             :         {
     402           2 :                 uint8_t checksum[MD5_DIGEST_LENGTH];
     403           2 :                 if(!md5_final(md5, checksum))
     404             :                 {
     405           0 :                         logp("md5_final() failed\n");
     406           0 :                         md5_free(&md5);
     407           0 :                         return SEND_FATAL;
     408             :                 }
     409           2 :                 if(write_endfile(asfd, *bytes, checksum))
     410             :                         return SEND_FATAL;
     411             :         }
     412           2 :         md5_free(&md5);
     413           2 :         return ret;
     414             : }
     415             : 
     416             : #ifdef HAVE_WIN32
     417             : struct winbuf
     418             : {
     419             :         struct md5 *md5;
     420             :         int quick_read;
     421             :         const char *datapth;
     422             :         struct cntr *cntr;
     423             :         uint64_t *bytes;
     424             :         struct asfd *asfd;
     425             : };
     426             : 
     427             : static DWORD WINAPI write_efs(PBYTE pbData,
     428             :         PVOID pvCallbackContext, ULONG ulLength)
     429             : {
     430             :         struct iobuf wbuf;
     431             :         struct winbuf *mybuf=(struct winbuf *)pvCallbackContext;
     432             :         (*(mybuf->bytes))+=ulLength;
     433             :         if(!md5_update(mybuf->md5, pbData, ulLength))
     434             :         {
     435             :                 logp("md5_update() failed\n");
     436             :                 return ERROR_FUNCTION_FAILED;
     437             :         }
     438             :         iobuf_set(&wbuf, CMD_APPEND, (char *)pbData, (size_t)ulLength);
     439             :         if(mybuf->asfd->write(mybuf->asfd, &wbuf))
     440             :         {
     441             :                 return ERROR_FUNCTION_FAILED;
     442             :         }
     443             :         if(mybuf->quick_read)
     444             :         {
     445             :                 int qr;
     446             :                 if((qr=do_quick_read(mybuf->asfd,
     447             :                                 mybuf->datapth, mybuf->cntr))<0)
     448             :                         return ERROR_FUNCTION_FAILED;
     449             :                 if(qr) // client wants to interrupt
     450             :                         return ERROR_FUNCTION_FAILED;
     451             :         }
     452             :         return ERROR_SUCCESS;
     453             : }
     454             : #endif
     455             : 
     456           9 : enum send_e send_whole_filel(struct asfd *asfd,
     457             : #ifdef HAVE_WIN32
     458             :         enum cmd cmd,
     459             : #endif
     460             :         const char *datapth,
     461             :         int quick_read, uint64_t *bytes, struct cntr *cntr,
     462             :         struct BFILE *bfd, const char *extrameta, size_t elen)
     463             : {
     464           9 :         enum send_e ret=SEND_OK;
     465           9 :         ssize_t s=0;
     466           9 :         struct md5 *md5=NULL;
     467           9 :         char buf[4096]="";
     468           9 :         struct iobuf wbuf;
     469             : 
     470           9 :         if(!bfd)
     471             :         {
     472           1 :                 logp("No bfd in %s()\n", __func__);
     473           1 :                 return SEND_FATAL;
     474             :         }
     475             : 
     476           8 :         if(!(md5=md5_alloc(__func__)))
     477             :                 return SEND_FATAL;
     478           8 :         if(!md5_init(md5))
     479             :         {
     480           0 :                 logp("md5_init() failed\n");
     481           0 :                 md5_free(&md5);
     482           0 :                 return SEND_FATAL;
     483             :         }
     484             : 
     485           8 :         if(extrameta)
     486             :         {
     487             :                 size_t metalen=0;
     488             :                 const char *metadata=NULL;
     489             : 
     490             :                 metadata=extrameta;
     491             :                 metalen=elen;
     492             : 
     493             :                 // Send metadata in chunks, rather than all at once.
     494           0 :                 while(metalen>0)
     495             :                 {
     496           0 :                         if(metalen>ZCHUNK) s=ZCHUNK;
     497             :                         else s=metalen;
     498             : 
     499           0 :                         if(!md5_update(md5, metadata, s))
     500             :                         {
     501           0 :                                 logp("md5_update() failed\n");
     502           0 :                                 ret=SEND_FATAL;
     503             :                         }
     504           0 :                         iobuf_set(&wbuf, CMD_APPEND, (char *)metadata, s);
     505           0 :                         if(asfd->write(asfd, &wbuf))
     506           0 :                                 ret=SEND_FATAL;
     507             : 
     508           0 :                         metadata+=s;
     509           0 :                         metalen-=s;
     510             : 
     511           0 :                         *bytes+=s;
     512             :                 }
     513             :         }
     514             :         else
     515             :         {
     516             : #ifdef HAVE_WIN32
     517             :                 if(ret==SEND_OK && cmd==CMD_EFS_FILE)
     518             :                 {
     519             :                         struct winbuf mybuf;
     520             :                         mybuf.md5=md5;
     521             :                         mybuf.quick_read=quick_read;
     522             :                         mybuf.datapth=datapth;
     523             :                         mybuf.cntr=cntr;
     524             :                         mybuf.bytes=bytes;
     525             :                         mybuf.asfd=asfd;
     526             :                         // The EFS read function, ReadEncryptedFileRaw(),
     527             :                         // works in an annoying way. You have to give it a
     528             :                         // function that it calls repeatedly every time the
     529             :                         // read buffer is called.
     530             :                         // So ReadEncryptedFileRaw() will not return until
     531             :                         // it has read the whole file. I have no idea why
     532             :                         // they do not have a plain 'read()' function for it.
     533             : 
     534             :                         ReadEncryptedFileRaw((PFE_EXPORT_FUNC)write_efs,
     535             :                                 &mybuf, bfd->pvContext);
     536             :                 }
     537             :                 else
     538             : #endif
     539             : 
     540             :                 if(ret==SEND_OK)
     541             :                 {
     542             : #ifdef HAVE_WIN32
     543             :                   int do_known_byte_count=0;
     544             :                   size_t datalen=bfd->datalen;
     545             :                   if(datalen>0) do_known_byte_count=1;
     546             : #endif
     547          10 :                   while(1)
     548             :                   {
     549             : #ifdef HAVE_WIN32
     550             :                         if(do_known_byte_count)
     551             :                         {
     552             :                                 s=bfd->read(bfd,
     553             :                                         buf, min((size_t)4096, datalen));
     554             :                                 if(s>0)
     555             :                                         datalen-=s;
     556             :                         }
     557             :                         else
     558             :                         {
     559             : #endif
     560          10 :                                 s=bfd->read(bfd, buf, 4096);
     561             : #ifdef HAVE_WIN32
     562             :                         }
     563             : #endif
     564          10 :                         if(!s)
     565             :                                 break;
     566           2 :                         else if(s<0)
     567             :                         {
     568           0 :                                 logw(asfd, cntr,
     569             :                                         "Error when reading %s in %s: %s\n",
     570           0 :                                         bfd->path, __func__, strerror(errno));
     571           0 :                                 ret=SEND_ERROR;
     572           0 :                                 break;
     573             :                         }
     574             : 
     575           2 :                         *bytes+=s;
     576           2 :                         if(!md5_update(md5, buf, s))
     577             :                         {
     578           0 :                                 logp("md5_update() failed\n");
     579           0 :                                 ret=SEND_FATAL;
     580           0 :                                 break;
     581             :                         }
     582           2 :                         iobuf_set(&wbuf, CMD_APPEND, buf, s);
     583           2 :                         if(asfd->write(asfd, &wbuf))
     584             :                         {
     585             :                                 ret=SEND_FATAL;
     586             :                                 break;
     587             :                         }
     588           2 :                         if(quick_read)
     589             :                         {
     590           2 :                                 int qr;
     591           2 :                                 if((qr=do_quick_read(asfd, datapth, cntr))<0)
     592             :                                 {
     593             :                                         ret=SEND_FATAL;
     594             :                                         break;
     595             :                                 }
     596           2 :                                 if(qr)
     597             :                                 {
     598             :                                         // client wants to interrupt
     599             :                                         break;
     600             :                                 }
     601             :                         }
     602             : #ifdef HAVE_WIN32
     603             :                         // Windows VSS headers tell us how many bytes to
     604             :                         // expect.
     605             :                         if(do_known_byte_count && datalen<=0) break;
     606             : #endif
     607             :                   }
     608             :                 }
     609             :         }
     610           8 :         if(ret!=SEND_FATAL)
     611             :         {
     612           8 :                 uint8_t checksum[MD5_DIGEST_LENGTH];
     613           8 :                 if(!md5_final(md5, checksum))
     614             :                 {
     615           0 :                         logp("md5_final() failed\n");
     616           0 :                         md5_free(&md5);
     617           0 :                         return SEND_FATAL;
     618             :                 }
     619           8 :                 if(write_endfile(asfd, *bytes, checksum))
     620             :                         return SEND_FATAL;
     621             :         }
     622           8 :         md5_free(&md5);
     623           8 :         return ret;
     624             : }

Generated by: LCOV version 1.16