X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Ffiled%2Frestore.c;h=299b78f9e2a5b33902fbe92add40c289f14028d2;hb=f5571f4e4916261503020df01b6f9d30d17ae194;hp=4b1157bccbb0d72270db7f69c01a4d4d51653631;hpb=84adb85e09cfbfe6b59994bedc8d4bb07a258269;p=bacula%2Fbacula diff --git a/bacula/src/filed/restore.c b/bacula/src/filed/restore.c index 4b1157bccb..299b78f9e2 100644 --- a/bacula/src/filed/restore.c +++ b/bacula/src/filed/restore.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2007 Free Software Foundation Europe e.V. + Copyright (C) 2000-2008 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. @@ -83,10 +83,11 @@ struct r_ctx { uint64_t fileAddr; /* file write address */ uint32_t size; /* Size of file */ int flags; /* Options for extract_data() */ - BFILE forkbfd; /* Alternative data stream */ - uint64_t fork_addr; /* Write address for alternative stream */ - intmax_t fork_size; /* Size of alternate stream */ - int fork_flags; /* Options for extract_data() */ + BFILE forkbfd; /* Alternative data stream */ + uint64_t fork_addr; /* Write address for alternative stream */ + intmax_t fork_size; /* Size of alternate stream */ + int fork_flags; /* Options for extract_data() */ + int32_t type; /* file type FT_ */ SIGNATURE *sig; /* Cryptographic signature (if any) for file */ CRYPTO_SESSION *cs; /* Cryptographic session data (if any) for file */ @@ -110,7 +111,7 @@ static void free_session(r_ctx &rctx); -static bool verify_signature(JCR *jcr, SIGNATURE *sig); +static bool verify_signature(JCR *jcr, r_ctx &rctx); int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen, uint64_t *addr, int flags, RESTORE_CIPHER_CTX *cipher_ctx); bool flush_cipher(JCR *jcr, BFILE *bfd, uint64_t *addr, int flags, @@ -119,9 +120,9 @@ bool flush_cipher(JCR *jcr, BFILE *bfd, uint64_t *addr, int flags, /* * Close a bfd check that we are at the expected file offset. - * Makes some code in set_attributes(). + * Makes use of some code from set_attributes(). */ -int bclose_chksize(JCR *jcr, BFILE *bfd, boffset_t osize) +static int bclose_chksize(JCR *jcr, BFILE *bfd, boffset_t osize) { char ec1[50], ec2[50]; boffset_t fsize; @@ -239,7 +240,7 @@ void do_restore(JCR *jcr) */ binit(&rctx.bfd); binit(&rctx.forkbfd); - attr = new_attr(); + attr = new_attr(jcr); jcr->acl_text = get_pool_memory(PM_MESSAGE); @@ -298,11 +299,16 @@ void do_restore(JCR *jcr) deallocate_fork_cipher(rctx); } - set_attributes(jcr, attr, &rctx.bfd); + if (jcr->plugin) { + plugin_set_attributes(jcr, attr, &rctx.bfd); + } else { + set_attributes(jcr, attr, &rctx.bfd); + } extract = false; /* Verify the cryptographic signature, if any */ - verify_signature(jcr, rctx.sig); + rctx.type = attr->type; + verify_signature(jcr, rctx); /* Free Signature */ free_signature(rctx); @@ -314,6 +320,11 @@ void do_restore(JCR *jcr) bclose(&rctx.bfd); } + /* TODO: manage deleted files */ + if (rctx.type == FT_DELETED) { /* deleted file */ + continue; + } + /* * Unpack attributes and do sanity check them */ @@ -343,11 +354,16 @@ void do_restore(JCR *jcr) build_attr_output_fnames(jcr, attr); /* - * Now determine if we are extracting or not. + * Try to actually create the file, which returns a status telling + * us if we need to extract or not. */ jcr->num_files_examined++; extract = false; - stat = create_file(jcr, attr, &rctx.bfd, jcr->replace); + if (jcr->plugin) { + stat = plugin_create_file(jcr, attr, &rctx.bfd, jcr->replace); + } else { + stat = create_file(jcr, attr, &rctx.bfd, jcr->replace); + } Dmsg2(30, "Outfile=%s create_file stat=%d\n", attr->ofname, stat); switch (stat) { case CF_ERROR: @@ -374,7 +390,11 @@ void do_restore(JCR *jcr) } if (!extract) { /* set attributes now because file will not be extracted */ - set_attributes(jcr, attr, &rctx.bfd); + if (jcr->plugin) { + plugin_set_attributes(jcr, attr, &rctx.bfd); + } else { + set_attributes(jcr, attr, &rctx.bfd); + } } break; } @@ -393,18 +413,18 @@ void do_restore(JCR *jcr) } /* Do we have any keys at all? */ - if (!jcr->pki_recipients) { + if (!jcr->crypto.pki_recipients) { Jmsg(jcr, M_ERROR, 0, _("No private decryption keys have been defined to decrypt encrypted backup data.\n")); extract = false; bclose(&rctx.bfd); break; } - if (jcr->digest) { - crypto_digest_free(jcr->digest); + if (jcr->crypto.digest) { + crypto_digest_free(jcr->crypto.digest); } - jcr->digest = crypto_digest_new(jcr, signing_algorithm); - if (!jcr->digest) { + jcr->crypto.digest = crypto_digest_new(jcr, signing_algorithm); + if (!jcr->crypto.digest) { Jmsg0(jcr, M_FATAL, 0, _("Could not create digest.\n")); extract = false; bclose(&rctx.bfd); @@ -413,7 +433,7 @@ void do_restore(JCR *jcr) /* Decode and save session keys. */ cryptoerr = crypto_session_decode((uint8_t *)sd->msg, (uint32_t)sd->msglen, - jcr->pki_recipients, &rctx.cs); + jcr->crypto.pki_recipients, &rctx.cs); switch(cryptoerr) { case CRYPTO_ERROR_NONE: /* Success */ @@ -512,22 +532,22 @@ void do_restore(JCR *jcr) case STREAM_ENCRYPTED_MACOS_FORK_DATA: case STREAM_MACOS_FORK_DATA: #ifdef HAVE_DARWIN_OS - fork_flags = 0; + rctx.fork_flags = 0; jcr->ff->flags |= FO_HFSPLUS; - if (stream == STREAM_ENCRYPTED_MACOS_FORK_DATA) { - fork_flags |= FO_ENCRYPT; + if (rctx.stream == STREAM_ENCRYPTED_MACOS_FORK_DATA) { + rctx.fork_flags |= FO_ENCRYPT; /* Set up a decryption context */ if (extract && !rctx.fork_cipher_ctx.cipher) { - if (!cs) { + if (!rctx.cs) { Jmsg1(jcr, M_ERROR, 0, _("Missing encryption session data stream for %s\n"), jcr->last_fname); extract = false; bclose(&rctx.bfd); continue; } - if ((rctx.fork_cipher_ctx.cipher = crypto_cipher_new(cs, false, &rctx.fork_cipher_ctx.block_size)) == NULL) { + if ((rctx.fork_cipher_ctx.cipher = crypto_cipher_new(rctx.cs, false, &rctx.fork_cipher_ctx.block_size)) == NULL) { Jmsg1(jcr, M_ERROR, 0, _("Failed to initialize decryption context for %s\n"), jcr->last_fname); free_session(rctx); extract = false; @@ -538,21 +558,21 @@ void do_restore(JCR *jcr) } if (extract) { - if (prev_stream != stream) { - if (bopen_rsrc(&forkbfd, jcr->last_fname, O_WRONLY | O_TRUNC | O_BINARY, 0) < 0) { + if (rctx.prev_stream != rctx.stream) { + if (bopen_rsrc(&rctx.forkbfd, jcr->last_fname, O_WRONLY | O_TRUNC | O_BINARY, 0) < 0) { Jmsg(jcr, M_ERROR, 0, _(" Cannot open resource fork for %s.\n"), jcr->last_fname); extract = false; continue; } - fork_size = rsrc_len; + rctx.fork_size = rsrc_len; Dmsg0(30, "Restoring resource fork\n"); } - if (extract_data(jcr, &forkbfd, sd->msg, sd->msglen, &rctx.fork_addr, fork_flags, - &rctxfork_cipher_ctx) < 0) { + if (extract_data(jcr, &rctx.forkbfd, sd->msg, sd->msglen, &rctx.fork_addr, rctx.fork_flags, + &rctx.fork_cipher_ctx) < 0) { extract = false; - bclose(&forkbfd); + bclose(&rctx.forkbfd); continue; } } @@ -578,7 +598,7 @@ void do_restore(JCR *jcr) #endif break; - case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL: + case STREAM_UNIX_ACCESS_ACL: if (have_acl) { pm_strcpy(jcr->acl_text, sd->msg); Dmsg2(400, "Restoring ACL type 0x%2x <%s>\n", BACL_TYPE_ACCESS, jcr->acl_text); @@ -590,7 +610,7 @@ void do_restore(JCR *jcr) } break; - case STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL: + case STREAM_UNIX_DEFAULT_ACL: if (have_acl) { pm_strcpy(jcr->acl_text, sd->msg); Dmsg2(400, "Restoring ACL type 0x%2x <%s>\n", BACL_TYPE_DEFAULT, jcr->acl_text); @@ -629,6 +649,11 @@ void do_restore(JCR *jcr) } break; + case STREAM_PLUGIN_NAME: + Dmsg1(000, "restore stream_plugin_name=%s\n", sd->msg); + plugin_name_stream(jcr, sd->msg); + break; + default: /* If extracting, wierd stream (not 1 or 2), close output file anyway */ if (extract) { @@ -640,10 +665,15 @@ void do_restore(JCR *jcr) deallocate_cipher(rctx); deallocate_fork_cipher(rctx); - set_attributes(jcr, attr, &rctx.bfd); + if (jcr->plugin) { + plugin_set_attributes(jcr, attr, &rctx.bfd); + } else { + set_attributes(jcr, attr, &rctx.bfd); + } /* Verify the cryptographic signature if any */ - verify_signature(jcr, rctx.sig); + rctx.type = attr->type; + verify_signature(jcr, rctx); extract = false; } else if (is_bopen(&rctx.bfd)) { Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n")); @@ -651,7 +681,7 @@ void do_restore(JCR *jcr) } Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), rctx.stream); - Dmsg2(0, "None of above!!! stream=%d data=%s\n", rctx.stream,sd->msg); + Dmsg2(0, "Unknown stream=%d data=%s\n", rctx.stream, sd->msg); break; } /* end switch(stream) */ @@ -668,10 +698,15 @@ void do_restore(JCR *jcr) deallocate_cipher(rctx); deallocate_fork_cipher(rctx); - set_attributes(jcr, attr, &rctx.bfd); + if (jcr->plugin) { + plugin_set_attributes(jcr, attr, &rctx.bfd); + } else { + set_attributes(jcr, attr, &rctx.bfd); + } /* Verify the cryptographic signature on the last file, if any */ - verify_signature(jcr, rctx.sig); + rctx.type = attr->type; + verify_signature(jcr, rctx); } if (is_bopen(&rctx.bfd)) { @@ -688,9 +723,9 @@ ok_out: /* Free Signature & Crypto Data */ free_signature(rctx); free_session(rctx); - if (jcr->digest) { - crypto_digest_free(jcr->digest); - jcr->digest = NULL; + if (jcr->crypto.digest) { + crypto_digest_free(jcr->crypto.digest); + jcr->crypto.digest = NULL; } /* Free file cipher restore context */ @@ -771,11 +806,10 @@ static const char *zlib_strerror(int stat) } #endif -static int do_file_digest(FF_PKT *ff_pkt, void *pkt, bool top_level) +static int do_file_digest(JCR *jcr, FF_PKT *ff_pkt, bool top_level) { - JCR *jcr = (JCR *)pkt; Dmsg1(50, "do_file_digest jcr=%p\n", jcr); - return (digest_file(jcr, ff_pkt, jcr->digest)); + return (digest_file(jcr, ff_pkt, jcr->crypto.digest)); } /* @@ -785,7 +819,7 @@ static int do_file_digest(FF_PKT *ff_pkt, void *pkt, bool top_level) * TODO landonf: Implement without using find_one_file and * without re-reading the file. */ -static bool verify_signature(JCR *jcr, SIGNATURE *sig) +static bool verify_signature(JCR *jcr, r_ctx &rctx) { X509_KEYPAIR *keypair; DIGEST *digest = NULL; @@ -794,37 +828,42 @@ static bool verify_signature(JCR *jcr, SIGNATURE *sig) crypto_digest_t signing_algorithm = have_sha2 ? CRYPTO_DIGEST_SHA256 : CRYPTO_DIGEST_SHA1; crypto_digest_t algorithm; + SIGNATURE *sig = rctx.sig; - if (!jcr->pki_sign) { + if (!jcr->crypto.pki_sign) { return true; /* no signature OK */ } if (!sig) { - Jmsg1(jcr, M_ERROR, 0, _("Missing cryptographic signature for %s\n"), - jcr->last_fname); + if (rctx.type == FT_REGE || rctx.type == FT_REG || rctx.type == FT_RAW) { + Jmsg1(jcr, M_ERROR, 0, _("Missing cryptographic signature for %s\n"), + jcr->last_fname); + goto bail_out; + } + return true; } /* Iterate through the trusted signers */ - foreach_alist(keypair, jcr->pki_signers) { - err = crypto_sign_get_digest(sig, jcr->pki_keypair, algorithm, &digest); + foreach_alist(keypair, jcr->crypto.pki_signers) { + err = crypto_sign_get_digest(sig, jcr->crypto.pki_keypair, algorithm, &digest); switch (err) { case CRYPTO_ERROR_NONE: Dmsg0(50, "== Got digest\n"); /* - * We computed jcr->digest using signing_algorithm while writing + * We computed jcr->crypto.digest using signing_algorithm while writing * the file. If it is not the same as the algorithm used for * this file, punt by releasing the computed algorithm and * computing by re-reading the file. */ if (algorithm != signing_algorithm) { - if (jcr->digest) { - crypto_digest_free(jcr->digest); - jcr->digest = NULL; + if (jcr->crypto.digest) { + crypto_digest_free(jcr->crypto.digest); + jcr->crypto.digest = NULL; } } - if (jcr->digest) { + if (jcr->crypto.digest) { /* Use digest computed while writing the file to verify the signature */ - if ((err = crypto_sign_verify(sig, keypair, jcr->digest)) != CRYPTO_ERROR_NONE) { + if ((err = crypto_sign_verify(sig, keypair, jcr->crypto.digest)) != CRYPTO_ERROR_NONE) { Dmsg1(50, "Bad signature on %s\n", jcr->last_fname); Jmsg2(jcr, M_ERROR, 0, _("Signature validation failed for file %s: ERR=%s\n"), jcr->last_fname, crypto_strerror(err)); @@ -834,12 +873,12 @@ static bool verify_signature(JCR *jcr, SIGNATURE *sig) /* Signature found, digest allocated. Old method, * re-read the file and compute the digest */ - jcr->digest = digest; + jcr->crypto.digest = digest; /* Checksum the entire file */ /* Make sure we don't modify JobBytes by saving and restoring it */ saved_bytes = jcr->JobBytes; - if (find_one_file(jcr, jcr->ff, do_file_digest, jcr, jcr->last_fname, (dev_t)-1, 1) != 0) { + if (find_one_file(jcr, jcr->ff, do_file_digest, jcr->last_fname, (dev_t)-1, 1) != 0) { Jmsg(jcr, M_ERROR, 0, _("Digest one file failed for file: %s\n"), jcr->last_fname); jcr->JobBytes = saved_bytes; @@ -854,7 +893,7 @@ static bool verify_signature(JCR *jcr, SIGNATURE *sig) jcr->last_fname, crypto_strerror(err)); goto bail_out; } - jcr->digest = NULL; + jcr->crypto.digest = NULL; } /* Valid signature */ @@ -950,8 +989,8 @@ static void unser_crypto_packet_len(RESTORE_CIPHER_CTX *ctx) bool store_data(JCR *jcr, BFILE *bfd, char *data, const int32_t length, bool win32_decomp) { - if (jcr->digest) { - crypto_digest_update(jcr->digest, (uint8_t *)data, length); + if (jcr->crypto.digest) { + crypto_digest_update(jcr->crypto.digest, (uint8_t *)data, length); } if (win32_decomp) { if (!processWin32BackupAPIBlock(bfd, data, length)) { @@ -1075,7 +1114,6 @@ int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen, * packet length may be re-read by unser_crypto_packet_len() */ cipher_ctx->packet_len = 0; } - return wsize; }