Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sbin/atactl Add some ATA SECURITY commands to atactl(8).



details:   https://anonhg.NetBSD.org/src/rev/0d8b4b94afde
branches:  trunk
changeset: 783816:0d8b4b94afde
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Wed Jan 09 21:58:23 2013 +0000

description:
Add some ATA SECURITY commands to atactl(8).

diffstat:

 sbin/atactl/atactl.8 |   71 +++++++++++++++++-
 sbin/atactl/atactl.c |  196 +++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 225 insertions(+), 42 deletions(-)

diffs (truncated from 371 to 300 lines):

diff -r 5e107895d95c -r 0d8b4b94afde sbin/atactl/atactl.8
--- a/sbin/atactl/atactl.8      Wed Jan 09 18:19:09 2013 +0000
+++ b/sbin/atactl/atactl.8      Wed Jan 09 21:58:23 2013 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: atactl.8,v 1.23 2008/04/30 13:10:52 martin Exp $
+.\"    $NetBSD: atactl.8,v 1.24 2013/01/09 21:58:23 riastradh Exp $
 .\"
 .\" Copyright (c) 1998 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd November 18, 2007
+.Dd January 9, 2013
 .Dt ATACTL 8
 .Os
 .Sh NAME
@@ -160,7 +160,7 @@
 .It Ar selftest-log
 Prints the self-test log.
 .El
-.It Cm security Bq Ar freeze | status
+.It Cm security Bq Ar status | freeze | setpass | unlock | disable | erase
 Controls
 .Dq security
 (password protection) features of modern ATA drives.
@@ -175,11 +175,46 @@
 .Dq freeze
 command early in the boot process.
 .Bl -tag -width freezeXX
+.It Ar status
+displays the drive's security status
 .It Ar freeze
 freezes the drive's security status
-.It Ar status
-displays the drive's security status
+.It Ar setpass Bq user | master
+sets the drive's user or master password
+.It Ar unlock Bq user | master
+unlocks a password-protected drive
+.It Ar disable Bq user | master
+disables password protection
+.It Ar erase Bq user | master
+erases the device and clears security state, using enhanced erasure if
+the drive supports it; may take a long time to run
 .El
+.Pp
+Note that to erase a drive, it must have a password set and be
+unfrozen.
+If you can't persuade your firmware to leave the drive unfrozen on
+boot, but it is a SATA drive, say
+.Pa wd2
+at
+.Pa atabus3 ,
+that you can safely physically disconnect and reconnect, then you may
+be able to use SATA hot-plug to work around this: first run
+.Bd -literal -offset indent
+# drvctl -d wd2
+.Ed
+.Pp
+Then physically disconnect and reconnect the drive, and run
+.Bd -literal -offset indent
+# drvctl -r -a ata_hl atabus3
+.Ed
+.Pp
+After this, check that the security status does not list
+.Dq frozen :
+.Bd -literal -offset indent
+# atactl wd2 security status
+       supported
+#
+.Ed
 .El
 .Sh BUS COMMANDS
 The following commands may be used on IDE and ATA busses.
@@ -190,10 +225,29 @@
 This will reset all ATA devices present on the bus.
 Any ATAPI device with pending commands will also be reset.
 .El
+.Sh EXAMPLES
+To erase
+.Pa wd2
+which is currently unfrozen and has no password set:
+.Bd -literal -offset indent
+# atactl wd2 security status
+       supported
+# atactl wd2 security setpass user
+Password:
+Confirm password:
+# atactl wd2 security status
+       supported
+       enabled
+# atactl wd2 security erase user
+Password:
+Erasing may take up to 0h 2m 0s...
+#
+.Ed
 .Sh SEE ALSO
 .Xr ioctl 2 ,
 .Xr wd 4 ,
 .Xr dkctl 8 ,
+.Xr drvctl 8 ,
 .Xr scsictl 8
 .Sh HISTORY
 The
@@ -211,3 +265,10 @@
 The output from the
 .Cm identify
 command is rather ugly.
+.Pp
+Support for master passwords is not implemented.
+.Pp
+The
+.Nx
+kernel behaves poorly with drives that have passwords set and are
+locked.
diff -r 5e107895d95c -r 0d8b4b94afde sbin/atactl/atactl.c
--- a/sbin/atactl/atactl.c      Wed Jan 09 18:19:09 2013 +0000
+++ b/sbin/atactl/atactl.c      Wed Jan 09 21:58:23 2013 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: atactl.c,v 1.67 2012/10/19 17:09:07 drochner Exp $     */
+/*     $NetBSD: atactl.c,v 1.68 2013/01/09 21:58:23 riastradh Exp $    */
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
 #include <sys/cdefs.h>
 
 #ifndef lint
-__RCSID("$NetBSD: atactl.c,v 1.67 2012/10/19 17:09:07 drochner Exp $");
+__RCSID("$NetBSD: atactl.c,v 1.68 2013/01/09 21:58:23 riastradh Exp $");
 #endif
 
 
@@ -44,6 +44,7 @@
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -144,7 +145,9 @@
        { "smart",
                "enable|disable|status|offline #|error-log|selftest-log",
                                                device_smart },
-       { "security",   "freeze|status",        device_security },
+       { "security",
+               "status|freeze|[setpass|unlock|disable|erase] [user|master]",
+                                               device_security },
        { NULL,         NULL,                   NULL },
 };
 
@@ -851,6 +854,49 @@
        buf[j] = '\0';
 }
 
+static void
+compute_capacity(const struct ataparams *inqbuf, uint64_t *capacityp,
+    uint64_t *sectorsp, uint32_t *secsizep)
+{
+       uint64_t capacity;
+       uint64_t sectors;
+       uint32_t secsize;
+
+       if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff &&
+           inqbuf->atap_cmd2_en & ATA_CMD2_LBA48) {
+               sectors =
+                   ((uint64_t)inqbuf->atap_max_lba[3] << 48) |
+                   ((uint64_t)inqbuf->atap_max_lba[2] << 32) |
+                   ((uint64_t)inqbuf->atap_max_lba[1] << 16) |
+                   ((uint64_t)inqbuf->atap_max_lba[0] <<  0);
+       } else if (inqbuf->atap_capabilities1 & WDC_CAP_LBA) {
+               sectors = (inqbuf->atap_capacity[1] << 16) |
+                   inqbuf->atap_capacity[0];
+       } else {
+               sectors = inqbuf->atap_cylinders *
+                   inqbuf->atap_heads * inqbuf->atap_sectors;
+       }
+
+       secsize = 512;
+
+       if ((inqbuf->atap_secsz & ATA_SECSZ_VALID_MASK) == ATA_SECSZ_VALID) {
+               if (inqbuf->atap_secsz & ATA_SECSZ_LLS) {
+                       secsize = 2 *           /* words to bytes */
+                           (inqbuf->atap_lls_secsz[1] << 16 |
+                           inqbuf->atap_lls_secsz[0] <<  0);
+               }
+       }
+
+       capacity = sectors * secsize;
+
+       if (capacityp)
+               *capacityp = capacity;
+       if (sectorsp)
+               *sectorsp = sectors;
+       if (secsizep)
+               *secsizep = secsize;
+}
+
 /*
  * DEVICE COMMANDS
  */
@@ -934,32 +980,7 @@
               "ATAPI" : "ATA", inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" :
               "removable");
 
-       if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff &&
-           inqbuf->atap_cmd2_en & ATA_CMD2_LBA48) {
-               sectors =
-                   ((uint64_t)inqbuf->atap_max_lba[3] << 48) |
-                   ((uint64_t)inqbuf->atap_max_lba[2] << 32) |
-                   ((uint64_t)inqbuf->atap_max_lba[1] << 16) |
-                   ((uint64_t)inqbuf->atap_max_lba[0] <<  0);
-       } else if (inqbuf->atap_capabilities1 & WDC_CAP_LBA) {
-               sectors = (inqbuf->atap_capacity[1] << 16) |
-                   inqbuf->atap_capacity[0];
-       } else {
-               sectors = inqbuf->atap_cylinders *
-                   inqbuf->atap_heads * inqbuf->atap_sectors;
-       }
-
-       secsize = 512;
-
-       if ((inqbuf->atap_secsz & ATA_SECSZ_VALID_MASK) == ATA_SECSZ_VALID) {
-               if (inqbuf->atap_secsz & ATA_SECSZ_LLS) {
-                       secsize = 2 *           /* words to bytes */
-                           (inqbuf->atap_lls_secsz[1] << 16 |
-                           inqbuf->atap_lls_secsz[0] <<  0);
-               }
-       }
-
-       capacity = sectors * secsize;
+       compute_capacity(inqbuf, &capacity, &sectors, &secsize);
 
        humanize_number(hnum, sizeof(hnum), capacity, "bytes",
                HN_AUTOSCALE, HN_DIVISOR_1000);
@@ -1368,23 +1389,124 @@
 {
        struct atareq req;
        const struct ataparams *inqbuf;
+       unsigned char data[DEV_BSIZE];
+       char *pass;
 
        /* need subcommand */
        if (argc < 1)
                usage();
 
-       if (strcmp(argv[0], "freeze") == 0) {
-               memset(&req, 0, sizeof(req));
+       memset(&req, 0, sizeof(req));
+       if (strcmp(argv[0], "status") == 0) {
+               inqbuf = getataparams();
+               print_bitinfo("\t", "\n", inqbuf->atap_sec_st, ata_sec_st);
+       } else if (strcmp(argv[0], "freeze") == 0) {
                req.command = WDCC_SECURITY_FREEZE;
                req.timeout = 1000;
                ata_command(&req);
-       } else if (strcmp(argv[0], "status") == 0) {
-               inqbuf = getataparams();
-               print_bitinfo("\t", "\n", inqbuf->atap_sec_st, ata_sec_st);
-       } else
+       } else if ((strcmp(argv[0], "setpass") == 0) ||
+           (strcmp(argv[0], "unlock") == 0) ||
+           (strcmp(argv[0], "disable") == 0) ||
+           (strcmp(argv[0], "erase") == 0)) {
+               if (argc != 2)
+                       usage();
+               if (strcmp(argv[1], "user") != 0) {
+                       if (strcmp(argv[1], "master") == 0) {
+                               fprintf(stderr,
+                                   "Master passwords not supported\n");
+                               exit(1);
+                       } else {
+                               usage();
+                       }
+               }
+
+               pass = getpass("Password:");
+               if (strlen(pass) > 32) {
+                       fprintf(stderr, "Password must be <=32 characters\n");
+                       exit(1);
+               }
+
+               req.flags |= ATACMD_WRITE;
+               req.timeout = 1000;
+               req.databuf = data;
+               req.datalen = sizeof(data);
+               memset(data, 0, sizeof(data));
+               strlcpy((void *)&data[2], pass, 32 + 1);
+
+               if (strcmp(argv[0], "setpass") == 0) {
+                       char orig[32 + 1];
+                       strlcpy(orig, pass, 32 + 1);
+                       pass = getpass("Confirm password:");
+                       if (0 != strcmp(orig, pass)) {
+                               fprintf(stderr, "Passwords do not match\n");
+                               exit(1);
+                       }



Home | Main Index | Thread Index | Old Index