6b2dd0f
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
f4c76c0
From: Robert Marshall <rmarshall@redhat.com>
f4c76c0
Date: Thu, 25 Jun 2015 11:13:11 -0400
31cddd6
Subject: [PATCH] Add friendly grub2 password config tool (#985962)
f4c76c0
f4c76c0
Provided a tool for users to reset the grub2 root user password
f4c76c0
without having to alter the grub.cfg. The hashed password now
f4c76c0
lives in a root-only-readable configuration file.
f4c76c0
f4c76c0
Resolves: rhbz#985962
7e98da0
7e98da0
Signed-off-by: Robert Marshall <rmarshall@redhat.com>
7e98da0
[pjones: fix the efidir in grub-setpassword and rename tool]
7e98da0
Signed-off-by: Peter Jones <pjones@redhat.com>
7e98da0
[luto: fix grub-setpassword -o's output path]
bd73b85
Signed-off-by: Andy Lutomirski <luto@kernel.org>
3d407d2
[rharwood: migrate man page to h2m, context]
bd73b85
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
f4c76c0
---
bd73b85
 configure.ac                   |   1 +
bd73b85
 Makefile.util.def              |  13 +++++
bd73b85
 docs/man/grub-set-password.h2m |   2 +
bd73b85
 util/grub-mkconfig.in          |   2 +
bd73b85
 util/grub-set-password.in      | 128 +++++++++++++++++++++++++++++++++++++++++
bd73b85
 util/grub.d/01_users.in        |  11 ++++
bd73b85
 6 files changed, 157 insertions(+)
bd73b85
 create mode 100644 docs/man/grub-set-password.h2m
7e98da0
 create mode 100644 util/grub-set-password.in
f4c76c0
 create mode 100644 util/grub.d/01_users.in
f4c76c0
ec4acbb
diff --git a/configure.ac b/configure.ac
3d407d2
index 8331f95b64..7f59ad788f 100644
ec4acbb
--- a/configure.ac
ec4acbb
+++ b/configure.ac
46968b6
@@ -72,6 +72,7 @@ grub_TRANSFORM([grub-mkrelpath])
ec4acbb
 grub_TRANSFORM([grub-mkrescue])
ec4acbb
 grub_TRANSFORM([grub-probe])
ec4acbb
 grub_TRANSFORM([grub-reboot])
7e98da0
+grub_TRANSFORM([grub-set-password])
ec4acbb
 grub_TRANSFORM([grub-script-check])
ec4acbb
 grub_TRANSFORM([grub-set-default])
3d407d2
 grub_TRANSFORM([grub-sparc64-setup])
f4c76c0
diff --git a/Makefile.util.def b/Makefile.util.def
3d407d2
index 2c9b283a23..4ee22c5daa 100644
f4c76c0
--- a/Makefile.util.def
f4c76c0
+++ b/Makefile.util.def
46968b6
@@ -452,6 +452,12 @@ script = {
da63b36
   installdir = grubconf;
f4c76c0
 };
f4c76c0
 
da63b36
+script = {
f4c76c0
+  name = '01_users';
f4c76c0
+  common = util/grub.d/01_users.in;
f4c76c0
+  installdir = grubconf;
f4c76c0
+};
f4c76c0
+
da63b36
 script = {
f4c76c0
   name = '10_windows';
f4c76c0
   common = util/grub.d/10_windows.in;
3d407d2
@@ -724,6 +730,13 @@ script = {
da63b36
   installdir = sbin;
f4c76c0
 };
f4c76c0
 
da63b36
+script = {
7e98da0
+  name = grub-set-password;
7e98da0
+  common = util/grub-set-password.in;
f4c76c0
+  mansection = 8;
f4c76c0
+  installdir = sbin;
f4c76c0
+};
f4c76c0
+
da63b36
 script = {
f4c76c0
   name = grub-mkconfig_lib;
f4c76c0
   common = util/grub-mkconfig_lib.in;
bd73b85
diff --git a/docs/man/grub-set-password.h2m b/docs/man/grub-set-password.h2m
bd73b85
new file mode 100644
e622855
index 0000000000..10ee82f4d5
bd73b85
--- /dev/null
bd73b85
+++ b/docs/man/grub-set-password.h2m
bd73b85
@@ -0,0 +1,2 @@
bd73b85
+[NAME]
bd73b85
+grub-set-password \- generate the user.cfg file containing the hashed grub bootloader password
f4c76c0
diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
e622855
index 8ea2315ebc..ba14cf6261 100644
f4c76c0
--- a/util/grub-mkconfig.in
f4c76c0
+++ b/util/grub-mkconfig.in
13985b0
@@ -276,6 +276,8 @@ for i in "${grub_mkconfig_dir}"/* ; do
f4c76c0
     *~) ;;
f4c76c0
     # emacsen autosave files. FIXME: support other editors
f4c76c0
     */\#*\#) ;;
f4c76c0
+    # rpm config files of yore.
f4c76c0
+    *.rpmsave|*.rpmnew|*.rpmorig) ;;
f4c76c0
     *)
f4c76c0
       if grub_file_is_not_garbage "$i" && test -x "$i" ; then
f4c76c0
         echo
7e98da0
diff --git a/util/grub-set-password.in b/util/grub-set-password.in
f4c76c0
new file mode 100644
e622855
index 0000000000..5ebf50576d
f4c76c0
--- /dev/null
7e98da0
+++ b/util/grub-set-password.in
7e98da0
@@ -0,0 +1,128 @@
f4c76c0
+#!/bin/sh -e
f4c76c0
+
7e98da0
+EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/')
f4c76c0
+if [ -d /sys/firmware/efi/efivars/ ]; then
7e98da0
+    grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
f4c76c0
+else
f4c76c0
+    grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
f4c76c0
+fi
f4c76c0
+
f4c76c0
+PACKAGE_VERSION="@PACKAGE_VERSION@"
f4c76c0
+PACKAGE_NAME="@PACKAGE_NAME@"
f4c76c0
+self=`basename $0`
f4c76c0
+bindir="@bindir@"
f4c76c0
+grub_mkpasswd="${bindir}/@grub_mkpasswd_pbkdf2@"
f4c76c0
+
f4c76c0
+# Usage: usage
f4c76c0
+# Print the usage.
f4c76c0
+usage () {
f4c76c0
+    cat <
7e98da0
+Usage: $0 [OPTION]
f4c76c0
+$0 prompts the user to set a password on the grub bootloader. The password
7e98da0
+is written to a file named user.cfg which lives in the GRUB directory
7e98da0
+located by default at ${grubdir}.
7e98da0
+
7e98da0
+  -h, --help                     print this message and exit
7e98da0
+  -v, --version                  print the version information and exit
7e98da0
+  -o, --output_path <DIRECTORY>  put user.cfg in a user-selected directory
f4c76c0
+
f4c76c0
+Report bugs at https://bugzilla.redhat.com.
f4c76c0
+EOF
f4c76c0
+}
f4c76c0
+
f4c76c0
+argument () {
f4c76c0
+    opt=$1
f4c76c0
+    shift
f4c76c0
+
f4c76c0
+    if test $# -eq 0; then
f4c76c0
+        gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2
f4c76c0
+        exit 1
f4c76c0
+    fi
f4c76c0
+    echo $1
f4c76c0
+}
f4c76c0
+
f4c76c0
+# Ensure that it's the root user running this script
f4c76c0
+if [ "${EUID}" -ne 0 ]; then
f4c76c0
+    echo "The grub bootloader password may only be set by root."
f4c76c0
+    usage
f4c76c0
+    exit 2
f4c76c0
+fi
f4c76c0
+
f4c76c0
+# Check the arguments.
f4c76c0
+while test $# -gt 0
f4c76c0
+do
f4c76c0
+    option=$1
f4c76c0
+    shift
f4c76c0
+
f4c76c0
+    case "$option" in
f4c76c0
+    -h | --help)
f4c76c0
+	usage
f4c76c0
+	exit 0 ;;
f4c76c0
+    -v | --version)
f4c76c0
+	echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}"
f4c76c0
+	exit 0 ;;
f4c76c0
+    -o | --output)
f4c76c0
+        OUTPUT_PATH=`argument $option "$@"`; shift ;;
f4c76c0
+    --output=*)
f4c76c0
+        OUTPUT_PATH=`echo "$option" | sed 's/--output=//'` ;;
f4c76c0
+    -o=*)
f4c76c0
+        OUTPUT_PATH=`echo "$option" | sed 's/-o=//'` ;;
f4c76c0
+    esac
f4c76c0
+done
f4c76c0
+
f4c76c0
+# set user input or default path for user.cfg file
f4c76c0
+if [ -z "${OUTPUT_PATH}" ]; then
f4c76c0
+    OUTPUT_PATH="${grubdir}"
f4c76c0
+fi
f4c76c0
+
f4c76c0
+if [ ! -d "${OUTPUT_PATH}" ]; then
f4c76c0
+    echo "${OUTPUT_PATH} does not exist."
f4c76c0
+    usage
f4c76c0
+    exit 2;
f4c76c0
+fi
f4c76c0
+
f4c76c0
+ttyopt=$(stty -g)
f4c76c0
+fixtty() {
f4c76c0
+      stty ${ttyopt}
f4c76c0
+}
f4c76c0
+
f4c76c0
+trap fixtty EXIT
f4c76c0
+stty -echo
f4c76c0
+
f4c76c0
+# prompt & confirm new grub2 root user password
f4c76c0
+echo -n "Enter password: "
f4c76c0
+read PASSWORD
f4c76c0
+echo
f4c76c0
+echo -n "Confirm password: "
f4c76c0
+read PASSWORD_CONFIRM
f4c76c0
+echo
f4c76c0
+stty ${ttyopt}
f4c76c0
+
f4c76c0
+getpass() {
f4c76c0
+    local P0
f4c76c0
+    local P1
f4c76c0
+    P0="$1" && shift
f4c76c0
+    P1="$1" && shift
f4c76c0
+
f4c76c0
+    ( echo ${P0} ; echo ${P1} ) | \
7e98da0
+        LC_ALL=C ${grub_mkpasswd} | \
f4c76c0
+        grep -v '[eE]nter password:' | \
f4c76c0
+        sed -e "s/PBKDF2 hash of your password is //"
f4c76c0
+}
f4c76c0
+
f4c76c0
+MYPASS="$(getpass "${PASSWORD}" "${PASSWORD_CONFIRM}")"
f4c76c0
+if [ -z "${MYPASS}" ]; then
f4c76c0
+      echo "${self}: error: empty password" 1>&2
f4c76c0
+      exit 1
f4c76c0
+fi
f4c76c0
+
f4c76c0
+# on the ESP, these will fail to set the permissions, but it's okay because
f4c76c0
+# the directory is protected.
7e98da0
+install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || :
7e98da0
+chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || :
7e98da0
+echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg"
7e98da0
+
7e98da0
+if ! grep -q "^### BEGIN /etc/grub.d/01_users ###$" "${OUTPUT_PATH}/grub.cfg"; then
7e98da0
+    echo "WARNING: The current configuration lacks password support!"
7e98da0
+    echo "Update your configuration with @grub_mkconfig@ to support this feature."
7e98da0
+fi
f4c76c0
diff --git a/util/grub.d/01_users.in b/util/grub.d/01_users.in
f4c76c0
new file mode 100644
e622855
index 0000000000..db2f44bfb7
f4c76c0
--- /dev/null
f4c76c0
+++ b/util/grub.d/01_users.in
f4c76c0
@@ -0,0 +1,11 @@
f4c76c0
+#!/bin/sh -e
f4c76c0
+cat << EOF
f4c76c0
+if [ -f \${prefix}/user.cfg ]; then
f4c76c0
+  source \${prefix}/user.cfg
9d15b4d
+  if [ -n "\${GRUB2_PASSWORD}" ]; then
f4c76c0
+    set superusers="root"
f4c76c0
+    export superusers
f4c76c0
+    password_pbkdf2 root \${GRUB2_PASSWORD}
f4c76c0
+  fi
f4c76c0
+fi
f4c76c0
+EOF