summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorGrigoriy Orlov <gluk@cvs.openbsd.org>2002-07-06 14:46:58 +0000
committerGrigoriy Orlov <gluk@cvs.openbsd.org>2002-07-06 14:46:58 +0000
commitf0fe6ec1e0f247fa1b9efc1114ae8b7a9019219f (patch)
tree003e6fab839d5f36e90547bf2ef5db11da7134ed /sbin
parent6a562d6086cddc67b259e043e83a9a3958fa7169 (diff)
Security Mode feature set.
From Alexander Yurchenko <grange@rt.mipt.ru> Approved by csapuntz@ and me.
Diffstat (limited to 'sbin')
-rw-r--r--sbin/atactl/atactl.8106
-rw-r--r--sbin/atactl/atactl.c311
-rw-r--r--sbin/atactl/atasec.h53
3 files changed, 449 insertions, 21 deletions
diff --git a/sbin/atactl/atactl.8 b/sbin/atactl/atactl.8
index 708174d6554..113715679c7 100644
--- a/sbin/atactl/atactl.8
+++ b/sbin/atactl/atactl.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: atactl.8,v 1.15 2002/06/09 08:13:05 todd Exp $
+.\" $OpenBSD: atactl.8,v 1.16 2002/07/06 14:46:57 gluk Exp $
.\" $NetBSD: atactl.8,v 1.5 1999/02/24 18:49:14 jwise Exp $
.\"
.\" Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -234,6 +234,107 @@ behaviour in implementing this, so it is
recommended to issue this command on a disk containing any currently
mounted filesystems.
.Pp
+.Cm secsetpass
+.Ar user
+.Ar high | maximum
+.br
+.Cm secsetpass
+.Ar master
+.Pp
+Sets password and security level for the specified device.
+There are two passwords, user and master, and two security levels, high and
+maximum.
+The maximum password length is 32 symbols.
+The security system is enabled by sending a user password to the device with
+this command.
+When the security system is enabled, access to user data on the device is
+denied after a power cycle until the user password is sent to the device with
+the
+.Cm secunlock
+command.
+A master password may be set in a addition to the user password.
+The purpose of the master password is to allow an administrator to establish
+a password that is kept secret from the user, and which may be used to unlock
+the device if the user password is lost.
+Setting the master password does not enable security system.
+Each master password change causes decrement of the master password revision
+code value which is displayed in the
+.Cm identify
+command output if supported.
+After value 0x0001 is reached the next value will be 0xfffe.
+The security level determines device behavior when the master password is used
+to unlock the device.
+When the security level is set to high the device requires the
+.Cm secunlock
+command if the master password is used to unlock.
+When the security level is set to maximum the device requires a
+.Cm secerase
+command if the master password is used to unlock.
+Execution of the
+.Cm secerase
+command erases all user data on the device.
+.Pp
+.Cm secunlock
+.Ar user | master
+.Pp
+Unlocks the specified device with user or master password.
+The device will always unlock if valid user password is received.
+If the security level was set to high during the last
+.Cm secsetpass
+command, the device will unlock if the master password is received.
+If the security level was set to maximum during the last
+.Cm secsetpass
+command, the device won't unlock if the master password is received.
+.Pp
+.Cm secerase
+.Ar user | master
+.Op Ar enhanced
+.Pp
+Erases all user data and unlocks the specified device.
+Execution of this command with master password is the only way to unlock the
+device being locked at maximum security level with
+.Cm secsetpass
+command if user password lost or unknown.
+There are two erase modes: normal and enhanced.
+Default erase mode is normal.
+In the normal erase mode this command will write binary zeroes to
+all user data areas.
+The enhanced erase mode is optional and may not be supported by your device.
+When enhanced erase mode specified, the device will write predetermined
+data patterns to all user data areas.
+In enhanced erase mode, all previously written user data will be overwritten,
+including sectors that are no longer in use due to reallocation.
+This command will disable the device lock mode, however, the master password
+will still be stored internally within the device and may be reactivated later
+when a new user password is set.
+.Pp
+.Cm secfreeze
+.Pp
+Prevents changes to passwords until a following power cycle.
+The purpose of this command is to prevent password setting attacks on the
+security system.
+After command completion any other commands that update the device lock mode
+will be aborted.
+.Pp
+.Cm secdisablepass
+.Ar user | master
+.Pp
+Disables the lock mode for the specified device with user or master password.
+This command won't change the master password.
+The master password will be reactivated when a user password is set.
+.Pp
+Support for the security commands is indicated by the device with
+.Sq Security Mode feature set
+in the output of the
+.Cm identify
+command.
+.Pp
+.Em WARNING
+.br
+Be very carefull while playing with theese commands.
+If you lose user and master passwords the device will be inaccessible at all.
+Don't use it unless the implications are completely understood.
+.Pp
.Cm smartenable
.Pp
Enables SMART (Self-Monitoring, Analysis, and Reporting Technology) on the
@@ -425,6 +526,3 @@ command is rather ugly.
Disabling read look-head with the
.Cm readaheaddisable
might cause problems with mounted filesystems on that device.
-.Pp
-There is no support for the Secure Mode commands (in particular the
-Security Erase Unit).
diff --git a/sbin/atactl/atactl.c b/sbin/atactl/atactl.c
index 356b95c7985..e87027aa68e 100644
--- a/sbin/atactl/atactl.c
+++ b/sbin/atactl/atactl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atactl.c,v 1.18 2002/07/03 22:32:32 deraadt Exp $ */
+/* $OpenBSD: atactl.c,v 1.19 2002/07/06 14:46:57 gluk Exp $ */
/* $NetBSD: atactl.c,v 1.4 1999/02/24 18:49:14 jwise Exp $ */
/*-
@@ -57,6 +57,7 @@
#include <dev/ic/wdcreg.h>
#include <sys/ataio.h>
+#include "atasec.h"
#include "atasmart.h"
struct command {
@@ -93,6 +94,11 @@ void device_checkpower(int, char *[]);
void device_acoustic(int, char *[]);
void device_apm(int, char *[]);
void device_feature(int, char *[]);
+void device_sec_setpass(int, char *[]);
+void device_sec_unlock(int, char *[]);
+void device_sec_erase(int, char *[]);
+void device_sec_freeze(int, char *[]);
+void device_sec_disablepass(int, char *[]);
void device_smart_enable(int, char *[]);
void device_smart_disable(int, char *[]);
void device_smart_status(int, char *[]);
@@ -105,6 +111,8 @@ void device_attr(int, char *[]);
void smart_print_errdata(struct smart_log_errdata *);
int smart_cksum(u_int8_t *, int);
+char *sec_getpass(int, int);
+
struct command commands[] = {
{ "dump", device_dump },
{ "identify", device_identify },
@@ -125,6 +133,11 @@ struct command commands[] = {
{ "puisspinup", device_feature },
{ "readaheaddisable", device_feature },
{ "readaheadenable", device_feature },
+ { "secsetpass", device_sec_setpass },
+ { "secunlock", device_sec_unlock },
+ { "secerase", device_sec_erase },
+ { "secfreeze", device_sec_freeze },
+ { "secdisablepass", device_sec_disablepass },
{ "smartenable", device_smart_enable },
{ "smartdisable", device_smart_disable },
{ "smartstatus", device_smart_status },
@@ -369,7 +382,7 @@ void
usage(void)
{
- fprintf(stderr, "usage: %s device command [arg [...]]\n",
+ fprintf(stderr, "usage: %s <device> <command> [arg [...]]\n",
__progname);
exit(1);
}
@@ -483,7 +496,7 @@ device_identify(int argc, char *argv[])
{
struct ataparams *inqbuf;
struct atareq req;
- char inbuf[512], *s;
+ char inbuf[DEV_BSIZE], *s;
if (argc != 1)
goto usage;
@@ -566,6 +579,12 @@ device_identify(int argc, char *argv[])
printf("\n");
}
+ if ((inqbuf->atap_cmd_set1 & WDC_CMD1_SEC) &&
+ inqbuf->atap_mpasswd_rev != 0 &&
+ inqbuf->atap_mpasswd_rev != 0xffff)
+ printf("Master password revision code 0x%04x\n",
+ inqbuf->atap_mpasswd_rev);
+
if (inqbuf->atap_cmd_set1 != 0 && inqbuf->atap_cmd_set1 != 0xffff &&
inqbuf->atap_cmd_set2 != 0 && inqbuf->atap_cmd_set2 != 0xffff) {
printf("Device supports the following command sets:\n");
@@ -584,7 +603,7 @@ device_identify(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s\n", __progname, argv[0]);
+ fprintf(stderr, "usage: %s <device> %s\n", __progname, argv[0]);
exit(1);
}
@@ -616,11 +635,269 @@ device_idle(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s\n", __progname, argv[0]);
+ fprintf(stderr, "usage: %s <device> %s\n", __progname, argv[0]);
exit(1);
}
/*
+ * SECURITY SET PASSWORD command
+ */
+void
+device_sec_setpass(int argc, char *argv[])
+{
+ struct atareq req;
+ struct sec_password pwd;
+ char *pass, inbuf[DEV_BSIZE];
+ struct ataparams *inqbuf = (struct ataparams *)inbuf;
+
+ if (argc < 2)
+ goto usage;
+
+ memset(&pwd, 0, sizeof(pwd));
+
+ if (strcmp(argv[1], "user") == 0 && argc == 3)
+ pwd.ctrl |= SEC_PASSWORD_USER;
+ else if (strcmp(argv[1], "master") == 0 && argc == 2)
+ pwd.ctrl |= SEC_PASSWORD_MASTER;
+ else
+ goto usage;
+ if (argc == 3)
+ if (strcmp(argv[2], "high") == 0)
+ pwd.ctrl |= SEC_LEVEL_HIGH;
+ else if (strcmp(argv[2], "maximum") == 0)
+ pwd.ctrl |= SEC_LEVEL_MAX;
+ else
+ goto usage;
+
+ /*
+ * Issue IDENTIFY command to obtain master password
+ * revision code and decrement its value.
+ * The valid revision codes are 0x0001 through 0xfffe.
+ * If device returnes 0x0000 or 0xffff as a revision
+ * code then the master password revision code is not
+ * supported so don't touch it.
+ */
+ memset(&inbuf, 0, sizeof(inbuf));
+ memset(&req, 0, sizeof(req));
+
+ req.command = WDCC_IDENTIFY;
+ req.timeout = 1000;
+ req.flags = ATACMD_READ;
+ req.databuf = (caddr_t)inbuf;
+ req.datalen = sizeof(inbuf);
+
+ ata_command(&req);
+
+ pwd.revision = inqbuf->atap_mpasswd_rev;
+ if (pwd.revision != 0 && pwd.revision != 0xffff && --pwd.revision == 0)
+ pwd.revision = 0xfffe;
+
+ pass = sec_getpass(pwd.ctrl & SEC_PASSWORD_MASTER, 1);
+ memcpy(pwd.password, pass, strlen(pass));
+
+ memset(&req, 0, sizeof(req));
+
+ req.command = ATA_SEC_SET_PASSWORD;
+ req.timeout = 1000;
+ req.flags = ATACMD_WRITE;
+ req.databuf = (caddr_t)&pwd;
+ req.datalen = sizeof(pwd);
+
+ ata_command(&req);
+
+ return;
+usage:
+ fprintf(stderr, "usage: %s <device> %s user high | maximum\n",
+ __progname, argv[0]);
+ fprintf(stderr, "usage: %s <device> %s master\n", __progname, argv[0]);
+}
+
+/*
+ * SECURITY UNLOCK command
+ */
+void
+device_sec_unlock(int argc, char *argv[])
+{
+ struct atareq req;
+ struct sec_password pwd;
+ char *pass;
+
+ if (argc != 2)
+ goto usage;
+
+ memset(&pwd, 0, sizeof(pwd));
+
+ if (strcmp(argv[1], "user") == 0)
+ pwd.ctrl |= SEC_PASSWORD_USER;
+ else if (strcmp(argv[1], "master") == 0)
+ pwd.ctrl |= SEC_PASSWORD_MASTER;
+ else
+ goto usage;
+
+ pass = sec_getpass(pwd.ctrl & SEC_PASSWORD_MASTER, 0);
+ memcpy(pwd.password, pass, strlen(pass));
+
+ memset(&req, 0, sizeof(req));
+
+ req.command = ATA_SEC_UNLOCK;
+ req.timeout = 1000;
+ req.flags = ATACMD_WRITE;
+ req.databuf = (caddr_t)&pwd;
+ req.datalen = sizeof(pwd);
+
+ ata_command(&req);
+
+ return;
+usage:
+ fprintf(stderr, "usage: %s <device> %s user | master\n", __progname,
+ argv[0]);
+}
+
+/*
+ * SECURITY ERASE UNIT command
+ */
+void
+device_sec_erase(int argc, char *argv[])
+{
+ struct atareq req;
+ struct sec_password pwd;
+ char *pass;
+
+ if (argc < 2)
+ goto usage;
+
+ memset(&pwd, 0, sizeof(pwd));
+
+ if (strcmp(argv[1], "user") == 0)
+ pwd.ctrl |= SEC_PASSWORD_USER;
+ else if (strcmp(argv[1], "master") == 0)
+ pwd.ctrl |= SEC_PASSWORD_MASTER;
+ else
+ goto usage;
+ if (argc == 2)
+ pwd.ctrl |= SEC_ERASE_NORMAL;
+ else if (argc == 3 && strcmp(argv[2], "enhanced") == 0)
+ pwd.ctrl |= SEC_ERASE_ENHANCED;
+ else
+ goto usage;
+
+ pass = sec_getpass(pwd.ctrl & SEC_PASSWORD_MASTER, 0);
+ memcpy(pwd.password, pass, strlen(pass));
+
+ /* Issue SECURITY ERASE PREPARE command before */
+ memset(&req, 0, sizeof(req));
+
+ req.command = ATA_SEC_ERASE_PREPARE;
+ req.timeout = 1000;
+
+ ata_command(&req);
+
+ memset(&req, 0, sizeof(req));
+
+ req.command = ATA_SEC_ERASE_UNIT;
+ req.timeout = 1000;
+ req.flags = ATACMD_WRITE;
+ req.databuf = (caddr_t)&pwd;
+ req.datalen = sizeof(pwd);
+
+ ata_command(&req);
+
+ return;
+usage:
+ fprintf(stderr, "usage: %s <device> %s user | master [enhanced]\n",
+ __progname, argv[0]);
+}
+
+/*
+ * SECURITY FREEZE LOCK command
+ */
+void
+device_sec_freeze(int argc, char *argv[])
+{
+ struct atareq req;
+
+ if (argc != 1)
+ goto usage;
+
+ memset(&req, 0, sizeof(req));
+
+ req.command = ATA_SEC_FREEZE_LOCK;
+ req.timeout = 1000;
+
+ ata_command(&req);
+
+ return;
+usage:
+ fprintf(stderr, "usage: %s <device> %s\n", __progname, argv[0]);
+}
+
+/*
+ * SECURITY DISABLE PASSWORD command
+ */
+void
+device_sec_disablepass(int argc, char *argv[])
+{
+ struct atareq req;
+ struct sec_password pwd;
+ char *pass;
+
+ if (argc != 2)
+ goto usage;
+
+ memset(&pwd, 0, sizeof(pwd));
+
+ if (strcmp(argv[1], "user") == 0)
+ pwd.ctrl |= SEC_PASSWORD_USER;
+ else if (strcmp(argv[1], "master") == 0)
+ pwd.ctrl |= SEC_PASSWORD_MASTER;
+ else
+ goto usage;
+
+ pass = sec_getpass(pwd.ctrl & SEC_PASSWORD_MASTER, 0);
+ memcpy(pwd.password, pass, strlen(pass));
+
+ memset(&req, 0, sizeof(req));
+
+ req.command = ATA_SEC_DISABLE_PASSWORD;
+ req.timeout = 1000;
+ req.flags = ATACMD_WRITE;
+ req.databuf = (caddr_t)&pwd;
+ req.datalen = sizeof(pwd);
+
+ ata_command(&req);
+
+ return;
+usage:
+ fprintf(stderr, "usage: %s <device> %s user | master\n", __progname,
+ argv[0]);
+}
+
+char *
+sec_getpass(int ident, int confirm)
+{
+ char *pass;
+
+ if ((pass = getpass(ident ? "Master password:" :
+ "User password:")) == NULL)
+ err(1, "getpass()");
+ if (strlen(pass) > 32)
+ errx(1, "password too long");
+ if (confirm) {
+ char *pass2;
+
+ pass2 = strdup(pass);
+ if ((pass = getpass(ident ? "Retype master password:" :
+ "Retype user password:")) == NULL)
+ err(1, "getpass()");
+ if (strcmp(pass, pass2) != 0)
+ errx(1, "password mismatch");
+ free(pass2);
+ }
+
+ return pass;
+}
+
+/*
* SMART ENABLE OPERATIONS command
*/
void
@@ -642,7 +919,7 @@ device_smart_enable(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s\n", __progname, argv[0]);
+ fprintf(stderr, "usage: %s <device> %s\n", __progname, argv[0]);
exit(1);
}
@@ -668,7 +945,7 @@ device_smart_disable(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s\n", __progname, argv[0]);
+ fprintf(stderr, "usage: %s <device> %s\n", __progname, argv[0]);
exit(1);
}
@@ -704,7 +981,7 @@ device_smart_status(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s\n", __progname, argv[0]);
+ fprintf(stderr, "usage: %s <device> %s\n", __progname, argv[0]);
exit(1);
}
@@ -734,7 +1011,7 @@ device_smart_autosave(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s enable | disable\n", __progname,
+ fprintf(stderr, "usage: %s <device> %s enable | disable\n", __progname,
argv[0]);
exit(1);
}
@@ -765,7 +1042,7 @@ device_smart_offline(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s subcommand\n", __progname,
+ fprintf(stderr, "usage: %s <device> %s <subcommand>\n", __progname,
argv[0]);
exit(1);
}
@@ -826,7 +1103,7 @@ device_smart_read(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s\n", __progname, argv[0]);
+ fprintf(stderr, "usage: %s <device> %s\n", __progname, argv[0]);
exit(1);
}
@@ -999,7 +1276,7 @@ device_smart_readlog(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s log\n", __progname, argv[0]);
+ fprintf(stderr, "usage: %s <device> %s <log>\n", __progname, argv[0]);
exit(1);
}
@@ -1176,7 +1453,7 @@ device_acoustic(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s acoustic-management-value\n",
+ fprintf(stderr, "usage: %s <device> %s <acoustic-management-value>\n",
__progname, argv[0]);
exit(1);
}
@@ -1224,7 +1501,7 @@ device_apm(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s power-management-level\n",
+ fprintf(stderr, "usage: %s <device> %s <power-management-level>\n",
__progname, argv[0]);
exit(1);
}
@@ -1273,7 +1550,7 @@ device_feature(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s\n", __progname,
+ fprintf(stderr, "usage: %s <device> %s\n", __progname,
argv[0]);
exit(1);
}
@@ -1330,7 +1607,7 @@ device_setidle(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s idle-time\n", __progname,
+ fprintf(stderr, "usage: %s <device> %s <idle-time>\n", __progname,
argv[0]);
exit(1);
}
@@ -1372,6 +1649,6 @@ device_checkpower(int argc, char *argv[])
return;
usage:
- fprintf(stderr, "usage: %s device %s\n", __progname, argv[0]);
+ fprintf(stderr, "usage: %s <device> %s\n", __progname, argv[0]);
exit(1);
}
diff --git a/sbin/atactl/atasec.h b/sbin/atactl/atasec.h
new file mode 100644
index 00000000000..e2a0bc1925e
--- /dev/null
+++ b/sbin/atactl/atasec.h
@@ -0,0 +1,53 @@
+/* $OpenBSD: atasec.h,v 1.1 2002/07/06 14:46:57 gluk Exp $ */
+
+/*
+ * Copyright (c) 2002 Alexander Yurchenko <grange@rt.mipt.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* ATA Security Mode commands */
+#define ATA_SEC_SET_PASSWORD 0xf1
+#define ATA_SEC_UNLOCK 0xf2
+#define ATA_SEC_ERASE_PREPARE 0xf3
+#define ATA_SEC_ERASE_UNIT 0xf4
+#define ATA_SEC_FREEZE_LOCK 0xf5
+#define ATA_SEC_DISABLE_PASSWORD 0xf6
+
+/* security password sector */
+struct sec_password {
+ u_int16_t ctrl; /* Control word */
+#define SEC_PASSWORD_USER 0x0000
+#define SEC_PASSWORD_MASTER 0x0001
+#define SEC_ERASE_NORMAL 0x0000
+#define SEC_ERASE_ENHANCED 0x0002
+#define SEC_LEVEL_HIGH 0x0000
+#define SEC_LEVEL_MAX 0x0100
+ u_int8_t password[32]; /* Password */
+ u_int16_t revision; /* Master password revision code */
+ u_int16_t res[238]; /* Reserved */
+};