Change command line option processing (#82)

* Changes command line option processing:
  - Use getopt_long in libc and support long options
  - GNU style option processing (don't try to enforce non-conflicting options)
  - GNU style usage message
  - Separate encrypt and decrypt settings
  - --unprotect -> --allow-raw-read, --protect -> --no-allow-raw-read for clarification
  - Change reading key file from stdin using --key-file=-
  - Always print detailed status, remove summary "Drive Encryption" line

* Other formatting and style cleanup

* Test output changes
This commit is contained in:
James Wilson
2022-05-31 15:05:46 -07:00
committed by GitHub
parent 1200fe92ee
commit 23f8d829bf
5 changed files with 406 additions and 415 deletions

View File

@@ -26,6 +26,7 @@ GNU General Public License for more details.
#include <string> #include <string>
#include <vector> #include <vector>
#include <getopt.h>
#include <sys/mtio.h> #include <sys/mtio.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <syslog.h> #include <syslog.h>
@@ -43,6 +44,8 @@ GNU General Public License for more details.
#include "scsiencrypt.h" #include "scsiencrypt.h"
using namespace std::literals::string_literals;
static std::optional<std::vector<std::uint8_t>> static std::optional<std::vector<std::uint8_t>>
key_from_hex_chars(const std::string& s) key_from_hex_chars(const std::string& s)
{ {
@@ -72,21 +75,43 @@ key_from_hex_chars(const std::string& s)
} }
// shows the command usage // shows the command usage
static void showUsage() static void print_usage(std::ostream& os)
{ {
std::cerr << "Usage: stenc --version | " os << "\
"-f <device> [--detail] [-e <on/mixed/rawread/off> [-k <file>] " Usage: stenc [OPTION...]\n\
"[-kd <description>] [-a <index>] [--protect | --unprotect] " \n\
"[--ckod] ]\n\n" Mandatory arguments to long options are mandatory for short options too.\n\
"Type 'man stenc' for more information.\n"; -f, --file=DEVICE use DEVICE as the tape drive to operate on\n\
} -e, --encrypt=ENC-MODE set encryption mode to ENC-MODE\n\
-d, --decrypt=DEC-MODE set decryption mode to DEC-MODE\n\
// exits to shell with an error message -k, --key-file=FILE read encryption key and key descriptor from FILE,\n\
static void errorOut(const std::string& message) or standard input when FILE is -\n\
{ -a, --algorithm=INDEX use encryption algorithm INDEX\n\
std::cerr << "Error: " << message << "\n"; --allow-raw-read mark written blocks to allow raw reads of\n\
showUsage(); encrypted data\n\
exit(EXIT_FAILURE); --no-allow-raw-read mark written blocks to disallow raw reads of\n\
encrypted data\n\
--ckod clear key on demount of tape media\n\
-h, --help print this usage statement and exit\n\
--version print version information and exit\n\
\n\
ENC-MODE is one of the following:\n\
off Data written to DEVICE will not be encrypted\n\
on Data written to DEVICE will be encrypted\n\
\n\
DEC-MODE is one of the following:\n\
off Data read from DEVICE will not be decrypted and only unencrypted\n\
records can be read.\n\
on Data read from DEVICE will be decrypted and only encrypted records\n\
can be read.\n\
mixed Data read from DEVICE will be decrypted, if needed. Both encrypted\n\
and unencrypted records can be read.\n\
\n\
INDEX is a number that selects the encryption algorithm and mode to use.\n\
\n\
When neither options to set encryption or decryption mode are given, print\n\
encryption status and capabilities of DEVICE, including a list of supported\n\
algorithm indexes.\n";
} }
static void print_algorithm_name(std::ostream& os, const uint32_t code) static void print_algorithm_name(std::ostream& os, const uint32_t code)
@@ -123,7 +148,8 @@ static void print_algorithms(std::ostream& os, const scsi::page_dec& page)
for (auto ad_ptr: algorithms) { for (auto ad_ptr: algorithms) {
auto& ad {*ad_ptr}; auto& ad {*ad_ptr};
os << std::left << std::setw(5) << (unsigned int) {ad.algorithm_index}; os << std::left << std::setw(5)
<< static_cast<unsigned int>(ad.algorithm_index);
print_algorithm_name(os, ntohl(ad.security_algorithm_code)); print_algorithm_name(os, ntohl(ad.security_algorithm_code));
os.put('\n'); os.put('\n');
@@ -194,39 +220,8 @@ static void inquiryDrive(const std::string& tapeDevice)
print_device_inquiry(std::cout, iresult); print_device_inquiry(std::cout, iresult);
} }
static void print_device_status(std::ostream& os, const scsi::page_des& opt, static void print_device_status(std::ostream& os, const scsi::page_des& opt)
bool detail)
{ {
std::string emode = "unknown";
os << std::left << std::setw(25) << "Drive Encryption:";
if (opt.encryption_mode == scsi::encrypt_mode::on && // encrypt
opt.decryption_mode == scsi::decrypt_mode::on // read only encrypted data
) {
emode = "on";
}
if (opt.encryption_mode == scsi::encrypt_mode::on && // encrypt
opt.decryption_mode ==
scsi::decrypt_mode::mixed // read encrypted and unencrypted
) {
emode = "mixed";
}
if (opt.encryption_mode == scsi::encrypt_mode::on && // encrypt
opt.decryption_mode ==
scsi::decrypt_mode::raw // read encrypted and unencrypted
) {
emode = "rawread";
}
if (opt.encryption_mode == scsi::encrypt_mode::off && // encrypt
opt.decryption_mode ==
scsi::decrypt_mode::off // read encrypted and unencrypted
) {
emode = "off";
}
os << emode << "\n";
if (detail) {
os << std::left << std::setw(25) << "Drive Output:"; os << std::left << std::setw(25) << "Drive Output:";
switch (opt.decryption_mode) { switch (opt.decryption_mode) {
case scsi::decrypt_mode::off: case scsi::decrypt_mode::off:
@@ -274,11 +269,10 @@ static void print_device_status(std::ostream& os, const scsi::page_des& opt,
} }
os << std::setw(25) << "Key Instance Counter:" << std::dec os << std::setw(25) << "Key Instance Counter:" << std::dec
<< ntohl(opt.key_instance_counter) << "\n"; << ntohl(opt.key_instance_counter) << '\n';
if (opt.algorithm_index != 0) { if (opt.algorithm_index != 0) {
os << std::setw(25) << "Encryption Algorithm:" << std::dec os << std::setw(25) << "Encryption Algorithm:" << std::dec
<< static_cast<unsigned int>(opt.algorithm_index) << "\n"; << static_cast<unsigned int>(opt.algorithm_index) << '\n';
}
} }
auto kads {scsi::read_page_kads(opt)}; auto kads {scsi::read_page_kads(opt)};
for (auto kd: kads) { for (auto kd: kads) {
@@ -299,25 +293,24 @@ static void print_device_status(std::ostream& os, const scsi::page_des& opt,
} }
} }
static void showDriveStatus(const std::string& tapeDrive, bool detail) static void showDriveStatus(const std::string& tapeDrive)
{ {
alignas(4) scsi::page_buffer buffer; alignas(4) scsi::page_buffer buffer;
scsi::get_des(tapeDrive, buffer, sizeof(buffer)); scsi::get_des(tapeDrive, buffer, sizeof(buffer));
auto& opt {reinterpret_cast<const scsi::page_des&>(buffer)}; auto& opt {reinterpret_cast<const scsi::page_des&>(buffer)};
print_device_status(std::cout, opt, detail); print_device_status(std::cout, opt);
} }
static void print_volume_status(std::ostream& os, const scsi::page_nbes& opt) static void print_volume_status(std::ostream& os, const scsi::page_nbes& opt)
{ {
auto compression_status {static_cast<std::uint8_t>( auto compression_status {static_cast<std::uint8_t>(
(opt.status & scsi::page_nbes::status_compression_mask) >> opt.status & scsi::page_nbes::status_compression_mask)};
scsi::page_nbes::status_compression_pos)};
// From vendor docs, no known drives actually report anything other than 0 // From vendor docs, no known drives actually report anything other than 0
if (compression_status != 0u) { if (compression_status != 0u) {
os << std::left << std::setw(25) << "Volume Compressed:"; os << std::left << std::setw(25) << "Volume Compressed:";
switch (compression_status) { switch (compression_status) {
case 0u: case 0u << scsi::page_nbes::status_compression_pos:
os << "Drive cannot determine\n"; os << "Drive cannot determine\n";
break; break;
default: default:
@@ -328,28 +321,27 @@ static void print_volume_status(std::ostream& os, const scsi::page_nbes& opt)
} }
os << std::left << std::setw(25) << "Volume Encryption:"; os << std::left << std::setw(25) << "Volume Encryption:";
auto encryption_status {static_cast<std::uint8_t>( auto encryption_status {static_cast<std::uint8_t>(
(opt.status & scsi::page_nbes::status_encryption_mask) >> opt.status & scsi::page_nbes::status_encryption_mask)};
scsi::page_nbes::status_encryption_pos)};
auto kads {read_page_kads(opt)}; auto kads {read_page_kads(opt)};
switch (encryption_status) { switch (encryption_status) {
case 0u: case 0u << scsi::page_nbes::status_encryption_pos:
case 1u: case 1u << scsi::page_nbes::status_encryption_pos:
os << "Unable to determine\n"; os << "Unable to determine\n";
break; break;
case 2u: case 2u << scsi::page_nbes::status_encryption_pos:
os << "Tape position not at a logical block\n"; os << "Tape position not at a logical block\n";
break; break;
case 3u: case 3u << scsi::page_nbes::status_encryption_pos:
os << "Not encrypted\n"; os << "Not encrypted\n";
break; break;
case 5u: case 5u << scsi::page_nbes::status_encryption_pos:
os << "Encrypted and able to decrypt\n"; os << "Encrypted and able to decrypt\n";
if ((opt.flags & scsi::page_nbes::flags_rdmds_mask) == if ((opt.flags & scsi::page_nbes::flags_rdmds_mask) ==
scsi::page_nbes::flags_rdmds_mask) { scsi::page_nbes::flags_rdmds_mask) {
os << std::left << std::setw(25) << " Protected from raw read\n"; os << std::left << std::setw(25) << " Protected from raw read\n";
} }
break; break;
case 6u: case 6u << scsi::page_nbes::status_encryption_pos:
os << "Encrypted, but unable to decrypt due to invalid key.\n"; os << "Encrypted, but unable to decrypt due to invalid key.\n";
for (auto kd: kads) { for (auto kd: kads) {
switch (kd->type) { switch (kd->type) {
@@ -380,7 +372,7 @@ static void print_volume_status(std::ostream& os, const scsi::page_nbes& opt)
if (opt.algorithm_index != 0) { if (opt.algorithm_index != 0) {
os << std::left << std::setw(25) os << std::left << std::setw(25)
<< "Volume Algorithm:" << static_cast<unsigned int>(opt.algorithm_index) << "Volume Algorithm:" << static_cast<unsigned int>(opt.algorithm_index)
<< "\n"; << '\n';
} }
} }
@@ -403,104 +395,104 @@ static void echo(bool on)
} }
#if !defined(CATCH_CONFIG_MAIN) #if !defined(CATCH_CONFIG_MAIN)
int main(int argc, const char **argv) int main(int argc, char **argv)
{ {
std::string tapeDrive; std::string tapeDrive;
int action = 0; // 0 = status, 1 =setting param, 2 = generating key std::string keyFile;
std::string keyFile, keyDesc;
bool detail = false;
scsi::encrypt_mode enc_mode; std::optional<scsi::encrypt_mode> enc_mode;
scsi::decrypt_mode dec_mode; std::optional<scsi::decrypt_mode> dec_mode;
std::uint8_t algorithm_index; std::uint8_t algorithm_index;
std::vector<uint8_t> key; std::vector<uint8_t> key;
std::string key_name; std::string key_name;
scsi::sde_rdmc rdmc {}; scsi::sde_rdmc rdmc {};
bool ckod {}; bool ckod {};
// First load all of the options enum opt_key : int {
for (int i = 1; i < argc; i++) { opt_version = 256,
std::string thisCmd = argv[i]; opt_ckod,
std::string nextCmd = ""; opt_rdmc_enable,
if (i + 1 < argc) { opt_rdmc_disable,
if (strncmp(argv[i + 1], "-", 1) != 0) };
nextCmd = argv[i + 1];
} const struct option long_options[] = {
if (thisCmd == "--version") { {"algorithm", required_argument, nullptr, 'a'},
std::cout << "stenc v" << VERSION << " - SCSI Tape Encryption Manager\n"; {"decrypt", required_argument, nullptr, 'd'},
std::cout << "https://github.com/scsitape/stenc \n"; {"encrypt", required_argument, nullptr, 'e'},
exit(EXIT_SUCCESS); {"file", required_argument, nullptr, 'f'},
} {"key-file", required_argument, nullptr, 'k'},
if (thisCmd == "-e") { {"help", no_argument, nullptr, 'h'},
if (nextCmd == "") { {"ckod", no_argument, nullptr, opt_ckod},
errorOut("Key file not specified after -k option"); {"allow-raw-read", no_argument, nullptr, opt_rdmc_enable},
} {"no-allow-raw-read", no_argument, nullptr, opt_rdmc_disable},
if (nextCmd == "on") { {"version", no_argument, nullptr, opt_version},
// encrypt, read only encrypted data {nullptr, 0, nullptr, 0},
enc_mode = scsi::encrypt_mode::on; };
int opt_char;
while ((opt_char = getopt_long(argc, argv, "+a:d:e:f:k:h", long_options,
nullptr)) != -1) {
switch (opt_char) {
case 'a':
algorithm_index = std::atoi(optarg);
break;
case 'd': {
std::string arg {optarg};
if (arg == "on"s) {
dec_mode = scsi::decrypt_mode::on; dec_mode = scsi::decrypt_mode::on;
} else if (nextCmd == "mixed") { } else if (arg == "off"s) {
// encrypt, read encrypted and unencrypted data
enc_mode = scsi::encrypt_mode::on;
dec_mode = scsi::decrypt_mode::mixed;
} else if (nextCmd == "rawread") {
// encrypt, read encrypted and unencrypted data
enc_mode = scsi::encrypt_mode::on;
dec_mode = scsi::decrypt_mode::raw;
} else if (nextCmd == "off") {
// encrypt, read encrypted and unencrypted data
enc_mode = scsi::encrypt_mode::off;
dec_mode = scsi::decrypt_mode::off; dec_mode = scsi::decrypt_mode::off;
} else if (arg == "mixed"s) {
dec_mode = scsi::decrypt_mode::mixed;
} else { } else {
errorOut("Unknown encryption mode '" + nextCmd + print_usage(std::cerr);
"'"); // encrypt, read encrypted and unencrypted data exit(EXIT_FAILURE);
} }
i++; // skip the next argument break;
action = 1;
} else if (thisCmd == "-f") {
if (nextCmd == "")
errorOut("Device not specified after -f option.");
tapeDrive = nextCmd; // set the tape drive
i++; // skip the next argument
} else if (thisCmd == "-k") {
if (nextCmd == "")
errorOut("Key file not specified after -k option");
keyFile = nextCmd; // set the key file
i++; // skip the next argument
} else if (thisCmd == "-kd") {
if (nextCmd == "")
errorOut("Key description not specified after the -kd option");
keyDesc = nextCmd; // set the key file
if (keyDesc.size() > SSP_UKAD_LENGTH) {
errorOut("Key description too long!");
} }
i++; // skip the next argument case 'e': {
} else if (thisCmd == "--protect") { std::string arg {optarg};
if (rdmc == scsi::sde_rdmc::enabled) { if (arg == "on"s) {
errorOut("'--protect' cannot be specified at the same time as " enc_mode = scsi::encrypt_mode::on;
"'--unprotect'"); } else if (arg == "off"s) {
enc_mode = scsi::encrypt_mode::off;
} else {
print_usage(std::cerr);
exit(EXIT_FAILURE);
} }
rdmc = scsi::sde_rdmc::disabled; break;
} else if (thisCmd == "--unprotect") {
if (rdmc == scsi::sde_rdmc::disabled) {
errorOut("'--unprotect' cannot be specified at the same time as "
"'--protect'");
} }
rdmc = scsi::sde_rdmc::enabled; case 'f':
} else if (thisCmd == "--ckod") { tapeDrive = optarg;
break;
case 'k':
keyFile = optarg;
break;
case opt_ckod:
ckod = true; ckod = true;
} else if (thisCmd == "--detail") { break;
detail = true; case opt_rdmc_enable:
} else if (thisCmd == "-a") { rdmc = scsi::sde_rdmc::enabled;
if (nextCmd == "") break;
errorOut("You must specify a numeric algorithm index when using the -a " case opt_rdmc_disable:
"flag"); rdmc = scsi::sde_rdmc::disabled;
algorithm_index = std::atoi(nextCmd.c_str()); break;
i++; // skip the next argument case static_cast<int>('h'):
} else { print_usage(std::cout);
errorOut("Unknown command '" + thisCmd + "'"); exit(EXIT_SUCCESS);
case opt_version:
std::cout << "stenc " VERSION " - SCSI Tape Encryption Manager\n"
<< "https://github.com/scsitape/stenc\n";
exit(EXIT_SUCCESS);
default:
print_usage(std::cerr);
exit(EXIT_FAILURE);
} }
} }
if (optind != argc) { // left-over unparsed arguments or options
print_usage(std::cerr);
exit(EXIT_FAILURE);
}
// select device from env variable or system default if not given with -f // select device from env variable or system default if not given with -f
if (tapeDrive.empty()) { if (tapeDrive.empty()) {
@@ -511,23 +503,17 @@ int main(int argc, const char **argv)
tapeDrive = DEFTAPE; tapeDrive = DEFTAPE;
} }
} }
if (dec_mode == scsi::decrypt_mode::raw && rdmc == scsi::sde_rdmc::disabled) {
errorOut(
"'--protect' is not valid when setting encryption mode to 'rawread'");
}
openlog("stenc", LOG_CONS, LOG_USER); openlog("stenc", LOG_CONS, LOG_USER);
if (action == 0) { if (!enc_mode && !dec_mode) {
std::cout << "Status for " << tapeDrive << "\n" std::cout << "Status for " << tapeDrive << '\n'
<< "--------------------------------------------------\n"; << "--------------------------------------------------\n";
try { try {
if (detail) {
inquiryDrive(tapeDrive); inquiryDrive(tapeDrive);
} showDriveStatus(tapeDrive);
showDriveStatus(tapeDrive, detail); if (scsi::is_device_ready(tapeDrive)) {
if (detail && scsi::is_device_ready(tapeDrive)) {
try { try {
showVolumeStatus(tapeDrive); showVolumeStatus(tapeDrive);
} catch (const scsi::scsi_error& err) { } catch (const scsi::scsi_error& err) {
@@ -540,98 +526,106 @@ int main(int argc, const char **argv)
} }
} }
} }
if (detail) {
alignas(4) scsi::page_buffer buffer {}; alignas(4) scsi::page_buffer buffer {};
scsi::get_dec(tapeDrive, buffer, sizeof(buffer)); scsi::get_dec(tapeDrive, buffer, sizeof(buffer));
auto& page {reinterpret_cast<const scsi::page_dec&>(buffer)}; auto& page {reinterpret_cast<const scsi::page_dec&>(buffer)};
print_algorithms(std::cout, page); print_algorithms(std::cout, page);
}
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} catch (const scsi::scsi_error& err) { } catch (const scsi::scsi_error& err) {
std::cerr << "stenc: " << err.what() << '\n';
scsi::print_sense_data(std::cerr, err.get_sense()); scsi::print_sense_data(std::cerr, err.get_sense());
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} catch (const std::runtime_error& err) { } catch (const std::runtime_error& err) {
std::cerr << err.what() << '\n'; std::cerr << "stenc: " << err.what() << '\n';
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
if (enc_mode == scsi::encrypt_mode::on) { // Infer encrypt/decrypt mode when only one is specified
if (keyFile.empty()) { if (enc_mode && !dec_mode) {
std::string p1; if (enc_mode == scsi::encrypt_mode::off) {
std::string p2; dec_mode = scsi::decrypt_mode::off;
bool done = false; std::cerr << "Decrypt mode not specified, using decrypt = off\n";
while (!done) { } else if (enc_mode == scsi::encrypt_mode::on) {
std::cout << "Enter key in hex format: "; dec_mode = scsi::decrypt_mode::on;
echo(false); std::cerr << "Decrypt mode not specified, using decrypt = on\n";
getline(std::cin, p1);
echo(true);
std::cout << "\nRe-enter key in hex format: ";
echo(false);
getline(std::cin, p2);
echo(true);
std::cout << "\n";
if (p1 != p2) {
std::cout << "Keys do not match!\n";
} else if (p1.empty()) {
std::cout << "Key cannot be empty!\n";
} else { } else {
if (auto key_bytes = key_from_hex_chars(p1)) { std::cerr << "stenc: Unexpected encrypt mode "
std::cout << "Set encryption using this key? [y/n]: "; << static_cast<unsigned int>(*enc_mode) << '\n';
std::string ans = ""; exit(EXIT_FAILURE);
getline(std::cin, ans);
if (ans == "y") {
key = *key_bytes;
done = true;
} }
} else if (!enc_mode && dec_mode) {
if (dec_mode == scsi::decrypt_mode::off) {
enc_mode = scsi::encrypt_mode::off;
std::cerr << "Encrypt mode not specified, using encrypt = off\n";
} else if (dec_mode == scsi::decrypt_mode::on ||
dec_mode == scsi::decrypt_mode::mixed) {
enc_mode = scsi::encrypt_mode::on;
std::cerr << "Encrypt mode not specified, using encrypt = on\n";
} else { } else {
std::cout << "Invalid key!\n"; std::cerr << "stenc: Unexpected decrypt mode "
} << static_cast<unsigned int>(*dec_mode) << '\n';
} exit(EXIT_FAILURE);
}
key_name = keyDesc;
} else {
// set keyInput here
std::string keyInput;
std::ifstream myfile(keyFile.c_str());
if (myfile.is_open()) {
getline(myfile, keyInput);
getline(myfile, keyDesc);
myfile.close();
if (auto key_bytes = key_from_hex_chars(keyInput)) {
key = *key_bytes;
} else {
errorOut("Invalid key found in '" + keyFile + "'");
}
key_name = keyDesc;
} else
errorOut("Could not open '" + keyFile + "' for reading");
} }
} }
if (enc_mode != scsi::encrypt_mode::off ||
dec_mode != scsi::decrypt_mode::off) {
if (keyFile.empty()) {
std::cerr << "stenc: Encryption key required but no key file specified\n";
exit(EXIT_FAILURE);
}
// set keyInput here
std::string keyInput;
if (keyFile == "-"s) { // Read key file from standard input
if (isatty(STDIN_FILENO)) {
std::cout << "Enter key (input will be hidden): ";
echo(false);
}
std::getline(std::cin, keyInput);
if (isatty(STDIN_FILENO)) {
std::cout << "\nEnter key descriptor (optional): ";
echo(true);
}
std::getline(std::cin, key_name);
} else {
std::ifstream myfile {keyFile};
if (!myfile.is_open()) {
std::cerr << "stenc: Cannot open " << keyFile << ": " << strerror(errno)
<< '\n';
exit(EXIT_FAILURE);
}
std::getline(myfile, keyInput);
std::getline(myfile, key_name);
}
if (auto key_bytes = key_from_hex_chars(keyInput)) {
key = *key_bytes;
} else {
std::cerr << "stenc: Invalid key in key file\n";
exit(EXIT_FAILURE);
}
}
if (enc_mode != scsi::encrypt_mode::on) {
key_name.erase(); // key descriptor only valid when key is used for writing
}
// Write the options to the tape device // Write the options to the tape device
std::cout << "Turning " std::cerr << "Changing encryption settings on device " << tapeDrive << '\n';
<< (enc_mode != scsi::encrypt_mode::off ? "on" : "off")
<< " encryption on device '" << tapeDrive << "'..." << std::endl;
try { try {
auto sde_buffer {scsi::make_sde(enc_mode, dec_mode, algorithm_index, key, auto sde_buffer {scsi::make_sde(enc_mode.value(), dec_mode.value(),
key_name, rdmc, ckod)}; algorithm_index, key, key_name, rdmc,
ckod)};
scsi::write_sde(tapeDrive, sde_buffer.get()); scsi::write_sde(tapeDrive, sde_buffer.get());
alignas(4) scsi::page_buffer buffer {}; alignas(4) scsi::page_buffer buffer {};
scsi::get_des(tapeDrive, buffer, sizeof(buffer)); scsi::get_des(tapeDrive, buffer, sizeof(buffer));
auto& opt {reinterpret_cast<const scsi::page_des&>(buffer)}; auto& opt {reinterpret_cast<const scsi::page_des&>(buffer)};
if (enc_mode != scsi::encrypt_mode::off &&
opt.encryption_mode == scsi::encrypt_mode::off) {
errorOut("Turning encryption on for '" + tapeDrive + "' failed!");
}
if (enc_mode == scsi::encrypt_mode::off &&
opt.encryption_mode != scsi::encrypt_mode::off) {
errorOut("Turning encryption off for '" + tapeDrive + "' failed!");
}
if (enc_mode != scsi::encrypt_mode::off) { if (enc_mode != scsi::encrypt_mode::off) {
std::stringstream msg; std::stringstream msg;
msg << "Encryption turned on for device '" << tapeDrive << "'. "; msg << "Encryption turned on for device '" << tapeDrive << "'. ";
@@ -639,7 +633,7 @@ int main(int argc, const char **argv)
msg << "Key Descriptor: '" << key_name << "'"; msg << "Key Descriptor: '" << key_name << "'";
} }
msg << " Key Instance: " << std::dec << ntohl(opt.key_instance_counter) msg << " Key Instance: " << std::dec << ntohl(opt.key_instance_counter)
<< std::endl; << '\n';
syslog(LOG_NOTICE, "%s", msg.str().c_str()); syslog(LOG_NOTICE, "%s", msg.str().c_str());
} else { } else {
@@ -647,22 +641,18 @@ int main(int argc, const char **argv)
msg << "Encryption turned off for device '" << tapeDrive << "'."; msg << "Encryption turned off for device '" << tapeDrive << "'.";
msg << " Key Instance: " << std::dec << ntohl(opt.key_instance_counter) msg << " Key Instance: " << std::dec << ntohl(opt.key_instance_counter)
<< std::endl; << '\n';
syslog(LOG_NOTICE, "%s", msg.str().c_str()); syslog(LOG_NOTICE, "%s", msg.str().c_str());
} }
std::cout << "Success! See system logs for a key change audit log.\n"; std::cerr << "Success! See system logs for a key change audit log.\n";
exit(EXIT_SUCCESS);
} catch (const scsi::scsi_error& err) { } catch (const scsi::scsi_error& err) {
std::cerr << "stenc: " << err.what() << '\n';
scsi::print_sense_data(std::cerr, err.get_sense()); scsi::print_sense_data(std::cerr, err.get_sense());
exit(EXIT_FAILURE);
} catch (const std::runtime_error& err) { } catch (const std::runtime_error& err) {
std::cerr << err.what() << '\n'; std::cerr << "stenc: " << err.what() << '\n';
} exit(EXIT_FAILURE);
if (enc_mode != scsi::encrypt_mode::off) {
errorOut("Turning encryption on for '" + tapeDrive + "' failed!");
} else {
errorOut("Turning encryption off for '" + tapeDrive + "' failed!");
} }
} }
#endif // defined(CATCH_CONFIG_MAIN) #endif // defined(CATCH_CONFIG_MAIN)

View File

@@ -303,6 +303,9 @@ void print_sense_data(std::ostream& os, const sense_data& sd)
case sense_data::no_sense: case sense_data::no_sense:
os << "No specific error"; os << "No specific error";
break; break;
case sense_data::recovered_error:
os << "Recovered error";
break;
case sense_data::not_ready: case sense_data::not_ready:
os << "Device not ready"; os << "Device not ready";
break; break;
@@ -329,10 +332,10 @@ void print_sense_data(std::ostream& os, const sense_data& sd)
os << " (0x" << HEX(sense_key) << ")\n"; os << " (0x" << HEX(sense_key) << ")\n";
os << std::left << std::setw(25) << " ASC:" os << std::left << std::setw(25) << " ASC:"
<< "0x" << HEX(sd.additional_sense_code) << "\n"; << "0x" << HEX(sd.additional_sense_code) << '\n';
os << std::left << std::setw(25) << " ASCQ:" os << std::left << std::setw(25) << " ASCQ:"
<< "0x" << HEX(sd.additional_sense_qualifier) << "\n"; << "0x" << HEX(sd.additional_sense_qualifier) << '\n';
if (sd.additional_sense_length > 0) { if (sd.additional_sense_length > 0) {
os << std::left << std::setw(25) << " Additional data: " os << std::left << std::setw(25) << " Additional data: "
@@ -341,7 +344,7 @@ void print_sense_data(std::ostream& os, const sense_data& sd)
for (int i = 0; i < sd.additional_sense_length; i++) { for (int i = 0; i < sd.additional_sense_length; i++) {
os << HEX(sd.additional_sense_bytes[i]); os << HEX(sd.additional_sense_bytes[i]);
} }
os << "\n"; os << '\n';
} }
#ifdef DEBUGSCSI #ifdef DEBUGSCSI
os << std::left << std::setw(25) << " Raw Sense:" os << std::left << std::setw(25) << " Raw Sense:"
@@ -351,7 +354,7 @@ void print_sense_data(std::ostream& os, const sense_data& sd)
for (int i = 0; i < sense_data::maximum_size; i++) { for (int i = 0; i < sense_data::maximum_size; i++) {
os << HEX(rawsense[i]); os << HEX(rawsense[i]);
} }
os << "\n"; os << '\n';
#endif #endif
} }

View File

@@ -344,7 +344,7 @@ using sense_buffer = std::array<std::uint8_t, sense_data::maximum_size>;
class scsi_error : public std::runtime_error { class scsi_error : public std::runtime_error {
public: public:
explicit scsi_error(std::unique_ptr<sense_buffer>&& buf) explicit scsi_error(std::unique_ptr<sense_buffer>&& buf)
: sense_buf {std::move(buf)}, std::runtime_error {""} : sense_buf {std::move(buf)}, std::runtime_error {"SCSI I/O error"}
{} {}
const sense_data& get_sense() const const sense_data& get_sense() const
{ {

View File

@@ -62,13 +62,12 @@ TEST_CASE("SCSI get device encryption status output 1", "[output]")
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}; };
const std::string expected_output {"\ const std::string expected_output {"\
Drive Encryption: off\n\
Drive Output: Not decrypting\n\ Drive Output: Not decrypting\n\
Raw encrypted data not outputted\n\ Raw encrypted data not outputted\n\
Drive Input: Not encrypting\n\ Drive Input: Not encrypting\n\
Key Instance Counter: 0\n"s}; Key Instance Counter: 0\n"s};
std::ostringstream oss; std::ostringstream oss;
print_device_status(oss, reinterpret_cast<const scsi::page_des&>(page), true); print_device_status(oss, reinterpret_cast<const scsi::page_des&>(page));
REQUIRE(oss.str() == expected_output); REQUIRE(oss.str() == expected_output);
} }
@@ -81,7 +80,6 @@ TEST_CASE("SCSI get device encryption status output 2", "[output]")
0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21,
}; };
const std::string expected_output {"\ const std::string expected_output {"\
Drive Encryption: on\n\
Drive Output: Decrypting\n\ Drive Output: Decrypting\n\
Unencrypted data not outputted\n\ Unencrypted data not outputted\n\
Drive Input: Encrypting\n\ Drive Input: Encrypting\n\
@@ -89,7 +87,7 @@ Key Instance Counter: 1\n\
Encryption Algorithm: 1\n\ Encryption Algorithm: 1\n\
Drive Key Desc.(uKAD): Hello world!\n"s}; Drive Key Desc.(uKAD): Hello world!\n"s};
std::ostringstream oss; std::ostringstream oss;
print_device_status(oss, reinterpret_cast<const scsi::page_des&>(page), true); print_device_status(oss, reinterpret_cast<const scsi::page_des&>(page));
REQUIRE(oss.str() == expected_output); REQUIRE(oss.str() == expected_output);
} }