static bRC do_clear_scsi_encryption_key(void *value) { DCR *dcr; DEVICE *dev; DEVRES *device; bool need_to_clear; /* * Unpack the arguments passed in. */ dcr = (DCR *)value; if (!dcr) { return bRC_Error; } dev = dcr->dev; if (!dev) { return bRC_Error; } device = dev->device; if (!device) { return bRC_Error; } /* * See if device supports hardware encryption. */ if (!device->drive_crypto_enabled) { return bRC_OK; } P(crypto_operation_mutex); /* * See if we need to query the drive or use the tracked encryption status of the stored. */ if (device->query_crypto_status) { need_to_clear = is_scsi_encryption_enabled(dev->fd(), dev->dev_name); } else { need_to_clear = dev->is_crypto_enabled(); } if (need_to_clear) { Dmsg0(dbglvl, "scsicrypto-sd: Clearing crypto key\n"); if (clear_scsi_encryption_key(dev->fd(), dev->dev_name)) { dev->clear_crypto_enabled(); V(crypto_operation_mutex); return bRC_OK; } else { V(crypto_operation_mutex); return bRC_Error; } } else { Dmsg0(dbglvl, "scsicrypto-sd: Not clearing crypto key because encryption is currently not enabled on drive\n"); V(crypto_operation_mutex); return bRC_OK; } }
static bRC handle_tapealert_readout(void *value) { DCR *dcr; DEVICE *dev; DEVRES *device; uint64_t flags; /* * Unpack the arguments passed in. */ dcr = (DCR *)value; if (!dcr) { return bRC_Error; } dev = dcr->dev; if (!dev) { return bRC_Error; } device = dev->device; if (!device) { return bRC_Error; } /* * See if drive tapealert is enabled. */ if (!device->drive_tapealert_enabled) { Dmsg1(dbglvl, "scsitapealert-sd: tapealert is not enabled on device %s\n", dev->dev_name); return bRC_OK; } Dmsg1(dbglvl, "scsitapealert-sd: checking for tapealerts on device %s\n", dev->dev_name); P(tapealert_operation_mutex); get_tapealert_flags(dev->fd(), dev->dev_name, &flags); V(tapealert_operation_mutex); Dmsg1(dbglvl, "scsitapealert-sd: checking for tapealerts on device %s DONE\n", dev->dev_name); Dmsg1(dbglvl, "scsitapealert-sd: flags: %ld \n", flags); if (flags) { Dmsg1(dbglvl, "scsitapealert-sd: tapealerts on device %s, calling UpdateTapeAlerts\n", dev->dev_name); bfuncs->UpdateTapeAlert(dcr, flags); } return bRC_OK; }
/* * Do an lseek on a DVD handling all the different parts */ boffset_t lseek_dvd(DCR *dcr, boffset_t offset, int whence) { DEVICE *dev; boffset_t pos; char ed1[50], ed2[50]; if (!dcr) { /* can be NULL when called from rewind(NULL) */ return -1; } dev = dcr->dev; Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd(), edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts); switch(whence) { case SEEK_SET: Dmsg2(400, "lseek_dvd SEEK_SET to %s (part_start=%s)\n", edit_int64(offset, ed1), edit_uint64(dev->part_start, ed2)); if ((uint64_t)offset >= dev->part_start) { if ((uint64_t)offset == dev->part_start || (uint64_t)offset < dev->part_start+dev->part_size) { /* We are staying in the current part, just seek */ #if defined(HAVE_WIN32) pos = _lseeki64(dev->fd(), offset-dev->part_start, SEEK_SET); #else pos = lseek(dev->fd(), offset-dev->part_start, SEEK_SET); #endif if (pos < 0) { return pos; } else { return pos + dev->part_start; } } else { /* Load next part, and start again */ Dmsg0(100, "lseek open next part\n"); if (dvd_open_next_part(dcr) < 0) { Dmsg0(400, "lseek_dvd failed while trying to open the next part\n"); return -1; } Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n", dev->part, dev->num_dvd_parts); return lseek_dvd(dcr, offset, SEEK_SET); } } else { /* * pos < dev->part_start : * We need to access a previous part, * so just load the first one, and seek again * until the right one is loaded */ Dmsg0(100, "lseek open first part\n"); if (!dvd_open_first_part(dcr, dev->openmode)) { Dmsg0(400, "lseek_dvd failed while trying to open the first part\n"); return -1; } Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n", dev->part, dev->num_dvd_parts); return lseek_dvd(dcr, offset, SEEK_SET); /* system lseek */ } break; case SEEK_CUR: Dmsg1(400, "lseek_dvd SEEK_CUR to %s\n", edit_int64(offset, ed1)); if ((pos = lseek(dev->fd(), 0, SEEK_CUR)) < 0) { Dmsg0(400, "Seek error.\n"); return pos; } pos += dev->part_start; if (offset == 0) { Dmsg1(400, "lseek_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1)); return pos; } else { Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1)); return lseek_dvd(dcr, pos, SEEK_SET); } break; case SEEK_END: Dmsg1(400, "lseek_dvd SEEK_END to %s\n", edit_int64(offset, ed1)); /* * Bacula does not use offsets for SEEK_END * Also, Bacula uses seek_end only when it wants to * append to the volume, so for a dvd that means * that the volume must be spooled since the DVD * itself is read-only (as currently implemented). */ if (offset > 0) { /* Not used by bacula */ Dmsg1(400, "lseek_dvd SEEK_END called with an invalid offset %s\n", edit_uint64(offset, ed1)); errno = EINVAL; return -1; } /* If we are already on a spooled part and have the * right part number, simply seek */ if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) { if ((pos = lseek(dev->fd(), 0, SEEK_END)) < 0) { return pos; } else { Dmsg1(400, "lseek_dvd SEEK_END returns %s\n", edit_uint64(pos + dev->part_start, ed1)); return pos + dev->part_start; } } else { /* * Load the first part, then load the next until we reach the last one. * This is the only way to be sure we compute the right file address. * * Save previous openmode, and open all but last part read-only * (useful for DVDs) */ int modesave = dev->openmode; if (!dvd_open_first_part(dcr, OPEN_READ_ONLY)) { Dmsg0(400, "lseek_dvd failed while trying to open the first part\n"); return -1; } if (dev->num_dvd_parts > 0) { while (dev->part < dev->num_dvd_parts) { if (dvd_open_next_part(dcr) < 0) { Dmsg0(400, "lseek_dvd failed while trying to open the next part\n"); return -1; } } dev->openmode = modesave; if (dvd_open_next_part(dcr) < 0) { Dmsg0(400, "lseek_dvd failed while trying to open the next part\n"); return -1; } } return lseek_dvd(dcr, 0, SEEK_END); } break; default: Dmsg0(400, "Seek call error.\n"); errno = EINVAL; return -1; } }
/* * Open the next part file. * - Close the fd * - Increment part number * - Reopen the device */ int dvd_open_next_part(DCR *dcr) { DEVICE *dev = dcr->dev; Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n", dev->part, dev->num_dvd_parts, dev->print_name(), dev->getVolCatName(), dev->openmode, dev->file_addr); if (!dev->is_dvd()) { Dmsg1(100, "Device %s is not dvd!!!!\n", dev->print_name()); return -1; } /* When appending, do not open a new part if the current is empty */ if (dev->can_append() && (dev->part > dev->num_dvd_parts) && (dev->part_size == 0)) { Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n"); return dev->fd(); } dev->close_part(dcr); /* close current part */ /* * If we have a spooled part open, write it to the * DVD before opening the next part. */ if (dev->is_part_spooled()) { Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n", dev->part, dev->num_dvd_parts); if (!dvd_write_part(dcr)) { Dmsg0(29, "Error in dvd_write part.\n"); return -1; } } dev->part_start += dev->part_size; dev->part++; Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts); /* Are we working on a part past what is written in the DVD? */ if (dev->num_dvd_parts < dev->part) { POOL_MEM archive_name(PM_FNAME); struct stat buf; /* * First check what is on DVD. If our part is there, we * are in trouble, so bail out. * NB: This is however not a problem if we are writing the first part. * It simply means that we are over writing an existing volume... */ if (dev->num_dvd_parts > 0) { make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */ Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str()); if (stat(archive_name.c_str(), &buf) == 0) { /* bad news bail out */ dev->set_part_spooled(false); Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"), archive_name.c_str()); return -1; } } #ifdef neeeded Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part); make_spooled_dvd_filename(dev, archive_name); /* makes spool name */ /* Check if the next part exists in spool directory . */ Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str()); if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) { Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str()); /* Then try to unlink it */ if (unlink(archive_name.c_str()) < 0) { berrno be; dev->set_part_spooled(false); dev->dev_errno = errno; Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), archive_name.c_str(), be.bstrerror()); return -1; } } #endif } Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->getVolCatName(), dev->openmode); /* Open next part. Note, this sets part_size for part opened. */ if (dev->open(dcr, OPEN_READ_ONLY) < 0) { return -1; } dev->set_labeled(); /* all next parts are "labeled" */ return dev->fd(); }
void set_os_device_parameters(DCR *dcr) { DEVICE *dev = dcr->dev; if (strcmp(dev->dev_name, "/dev/null") == 0) { return; /* no use trying to set /dev/null */ } #if defined(HAVE_LINUX_OS) || defined(HAVE_WIN32) struct mtop mt_com; Dmsg0(100, "In set_os_device_parameters\n"); #if defined(MTSETBLK) if (dev->min_block_size == dev->max_block_size && dev->min_block_size == 0) { /* variable block mode */ mt_com.mt_op = MTSETBLK; mt_com.mt_count = 0; Dmsg0(100, "Set block size to zero\n"); if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) { dev->clrerror(MTSETBLK); } } #endif #if defined(MTSETDRVBUFFER) if (getuid() == 0) { /* Only root can do this */ mt_com.mt_op = MTSETDRVBUFFER; mt_com.mt_count = MT_ST_CLEARBOOLEANS; if (!dev->has_cap(CAP_TWOEOF)) { mt_com.mt_count |= MT_ST_TWO_FM; } if (dev->has_cap(CAP_EOM)) { mt_com.mt_count |= MT_ST_FAST_MTEOM; } Dmsg0(100, "MTSETDRVBUFFER\n"); if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) { dev->clrerror(MTSETDRVBUFFER); } } #endif return; #endif #ifdef HAVE_NETBSD_OS struct mtop mt_com; if (dev->min_block_size == dev->max_block_size && dev->min_block_size == 0) { /* variable block mode */ mt_com.mt_op = MTSETBSIZ; mt_com.mt_count = 0; if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) { dev->clrerror(MTSETBSIZ); } /* Get notified at logical end of tape */ mt_com.mt_op = MTEWARN; mt_com.mt_count = 1; if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) { dev->clrerror(MTEWARN); } } return; #endif #if HAVE_FREEBSD_OS || HAVE_OPENBSD_OS struct mtop mt_com; if (dev->min_block_size == dev->max_block_size && dev->min_block_size == 0) { /* variable block mode */ mt_com.mt_op = MTSETBSIZ; mt_com.mt_count = 0; if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) { dev->clrerror(MTSETBSIZ); } } #if defined(MTIOCSETEOTMODEL) uint32_t neof; if (dev->has_cap(CAP_TWOEOF)) { neof = 2; } else { neof = 1; } if (dev->d_ioctl(dev->fd(), MTIOCSETEOTMODEL, (caddr_t)&neof) < 0) { berrno be; dev->dev_errno = errno; /* save errno */ Mmsg2(dev->errmsg, _("Unable to set eotmodel on device %s: ERR=%s\n"), dev->print_name(), be.bstrerror(dev->dev_errno)); Jmsg(dcr->jcr, M_FATAL, 0, dev->errmsg); } #endif return; #endif #ifdef HAVE_SUN_OS struct mtop mt_com; if (dev->min_block_size == dev->max_block_size && dev->min_block_size == 0) { /* variable block mode */ mt_com.mt_op = MTSRSZ; mt_com.mt_count = 0; if (dev->d_ioctl(dev->fd(), MTIOCTOP, (char *)&mt_com) < 0) { dev->clrerror(MTSRSZ); } } return; #endif }
static bRC handle_read_error(void *value) { DCR *dcr; DEVICE *dev; DEVRES *device; bool decryption_needed; /* * Unpack the arguments passed in. */ dcr = (DCR *)value; if (!dcr) { return bRC_Error; } dev = dcr->dev; if (!dev) { return bRC_Error; } device = dev->device; if (!device) { return bRC_Error; } /* * See if drive crypto is enabled. */ if (device->drive_crypto_enabled) { /* * See if the read error is an EIO which can be returned when we try to read an * encrypted block from a volume without decryption enabled or without a proper * encryption key loaded. */ switch (dev->dev_errno) { case EIO: /* * See if we need to query the drive or use the tracked encryption status of the stored. * When we can query the drive we look at the next block encryption state to see if * we need decryption of the data on the volume. */ if (device->query_crypto_status) { P(crypto_operation_mutex); if (need_scsi_crypto_key(dev->fd(), dev->dev_name, false)) { decryption_needed = true; } else { decryption_needed = false; } V(crypto_operation_mutex); } else { decryption_needed = dev->is_crypto_enabled(); } /* * Alter the error message so it known this error is most likely due to a * failed decryption of the encrypted data on the volume. */ if (decryption_needed) { berrno be; be.set_errno(dev->dev_errno); Mmsg5(dev->errmsg, _("Read error on fd=%d at file:blk %u:%u on device %s. ERR=%s.\n" "Probably due to reading encrypted data from volume\n"), dev->fd(), dev->file, dev->block_num, dev->print_name(), be.bstrerror()); } break; default: break; } } return bRC_OK; }
static bRC do_set_scsi_encryption_key(void *value) { DCR *dcr; DEVICE *dev; DEVRES *device; DIRRES *director; char StoredVolEncrKey[MAX_NAME_LENGTH]; char VolEncrKey[MAX_NAME_LENGTH]; /* * Unpack the arguments passed in. */ dcr = (DCR *)value; if (!dcr) { return bRC_Error; } dev = dcr->dev; if (!dev) { return bRC_Error; } device = dev->device; if (!device) { return bRC_Error; } *StoredVolEncrKey = '\0'; if (!get_volume_encryption_key(dcr, StoredVolEncrKey)) { return bRC_Error; } /* * See if a volume encryption key is available. */ if (!*StoredVolEncrKey) { Dmsg0(dbglvl, "scsicrypto-sd: No encryption key to load on device\n"); return bRC_OK; } /* * See if device supports hardware encryption. */ if (!device->drive_crypto_enabled) { Dmsg0(dbglvl, "scsicrypto-sd: Trying to load encryption key on drive without support\n"); Emsg0(M_ERROR, 0, _("scsicrypto-sd: Trying to load encryption key on drive without support\n")); return bRC_Error; } /* * The key passed from the director to the storage daemon is always base64 encoded. */ base64_to_bin(VolEncrKey, sizeof(VolEncrKey), StoredVolEncrKey, strlen(StoredVolEncrKey)); /* * See if we have an key encryption key in the config then the passed key * has been wrapped using RFC3394 key wrapping. We first copy the current * wrapped key into a temporary variable for unwrapping. */ if (dcr->jcr && dcr->jcr->director) { director = dcr->jcr->director; if (director->keyencrkey) { char WrappedVolEncrKey[MAX_NAME_LENGTH]; memcpy(WrappedVolEncrKey, VolEncrKey, MAX_NAME_LENGTH); memset(VolEncrKey, 0, MAX_NAME_LENGTH); if (aes_unwrap((unsigned char *)director->keyencrkey, DEFAULT_PASSPHRASE_LENGTH / 8, (unsigned char *)WrappedVolEncrKey, (unsigned char *)VolEncrKey) != 0) { Dmsg1(dbglvl, "scsicrypto-sd: Failed to unwrap encryption key using %s\n", director->keyencrkey); Emsg0(M_ERROR, 0, _("scsicrypto-sd: Failed to unwrap encryption key, probably wrong KeyEncryptionKey in config\n")); return bRC_Error; } } } Dmsg1(dbglvl, "scsicrypto-sd: Loading new crypto key %s\n", VolEncrKey); P(crypto_operation_mutex); if (set_scsi_encryption_key(dev->fd(), dev->dev_name, VolEncrKey)) { dev->set_crypto_enabled(); V(crypto_operation_mutex); return bRC_OK; } else { V(crypto_operation_mutex); return bRC_Error; } }