This is an old revision of the document!


User-specific boot menus

This page outlines the steps I took to implement a proof of concept comprising user authentication at preboot time and dynamically generated boot menus. The user is first presented with a login screen. The user's credentials are passed via an SSL-encrypted link to a server, which authenticates the user and then provides a boot menu containing a list of authorised boot selections. The list of boot selections can vary according to the user.

Setup (boring part)

Find a suitable Apache web server, complete with valid SSL certificate. Create a directory called “boot” on this web server. For the purpose of this documentation, I will assume that the full URI for this directory is http://my.web.server/boot.

In the “boot” directory, create a file “.htaccess” containing

  SSLRequireSSL

and a file “menu.gpxe” containing

  #!gpxe
  
  imgfree
  login
  kernel -n menu https://${username:uristring}:${password:uristring}@my.web.server/boot/vesamenu.c32 menu.php
  boot menu

Configure your DHCP server to hand out menu.gpxe as the boot file, using something like (for ISC dhcpd)1):

  filename "https://my.web.server/boot/menu.gpxe";

Download the latest syslinux tarball from http://www.kernel.org/pub/linux/utils/boot/syslinux/ and build it. Copy the files com32/menu/vesamenu.c32 and com32/modules/cmd.c322) into the “boot” directory.

Setup (interesting part)

In the “boot” directory, you can now create a file called “menu.php”. This PHP script needs to generate a standard syslinux menu configuration file; the resulting menu will be displayed to the user.

The PHP script will have access to the plaintext of the username and password (in the variables $_SERVER["PHP_AUTH_USER"] and $_SERVER["PHP_AUTH_PW"]). Although the script has access to the plaintext, the traffic over the wire was encrypted with SSL and so is (nominally) not vulnerable to eavesdropping.

You can implement any kind of policy that you like with the script. Here is a trivial proof-of-concept example:

  <?php
  
  header ( 'Content-type: text/plain' );
  
  $username = $_SERVER["PHP_AUTH_USER"];
  $password = $_SERVER["PHP_AUTH_PW"];
  
  $index = 0;
  
  function title ( $title ) {
    global $username;
    echo "menu title ".$title;
    echo ( $username ? " for ".$username : "" )."\n";
  }
  
  function label ( $label ) {
    global $index;
    $index++;
    echo "label item".$index."\n";
    echo "  menu label ";
    echo "^".( ( $index < 10 ) ? $index :
               sprintf ( "%c", $index + ord ( 'A' ) - 10 ) )." ";
    echo $label."\n";
  }
  
  function sanboot ( $label, $root_path ) {
    label ( $label );
    echo "  kernel cmd.c32\n";
    echo "  append sanboot ".$root_path."\n";
    echo "\n";
  }
  
  function uriboot ( $label, $uri, $args ) {
    label ( $label );
    echo "  kernel ".$uri."\n";
    if ( $args )
        echo "  append ".$args."\n";
  }
  
  function retry () {
    echo "label failed\n";
    echo "  menu label Authentication Failed\n";
    echo "  menu disable\n";
    uriboot ( "Try again", "menu.gpxe", "" );
  }
  
  function authenticated () {
    global $username;
    global $password;
  
    switch ( "$username:$password" ) {
    case "mcb30:password":
    case "guest:guest":
      return 1;
    default:
      return 0;
    }
  }
  
  ?>
  
  menu background atlantis.png
  prompt 0
  timeout 100
  allowoptions 0
  menu timeoutrow 29
  menu vshift 2
  menu rows 8
  menu color title  1;36;44   #ff8bc2ff #00000000 std
  menu color unsel  37;44     #ff1069c5 #00000000 std
  menu color sel    7;37;40   #ff000000 #ffff7518 all
  menu color hotkey 1;37;44   #ffffffff #00000000 std
  menu color hotsel 1;7;37;40 #ff000431 #ffff7518 all
  
  <?
  
  title ( "Secure Network Boot" );
  
  if ( ! authenticated() ) {
    retry();
  } else {
  
    if ( $username == "mcb30" ) {
  
      sanboot ( "MS-DOS 6.22",
                "iscsi:chipmunk.tuntap::::iqn.2007-07.chipmunk:msdos622" );
  
      sanboot ( "Windows 2k3",
                "iscsi:chipmunk.tuntap::::iqn.2007-07.chipmunk:win2k3" );
  
    }
  
    uriboot ( "Linux rescue shell",
              "http://chipmunk.tuntap/images/uniboot/uniboot.php", "" );
  }
  
  ?>

This sample script authenticates the user against a hardcoded password list and then generates a boot menu. User mcb30 will receive the option of booting MS-DOS, Windows 2003 or Linux, user guest will receive only the option of booting Linux. If authentication fails, the user is redirected back to the login screen.

Screenshots

When first booting, the user sees this login screen:

Login screen

After authenticating correctly as mcb30, the user sees this menu screen:

Menu screen

This was generated by menu.php as:

  menu background atlantis.png
  prompt 0
  timeout 100
  allowoptions 0
  menu timeoutrow 29
  menu vshift 2
  menu rows 8
  menu color title  1;36;44   #ff8bc2ff #00000000 std
  menu color unsel  37;44     #ff1069c5 #00000000 std
  menu color sel    7;37;40   #ff000000 #ffff7518 all
  menu color hotkey 1;37;44   #ffffffff #00000000 std
  menu color hotsel 1;7;37;40 #ff000431 #ffff7518 all
  
  menu title Secure Network Boot for mcb30
  label item1
    menu label ^1 MS-DOS 6.22
    kernel cmd.c32
    append sanboot iscsi:chipmunk.tuntap::::iqn.2007-07.chipmunk:msdos622
  
  label item2
    menu label ^2 Windows 2k3
    kernel cmd.c32
    append sanboot iscsi:chipmunk.tuntap::::iqn.2007-07.chipmunk:win2k3
  
  label item3
    menu label ^3 Linux rescue shell
    kernel http://chipmunk.tuntap/images/uniboot/uniboot.php

Further reading

The syntax of the generated menu files is documented within the syslinux project at http://syslinux.zytor.com/wiki/index.php/Comboot/menu.c32 and http://syslinux.zytor.com/wiki/index.php/SYSLINUX.

1)
If you are using PXE-chaining, you may want to investigate the various methods for avoiding infinite loops described in the PXE chainloading HowTo.
2)
At the time of writing, cmd.c32 is not yet integrated into a syslinux release; you will need to apply the patch from http://rom.etherboot.org/share/mcb30/syslinux-cmd.patch before building syslinux, or just grab the prebuild cmd.c32 binary from http://rom.etherboot.org/share/mcb30/cmd.c32.

QR Code
QR Code appnotes:authmenus (generated for current page)