Beispiel #1
0
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;
   }
}
Beispiel #2
0
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;
}
Beispiel #3
0
/* 
 * 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;
   }
}
Beispiel #4
0
/*
 * 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();
}
Beispiel #5
0
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
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;
   }
}