[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-sparc
Subject:    Patch: allow eeprom(8) to set OBP password
From:       Todd Carson <toc () daybefore ! net>
Date:       2008-01-29 2:53:46
Message-ID: 20080129025346.GA64311 () trystero ! daybefore ! net
[Download RAW message or body]

This is a patch to implement a user interface for changing the
security-mode and security-password PROM options through eeprom(8). This
is useful if, for example, you lose the PROM password for a system with
security-mode set to command, but still have the root password (which
certainly didn't recently happen to me).

The interface is almost identical to that presented by the Solaris
eeprom utility; it prompts for the password using readpassphrase(), and
forces you to change the password at the same time if you raise the
security mode from none. Unlike Solaris, it doesn't subject the
password to (weak) complexity checks, or disallow changing the password
when security-mode is set to none.

I also had to change the handler for the OPIOCSET ioctl; it was returning
EINVAL if the return value from the firmware is not equal to the length of
the new value being set. The firmware returns zero when it sets
security-password successfully, so the kernel should return EINVAL only
if the return code from the firmware is negative.

Below are diffs for eeprom, the sparc64 and sparc openprom drivers, and
the eeprom manpage. They work for me on a Netra t1, a U10, and an SS5.

Index: defs.h
===================================================================
RCS file: /cvs/src/usr.sbin/eeprom/defs.h,v
retrieving revision 1.6
diff -u -r1.6 defs.h
--- defs.h	12 Nov 2007 20:54:54 -0000	1.6
+++ defs.h	29 Jan 2008 02:12:44 -0000
@@ -40,6 +40,8 @@
 #undef BUFSIZE
 #define BUFSIZE		1024
 
+#define	MAX_PASSWD_SIZE	8
+
 #define IO_READ		0
 #define IO_WRITE	1
 
@@ -82,7 +84,7 @@
  */
 struct	extabent {
 	char	*ex_keyword;		/* keyword for this entry */
-	void	(*ex_handler)(struct extabent *, struct opiocdesc *, char *);
+	void	(*ex_handler)(int, struct extabent *, struct opiocdesc *, char *);
 					/* handler function for this entry */
 };
 
Index: eeprom.8
===================================================================
RCS file: /cvs/src/usr.sbin/eeprom/eeprom.8,v
retrieving revision 1.18
diff -u -r1.18 eeprom.8
--- eeprom.8	7 Sep 2007 13:54:43 -0000	1.18
+++ eeprom.8	29 Jan 2008 02:12:45 -0000
@@ -35,7 +35,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: September 7 2007 $
+.Dd $Mdocdate: January 28 2008 $
 .Dt EEPROM 8
 .Os
 .Sh NAME
@@ -337,6 +337,25 @@
 .Xr hme 4
 boards, will respect this setting;
 other hardware will not.
+.It Ar security-password
+This parameter can be written to, but it cannot be read.
+In conjunction with
+.Ar security-mode
+(see below), it specifies a password to protect the PROM
+from unauthorized manipulation.
+Only the first eight characters of this password are used.
+.It Ar security-mode
+When set to
+.Em full ,
+a password is required to boot the system or to execute
+any PROM command except
+.Em go .
+The
+.Em command
+mode is similar, except that it does not require a password
+to boot the system from the default boot device.
+No password is ever required if this option is set to
+.Em none .
 .El
 .Sh FILES
 .Bl -tag -width "/dev/openprom" -compact
@@ -352,10 +371,12 @@
 systems with an OpenPROM.
 Your mileage may vary.
 .Pp
-There are a few fields known to exist in some revisions of the EEPROM
-and/or OpenPROM that are not yet supported.
-Most notable are those
-relating to password protection of the EEPROM or OpenPROM.
+If you set
+.Em security-mode
+to
+.Em full
+and forget the firmware password, you will need to replace the
+PROM chip in order to regain access to the system.
 .Pp
 Avoid gratuitously changing the contents of the EEPROM.
 It has a limited number of write cycles.
Index: ophandlers.c
===================================================================
RCS file: /cvs/src/usr.sbin/eeprom/ophandlers.c,v
retrieving revision 1.11
diff -u -r1.11 ophandlers.c
--- ophandlers.c	12 Nov 2007 20:54:54 -0000	1.11
+++ ophandlers.c	29 Jan 2008 02:12:50 -0000
@@ -42,6 +42,7 @@
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <readpassphrase.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -59,7 +60,9 @@
 
 static	char err_str[BUFSIZE];
 
-static	void op_notsupp(struct extabent *, struct opiocdesc *, char *);
+static	void op_notsupp(int, struct extabent *, struct opiocdesc *, char *);
+static	void op_password(int, struct extabent *, struct opiocdesc *, char *);
+static	void op_security(int, struct extabent *, struct opiocdesc *, char *);
 static	void op_print(char *);
 
 /*
@@ -67,8 +70,8 @@
  * deal with or require special treatment.
  */
 static	struct extabent opextab[] = {
-	{ "security-password",		op_notsupp },
-	{ "security-mode",		op_notsupp },
+	{ "security-password",		op_password },
+	{ "security-mode",		op_security },
 	{ "oem-logo",			op_notsupp },
 	{ NULL,				op_notsupp },
 };
@@ -119,13 +122,13 @@
 			}
 
 			if (ex->ex_keyword != NULL)
-				(*ex->ex_handler)(ex, &opio, NULL);
+				(*ex->ex_handler)(fd, ex, &opio, NULL);
 			else
 				op_print(opio.op_buf);
 		}
  out:
 		if (ex->ex_keyword != NULL)
-			(*ex->ex_handler)(ex, &opio, arg);
+			(*ex->ex_handler)(fd, ex, &opio, arg);
 		else {
 			opio.op_buf = arg;
 			opio.op_buflen = strlen(arg);
@@ -137,7 +140,7 @@
 		if (verbose) {
 			printf("new: ");
 			if (ex->ex_keyword != NULL)
-				(*ex->ex_handler)(ex, &opio, NULL);
+				(*ex->ex_handler)(fd, ex, &opio, NULL);
 			else
 				op_print(opio.op_buf);
 		}
@@ -155,7 +158,7 @@
 		}
 
 		if (ex->ex_keyword != NULL)
-			(*ex->ex_handler)(ex, &opio, NULL);
+			(*ex->ex_handler)(fd, ex, &opio, NULL);
 		else {
 			printf("%s=", keyword);
 			op_print(opio.op_buf);
@@ -168,12 +171,95 @@
 
 /* ARGSUSED */
 static void
-op_notsupp(struct extabent *exent, struct opiocdesc *opiop, char *arg)
+op_notsupp(int fd, struct extabent *exent, struct opiocdesc *opiop, char *arg)
 {
-
 	warnx("property `%s' not yet supported", exent->ex_keyword);
 }
 
+static void
+op_password(int fd, struct extabent *exent, struct opiocdesc *opiop, char *arg)
+{
+	static char password_buf[MAX_PASSWD_SIZE + 1];
+	char retype_buf[MAX_PASSWD_SIZE + 1];
+	
+	if (arg == NULL) {
+		printf("%s not displayed\n", exent->ex_keyword);
+		return;
+	}
+
+again:
+	printf("Changing PROM password. Only the first %d characters are used.\n",
+	    MAX_PASSWD_SIZE);
+	if ((readpassphrase("New password:", password_buf,
+	    sizeof(password_buf), 0) == NULL) ||
+	    (readpassphrase("Retype new password:", retype_buf,
+	    sizeof(retype_buf), 0) == NULL))
+		errx(1, "error reading PROM password");
+	if (strcmp(password_buf, retype_buf)) {
+		printf("They don't match; try again.\n");
+		goto again;
+	}
+	bzero(retype_buf, sizeof(retype_buf));
+	opiop->op_buf = password_buf;
+	opiop->op_buflen = strlen(password_buf);
+}
+
+static void
+op_security(int fd, struct extabent *exent, struct opiocdesc *opiop, char *arg)
+{
+	char opio_buf[BUFSIZE];
+	char *prev_mode;
+	struct opiocdesc opio_passwd;
+
+	if (arg == NULL) {
+		if (opiop->op_buflen > 0) {
+			printf("%s=", exent->ex_keyword);
+			op_print(opiop->op_buf);
+		}
+	} else {
+		/* Get the current security mode, if the caller didn't. */
+		if (opiop->op_buf == NULL) {
+			opiop->op_buf = opio_buf;
+			opiop->op_buflen = sizeof(opio_buf);
+			if (ioctl(fd, OPIOCGET, (char *)opiop) < 0) {
+				warn("OPIOCGET");
+				return;
+			}
+		}
+		prev_mode = opiop->op_buf;
+		opiop->op_buf = NULL;
+		opiop->op_buflen = 0;
+		/*
+		 * Prompt the user for a password if changing from security-mode
+		 * none to command or full. Clear the password if changing to
+		 * security-mode none. This isn't imposed by the OBP; it's to
+		 * protect users from bricking their systems by setting a
+		 * security mode and forgetting to set the password.
+		 */
+		bzero(&opio_passwd, sizeof(opio_passwd));
+		opio_passwd.op_nodeid = opiop->op_nodeid;
+		opio_passwd.op_name = "security-password";
+		opio_passwd.op_namelen = strlen(opio_passwd.op_name);
+		if ((!strcmp(arg, "command")) || (!strcmp(arg, "full"))) {
+			if (!strcmp(prev_mode, "none"))
+				op_password(fd, exent, &opio_passwd, "");
+		} else if (!strcmp(arg, "none")) {
+			bzero(&opio_buf, MAX_PASSWD_SIZE);
+			opio_passwd.op_buf = opio_buf;
+			opio_passwd.op_buflen = MAX_PASSWD_SIZE;
+		} else {
+			warnx("invalid security mode: %s", arg);
+			return;
+		}
+		if (ioctl(fd, OPIOCSET, (char *)&opio_passwd) < 0) {
+			warn("OPIOCSET");
+			return;
+		}
+		opiop->op_buf = arg;
+		opiop->op_buflen = strlen(arg);
+	}
+}
+
 /*
  * XXX: This code is quite ugly.  You have been warned.
  * (Really!  This is the only way I could get it to work!)
@@ -249,7 +335,7 @@
 				break;
 
 		if (ex->ex_keyword != NULL)
-			(*ex->ex_handler)(ex, &opio2, NULL);
+			(*ex->ex_handler)(fd, ex, &opio2, NULL);
 		else {
 			printf("%s=", opio2.op_name);
 			op_print(opio2.op_buf);

Index: openprom.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/sparc64/openprom.c,v
retrieving revision 1.13
diff -u -r1.13 openprom.c
--- openprom.c	13 Nov 2007 13:50:10 -0000	1.13
+++ openprom.c	29 Jan 2008 02:15:11 -0000
@@ -194,7 +194,7 @@
 		s = splhigh();
 		len = OF_setprop(node, name, value, op->op_buflen + 1);
 		splx(s);
-		if (len != op->op_buflen)
+		if (len < 0)
 			error = EINVAL;
 		break;

Index: openprom.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc/sparc/openprom.c,v
retrieving revision 1.5
diff -u -r1.5 openprom.c
--- openprom.c	2 Jun 2003 23:27:55 -0000	1.5
+++ openprom.c	29 Jan 2008 02:15:51 -0000
@@ -198,7 +198,7 @@
 		s = splhigh();
 		len = no->no_setprop(node, name, value, op->op_buflen + 1);
 		splx(s);
-		if (len != op->op_buflen)
+		if (len < 0)
 			error = EINVAL;
 		break;

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic