Ejemplo n.º 1
0
/*
 * Cleanup a NDMP restore session.
 */
void ndmp_restore_cleanup(JCR *jcr, int TermCode)
{
   char term_code[100];
   const char *term_msg;
   int msg_type = M_INFO;

   Dmsg0(20, "In ndmp_restore_cleanup\n");
   update_job_end(jcr, TermCode);

   if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
      secure_erase(jcr, jcr->RestoreBootstrap);
      jcr->unlink_bsr = false;
   }

   if (job_canceled(jcr)) {
      cancel_storage_daemon_job(jcr);
   }

   switch (TermCode) {
   case JS_Terminated:
      if (jcr->ExpectedFiles > jcr->jr.JobFiles) {
         term_msg = _("Restore OK -- warning file count mismatch");
      } else {
         term_msg = _("Restore OK");
      }
      break;
   case JS_Warnings:
         term_msg = _("Restore OK -- with warnings");
         break;
   case JS_FatalError:
   case JS_ErrorTerminated:
      term_msg = _("*** Restore Error ***");
      msg_type = M_ERROR;          /* Generate error message */
      if (jcr->store_bsock) {
         jcr->store_bsock->signal(BNET_TERMINATE);
         if (jcr->SD_msg_chan_started) {
            pthread_cancel(jcr->SD_msg_chan);
         }
      }
      break;
   case JS_Canceled:
      term_msg = _("Restore Canceled");
      if (jcr->store_bsock) {
         jcr->store_bsock->signal(BNET_TERMINATE);
         if (jcr->SD_msg_chan_started) {
            pthread_cancel(jcr->SD_msg_chan);
         }
      }
      break;
   default:
      term_msg = term_code;
      sprintf(term_code, _("Inappropriate term code: %c\n"), TermCode);
      break;
   }

   generate_restore_summary(jcr, msg_type, term_msg);

   Dmsg0(20, "Leaving ndmp_restore_cleanup\n");
}
Ejemplo n.º 2
0
/*
 * Erases the data on the device specified.
 */
int nvm_erase_device(const NVM_UID device_uid,
		const NVM_PASSPHRASE passphrase, const NVM_SIZE passphrase_len)
{
	COMMON_LOG_ENTRY();
	int rc = NVM_SUCCESS;
	struct device_discovery discovery;

	// check user has permission to make changes
	if (check_caller_permissions() != COMMON_SUCCESS)
	{
		rc = NVM_ERR_INVALIDPERMISSIONS;
	}
	else if (!is_supported_driver_available())
	{
		rc = NVM_ERR_BADDRIVER;
	}
	else if ((rc = IS_NVM_FEATURE_SUPPORTED(modify_device_security)) != NVM_SUCCESS)
	{
		COMMON_LOG_ERROR("Modifying " NVM_DIMM_NAME " security is not supported.");
	}
	else if (device_uid == NULL)
	{
		COMMON_LOG_ERROR("Invalid parameter, device_uid is NULL");
		rc = NVM_ERR_INVALIDPARAMETER;
	}
	else if ((rc = exists_and_manageable(device_uid, &discovery, 1)) == NVM_SUCCESS)
	{
		if (discovery.security_capabilities.passphrase_capable)
		{
			// check passphrase length
			if (check_passphrase(passphrase, passphrase_len) != NVM_SUCCESS)
			{
				rc = NVM_ERR_BADPASSPHRASE;
			}
			// verify device is in the right state to accept a secure erase
			else if ((rc =
					security_change_prepare(&discovery, passphrase, passphrase_len))
					== NVM_SUCCESS)
			{
				rc = secure_erase(passphrase, passphrase_len, &discovery);
				// clear any device context - security state has likely changed
				invalidate_devices();
			}
		}
		else
		{
			COMMON_LOG_ERROR("Invalid parameter. "
					"Crypto scramble erase is not valid in the current security state");
			rc = NVM_ERR_INVALIDPARAMETER;
		}
	}

	COMMON_LOG_EXIT_RETURN_I(rc);
	return rc;
}
Ejemplo n.º 3
0
int
create_volume(struct tcplay_opts *opts)
{
	char *pass, *pass_again;
	char *h_pass = NULL;
	char buf[1024];
	disksz_t blocks, hidden_blocks = 0;
	size_t blksz;
	struct tchdr_enc *ehdr, *hehdr;
	struct tchdr_enc *ehdr_backup, *hehdr_backup;
	uint64_t tmp;
	int error, r, ret;

	pass = h_pass = pass_again = NULL;
	ehdr = hehdr = NULL;
	ehdr_backup = hehdr_backup = NULL;
	ret = -1; /* Default to returning error */

	if (opts->cipher_chain == NULL)
		opts->cipher_chain = tc_cipher_chains[0];
	if (opts->prf_algo == NULL)
		opts->prf_algo = &pbkdf_prf_algos[0];
	if (opts->h_cipher_chain == NULL)
		opts->h_cipher_chain = opts->cipher_chain;
	if (opts->h_prf_algo == NULL)
		opts->h_prf_algo = opts->prf_algo;

	if ((error = get_disk_info(opts->dev, &blocks, &blksz)) != 0) {
		tc_log(1, "could not get disk info\n");
		return -1;
	}

	if ((blocks*blksz) <= MIN_VOL_BYTES) {
		tc_log(1, "Cannot create volumes on devices with less "
		    "than %d bytes\n", MIN_VOL_BYTES);
		return -1;
	}

	if (opts->interactive) {
		if (((pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) ||
		   ((pass_again = alloc_safe_mem(PASS_BUFSZ)) == NULL)) {
			tc_log(1, "could not allocate safe passphrase memory\n");
			goto out;
		}

		if ((error = read_passphrase("Passphrase: ", pass, MAX_PASSSZ,
		    PASS_BUFSZ, 0) ||
		    (read_passphrase("Repeat passphrase: ", pass_again,
		    MAX_PASSSZ, PASS_BUFSZ, 0)))) {
			tc_log(1, "could not read passphrase\n");
			goto out;
		}

		if (strcmp(pass, pass_again) != 0) {
			tc_log(1, "Passphrases don't match\n");
			goto out;
		}

		free_safe_mem(pass_again);
		pass_again = NULL;
	} else {
		/* In batch mode, use provided passphrase */
		if ((pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) {
			tc_log(1, "could not allocate safe "
			    "passphrase memory");
			goto out;
		}

		if (opts->passphrase != NULL) {
			strncpy(pass, opts->passphrase, MAX_PASSSZ);
			pass[MAX_PASSSZ] = '\0';
		}
	}

	if (opts->nkeyfiles > 0) {
		/* Apply keyfiles to 'pass' */
		if ((error = apply_keyfiles((unsigned char *)pass, PASS_BUFSZ,
		    opts->keyfiles, opts->nkeyfiles))) {
			tc_log(1, "could not apply keyfiles\n");
			goto out;
		}
	}

	if (opts->hidden) {
		if (opts->interactive) {
			if (((h_pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) ||
			   ((pass_again = alloc_safe_mem(PASS_BUFSZ)) == NULL)) {
				tc_log(1, "could not allocate safe "
				    "passphrase memory\n");
				goto out;
			}

			if ((error = read_passphrase("Passphrase for hidden volume: ",
			   h_pass, MAX_PASSSZ, PASS_BUFSZ, 0) ||
			   (read_passphrase("Repeat passphrase: ", pass_again,
			   MAX_PASSSZ, PASS_BUFSZ, 0)))) {
				tc_log(1, "could not read passphrase\n");
				goto out;
			}

			if (strcmp(h_pass, pass_again) != 0) {
				tc_log(1, "Passphrases for hidden volume don't "
				    "match\n");
				goto out;
			}

			free_safe_mem(pass_again);
			pass_again = NULL;
		} else {
			/* In batch mode, use provided passphrase */
			if ((h_pass = alloc_safe_mem(PASS_BUFSZ)) == NULL) {
				tc_log(1, "could not allocate safe "
				    "passphrase memory");
				goto out;
			}

			if (opts->h_passphrase != NULL) {
				strncpy(h_pass, opts->h_passphrase, MAX_PASSSZ);
				h_pass[MAX_PASSSZ] = '\0';
			}
		}

		if (opts->n_hkeyfiles > 0) {
			/* Apply keyfiles to 'h_pass' */
			if ((error = apply_keyfiles((unsigned char *)h_pass,
			    PASS_BUFSZ, opts->h_keyfiles, opts->n_hkeyfiles))) {
				tc_log(1, "could not apply keyfiles\n");
				goto out;
			}
		}

		if (opts->interactive) {
			hidden_blocks = 0;
		} else {
			hidden_blocks = opts->hidden_size_bytes/blksz;
			if (hidden_blocks == 0) {
				tc_log(1, "hidden_blocks to create volume "
				    "cannot be zero!\n");
				goto out;
			}

			if (opts->hidden_size_bytes >=
			    (blocks*blksz) - MIN_VOL_BYTES) {
				tc_log(1, "Hidden volume needs to be "
				    "smaller than the outer volume\n");
				goto out;
			}
		}

		/* This only happens in interactive mode */
		while (hidden_blocks == 0) {
			if ((r = _humanize_number(buf, sizeof(buf),
			    (uint64_t)(blocks * blksz))) < 0) {
				sprintf(buf, "%"DISKSZ_FMT" bytes", (blocks * blksz));
			}

			printf("The total volume size of %s is %s (bytes)\n", opts->dev, buf);
			memset(buf, 0, sizeof(buf));
			printf("Size of hidden volume (e.g. 127M):  ");
			fflush(stdout);

			if ((fgets(buf, sizeof(buf), stdin)) == NULL) {
				tc_log(1, "Could not read from stdin\n");
				goto out;
			}

			/* get rid of trailing newline */
			buf[strlen(buf)-1] = '\0';
			if ((error = _dehumanize_number(buf,
			    &tmp)) != 0) {
				tc_log(1, "Could not interpret input: %s\n", buf);
				continue;
			}

			if (tmp >= (blocks*blksz) - MIN_VOL_BYTES) {
				tc_log(1, "Hidden volume needs to be "
				    "smaller than the outer volume\n");
				hidden_blocks = 0;
				continue;
			}

			hidden_blocks = (size_t)tmp;
			hidden_blocks /= blksz;
		}
	}

	if (opts->interactive) {
		/* Show summary and ask for confirmation */
		printf("Summary of actions:\n");
		if (opts->secure_erase)
			printf(" - Completely erase *EVERYTHING* on %s\n", opts->dev);
		printf(" - Create %svolume on %s\n", opts->hidden?("outer "):"", opts->dev);
		if (opts->hidden) {
			printf(" - Create hidden volume of %"DISKSZ_FMT" bytes at end of "
			    "outer volume\n",
			    hidden_blocks * blksz);
		}

		printf("\n Are you sure you want to proceed? (y/n) ");
		fflush(stdout);
		if ((fgets(buf, sizeof(buf), stdin)) == NULL) {
			tc_log(1, "Could not read from stdin\n");
			goto out;
		}

		if ((buf[0] != 'y') && (buf[0] != 'Y')) {
			tc_log(1, "User cancelled action(s)\n");
			goto out;
		}
	}

	/* erase volume */
	if (opts->secure_erase) {
		tc_log(0, "Securely erasing the volume...\nThis process may take "
		    "some time depending on the size of the volume\n");

		if (opts->state_change_fn)
			opts->state_change_fn(opts->api_ctx, "secure_erase", 1);

		if ((error = secure_erase(opts->dev, blocks * blksz, blksz)) != 0) {
			tc_log(1, "could not securely erase device %s\n", opts->dev);
			goto out;
		}

		if (opts->state_change_fn)
			opts->state_change_fn(opts->api_ctx, "secure_erase", 0);
	}

	tc_log(0, "Creating volume headers...\nDepending on your system, this "
	    "process may take a few minutes as it uses true random data which "
	    "might take a while to refill\n");

	if (opts->weak_keys_and_salt) {
		tc_log(0, "WARNING: Using a weak random generator to get "
		    "entropy for the key material. Odds are this is NOT "
		    "what you want.\n");
	}

	if (opts->state_change_fn)
		opts->state_change_fn(opts->api_ctx, "create_header", 1);

	/* create encrypted headers */
	ehdr = create_hdr((unsigned char *)pass,
	    (opts->nkeyfiles > 0)?MAX_PASSSZ:strlen(pass),
	    opts->prf_algo, opts->cipher_chain, blksz, blocks, VOL_RSVD_BYTES_START/blksz,
	    blocks - (MIN_VOL_BYTES/blksz), 0, opts->weak_keys_and_salt, &ehdr_backup);
	if (ehdr == NULL) {
		tc_log(1, "Could not create header\n");
		goto out;
	}

	if (opts->hidden) {
		hehdr = create_hdr((unsigned char *)h_pass,
		    (opts->n_hkeyfiles > 0)?MAX_PASSSZ:strlen(h_pass), opts->h_prf_algo,
		    opts->h_cipher_chain,
		    blksz, blocks,
		    blocks - (VOL_RSVD_BYTES_END/blksz) - hidden_blocks,
		    hidden_blocks, 1, opts->weak_keys_and_salt, &hehdr_backup);
		if (hehdr == NULL) {
			tc_log(1, "Could not create hidden volume header\n");
			goto out;
		}
	}

	if (opts->state_change_fn)
		opts->state_change_fn(opts->api_ctx, "create_header", 0);

	tc_log(0, "Writing volume headers to disk...\n");

	if ((error = write_to_disk(opts->dev, 0, blksz, ehdr, sizeof(*ehdr))) != 0) {
		tc_log(1, "Could not write volume header to device\n");
		goto out;
	}

	/* Write backup header; it's offset is relative to the end */
	if ((error = write_to_disk(opts->dev, (blocks*blksz - BACKUP_HDR_OFFSET_END),
	    blksz, ehdr_backup, sizeof(*ehdr_backup))) != 0) {
		tc_log(1, "Could not write backup volume header to device\n");
		goto out;
	}

	if (opts->hidden) {
		if ((error = write_to_disk(opts->dev, HDR_OFFSET_HIDDEN, blksz, hehdr,
		    sizeof(*hehdr))) != 0) {
			tc_log(1, "Could not write hidden volume header to "
			    "device\n");
			goto out;
		}

		/* Write backup hidden header; offset is relative to end */
		if ((error = write_to_disk(opts->dev,
		    (blocks*blksz - BACKUP_HDR_HIDDEN_OFFSET_END), blksz,
		    hehdr_backup, sizeof(*hehdr_backup))) != 0) {
			tc_log(1, "Could not write backup hidden volume "
			    "header to device\n");
			goto out;
		}
	}

	/* Everything went ok */
	tc_log(0, "All done!\n");

	ret = 0;

out:
	if (pass)
		free_safe_mem(pass);
	if (h_pass)
		free_safe_mem(h_pass);
	if (pass_again)
		free_safe_mem(pass_again);
	if (ehdr)
		free_safe_mem(ehdr);
	if (hehdr)
		free_safe_mem(hehdr);
	if (ehdr_backup)
		free_safe_mem(ehdr_backup);
	if (hehdr_backup)
		free_safe_mem(hehdr_backup);

	return ret;
}
Ejemplo n.º 4
0
void keystore_secure_free(void *ptr, size_t size) {
    secure_erase(ptr, size);
    free(ptr);
}
Ejemplo n.º 5
0
/*
 * Release resources allocated during verify.
 */
void verify_cleanup(JCR *jcr, int TermCode)
{
   int JobLevel;
   char sdt[50], edt[50];
   char ec1[30], ec2[30];
   char term_code[100], fd_term_msg[100], sd_term_msg[100];
   const char *term_msg;
   int msg_type;
   const char *Name;

// Dmsg1(100, "Enter verify_cleanup() TermCod=%d\n", TermCode);

   JobLevel = jcr->getJobLevel();
   Dmsg3(900, "JobLevel=%c Expected=%u JobFiles=%u\n", JobLevel,
      jcr->ExpectedFiles, jcr->JobFiles);
   if (JobLevel == L_VERIFY_VOLUME_TO_CATALOG &&
       jcr->ExpectedFiles != jcr->JobFiles) {
      TermCode = JS_ErrorTerminated;
   }

   update_job_end(jcr, TermCode);

   if (job_canceled(jcr)) {
      cancel_storage_daemon_job(jcr);
   }

   if (jcr->unlink_bsr && jcr->RestoreBootstrap) {
      secure_erase(jcr, jcr->RestoreBootstrap);
      jcr->unlink_bsr = false;
   }

   msg_type = M_INFO;                 /* By default INFO message */
   switch (TermCode) {
   case JS_Terminated:
      term_msg = _("Verify OK");
      break;
   case JS_FatalError:
   case JS_ErrorTerminated:
      term_msg = _("*** Verify Error ***");
      msg_type = M_ERROR;             /* Generate error message */
      break;
   case JS_Error:
      term_msg = _("Verify warnings");
      break;
   case JS_Canceled:
      term_msg = _("Verify Canceled");
      break;
   case JS_Differences:
      term_msg = _("Verify Differences");
      break;
   default:
      term_msg = term_code;
      bsnprintf(term_code, sizeof(term_code),
                _("Inappropriate term code: %d %c\n"), TermCode, TermCode);
      break;
   }
   bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
   bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
   if (jcr->res.verify_job) {
      Name = jcr->res.verify_job->hdr.name;
   } else {
      Name = "";
   }

   jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
   switch (JobLevel) {
   case L_VERIFY_VOLUME_TO_CATALOG:
      jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
      Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n"
           "  Build OS:               %s %s %s\n"
           "  JobId:                  %d\n"
           "  Job:                    %s\n"
           "  FileSet:                %s\n"
           "  Verify Level:           %s\n"
           "  Client:                 %s\n"
           "  Verify JobId:           %d\n"
           "  Verify Job:             %s\n"
           "  Start time:             %s\n"
           "  End time:               %s\n"
           "  Files Expected:         %s\n"
           "  Files Examined:         %s\n"
           "  Non-fatal FD errors:    %d\n"
           "  FD termination status:  %s\n"
           "  SD termination status:  %s\n"
           "  Termination:            %s\n\n"),
           BAREOS, my_name, VERSION, LSMDATE,
           HOST_OS, DISTNAME, DISTVER,
           jcr->jr.JobId,
           jcr->jr.Job,
           jcr->res.fileset->hdr.name,
           level_to_str(JobLevel),
           jcr->res.client->hdr.name,
           jcr->previous_jr.JobId,
           Name,
           sdt,
           edt,
           edit_uint64_with_commas(jcr->ExpectedFiles, ec1),
           edit_uint64_with_commas(jcr->JobFiles, ec2),
           jcr->JobErrors,
           fd_term_msg,
           sd_term_msg,
           term_msg);
      break;
   default:
      Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n"
           "  Build:                  %s %s %s\n"
           "  JobId:                  %d\n"
           "  Job:                    %s\n"
           "  FileSet:                %s\n"
           "  Verify Level:           %s\n"
           "  Client:                 %s\n"
           "  Verify JobId:           %d\n"
           "  Verify Job:             %s\n"
           "  Start time:             %s\n"
           "  End time:               %s\n"
           "  Files Examined:         %s\n"
           "  Non-fatal FD errors:    %d\n"
           "  FD termination status:  %s\n"
           "  Termination:            %s\n\n"),
           BAREOS, my_name, VERSION, LSMDATE,
           HOST_OS, DISTNAME, DISTVER,
           jcr->jr.JobId,
           jcr->jr.Job,
           jcr->res.fileset->hdr.name,
           level_to_str(JobLevel),
           jcr->res.client->name(),
           jcr->previous_jr.JobId,
           Name,
           sdt,
           edt,
           edit_uint64_with_commas(jcr->JobFiles, ec1),
           jcr->JobErrors,
           fd_term_msg,
           term_msg);
      break;
   }

   Dmsg0(100, "Leave verify_cleanup()\n");
}
Ejemplo n.º 6
0
/*
 * Create the file, or the directory
 *
 * fname is the original filename
 * ofile is the output filename (may be in a different directory)
 *
 * Returns:  CF_SKIP     if file should be skipped
 *           CF_ERROR    on error
 *           CF_EXTRACT  file created and data to restore
 *           CF_CREATED  file created no data to restore
 *
 * Note, we create the file here, except for special files,
 * we do not set the attributes because we want to first
 * write the file, then when the writing is done, set the
 * attributes.
 *
 * So, we return with the file descriptor open for normal files.
 */
int create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
{
   mode_t new_mode, parent_mode;
   int flags;
   uid_t uid;
   gid_t gid;
   int pnl;
   bool exists = false;
   struct stat mstatp;
#ifndef HAVE_WIN32
   bool isOnRoot;
#endif

   bfd->reparse_point = false;
   if (is_win32_stream(attr->data_stream)) {
      set_win32_backup(bfd);
   } else {
      set_portable_backup(bfd);
   }

   new_mode = attr->statp.st_mode;
   Dmsg3(200, "type=%d newmode=%x file=%s\n", attr->type, new_mode, attr->ofname);
   parent_mode = S_IWUSR | S_IXUSR | new_mode;
   gid = attr->statp.st_gid;
   uid = attr->statp.st_uid;

#ifdef HAVE_WIN32
   if (!bfd->use_backup_api) {
      /*
       * Eliminate invalid windows filename characters from foreign filenames
       */
      char *ch = (char *)attr->ofname;
      if (ch[0] != 0 && ch[1] != 0) {
         ch += 2;
         while (*ch) {
            switch (*ch) {
            case ':':
            case '<':
            case '>':
            case '*':
            case '?':
            case '|':
               *ch = '_';
                break;
            }
            ch++;
         }
      }
   }
#endif

   Dmsg2(400, "Replace=%c %d\n", (char)replace, replace);
   if (lstat(attr->ofname, &mstatp) == 0) {
      exists = true;
      switch (replace) {
      case REPLACE_IFNEWER:
         if (attr->statp.st_mtime <= mstatp.st_mtime) {
            Qmsg(jcr, M_INFO, 0, _("File skipped. Not newer: %s\n"), attr->ofname);
            return CF_SKIP;
         }
         break;
      case REPLACE_IFOLDER:
         if (attr->statp.st_mtime >= mstatp.st_mtime) {
            Qmsg(jcr, M_INFO, 0, _("File skipped. Not older: %s\n"), attr->ofname);
            return CF_SKIP;
         }
         break;
      case REPLACE_NEVER:
         /*
          * Set attributes if we created this directory
          */
         if (attr->type == FT_DIREND && path_list_lookup(jcr->path_list, attr->ofname)) {
            break;
         }
         Qmsg(jcr, M_INFO, 0, _("File skipped. Already exists: %s\n"), attr->ofname);
         return CF_SKIP;
      case REPLACE_ALWAYS:
         break;
      }
   }

   switch (attr->type) {
   case FT_RAW:                       /* Raw device to be written */
   case FT_FIFO:                      /* FIFO to be written to */
   case FT_LNKSAVED:                  /* Hard linked, file already saved */
   case FT_LNK:
   case FT_SPEC:                      /* Fifo, ... to be backed up */
   case FT_REGE:                      /* Empty file */
   case FT_REG:                       /* Regular file */
      /*
       * Note, we do not delete FT_RAW because these are device files
       * or FIFOs that should already exist. If we blow it away,
       * we may blow away a FIFO that is being used to read the
       * restore data, or we may blow away a partition definition.
       */
      if (exists && attr->type != FT_RAW && attr->type != FT_FIFO) {
         /* Get rid of old copy */
         Dmsg1(400, "unlink %s\n", attr->ofname);
         if (secure_erase(jcr, attr->ofname) == -1) {
            berrno be;

            Qmsg(jcr, M_ERROR, 0, _("File %s already exists and could not be replaced. ERR=%s.\n"),
                 attr->ofname, be.bstrerror());
            /* Continue despite error */
         }
      }

      /*
       * Here we do some preliminary work for all the above
       *   types to create the path to the file if it does
       *   not already exist.  Below, we will split to
       *   do the file type specific work
       */
      pnl = separate_path_and_file(jcr, attr->fname, attr->ofname);
      if (pnl < 0) {
         return CF_ERROR;
      }

      /*
       * If path length is <= 0 we are making a file in the root
       *  directory. Assume that the directory already exists.
       */
      if (pnl > 0) {
         char savechr;
         savechr = attr->ofname[pnl];
         attr->ofname[pnl] = 0;                 /* terminate path */

         if (!path_already_seen(jcr, attr->ofname, pnl)) {
            Dmsg1(400, "Make path %s\n", attr->ofname);
            /*
             * If we need to make the directory, ensure that it is with
             * execute bit set (i.e. parent_mode), and preserve what already
             * exists. Normally, this should do nothing.
             */
            if (!makepath(attr, attr->ofname, parent_mode, parent_mode, uid, gid, 1)) {
               Dmsg1(10, "Could not make path. %s\n", attr->ofname);
               attr->ofname[pnl] = savechr;     /* restore full name */
               return CF_ERROR;
            }
         }
         attr->ofname[pnl] = savechr;           /* restore full name */
      }

      /*
       * Now we do the specific work for each file type
       */
      switch(attr->type) {
      case FT_REGE:
      case FT_REG:
         Dmsg1(100, "Create=%s\n", attr->ofname);
         flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; /*  O_NOFOLLOW; */
         if (IS_CTG(attr->statp.st_mode)) {
            flags |= O_CTG;              /* set contiguous bit if needed */
         }

         if (is_bopen(bfd)) {
            Qmsg1(jcr, M_ERROR, 0, _("bpkt already open fid=%d\n"), bfd->fid);
            bclose(bfd);
         }

         if (bopen(bfd, attr->ofname, flags, 0, attr->statp.st_rdev) < 0) {
            berrno be;

            be.set_errno(bfd->berrno);
            Qmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"), attr->ofname, be.bstrerror());
            Dmsg2(100,"Could not create %s: ERR=%s\n", attr->ofname, be.bstrerror());

            return CF_ERROR;
         }

         return CF_EXTRACT;

#ifndef HAVE_WIN32 /* None of these exist in MS Windows */
      case FT_RAW:                    /* Bareos raw device e.g. /dev/sda1 */
      case FT_FIFO:                   /* Bareos fifo to save data */
      case FT_SPEC:
         flags = O_WRONLY | O_BINARY;

         isOnRoot = bstrcmp(attr->fname, attr->ofname) ? 1 : 0;
         if (S_ISFIFO(attr->statp.st_mode)) {
            Dmsg1(400, "Restore fifo: %s\n", attr->ofname);
            if (mkfifo(attr->ofname, attr->statp.st_mode) != 0 && errno != EEXIST) {
               berrno be;
               Qmsg2(jcr, M_ERROR, 0, _("Cannot make fifo %s: ERR=%s\n"),
                     attr->ofname, be.bstrerror());
               return CF_ERROR;
            }
         } else if (S_ISSOCK(attr->statp.st_mode)) {
             Dmsg1(200, "Skipping restore of socket: %s\n", attr->ofname);
#ifdef S_IFDOOR /* Solaris high speed RPC mechanism */
         } else if (S_ISDOOR(attr->statp.st_mode)) {
             Dmsg1(200, "Skipping restore of door file: %s\n", attr->ofname);
#endif
#ifdef S_IFPORT /* Solaris event port for handling AIO */
         } else if (S_ISPORT(attr->statp.st_mode)) {
             Dmsg1(200, "Skipping restore of event port file: %s\n", attr->ofname);
#endif
         } else if ((S_ISBLK(attr->statp.st_mode) || S_ISCHR(attr->statp.st_mode)) && !exists && isOnRoot) {
             /*
              * Fatal: Restoring a device on root-file system, but device node does not exist.
              * Should not create a dump file.
              */
             Qmsg1(jcr, M_ERROR, 0, _("Device restore on root failed, device %s missing.\n"), attr->fname);
             return CF_ERROR;
         } else if (S_ISBLK(attr->statp.st_mode) || S_ISCHR(attr->statp.st_mode)) {
             Dmsg1(400, "Restoring a device as a file: %s\n", attr->ofname);
             flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
         } else {
            Dmsg1(400, "Restore node: %s\n", attr->ofname);
            if (mknod(attr->ofname, attr->statp.st_mode, attr->statp.st_rdev) != 0 && errno != EEXIST) {
               berrno be;
               Qmsg2(jcr, M_ERROR, 0, _("Cannot make node %s: ERR=%s\n"),
                     attr->ofname, be.bstrerror());
               return CF_ERROR;
            }
         }

         /*
          * Here we are going to attempt to restore to a FIFO, which
          * means that the FIFO must already exist, AND there must
          * be some process already attempting to read from the
          * FIFO, so we open it write-only.
          */
         if (attr->type == FT_RAW || attr->type == FT_FIFO) {
            btimer_t *tid;
            Dmsg1(400, "FT_RAW|FT_FIFO %s\n", attr->ofname);
            /*
             * Timeout open() in 60 seconds
             */
            if (attr->type == FT_FIFO) {
               Dmsg0(400, "Set FIFO timer\n");
               tid = start_thread_timer(jcr, pthread_self(), 60);
            } else {
               tid = NULL;
            }
            if (is_bopen(bfd)) {
               Qmsg1(jcr, M_ERROR, 0, _("bpkt already open fid=%d\n"), bfd->fid);
            }
            Dmsg2(400, "open %s flags=0x%x\n", attr->ofname, flags);
            if ((bopen(bfd, attr->ofname, flags, 0, 0)) < 0) {
               berrno be;
               be.set_errno(bfd->berrno);
               Qmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"),
                     attr->ofname, be.bstrerror());
               Dmsg2(400, "Could not open %s: ERR=%s\n", attr->ofname, be.bstrerror());
               stop_thread_timer(tid);
               return CF_ERROR;
            }
            stop_thread_timer(tid);
            return CF_EXTRACT;
         }
         Dmsg1(400, "FT_SPEC %s\n", attr->ofname);
         return CF_CREATED;

      case FT_LNKSAVED:                  /* Hard linked, file already saved */
         Dmsg2(130, "Hard link %s => %s\n", attr->ofname, attr->olname);
         if (link(attr->olname, attr->ofname) != 0) {
            berrno be;
#ifdef HAVE_CHFLAGS
            struct stat s;

            /*
             * If using BSD user flags, maybe has a file flag preventing this.
             * So attempt to disable, retry link, and reset flags.
             * Note that BSD securelevel may prevent disabling flag.
             */
            if (stat(attr->olname, &s) == 0 && s.st_flags != 0) {
               if (chflags(attr->olname, 0) == 0) {
                  if (link(attr->olname, attr->ofname) != 0) {
                     /*
                      * Restore original file flags even when linking failed
                      */
                     if (chflags(attr->olname, s.st_flags) < 0) {
                        Qmsg2(jcr, M_ERROR, 0, _("Could not restore file flags for file %s: ERR=%s\n"),
                              attr->olname, be.bstrerror());
                     }
#endif /* HAVE_CHFLAGS */
            Qmsg3(jcr, M_ERROR, 0, _("Could not hard link %s -> %s: ERR=%s\n"),
                  attr->ofname, attr->olname, be.bstrerror());
            Dmsg3(200, "Could not hard link %s -> %s: ERR=%s\n",
                  attr->ofname, attr->olname, be.bstrerror());
            return CF_ERROR;
#ifdef HAVE_CHFLAGS
                  }
                  /*
                   * Finally restore original file flags
                   */
                  if (chflags(attr->olname, s.st_flags) < 0) {
                     Qmsg2(jcr, M_ERROR, 0, _("Could not restore file flags for file %s: ERR=%s\n"),
                            attr->olname, be.bstrerror());
                  }
               } else {
                 Qmsg2(jcr, M_ERROR, 0, _("Could not reset file flags for file %s: ERR=%s\n"),
                       attr->olname, be.bstrerror());
               }
            } else {
              Qmsg3(jcr, M_ERROR, 0, _("Could not hard link %s -> %s: ERR=%s\n"),
                    attr->ofname, attr->olname, be.bstrerror());
              return CF_ERROR;
            }
#endif /* HAVE_CHFLAGS */

         }
         return CF_CREATED;

#endif /* HAVE_WIN32 */
#ifdef HAVE_WIN32
      case FT_LNK:
         /*
          * Handle Windows Symlink-Like Reparse Points
          * - Directory Symlinks
          * - File Symlinks
          * - Volume Mount Points
          * - Junctions
          */
         Dmsg2(130, "FT_LNK should restore: %s -> %s\n", attr->ofname, attr->olname);
         if (attr->statp.st_rdev & FILE_ATTRIBUTE_VOLUME_MOUNT_POINT) {
            /*
             * We do not restore volume mount points
             */
            Dmsg0(130, "Skipping Volume Mount Point\n");
            return CF_SKIP;
         }
         if (win32_symlink(attr->olname, attr->ofname, attr->statp.st_rdev) != 0 && errno != EEXIST) {
            berrno be;
            Qmsg3(jcr, M_ERROR, 0, _("Could not symlink %s -> %s: ERR=%s\n"),
                  attr->ofname, attr->olname, be.bstrerror());
            return CF_ERROR;
         }
         return CF_CREATED;
#else
      case FT_LNK:
         /*
          * Unix/Linux symlink handling
          */
         Dmsg2(130, "FT_LNK should restore: %s -> %s\n", attr->ofname, attr->olname);
         if (symlink(attr->olname, attr->ofname) != 0 && errno != EEXIST) {
            berrno be;
            Qmsg3(jcr, M_ERROR, 0, _("Could not symlink %s -> %s: ERR=%s\n"),
                  attr->ofname, attr->olname, be.bstrerror());
            return CF_ERROR;
         }
         return CF_CREATED;
#endif
      } /* End inner switch */

   case FT_REPARSE:
   case FT_JUNCTION:
      bfd->reparse_point = true;
      /*
       * Fall through wanted
       */
   case FT_DIRBEGIN:
   case FT_DIREND:
      Dmsg2(200, "Make dir mode=%o dir=%s\n", new_mode, attr->ofname);
      if (!makepath(attr, attr->ofname, new_mode, parent_mode, uid, gid, 0)) {
         return CF_ERROR;
      }
      /*
       * If we are using the Win32 Backup API, we open the directory so
       * that the security info will be read and saved.
       */
      if (!is_portable_backup(bfd)) {
         if (is_bopen(bfd)) {
            Qmsg1(jcr, M_ERROR, 0, _("bpkt already open fid=%d\n"), bfd->fid);
         }
         if (bopen(bfd, attr->ofname, O_WRONLY | O_BINARY, 0, attr->statp.st_rdev) < 0) {
            berrno be;
            be.set_errno(bfd->berrno);
#ifdef HAVE_WIN32
            /*
             * Check for trying to create a drive, if so, skip
             */
            if (attr->ofname[1] == ':' &&
                IsPathSeparator(attr->ofname[2]) &&
                attr->ofname[3] == '\0') {
               return CF_SKIP;
            }
#endif
            Qmsg2(jcr, M_ERROR, 0, _("Could not open %s: ERR=%s\n"),
                  attr->ofname, be.bstrerror());
            return CF_ERROR;
         }
         return CF_EXTRACT;
      } else {
         return CF_CREATED;
      }

   case FT_DELETED:
      Qmsg2(jcr, M_INFO, 0, _("Original file %s have been deleted: type=%d\n"), attr->fname, attr->type);
      break;
   /*
    * The following should not occur
    */
   case FT_NOACCESS:
   case FT_NOFOLLOW:
   case FT_NOSTAT:
   case FT_DIRNOCHG:
   case FT_NOCHG:
   case FT_ISARCH:
   case FT_NORECURSE:
   case FT_NOFSCHG:
   case FT_NOOPEN:
      Qmsg2(jcr, M_ERROR, 0, _("Original file %s not saved: type=%d\n"), attr->fname, attr->type);
      break;
   default:
      Qmsg2(jcr, M_ERROR, 0, _("Unknown file type %d; not restored: %s\n"), attr->type, attr->fname);
      break;
   }
   return CF_ERROR;
}
Ejemplo n.º 7
0
/*
 * Remove old .spool files written by me from the working directory.
 */
static void cleanup_old_files()
{
   DIR* dp;
   struct dirent *entry, *result;
   int rc, name_max;
   int my_name_len = strlen(my_name);
   int len = strlen(me->working_directory);
   POOLMEM *cleanup = get_pool_memory(PM_MESSAGE);
   POOLMEM *basename = get_pool_memory(PM_MESSAGE);
   regex_t preg1;
   char prbuf[500];
   berrno be;

   /* Look for .spool files but don't allow spaces */
   const char *pat1 = "^[^ ]+\\.spool$";

   /* Setup working directory prefix */
   pm_strcpy(basename, me->working_directory);
   if (len > 0 && !IsPathSeparator(me->working_directory[len-1])) {
      pm_strcat(basename, "/");
   }

   /* Compile regex expressions */
   rc = regcomp(&preg1, pat1, REG_EXTENDED);
   if (rc != 0) {
      regerror(rc, &preg1, prbuf, sizeof(prbuf));
      Pmsg2(000,  _("Could not compile regex pattern \"%s\" ERR=%s\n"),
           pat1, prbuf);
      goto get_out2;
   }

   name_max = pathconf(".", _PC_NAME_MAX);
   if (name_max < 1024) {
      name_max = 1024;
   }

   if (!(dp = opendir(me->working_directory))) {
      berrno be;
      Pmsg2(000, "Failed to open working dir %s for cleanup: ERR=%s\n",
            me->working_directory, be.bstrerror());
      goto get_out1;
   }

   entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
   while (1) {
      if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
         break;
      }
      /* Exclude any name with ., .., not my_name or containing a space */
      if (strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0 ||
          strncmp(result->d_name, my_name, my_name_len) != 0) {
         Dmsg1(500, "Skipped: %s\n", result->d_name);
         continue;
      }

      /* Unlink files that match regex */
      if (regexec(&preg1, result->d_name, 0, NULL, 0) == 0) {
         pm_strcpy(cleanup, basename);
         pm_strcat(cleanup, result->d_name);
         Dmsg1(500, "Unlink: %s\n", cleanup);
         secure_erase(NULL, cleanup);
      }
   }
   free(entry);
   closedir(dp);

get_out1:
   regfree(&preg1);
get_out2:
   free_pool_memory(cleanup);
   free_pool_memory(basename);
}