*
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
/* ... and store the encoded size */
jcr->pki_session_encoded_size = size;
+
+ /* Allocate the encryption/decryption buffer */
+ jcr->crypto_buf = get_memory(CRYPTO_CIPHER_MAX_BLOCK_SIZE);
}
Dmsg1(300, "set_find_options ff=%p\n", jcr->ff);
free_pool_memory(jcr->compress_buf);
jcr->compress_buf = NULL;
}
+ if (jcr->crypto_buf) {
+ free_pool_memory(jcr->crypto_buf);
+ jcr->crypto_buf = NULL;
+ }
if (jcr->pki_session) {
crypto_session_free(jcr->pki_session);
#else
crypto_digest_t signing_algorithm = CRYPTO_DIGEST_SHA1;
#endif
- BSOCK *sd;
JCR *jcr = (JCR *)vjcr;
+ BSOCK *sd = jcr->store_bsock;
if (job_canceled(jcr)) {
return 0;
}
- sd = jcr->store_bsock;
jcr->num_files_examined++; /* bump total file count */
switch (ff_pkt->type) {
Dmsg2(130, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
break;
case FT_DIRBEGIN:
+ jcr->num_files_examined--; /* correct file count */
return 1; /* not used */
case FT_NORECURSE:
Jmsg(jcr, M_INFO, 1, _(" Recursion turned off. Will not descend into %s\n"),
if (jcr->pki_sign) {
signing_digest = crypto_digest_new(signing_algorithm);
}
-
/* Full-stop if a failure occured initializing the signature digest */
if (jcr->pki_sign && signing_digest == NULL) {
Jmsg(jcr, M_NOTSAVED, 0, _("%s signature digest initialization failed\n"),
return 1;
}
+ /* Enable encryption */
+ if (jcr->pki_encrypt) {
+ ff_pkt->flags |= FO_ENCRYPT;
+ }
+
/* Initialise the file descriptor we use for data and other streams. */
binit(&ff_pkt->bfd);
if (ff_pkt->flags & FO_PORTABLE) {
char *rbuf, *wbuf;
int rsize = jcr->buf_size; /* read buffer size */
POOLMEM *msgsave;
+ CIPHER_CONTEXT *cipher_ctx = NULL; /* Quell bogus uninitialized warnings */
+ const void *cipher_input;
+ size_t cipher_input_len;
+ size_t cipher_block_size;
+ size_t encrypted_len;
#ifdef FD_NO_SEND_TEST
return 1;
#endif
msgsave = sd->msg;
rbuf = sd->msg; /* read buffer */
wbuf = sd->msg; /* write buffer */
+ cipher_input = rbuf; /* encrypt uncompressed data */
Dmsg1(300, "Saving data, type=%d\n", ff_pkt->type);
-
#ifdef HAVE_LIBZ
uLong compress_len, max_compress_len = 0;
const Bytef *cbuf = NULL;
max_compress_len = jcr->compress_buf_size; /* set max length */
}
wbuf = jcr->compress_buf; /* compressed output here */
+ cipher_input = jcr->compress_buf; /* encrypt compressed data */
}
+#else
+ const uint32_t max_compress_len = 0;
#endif
+ if (ff_pkt->flags & FO_ENCRYPT) {
+ /* Allocate the cipher context */
+ if ((cipher_ctx = crypto_cipher_new(jcr->pki_session, true, &cipher_block_size)) == NULL) {
+ /* Shouldn't happen! */
+ Jmsg0(jcr, M_FATAL, 0, _("Failed to initialize encryption context\n"));
+ goto err;
+ }
+
+ /*
+ * Grow the crypto buffer, if necessary.
+ * crypto_cipher_update() will buffer up to (cipher_block_size - 1).
+ * We grow crypto_buf to the maximum number of blocks that
+ * could be returned for the given read buffer size.
+ * (Using the larger of either rsize or max_compress_len)
+ */
+ jcr->crypto_buf = check_pool_memory_size(jcr->crypto_buf, (MAX((size_t) rsize, max_compress_len) + cipher_block_size - 1) / cipher_block_size * cipher_block_size);
+
+ wbuf = jcr->crypto_buf; /* Encrypted, possibly compressed output here. */
+ }
+
/*
* Send Data header to Storage daemon
* <file-index> <stream> <info>
if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream)) {
Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
bnet_strerror(sd));
- return 0;
+ goto err;
}
Dmsg1(300, ">stored: datahdr %s\n", sd->msg);
if (S_ISBLK(ff_pkt->statp.st_mode))
rsize = (rsize/512) * 512;
#endif
+
+#ifdef HAVE_LIBZ
+ /*
+ * instead of using compress2 for every block (with 256KB alloc + free per block)
+ * we init the zlib once per file which leads to less pagefaults on large files (>64K)
+ */
+
+ z_stream zstream;
+ zstream.zalloc = Z_NULL;
+ zstream.zfree = Z_NULL;
+ zstream.opaque = Z_NULL;
+ zstream.state = Z_NULL;
+
+ BOOL blibzInited = deflateInit(&zstream, ff_pkt->GZIP_level) == Z_OK;
+#endif
/*
* Read the file data
jcr->ReadBytes += sd->msglen; /* count bytes read */
fileAddr += sd->msglen;
+ /* Uncompressed cipher input length */
+ cipher_input_len = sd->msglen;
+
/* Update checksum if requested */
if (digest) {
crypto_digest_update(digest, rbuf, sd->msglen);
#ifdef HAVE_LIBZ
/* Do compression if turned on */
- if (!sparseBlock && ff_pkt->flags & FO_GZIP) {
+ if (!sparseBlock && (ff_pkt->flags & FO_GZIP) && blibzInited) {
int zstat;
compress_len = max_compress_len;
Dmsg4(400, "cbuf=0x%x len=%u rbuf=0x%x len=%u\n", cbuf, compress_len,
rbuf, sd->msglen);
- /* NOTE! This call modifies compress_len !!! */
- if ((zstat=compress2((Bytef *)cbuf, &compress_len,
- (const Bytef *)rbuf, (uLong)sd->msglen,
- ff_pkt->GZIP_level)) != Z_OK) {
+
+ zstream.next_in = (Bytef *)rbuf;
+ zstream.avail_in = sd->msglen;
+ zstream.next_out = (Bytef *)cbuf;
+ zstream.avail_out = compress_len;
+
+ if ((zstat=deflate(&zstream, Z_FINISH)) != Z_STREAM_END) {
Jmsg(jcr, M_FATAL, 0, _("Compression error: %d\n"), zstat);
- sd->msg = msgsave;
- sd->msglen = 0;
set_jcr_job_status(jcr, JS_ErrorTerminated);
- return 0;
+ goto err;
}
+ compress_len = zstream.total_out;
+ blibzInited = deflateReset(&zstream) == Z_OK;
+
Dmsg2(400, "compressed len=%d uncompressed len=%d\n",
compress_len, sd->msglen);
sd->msglen = compress_len; /* set compressed length */
+ cipher_input_len = compress_len;
}
#endif
+ if (ff_pkt->flags & FO_ENCRYPT) {
+ /* Encrypt the input block */
+ if (crypto_cipher_update(cipher_ctx, cipher_input, cipher_input_len, jcr->crypto_buf, &encrypted_len)) {
+ if (encrypted_len == 0) {
+ /* No full block of data available, read more data */
+ continue;
+ }
+ Dmsg2(400, "encrypted len=%d unencrypted len=%d\n",
+ encrypted_len, sd->msglen);
+ sd->msglen = encrypted_len; /* set encrypted length */
+ } else {
+ /* Encryption failed. Shouldn't happen. */
+ Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
+ goto err;
+ }
+ }
+
/* Send the buffer to the Storage daemon */
if (!sparseBlock) {
if (ff_pkt->flags & FO_SPARSE) {
if (!bnet_send(sd)) {
Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
bnet_strerror(sd));
- sd->msg = msgsave; /* restore bnet buffer */
- sd->msglen = 0;
- return 0;
+ goto err;
}
}
Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
/* #endif */
- jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed */
+ jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed/encrypted */
sd->msg = msgsave; /* restore read buffer */
} /* end while read file data */
+ /* Send any remaining encrypted data + padding */
+ if (ff_pkt->flags & FO_ENCRYPT) {
+ if (!crypto_cipher_finalize(cipher_ctx, jcr->crypto_buf, &encrypted_len)) {
+ /* Padding failed. Shouldn't happen. */
+ Jmsg(jcr, M_FATAL, 0, _("Encryption padding error\n"));
+ goto err;
+ }
+
+ if (encrypted_len > 0) {
+ sd->msglen = encrypted_len; /* set encrypted length */
+
+ /* Send remaining encrypted data to the SD */
+ if (ff_pkt->flags & FO_SPARSE) {
+ sd->msglen += SPARSE_FADDR_SIZE; /* include fileAddr in size */
+ }
+ sd->msg = wbuf; /* set correct write buffer */
+ if (!bnet_send(sd)) {
+ Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
+ bnet_strerror(sd));
+ goto err;
+ }
+ Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
+ jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed/encrypted */
+ sd->msg = msgsave; /* restore bnet buffer */
+ }
+ }
if (sd->msglen < 0) {
berrno be;
if (!bnet_sig(sd, BNET_EOD)) { /* indicate end of file data */
Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
bnet_strerror(sd));
- return 0;
+ goto err;
}
+ /* Free the cipher context */
+ if (cipher_ctx) {
+ crypto_cipher_free(cipher_ctx);
+ }
+#ifdef HAVE_LIBZ
+ /* Free the zlib stream */
+ deflateEnd(&zstream);
+#endif
+
return 1;
+
+err:
+ /* Free the cipher context */
+ if (cipher_ctx) {
+ crypto_cipher_free(cipher_ctx);
+ }
+#ifdef HAVE_LIBZ
+ /* Free the zlib stream */
+ deflateEnd(&zstream);
+#endif
+
+ sd->msg = msgsave; /* restore bnet buffer */
+ sd->msglen = 0;
+ return 0;
}
/*
#endif
/* Find what data stream we will use, then encode the attributes */
- data_stream = select_data_stream(ff_pkt);
+ if ((data_stream = select_data_stream(ff_pkt)) == STREAM_NONE) {
+ /* This should not happen */
+ Jmsg0(jcr, M_FATAL, 0, _("Invalid file flags, no supported data stream type.\n"));
+ return false;
+ }
encode_stat(attribs, ff_pkt, data_stream);
/* Now possibly extend the attributes */
Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx);
- P(jcr->mutex);
+ jcr->lock();
jcr->JobFiles++; /* increment number of files sent */
ff_pkt->FileIndex = jcr->JobFiles; /* return FileIndex */
pm_strcpy(jcr->last_fname, ff_pkt->fname);
- V(jcr->mutex);
+ jcr->unlock();
/*
* Send Attributes header to Storage daemon