summaryrefslogtreecommitdiffstats
path: root/modules-available/serversetup-bwlp/inc
diff options
context:
space:
mode:
authorSimon Rettberg2019-02-12 14:55:12 +0100
committerSimon Rettberg2019-02-12 14:55:12 +0100
commitc2a6dfb649107ce3ad64162e2bb2c3c7275650fb (patch)
tree5a58f34c9c2563bb9baebcf7a36afe3e1d08a120 /modules-available/serversetup-bwlp/inc
parent[serversetup-bwlp] Auto-import of old PXELinux config on bootup (diff)
downloadslx-admin-c2a6dfb649107ce3ad64162e2bb2c3c7275650fb.tar.gz
slx-admin-c2a6dfb649107ce3ad64162e2bb2c3c7275650fb.tar.xz
slx-admin-c2a6dfb649107ce3ad64162e2bb2c3c7275650fb.zip
[serversetup*] PXELinux and iPXE side-by-side
Diffstat (limited to 'modules-available/serversetup-bwlp/inc')
-rw-r--r--modules-available/serversetup-bwlp/inc/bootentry.inc.php258
-rw-r--r--modules-available/serversetup-bwlp/inc/ipxe.inc.php453
-rw-r--r--modules-available/serversetup-bwlp/inc/ipxemenu.inc.php142
-rw-r--r--modules-available/serversetup-bwlp/inc/localboot.inc.php15
-rw-r--r--modules-available/serversetup-bwlp/inc/menuentry.inc.php177
-rw-r--r--modules-available/serversetup-bwlp/inc/pxelinux.inc.php302
6 files changed, 0 insertions, 1347 deletions
diff --git a/modules-available/serversetup-bwlp/inc/bootentry.inc.php b/modules-available/serversetup-bwlp/inc/bootentry.inc.php
deleted file mode 100644
index 69adffd3..00000000
--- a/modules-available/serversetup-bwlp/inc/bootentry.inc.php
+++ /dev/null
@@ -1,258 +0,0 @@
-<?php
-
-abstract class BootEntry
-{
-
- public function __construct($data = false)
- {
- if (is_array($data)) {
- foreach ($data as $key => $value) {
- if (property_exists($this, $key)) {
- $this->{$key} = $value;
- }
- }
- }
- }
-
- public abstract function supportsMode($mode);
-
- public abstract function toScript($failLabel, $mode);
-
- public abstract function toArray();
-
- public abstract function addFormFields(&$array);
-
- /*
- *
- */
-
- /**
- * Return a BootEntry instance from the serialized data.
- *
- * @param string $jsonString serialized entry data
- * @return BootEntry|null instance representing boot entry, null on error
- */
- public static function fromJson($data)
- {
- if (is_string($data)) {
- $data = json_decode($data, true);
- }
- if (isset($data['script'])) {
- return new CustomBootEntry($data);
- }
- if (isset($data['executable'])) {
- return new StandardBootEntry($data);
- }
- return null;
- }
-
- public static function newStandardBootEntry($initData)
- {
- $ret = new StandardBootEntry($initData);
- $list = [];
- if ($ret->arch() !== StandardBootEntry::EFI) {
- $list[] = StandardBootEntry::BIOS;
- }
- if ($ret->arch() === StandardBootEntry::EFI || $ret->arch() === StandardBootEntry::BOTH) {
- $list[] = StandardBootEntry::EFI;
- }
- foreach ($list as $mode) {
- if (empty($initData['executable'][$mode]))
- return null;
- }
- return $ret;
- }
-
- public static function newCustomBootEntry($initData)
- {
- if (empty($initData['script']))
- return null;
- return new CustomBootEntry($initData);
- }
-
- /**
- * Return a BootEntry instance from database with the given id.
- *
- * @param string $id
- * @return BootEntry|null|false false == unknown id, null = unknown entry type, BootEntry instance on success
- */
- public static function fromDatabaseId($id)
- {
- $row = Database::queryFirst("SELECT data FROM serversetup_bootentry
- WHERE entryid = :id LIMIT 1", ['id' => $id]);
- if ($row === false)
- return false;
- return self::fromJson($row['data']);
- }
-
-}
-
-class StandardBootEntry extends BootEntry
-{
- protected $executable;
- protected $initRd;
- protected $commandLine;
- protected $replace;
- protected $autoUnload;
- protected $resetConsole;
- protected $arch; // Constants below
-
- const BIOS = 'PCBIOS'; // Only valid for legacy BIOS boot
- const EFI = 'EFI'; // Only valid for EFI boot
- const BOTH = 'PCBIOS-EFI'; // Supports both via distinct entry
- const AGNOSTIC = 'agnostic'; // Supports both via same entry (PCBIOS entry)
-
- public function __construct($data = false)
- {
- if ($data instanceof PxeSection) {
- // Gets arrayfied below
- $this->executable = $data->kernel;
- $this->initRd = $data->initrd;
- $this->commandLine = ' ' . str_replace('vga=current', '', $data->append) . ' ';
- $this->resetConsole = true;
- $this->replace = true;
- $this->autoUnload = true;
- if (strpos($this->commandLine, ' quiet ') !== false) {
- $this->commandLine .= ' loglevel=5 rd.systemd.show_status=auto';
- }
- if ($data->ipAppend & 1) {
- $this->commandLine .= ' ${ipappend1}';
- }
- if ($data->ipAppend & 2) {
- $this->commandLine .= ' ${ipappend2}';
- }
- if ($data->ipAppend & 4) {
- $this->commandLine .= ' SYSUUID=${uuid}';
- }
- $this->commandLine = trim(preg_replace('/\s+/', ' ', $this->commandLine));
- } else {
- parent::__construct($data);
- }
- // Convert legacy DB format
- foreach (['executable', 'initRd', 'commandLine', 'replace', 'autoUnload', 'resetConsole'] as $key) {
- if (!is_array($this->{$key})) {
- $this->{$key} = [ 'PCBIOS' => $this->{$key}, 'EFI' => '' ];
- }
- }
- if ($this->arch === null) {
- $this->arch = self::AGNOSTIC;
- }
- }
-
- public function arch()
- {
- return $this->arch;
- }
-
- public function supportsMode($mode)
- {
- if ($mode === $this->arch || $this->arch === self::AGNOSTIC)
- return true;
- if ($mode === self::BIOS || $mode === self::EFI) {
- return $this->arch === self::BOTH;
- }
- error_log('Unknown iPXE platform: ' . $mode);
- return false;
- }
-
- public function toScript($failLabel, $mode)
- {
- if (!$this->supportsMode($mode)) {
- return "prompt Entry doesn't have an executable for mode $mode\n";
- }
- if ($this->arch === self::AGNOSTIC) {
- $mode = self::BIOS;
- }
-
- $script = '';
- if ($this->resetConsole[$mode]) {
- $script .= "console ||\n";
- }
- if (!empty($this->initRd[$mode])) {
- $script .= "imgfree ||\n";
- if (!is_array($this->initRd[$mode])) {
- $script .= "initrd {$this->initRd[$mode]} || goto $failLabel\n";
- } else {
- foreach ($this->initRd[$mode] as $initrd) {
- $script .= "initrd $initrd || goto $failLabel\n";
- }
- }
- }
- $script .= "boot ";
- if ($this->autoUnload[$mode]) {
- $script .= "-a ";
- }
- if ($this->replace[$mode]) {
- $script .= "-r ";
- }
- $script .= $this->executable[$mode];
- $rdBase = basename($this->initRd[$mode]);
- if (!empty($this->commandLine[$mode])) {
- $script .= " initrd=$rdBase {$this->commandLine[$mode]}";
- }
- $script .= " || goto $failLabel\n";
- if ($this->resetConsole[$mode]) {
- $script .= "goto start ||\n";
- }
- return $script;
- }
-
- public function addFormFields(&$array)
- {
- $array[$this->arch . '_selected'] = 'selected';
- foreach ([self::BIOS, self::EFI] as $mode) {
- $array['entries'][] = [
- 'is' . $mode => true,
- 'mode' => $mode,
- 'executable' => $this->executable[$mode],
- 'initRd' => $this->initRd[$mode],
- 'commandLine' => $this->commandLine[$mode],
- 'replace_checked' => $this->replace[$mode] ? 'checked' : '',
- 'autoUnload_checked' => $this->autoUnload[$mode] ? 'checked' : '',
- 'resetConsole_checked' => $this->resetConsole[$mode] ? 'checked' : '',
- ];
- }
- $array['exec_checked'] = 'checked';
- }
-
- public function toArray()
- {
- return [
- 'executable' => $this->executable,
- 'initRd' => $this->initRd,
- 'commandLine' => $this->commandLine,
- 'replace' => $this->replace,
- 'autoUnload' => $this->autoUnload,
- 'resetConsole' => $this->resetConsole,
- 'arch' => $this->arch,
- ];
- }
-}
-
-class CustomBootEntry extends BootEntry
-{
- protected $script;
-
- public function supportsMode($mode)
- {
- return true;
- }
-
- public function toScript($failLabel, $mode)
- {
- return str_replace('%fail%', $failLabel, $this->script) . "\n";
- }
-
- public function addFormFields(&$array)
- {
- $array['entry'] = [
- 'script' => $this->script,
- ];
- $array['script_checked'] = 'checked';
- }
-
- public function toArray()
- {
- return ['script' => $this->script];
- }
-}
diff --git a/modules-available/serversetup-bwlp/inc/ipxe.inc.php b/modules-available/serversetup-bwlp/inc/ipxe.inc.php
deleted file mode 100644
index d34839f0..00000000
--- a/modules-available/serversetup-bwlp/inc/ipxe.inc.php
+++ /dev/null
@@ -1,453 +0,0 @@
-<?php
-
-class IPxe
-{
-
- /**
- * Import all IP-Range based pxe menus from the given directory.
- *
- * @param string $configPath The pxelinux.cfg path where to look for menu files in hexadecimal IP format.
- * @return Number of menus imported
- */
- public static function importPxeMenus($configPath)
- {
- $importCount = 0;
- $menus = [];
- foreach (glob($configPath . '/*', GLOB_NOSORT) as $file) {
- if (!is_file($file) || !preg_match('~/[A-F0-9]{1,8}$~', $file))
- continue;
- $content = file_get_contents($file);
- if ($content === false)
- continue;
- $file = basename($file);
- $start = hexdec(str_pad($file,8, '0'));
- $end = hexdec(str_pad($file,8, 'f')); // TODO ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^PREFIX
- error_log('From ' . long2ip($start) . ' to ' . long2ip($end));
- $res = Database::simpleQuery("SELECT locationid, startaddr, endaddr FROM subnet
- WHERE startaddr >= :start AND endaddr <= :end", compact('start', 'end'));
- $locations = [];
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
- foreach ($locations as &$loc) {
- if ($row['startaddr'] <= $loc['startaddr'] && $row['endaddr'] >= $loc['endaddr']) {
- $loc = false;
- } elseif ($row['startaddr'] >= $loc['startaddr'] && $row['endaddr'] <= $loc['endaddr']) {
- continue 2;
- }
- }
- unset($loc);
- $locations[] = $row;
- }
- $menu = PxeLinux::parsePxeLinux($content);
- $key = $menu->hash(true);
- if (isset($menus[$key])) {
- $menuId = $menus[$key];
- $defId = null;
- // Figure out the default label, get it's label name
- foreach ($menu->sections as $section) {
- if ($section->isDefault) {
- $defId = $section;
- } elseif ($defId === null && $section->label === $menu->timeoutLabel) {
- $defId = $section;
- }
- }
- if ($defId !== null) {
- $defId = self::cleanLabelFixLocal($defId);
- // Confirm it actually exists (it should since the menu seems identical) and get menuEntryId
- $me = Database::queryFirst('SELECT m.defaultentryid, me.menuentryid FROM serversetup_bootentry be
- INNER JOIN serversetup_menuentry me ON (be.entryid = me.entryid)
- INNER JOIN serversetup_menu m ON (m.menuid = me.menuid)
- WHERE be.entryid = :id AND me.menuid = :menuid',
- ['id' => $defId, 'menuid' => $menuId]);
- if ($me === false || $me['defaultentryid'] == $me['menuentryid']) {
- $defId = null; // Not found, or is already default - don't override if it's the same
- } else {
- $defId = $me['menuentryid'];
- }
- }
- } else {
- $menuId = self::insertMenu($menu, 'Imported', false, 0, [], []);
- $menus[$key] = $menuId;
- $defId = null;
- $importCount++;
- }
- if ($menuId === false)
- continue;
- foreach ($locations as $loc) {
- if ($loc === false)
- continue;
- Database::exec('INSERT IGNORE INTO serversetup_menu_location (menuid, locationid, defaultentryid)
- VALUES (:menuid, :locationid, :def)', [
- 'menuid' => $menuId,
- 'locationid' => $loc['locationid'],
- 'def' => $defId,
- ]);
- }
- }
- return $importCount;
- }
-
- public static function importLegacyMenu($force = false)
- {
- if (!$force && false !== Database::queryFirst("SELECT entryid FROM serversetup_bootentry WHERE entryid = 'bwlp-default'"))
- return false; // Already exists
- // Now create the default entry
- self::createDefaultEntries();
- $prepend = ['bwlp-default' => false, 'localboot' => false];
- $defaultLabel = 'bwlp-default';
- $menuTitle = 'bwLehrpool Bootauswahl';
- $pxeConfig = '';
- $timeoutSecs = 60;
- // Try to import any customization
- $oldMenu = Property::getBootMenu();
- if (is_array($oldMenu)) {
- //
- if (isset($oldMenu['timeout'])) {
- $timeoutSecs = (int)$oldMenu['timeout'];
- }
- if (isset($oldMenu['defaultentry'])) {
- if ($oldMenu['defaultentry'] === 'net') {
- $defaultLabel = 'bwlp-default';
- } elseif ($oldMenu['defaultentry'] === 'hdd') {
- $defaultLabel = 'localboot';
- } elseif ($oldMenu['defaultentry'] === 'custom') {
- $defaultLabel = 'custom';
- }
- }
- if (!empty($oldMenu['custom'])) {
- $pxeConfig = $oldMenu['custom'];
- }
- }
- $append = [
- '',
- 'bwlp-default-dbg' => false,
- '',
- 'poweroff' => false,
- ];
- return self::insertMenu(PxeLinux::parsePxeLinux($pxeConfig), $menuTitle, $defaultLabel, $timeoutSecs, $prepend, $append);
- }
-
- /**
- * @param PxeMenu $pxeMenu
- * @param string $menuTitle
- * @param string|false $defaultLabel
- * @param $defaultTimeoutSeconds
- * @param $prepend
- * @param $append
- * @return bool|int
- */
- private static function insertMenu($pxeMenu, $menuTitle, $defaultLabel, $defaultTimeoutSeconds, $prepend, $append)
- {
- $timeoutMs = [];
- $menuEntries = $prepend;
- settype($menuEntries, 'array');
- if (!empty($pxeMenu)) {
- $pxe =& $pxeMenu;
- if (!empty($pxe->title)) {
- $menuTitle = $pxe->title;
- }
- if ($pxe->timeoutLabel !== null) {
- $defaultLabel = $pxe->timeoutLabel;
- }
- $timeoutMs[] = $pxe->timeoutMs;
- $timeoutMs[] = $pxe->totalTimeoutMs;
- foreach ($pxe->sections as $section) {
- if ($section->localBoot || preg_match('/chain\.c32$/i', $section->kernel)) {
- $menuEntries['localboot'] = 'localboot';
- continue;
- }
- if ($section->label === null) {
- if (!$section->isHidden && !empty($section->title)) {
- $menuEntries[] = $section->title;
- }
- continue;
- }
- if (empty($section->kernel)) {
- if (!$section->isHidden && !empty($section->title)) {
- $menuEntries[] = $section->title;
- }
- continue;
- }
- $entry = self::pxe2BootEntry($section);
- if ($entry === null)
- continue;
- $label = self::cleanLabelFixLocal($section);
- if ($defaultLabel === $section->label) {
- $defaultLabel = $label;
- }
- $hotkey = MenuEntry::filterKeyName($section->hotkey);
- // Create boot entry
- $data = $entry->toArray();
- Database::exec('INSERT IGNORE INTO serversetup_bootentry (entryid, hotkey, title, builtin, data)
- VALUES (:label, :hotkey, :title, 0, :data)', [
- 'label' => $label,
- 'hotkey' => $hotkey,
- 'title' => self::sanitizeIpxeString($section->title),
- 'data' => json_encode($data),
- ]);
- $menuEntries[$label] = $section;
- }
- }
- if (is_array($append)) {
- $menuEntries += $append;
- }
- if (empty($menuEntries))
- return false;
- // Make menu
- $timeoutMs = array_filter($timeoutMs, 'is_int');
- if (empty($timeoutMs)) {
- $timeoutMs = (int)($defaultTimeoutSeconds * 1000);
- } else {
- $timeoutMs = min($timeoutMs);
- }
- $isDefault = (int)(Database::queryFirst('SELECT menuid FROM serversetup_menu WHERE isdefault = 1') === false);
- Database::exec("INSERT INTO serversetup_menu (timeoutms, title, defaultentryid, isdefault)
- VALUES (:timeoutms, :title, NULL, :isdefault)", [
- 'title' => self::sanitizeIpxeString($menuTitle),
- 'timeoutms' => $timeoutMs,
- 'isdefault' => $isDefault,
- ]);
- $menuId = Database::lastInsertId();
- if (!array_key_exists($defaultLabel, $menuEntries) && $timeoutMs > 0) {
- $defaultLabel = array_keys($menuEntries)[0];
- }
- // Link boot entries to menu
- $defaultEntryId = null;
- $order = 1000;
- foreach ($menuEntries as $label => $entry) {
- if (is_string($entry)) {
- // Gap entry
- Database::exec("INSERT INTO serversetup_menuentry
- (menuid, entryid, hotkey, title, hidden, sortval, plainpass, md5pass)
- VALUES (:menuid, :entryid, :hotkey, :title, :hidden, :sortval, '', '')", [
- 'menuid' => $menuId,
- 'entryid' => null,
- 'hotkey' => '',
- 'title' => self::sanitizeIpxeString($entry),
- 'hidden' => 0,
- 'sortval' => $order += 100,
- ]);
- continue;
- }
- $data = Database::queryFirst("SELECT entryid, hotkey, title FROM serversetup_bootentry WHERE entryid = :entryid", ['entryid' => $label]);
- if ($data === false)
- continue;
- $data['pass'] = '';
- $data['hidden'] = 0;
- if ($entry instanceof PxeSection) {
- $data['hidden'] = (int)$entry->isHidden;
- // Prefer explicit data from this imported menu over the defaults
- $data['title'] = self::sanitizeIpxeString($entry->title);
- if (MenuEntry::getKeyCode($entry->hotkey) !== false) {
- $data['hotkey'] = $entry->hotkey;
- }
- if (!empty($entry->passwd)) {
- // Most likely it's a hash so we cannot recover; ask people to reset
- $data['pass'] ='please_reset';
- }
- }
- $data['menuid'] = $menuId;
- $data['sortval'] = $order += 100;
- $res = Database::exec("INSERT INTO serversetup_menuentry
- (menuid, entryid, hotkey, title, hidden, sortval, plainpass, md5pass)
- VALUES (:menuid, :entryid, :hotkey, :title, :hidden, :sortval, :pass, :pass)", $data);
- if ($res !== false && $label === $defaultLabel) {
- $defaultEntryId = Database::lastInsertId();
- }
- }
- // Now we can set default entry
- if (!empty($defaultEntryId)) {
- Database::exec("UPDATE serversetup_menu SET defaultentryid = :entryid WHERE menuid = :menuid",
- ['menuid' => $menuId, 'entryid' => $defaultEntryId]);
- }
- // TODO: masterpw? rather pointless....
- //$oldMenu['masterpasswordclear'];
- return $menuId;
- }
-
- private static function createDefaultEntries()
- {
- $query = 'INSERT IGNORE INTO serversetup_bootentry (entryid, hotkey, title, builtin, data)
- VALUES (:entryid, :hotkey, :title, 1, :data)';
- Database::exec($query,
- [
- 'entryid' => 'bwlp-default',
- 'hotkey' => 'B',
- 'title' => 'bwLehrpool-Umgebung starten',
- 'data' => json_encode([
- 'executable' => '/boot/default/kernel',
- 'initRd' => '/boot/default/initramfs-stage31',
- 'commandLine' => 'slxbase=boot/default quiet splash loglevel=5 rd.systemd.show_status=auto intel_iommu=igfx_off ${ipappend1} ${ipappend2}',
- 'replace' => true,
- 'autoUnload' => true,
- 'resetConsole' => true,
- ]),
- ]);
- Database::exec($query,
- [
- 'entryid' => 'bwlp-default-dbg',
- 'hotkey' => '',
- 'title' => 'bwLehrpool-Umgebung starten (nosplash, debug)',
- 'data' => json_encode([
- 'executable' => '/boot/default/kernel',
- 'initRd' => '/boot/default/initramfs-stage31',
- 'commandLine' => 'slxbase=boot/default loglevel=7 intel_iommu=igfx_off ${ipappend1} ${ipappend2}',
- 'replace' => true,
- 'autoUnload' => true,
- 'resetConsole' => true,
- ]),
- ]);
- Database::exec($query,
- [
- 'entryid' => 'localboot',
- 'hotkey' => 'L',
- 'title' => 'Lokales System starten',
- 'data' => json_encode([
- 'script' => 'goto slx_localboot || goto %fail% ||',
- ]),
- ]);
- Database::exec($query,
- [
- 'entryid' => 'poweroff',
- 'hotkey' => 'P',
- 'title' => 'Power off',
- 'data' => json_encode([
- 'script' => 'poweroff || goto %fail% ||',
- ]),
- ]);
- Database::exec($query,
- [
- 'entryid' => 'reboot',
- 'hotkey' => 'R',
- 'title' => 'Reboot',
- 'data' => json_encode([
- 'script' => 'reboot || goto %fail% ||',
- ]),
- ]);
- }
-
- /**
- * Create unique label for a boot entry. It will try to figure out whether
- * this is one of our default entries and if not, create a unique label
- * representing the menu entry contents.
- * Also it patches the entry if it's referencing the local bwlp install
- * because side effects.
- *
- * @param PxeSection $section
- * @return string
- */
- private static function cleanLabelFixLocal($section)
- {
- $myip = Property::getServerIp();
- // Detect our "old" entry types
- if (count($section->initrd) === 1 && preg_match(",$myip/boot/default/kernel\$,", $section->kernel)
- && preg_match(",$myip/boot/default/initramfs-stage31\$,", $section->initrd[0])) {
- // Kernel and initrd match, examine KCL
- if ($section->append === 'slxbase=boot/default vga=current quiet splash') {
- // Normal
- return 'bwlp-default';
- } elseif ($section->append === 'slxbase=boot/default') {
- // Debug output
- return 'bwlp-default-dbg';
- } else {
- // Transform to relative URL, leave KCL, fall through to generic label gen
- $section->kernel = '/boot/default/kernel';
- $section->initrd = ['/boot/default/initramfs-stage31'];
- }
- }
- // Generic -- "smart" hash of kernel, initrd and command line
- $str = $section->kernel . ' ' . implode(',', $section->initrd);
- $array = preg_split('/\s+/', $section->append, -1, PREG_SPLIT_NO_EMPTY);
- sort($array);
- $str .= ' ' . implode(' ', $array);
-
- return 'i-' . substr(md5($str), 0, 12);
- }
-
- /**
- * @param PxeSection $section
- * @return BootEntry|null The according boot entry, null if it's unparsable
- */
- private static function pxe2BootEntry($section)
- {
- if (preg_match('/(pxechain\.com|pxechn\.c32)$/i', $section->kernel)) {
- // Chaining -- create script
- $args = preg_split('/\s+/', $section->append);
- $script = '';
- $file = false;
- for ($i = 0; $i < count($args); ++$i) {
- $arg = $args[$i];
- if ($arg === '-c') { // PXELINUX config file option
- ++$i;
- $script .= "set 209:string {$args[$i]} || goto %fail%\n";
- } elseif ($arg === '-p') { // PXELINUX prefix path option
- ++$i;
- $script .= "set 210:string {$args[$i]} || goto %fail%\n";
- } elseif ($arg === '-t') { // PXELINUX timeout option
- ++$i;
- $script .= "set 211:int32 {$args[$i]} || goto %fail%\n";
- } elseif ($arg === '-o') { // Overriding various DHCP options
- ++$i;
- if (preg_match('/^((?:0x)?[a-f0-9]{1,4})\.([bwlsh])=(.*)$/i', $args[$i], $out)) {
- // TODO: 'q' (8byte) unsupported for now
- $opt = intval($out[1], 0);
- if ($opt > 0 && $opt < 255) {
- static $optType = ['b' => 'uint8', 'w' => 'uint16', 'l' => 'int32', 's' => 'string', 'h' => 'hex'];
- $type = $optType[$out[2]];
- $script .= "set {$opt}:{$type} {$args[$i]} || goto %fail%\n";
- }
- }
- } elseif ($arg{0} === '-') {
- continue;
- } elseif ($file === false) {
- $file = self::parseFile($arg);
- }
- }
- if ($file !== false) {
- $url = parse_url($file);
- if (isset($url['host'])) {
- $script .= "set next-server {$url['host']} || goto %fail%\n";
- }
- if (isset($url['path'])) {
- $script .= "set filename {$url['path']} || goto %fail%\n";
- }
- $script .= "chain -ar {$file} || goto %fail%\n";
- return new CustomBootEntry(['script' => $script]);
- }
- return null;
- }
- // "Normal" entry that should be convertible into a StandardBootEntry
- $section->kernel = self::parseFile($section->kernel);
- foreach ($section->initrd as &$initrd) {
- $initrd = self::parseFile($initrd);
- }
- return BootEntry::newStandardBootEntry($section);
- }
-
- /**
- * Parse PXELINUX file notion. Basically, turn
- * server::file into tftp://server/file.
- *
- * @param string $file
- * @return string
- */
- private static function parseFile($file)
- {
- if (preg_match(',^([^:/]+)::(.*)$,', $file, $out)) {
- return 'tftp://' . $out[1] . '/' . $out[2];
- }
- return $file;
- }
-
- public static function sanitizeIpxeString($string)
- {
- return str_replace(['&', '|', ';', '$', "\r", "\n"], ['+', '/', ':', 'S', ' ', ' '], $string);
- }
-
- public static function makeMd5Pass($plainpass, $salt)
- {
- if (empty($plainpass))
- return '';
- return md5(md5($plainpass) . '-' . $salt);
- }
-
-}
diff --git a/modules-available/serversetup-bwlp/inc/ipxemenu.inc.php b/modules-available/serversetup-bwlp/inc/ipxemenu.inc.php
deleted file mode 100644
index 5c1a87d5..00000000
--- a/modules-available/serversetup-bwlp/inc/ipxemenu.inc.php
+++ /dev/null
@@ -1,142 +0,0 @@
-<?php
-
-class IPxeMenu
-{
-
- protected $menuid;
- protected $timeoutMs;
- protected $title;
- protected $defaultEntryId;
- /**
- * @var MenuEntry[]
- */
- protected $items = [];
-
- public function __construct($menu)
- {
- if (!is_array($menu)) {
- $menu = Database::queryFirst("SELECT menuid, timeoutms, title, defaultentryid FROM serversetup_menu
- WHERE menuid = :menuid LIMIT 1", ['menuid' => $menu]);
- if (!is_array($menu)) {
- $menu = ['menuid' => 'foo', 'title' => 'Invalid Menu ID: ' . (int)$menu];
- }
- }
- $this->menuid = (int)$menu['menuid'];
- $this->timeoutMs = (int)$menu['timeoutms'];
- $this->title = $menu['title'];
- $this->defaultEntryId = $menu['defaultentryid'];
- $res = Database::simpleQuery("SELECT e.menuentryid, e.entryid, e.hotkey, e.title, e.hidden, e.sortval, e.md5pass,
- b.data AS bootentry
- FROM serversetup_menuentry e
- LEFT JOIN serversetup_bootentry b USING (entryid)
- WHERE e.menuid = :menuid
- ORDER BY e.sortval ASC, e.title ASC", ['menuid' => $menu['menuid']]);
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
- $this->items[] = new MenuEntry($row);
- }
- }
-
- public function getMenuDefinition($targetVar, $mode, $slxExtensions)
- {
- $str = "menu -- {$this->title}\n";
- foreach ($this->items as $item) {
- $str .= $item->getMenuItemScript("m_{$this->menuid}", $this->defaultEntryId, $mode, $slxExtensions);
- }
- if ($this->defaultEntryId === null) {
- $defaultLabel = "mx_{$this->menuid}_poweroff";
- } else {
- $defaultLabel = "m_{$this->menuid}_{$this->defaultEntryId}";
- }
- $str .= "choose";
- if ($this->timeoutMs > 0) {
- $str .= " --timeout {$this->timeoutMs}";
- }
- $str .= " $targetVar || goto $defaultLabel || goto fail\n";
- if ($this->defaultEntryId === null) {
- $str .= "goto skip_{$defaultLabel}\n"
- . ":{$defaultLabel}\n"
- . "poweroff || goto fail\n"
- . ":skip_{$defaultLabel}\n";
- }
- return $str;
- }
-
- public function getItemsCode($mode)
- {
- $str = '';
- foreach ($this->items as $item) {
- $str .= $item->getBootEntryScript("m_{$this->menuid}", 'fail', $mode);
- $str .= "goto slx_menu\n";
- }
- return $str;
- }
-
- /*
- *
- */
-
- public static function forLocation($locationId)
- {
- $chain = null;
- if (Module::isAvailable('location')) {
- $chain = Location::getLocationRootChain($locationId);
- }
- if (!empty($chain)) {
- $res = Database::simpleQuery("SELECT m.menuid, m.timeoutms, m.title, IFNULL(ml.defaultentryid, m.defaultentryid) AS defaultentryid, ml.locationid
- FROM serversetup_menu m
- INNER JOIN serversetup_menu_location ml USING (menuid)
- WHERE ml.locationid IN (:chain)", ['chain' => $chain]);
- if ($res->rowCount() > 0) {
- // Make the location id key, preserving order (closest location is first)
- $chain = array_flip($chain);
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
- // Overwrite the value (numeric ascending values, useless) with menu array of according location
- $chain[(int)$row['locationid']] = $row;
- }
- // Use first one that was found
- foreach ($chain as $menu) {
- if (is_array($menu)) {
- return new IPxeMenu($menu);
- }
- }
- // Should never end up here, but we'd just fall through and use the default
- }
- }
- // We're here, no specific menu, use default
- $menu = Database::queryFirst("SELECT menuid, timeoutms, title, defaultentryid
- FROM serversetup_menu
- ORDER BY isdefault DESC LIMIT 1");
- if ($menu === false) {
- return new EmptyIPxeMenu;
- }
- return new IPxeMenu($menu);
- }
-
- public static function forClient($ip, $uuid)
- {
- $locationId = 0;
- if (Module::isAvailable('location')) {
- $locationId = Location::getFromIpAndUuid($ip, $uuid);
- }
- return self::forLocation($locationId);
- }
-
-}
-
-class EmptyIPxeMenu extends IPxeMenu
-{
-
- /** @noinspection PhpMissingParentConstructorInspection */
- public function __construct()
- {
- $this->title = 'No menu defined';
- $this->menuid = -1;
- $this->items[] = new MenuEntry([
- 'title' => 'Please create a menu in Server-Setup first'
- ]);
- $this->items[] = new MenuEntry([
- 'title' => 'Bitte erstellen Sie zunächst ein Menü'
- ]);
- }
-
-} \ No newline at end of file
diff --git a/modules-available/serversetup-bwlp/inc/localboot.inc.php b/modules-available/serversetup-bwlp/inc/localboot.inc.php
deleted file mode 100644
index 3ab81862..00000000
--- a/modules-available/serversetup-bwlp/inc/localboot.inc.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-class Localboot
-{
-
- const PROPERTY_KEY = 'serversetup.localboot';
-
- const BOOT_METHODS = [
- 'AUTO' => 'iseq efi ${platform} && exit 1 || sanboot --no-describe',
- 'EXIT' => 'exit 1',
- 'COMBOOT' => 'chain /tftp/chain.c32 hd0',
- 'SANBOOT' => 'sanboot --no-describe',
- ];
-
-} \ No newline at end of file
diff --git a/modules-available/serversetup-bwlp/inc/menuentry.inc.php b/modules-available/serversetup-bwlp/inc/menuentry.inc.php
deleted file mode 100644
index d243fd23..00000000
--- a/modules-available/serversetup-bwlp/inc/menuentry.inc.php
+++ /dev/null
@@ -1,177 +0,0 @@
-<?php
-
-class MenuEntry
-{
- /**
- * @var int id of entry, used for pw
- */
- private $menuentryid;
- /**
- * @var false|string key code as expected by iPXE
- */
- private $hotkey;
- /**
- * @var string
- */
- private $title;
- /**
- * @var bool
- */
- private $hidden;
- /**
- * @var bool
- */
- private $gap;
- /**
- * @var int
- */
- private $sortval;
- /**
- * @var BootEntry
- */
- private $bootEntry = null;
-
- private $md5pass = null;
-
- /**
- * MenuEntry constructor.
- *
- * @param array $row row from database
- */
- public function __construct($row)
- {
- if (is_array($row)) {
- foreach ($row as $key => $value) {
- if (property_exists($this, $key)) {
- $this->{$key} = $value;
- }
- }
- $this->hotkey = self::getKeyCode($row['hotkey']);
- if (!empty($row['bootentry'])) {
- $this->bootEntry = BootEntry::fromJson($row['bootentry']);
- }
- $this->gap = (array_key_exists('entryid', $row) && $row['entryid'] === null);
- }
- settype($this->hidden, 'bool');
- settype($this->gap, 'bool');
- settype($this->sortval, 'int');
- settype($this->menuentryid, 'int');
- }
-
- public function getMenuItemScript($lblPrefix, $requestedDefaultId, $mode, $slxExtensions)
- {
- if ($this->bootEntry !== null && !$this->bootEntry->supportsMode($mode))
- return '';
- $str = 'item ';
- if ($this->gap) {
- $str .= '--gap ';
- } else {
- if ($this->hidden && $slxExtensions) {
- if ($this->hotkey === false)
- return ''; // Hidden entries without hotkey are illegal
- $str .= '--hidden ';
- }
- if ($this->hotkey !== false) {
- $str .= '--key ' . $this->hotkey . ' ';
- }
- if ($this->menuentryid == $requestedDefaultId) {
- $str .= '--default ';
- }
- $str .= "{$lblPrefix}_{$this->menuentryid} ";
- }
- if (empty($this->title)) {
- $str .= '${}';
- } else {
- $str .= $this->title;
- }
- return $str . " || prompt Could not create menu item for {$lblPrefix}_{$this->menuentryid}\n";
- }
-
- public function getBootEntryScript($lblPrefix, $failLabel, $mode)
- {
- if ($this->bootEntry === null || !$this->bootEntry->supportsMode($mode))
- return '';
- $str = ":{$lblPrefix}_{$this->menuentryid}\n";
- if (!empty($this->md5pass)) {
- $str .= "set slx_hash {$this->md5pass} || goto $failLabel\n"
- . "set slx_salt {$this->menuentryid} || goto $failLabel\n"
- . "set slx_pw_ok {$lblPrefix}_ok || goto $failLabel\n"
- . "set slx_pw_fail slx_menu || goto $failLabel\n"
- . "goto slx_pass_check || goto $failLabel\n"
- . ":{$lblPrefix}_ok\n";
- }
- return $str . $this->bootEntry->toScript($failLabel, $mode);
- }
-
- /*
- *
- */
-
- private static function getKeyArray()
- {
- static $data = false;
- if ($data === false) {
- $data = [
- 'F5' => 0x107e,
- 'F6' => 0x127e,
- 'F7' => 0x137e,
- 'F8' => 0x147e,
- 'F9' => 0x157e,
- 'F10' => 0x167e,
- 'F11' => 0x187e,
- 'F12' => 0x197e,
- ];
- for ($i = 1; $i <= 26; ++$i) {
- $letter = chr(0x40 + $i);
- $data['SHIFT_' . $letter] = 0x40 + $i;
- if ($letter !== 'C') {
- $data['CTRL_' . $letter] = $i;
- }
- $data[$letter] = 0x60 + $i;
- }
- for ($i = 0; $i <= 9; ++$i) {
- $data[chr(0x30 + $i)] = 0x30 + $i;
- }
- asort($data, SORT_NUMERIC);
- }
- return $data;
- }
-
- /**
- * Get all the known/supported keys, usable for menu items.
- *
- * @return string[] list of known key names
- */
- public static function getKeyList()
- {
- return array_keys(self::getKeyArray());
- }
-
- /**
- * Get the key code ipxe expects for the given named
- * key. Returns false if the key name is unknown.
- *
- * @param string $keyName
- * @return false|string Key code as hex string, or false if not found
- */
- public static function getKeyCode($keyName)
- {
- $data = self::getKeyArray();
- if (isset($data[$keyName]))
- return '0x' . dechex($data[$keyName]);
- return false;
- }
-
- /**
- * @param string $keyName desired key name
- * @return string $keyName if it's known, empty string otherwise
- */
- public static function filterKeyName($keyName)
- {
- $data = self::getKeyArray();
- if (isset($data[$keyName]))
- return $keyName;
- return '';
- }
-
-}
diff --git a/modules-available/serversetup-bwlp/inc/pxelinux.inc.php b/modules-available/serversetup-bwlp/inc/pxelinux.inc.php
deleted file mode 100644
index 1d022fef..00000000
--- a/modules-available/serversetup-bwlp/inc/pxelinux.inc.php
+++ /dev/null
@@ -1,302 +0,0 @@
-<?php
-
-
-class PxeLinux
-{
-
- /**
- * Takes a (partial) pxelinux menu and parses it into
- * a PxeMenu object.
- * @param string $input The pxelinux menu to parse
- * @return PxeMenu the parsed menu
- */
- public static function parsePxeLinux($input)
- {
- /*
- LABEL openslx-debug
- MENU LABEL ^bwLehrpool-Umgebung starten (nosplash, debug)
- KERNEL http://IPADDR/boot/default/kernel
- INITRD http://IPADDR/boot/default/initramfs-stage31
- APPEND slxbase=boot/default
- IPAPPEND 3
- */
- $menu = new PxeMenu;
- $sectionPropMap = [
- 'menu label' => ['string', 'title'],
- 'menu default' => ['true', 'isDefault'],
- 'menu hide' => ['true', 'isHidden'],
- 'menu disabled' => ['true', 'isDisabled'],
- 'menu indent' => ['int', 'indent'],
- 'kernel' => ['string', 'kernel'],
- 'com32' => ['string', 'kernel'],
- 'pxe' => ['string', 'kernel'],
- 'initrd' => ['string', 'initrd'],
- 'append' => ['string', 'append'],
- 'ipappend' => ['int', 'ipAppend'],
- 'sysappend' => ['int', 'ipAppend'],
- 'localboot' => ['int', 'localBoot'],
- ];
- $globalPropMap = [
- 'timeout' => ['int', 'timeoutMs', 100],
- 'totaltimeout' => ['int', 'totalTimeoutMs', 100],
- 'menu title' => ['string', 'title'],
- 'menu clear' => ['true', 'menuClear'],
- 'menu immediate' => ['true', 'immediateHotkeys'],
- 'ontimeout' => ['string', 'timeoutLabel'],
- ];
- $lines = preg_split('/[\r\n]+/', $input);
- $section = null;
- $count = count($lines);
- for ($li = 0; $li < $count; ++$li) {
- $line =& $lines[$li];
- if (!preg_match('/^\s*([^m]\S*|menu\s+\S+)(\s+.*?|)\s*$/i', $line, $out))
- continue;
- $val = trim($out[2]);
- $key = trim($out[1]);
- $key = strtolower($key);
- $key = preg_replace('/\s+/', ' ', $key);
- if ($key === 'label') {
- if ($section !== null) {
- $menu->sections[] = $section;
- }
- $section = new PxeSection($val);
- } elseif ($key === 'menu separator') {
- if ($section !== null) {
- $menu->sections[] = $section;
- $section = null;
- }
- $menu->sections[] = new PxeSection(null);
- } elseif (self::handleKeyword($key, $val, $globalPropMap, $menu)) {
- continue;
- } elseif ($section === null) {
- continue;
- } elseif ($key === 'text' && strtolower($val) === 'help') {
- $text = '';
- while (++$li < $count) {
- $line =& $lines[$li];
- if (strtolower(trim($line)) === 'endtext')
- break;
- $text .= $line . "\n";
- }
- $section->helpText = $text;
- } elseif (self::handleKeyword($key, $val, $sectionPropMap, $section)) {
- continue;
- }
- }
- if ($section !== null) {
- $menu->sections[] = $section;
- }
- foreach ($menu->sections as $section) {
- $section->mangle();
- }
- return $menu;
- }
-
- /**
- * Check if keyword is valid and if so, add its interpreted value
- * to the given object. The map to look up the keyword has to be passed
- * as well as the object to set the value in. Map and object should
- * obviously match.
- * @param string $key keyword of parsed line
- * @param string $val raw value of currently parsed line (empty if not present)
- * @param array $map Map in which $key is looked up as key
- * @param PxeMenu|PxeSection The object to set the parsed and sanitized value in
- * @return bool true if the value was found in the map (and set in the object), false otherwise
- */
- private static function handleKeyword($key, $val, $map, $object)
- {
- if (!isset($map[$key]))
- return false;
- $opt = $map[$key];
- // opt[0] is the type the value should be cast to; special case "true" means
- // this is a bool option that will be set as soon as the keyword is present,
- // as it doesn't have any parameters
- if ($opt[0] === 'true') {
- $val = true;
- } else {
- settype($val, $opt[0]);
- }
- // If opt[2] is present it's a multiplier for the value
- if (isset($opt[2])) {
- $val *= $opt[2];
- }
- $object->{$opt[1]} = $val;
- return true;
- }
-
-}
-
-/**
- * Class representing a parsed pxelinux menu. Members
- * will be set to their annotated type if present or
- * be null otherwise, except for present-only boolean
- * options, which will default to false.
- */
-class PxeMenu
-{
-
- /**
- * @var string menu title, shown at the top of the menu
- */
- public $title;
- /**
- * @var int initial timeout after which $timeoutLabel would be executed
- */
- public $timeoutMs;
- /**
- * @var int if the user canceled the timeout by pressing a key, this timeout would still eventually
- * trigger and launch the $timeoutLabel section
- */
- public $totalTimeoutMs;
- /**
- * @var string label of section which will execute if the timeout expires
- */
- public $timeoutLabel;
- /**
- * @var bool hide menu and just show background after triggering an entry
- */
- public $menuClear = false;
- /**
- * @var bool boot the associated entry directly if its corresponding hotkey is pressed instead of just highlighting
- */
- public $immediateHotkeys = false;
- /**
- * @var PxeSection[] list of sections the menu contains
- */
- public $sections = [];
-
- public function hash($fuzzy)
- {
- $ctx = hash_init('md5');
- if (!$fuzzy) {
- hash_update($ctx, $this->title);
- hash_update($ctx, $this->timeoutLabel);
- }
- hash_update($ctx, $this->timeoutMs);
- foreach ($this->sections as $section) {
- if ($fuzzy) {
- hash_update($ctx, mb_strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $section->title)));
- } else {
- hash_update($ctx, $section->label);
- hash_update($ctx, $section->title);
- hash_update($ctx, $section->indent);
- hash_update($ctx, $section->helpText);
- hash_update($ctx, $section->isDefault);
- hash_update($ctx, $section->hotkey);
- }
- hash_update($ctx, $section->kernel);
- hash_update($ctx, $section->append);
- hash_update($ctx, $section->ipAppend);
- hash_update($ctx, $section->passwd);
- hash_update($ctx, $section->isHidden);
- hash_update($ctx, $section->isDisabled);
- hash_update($ctx, $section->localBoot);
- foreach ($section->initrd as $initrd) {
- hash_update($ctx, $initrd);
- }
- }
- return hash_final($ctx, false);
- }
-
-}
-
-/**
- * Class representing a parsed pxelinux menu entry. Members
- * will be set to their annotated type if present or
- * be null otherwise, except for present-only boolean
- * options, which will default to false.
- */
-class PxeSection
-{
-
- /**
- * @var string label used internally in PXEMENU definition to address this entry
- */
- public $label;
- /**
- * @var string MENU LABEL of PXEMENU - title of entry displayed to the user
- */
- public $title;
- /**
- * @var int Number of spaces to prefix the title with
- */
- public $indent;
- /**
- * @var string help text to display when the entry is highlighted
- */
- public $helpText;
- /**
- * @var string Kernel to load
- */
- public $kernel;
- /**
- * @var string|string[] initrd to load for the kernel.
- * If mangle() has been called this will be an array,
- * otherwise it's a comma separated list.
- */
- public $initrd;
- /**
- * @var string command line options to pass to the kernel
- */
- public $append;
- /**
- * @var int IPAPPEND from PXEMENU. Bitmask of valid options 1 and 2.
- */
- public $ipAppend;
- /**
- * @var string Password protecting the entry. This is most likely in crypted form.
- */
- public $passwd;
- /**
- * @var bool whether this section is marked as default (booted after timeout)
- */
- public $isDefault = false;
- /**
- * @var bool Menu entry is not visible (can only be triggered by timeout)
- */
- public $isHidden = false;
- /**
- * @var bool Disable this entry, making it unselectable
- */
- public $isDisabled = false;
- /**
- * @var int Value of the LOCALBOOT field
- */
- public $localBoot;
- /**
- * @var string hotkey to trigger item. Only valid after calling mangle()
- */
- public $hotkey;
-
- public function __construct($label) { $this->label = $label; }
-
- public function mangle()
- {
- if (($i = strpos($this->title, '^')) !== false) {
- $this->hotkey = strtoupper($this->title{$i+1});
- $this->title = substr($this->title, 0, $i) . substr($this->title, $i + 1);
- }
- if (strpos($this->append, 'initrd=') !== false) {
- $parts = preg_split('/\s+/', $this->append);
- $this->append = '';
- for ($i = 0; $i < count($parts); ++$i) {
- if (preg_match('/^initrd=(.*)$/', $parts[$i], $out)) {
- if (!empty($this->initrd)) {
- $this->initrd .= ',';
- }
- $this->initrd .= $out[1];
- } else {
- $this->append .= ' ' . $parts[$i];
- }
- }
- $this->append = trim($this->append);
- }
- if (is_string($this->initrd)) {
- $this->initrd = explode(',', $this->initrd);
- } elseif (!is_array($this->initrd)) {
- $this->initrd = [];
- }
- }
-
-}
-