<?php

/**
 * LibreSchool PXEServer dispatcher
 *
 * This script manages the loading of the PXE image, based on specific
 * host preferences.
 * 
 * php version 5.4.16
 *
 * @category  Client_Management
 * @package   Libreschool
 * @author    Paolo Asperti <paolo@asperti.com>
 * @copyright 2020 The LibreSchool project
 * @license   https://www.gnu.org/licenses/gpl-3.0.en.html GPL-3.0
 * @version   GIT: $Id$
 * @link      https://git.libreschool.org/LibreSchool/libreschool-pxeserver
 * @since     1.0.0
 */

require_once "EsmithDatabase.php";

$hosts_db = new EsmithDatabase('hosts');

/** 
 * Check if specified mac address is valid
 * 
 * We should've used filter_var($mac, FILTER_VALIDATE_MAC) but it's available
 * from PHP 5.5.0 and we have 5.4.16. Too bad.
 * 
 * @param string $mac the mac address to examine
 * 
 * @return bool if the macaddress is valid or not
 */
function isValidMAC($mac) {
    if (preg_match('/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/', $mac)) {
        // 01:23:45:67:89:ab
        return true;
    } elseif (preg_match('/^([a-fA-F0-9]{2}\-){5}[a-fA-F0-9]{2}$/', $mac)) {
        // 01-23-45-67-89-ab
        return true;
    } elseif (preg_match('/^[a-fA-F0-9]{12}$/', $mac)) {
        // 0123456789ab
        return true;
    } else if (preg_match('/^([a-fA-F0-9]{4}\.){2}[a-fA-F0-9]{4}$/', $mac)) {
        // 0123.4567.89ab
        return true;
    } else {
        return false;
    }
}

/** 
 * Get the client corresponding a specific mac address
 * 
 * @param string $mac the mac address of the client
 * 
 * @return host||boolean client if found, false otherwise
 */
function getClientFromMAC($mac=false) {
    global $hosts_db;
    $hosts = $hosts_db->getAllByProp('MacAddress', $mac);
    if (count($hosts)>0) {
        return array_pop($hosts);
    } else {
        return false;
    }
}

/** 
 * Default exit string
 * This string will instruct to reload the script 
 * passing the mac address of the calling machine
 * 
 * @return null
 */
function defaultExit() {
    print("#!ipxe
# reload with mac address
chain http://".$_SERVER['HTTP_HOST'].$_SERVER["SCRIPT_NAME"]."?mac=\${mac}
    ");
    exit();
}


/** 
 * Check if specified PXE image exists
 * 
 * @param string $i image name
 * 
 * @return bool if the image exists or not
 */
function imageExists($i) {
    $pwd = dirname(__FILE__);
    $dir = $pwd . '/' . $i;
    $bootfile = $dir . '/boot'; 
    $iso_is_mounted = $dir . '/iso_is_mounted'; 
    $iso_ok = ! file_exists($iso_is_mounted) || 
        (is_link($iso_is_mounted) && is_readable($iso_is_mounted));
    return is_dir($dir) && is_readable($bootfile) && $iso_ok;
}

if (!isset($_REQUEST['mac'])) {
    defaultExit();
}
if (empty($_REQUEST['mac'])) {
    defaultExit();
}
if (!isValidMAC($_REQUEST['mac'])) {
    defaultExit();
}
$mac = $_REQUEST['mac'];
$client = getClientFromMAC($mac);
if (!$client) {
    // TODO: make up a default for unknown clients
    defaultExit();
}

if (isset($client['PXEImageOneTime']) && !empty($client['PXEImageOneTime'])) {
    // try to boot the OneTime image
    if (imageExists($client['PXEImageOneTime'])) {
        print("#!ipxe
# Loading PXEImageOneTime
chain " . $client['PXEImageOneTime'] . "/boot
        ");
        $props = array(
            'PXEImageOneTime' => ''
        );
        $hosts_db->setProp($client['name'], $props);
        exit();
    }
}

if (isset($client['PXEImage']) && !empty($client['PXEImage'])) {
    // try to boot the standard image
    if (imageExists($client['PXEImage'])) {
        print("#!ipxe
# Loading PXEImage
chain " . $client['PXEImage'] . "/boot
        ");
        exit();
    }
}

print("#!ipxe
# catchall
chain localhd/boot
");