Beispiel #1
0
/*
 * Called here to send the appropriate commands to the SD
 *  to do truncate on purge.
 */
static void do_truncate_on_purge(UAContext *ua, MEDIA_DBR *mr,
                                 char *pool, char *storage,
                                 int drive, BSOCK *sd)
{
   bool ok=false;
   uint64_t VolBytes = 0;

   /* TODO: Return if not mr->Recyle ? */
   if (!mr->Recycle) {
      return;
   }

   /* Do it only if action on purge = truncate is set */
   if (!(mr->ActionOnPurge & ON_PURGE_TRUNCATE)) {
      return;
   }
   /*
    * Send the command to truncate the volume after purge. If this feature
    * is disabled for the specific device, this will be a no-op.
    */

   /* Protect us from spaces */
   bash_spaces(mr->VolumeName);
   bash_spaces(mr->MediaType);
   bash_spaces(pool);
   bash_spaces(storage);

   /* Do it by relabeling the Volume, which truncates it */
   sd->fsend("relabel %s OldName=%s NewName=%s PoolName=%s "
             "MediaType=%s Slot=%d drive=%d\n",
                storage,
                mr->VolumeName, mr->VolumeName,
                pool, mr->MediaType, mr->Slot, drive);

   unbash_spaces(mr->VolumeName);
   unbash_spaces(mr->MediaType);
   unbash_spaces(pool);
   unbash_spaces(storage);

   /* Send relabel command, and check for valid response */
   while (sd->recv() >= 0) {
      ua->send_msg("%s", sd->msg);
      if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu ", &VolBytes) == 1) {
         ok = true;
      }
   }

   if (ok) {
      mr->VolBytes = VolBytes;
      mr->VolFiles = 0;
      set_storageid_in_mr(NULL, mr);
      if (!db_update_media_record(ua->jcr, ua->db, mr)) {
         ua->error_msg(_("Can't update volume size in the catalog\n"));
      }
      ua->send_msg(_("The volume \"%s\" has been truncated\n"), mr->VolumeName);
   } else {
      ua->warning_msg(_("Unable to truncate volume \"%s\"\n"), mr->VolumeName);
   }
}
Beispiel #2
0
/*
 *   Query Device command from Director
 *   Sends Storage Daemon's information on the device to the
 *    caller (presumably the Director).
 *   This command always returns "true" so that the line is
 *    not closed on an error.
 *
 */
bool query_cmd(JCR *jcr)
{
   POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
   BSOCK *dir = jcr->dir_bsock;
   DEVRES *device;
   AUTOCHANGER *changer;
   bool ok;

   Dmsg1(100, "Query_cmd: %s", dir->msg);
   ok = sscanf(dir->msg, query_device, dev_name.c_str()) == 1;
   Dmsg1(100, "<dird: %s", dir->msg);
   if (ok) {
      unbash_spaces(dev_name);
      foreach_res(device, R_DEVICE) {
         /* Find resource, and make sure we were able to open it */
         if (bstrcmp(dev_name.c_str(), device->name())) {
            if (!device->dev) {
               device->dev = init_dev(jcr, device);
            }
            if (!device->dev) {
               break;
            }
            ok = dir_update_device(jcr, device->dev);
            if (ok) {
               ok = dir->fsend(OK_query);
            } else {
               dir->fsend(NO_query);
            }
            return ok;
         }
      }
      foreach_res(changer, R_AUTOCHANGER) {
         /*Find resource, and make sure we were able to open it */
         if (bstrcmp(dev_name.c_str(), changer->name())) {
            if (!changer->device || changer->device->size() == 0) {
               continue;              /* no devices */
            }
            ok = dir_update_changer(jcr, changer);
            if (ok) {
               ok = dir->fsend(OK_query);
            } else {
               dir->fsend(NO_query);
            }
            return ok;
         }
      }
      /* If we get here, the device/autochanger was not found */
      unbash_spaces(dir->msg);
      pm_strcpy(jcr->errmsg, dir->msg);
      dir->fsend(NO_device, dev_name.c_str());
      Dmsg1(100, ">dird: %s", dir->msg);
   } else {
Beispiel #3
0
static int send_volume_info_to_storage_daemon(JCR *jcr, BSOCK *sd, MEDIA_DBR *mr)
{
   int status;
   char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];

   jcr->MediaId = mr->MediaId;
   pm_strcpy(jcr->VolumeName, mr->VolumeName);
   bash_spaces(mr->VolumeName);
   status = sd->fsend(OK_media, mr->VolumeName, mr->VolJobs,
      mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
      mr->VolMounts, mr->VolErrors, mr->VolWrites,
      edit_uint64(mr->MaxVolBytes, ed2),
      edit_uint64(mr->VolCapacityBytes, ed3),
      mr->VolStatus, mr->Slot, mr->MaxVolJobs, mr->MaxVolFiles,
      mr->InChanger,
      edit_int64(mr->VolReadTime, ed4),
      edit_int64(mr->VolWriteTime, ed5),
      mr->EndFile, mr->EndBlock,
      mr->LabelType,
      edit_uint64(mr->MediaId, ed6),
      mr->EncrKey, mr->MinBlocksize, mr->MaxBlocksize);
   unbash_spaces(mr->VolumeName);
   Dmsg2(100, "Vol Info for %s: %s", jcr->Job, sd->msg);
   return status;
}
Beispiel #4
0
/**
 * Get Volume info for a specific volume from the Director's Database
 *
 * Returns: true  on success   (Director guarantees that Pool and MediaType
 *                              are correct and VolStatus==Append or
 *                              VolStatus==Recycle)
 *          false on failure
 *
 *          Volume information returned in dcr->VolCatInfo
 */
bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
{
   JCR *jcr = dcr->jcr;
   BSOCK *dir = jcr->dir_bsock;

   P(vol_info_mutex);
   dcr->setVolCatName(dcr->VolumeName);
   bash_spaces(dcr->getVolCatName());
   dir->fsend(Get_Vol_Info, jcr->Job, dcr->getVolCatName(),
      writing==GET_VOL_INFO_FOR_WRITE?1:0);
   Dmsg1(dbglvl, ">dird %s", dir->msg);
   unbash_spaces(dcr->getVolCatName());
   bool ok = do_get_volume_info(dcr);
   V(vol_info_mutex);
   return ok;
}
Beispiel #5
0
/**
 * Get Volume info for a specific volume from the Director's Database
 *
 * Returns: true  on success   (Director guarantees that Pool and MediaType
 *                              are correct and VolStatus==Append or
 *                              VolStatus==Recycle)
 *          false on failure
 *
 * Volume information returned in dcr->VolCatInfo
 */
bool SD_DCR::dir_get_volume_info(enum get_vol_info_rw writing)
{
   bool ok;
   BSOCK *dir = jcr->dir_bsock;

   P(vol_info_mutex);
   setVolCatName(VolumeName);
   bash_spaces(getVolCatName());
   dir->fsend(Get_Vol_Info, jcr->Job, getVolCatName(),
              (writing == GET_VOL_INFO_FOR_WRITE) ? 1 : 0);
   Dmsg1(dbglvl, ">dird %s", dir->msg);
   unbash_spaces(getVolCatName());
   ok = do_get_volume_info(this);
   V(vol_info_mutex);

   return ok;
}
Beispiel #6
0
static void build_restore_command(JCR *jcr, POOL_MEM &ret)
{
   char replace, *where, *cmd;
   char empty = '\0';

   /*
    * Build the restore command
    */
   if (jcr->replace != 0) {
      replace = jcr->replace;
   } else if (jcr->res.job->replace != 0) {
      replace = jcr->res.job->replace;
   } else {
      replace = REPLACE_ALWAYS;       /* always replace */
   }

   if (jcr->RegexWhere) {
      where = jcr->RegexWhere;        /* override */
      cmd = restorecmdR;
   } else if (jcr->res.job->RegexWhere) {
      where = jcr->res.job->RegexWhere;   /* no override take from job */
      cmd = restorecmdR;
   } else if (jcr->where) {
      where = jcr->where;             /* override */
      cmd = restorecmd;
   } else if (jcr->res.job->RestoreWhere) {
      where = jcr->res.job->RestoreWhere; /* no override take from job */
      cmd = restorecmd;
   } else {                           /* nothing was specified */
      where = &empty;                 /* use default */
      cmd   = restorecmd;
   }

   jcr->prefix_links = jcr->res.job->PrefixLinks;

   bash_spaces(where);
   Mmsg(ret, cmd, replace, jcr->prefix_links, where);
   unbash_spaces(where);
}
Beispiel #7
0
/*
 * See who is connecting and lookup the authentication information.
 * First make him prove his identity and then prove our identity to the Remote daemon.
 */
static inline bool two_way_authenticate(int rcode, BSOCK *bs, JCR* jcr)
{
   POOLMEM *dirname = get_pool_memory(PM_MESSAGE);
   DIRRES *director = NULL;
   int tls_local_need = BNET_TLS_NONE;
   int tls_remote_need = BNET_TLS_NONE;
   bool compatible = true;                /* Want md5 compatible DIR */
   bool auth_success = false;
   alist *verify_list = NULL;
   btimer_t *tid = NULL;

   if (rcode != R_DIRECTOR) {
      Dmsg1(dbglvl, "I only authenticate directors, not %d\n", rcode);
      Jmsg1(jcr, M_FATAL, 0, _("I only authenticate directors, not %d\n"), rcode);
      goto auth_fatal;
   }

   if (bs->msglen < 25 || bs->msglen > 500) {
      Dmsg2(dbglvl, "Bad Hello command from Director at %s. Len=%d.\n",
            bs->who(), bs->msglen);
      char addr[64];
      char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
      Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"),
             who, bs->msglen);
      goto auth_fatal;
   }
   dirname = check_pool_memory_size(dirname, bs->msglen);

   if (sscanf(bs->msg, "Hello Director %s calling", dirname) != 1) {
      char addr[64];
      char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
      bs->msg[100] = 0;
      Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n",
            bs->who(), bs->msg);
      Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"),
            who, bs->msg);
      goto auth_fatal;
   }
   unbash_spaces(dirname);
   foreach_res(director, R_DIRECTOR) {
      if (bstrcmp(director->hdr.name, dirname))
         break;
   }
   if (!director) {
      char addr[64];
      char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
      Jmsg2(jcr, M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n"),
            dirname, who);
      goto auth_fatal;
   }

   if (have_tls) {
      /*
       * TLS Requirement
       */
      if (director->tls_enable) {
         if (director->tls_require) {
            tls_local_need = BNET_TLS_REQUIRED;
         } else {
            tls_local_need = BNET_TLS_OK;
         }
      }

      if (director->tls_authenticate) {
         tls_local_need = BNET_TLS_REQUIRED;
      }

      if (director->tls_verify_peer) {
         verify_list = director->tls_allowed_cns;
      }
   }

   /*
    * Timeout Hello after 10 min
    */
   tid = start_bsock_timer(bs, AUTH_TIMEOUT);

   /*
    * Sanity check.
    */
   ASSERT(director->password.encoding == p_encoding_md5);

   /*
    * Challenge the director
    */
   auth_success = cram_md5_challenge(bs, director->password.value, tls_local_need, compatible);
   if (job_canceled(jcr)) {
      auth_success = false;
      goto auth_fatal;                   /* quick exit */
   }

   if (auth_success) {
      auth_success = cram_md5_respond(bs, director->password.value, &tls_remote_need, &compatible);
      if (!auth_success) {
          char addr[64];
          char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
          Dmsg1(dbglvl, "cram_get_auth failed for %s\n", who);
      }
   } else {
       char addr[64];
       char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
       Dmsg1(dbglvl, "cram_auth failed for %s\n", who);
   }

   if (!auth_success) {
       Emsg1(M_FATAL, 0, _("Incorrect password given by Director at %s.\n"),
             bs->who());
       goto auth_fatal;
   }

   /*
    * Verify that the remote host is willing to meet our TLS requirements
    */
   if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
           " advertize required TLS support.\n"));
      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
      auth_success = false;
      goto auth_fatal;
   }

   /*
    * Verify that we are willing to meet the remote host's requirements
    */
   if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
      auth_success = false;
      goto auth_fatal;
   }

   if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
      /*
       * Engage TLS! Full Speed Ahead!
       */
      if (!bnet_tls_server(director->tls_ctx, bs, verify_list)) {
         Jmsg0(jcr, M_FATAL, 0, _("TLS negotiation failed.\n"));
         auth_success = false;
         goto auth_fatal;
      }
      if (director->tls_authenticate) {         /* authentication only? */
         bs->free_tls();                        /* shutodown tls */
      }
   }

auth_fatal:
   if (tid) {
      stop_bsock_timer(tid);
      tid = NULL;
   }
   free_pool_memory(dirname);
   jcr->director = director;

   /*
    * Single thread all failures to avoid DOS
    */
   if (!auth_success) {
      P(mutex);
      bmicrosleep(6, 0);
      V(mutex);
   }

   return auth_success;
}
Beispiel #8
0
/**
 * Get info on the next appendable volume in the Director's database
 *
 * Returns: true  on success dcr->VolumeName is volume
 *                reserve_volume() called on Volume name
 *          false on failure dcr->VolumeName[0] == 0
 *                also sets dcr->found_in_use if at least one
 *                in use volume was found.
 *
 *          Volume information returned in dcr
 *
 */
bool dir_find_next_appendable_volume(DCR *dcr)
{
    JCR *jcr = dcr->jcr;
    BSOCK *dir = jcr->dir_bsock;
    bool rtn;
    char lastVolume[MAX_NAME_LENGTH];

    Dmsg2(dbglvl, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n",
       dcr->is_reserved(), dcr->VolumeName);

    /*
     * Try the twenty oldest or most available volumes.  Note,
     *   the most available could already be mounted on another
     *   drive, so we continue looking for a not in use Volume.
     */
    lock_volumes();
    P(vol_info_mutex);
    dcr->clear_found_in_use();
    lastVolume[0] = 0;
    for (int vol_index=1;  vol_index < 20; vol_index++) {
       bash_spaces(dcr->media_type);
       bash_spaces(dcr->pool_name);
       dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
       unbash_spaces(dcr->media_type);
       unbash_spaces(dcr->pool_name);
       Dmsg1(dbglvl, ">dird %s", dir->msg);
       if (do_get_volume_info(dcr)) {
          /* Give up if we get the same volume name twice */
          if (lastVolume[0] && bstrcmp(lastVolume, dcr->VolumeName)) {
             Dmsg1(dbglvl, "Got same vol = %s\n", lastVolume);
             break;
          }
          bstrncpy(lastVolume, dcr->VolumeName, sizeof(lastVolume));
          if (dcr->can_i_write_volume()) {
             Dmsg1(dbglvl, "Call reserve_volume for write. Vol=%s\n", dcr->VolumeName);
             if (reserve_volume(dcr, dcr->VolumeName) == NULL) {
                Dmsg2(dbglvl, "Could not reserve volume %s on %s\n", dcr->VolumeName,
                    dcr->dev->print_name());
                continue;
             }
             Dmsg1(dbglvl, "dir_find_next_appendable_volume return true. vol=%s\n",
                dcr->VolumeName);
             rtn = true;
             goto get_out;
          } else {
             Dmsg1(dbglvl, "Volume %s is in use.\n", dcr->VolumeName);
             /* If volume is not usable, it is in use by someone else */
             dcr->set_found_in_use();
             continue;
          }
       }
       Dmsg2(dbglvl, "No vol. index %d return false. dev=%s\n", vol_index,
          dcr->dev->print_name());
       break;
    }
    rtn = false;
    dcr->VolumeName[0] = 0;

get_out:
    V(vol_info_mutex);
    unlock_volumes();
    return rtn;
}
Beispiel #9
0
/*
 * Common routine for both label and relabel
 */
static int do_label(UAContext *ua, const char *cmd, int relabel)
{
   USTORE store;
   BSOCK *sd;
   char dev_name[MAX_NAME_LENGTH];
   MEDIA_DBR mr, omr;
   POOL_DBR pr;
   bool print_reminder = true;
   bool label_barcodes = false;
   int ok = FALSE;
   int i, j;
   int drive;
   bool media_record_exists = false;
   static const char *barcode_keyword[] = {
      "barcode",
      "barcodes",
      NULL};


   memset(&pr, 0, sizeof(pr));
   if (!open_client_db(ua)) {
      return 1;
   }

   /* Look for one of the barcode keywords */
   if (!relabel && (i=find_arg_keyword(ua, barcode_keyword)) >= 0) {
      /* Now find the keyword in the list */
      if ((j = find_arg(ua, barcode_keyword[i])) > 0) {
         *ua->argk[j] = 0;      /* zap barcode keyword */
      }
      label_barcodes = true;
   }

   store.store = get_storage_resource(ua, true/*use default*/);
   if (!store.store) {
      return 1;
   }
   pm_strcpy(store.store_source, _("command line"));
   set_wstorage(ua->jcr, &store);
   drive = get_storage_drive(ua, store.store);

   if (label_barcodes) {
      label_from_barcodes(ua, drive);
      return 1;
   }

   /* If relabel get name of Volume to relabel */
   if (relabel) {
      /* Check for oldvolume=name */
      i = find_arg_with_value(ua, "oldvolume");
      if (i >= 0) {
         memset(&omr, 0, sizeof(omr));
         bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
         if (db_get_media_record(ua->jcr, ua->db, &omr)) {
            goto checkVol;
         }
         ua->error_msg("%s", db_strerror(ua->db));
      }
      /* No keyword or Vol not found, ask user to select */
      if (!select_media_dbr(ua, &omr)) {
         return 1;
      }

      /* Require Volume to be Purged or Recycled */
checkVol:
      if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
         ua->error_msg(_("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
            omr.VolumeName, omr.VolStatus);
         return 1;
      }
   }

   /* Check for volume=NewVolume */
   i = find_arg_with_value(ua, "volume");
   if (i >= 0) {
      pm_strcpy(ua->cmd, ua->argv[i]);
      goto checkName;
   }

   /* Get a new Volume name */
   for ( ;; ) {
      media_record_exists = false;
      if (!get_cmd(ua, _("Enter new Volume name: "))) {
         return 1;
      }
checkName:
      if (!is_volume_name_legal(ua, ua->cmd)) {
         continue;
      }

      memset(&mr, 0, sizeof(mr));
      bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
      /* If VolBytes are zero the Volume is not labeled */
      if (db_get_media_record(ua->jcr, ua->db, &mr)) {
         if (mr.VolBytes != 0) {
             ua->error_msg(_("Media record for new Volume \"%s\" already exists.\n"),
                mr.VolumeName);
             continue;
          }
          media_record_exists = true;
      }
      break;                          /* Got it */
   }

   /* If autochanger, request slot */
   i = find_arg_with_value(ua, "slot");
   if (i >= 0) {
      mr.Slot = atoi(ua->argv[i]);
      if (mr.Slot < 0) {
         mr.Slot = 0;
      }
      mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
   } else if (store.store->autochanger) {
      if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
         return 1;
      }
      mr.Slot = ua->pint32_val;
      if (mr.Slot < 0) {
         mr.Slot = 0;
      }
      mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
   }
   mr.StorageId = store.store->StorageId;

   bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType));

   /* Must select Pool if not already done */
   if (pr.PoolId == 0) {
      memset(&pr, 0, sizeof(pr));
      if (!select_pool_dbr(ua, &pr)) {
         return 1;
      }
   }

   ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);

   if (ok) {
      sd = ua->jcr->store_bsock;
      if (relabel) {
         /* Delete the old media record */
         if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
            ua->error_msg(_("Delete of Volume \"%s\" failed. ERR=%s"),
               omr.VolumeName, db_strerror(ua->db));
         } else {
            ua->info_msg(_("Old volume \"%s\" deleted from catalog.\n"),
               omr.VolumeName);
            /* Update the number of Volumes in the pool */
            pr.NumVols--;
            if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
               ua->error_msg("%s", db_strerror(ua->db));
            }
         }
      }
      if (ua->automount) {
         bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
         ua->info_msg(_("Requesting to mount %s ...\n"), dev_name);
         bash_spaces(dev_name);
         bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
         unbash_spaces(dev_name);
         while (bnet_recv(sd) >= 0) {
            ua->send_msg("%s", sd->msg);
            /* Here we can get
             *  3001 OK mount. Device=xxx      or
             *  3001 Mounted Volume vvvv
             *  3002 Device "DVD-Writer" (/dev/hdc) is mounted.
             *  3906 is cannot mount non-tape
             * So for those, no need to print a reminder
             */
            if (strncmp(sd->msg, "3001 ", 5) == 0 ||
                strncmp(sd->msg, "3002 ", 5) == 0 ||
                strncmp(sd->msg, "3906 ", 5) == 0) {
               print_reminder = false;
            }
         }
      }
   }
   if (print_reminder) {
      ua->info_msg(_("Do not forget to mount the drive!!!\n"));
   }
   close_sd_bsock(ua);

   return 1;
}
Beispiel #10
0
/**
 * Common routine for:
 *   dir_get_volume_info()
 * and
 *   dir_find_next_appendable_volume()
 *
 *  NOTE!!! All calls to this routine must be protected by
 *          locking vol_info_mutex before calling it so that
 *          we don't have one thread modifying the parameters
 *          and another reading them.
 *
 *  Returns: true  on success and vol info in dcr->VolCatInfo
 *           false on failure
 */
static bool do_get_volume_info(DCR *dcr)
{
    JCR *jcr = dcr->jcr;
    BSOCK *dir = jcr->dir_bsock;
    VOLUME_CAT_INFO vol;
    int n;
    int32_t InChanger;

    dcr->setVolCatInfo(false);
    if (dir->recv() <= 0) {
       Dmsg0(dbglvl, "getvolname error bnet_recv\n");
       Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
       return false;
    }
    memset(&vol, 0, sizeof(vol));
    Dmsg1(dbglvl, "<dird %s", dir->msg);
    n = sscanf(dir->msg, OK_media, vol.VolCatName,
               &vol.VolCatJobs, &vol.VolCatFiles,
               &vol.VolCatBlocks, &vol.VolCatBytes,
               &vol.VolCatMounts, &vol.VolCatErrors,
               &vol.VolCatWrites, &vol.VolCatMaxBytes,
               &vol.VolCatCapacityBytes, vol.VolCatStatus,
               &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
               &InChanger, &vol.VolReadTime, &vol.VolWriteTime,
               &vol.EndFile, &vol.EndBlock, &vol.LabelType,
               &vol.VolMediaId, vol.VolEncrKey,
               &vol.VolMinBlocksize, &vol.VolMaxBlocksize);
    if (n != 24) {
       Dmsg3(dbglvl, "Bad response from Dir fields=%d, len=%d: %s",
             n, dir->msglen, dir->msg);
       Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
       return false;
    }
    vol.InChanger = InChanger;        /* bool in structure */
    vol.is_valid = true;
    unbash_spaces(vol.VolCatName);
    bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
    dcr->VolCatInfo = vol;            /* structure assignment */

    /*
     * If we received a new crypto key update the cache and write out the new cache on a change.
     */
    if (*vol.VolEncrKey) {
       if (update_crypto_cache(vol.VolCatName, vol.VolEncrKey)) {
          write_crypto_cache(me->working_directory, "bareos-sd",
                             get_first_port_host_order(me->SDaddrs));
       }
    }

    Dmsg4(dbglvl, "do_get_volume_info return true slot=%d Volume=%s, "
                  "VolminBlocksize=%u VolMaxBlocksize=%u\n",
          vol.Slot, vol.VolCatName, vol.VolMinBlocksize, vol.VolMaxBlocksize);
    Dmsg2(dbglvl, "setting dcr->VolMinBlocksize(%u) to vol.VolMinBlocksize(%u)\n",
          dcr->VolMinBlocksize, vol.VolMinBlocksize);
    Dmsg2(dbglvl, "setting dcr->VolMaxBlocksize(%u) to vol.VolMaxBlocksize(%u)\n",
          dcr->VolMaxBlocksize, vol.VolMaxBlocksize);

    /*
     * Assign the volcatinfo to the dcr.
     */
    dcr->VolMinBlocksize = vol.VolMinBlocksize;
    dcr->VolMaxBlocksize = vol.VolMaxBlocksize;

    return true;
}
Beispiel #11
0
/*
 * Common routine for both label and relabel
 */
static int do_label(UAContext *ua, const char *cmd, bool relabel)
{
   USTORERES store;
   BSOCK *sd;
   char dev_name[MAX_NAME_LENGTH];
   MEDIA_DBR mr, omr;
   POOL_DBR pr;
   bool print_reminder = true;
   bool label_barcodes = false;
   bool label_encrypt = false;
   int ok = FALSE;
   int i, j;
   int drive;
   bool media_record_exists = false;
   static const char *barcode_keywords[] = {
      "barcode",
      "barcodes",
      NULL
   };

   memset(&pr, 0, sizeof(pr));
   if (!open_client_db(ua)) {
      return 1;
   }

   /*
    * Look for one of the barcode keywords
    */
   if (!relabel && (i = find_arg_keyword(ua, barcode_keywords)) >= 0) {
      /*
       * Now find the keyword in the list
       */
      if ((j = find_arg(ua, barcode_keywords[i])) > 0) {
         *ua->argk[j] = 0;      /* zap barcode keyword */
      }
      label_barcodes = true;
   }

   /*
    * Look for the encrypt keyword
    */
   if ((i = find_arg(ua, "encrypt")) > 0) {
      *ua->argk[i] = 0;         /* zap encrypt keyword */
      label_encrypt = true;
   }

   store.store = get_storage_resource(ua, true, label_barcodes);
   if (!store.store) {
      return 1;
   }

   switch (store.store->Protocol) {
   case APT_NDMPV2:
   case APT_NDMPV3:
   case APT_NDMPV4:
      /*
       * See if the user selected a NDMP storage device but its
       * handled by a native Bareos storage daemon e.g. we have
       * a paired_storage pointer.
       */
      if (store.store->paired_storage) {
         store.store = store.store->paired_storage;
      } else {
         ua->warning_msg(_("Storage has non-native protocol.\n"));
         return 1;
      }
      break;
   default:
      break;
   }

   pm_strcpy(store.store_source, _("command line"));
   set_wstorage(ua->jcr, &store);
   drive = get_storage_drive(ua, store.store);

   if (label_barcodes) {
      label_from_barcodes(ua, drive, label_encrypt);
      return 1;
   }

   /*
    * If relabel get name of Volume to relabel
    */
   if (relabel) {
      /*
       * Check for oldvolume=name
       */
      i = find_arg_with_value(ua, "oldvolume");
      if (i >= 0) {
         bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
         if (db_get_media_record(ua->jcr, ua->db, &omr)) {
            goto checkVol;
         }
         ua->error_msg("%s", db_strerror(ua->db));
      }
      /*
       * No keyword or Vol not found, ask user to select
       */
      if (!select_media_dbr(ua, &omr)) {
         return 1;
      }

      /*
       * Require Volume to be Purged or Recycled
       */
checkVol:
      if (!bstrcmp(omr.VolStatus, "Purged") && !bstrcmp(omr.VolStatus, "Recycle")) {
         ua->error_msg(_("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
            omr.VolumeName, omr.VolStatus);
         return 1;
      }
   }

   /*
    * Check for volume=NewVolume
    */
   i = find_arg_with_value(ua, "volume");
   if (i >= 0) {
      pm_strcpy(ua->cmd, ua->argv[i]);
      goto checkName;
   }

   /*
    * Get a new Volume name
    */
   for ( ;; ) {
      media_record_exists = false;
      if (!get_cmd(ua, _("Enter new Volume name: "))) {
         return 1;
      }
checkName:
      if (!is_volume_name_legal(ua, ua->cmd)) {
         continue;
      }

      /*
       * Search by Media name so set VolumeName and clear MediaId.
       */
      mr.MediaId = 0;
      bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));

      /*
       * If VolBytes are zero the Volume is not labeled
       */
      if (db_get_media_record(ua->jcr, ua->db, &mr)) {
         if (mr.VolBytes != 0) {
             ua->error_msg(_("Media record for new Volume \"%s\" already exists.\n"),
                mr.VolumeName);
             continue;
          }
          media_record_exists = true;
      }
      break;                          /* Got it */
   }

   /*
    * If autochanger, request slot
    */
   i = find_arg_with_value(ua, "slot");
   if (i >= 0) {
      mr.Slot = atoi(ua->argv[i]);
      if (mr.Slot < 0) {
         mr.Slot = 0;
      }
      mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
   } else if (store.store->autochanger) {
      if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
         return 1;
      }
      mr.Slot = ua->pint32_val;
      if (mr.Slot < 0) {
         mr.Slot = 0;
      }
      mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
   }
   set_storageid_in_mr(store.store, &mr);

   bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType));

   /*
    * Must select Pool if not already done
    */
   if (pr.PoolId == 0) {
      memset(&pr, 0, sizeof(pr));
      if (!select_pool_dbr(ua, &pr)) {
         return 1;
      }
   }

   /*
    * See if we need to generate a new passphrase for hardware encryption.
    */
   if (label_encrypt) {
      ua->info_msg(_("Generating new hardware encryption key\n"));
      if (!generate_new_encryption_key(ua, &mr)) {
         return 1;
      }
   }

   ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);

   if (ok) {
      sd = ua->jcr->store_bsock;
      if (relabel) {
         /*
          * Delete the old media record
          */
         if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
            ua->error_msg(_("Delete of Volume \"%s\" failed. ERR=%s"),
               omr.VolumeName, db_strerror(ua->db));
         } else {
            ua->info_msg(_("Old volume \"%s\" deleted from catalog.\n"),
               omr.VolumeName);
            /*
             * Update the number of Volumes in the pool
             */
            pr.NumVols--;
            if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
               ua->error_msg("%s", db_strerror(ua->db));
            }
         }
      }
      if (ua->automount) {
         bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
         ua->info_msg(_("Requesting to mount %s ...\n"), dev_name);
         bash_spaces(dev_name);
         sd->fsend("mount %s drive=%d", dev_name, drive);
         unbash_spaces(dev_name);

         /*
          * We use bget_dirmsg here and not bnet_recv because as part of
          * the mount request the stored can request catalog information for
          * any plugin who listens to the bsdEventLabelVerified event.
          * As we don't want to loose any non protocol data e.g. errors
          * without a 3xxx prefix we set the allow_any_message of
          * bget_dirmsg to true and as such is behaves like a normal
          * bnet_recv for any non protocol messages.
          */
         while (bget_dirmsg(sd, true) >= 0) {
            ua->send_msg("%s", sd->msg);

            /*
             * Here we can get
             *  3001 OK mount. Device=xxx      or
             *  3001 Mounted Volume vvvv
             *  3002 Device "DVD-Writer" (/dev/hdc) is mounted.
             *  3906 is cannot mount non-tape
             * So for those, no need to print a reminder
             */
            if (bstrncmp(sd->msg, "3001 ", 5) ||
                bstrncmp(sd->msg, "3002 ", 5) ||
                bstrncmp(sd->msg, "3906 ", 5)) {
               print_reminder = false;
            }
         }
      }
   }

   if (print_reminder) {
      ua->info_msg(_("Do not forget to mount the drive!!!\n"));
   }

   close_sd_bsock(ua);

   return 1;
}
Beispiel #12
0
int authenticate_user_agent(UAContext *uac)
{
   char name[MAX_NAME_LENGTH];
   int tls_local_need = BNET_TLS_NONE;
   int tls_remote_need = BNET_TLS_NONE;
   bool tls_authenticate;
   int compatible = true;
   CONRES *cons = NULL;
   BSOCK *ua = uac->UA_sock;
   bool auth_success = false;
   TLS_CONTEXT *tls_ctx = NULL;
   alist *verify_list = NULL;

   if (ua->msglen < 16 || ua->msglen >= MAX_NAME_LENGTH + 15) {
      Emsg4(M_ERROR, 0, _("UA Hello from %s:%s:%d is invalid. Len=%d\n"), ua->who(),
            ua->host(), ua->port(), ua->msglen);
      return 0;
   }

   if (sscanf(ua->msg, "Hello %127s calling\n", name) != 1) {
      ua->msg[100] = 0;               /* terminate string */
      Emsg4(M_ERROR, 0, _("UA Hello from %s:%s:%d is invalid. Got: %s\n"), ua->who(),
            ua->host(), ua->port(), ua->msg);
      return 0;
   }

   name[sizeof(name)-1] = 0;             /* terminate name */
   if (bstrcmp(name, "*UserAgent*")) {  /* default console */
      /* TLS Requirement */
      if (director->tls_enable) {
         if (director->tls_require) {
            tls_local_need = BNET_TLS_REQUIRED;
         } else {
            tls_local_need = BNET_TLS_OK;
         }
      }

      tls_authenticate = director->tls_authenticate;

      if (tls_authenticate) {
         tls_local_need = BNET_TLS_REQUIRED;
      }

      if (director->tls_verify_peer) {
         verify_list = director->tls_allowed_cns;
      }

      auth_success = cram_md5_challenge(ua, director->password, tls_local_need,
                                        compatible) &&
                     cram_md5_respond(ua, director->password, &tls_remote_need, &compatible);
   } else {
      unbash_spaces(name);
      cons = (CONRES *)GetResWithName(R_CONSOLE, name);
      if (cons) {
         /* TLS Requirement */
         if (cons->tls_enable) {
            if (cons->tls_require) {
               tls_local_need = BNET_TLS_REQUIRED;
            } else {
               tls_local_need = BNET_TLS_OK;
            }
         }

         tls_authenticate = cons->tls_authenticate;

         if (tls_authenticate) {
            tls_local_need = BNET_TLS_REQUIRED;
         }

         if (cons->tls_verify_peer) {
            verify_list = cons->tls_allowed_cns;
         }

         auth_success = cram_md5_challenge(ua, cons->password, tls_local_need,
                                           compatible) &&
                     cram_md5_respond(ua, cons->password, &tls_remote_need, &compatible);

         if (auth_success) {
            uac->cons = cons;         /* save console resource pointer */
         }
      } else {
         auth_success = false;
         goto auth_done;
      }
   }


   /* Verify that the remote peer is willing to meet our TLS requirements */
   if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Emsg0(M_FATAL, 0, _("Authorization problem:"
            " Remote client did not advertise required TLS support.\n"));
      auth_success = false;
      goto auth_done;
   }

   /* Verify that we are willing to meet the peer's requirements */
   if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Emsg0(M_FATAL, 0, _("Authorization problem:"
            " Remote client requires TLS.\n"));
      auth_success = false;
      goto auth_done;
   }

   if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
      if (cons) {
         tls_ctx = cons->tls_ctx;
      } else {
         tls_ctx = director->tls_ctx;
      }

      /* Engage TLS! Full Speed Ahead! */
      if (!bnet_tls_server(tls_ctx, ua, verify_list)) {
         Emsg0(M_ERROR, 0, _("TLS negotiation failed.\n"));
         auth_success = false;
         goto auth_done;
      }
      if (tls_authenticate) {            /* authentication only? */
         ua->free_tls();                 /* stop tls */
      }
   }


/* Authorization Completed */
auth_done:
   if (!auth_success) {
      ua->fsend("%s", _(Dir_sorry));
      Emsg4(M_ERROR, 0, _("Unable to authenticate console \"%s\" at %s:%s:%d.\n"),
            name, ua->who(), ua->host(), ua->port());
      sleep(5);
      return 0;
   }
   ua->fsend(_("1000 OK: %s Version: %s (%s)\n"), my_name, VERSION, BDATE);
   return 1;
}
Beispiel #13
0
/*
 * Director requests us to start a job
 * Basic tasks done here:
 *  - We pickup the JobId to be run from the Director.
 *  - We pickup the device, media, and pool from the Director
 *  - Wait for a connection from the File Daemon (FD)
 *  - Accept commands from the FD (i.e. run the job)
 *  - Return when the connection is terminated or
 *    there is an error.
 */
bool job_cmd(JCR *jcr)
{
   int32_t JobId;
   char sd_auth_key[200];
   char spool_size[30];
   char seed[100];
   BSOCK *dir = jcr->dir_bsock;
   POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
   int32_t JobType, level, spool_attributes, no_attributes, spool_data;
   int32_t write_part_after_job, PreferMountedVols;
   int32_t rerunning;
   int32_t is_client;
   int stat;
   JCR *ojcr;

   /*
    * Get JobId and permissions from Director
    */
   Dmsg1(100, "<dird: %s", dir->msg);
   bstrncpy(spool_size, "0", sizeof(spool_size));
   stat = sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(),
              client_name.c_str(),
              &JobType, &level, fileset_name.c_str(), &no_attributes,
              &spool_attributes, fileset_md5.c_str(), &spool_data,
              &write_part_after_job, &PreferMountedVols, spool_size,
              &rerunning, &jcr->VolSessionId, &jcr->VolSessionTime,
              &is_client, &sd_auth_key);
   if (stat != 19) {
      pm_strcpy(jcr->errmsg, dir->msg);
      dir->fsend(BAD_job, stat, jcr->errmsg);
      Dmsg1(100, ">dird: %s", dir->msg);
      jcr->setJobStatus(JS_ErrorTerminated);
      return false;
   }
   jcr->rerunning = rerunning;
   jcr->sd_client = is_client;
   if (is_client) {
      jcr->sd_auth_key = bstrdup(sd_auth_key);
   }
   Dmsg3(100, "rerunning=%d VolSesId=%d VolSesTime=%d\n", jcr->rerunning,
         jcr->VolSessionId, jcr->VolSessionTime);
   /*
    * Since this job could be rescheduled, we
    *  check to see if we have it already. If so
    *  free the old jcr and use the new one.
    */
   ojcr = get_jcr_by_full_name(job.c_str());
   if (ojcr && !ojcr->authenticated) {
      Dmsg2(100, "Found ojcr=0x%x Job %s\n", (unsigned)(intptr_t)ojcr, job.c_str());
      free_jcr(ojcr);
   }
   jcr->JobId = JobId;
   Dmsg2(800, "Start JobId=%d %p\n", JobId, jcr);
   set_jcr_in_tsd(jcr);

   /*
    * If job rescheduled because previous was incomplete,
    * the Resched flag is set and VolSessionId and VolSessionTime
    * are given to us (same as restarted job).
    */
   if (!jcr->rerunning) {
      jcr->VolSessionId = newVolSessionId();
      jcr->VolSessionTime = VolSessionTime;
   }
   bstrncpy(jcr->Job, job, sizeof(jcr->Job));
   unbash_spaces(job_name);
   jcr->job_name = get_pool_memory(PM_NAME);
   pm_strcpy(jcr->job_name, job_name);
   unbash_spaces(client_name);
   jcr->client_name = get_pool_memory(PM_NAME);
   pm_strcpy(jcr->client_name, client_name);
   unbash_spaces(fileset_name);
   jcr->fileset_name = get_pool_memory(PM_NAME);
   pm_strcpy(jcr->fileset_name, fileset_name);
   jcr->setJobType(JobType);
   jcr->setJobLevel(level);
   jcr->no_attributes = no_attributes;
   jcr->spool_attributes = spool_attributes;
   jcr->spool_data = spool_data;
   jcr->spool_size = str_to_int64(spool_size);
   jcr->write_part_after_job = write_part_after_job;
   jcr->fileset_md5 = get_pool_memory(PM_NAME);
   pm_strcpy(jcr->fileset_md5, fileset_md5);
   jcr->PreferMountedVols = PreferMountedVols;


   jcr->authenticated = false;

   /*
    * Pass back an authorization key for the File daemon
    */
   if (jcr->sd_client) {
      bstrncpy(sd_auth_key, "xxx", 3);
   } else {
      bsnprintf(seed, sizeof(seed), "%p%d", jcr, JobId);
      make_session_key(sd_auth_key, seed, 1);
   }
   dir->fsend(OKjob, jcr->VolSessionId, jcr->VolSessionTime, sd_auth_key);
   Dmsg2(150, ">dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
   /* If not client, set key, otherwise it is already set */
   if (!jcr->sd_client) {
      jcr->sd_auth_key = bstrdup(sd_auth_key);
      memset(sd_auth_key, 0, sizeof(sd_auth_key));
   }
   new_plugins(jcr);            /* instantiate the plugins */
   generate_daemon_event(jcr, "JobStart");
   generate_plugin_event(jcr, bsdEventJobStart, (void *)"JobStart");
   return true;
}
Beispiel #14
0
/*
 * NOTE! This routine opens the SD socket but leaves it open
 */
static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
                               POOL_DBR *pr, bool relabel, bool media_record_exists,
                               int drive)
{
   BSOCK *sd;
   char dev_name[MAX_NAME_LENGTH];
   bool ok = false;
   uint64_t VolBytes = 0;

   if (!(sd=open_sd_bsock(ua))) {
      return false;
   }

   bstrncpy(dev_name, ua->jcr->res.wstore->dev_name(), sizeof(dev_name));
   bash_spaces(dev_name);
   bash_spaces(mr->VolumeName);
   bash_spaces(mr->MediaType);
   bash_spaces(pr->Name);
   if (relabel) {
      bash_spaces(omr->VolumeName);
      sd->fsend("relabel %s OldName=%s NewName=%s PoolName=%s "
                     "MediaType=%s Slot=%d drive=%d MinBlocksize=%d MaxBlocksize=%d",
                 dev_name, omr->VolumeName, mr->VolumeName, pr->Name,
                 mr->MediaType, mr->Slot, drive,
                 /*
                  * if relabeling, keep blocksize settings
                  */
                 omr->MinBlocksize, omr->MaxBlocksize);
      ua->send_msg(_("Sending relabel command from \"%s\" to \"%s\" ...\n"),
         omr->VolumeName, mr->VolumeName);
   } else {
      sd->fsend("label %s VolumeName=%s PoolName=%s MediaType=%s "
                     "Slot=%d drive=%d MinBlocksize=%d MaxBlocksize=%d",
                 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
                 mr->Slot, drive,
                 /*
                  * if labeling, use blocksize defined in pool
                  */
                 pr->MinBlocksize, pr->MaxBlocksize);
      ua->send_msg(_("Sending label command for Volume \"%s\" Slot %d ...\n"),
         mr->VolumeName, mr->Slot);
      Dmsg8(100, "label %s VolumeName=%s PoolName=%s MediaType=%s "
                 "Slot=%d drive=%d MinBlocksize=%d MaxBlocksize=%d\n",
         dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive,
         pr->MinBlocksize, pr->MaxBlocksize);
   }

   /*
    * We use bget_dirmsg here and not bnet_recv because as part of
    * the label request the stored can request catalog information for
    * any plugin who listens to the bsdEventLabelVerified event.
    * As we don't want to loose any non protocol data e.g. errors
    * without a 3xxx prefix we set the allow_any_message of
    * bget_dirmsg to true and as such is behaves like a normal
    * bnet_recv for any non protocol messages.
    */
   while (bget_dirmsg(sd, true) >= 0) {
      ua->send_msg("%s", sd->msg);
      if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu ", &VolBytes) == 1) {
         ok = true;
      }
   }

   unbash_spaces(mr->VolumeName);
   unbash_spaces(mr->MediaType);
   unbash_spaces(pr->Name);
   mr->LabelDate = time(NULL);
   mr->set_label_date = true;

   if (ok) {
      if (media_record_exists) {      /* we update it */
         mr->VolBytes = VolBytes;
         mr->InChanger = mr->Slot > 0;  /* if slot give assume in changer */
         set_storageid_in_mr(ua->jcr->res.wstore, mr);
         if (!db_update_media_record(ua->jcr, ua->db, mr)) {
             ua->error_msg("%s", db_strerror(ua->db));
             ok = false;
         }
      } else {                        /* create the media record */
         set_pool_dbr_defaults_in_media_dbr(mr, pr);
         mr->VolBytes = VolBytes;
         mr->InChanger = mr->Slot > 0;  /* if slot give assume in changer */
         mr->Enabled = 1;
         set_storageid_in_mr(ua->jcr->res.wstore, mr);
         if (db_create_media_record(ua->jcr, ua->db, mr)) {
            ua->info_msg(_("Catalog record for Volume \"%s\", Slot %d  successfully created.\n"),
            mr->VolumeName, mr->Slot);
            /*
             * Update number of volumes in pool
             */
            pr->NumVols++;
            if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
               ua->error_msg("%s", db_strerror(ua->db));
            }
         } else {
            ua->error_msg("%s", db_strerror(ua->db));
            ok = false;
         }
      }
   } else {
      ua->error_msg(_("Label command failed for Volume %s.\n"), mr->VolumeName);
   }

   return ok;
}
Beispiel #15
0
void catalog_request(JCR *jcr, BSOCK *bs)
{
   MEDIA_DBR mr, sdmr;
   JOBMEDIA_DBR jm;
   char Job[MAX_NAME_LENGTH];
   char pool_name[MAX_NAME_LENGTH];
   int index, ok, label, writing;
   POOLMEM *omsg;
   POOL_DBR pr;
   uint32_t Stripe, Copy;
   uint64_t MediaId;
   utime_t VolFirstWritten;
   utime_t VolLastWritten;

   memset(&sdmr, 0, sizeof(sdmr));
   memset(&jm, 0, sizeof(jm));
   Dsm_check(100);

   /*
    * Request to find next appendable Volume for this Job
    */
   Dmsg1(100, "catreq %s", bs->msg);
   if (!jcr->db) {
      omsg = get_memory(bs->msglen+1);
      pm_strcpy(omsg, bs->msg);
      bs->fsend(_("1990 Invalid Catalog Request: %s"), omsg);
      Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog request; DB not open: %s"), omsg);
      free_memory(omsg);
      return;
   }
   /*
    * Find next appendable medium for SD
    */
   if (sscanf(bs->msg, Find_media, &Job, &index, &pool_name, &mr.MediaType) == 4) {
      memset(&pr, 0, sizeof(pr));
      bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
      unbash_spaces(pr.Name);
      ok = db_get_pool_record(jcr, jcr->db, &pr);
      if (ok) {
         mr.PoolId = pr.PoolId;
         set_storageid_in_mr(jcr->res.wstore, &mr);
         mr.ScratchPoolId = pr.ScratchPoolId;
         ok = find_next_volume_for_append(jcr, &mr, index, fnv_create_vol, fnv_prune);
         Dmsg3(050, "find_media ok=%d idx=%d vol=%s\n", ok, index, mr.VolumeName);
      }
      /*
       * Send Find Media response to Storage daemon
       */
      if (ok) {
         send_volume_info_to_storage_daemon(jcr, bs, &mr);
      } else {
         bs->fsend(_("1901 No Media.\n"));
         Dmsg0(500, "1901 No Media.\n");
      }

   /*
    * Request to find specific Volume information
    */
   } else if (sscanf(bs->msg, Get_Vol_Info, &Job, &mr.VolumeName, &writing) == 3) {
      Dmsg1(100, "CatReq GetVolInfo Vol=%s\n", mr.VolumeName);
      /*
       * Find the Volume
       */
      unbash_spaces(mr.VolumeName);
      if (db_get_media_record(jcr, jcr->db, &mr)) {
         const char *reason = NULL;           /* detailed reason for rejection */
         /*
          * If we are reading, accept any volume (reason == NULL)
          * If we are writing, check if the Volume is valid
          *   for this job, and do a recycle if necessary
          */
         if (writing) {
            /*
             * SD wants to write this Volume, so make
             *   sure it is suitable for this job, i.e.
             *   Pool matches, and it is either Append or Recycle
             *   and Media Type matches and Pool allows any volume.
             */
            if (mr.PoolId != jcr->jr.PoolId) {
               reason = _("not in Pool");
            } else if (!bstrcmp(mr.MediaType, jcr->res.wstore->media_type)) {
               reason = _("not correct MediaType");
            } else {
               /*
                * Now try recycling if necessary
                *   reason set non-NULL if we cannot use it
                */
               check_if_volume_valid_or_recyclable(jcr, &mr, &reason);
            }
         }
         if (!reason && mr.Enabled != 1) {
            reason = _("is not Enabled");
         }
         if (reason == NULL) {
            /*
             * Send Find Media response to Storage daemon
             */
            send_volume_info_to_storage_daemon(jcr, bs, &mr);
         } else {
            /* Not suitable volume */
            bs->fsend(_("1998 Volume \"%s\" catalog status is %s, %s.\n"), mr.VolumeName,
               mr.VolStatus, reason);
         }

      } else {
         bs->fsend(_("1997 Volume \"%s\" not in catalog.\n"), mr.VolumeName);
         Dmsg1(100, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName);
      }

   /*
    * Request to update Media record. Comes typically at the end
    *  of a Storage daemon Job Session, when labeling/relabeling a
    *  Volume, or when an EOF mark is written.
    */
   } else if (sscanf(bs->msg, Update_media, &Job, &sdmr.VolumeName,
                     &sdmr.VolJobs, &sdmr.VolFiles, &sdmr.VolBlocks, &sdmr.VolBytes,
                     &sdmr.VolMounts, &sdmr.VolErrors, &sdmr.VolWrites, &sdmr.MaxVolBytes,
                     &VolLastWritten, &sdmr.VolStatus, &sdmr.Slot, &label, &sdmr.InChanger,
                     &sdmr.VolReadTime, &sdmr.VolWriteTime, &VolFirstWritten) == 18) {
      db_lock(jcr->db);
      Dmsg3(400, "Update media %s oldStat=%s newStat=%s\n", sdmr.VolumeName,
         mr.VolStatus, sdmr.VolStatus);
      bstrncpy(mr.VolumeName, sdmr.VolumeName, sizeof(mr.VolumeName)); /* copy Volume name */
      unbash_spaces(mr.VolumeName);
      if (!db_get_media_record(jcr, jcr->db, &mr)) {
         Jmsg(jcr, M_ERROR, 0, _("Unable to get Media record for Volume %s: ERR=%s\n"),
              mr.VolumeName, db_strerror(jcr->db));
         bs->fsend(_("1991 Catalog Request for vol=%s failed: %s"),
            mr.VolumeName, db_strerror(jcr->db));
         goto bail_out;

      }
      /* Set first written time if this is first job */
      if (mr.FirstWritten == 0) {
         if (VolFirstWritten == 0) {
            mr.FirstWritten = jcr->start_time;   /* use Job start time as first write */
         } else {
            mr.FirstWritten = VolFirstWritten;
         }
         mr.set_first_written = true;
      }
      /* If we just labeled the tape set time */
      if (label || mr.LabelDate == 0) {
         mr.LabelDate = jcr->start_time;
         mr.set_label_date = true;
         if (mr.InitialWrite == 0) {
            mr.InitialWrite = jcr->start_time;
         }
         Dmsg2(400, "label=%d labeldate=%d\n", label, mr.LabelDate);
      } else {
         /*
          * Insanity check for VolFiles get set to a smaller value
          */
         if (sdmr.VolFiles < mr.VolFiles) {
            Jmsg(jcr, M_FATAL, 0, _("Volume Files at %u being set to %u"
                 " for Volume \"%s\". This is incorrect.\n"),
               mr.VolFiles, sdmr.VolFiles, mr.VolumeName);
            bs->fsend(_("1992 Update Media error. VolFiles=%u, CatFiles=%u\n"),
               sdmr.VolFiles, mr.VolFiles);
            goto bail_out;

         }
      }
      Dmsg2(400, "Update media: BefVolJobs=%u After=%u\n", mr.VolJobs, sdmr.VolJobs);

      /*
       * Check if the volume has been written by the job,
       * and update the LastWritten field if needed.
       */
      if (mr.VolBlocks != sdmr.VolBlocks && VolLastWritten != 0) {
         mr.LastWritten = VolLastWritten;
      }

      /*
       * Update to point to the last device used to write the Volume.
       *   However, do so only if we are writing the tape, i.e.
       *   the number of VolWrites has increased.
       */
      if (jcr->res.wstore && sdmr.VolWrites > mr.VolWrites) {
         Dmsg2(050, "Update StorageId old=%d new=%d\n",
               mr.StorageId, jcr->res.wstore->StorageId);
         /* Update StorageId after write */
         set_storageid_in_mr(jcr->res.wstore, &mr);
      } else {
         /* Nothing written, reset same StorageId */
         set_storageid_in_mr(NULL, &mr);
      }

      /* Copy updated values to original media record */
      mr.VolJobs      = sdmr.VolJobs;
      mr.VolFiles     = sdmr.VolFiles;
      mr.VolBlocks    = sdmr.VolBlocks;
      mr.VolBytes     = sdmr.VolBytes;
      mr.VolMounts    = sdmr.VolMounts;
      mr.VolErrors    = sdmr.VolErrors;
      mr.VolWrites    = sdmr.VolWrites;
      mr.Slot         = sdmr.Slot;
      mr.InChanger    = sdmr.InChanger;
      bstrncpy(mr.VolStatus, sdmr.VolStatus, sizeof(mr.VolStatus));
      mr.VolReadTime  = sdmr.VolReadTime;
      mr.VolWriteTime = sdmr.VolWriteTime;

      Dmsg2(400, "db_update_media_record. Stat=%s Vol=%s\n", mr.VolStatus, mr.VolumeName);
      /*
       * Update the database, then before sending the response to the
       *  SD, check if the Volume has expired.
       */
      if (!db_update_media_record(jcr, jcr->db, &mr)) {
         Jmsg(jcr, M_FATAL, 0, _("Catalog error updating Media record. %s"),
            db_strerror(jcr->db));
         bs->fsend(_("1993 Update Media error\n"));
         Dmsg0(400, "send error\n");
      } else {
         (void)has_volume_expired(jcr, &mr);
         send_volume_info_to_storage_daemon(jcr, bs, &mr);
      }

bail_out:
      db_unlock(jcr->db);

      Dmsg1(400, ">CatReq response: %s", bs->msg);
      Dmsg1(400, "Leave catreq jcr 0x%x\n", jcr);
      return;
   /*
    * Request to create a JobMedia record
    */
   } else if (sscanf(bs->msg, Create_job_media, &Job,
      &jm.FirstIndex, &jm.LastIndex, &jm.StartFile, &jm.EndFile,
      &jm.StartBlock, &jm.EndBlock, &Copy, &Stripe, &MediaId) == 10) {

      if (jcr->mig_jcr) {
         jm.JobId = jcr->mig_jcr->JobId;
      } else {
         jm.JobId = jcr->JobId;
      }
      jm.MediaId = MediaId;
      Dmsg6(400, "create_jobmedia JobId=%d MediaId=%d SF=%d EF=%d FI=%d LI=%d\n",
         jm.JobId, jm.MediaId, jm.StartFile, jm.EndFile, jm.FirstIndex, jm.LastIndex);
      if (!db_create_jobmedia_record(jcr, jcr->db, &jm)) {
         Jmsg(jcr, M_FATAL, 0, _("Catalog error creating JobMedia record. %s"),
            db_strerror(jcr->db));
         bs->fsend(_("1992 Create JobMedia error\n"));
      } else {
         Dmsg0(400, "JobMedia record created\n");
         bs->fsend(OK_create);
      }

   } else {
      omsg = get_memory(bs->msglen+1);
      pm_strcpy(omsg, bs->msg);
      bs->fsend(_("1990 Invalid Catalog Request: %s"), omsg);
      Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog request: %s"), omsg);
      free_memory(omsg);
   }

   Dmsg1(400, ">CatReq response: %s", bs->msg);
   Dmsg1(400, "Leave catreq jcr 0x%x\n", jcr);
   return;
}
Beispiel #16
0
/*
 * NOTE! This routine opens the SD socket but leaves it open
 */
static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
                               POOL_DBR *pr, int relabel, bool media_record_exists,
                               int drive)
{
   BSOCK *sd;
   char dev_name[MAX_NAME_LENGTH];
   bool ok = false;
   bool is_dvd = false;
   uint64_t VolBytes = 0;

   if (!(sd=open_sd_bsock(ua))) {
      return false;
   }
   bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name));
   bash_spaces(dev_name);
   bash_spaces(mr->VolumeName);
   bash_spaces(mr->MediaType);
   bash_spaces(pr->Name);
   if (relabel) {
      bash_spaces(omr->VolumeName);
      sd->fsend("relabel %s OldName=%s NewName=%s PoolName=%s "
                     "MediaType=%s Slot=%d drive=%d",
                 dev_name, omr->VolumeName, mr->VolumeName, pr->Name, 
                 mr->MediaType, mr->Slot, drive);
      ua->send_msg(_("Sending relabel command from \"%s\" to \"%s\" ...\n"),
         omr->VolumeName, mr->VolumeName);
   } else {
      sd->fsend("label %s VolumeName=%s PoolName=%s MediaType=%s "
                     "Slot=%d drive=%d",
                 dev_name, mr->VolumeName, pr->Name, mr->MediaType, 
                 mr->Slot, drive);
      ua->send_msg(_("Sending label command for Volume \"%s\" Slot %d ...\n"),
         mr->VolumeName, mr->Slot);
      Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
         dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
   }

   while (sd->recv() >= 0) {
      int dvd;
      ua->send_msg("%s", sd->msg);
      if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", &VolBytes,
                 &dvd) == 2) {
         is_dvd = dvd;
         ok = true;
      }
   }
   unbash_spaces(mr->VolumeName);
   unbash_spaces(mr->MediaType);
   unbash_spaces(pr->Name);
   mr->LabelDate = time(NULL);
   mr->set_label_date = true;
   if (is_dvd) {
      /* We know that a freshly labelled DVD has 1 VolParts */
      /* This does not apply to auto-labelled DVDs. */
      mr->VolParts = 1;
   }
   if (ok) {
      if (media_record_exists) {      /* we update it */
         mr->VolBytes = VolBytes;
         mr->InChanger = mr->Slot > 0;  /* if slot give assume in changer */
         mr->StorageId = ua->jcr->wstore->StorageId;
         if (!db_update_media_record(ua->jcr, ua->db, mr)) {
             ua->error_msg("%s", db_strerror(ua->db));
             ok = false;
         }
      } else {                        /* create the media record */
         set_pool_dbr_defaults_in_media_dbr(mr, pr);
         mr->VolBytes = VolBytes;
         mr->InChanger = mr->Slot > 0;  /* if slot give assume in changer */
         mr->StorageId = ua->jcr->wstore->StorageId;
         mr->Enabled = 1;
         if (db_create_media_record(ua->jcr, ua->db, mr)) {
            ua->info_msg(_("Catalog record for Volume \"%s\", Slot %d  successfully created.\n"),
            mr->VolumeName, mr->Slot);
            /* Update number of volumes in pool */
            pr->NumVols++;
            if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
               ua->error_msg("%s", db_strerror(ua->db));
            }
         } else {
            ua->error_msg("%s", db_strerror(ua->db));
            ok = false;
         }
      }
   } else {
      ua->error_msg(_("Label command failed for Volume %s.\n"), mr->VolumeName);
   }
   return ok;
}
Beispiel #17
0
/*
 * See who is connecting and lookup the authentication information.
 * First make him prove his identity and then prove our identity to the Remote daemon.
 */
static inline bool two_way_authenticate(int rcode, BSOCK *bs, JCR* jcr)
{
   POOLMEM *dirname;
   DIRRES *director = NULL;
   int tls_local_need = BNET_TLS_NONE;
   int tls_remote_need = BNET_TLS_NONE;
   bool compatible = true;                 /* require md5 compatible DIR */
   bool auth_success = false;
   alist *verify_list = NULL;

   if (rcode != R_DIRECTOR) {
      Dmsg1(dbglvl, "I only authenticate Directors, not %d\n", rcode);
      Jmsg1(jcr, M_FATAL, 0, _("I only authenticate Directors, not %d\n"), rcode);
      return 0;
   }

   /*
    * Sanity check.
    */
   if (bs->msglen < 25 || bs->msglen > 500) {
      Dmsg2(dbglvl, "Bad Hello command from Director at %s. Len=%d.\n",
            bs->who(), bs->msglen);
      Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"),
            bs->who(), bs->msglen);
      return 0;
   }
   dirname = get_pool_memory(PM_MESSAGE);
   dirname = check_pool_memory_size(dirname, bs->msglen);

   if (sscanf(bs->msg, "Hello Director %127s calling", dirname) != 1) {
      bs->msg[100] = 0;
      Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n",
            bs->who(), bs->msg);
      Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"),
            bs->who(), bs->msg);
      return 0;
   }

   director = NULL;
   unbash_spaces(dirname);
   foreach_res(director, rcode) {
      if (bstrcmp(director->hdr.name, dirname)) {
         break;
      }
   }

   if (!director) {
      Dmsg2(dbglvl, "Connection from unknown Director %s at %s rejected.\n",
            dirname, bs->who());
      Jmsg(jcr, M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n"
                              "Please see %s for help.\n"),
           dirname, bs->who(), MANUAL_AUTH_URL);
      free_pool_memory(dirname);
      return 0;
   }

   /*
    * TLS Requirement
    */
   if (director->tls_enable) {
      if (director->tls_require) {
         tls_local_need = BNET_TLS_REQUIRED;
      } else {
         tls_local_need = BNET_TLS_OK;
      }
   }

   if (director->tls_authenticate) {
      tls_local_need = BNET_TLS_REQUIRED;
   }

   if (director->tls_verify_peer) {
      verify_list = director->tls_allowed_cns;
   }

   ASSERT(director->password.encoding == p_encoding_md5);

   /*
    * Timeout Hello after 10 mins
    */
   btimer_t *tid = start_bsock_timer(bs, AUTH_TIMEOUT);
   auth_success = cram_md5_challenge(bs, director->password.value, tls_local_need, compatible);
   if (auth_success) {
      auth_success = cram_md5_respond(bs, director->password.value, &tls_remote_need, &compatible);
      if (!auth_success) {
         Dmsg1(dbglvl, "cram_get_auth failed with %s\n", bs->who());
      }
   } else {
      Dmsg1(dbglvl, "cram_auth failed with %s\n", bs->who());
   }

   if (!auth_success) {
      Jmsg(jcr, M_FATAL, 0, _("Incorrect password given by Director.\n"
                              "Please see %s for help.\n"), MANUAL_AUTH_URL);
      auth_success = false;
      goto auth_fatal;
   }

   /*
    * Verify that the remote host is willing to meet our TLS requirements
    */
   if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
                               " advertize required TLS support.\n"));
      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
      auth_success = false;
      goto auth_fatal;
   }

   /*
    * Verify that we are willing to meet the remote host's requirements
    */
   if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
      auth_success = false;
      goto auth_fatal;
   }

   if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
      /*
       * Engage TLS! Full Speed Ahead!
       */
      if (!bnet_tls_server(director->tls_ctx, bs, verify_list)) {
         Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with DIR at \"%s:%d\"\n"),
              bs->host(), bs->port());
         auth_success = false;
         goto auth_fatal;
      }
      if (director->tls_authenticate) {     /* authenticate with tls only? */
         bs->free_tls();                    /* yes, shut it down */
      }
   }

auth_fatal:
   stop_bsock_timer(tid);
   free_pool_memory(dirname);
   jcr->director = director;

   return auth_success;
}
Beispiel #18
0
/*
 * Get a message
 *  Call appropriate processing routine
 *  If it is not a Jmsg or a ReqCat message,
 *   return it to the caller.
 *
 *  This routine is called to get the next message from
 *  another daemon. If the message is in canonical message
 *  format and the type is known, it will be dispatched
 *  to the appropriate handler.  If the message is
 *  in any other format, it will be returned.
 *
 *  E.g. any message beginning with a digit will be passed
 *       through to the caller.
 *  All other messages are expected begin with some identifier
 *    -- for the moment only the first character is checked, but
 *    at a later time, the whole identifier (e.g. Jmsg, CatReq, ...)
 *    could be checked. This is followed by Job=Jobname <user-defined>
 *    info. The identifier is used to dispatch the message to the right
 *    place (Job message, catalog request, ...). The Job is used to lookup
 *    the JCR so that the action is performed on the correct jcr, and
 *    the rest of the message is up to the user.  Note, DevUpd uses
 *    *System* for the Job name, and hence no JCR is obtained. This
 *    is a *rare* case where a jcr is not really needed.
 *
 */
int bget_dirmsg(BSOCK *bs, bool allow_any_message)
{
   int32_t n = BNET_TERMINATE;
   char Job[MAX_NAME_LENGTH];
   char MsgType[20];
   int type;
   utime_t mtime;                     /* message time */
   JCR *jcr = bs->jcr();
   char *msg;

   for ( ; !bs->is_stop() && !bs->is_timed_out(); ) {
      n = bs->recv();
      Dmsg2(200, "bget_dirmsg %d: %s\n", n, bs->msg);

      if (bs->is_stop() || bs->is_timed_out()) {
         return n;                    /* error or terminate */
      }
      if (n == BNET_SIGNAL) {          /* handle signal */
         /* BNET_SIGNAL (-1) return from bnet_recv() => network signal */
         switch (bs->msglen) {
         case BNET_EOD:            /* end of data */
            return n;
         case BNET_EOD_POLL:
            bs->fsend(OK_msg);/* send response */
            return n;              /* end of data */
         case BNET_TERMINATE:
            bs->set_terminated();
            return n;
         case BNET_POLL:
            bs->fsend(OK_msg); /* send response */
            break;
         case BNET_HEARTBEAT:
//          encode_time(time(NULL), Job);
//          Dmsg1(100, "%s got heartbeat.\n", Job);
            break;
         case BNET_HB_RESPONSE:
            break;
         case BNET_STATUS:
            /* *****FIXME***** Implement more completely */
            bs->fsend("Status OK\n");
            bs->signal(BNET_EOD);
            break;
         case BNET_BTIME:             /* send BAREOS time */
            char ed1[50];
            bs->fsend("btime %s\n", edit_uint64(get_current_btime(),ed1));
            break;
         default:
            Jmsg1(jcr, M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
            return n;
         }
         continue;
      }

      /*
       * Handle normal data
       */
      if (n > 0 && B_ISDIGIT(bs->msg[0])) {      /* response? */
         return n;                    /* yes, return it */
      }

      /*
       * If we get here, it must be a request.  Either
       *  a message to dispatch, or a catalog request.
       *  Try to fulfill it.
       */
      if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) {
         /*
          * If the special flag allow_any_message is given ignore
          * the error and just return it as normal data.
          */
         if (allow_any_message) {
            return n;
         } else {
            Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
            continue;
         }
      }

      /*
       * Skip past "Jmsg Job=nnn"
       */
      if (!(msg=find_msg_start(bs->msg))) {
         Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
         continue;
      }

      /*
       * Here we are expecting a message of the following format:
       *   Jmsg Job=nnn type=nnn level=nnn Message-string
       * Note, level should really be mtime, but that changes
       *   the protocol.
       */
      if (bs->msg[0] == 'J') {           /* Job message */
         if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%lld",
                    Job, &type, &mtime) != 3) {
            Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
            continue;
         }
         Dmsg1(900, "Got msg: %s\n", bs->msg);
         skip_spaces(&msg);
         skip_nonspaces(&msg);        /* skip type=nnn */
         skip_spaces(&msg);
         skip_nonspaces(&msg);        /* skip level=nnn */
         if (*msg == ' ') {
            msg++;                    /* skip leading space */
         }
         Dmsg1(900, "Dispatch msg: %s", msg);
         dispatch_message(jcr, type, mtime, msg);
         continue;
      }
      /*
       * Here we expact a CatReq message
       *   CatReq Job=nn Catalog-Request-Message
       */
      if (bs->msg[0] == 'C') {        /* Catalog request */
         Dmsg2(900, "Catalog req jcr 0x%x: %s", jcr, bs->msg);
         catalog_request(jcr, bs);
         continue;
      }
      if (bs->msg[0] == 'U') {        /* SD sending attributes */
         Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg);
         catalog_update(jcr, bs);
         continue;
      }
      if (bs->msg[0] == 'B') {        /* SD sending file spool attributes */
         Dmsg2(100, "Blast attributes jcr 0x%x: %s", jcr, bs->msg);
         char filename[256];
         if (sscanf(bs->msg, "BlastAttr Job=%127s File=%255s",
                    Job, filename) != 2) {
            Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
            continue;
         }
         unbash_spaces(filename);
         if (despool_attributes_from_file(jcr, filename)) {
            bs->fsend("1000 OK BlastAttr\n");
         } else {
            bs->fsend("1990 ERROR BlastAttr\n");
         }
         continue;
      }
      if (bs->msg[0] == 'M') {        /* Mount request */
         Dmsg1(900, "Mount req: %s", bs->msg);
         mount_request(jcr, bs, msg);
         continue;
      }
      if (bs->msg[0] == 'S') {       /* Status change */
         int JobStatus;
         char Job[MAX_NAME_LENGTH];
         if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) {
            set_jcr_sd_job_status(jcr, JobStatus); /* current status */
         } else {
            Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
         }
         continue;
      }
#ifdef needed
      /* No JCR for Device Updates! */
      if (bs->msg[0] = 'D') {         /* Device update */
         DEVICE *dev;
         POOL_MEM dev_name, changer_name, media_type, volume_name;
         int dev_open, dev_append, dev_read, dev_labeled;
         int dev_offline, dev_autochanger, dev_autoselect;
         int dev_num_writers, dev_max_writers, dev_reserved;
         uint64_t dev_read_time, dev_write_time, dev_write_bytes, dev_read_bytes;
         uint64_t dev_PoolId;
         Dmsg1(100, "<stored: %s", bs->msg);
         if (sscanf(bs->msg, Device_update,
             &Job, dev_name.c_str(),
             &dev_append, &dev_read,
             &dev_num_writers, &dev_open,
             &dev_labeled, &dev_offline, &dev_reserved,
             &dev_max_writers, &dev_autoselect,
             &dev_autochanger,
             changer_name.c_str(), media_type.c_str(),
             volume_name.c_str(),
             &dev_read_time, &dev_write_time, &dev_read_bytes,
             &dev_write_bytes) != 19) {
            Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
         } else {
            unbash_spaces(dev_name);
            dev = (DEVICE *)GetResWithName(R_DEVICE, dev_name.c_str());
            if (!dev) {
               continue;
            }
            unbash_spaces(changer_name);
            unbash_spaces(media_type);
            unbash_spaces(volume_name);
            bstrncpy(dev->ChangerName, changer_name.c_str(), sizeof(dev->ChangerName));
            bstrncpy(dev->MediaType, media_type.c_str(), sizeof(dev->MediaType));
            bstrncpy(dev->VolumeName, volume_name.c_str(), sizeof(dev->VolumeName));
            /* Note, these are copied because they are boolean rather than
             *  integer.
             */
            dev->open = dev_open;
            dev->append = dev_append;
            dev->read = dev_read;
            dev->labeled = dev_labeled;
            dev->offline = dev_offline;
            dev->autoselect = dev_autoselect;
            dev->autochanger = dev_autochanger > 0;
            dev->num_drives = dev_autochanger;    /* does double duty */
            dev->PoolId = dev_PoolId;
            dev->num_writers = dev_num_writers;
            dev->max_writers = dev_max_writers;
            dev->reserved = dev_reserved;
            dev->found = true;
            dev->DevReadTime = dev_read_time; /* TODO : have to update database */
            dev->DevWriteTime = dev_write_time;
            dev->DevReadBytes = dev_read_bytes;
            dev->DevWriteBytes = dev_write_bytes;
         }
         continue;
      }
#endif
      return n;
   }
   return n;
}
Beispiel #19
0
/*
 * Director requests us to start a job
 * Basic tasks done here:
 *  - We pickup the JobId to be run from the Director.
 *  - We pickup the device, media, and pool from the Director
 *  - Wait for a connection from the File Daemon (FD)
 *  - Accept commands from the FD (i.e. run the job)
 *  - Return when the connection is terminated or
 *    there is an error.
 */
bool job_cmd(JCR *jcr)
{
   int32_t JobId;
   char auth_key[MAX_NAME_LENGTH];
   char seed[MAX_NAME_LENGTH];
   char spool_size[MAX_NAME_LENGTH];
   BSOCK *dir = jcr->dir_bsock;
   POOL_MEM job_name, client_name, job, fileset_name, fileset_md5, backup_format;
   int32_t JobType, level, spool_attributes, no_attributes, spool_data;
   int32_t PreferMountedVols, rerunning, protocol, dumplevel;
   int status;
   uint64_t quota = 0;
   JCR *ojcr;

   /*
    * Get JobId and permissions from Director
    */
   Dmsg1(100, "<dird: %s", dir->msg);
   bstrncpy(spool_size, "0", sizeof(spool_size));
   status = sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(),
                   client_name.c_str(), &JobType, &level, fileset_name.c_str(),
                   &no_attributes, &spool_attributes, fileset_md5.c_str(),
                   &spool_data, &PreferMountedVols, spool_size, &rerunning,
                   &jcr->VolSessionId, &jcr->VolSessionTime, &quota, &protocol,
                   backup_format.c_str(), &dumplevel);
   if (status != 20) {
      pm_strcpy(jcr->errmsg, dir->msg);
      dir->fsend(BAD_job, status, jcr->errmsg);
      Dmsg1(100, ">dird: %s", dir->msg);
      jcr->setJobStatus(JS_ErrorTerminated);
      return false;
   }

   jcr->rerunning = (rerunning) ? true : false;
   jcr->setJobProtocol(protocol);

   Dmsg4(100, "rerunning=%d VolSesId=%d VolSesTime=%d Protocol=%d\n",
         jcr->rerunning, jcr->VolSessionId, jcr->VolSessionTime, jcr->getJobProtocol());
   /*
    * Since this job could be rescheduled, we
    *  check to see if we have it already. If so
    *  free the old jcr and use the new one.
    */
   ojcr = get_jcr_by_full_name(job.c_str());
   if (ojcr && !ojcr->authenticated) {
      Dmsg2(100, "Found ojcr=0x%x Job %s\n", (unsigned)(intptr_t)ojcr, job.c_str());
      free_jcr(ojcr);
   }
   jcr->JobId = JobId;
   Dmsg2(800, "Start JobId=%d %p\n", JobId, jcr);
   /*
    * If job rescheduled because previous was incomplete,
    * the Resched flag is set and VolSessionId and VolSessionTime
    * are given to us (same as restarted job).
    */
   if (!jcr->rerunning) {
      jcr->VolSessionId = newVolSessionId();
      jcr->VolSessionTime = VolSessionTime;
   }
   bstrncpy(jcr->Job, job, sizeof(jcr->Job));
   unbash_spaces(job_name);
   jcr->job_name = get_pool_memory(PM_NAME);
   pm_strcpy(jcr->job_name, job_name);
   unbash_spaces(client_name);
   jcr->client_name = get_pool_memory(PM_NAME);
   pm_strcpy(jcr->client_name, client_name);
   unbash_spaces(fileset_name);
   jcr->fileset_name = get_pool_memory(PM_NAME);
   pm_strcpy(jcr->fileset_name, fileset_name);
   jcr->setJobType(JobType);
   jcr->setJobLevel(level);
   jcr->no_attributes = no_attributes;
   jcr->spool_attributes = spool_attributes;
   jcr->spool_data = spool_data;
   jcr->spool_size = str_to_int64(spool_size);
   jcr->fileset_md5 = get_pool_memory(PM_NAME);
   pm_strcpy(jcr->fileset_md5, fileset_md5);
   jcr->PreferMountedVols = PreferMountedVols;
   jcr->RemainingQuota = quota;
   unbash_spaces(backup_format);
   jcr->backup_format = get_pool_memory(PM_NAME);
   pm_strcpy(jcr->backup_format, backup_format);
   jcr->DumpLevel = dumplevel;
   jcr->authenticated = false;

   Dmsg1(50, "Quota set as %llu\n", quota);

   /*
    * Pass back an authorization key for the File daemon
    */
   bsnprintf(seed, sizeof(seed), "%p%d", jcr, JobId);
   make_session_key(auth_key, seed, 1);
   dir->fsend(OK_job, jcr->VolSessionId, jcr->VolSessionTime, auth_key);
   Dmsg2(50, ">dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
   jcr->sd_auth_key = bstrdup(auth_key);
   memset(auth_key, 0, sizeof(auth_key));

   dispatch_new_plugin_options(jcr);
   generate_plugin_event(jcr, bsdEventJobStart, (void *)"JobStart");

   return true;
}
Beispiel #20
0
/**
 * Get info on the next appendable volume in the Director's database
 *
 * Returns: true  on success dcr->VolumeName is volume
 *                reserve_volume() called on Volume name
 *          false on failure dcr->VolumeName[0] == 0
 *                also sets dcr->found_in_use if at least one
 *                in use volume was found.
 *
 * Volume information returned in dcr
 */
bool SD_DCR::dir_find_next_appendable_volume()
{
    bool retval;
    BSOCK *dir = jcr->dir_bsock;
    POOL_MEM unwanted_volumes(PM_MESSAGE);

    Dmsg2(dbglvl, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n", is_reserved(), VolumeName);

    /*
     * Try the twenty oldest or most available volumes. Note,
     * the most available could already be mounted on another
     * drive, so we continue looking for a not in use Volume.
     */
    lock_volumes();
    P(vol_info_mutex);
    clear_found_in_use();

    pm_strcpy(unwanted_volumes, "");
    for (int vol_index = 1; vol_index < 20; vol_index++) {
       bash_spaces(media_type);
       bash_spaces(pool_name);
       bash_spaces(unwanted_volumes.c_str());
       dir->fsend(Find_media, jcr->Job, vol_index, pool_name, media_type, unwanted_volumes.c_str());
       unbash_spaces(media_type);
       unbash_spaces(pool_name);
       unbash_spaces(unwanted_volumes.c_str());
       Dmsg1(dbglvl, ">dird %s", dir->msg);

       if (do_get_volume_info(this)) {
          if (vol_index == 1) {
             pm_strcpy(unwanted_volumes, VolumeName);
          } else {
             pm_strcat(unwanted_volumes, ",");
             pm_strcat(unwanted_volumes, VolumeName);
          }

          if (can_i_write_volume()) {
             Dmsg1(dbglvl, "Call reserve_volume for write. Vol=%s\n", VolumeName);
             if (reserve_volume(this, VolumeName) == NULL) {
                Dmsg2(dbglvl, "Could not reserve volume %s on %s\n", VolumeName, dev->print_name());
                continue;
             }
             Dmsg1(dbglvl, "dir_find_next_appendable_volume return true. vol=%s\n", VolumeName);
             retval = true;
             goto get_out;
          } else {
             Dmsg1(dbglvl, "Volume %s is in use.\n", VolumeName);

             /*
              * If volume is not usable, it is in use by someone else
              */
             set_found_in_use();
             continue;
          }
       }
       Dmsg2(dbglvl, "No vol. index %d return false. dev=%s\n", vol_index, dev->print_name());
       break;
    }
    retval = false;
    VolumeName[0] = 0;

get_out:
    V(vol_info_mutex);
    unlock_volumes();

    return retval;
}
Beispiel #21
0
bool run_cmd(JCR *jcr)
{
   struct timeval tv;
   struct timezone tz;
   struct timespec timeout;
   int errstat = 0;
   BSOCK *cl;
   int fd_version = 0;
   int sd_version = 0;
   char job_name[500];
   int i;
   int stat;

   Dsm_check(200);
   Dmsg1(200, "Run_cmd: %s\n", jcr->dir_bsock->msg);

   /* If we do not need the FD, we are doing a virtual backup. */
   if (jcr->no_client_used()) {
      do_vbackup(jcr);
      return false;
   }

   jcr->sendJobStatus(JS_WaitFD);          /* wait for FD to connect */

   Dmsg2(050, "sd_calls_client=%d sd_client=%d\n", jcr->sd_calls_client, jcr->sd_client);
   if (jcr->sd_calls_client) {
      /* We connected to Client, so finish work */
      cl = jcr->file_bsock;
      if (!cl) {
         Jmsg0(jcr, M_FATAL, 0, _("Client socket not open. Could not connect to Client.\n"));
         Dmsg0(050, "Client socket not open. Could not connect to Client.\n");
         return false;
      }
      /* Get response to Hello command sent earlier */
      Dmsg0(050, "Read Hello command from Client\n");
      for (i=0; i<60; i++) {
         stat = cl->recv();
         if (stat <= 0) {
            bmicrosleep(1, 0);
         } else {
            break;
         }
      }
      if (stat <= 0) {
         berrno be;
         Jmsg1(jcr, M_FATAL, 0, _("Recv request to Client failed. ERR=%s\n"),
            be.bstrerror());
         Dmsg1(050, _("Recv request to Client failed. ERR=%s\n"), be.bstrerror());
         return false;
      }
      Dmsg1(050, "Got from FD: %s\n", cl->msg);
      if (sscanf(cl->msg, "Hello Bacula SD: Start Job %127s %d %d", job_name, &fd_version, &sd_version) != 3) {
         Jmsg1(jcr, M_FATAL, 0, _("Bad Hello from Client: %s.\n"), cl->msg);
         Dmsg1(050, _("Bad Hello from Client: %s.\n"), cl->msg);
         return false;
      }
      unbash_spaces(job_name);
      jcr->FDVersion = fd_version;
      jcr->SDVersion = sd_version;
      Dmsg1(050, "FDVersion=%d\n", fd_version);

      /*
       * Authenticate the File daemon
       */
      Dmsg0(050, "=== Authenticate FD\n");
      if (jcr->authenticated || !authenticate_filed(jcr)) {
         Dmsg1(050, "Authentication failed Job %s\n", jcr->Job);
         Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n"));
      } else {
         jcr->authenticated = true;
      }
   } else if (!jcr->sd_client) {
      /* We wait to receive connection from Client */
      gettimeofday(&tv, &tz);
      timeout.tv_nsec = tv.tv_usec * 1000;
      timeout.tv_sec = tv.tv_sec + me->client_wait;

      Dmsg3(050, "%s waiting %d sec for FD to contact SD key=%s\n",
            jcr->Job, (int)(timeout.tv_sec-time(NULL)), jcr->sd_auth_key);

      Dmsg3(800, "=== Block Job=%s jid=%d %p\n", jcr->Job, jcr->JobId, jcr);

      /*
       * Wait for the File daemon to contact us to start the Job,
       *  when he does, we will be released, unless the 30 minutes
       *  expires.
       */
      P(mutex);
      while ( !jcr->authenticated && !job_canceled(jcr) ) {
         errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
         if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) {
            break;
         }
         Dmsg1(800, "=== Auth cond errstat=%d\n", errstat);
      }
      Dmsg4(050, "=== Auth=%d jid=%d canceled=%d errstat=%d\n",
         jcr->JobId, jcr->authenticated, job_canceled(jcr), errstat);
      V(mutex);
      Dmsg2(800, "Auth fail or cancel for jid=%d %p\n", jcr->JobId, jcr);
   }

   memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));

   if (jcr->authenticated && !job_canceled(jcr)) {
      Dmsg2(800, "Running jid=%d %p\n", jcr->JobId, jcr);
      run_job(jcr);                   /* Run the job */
   }
   Dmsg2(800, "Done jid=%d %p\n", jcr->JobId, jcr);
   return false;
}