From 72a047dedc29c5f53046126c0970faf152352901 Mon Sep 17 00:00:00 2001 From: itycodes Date: Tue, 9 Jul 2024 08:42:23 +0200 Subject: [PATCH] Add smartmontools patches Those patches were tested and work. Currently in the process of minimizing the code required in main.c . Those 4 patches mostly add support for more ATA Security commands to smartmontools. --- 0001-Add-ATA-command-Security-Unlock.patch | 119 ++++++++++++ ...Add-a-password-flag-for-ATA-Security.patch | 170 ++++++++++++++++++ ...patch-that-replaces-with-0-in-passwo.patch | 43 +++++ 0004-Add-ATA-command-Security-Disable.patch | 93 ++++++++++ 4 files changed, 425 insertions(+) create mode 100644 0001-Add-ATA-command-Security-Unlock.patch create mode 100644 0002-Add-a-password-flag-for-ATA-Security.patch create mode 100644 0003-Add-a-temporary-patch-that-replaces-with-0-in-passwo.patch create mode 100644 0004-Add-ATA-command-Security-Disable.patch diff --git a/0001-Add-ATA-command-Security-Unlock.patch b/0001-Add-ATA-command-Security-Unlock.patch new file mode 100644 index 0000000..4fdbb96 --- /dev/null +++ b/0001-Add-ATA-command-Security-Unlock.patch @@ -0,0 +1,119 @@ +From d46897645c8545638983e414b695a6a901074b86 Mon Sep 17 00:00:00 2001 +From: itycodes +Date: Wed, 29 May 2024 06:19:13 +0200 +Subject: [PATCH 1/4] Add ATA command Security Unlock + +--- + smartmontools/atacmds.h | 1 + + smartmontools/ataprint.cpp | 16 +++++++++++++--- + smartmontools/ataprint.h | 1 + + smartmontools/smartctl.cpp | 3 +++ + smartmontools/smartd.cpp | 6 ++++++ + 5 files changed, 24 insertions(+), 3 deletions(-) + +diff --git a/smartmontools/atacmds.h b/smartmontools/atacmds.h +index 9e813776..b914cc64 100644 +--- a/smartmontools/atacmds.h ++++ b/smartmontools/atacmds.h +@@ -55,6 +55,7 @@ typedef enum { + #define ATA_IDLE 0xe3 + #define ATA_SMART_CMD 0xb0 + #define ATA_SECURITY_FREEZE_LOCK 0xf5 ++#define ATA_SECURITY_UNLOCK 0xf2 + #ifndef ATA_SET_FEATURES + #define ATA_SET_FEATURES 0xef + #endif +diff --git a/smartmontools/ataprint.cpp b/smartmontools/ataprint.cpp +index 4efb03a7..40edd33f 100644 +--- a/smartmontools/ataprint.cpp ++++ b/smartmontools/ataprint.cpp +@@ -3754,7 +3754,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) + if ( options.smart_disable || options.smart_enable + || options.smart_auto_save_disable || options.smart_auto_save_enable + || options.smart_auto_offl_disable || options.smart_auto_offl_enable +- || options.set_aam || options.set_apm || options.set_lookahead ++ || options.set_aam || options.set_apm || options.set_lookahead || options.set_security_unlock + || options.set_wcache || options.set_security_freeze || options.set_standby + || options.sct_wcache_reorder_set || options.sct_wcache_sct_set || options.set_dsn) + pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); +@@ -3878,6 +3878,16 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) + pout("ATA Security set to frozen mode\n"); + } + ++ // Unlock ATA security ++ if (options.set_security_unlock) { ++ if (!ata_nodata_command(device, ATA_SECURITY_UNLOCK)) { ++ pout("ATA SECURITY UNLOCK failed: %s\n", device->get_errmsg()); ++ returnval |= FAILSMART; ++ } ++ else ++ pout("ATA Security set to unlocked\n"); ++ } ++ + // Set standby timer unless immediate standby is also requested + if (options.set_standby && !options.set_standby_now) { + if (!ata_nodata_command(device, ATA_IDLE, options.set_standby-1)) { +@@ -4000,8 +4010,8 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) + || options.smart_auto_save_disable || options.smart_auto_save_enable + || options.smart_auto_offl_disable || options.smart_auto_offl_enable + || options.set_aam || options.set_apm || options.set_lookahead +- || options.set_wcache || options.set_security_freeze || options.set_standby +- || options.sct_wcache_reorder_set || options.set_dsn) ++ || options.set_wcache || options.set_security_freeze || options.set_security_unlock ++ || options.set_standby || options.sct_wcache_reorder_set || options.set_dsn) + pout("\n"); + + // START OF READ-ONLY OPTIONS APART FROM -V and -i +diff --git a/smartmontools/ataprint.h b/smartmontools/ataprint.h +index 64b74570..ff35dead 100644 +--- a/smartmontools/ataprint.h ++++ b/smartmontools/ataprint.h +@@ -93,6 +93,7 @@ struct ata_print_options + bool set_standby_now = false; // set drive to standby + bool get_security = false; // print ATA security status + bool set_security_freeze = false; // Freeze ATA security ++ bool set_security_unlock = false; // Unlock ATA security + bool get_wcache = false; // print write cache status + int set_wcache = 0; // disable(-1), enable(1) write cache + bool sct_wcache_reorder_get = false; // print write cache reordering status +diff --git a/smartmontools/smartctl.cpp b/smartmontools/smartctl.cpp +index 67d1beef..4fd5915e 100644 +--- a/smartmontools/smartctl.cpp ++++ b/smartmontools/smartctl.cpp +@@ -1077,6 +1077,9 @@ static int parse_options(int argc, char** argv, const char * & type, + else if (!get && !strcmp(optarg, "security-freeze")) { + ataopts.set_security_freeze = true; + } ++ else if(!get && !strcmp(optarg, "security-unlock")) { ++ ataopts.set_security_unlock = true; ++ } + else if (!get && !strcmp(optarg, "standby,now")) { + ataopts.set_standby_now = true; + scsiopts.set_standby_now = true; +diff --git a/smartmontools/smartd.cpp b/smartmontools/smartd.cpp +index 34f2cde2..9e4ae2eb 100644 +--- a/smartmontools/smartd.cpp ++++ b/smartmontools/smartd.cpp +@@ -435,6 +435,7 @@ struct dev_config + int set_lookahead{}; // disable(-1), enable(1) read look-ahead + int set_standby{}; // set(1..255->0..254) standby timer + bool set_security_freeze{}; // Freeze ATA security ++ bool set_security_unlock{}; // Unlock ATA security + int set_wcache{}; // disable(-1), enable(1) write cache + int set_dsn{}; // disable(0x2), enable(0x1) DSN + +@@ -2341,6 +2342,11 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade + format_set_result_msg(msg, "Security freeze", + ata_nodata_command(atadev, ATA_SECURITY_FREEZE_LOCK)); + ++ ++ if (cfg.set_security_unlock) ++ format_set_result_msg(msg, "Security unlock", ++ ata_nodata_command(atadev, ATA_SECURITY_UNLOCK)); ++ + if (cfg.set_standby) + format_set_result_msg(msg, "Standby", + ata_nodata_command(atadev, ATA_IDLE, cfg.set_standby-1), cfg.set_standby, true); +-- +2.45.1 + diff --git a/0002-Add-a-password-flag-for-ATA-Security.patch b/0002-Add-a-password-flag-for-ATA-Security.patch new file mode 100644 index 0000000..c73ec8f --- /dev/null +++ b/0002-Add-a-password-flag-for-ATA-Security.patch @@ -0,0 +1,170 @@ +From a88a02e36b93e6c1d1b9d123761a3c26d652086d Mon Sep 17 00:00:00 2001 +From: itycodes +Date: Wed, 29 May 2024 23:01:48 +0200 +Subject: [PATCH 2/4] Add a password flag for ATA Security + +--- + smartmontools/atacmds.cpp | 19 +++++++++++++++++++ + smartmontools/atacmds.h | 15 +++++++++++++++ + smartmontools/ataprint.cpp | 2 +- + smartmontools/ataprint.h | 1 + + smartmontools/smartctl.cpp | 14 ++++++++++++++ + smartmontools/smartd.cpp | 1 + + 6 files changed, 51 insertions(+), 1 deletion(-) + +diff --git a/smartmontools/atacmds.cpp b/smartmontools/atacmds.cpp +index 3f88c299..0c465c8b 100644 +--- a/smartmontools/atacmds.cpp ++++ b/smartmontools/atacmds.cpp +@@ -12,6 +12,8 @@ + */ + + #include "config.h" ++#include ++#include + #define __STDC_FORMAT_MACROS 1 // enable PRI* for C++ + + #include +@@ -795,6 +797,23 @@ bool ata_nodata_command(ata_device * device, unsigned char command, + return device->ata_pass_through(in); + } + ++// Issue a no-data ATA command with optional sector count register value ++bool ata_password_command(ata_device * device, unsigned char command, unsigned char flags, ++ unsigned short password[16]) ++{ ++ ata_cmd_in in; ++ in.in_regs.command = command; ++ in.in_regs.sector_count = 1; ++ ata_security_unlock_data_content* unlock = new ata_security_unlock_data_content(); ++ memset(unlock, 0, sizeof(ata_security_unlock_data_content)); ++ memcpy(&unlock->flags, &flags, sizeof(unlock->flags)); ++ memcpy(&unlock->password, password, sizeof(unlock->password)); ++ printf("The password is: %s\n", (char*)&unlock->password); ++ in.set_data_out(unlock, 1); ++ ++ return device->ata_pass_through(in); ++} ++ + // Issue SET FEATURES command with optional sector count register value + bool ata_set_features(ata_device * device, unsigned char features, + int sector_count /* = -1 */) +diff --git a/smartmontools/atacmds.h b/smartmontools/atacmds.h +index b914cc64..77a1522d 100644 +--- a/smartmontools/atacmds.h ++++ b/smartmontools/atacmds.h +@@ -193,6 +193,17 @@ STATIC_ASSERT(sizeof(ata_smart_attribute) == 12); + #define ATTRIBUTE_FLAGS_OTHER(x) ((x) & 0xffc0) + + ++// ATA Security Unlock data structure ++#pragma pack(1) ++struct ata_security_unlock_data_content ++{ ++ unsigned short flags; // 3 = Error Recovery Control ++ unsigned short password[16]; // 1 = Set Current, 2 = Return Current, 3 = Set Power-on, 4 = Return Power-on, 5 = Restore Default ++ unsigned short words017_255[239]; // reserved ++} ATTR_PACKED; ++#pragma pack() ++STATIC_ASSERT(sizeof(ata_security_unlock_data_content) == 512); ++ + // Format of data returned by SMART READ DATA + // Table 62 of T13/1699-D (ATA8-ACS) Revision 6a, September 2008 + #pragma pack(1) +@@ -754,6 +765,10 @@ int ataCheckPowerMode(ata_device * device); + // Issue a no-data ATA command with optional sector count register value + bool ata_nodata_command(ata_device * device, unsigned char command, int sector_count = -1); + ++// Issue an ATA command that needs a password ++bool ata_password_command(ata_device * device, unsigned char command, unsigned char flags, ++ unsigned short password[16]); ++ + // Issue SET FEATURES command with optional sector count register value + bool ata_set_features(ata_device * device, unsigned char features, int sector_count = -1); + +diff --git a/smartmontools/ataprint.cpp b/smartmontools/ataprint.cpp +index 40edd33f..00ff8878 100644 +--- a/smartmontools/ataprint.cpp ++++ b/smartmontools/ataprint.cpp +@@ -3880,7 +3880,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) + + // Unlock ATA security + if (options.set_security_unlock) { +- if (!ata_nodata_command(device, ATA_SECURITY_UNLOCK)) { ++ if (!ata_password_command(device, ATA_SECURITY_UNLOCK, 0, options.security_password)) { + pout("ATA SECURITY UNLOCK failed: %s\n", device->get_errmsg()); + returnval |= FAILSMART; + } +diff --git a/smartmontools/ataprint.h b/smartmontools/ataprint.h +index ff35dead..dcf96dfb 100644 +--- a/smartmontools/ataprint.h ++++ b/smartmontools/ataprint.h +@@ -94,6 +94,7 @@ struct ata_print_options + bool get_security = false; // print ATA security status + bool set_security_freeze = false; // Freeze ATA security + bool set_security_unlock = false; // Unlock ATA security ++ unsigned short* security_password; // ATA security password + bool get_wcache = false; // print write cache status + int set_wcache = 0; // disable(-1), enable(1) write cache + bool sct_wcache_reorder_get = false; // print write cache reordering status +diff --git a/smartmontools/smartctl.cpp b/smartmontools/smartctl.cpp +index 4fd5915e..25b3d09e 100644 +--- a/smartmontools/smartctl.cpp ++++ b/smartmontools/smartctl.cpp +@@ -191,6 +191,8 @@ static void Usage() + " %s, swapid\n\n" + " -P TYPE, --presets=TYPE (ATA)\n" + " Drive-specific presets: use, ignore, show, showall\n\n" ++" -p PASSWORD, --password=PASSWORD (ATA)\n" ++" ATA Security User Password\n\n" + " -B [+]FILE, --drivedb=[+]FILE (ATA)\n" + " Read and replace [add] drive database from FILE\n" + " [default is +%s", +@@ -254,6 +256,8 @@ static std::string getvalidarglist(int opt) + "nvmelog,N,SIZE, tapedevstat, zdevstat, envrep, farm"; + case 'P': + return "use, ignore, show, showall"; ++ case 'p': ++ return ""; + case 't': + return "offline, short, long, conveyance, force, vendor,N, select,M-N, " + "pending,N, afterselect,[on|off]"; +@@ -331,6 +335,7 @@ static int parse_options(int argc, char** argv, const char * & type, + { "badsum", required_argument, 0, 'b' }, + { "report", required_argument, 0, 'r' }, + { "smart", required_argument, 0, opt_smart }, ++ { "password", required_argument, 0, 'p' }, + { "offlineauto", required_argument, 0, 'o' }, + { "saveauto", required_argument, 0, 'S' }, + { "health", no_argument, 0, 'H' }, +@@ -801,6 +806,15 @@ static int parse_options(int argc, char** argv, const char * & type, + badarg = true; + } + break; ++ // Password, has to be 32 characters ++ case 'p': ++ if(strlen(optarg) != 32) { ++ badarg = true; ++ } else { ++ ataopts.security_password = (unsigned short*)malloc(32); ++ memcpy(ataopts.security_password, optarg, 32); ++ } ++ break; + case 't': + if (!strcmp(optarg,"offline")) { + testcnt++; +diff --git a/smartmontools/smartd.cpp b/smartmontools/smartd.cpp +index 9e4ae2eb..c218434d 100644 +--- a/smartmontools/smartd.cpp ++++ b/smartmontools/smartd.cpp +@@ -436,6 +436,7 @@ struct dev_config + int set_standby{}; // set(1..255->0..254) standby timer + bool set_security_freeze{}; // Freeze ATA security + bool set_security_unlock{}; // Unlock ATA security ++ unsigned short security_password[16]{}; // ATA security password + int set_wcache{}; // disable(-1), enable(1) write cache + int set_dsn{}; // disable(0x2), enable(0x1) DSN + +-- +2.45.1 + diff --git a/0003-Add-a-temporary-patch-that-replaces-with-0-in-passwo.patch b/0003-Add-a-temporary-patch-that-replaces-with-0-in-passwo.patch new file mode 100644 index 0000000..26a6e64 --- /dev/null +++ b/0003-Add-a-temporary-patch-that-replaces-with-0-in-passwo.patch @@ -0,0 +1,43 @@ +From 7b081ec58a7fc893fc8aa7a89ac525bab07357ac Mon Sep 17 00:00:00 2001 +From: itycodes +Date: Fri, 31 May 2024 14:06:20 +0200 +Subject: [PATCH 3/4] Add a temporary patch that replaces '*' with '\0' in + --password + +--- + smartmontools/atacmds.cpp | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/smartmontools/atacmds.cpp b/smartmontools/atacmds.cpp +index 0c465c8b..b1164a13 100644 +--- a/smartmontools/atacmds.cpp ++++ b/smartmontools/atacmds.cpp +@@ -797,7 +797,7 @@ bool ata_nodata_command(ata_device * device, unsigned char command, + return device->ata_pass_through(in); + } + +-// Issue a no-data ATA command with optional sector count register value ++// Issue a password ATA command with optional sector count register value + bool ata_password_command(ata_device * device, unsigned char command, unsigned char flags, + unsigned short password[16]) + { +@@ -808,7 +808,15 @@ bool ata_password_command(ata_device * device, unsigned char command, unsigned c + memset(unlock, 0, sizeof(ata_security_unlock_data_content)); + memcpy(&unlock->flags, &flags, sizeof(unlock->flags)); + memcpy(&unlock->password, password, sizeof(unlock->password)); +- printf("The password is: %s\n", (char*)&unlock->password); ++ printf("The password is: %s (", (char*)&unlock->password); ++ char* passwd = (char*)&unlock->password; ++ for(int i = 0; i < 32; i++){ ++ if(passwd[i] == '*'){ ++ passwd[i] = 0; ++ } ++ printf(" %d ", passwd[i]); ++ } ++ printf("\n)"); + in.set_data_out(unlock, 1); + + return device->ata_pass_through(in); +-- +2.45.1 + diff --git a/0004-Add-ATA-command-Security-Disable.patch b/0004-Add-ATA-command-Security-Disable.patch new file mode 100644 index 0000000..62b2c0a --- /dev/null +++ b/0004-Add-ATA-command-Security-Disable.patch @@ -0,0 +1,93 @@ +From f3eb303f6b1c6192b50a05f1877665da0e009d53 Mon Sep 17 00:00:00 2001 +From: itycodes +Date: Fri, 14 Jun 2024 01:02:12 +0200 +Subject: [PATCH 4/4] Add ATA command Security Disable + +--- + smartmontools/atacmds.h | 1 + + smartmontools/ataprint.cpp | 15 +++++++++++++-- + smartmontools/ataprint.h | 1 + + smartmontools/smartctl.cpp | 3 +++ + 4 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/smartmontools/atacmds.h b/smartmontools/atacmds.h +index 77a1522d..32b57f77 100644 +--- a/smartmontools/atacmds.h ++++ b/smartmontools/atacmds.h +@@ -56,6 +56,7 @@ typedef enum { + #define ATA_SMART_CMD 0xb0 + #define ATA_SECURITY_FREEZE_LOCK 0xf5 + #define ATA_SECURITY_UNLOCK 0xf2 ++#define ATA_SECURITY_DISABLE 0xf6 + #ifndef ATA_SET_FEATURES + #define ATA_SET_FEATURES 0xef + #endif +diff --git a/smartmontools/ataprint.cpp b/smartmontools/ataprint.cpp +index 00ff8878..2fe97903 100644 +--- a/smartmontools/ataprint.cpp ++++ b/smartmontools/ataprint.cpp +@@ -3755,7 +3755,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) + || options.smart_auto_save_disable || options.smart_auto_save_enable + || options.smart_auto_offl_disable || options.smart_auto_offl_enable + || options.set_aam || options.set_apm || options.set_lookahead || options.set_security_unlock +- || options.set_wcache || options.set_security_freeze || options.set_standby ++ || options.set_security_disable || options.set_wcache || options.set_security_freeze || options.set_standby + || options.sct_wcache_reorder_set || options.sct_wcache_sct_set || options.set_dsn) + pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); + +@@ -3888,6 +3888,17 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) + pout("ATA Security set to unlocked\n"); + } + ++ ++ // Disable ATA security ++ if (options.set_security_disable) { ++ if (!ata_password_command(device, ATA_SECURITY_DISABLE, 0, options.security_password)) { ++ pout("ATA SECURITY DISABLE failed: %s\n", device->get_errmsg()); ++ returnval |= FAILSMART; ++ } ++ else ++ pout("ATA Security set to disabled\n"); ++ } ++ + // Set standby timer unless immediate standby is also requested + if (options.set_standby && !options.set_standby_now) { + if (!ata_nodata_command(device, ATA_IDLE, options.set_standby-1)) { +@@ -4011,7 +4022,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options) + || options.smart_auto_offl_disable || options.smart_auto_offl_enable + || options.set_aam || options.set_apm || options.set_lookahead + || options.set_wcache || options.set_security_freeze || options.set_security_unlock +- || options.set_standby || options.sct_wcache_reorder_set || options.set_dsn) ++ || options.set_security_disable || options.set_standby || options.sct_wcache_reorder_set || options.set_dsn) + pout("\n"); + + // START OF READ-ONLY OPTIONS APART FROM -V and -i +diff --git a/smartmontools/ataprint.h b/smartmontools/ataprint.h +index dcf96dfb..4725fe41 100644 +--- a/smartmontools/ataprint.h ++++ b/smartmontools/ataprint.h +@@ -94,6 +94,7 @@ struct ata_print_options + bool get_security = false; // print ATA security status + bool set_security_freeze = false; // Freeze ATA security + bool set_security_unlock = false; // Unlock ATA security ++ bool set_security_disable = false; // Disable ATA security + unsigned short* security_password; // ATA security password + bool get_wcache = false; // print write cache status + int set_wcache = 0; // disable(-1), enable(1) write cache +diff --git a/smartmontools/smartctl.cpp b/smartmontools/smartctl.cpp +index 25b3d09e..034b7c2a 100644 +--- a/smartmontools/smartctl.cpp ++++ b/smartmontools/smartctl.cpp +@@ -1094,6 +1094,9 @@ static int parse_options(int argc, char** argv, const char * & type, + else if(!get && !strcmp(optarg, "security-unlock")) { + ataopts.set_security_unlock = true; + } ++ else if(!get && !strcmp(optarg, "security-disable")) { ++ ataopts.set_security_disable = true; ++ } + else if (!get && !strcmp(optarg, "standby,now")) { + ataopts.set_standby_now = true; + scsiopts.set_standby_now = true; +-- +2.45.1 +