From fe6ac16498b05d0f0c8ed7fda394273815d3d6da Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 23 May 2014 20:49:02 +0200 Subject: Stuff (WIP) --- inc/configmodule.inc.php | 50 +++++++ inc/database.inc.php | 1 + inc/message.inc.php | 9 +- inc/property.inc.php | 22 ++- inc/taskmanager.inc.php | 7 +- inc/trigger.inc.php | 40 ++++++ inc/util.inc.php | 43 ++++++ modules/adduser.inc.php | 88 ++++++------ modules/ipxe.inc.php | 40 ------ modules/serversetup.inc.php | 11 +- modules/sysconfig.inc.php | 173 ++++++++++++++++++----- modules/sysconfig/addconfig.inc.php | 220 +++++++++++++++++++++++++++++ modules/sysconfig/addmodule_ad.inc.php | 27 ++-- modules/sysconfig/addmodule_custom.inc.php | 12 +- script/taskmanager.js | 5 +- style/default.css | 11 ++ templates/main-menu.html | 1 - templates/messagebox-error.html | 2 +- templates/messagebox-info.html | 2 +- templates/messagebox-success.html | 2 +- templates/messagebox-warning.html | 2 +- templates/page-ipxe.html | 21 --- templates/page-serversetup.html | 30 ---- templates/page-sysconfig-main.html | 94 +++++++----- templates/serversetup/ipaddress.html | 32 +++++ templates/serversetup/ipxe.html | 21 +++ templates/sysconfig/ad-finish.html | 4 +- templates/sysconfig/cfg-finish.html | 12 ++ templates/sysconfig/cfg-start.html | 35 +++++ templates/sysconfig/custom-fileselect.html | 4 +- templates/sysconfig/custom-upload.html | 1 + 31 files changed, 778 insertions(+), 244 deletions(-) create mode 100644 inc/configmodule.inc.php create mode 100644 inc/trigger.inc.php delete mode 100644 modules/ipxe.inc.php create mode 100644 modules/sysconfig/addconfig.inc.php delete mode 100644 templates/page-ipxe.html delete mode 100644 templates/page-serversetup.html create mode 100644 templates/serversetup/ipaddress.html create mode 100644 templates/serversetup/ipxe.html create mode 100644 templates/sysconfig/cfg-finish.html create mode 100644 templates/sysconfig/cfg-start.html diff --git a/inc/configmodule.inc.php b/inc/configmodule.inc.php new file mode 100644 index 00000000..55f76cf3 --- /dev/null +++ b/inc/configmodule.inc.php @@ -0,0 +1,50 @@ + $title)); + $id = Database::lastInsertId(); + if (!is_numeric($id)) Util::traceError('Inserting new AD config to DB did not yield a numeric insert id'); + // Entry created, now try to get a free port for the proxy + $res = Database::simpleQuery("SELECT moduleid, contents FROM configtgz_module"); + $ports = array(); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + if ($row['moduleid'] == $id) { + // ... + } else { + $data = json_decode($row['contents'], true); + if (isset($data['proxyport'])) $ports[] = $data['proxyport']; + } + } + $port = 3300; + while (in_array($port, $ports)) { + $port++; + } + // Port determined, carry on... + $ownEntry = array( + 'server' => $server, + 'searchbase' => $searchbase, + 'binddn' => $binddn, + 'bindpw' => $bindpw, + 'proxyport' => $port + ); + $data = json_encode($ownEntry); + if ($data === false) Util::traceError('Serializing the AD data failed.'); + $name = CONFIG_TGZ_LIST_DIR . '/modules/AD_AUTH_id_' . $id . '.' . mt_rand() . '.tgz'; + Database::exec("UPDATE configtgz_module SET filepath = :filename, contents = :contents WHERE moduleid = :id LIMIT 1", array( + 'id' => $id, + 'filename' => $name, + 'contents' => json_encode($ownEntry) + )); + // Add archive file name to array before returning it + $ownEntry['moduleid'] = $id; + $ownEntry['filename'] = $name; + return $ownEntry; + } + +} diff --git a/inc/database.inc.php b/inc/database.inc.php index 70f50116..a646e823 100644 --- a/inc/database.inc.php +++ b/inc/database.inc.php @@ -59,6 +59,7 @@ class Database * Note that this will re-use PDOStatements, so if you run the same * query again with different params, do not rely on the first PDOStatement * still being valid. If you need to do something fancy, use Database::prepare + * @return \PDOStatement The query result object */ public static function simpleQuery($query, $args = array()) { diff --git a/inc/message.inc.php b/inc/message.inc.php index cab8fbd3..2ed9e79a 100644 --- a/inc/message.inc.php +++ b/inc/message.inc.php @@ -19,8 +19,9 @@ $error_text = array( 'missing-file' => 'Es wurde keine Datei ausgewählt!', 'invalid-file' => 'Die Datei {{0}} existiert nicht!', 'upload-complete' => 'Upload von {{0}} war erfolgreich', - 'upload-failed' => 'Upload von {{0}} schlug fehl!', - 'config-activated' => 'Konfiguration wurde aktiviert', + 'upload-failed' => 'Upload schlug fehl: {{0}}', + 'config-activated' => 'Konfiguration {{0}} wurde aktiviert', + 'config-invalid' => 'Konfiguration mit ID {{0}} existiert nicht', 'error-write' => 'Fehler beim Schreiben von {{0}}', 'error-read' => 'Fehler beim Lesen von {{0}}', 'error-archive' => 'Korruptes Archiv oder nicht unterstütztes Format', @@ -29,6 +30,8 @@ $error_text = array( 'empty-archive' => 'Das Archiv enthält keine Dateien oder Verzeichnisse', 'error-extract' => 'Konnte Archiv nicht nach {{0}} entpacken - {{1}}', 'module-added' => 'Modul erfolgreich hinzugefügt', + 'module-deleted' => 'Modul {{0}} wurde gelöscht', + 'module-in-use' => 'Modul {{0}} wird noch durch Konfiguration {{1}} verwendet', 'taskmanager-error' => 'Verbindung zum Taskmanager fehlgeschlagen', 'taskmanager-format' => 'Taskmanager hat ungültige Daten zurückgeliefert', 'task-error' => 'Ausführung fehlgeschlagen: {{0}}', @@ -93,7 +96,7 @@ class Message foreach (self::$list as $item) { $message = $error_text[$item['id']]; foreach ($item['params'] as $index => $text) { - $message = str_replace('{{' . $index . '}}', $text, $message); + $message = str_replace('{{' . $index . '}}', '' . htmlspecialchars($text) . '', $message); } Render::addTemplate('messagebox-' . $item['type'], array('message' => $message)); self::$alreadyDisplayed[] = $item; diff --git a/inc/property.inc.php b/inc/property.inc.php index a1c252a5..c6f3e8ad 100644 --- a/inc/property.inc.php +++ b/inc/property.inc.php @@ -54,5 +54,25 @@ class Property { self::set('server-ip', $value); } + + public static function getIPxeIp() + { + return self::get('ipxe-ip', 'none'); + } + + public static function setIPxeIp($value) + { + self::set('ipxe-ip', $value); + } + + public static function getIPxeTaskId() + { + return self::get('ipxe-task'); + } + + public static function setIPxeTaskId($value) + { + self::set('ipxe-task', $value); + } -} \ No newline at end of file +} diff --git a/inc/taskmanager.inc.php b/inc/taskmanager.inc.php index 27e79dea..e93cc696 100644 --- a/inc/taskmanager.inc.php +++ b/inc/taskmanager.inc.php @@ -66,12 +66,17 @@ class Taskmanager public static function waitComplete($taskId) { + $done = false; for ($i = 0; $i < 10; ++$i) { $status = self::status($taskId); if (!isset($status['statusCode'])) break; - if ($status['statusCode'] != TASK_PROCESSING && $status['statusCode'] != TASK_WAITING) break; + if ($status['statusCode'] != TASK_PROCESSING && $status['statusCode'] != TASK_WAITING) { + $done = true; + break; + } usleep(150000); } + if ($done) self::release ($taskId); return $status; } diff --git a/inc/trigger.inc.php b/inc/trigger.inc.php new file mode 100644 index 00000000..40d9c491 --- /dev/null +++ b/inc/trigger.inc.php @@ -0,0 +1,40 @@ + Property::getServerIp() + )); + if (!isset($task['id'])) + return false; + Property::setIPxeTaskId($task['id']); + return $task['id']; + } + +} \ No newline at end of file diff --git a/inc/util.inc.php b/inc/util.inc.php index 4b974f6d..63680023 100644 --- a/inc/util.inc.php +++ b/inc/util.inc.php @@ -173,6 +173,49 @@ class Util } return sprintf("%.{$decimals}f ", $bytes / pow(1024, $factor)) . $sz[$factor]; } + + public static function sanitizeFilename($name) + { + return preg_replace('/[^a-zA-Z0-9_\-]+/', '_', $name); + } + + /** + * Create human readable error description from a $_FILES[<..>]['error'] code + * + * @param int $code the code to turn into an error description + * @return string the error description + */ + public static function uploadErrorString($code) + { + switch ($code) { + case UPLOAD_ERR_INI_SIZE: + $message = "The uploaded file exceeds the upload_max_filesize directive in php.ini"; + break; + case UPLOAD_ERR_FORM_SIZE: + $message = "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form"; + break; + case UPLOAD_ERR_PARTIAL: + $message = "The uploaded file was only partially uploaded"; + break; + case UPLOAD_ERR_NO_FILE: + $message = "No file was uploaded"; + break; + case UPLOAD_ERR_NO_TMP_DIR: + $message = "Missing a temporary folder"; + break; + case UPLOAD_ERR_CANT_WRITE: + $message = "Failed to write file to disk"; + break; + case UPLOAD_ERR_EXTENSION: + $message = "File upload stopped by extension"; + break; + + default: + $message = "Unknown upload error"; + break; + } + return $message; + } } diff --git a/modules/adduser.inc.php b/modules/adduser.inc.php index 6a5faf3a..19fa5425 100644 --- a/modules/adduser.inc.php +++ b/modules/adduser.inc.php @@ -1,49 +1,55 @@ $_POST['user'], - 'pass' => Crypto::hash6($_POST['pass1']), - 'fullname' => $_POST['fullname'], - 'phone' => $_POST['phone'], - 'email' => $_POST['email'], - ); - if (strlen($data['pass']) < 50) Util::traceError('Error hashing password using SHA-512'); - if (Database::exec('INSERT INTO user SET login = :user, passwd = :pass, fullname = :fullname, phone = :phone, email = :email', $data) != 1) { - Util::traceError('Could not create new user in DB'); - } - // Make it superadmin if first user. This method sucks as it's a race condition but hey... - $ret = Database::queryFirst('SELECT Count(*) AS num FROM user'); - if ($ret !== false && $ret['num'] == 1) { - Database::exec('UPDATE user SET permissions = 1'); + protected function doPreprocess() + { + User::load(); + + if (isset($_POST['action']) && $_POST['action'] === 'adduser') { + // Check required fields + if (empty($_POST['user']) || empty($_POST['pass1']) || empty($_POST['pass2']) || empty($_POST['fullname']) || empty($_POST['phone']) || empty($_POST['email'])) { + Message::addError('empty-field'); + Util::redirect('?do=AddUser'); + } elseif ($_POST['pass1'] !== $_POST['pass2']) { + Message::addError('password-mismatch'); + Util::redirect('?do=AddUser'); + } elseif (Database::queryFirst('SELECT userid FROM user LIMIT 1') !== false) { + Message::addError('adduser-disabled'); + Util::redirect('?do=Session&action=login'); + } else { + $data = array( + 'user' => $_POST['user'], + 'pass' => Crypto::hash6($_POST['pass1']), + 'fullname' => $_POST['fullname'], + 'phone' => $_POST['phone'], + 'email' => $_POST['email'], + ); + if (Database::exec('INSERT INTO user SET login = :user, passwd = :pass, fullname = :fullname, phone = :phone, email = :email', $data) != 1) { + Util::traceError('Could not create new user in DB'); + } + // Make it superadmin if first user. This method sucks as it's a race condition but hey... + $ret = Database::queryFirst('SELECT Count(*) AS num FROM user'); + if ($ret !== false && $ret['num'] == 1) { + Database::exec('UPDATE user SET permissions = 1'); + } + Message::addInfo('adduser-success'); + Util::redirect('?do=Session&action=login'); + } } - Message::addInfo('adduser-success'); - Util::redirect('?do=Session&action=login'); } -} -function render_module() -{ - // No user was added, check if current user is allowed to add a new user - // Currently you can only add users if there is no user yet. :) - if (Database::queryFirst('SELECT userid FROM user LIMIT 1') !== false) { - Message::addError('adduser-disabled'); - } else { - Render::setTitle('Benutzer anlegen'); - Render::addTemplate('page-adduser', $_POST); + protected function doRender() + { + // No user was added, check if current user is allowed to add a new user + // Currently you can only add users if there is no user yet. :) + if (Database::queryFirst('SELECT userid FROM user LIMIT 1') !== false) { + Message::addError('adduser-disabled'); + } else { + Render::setTitle('Benutzer anlegen'); + Render::addTemplate('page-adduser', $_POST); + } } -} +} diff --git a/modules/ipxe.inc.php b/modules/ipxe.inc.php deleted file mode 100644 index d479bd15..00000000 --- a/modules/ipxe.inc.php +++ /dev/null @@ -1,40 +0,0 @@ - $out[1], - 'current' => ($out[1] == $current) - ); - } - } - Render::addTemplate('page-ipxe', array('ips' => $ips, 'token' => Session::get('token'))); - } -} diff --git a/modules/serversetup.inc.php b/modules/serversetup.inc.php index 3f2b8768..daa3b4e8 100644 --- a/modules/serversetup.inc.php +++ b/modules/serversetup.inc.php @@ -13,7 +13,7 @@ class Page_ServerSetup extends Page Message::addError('no-permission'); Util::redirect('?do=Main'); } - + $this->currentAddress = Property::getServerIp(); $newAddress = Request::post('ip', 'none'); @@ -23,7 +23,7 @@ class Page_ServerSetup extends Page Util::redirect('?do=Main'); } - if ($this->taskStatus['statusCode'] === TASK_WAITING) { + if ($this->taskStatus['statusCode'] === TASK_WAITING) { // TODO: Async if just displaying $this->taskStatus = Taskmanager::waitComplete($this->taskStatus['id']); } @@ -54,6 +54,7 @@ class Page_ServerSetup extends Page } if ($valid) { Property::setServerIp($newAddress); + Trigger::ipxe(); } else { Message::addError('invalid-ip', $newAddress); } @@ -64,9 +65,13 @@ class Page_ServerSetup extends Page protected function doRender() { - Render::addTemplate('page-serversetup', array( + Render::addTemplate('serversetup/ipaddress', array( 'ips' => $this->taskStatus['data']['addresses'], 'token' => Session::get('token') )); + Render::addTemplate('serversetup/ipxe', array( + 'token' => Session::get('token'), + 'taskid' => Property::getIPxeTaskId() + )); } } \ No newline at end of file diff --git a/modules/sysconfig.inc.php b/modules/sysconfig.inc.php index f177f0f1..7c23ce56 100644 --- a/modules/sysconfig.inc.php +++ b/modules/sysconfig.inc.php @@ -6,6 +6,11 @@ class Page_SysConfig extends Page protected function doPreprocess() { User::load(); + + if (!User::hasPermission('superadmin')) { + Message::addError('no-permission'); + Util::redirect('?do=SysConfig'); + } $action = Request::any('action', 'list'); @@ -15,29 +20,28 @@ class Page_SysConfig extends Page AddModule_Base::preprocess(); } - // Action "activate" (set sysconfig as active) - if ($action === 'activate') { - if (!User::hasPermission('superadmin')) { - Message::addError('no-permission'); - Util::redirect('?do=SysConfig'); + if ($action === 'module') { + // Action: "delmodule" (delete module) + if (Request::post('del', 'no') !== 'no') { + $this->delModule(); } - if (!isset($_REQUEST['file'])) { - Message::addError('missing-file'); - Util::redirect('?do=SysConfig'); + } + + // Action: "addconfig" (compose config from one or more modules) + if ($action === 'addconfig') { + $this->initAddConfig(); + AddConfig_Base::preprocess(); + } + + if ($action === 'config') { + // Action: "delconfig" (delete config) + if (Request::post('del', 'no') !== 'no') { + $this->delConfig(); } - $file = preg_replace('/[^a-z0-9\-_\.]/', '', $_REQUEST['file']); - $path = CONFIG_TGZ_LIST_DIR . '/' . $file; - if (!file_exists($path)) { - Message::addError('invalid-file', $file); - Util::redirect('?do=SysConfig'); + // Action "activate" (set sysconfig as active) + if (Request::post('activate', 'no') !== 'no') { + $this->activateConfig(); } - mkdir(CONFIG_HTTP_DIR . '/default', 0755, true); - $linkname = CONFIG_HTTP_DIR . '/default/config.tgz'; - @unlink($linkname); - if (file_exists($linkname)) Util::traceError('Could not delete old config.tgz link!'); - if (!symlink($path, $linkname)) Util::traceError("Could not symlink to $path at $linkname!"); - Message::addSuccess('config-activated'); - Util::redirect('?do=SysConfig'); } } @@ -52,40 +56,122 @@ class Page_SysConfig extends Page case 'addmodule': AddModule_Base::render(); break; + case 'addconfig': + AddConfig_Base::render(); + break; case 'list': - $this->rr_list_configs(); + $this->listConfigs(); break; default: Message::addError('invalid-action', $action); break; } } - - protected function doAjax() - { - $action = Request::any('action', 'list'); - // Action: "addmodule" (upload new module) - if ($action === 'addmodule') { - $this->initAddModule(); - AddModule_Base::ajax(); - } - } - - private function rr_list_configs() + /** + * List all configurations and configuration modules. + */ + private function listConfigs() { - if (!User::hasPermission('superadmin')) { - Message::addError('no-permission'); - return; + // Configs + $res = Database::simpleQuery("SELECT configid, title, filepath FROM configtgz ORDER BY title ASC"); + $configs = array(); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $configs[] = array( + 'configid' => $row['configid'], + 'config' => $row['title'], + 'current' => readlink('/srv/openslx/www/boot/default/config.tgz') === $row['filepath'] + ); } - $res = Database::simpleQuery("SELECT title FROM configtgz_module ORDER BY title ASC"); + // Config modules + $res = Database::simpleQuery("SELECT moduleid, title FROM configtgz_module ORDER BY title ASC"); $modules = array(); while ($row = $res->fetch(PDO::FETCH_ASSOC)) { $modules[] = array( + 'moduleid' => $row['moduleid'], 'module' => $row['title'] ); } - Render::addTemplate('page-sysconfig-main', array('modules' => $modules, 'token' => Session::get('token'))); + Render::addTemplate('page-sysconfig-main', array( + 'configs' => $configs, + 'modules' => $modules, + 'token' => Session::get('token') + )); + } + + private function activateConfig() + { + $configid = Request::post('activate', 'MISSING'); + $row = Database::queryFirst("SELECT title, filepath FROM configtgz WHERE configid = :configid LIMIT 1", array('configid' => $configid)); + if ($row === false) { + Message::addError('config-invalid', $configid); + Util::redirect('?do=SysConfig'); + } + $task = Taskmanager::submit('LinkConfigTgz', array( + 'destination' => $row['filepath'] + )); + if (isset($task['statusCode']) && $task['statusCode'] === TASK_WAITING) { + $task = Taskmanager::waitComplete($task['id']); + } + if (!isset($task['statusCode']) || $task['statusCode'] === TASK_ERROR) { + Message::addError('task-error', $task['data']['error']); + } elseif ($task['statusCode'] === TASK_FINISHED) { + Message::addSuccess('config-activated', $row['title']); + } + Util::redirect('?do=SysConfig'); + } + + private function delModule() + { + $moduleid = Request::post('del', 'MISSING'); + $row = Database::queryFirst("SELECT title, filepath FROM configtgz_module WHERE moduleid = :moduleid LIMIT 1", array('moduleid' => $moduleid)); + if ($row === false) { + Message::addError('config-invalid', $moduleid); + Util::redirect('?do=SysConfig'); + } + $existing = Database::queryFirst("SELECT title FROM configtgz_x_module" + . " INNER JOIN configtgz USING (configid)" + . " WHERE moduleid = :moduleid LIMIT 1", array('moduleid' => $moduleid)); + if ($existing !== false) { + Message::addError('module-in-use', $row['title'], $existing['title']); + Util::redirect('?do=SysConfig'); + } + $task = Taskmanager::submit('DeleteFile', array( + 'file' => $row['filepath'] + )); + if (isset($task['statusCode']) && $task['statusCode'] === TASK_WAITING) { + $task = Taskmanager::waitComplete($task['id']); + } + if (!isset($task['statusCode']) || $task['statusCode'] === TASK_ERROR) { + Message::addWarning('task-error', $task['data']['error']); + } elseif ($task['statusCode'] === TASK_FINISHED) { + Message::addSuccess('module-deleted', $row['title']); + } + Database::exec("DELETE FROM configtgz_module WHERE moduleid = :moduleid LIMIT 1", array('moduleid' => $moduleid)); + Util::redirect('?do=SysConfig'); + } + + private function delConfig() + { + $configid = Request::post('del', 'MISSING'); + $row = Database::queryFirst("SELECT title, filepath FROM configtgz WHERE configid = :configid LIMIT 1", array('configid' => $configid)); + if ($row === false) { + Message::addError('config-invalid', $configid); + Util::redirect('?do=SysConfig'); + } + $task = Taskmanager::submit('DeleteFile', array( + 'file' => $row['filepath'] + )); + if (isset($task['statusCode']) && $task['statusCode'] === TASK_WAITING) { + $task = Taskmanager::waitComplete($task['id']); + } + if (!isset($task['statusCode']) || $task['statusCode'] === TASK_ERROR) { + Message::addWarning('task-error', $task['data']['error']); + } elseif ($task['statusCode'] === TASK_FINISHED) { + Message::addSuccess('module-deleted', $row['title']); + } + Database::exec("DELETE FROM configtgz WHERE configid = :configid LIMIT 1", array('configid' => $configid)); + Util::redirect('?do=SysConfig'); } private function initAddModule() @@ -98,5 +184,16 @@ class Page_SysConfig extends Page } AddModule_Base::setStep($step); } + + private function initAddConfig() + { + $step = Request::any('step', 0); + if ($step === 0) $step = 'AddConfig_Start'; + require_once 'modules/sysconfig/addconfig.inc.php'; + foreach (glob('modules/sysconfig/addconfig_*.inc.php') as $file) { + require_once $file; + } + AddConfig_Base::setStep($step); + } } diff --git a/modules/sysconfig/addconfig.inc.php b/modules/sysconfig/addconfig.inc.php new file mode 100644 index 00000000..6f076a12 --- /dev/null +++ b/modules/sysconfig/addconfig.inc.php @@ -0,0 +1,220 @@ + array( + 'unique' => true, + 'group' => 'Authentifizierung' + ), + 'custom' => array( + 'unique' => false, + 'group' => 'Generisch' + ) + ); + + /** + * Holds the instance for the currently executing step + * @var \AddConfig_Base + */ + private static $instance = false; + + /** + * + * @param type $step + * @return \AddConfig_Base + */ + public static function setStep($step) + { + if (empty($step) || !class_exists($step) || get_parent_class($step) !== 'AddConfig_Base') { + Message::addError('invalid-action', $step); + Util::redirect('?do=SysConfig'); + } + self::$instance = new $step(); + } + + protected function tmError() + { + Message::addError('taskmanager-error'); + Util::redirect('?do=SysConfig'); + } + + protected function taskError($status) + { + if (isset($status['data']['error'])) { + $error = $status['data']['error']; + } elseif (isset($status['statusCode'])) { + $error = $status['statusCode']; + } else { + $error = 'Unbekannter Taskmanager-Fehler'; // TODO: No text + } + Message::addError('task-error', $error); + Util::redirect('?do=SysConfig'); + } + + /** + * Called before any HTML rendering happens, so you can + * pepare stuff, validate input, and optionally redirect + * early if something is wrong, or you received post + * data etc. + */ + protected function preprocessInternal() + { + // void + } + + /** + * Do page rendering. + */ + protected function renderInternal() + { + // void + } + + /** + * Handle ajax stuff + */ + protected function ajaxInternal() + { + // void + } + + public static function preprocess() + { + if (self::$instance === false) { + Util::traceError('No step instance yet'); + } + self::$instance->preprocessInternal(); + } + + public static function render() + { + if (self::$instance === false) { + Util::traceError('No step instance yet'); + } + self::$instance->renderInternal(); + } + + public static function ajax() + { + if (self::$instance === false) { + Util::traceError('No step instance yet'); + } + self::$instance->ajaxInternal(); + } + +} + +/** + * Start dialog for adding config. Ask for title, + * show selection of modules. + */ +class AddConfig_Start extends AddConfig_Base +{ + + protected function renderInternal() + { + $res = Database::simpleQuery("SELECT moduleid, title, moduletype, filepath FROM configtgz_module" + . " ORDER BY title ASC"); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + if (!isset(self::$types[$row['moduletype']])) { + self::$types[$row['moduletype']] = array( + 'unique' => false, + 'group' => 'Undefined moduletype in addconfig.inc.php' + ); + } + if (!isset(self::$types[$row['moduletype']]['modules'])) { + self::$types[$row['moduletype']]['modules'] = array(); + self::$types[$row['moduletype']]['groupid'] = $row['moduletype']; + } + if (empty($row['filepath']) || !file_exists($row['filepath'])) $row['missing'] = true; + self::$types[$row['moduletype']]['modules'][] = $row; + } + Render::addDialog('Konfiguration zusammenstellen', false, 'sysconfig/cfg-start', array( + 'token' => Session::get('token'), + 'step' => 'AddConfig_Finish', + 'groups' => array_values(self::$types) + )); + } + +} + +/** + * Start dialog for adding config. Ask for title, + * show selection of modules. + */ +class AddConfig_Finish extends AddConfig_Base +{ + private $task = false; + private $destFile = false; + private $title = false; + private $moduleids = array(); + + protected function preprocessInternal() + { + $modules = Request::post('module'); + $this->title = Request::post('title'); + if (!is_array($modules)) { + Message::addError('missing-file'); + Util::redirect('?do=SysConfig&action=addconfig'); + } + if (empty($this->title)) { + Message::addError('empty-field'); + Util::redirect('?do=SysConfig&action=addconfig'); + } + // Get all input modules + $moduleids = '0'; // Passed directly in query. Make sure no SQL injection is possible + foreach ($modules as $module) { + $moduleids .= ',' . (int)$module; // Casting to int should make it safe + } + $res = Database::simpleQuery("SELECT moduleid, filepath FROM configtgz_module WHERE moduleid IN ($moduleids)"); + $files = array(); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $files[] = $row['filepath']; + $this->moduleids[] = $row['moduleid']; + } + // Create output file name (config.tgz) + do { + $this->destFile = CONFIG_TGZ_LIST_DIR . '/config-' . Util::sanitizeFilename($this->title) . '-' . mt_rand() . '.tgz'; + } while (file_exists($this->destFile)); + // Hand over to tm + $this->task = Taskmanager::submit('RecompressArchive', array( + 'inputFiles' => $files, + 'outputFile' => $this->destFile + )); + } + + protected function renderInternal() + { + if (isset($this->task['statusCode']) && $this->task['statusCode'] === TASK_WAITING) { + $this->task = Taskmanager::waitComplete($this->task['id']); + } + if ($this->task === false) $this->tmError(); + if (!isset($this->task['statusCode']) || $this->task['statusCode'] !== TASK_FINISHED) $this->taskError($this->task); + Database::exec("INSERT INTO configtgz (title, filepath) VALUES (:title, :filepath)", array( + 'title' => $this->title, + 'filepath' => $this->destFile + )); + $confid = Database::lastInsertId(); + foreach ($this->moduleids as $moduleid) { + Database::exec("INSERT INTO configtgz_x_module (configid, moduleid) VALUES (:configid, :moduleid)", array( + 'configid' => $confid, + 'moduleid' => $moduleid + )); + } + Render::addDialog('Konfiguration zusammenstellen', false, 'sysconfig/cfg-finish', array( + 'token' => Session::get('token'), + 'configid' => $confid + )); + } + +} diff --git a/modules/sysconfig/addmodule_ad.inc.php b/modules/sysconfig/addmodule_ad.inc.php index ab897096..ac820bbc 100644 --- a/modules/sysconfig/addmodule_ad.inc.php +++ b/modules/sysconfig/addmodule_ad.inc.php @@ -86,23 +86,14 @@ class AdModule_Finish extends AddModule_Base protected function preprocessInternal() { - $data = json_encode(array( - 'server' => Request::post('server'), - 'searchbase' => Request::post('searchbase'), - 'binddn' => Request::post('binddn'), - 'bindpw' => Request::post('bindpw'), - )); - Database::exec("INSERT INTO configtgz_module (title, moduletype, filename, contents) " - . " VALUES (:title, 'AD_AUTH', '', :content)", array( - 'title' => 'AD: ' . Request::post('server'), - 'content' => $data)); - $id = Database::lastInsertId(); - $name = CONFIG_TGZ_LIST_DIR . '/modules/AD_AUTH_id_' . $id . '.' . mt_rand() . '.tgz'; - Database::exec("UPDATE configtgz_module SET filename = :filename WHERE moduleid = :id LIMIT 1", array( - 'id' => $id, - 'filename' => $name - )); - $tgz = Taskmanager::submit('DummyTask', array()); + $config = ConfigModule::insertAdConfig('AD: ' . Request::post('server'), + Request::post('server'), + Request::post('searchbase'), + Request::post('binddn'), + Request::post('bindpw') + ); + $config['proxyip'] = Property::getServerIp(); + $tgz = Taskmanager::submit('CreateAdConfig', $config); if (isset($tgz['id'])) { $ldadp = Taskmanager::submit('DummyTask', array('parentTask' => $tgz['id'])); } @@ -111,7 +102,7 @@ class AdModule_Finish extends AddModule_Base return; } $this->taskIds = array( - 'tm-module' => $tgz['id'], + 'tm-config' => $tgz['id'], 'tm-ldadp' => $ldadp['id'] ); } diff --git a/modules/sysconfig/addmodule_custom.inc.php b/modules/sysconfig/addmodule_custom.inc.php index ec2c8af7..070c1fd4 100644 --- a/modules/sysconfig/addmodule_custom.inc.php +++ b/modules/sysconfig/addmodule_custom.inc.php @@ -20,7 +20,10 @@ class CustomModule_UploadForm extends AddModule_Base protected function renderInternal() { Session::set('mod_temp', false); - Render::addDialog('Eigenes Modul hinzufügen', false, 'sysconfig/custom-upload', array('step' => 'CustomModule_ProcessUpload')); + Render::addDialog('Eigenes Modul hinzufügen', false, 'sysconfig/custom-upload', array( + 'token' => Session::get('token'), + 'step' => 'CustomModule_ProcessUpload' + )); } } @@ -42,7 +45,7 @@ class CustomModule_ProcessUpload extends AddModule_Base Util::redirect('?do=SysConfig'); } if ($_FILES['modulefile']['error'] != UPLOAD_ERR_OK) { - Message::addError('upload-failed', $_FILES['modulefile']['name']); + Message::addError('upload-failed', Util::uploadErrorString($_FILES['modulefile']['error'])); Util::redirect('?do=SysConfig'); } $tempfile = $_FILES['modulefile']['tmp_name'] . '.tmp'; @@ -91,6 +94,7 @@ class CustomModule_ProcessUpload extends AddModule_Base } } Render::addDialog('Eigenes Modul hinzufügen', false, 'sysconfig/custom-fileselect', array( + 'token' => Session::get('token'), 'step' => 'CustomModule_CompressModule', 'files' => $list, )); @@ -114,7 +118,7 @@ class CustomModule_CompressModule extends AddModule_Base } // Recompress using task manager $this->taskId = 'tgzmod' . mt_rand() . '-' . microtime(true); - $destFile = CONFIG_TGZ_LIST_DIR . '/modules/mod-' . preg_replace('/[^a-z0-9_\-]+/is', '_', $title) . '-' . microtime(true) . '.tgz'; + $destFile = CONFIG_TGZ_LIST_DIR . '/modules/mod-' . Util::sanitizeFilename($title) . '-' . microtime(true) . '.tgz'; Taskmanager::submit('RecompressArchive', array( 'id' => $this->taskId, 'inputFiles' => array($tempfile), @@ -129,7 +133,7 @@ class CustomModule_CompressModule extends AddModule_Base $this->taskError($status); } // Seems ok, create entry in DB - $ret = Database::exec("INSERT INTO configtgz_module (title, moduletype, filename, contents) VALUES (:title, 'custom', :file, '')", + $ret = Database::exec("INSERT INTO configtgz_module (title, moduletype, filepath, contents) VALUES (:title, 'custom', :file, '')", array('title' => $title, 'file' => $destFile)); if ($ret === false) { unlink($destFile); diff --git a/script/taskmanager.js b/script/taskmanager.js index da3a0586..a78d6776 100644 --- a/script/taskmanager.js +++ b/script/taskmanager.js @@ -12,7 +12,7 @@ function tmInit() item.append('
'); } if (item.is('[data-tm-log]')) { - item.append('
');
+			item.append('