diff options
author | Grigoriy Orlov <gluk@cvs.openbsd.org> | 2002-07-06 14:46:58 +0000 |
---|---|---|
committer | Grigoriy Orlov <gluk@cvs.openbsd.org> | 2002-07-06 14:46:58 +0000 |
commit | f0fe6ec1e0f247fa1b9efc1114ae8b7a9019219f (patch) | |
tree | 003e6fab839d5f36e90547bf2ef5db11da7134ed /sbin | |
parent | 6a562d6086cddc67b259e043e83a9a3958fa7169 (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.8 | 106 | ||||
-rw-r--r-- | sbin/atactl/atactl.c | 311 | ||||
-rw-r--r-- | sbin/atactl/atasec.h | 53 |
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 */ +}; |