summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2020-11-16 14:03:21 +0100
committerSimon Rettberg2020-11-16 14:03:21 +0100
commit11c488215620d12c1f79fc9b05deb9928d2cab39 (patch)
treed6d546f5c1729325482976587a232e1e7a0378fc
parent[statistics] Honor filters for clients with special mode (diff)
downloadslx-admin-11c488215620d12c1f79fc9b05deb9928d2cab39.tar.gz
slx-admin-11c488215620d12c1f79fc9b05deb9928d2cab39.tar.xz
slx-admin-11c488215620d12c1f79fc9b05deb9928d2cab39.zip
[sysconfig] SSH: Split pubkey and rest of config, add more options
Now we can have exactly one SSH-Config per sysconfig, which avoids confusion due to config mismatch regarding "allow pw" and "port". The install include takes care of splitting the key into a new module for existing modules, but doesn't remove duplicate SshConfig modules from sysconfigs, as this might lead to additional confusion. Next time the user edits a sysconfig, they are forced to pick exactly one SshConfig module. The "allow password login" option was extended to allow password login for non-root users only in addition to simply being "yes" or "no". There's an additional option that can entirely limit the group of users allowed to log in via SSH.
-rw-r--r--modules-available/sysconfig/addmodule_sshconfig.inc.php16
-rw-r--r--modules-available/sysconfig/addmodule_sshkey.inc.php72
-rw-r--r--modules-available/sysconfig/inc/configmodule.inc.php10
-rw-r--r--modules-available/sysconfig/inc/configmodule/sshconfig.inc.php32
-rw-r--r--modules-available/sysconfig/inc/configmodule/sshkey.inc.php55
-rw-r--r--modules-available/sysconfig/inc/configtgz.inc.php17
-rw-r--r--modules-available/sysconfig/install.inc.php44
-rw-r--r--modules-available/sysconfig/lang/de/config-module.json9
-rw-r--r--modules-available/sysconfig/lang/de/template-tags.json39
-rw-r--r--modules-available/sysconfig/lang/en/config-module.json9
-rw-r--r--modules-available/sysconfig/lang/en/template-tags.json32
-rw-r--r--modules-available/sysconfig/templates/sshconfig-start.html33
-rw-r--r--modules-available/sysconfig/templates/sshkey-start.html18
13 files changed, 307 insertions, 79 deletions
diff --git a/modules-available/sysconfig/addmodule_sshconfig.inc.php b/modules-available/sysconfig/addmodule_sshconfig.inc.php
index 495ba2a9..4a75d77e 100644
--- a/modules-available/sysconfig/addmodule_sshconfig.inc.php
+++ b/modules-available/sysconfig/addmodule_sshconfig.inc.php
@@ -13,10 +13,14 @@ class SshConfig_Start extends AddModule_Base
$data = $this->edit->getData(false) + array(
'title' => $this->edit->title(),
'edit' => $this->edit->id(),
- 'apl' => $this->edit->getData('allowPasswordLogin') === 'yes'
+ 'PWD_' . strtoupper($this->edit->getData('allowPasswordLogin')) . '_selected' => 'selected',
+ 'USR_' . strtoupper($this->edit->getData('allowedUsersLogin')) . '_selected' => 'selected',
);
} else {
- $data = array();
+ $data = array(
+ 'PWD_NO_selected' => 'selected',
+ 'USR_ROOT_ONLY_selected' => 'selected',
+ );
}
Render::addDialog(Dictionary::translateFile('config-module', 'sshconfig_title'), false, 'sshconfig-start', $data + array(
'step' => 'SshConfig_Finish',
@@ -44,7 +48,8 @@ class SshConfig_Finish extends AddModule_Base
Message::addError('main.error-read', 'sshconfig.inc.php');
Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
}
- $module->setData('allowPasswordLogin', Request::post('allowPasswordLogin') === 'yes');
+ $module->setData('allowPasswordLogin', Request::post('allowPasswordLogin'));
+ $module->setData('allowedUsersLogin', Request::post('allowedUsersLogin'));
$port = Request::post('listenPort', '');
if ($port === '') {
$port = 22;
@@ -53,10 +58,7 @@ class SshConfig_Finish extends AddModule_Base
Message::addError('main.value-invalid', 'port', Request::post('listenPort'));
Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
}
- if (!$module->setData('publicKey', Request::post('publicKey'))) {
- Message::addError('main.value-invalid', 'pubkey', Request::post('publicKey'));
- Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
- }
+ $module->setData('publicKey', false);
if ($this->edit !== false)
$ret = $module->update($title);
else
diff --git a/modules-available/sysconfig/addmodule_sshkey.inc.php b/modules-available/sysconfig/addmodule_sshkey.inc.php
new file mode 100644
index 00000000..b5ab4ad6
--- /dev/null
+++ b/modules-available/sysconfig/addmodule_sshkey.inc.php
@@ -0,0 +1,72 @@
+<?php
+
+/*
+ * Wizard for configuring the sshd (client side).
+ */
+
+class SshKey_Start extends AddModule_Base
+{
+
+ protected function renderInternal()
+ {
+ if ($this->edit !== false) {
+ $data = $this->edit->getData(false) + array(
+ 'title' => $this->edit->title(),
+ 'edit' => $this->edit->id(),
+ );
+ } else {
+ $data = array();
+ }
+ Render::addDialog(Dictionary::translateFile('config-module', 'sshkey_title'), false, 'sshkey-start', $data + array(
+ 'step' => 'SshKey_Finish',
+ ));
+ }
+
+}
+
+class SshKey_Finish extends AddModule_Base
+{
+
+ protected function preprocessInternal()
+ {
+ $title = Request::post('title');
+ if (empty($title)) {
+ Message::addError('missing-title');
+ return;
+ }
+ // Seems ok, create entry
+ if ($this->edit === false) {
+ $module = ConfigModule::getInstance('SshKey');
+ } else {
+ $module = $this->edit;
+ }
+ if ($module === false) {
+ Message::addError('main.error-read', 'sshkey.inc.php');
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshKey_Start');
+ }
+ if (!$module->setData('publicKey', Request::post('publicKey'))) {
+ Message::addError('main.value-invalid', 'pubkey', Request::post('publicKey'));
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshKey_Start');
+ }
+ if ($this->edit !== false) {
+ $ret = $module->update($title);
+ } else {
+ $ret = $module->insert($title);
+ }
+ if (!$ret) {
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshKey_Start');
+ } elseif (!$module->generate($this->edit === false, NULL, 200)) {
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshKey_Start');
+ }
+ // Yay
+ if ($this->edit !== false) {
+ Message::addSuccess('module-edited');
+ } else {
+ Message::addSuccess('module-added');
+ AddModule_Base::setStep('AddModule_Assign', $module->id());
+ return;
+ }
+ Util::redirect('?do=SysConfig');
+ }
+
+}
diff --git a/modules-available/sysconfig/inc/configmodule.inc.php b/modules-available/sysconfig/inc/configmodule.inc.php
index a9035d78..f3906378 100644
--- a/modules-available/sysconfig/inc/configmodule.inc.php
+++ b/modules-available/sysconfig/inc/configmodule.inc.php
@@ -321,23 +321,25 @@ abstract class ConfigModule
*
* @return boolean true on success, false otherwise
*/
- public final function update($title)
+ public final function update($title = '')
{
if ($this->moduleId === 0)
Util::traceError('ConfigModule::update called when moduleId == 0');
- if (empty($title))
- $title = $this->moduleTitle;
+ if (!empty($title)) {
+ $this->moduleTitle = $title;
+ }
if (!$this->validateConfig())
return false;
// Update
Database::exec("UPDATE configtgz_module SET title = :title, contents = :contents, status = :status, dateline = :now "
. " WHERE moduleid = :moduleid LIMIT 1", array(
'moduleid' => $this->moduleId,
- 'title' => $title,
+ 'title' => $this->moduleTitle,
'contents' => json_encode($this->moduleData),
'status' => 'OUTDATED',
'now' => time(),
));
+ $this->moduleStatus = 'OUTDATED';
return true;
}
diff --git a/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php b/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php
index 9975f789..b5ab20e4 100644
--- a/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php
+++ b/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php
@@ -5,7 +5,7 @@ ConfigModule::registerModule(
Dictionary::translateFileModule('sysconfig', 'config-module', 'sshconfig_title'), // Title
Dictionary::translateFileModule('sysconfig', 'config-module', 'sshconfig_description'), // Description
Dictionary::translateFileModule('sysconfig', 'config-module', 'group_sshconfig'), // Group
- false, // Only one per config?
+ true, // Only one per config?
500
);
@@ -23,7 +23,6 @@ class ConfigModule_SshConfig extends ConfigModule
'failOnParentFail' => false,
'parent' => $parent
);
- // Create config module, which will also check if the pubkey is valid
return Taskmanager::submit('SshdConfigGenerator', $config);
}
@@ -34,25 +33,40 @@ class ConfigModule_SshConfig extends ConfigModule
protected function validateConfig()
{
- return isset($this->moduleData['publicKey']) && isset($this->moduleData['allowPasswordLogin']) && isset($this->moduleData['listenPort']);
+ // UPGRADE
+ if (isset($this->moduleData['allowPasswordLogin']) && !isset($this->moduleData['allowedUsersLogin'])) {
+ $this->moduleData['allowPasswordLogin'] = strtoupper($this->moduleData['allowPasswordLogin']);
+ if (!in_array($this->moduleData['allowPasswordLogin'], ['NO', 'USER_ONLY', 'YES'])) {
+ $this->moduleData['allowPasswordLogin'] = 'NO';
+ }
+ $this->moduleData['allowedUsersLogin'] = 'ALL';
+ }
+ return isset($this->moduleData['allowPasswordLogin']) && isset($this->moduleData['allowedUsersLogin'])
+ && isset($this->moduleData['listenPort']);
}
public function setData($key, $value)
{
switch ($key) {
case 'publicKey':
- break;
+ if ($value === false) {
+ error_log('Unsetting publicKey');
+ unset($this->moduleData[$key]);
+ return true;
+ }
+ return false;
case 'allowPasswordLogin':
- if ($value === true || $value === 'yes')
- $value = 'yes';
- elseif ($value === false || $value === 'no')
- $value = 'no';
- else
+ if (!in_array($value, ['NO', 'USER_ONLY', 'YES']))
+ return false;
+ break;
+ case 'allowedUsersLogin';
+ if (!in_array($value, ['ROOT_ONLY', 'USER_ONLY', 'ALL']))
return false;
break;
case 'listenPort':
if (!is_numeric($value) || $value < 1 || $value > 65535)
return false;
+ $value = (int)$value;
break;
default:
return false;
diff --git a/modules-available/sysconfig/inc/configmodule/sshkey.inc.php b/modules-available/sysconfig/inc/configmodule/sshkey.inc.php
new file mode 100644
index 00000000..2d212d25
--- /dev/null
+++ b/modules-available/sysconfig/inc/configmodule/sshkey.inc.php
@@ -0,0 +1,55 @@
+<?php
+
+ConfigModule::registerModule(
+ ConfigModule_SshKey::MODID, // ID
+ Dictionary::translateFileModule('sysconfig', 'config-module', 'sshkey_title'), // Title
+ Dictionary::translateFileModule('sysconfig', 'config-module', 'sshkey_description'), // Description
+ Dictionary::translateFileModule('sysconfig', 'config-module', 'group_sshkey'), // Group
+ false, // Only one per config?
+ 510
+);
+
+class ConfigModule_SshKey extends ConfigModule
+{
+ const MODID = 'SshKey';
+ const VERSION = 1;
+
+ protected function generateInternal($tgz, $parent)
+ {
+ if (!$this->validateConfig())
+ return false;
+ $config = array(
+ 'files' => [
+ '/root/.ssh/authorized_keys.d/sshkey_' . $this->id() . '_' . Util::sanitizeFilename($this->title()) . '.pub'
+ => $this->moduleData['publicKey']],
+ 'destination' => $tgz,
+ 'failOnParentFail' => false,
+ 'parent' => $parent
+ );
+ // Create config module, which will also check if the pubkey is valid
+ return Taskmanager::submit('MakeTarball', $config);
+ }
+
+ protected function moduleVersion()
+ {
+ return self::VERSION;
+ }
+
+ protected function validateConfig()
+ {
+ return isset($this->moduleData['publicKey']);
+ }
+
+ public function setData($key, $value)
+ {
+ switch ($key) {
+ case 'publicKey':
+ break;
+ default:
+ return false;
+ }
+ $this->moduleData[$key] = $value;
+ return true;
+ }
+
+}
diff --git a/modules-available/sysconfig/inc/configtgz.inc.php b/modules-available/sysconfig/inc/configtgz.inc.php
index ff9e306d..98f29753 100644
--- a/modules-available/sysconfig/inc/configtgz.inc.php
+++ b/modules-available/sysconfig/inc/configtgz.inc.php
@@ -56,7 +56,9 @@ class ConfigTgz
{
if (!is_array($moduleIds))
return false;
- $this->configTitle = $title;
+ if (!empty($title)) {
+ $this->configTitle = $title;
+ }
$this->modules = array();
// Get all modules to put in config
$idstr = '0'; // Passed directly in query. Make sure no SQL injection is possible
@@ -77,7 +79,7 @@ class ConfigTgz
// Update name
Database::exec("UPDATE configtgz SET title = :title, status = :status, dateline = :now WHERE configid = :configid LIMIT 1", array(
'configid' => $this->configId,
- 'title' => $title,
+ 'title' => $this->configTitle,
'status' => 'OUTDATED',
'now' => time(),
));
@@ -88,9 +90,10 @@ class ConfigTgz
*
* @param bool $deleteOnError
* @param int $timeoutMs
+ * @param string|null $parentTask parent task to order this rebuild after
* @return string|bool true=success, false=error, string=taskid, still running
*/
- public function generate($deleteOnError = false, $timeoutMs = 0)
+ public function generate($deleteOnError = false, $timeoutMs = 0, $parentTask = null)
{
if (!($this->configId > 0) || !is_array($this->modules) || $this->file === false)
Util::traceError ('configId <= 0 or modules not array in ConfigTgz::rebuild()');
@@ -103,7 +106,7 @@ class ConfigTgz
}
}
- $task = self::recompress($files, $this->file);
+ $task = self::recompress($files, $this->file, $parentTask);
// Wait for completion
if ($timeoutMs > 0 && !Taskmanager::isFailed($task) && !Taskmanager::isFinished($task)) {
@@ -215,7 +218,7 @@ class ConfigTgz
* @param string $destFile where to store final result
* @return false|array taskmanager task
*/
- private static function recompress($files, $destFile)
+ private static function recompress($files, $destFile, $parentTask = null)
{
// Get stuff other modules want to inject
$handler = function($hook) {
@@ -232,7 +235,9 @@ class ConfigTgz
// Hand over to tm
return Taskmanager::submit('RecompressArchive', array(
'inputFiles' => $files,
- 'outputFile' =>$destFile
+ 'outputFile' =>$destFile,
+ 'parentTask' => $parentTask,
+ 'failOnParentFail' => false,
));
}
diff --git a/modules-available/sysconfig/install.inc.php b/modules-available/sysconfig/install.inc.php
index ace5361b..fe6a8c09 100644
--- a/modules-available/sysconfig/install.inc.php
+++ b/modules-available/sysconfig/install.inc.php
@@ -120,17 +120,55 @@ if (!tableHasColumn('configtgz', 'warnings')) {
}
// ----- rebuild configs ------
-// TEMPORARY HACK; Rebuild configs.. move somewhere else?
+// PERMANENT HACK; Rebuild configs.. move somewhere else?
Module::isAvailable('sysconfig');
$list = ConfigModule::getAll();
+$parentTask = null;
+$configList = [];
if ($list === false) {
- EventLog::warning('Could not regenerate AD/LDAP configs - please do so manually');
+ EventLog::warning('Could not regenerate configs - please do so manually');
} else {
foreach ($list as $ad) {
+ if ($ad->moduleType() === 'SshConfig') {
+ // 2020-11-12: Split SshConfig into SshConfig and SshKey
+ $pubkey = $ad->getData('publicKey');
+ if ($pubkey !== false && !empty($pubkey)) {
+ error_log('Legacy module with pubkey ' . $ad->id());
+ $key = ConfigModule::getInstance('SshKey');
+ if ($key !== false) {
+ $key->setData('publicKey', $pubkey);
+ if ($key->insert($ad->title())) {
+ // Insert worked, remove key from old module, add this module to the same configs
+ $task = $key->generate(false, $parentTask);
+ if ($task !== false) {
+ $parentTask = $task;
+ }
+ error_log('Inserted new module with id ' . $key->id());
+ $ad->setData('publicKey', false);
+ $ad->update();
+ $configs = ConfigTgz::getAllForModule($ad->id());
+ foreach ($configs as $config) {
+ // Add newly created key-only module to all configs
+ $new = array_merge($config->getModuleIds(), [$key->id()]);
+ error_log(implode(',', $config->getModuleIds()) . ' -> ' . implode(',', $new));
+ $config->update('', $new);
+ $configList[] = $config;
+ }
+ }
+ }
+ }
+ }
if ($ad->needRebuild()) {
- $ad->generate(false);
+ $update[] = UPDATE_DONE;
+ $task = $ad->generate(false, $parentTask);
+ if ($task !== false) {
+ $parentTask = $task;
+ }
}
}
+ foreach ($configList as $config) {
+ $config->generate(false, 0, $parentTask);
+ }
}
// Create response for browser
diff --git a/modules-available/sysconfig/lang/de/config-module.json b/modules-available/sysconfig/lang/de/config-module.json
index f2ed9a90..33c743a5 100644
--- a/modules-available/sysconfig/lang/de/config-module.json
+++ b/modules-available/sysconfig/lang/de/config-module.json
@@ -9,11 +9,14 @@
"group_branding": "Einrichtungsspezifisches Logo",
"group_generic": "Generisch",
"group_screensaver": "Bildschirmschoner Styling",
- "group_sshconfig": "SSH",
+ "group_sshconfig": "SSH-Dämon",
+ "group_sshkey": "SSH-Key",
"ldapAuth_description": "Mit diesem Modul l\u00e4sst sich eine generische LDAP-Authentifizierung einrichten.",
"ldapAuth_title": "LDAP Authentifizierung",
"screensaver_title": "Bildschirmschoner Anpassungen",
"screensaver_description": "Mit diesem Modul können sie den Style (QSS) und die Texte des Bildschirmschoners anpassen.",
"sshconfig_description": "Mit diesem Modul l\u00e4sst sich steuern, ob und wie der sshd auf den gebooteten Clients startet, und welche Funktionen er zur Verf\u00fcgung stellt. Wenn Sie keinen sshd auf den Clients nutzen wollen, brauchen Sie kein solches Modul zu erstellen.",
- "sshconfig_title": "SSH-D\u00e4mon"
-} \ No newline at end of file
+ "sshconfig_title": "SSH-D\u00e4mon",
+ "sshkey_title": "SSH-Key",
+ "sshkey_description": "Einen öffentlichen SSH-Schlüssel zu den authorized_keys des root-Benutzers hinzufügen. Mit dem zugehörigen privaten Schlüssel kann dann via SSH auf die gebooteten Clients zugegriffen werden, sofern root-Login im zugehörigen SSH-Dämon-Modul aktiviert wurde."
+}
diff --git a/modules-available/sysconfig/lang/de/template-tags.json b/modules-available/sysconfig/lang/de/template-tags.json
index 0acdb8a7..9637314e 100644
--- a/modules-available/sysconfig/lang/de/template-tags.json
+++ b/modules-available/sysconfig/lang/de/template-tags.json
@@ -8,8 +8,6 @@
"lang_adText3": "Normalerweise k\u00f6nnen Sie als Bind DN die Kurzform im Format dom\u00e4ne\\benutzer angeben. Wenn dies nicht funktioniert, m\u00fcssen Sie den DN des Benutzers ermitteln. Z.B. unter Eingabe des folgenden Befehls auf einem DC:",
"lang_adText4": "Nach Eingabe aller ben\u00f6tigten Daten wird im n\u00e4chsten Schritt \u00fcberpr\u00fcft, ob die Kommunikation mit dem AD m\u00f6glich ist.",
"lang_add": "Hinzuf\u00fcgen",
- "lang_allowPass": "Login mit Passwort zulassen",
- "lang_allowPassInfo": "Wenn aktiviert, l\u00e4sst der sshd Logins mit Benutzername\/Passwort-Kombination zu. Ansonsten werden nur Logins nach dem pubkey-Verfahren zugelassen.",
"lang_asteriskMandatory": "Mit (*) gekennzeichnete Felder sind Pflichtfelder",
"lang_availableModules": "Verf\u00fcgbare Konfigurationsmodule",
"lang_availableSystem": "Verf\u00fcgbare Systemkonfigurationen",
@@ -74,10 +72,10 @@
"lang_mapModeNativeFallback": "Nativ in der VM einbinden; Fallback auf VMware Shared Folders",
"lang_mapModeNone": "Verzeichnisse nicht durchreichen",
"lang_mapModeVmware": "VMware Shared Folders [VMwareTools]",
+ "lang_modStillUsedBy": "Modul noch in Verwendung durch:",
"lang_mode": "Modus",
- "lang_modeEasy": "Vereinfachter Modus",
"lang_modeAdvanced": "Fortgeschrittener Modus",
- "lang_modStillUsedBy": "Modul noch in Verwendung durch:",
+ "lang_modeEasy": "Vereinfachter Modus",
"lang_moduleChoose": "Bitte w\u00e4hlen Sie aus, welche Art Konfigurationsmodul Sie erstellen m\u00f6chten.",
"lang_moduleConfiguration": "Konfigurationsmodule",
"lang_moduleName": "Modulname",
@@ -95,6 +93,7 @@
"lang_noValidCert": "Der Server besitzt kein oder ein nicht valides Zertifikat.",
"lang_onProblemSearchBase": "Werden keine Benutzer gefunden, dann \u00fcberpr\u00fcfen Sie bitte die Suchbasis",
"lang_or": "oder",
+ "lang_pwlogin_user_only": "Alle au\u00dfer root",
"lang_rebuild": "Neu generieren",
"lang_rebuildLong": "Modul oder Konfiguration neu generieren. Das entsprechende Modul bzw. Konfiguration ist aktuell und sollte nicht neu generiert werden m\u00fcssen.",
"lang_rebuildOutdatedLong": "Modul oder Konfiguration neu generieren. Das entsprechende Modul bzw. Konfiguration ist veraltet oder nicht vorhanden.",
@@ -102,34 +101,34 @@
"lang_replaces": "Ersetzt Modul: ",
"lang_restartWizard": "Wizard neu starten",
"lang_rootKey": "root pubkey (\u00f6ffentlicher Schl\u00fcssel)",
- "lang_rootKeyInfo": "Tragen Sie hier den \u00f6ffentlichen Schl\u00fcssel eines Schl\u00fcsselpaars ein, mit dem Sie sich als root-Benutzer an den Clients anmelden wollen. Lassen Sie das Feld leer, um diese Funktion nicht zu verwenden.",
+ "lang_rootKeyInfo": "Tragen Sie hier den \u00f6ffentlichen Schl\u00fcssel eines Schl\u00fcsselpaars ein, mit dem Sie sich als root-Benutzer an den Clients anmelden wollen.",
"lang_screenBackground": "Hintergrund",
"lang_screenBackgroundDescription": " - Ein Hintergrund, bestehend aus einem zweifarbigem Gradienten.",
- "lang_screenColor": "Farbe",
"lang_screenClock": "Uhr",
+ "lang_screenColor": "Farbe",
"lang_screenDescriptionIdleKill": "Ein Bildschirmschoner mit Timeout, nach dessen Ablauf alle Anwendungen ohne weitere Nachfragen geschlossen werden und der Nutzer ausgeloggt wird.",
"lang_screenDescriptionNoTimeout": "Ein Bildschirmschoner ohne Timeout.",
"lang_screenDescriptionShutdown": "Ein Bildschirmschoner mit Timeout, nach dessen Ablauf alle Anwendungen ohne weitere Nachfragen geschlossen werden und der PC heruntergefahren oder neugestartet wird.",
"lang_screenHeader": "Header",
"lang_screenLabel": "Label",
"lang_screenLocked": "Sperrbildschirm",
- "lang_screenMessageDefaultIdleKill": "Diese Sitzung wird bei Inaktivität in %1 beendet.",
+ "lang_screenMessageDefaultIdleKill": "Diese Sitzung wird bei Inaktivit\u00e4t in %1 beendet.",
"lang_screenMessageDefaultIdleKillLocked": "Diese Sitzung wird in %1 beendet, wenn sie nicht entsperrt wird.",
"lang_screenMessageDefaultNoTimeout": "Dieser Bildschirm wird gerade geschont.",
"lang_screenMessageDefaultNoTimeoutLocked": "Dieser Rechner ist gesperrt.",
"lang_screenMessageDefaultShutdown": "Achtung: Rechner wird in %1 heruntergefahren!",
"lang_screenMessageDefaultShutdownLocked": "Achtung: Rechner wird in %1 heruntergefahren!",
"lang_screenQss": "QSS",
- "lang_screenQssDefault": "#Saver {\n background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #443, stop:1 #000)\n}\n\nQLabel {\n color: #f64;\n}\n\n#lblClock {\n color: #999;\n font-size: 20pt;\n}\n\n#lblHeader {\n font-size: 20pt;\n}\n",
- "lang_screenSize": "Gr\u00f6ße",
+ "lang_screenQssDefault": "#Saver {\r\n background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #443, stop:1 #000)\r\n}\r\n\r\nQLabel {\r\n color: #f64;\r\n}\r\n\r\n#lblClock {\r\n color: #999;\r\n font-size: 20pt;\r\n}\r\n\r\n#lblHeader {\r\n font-size: 20pt;\r\n}\r\n",
+ "lang_screenSize": "Gr\u00f6\u00dfe",
+ "lang_screenText": "Inhaltstext Bearbeiten",
+ "lang_screenTextDefaultIdleKill": "<html><body>Keine Nutzeraktivit\u00e4t festgestellt. <br>Zum oben angegebenen Zeitpunkt wird die aktuell laufende Sitzung beendet, wenn der Rechner nicht mehr verwendet wird. <br>Alle noch laufenden Programme <br>werden ohne Nachfrage geschlossen. Stellen Sie daher sicher, bis zum angegebenen Zeitpunkt <br>s\u00e4mtliche sich in Bearbeitung befindlichen Daten abzuspeichern. <br><br>Dies dient dazu zu vermeiden, dass ein Rechner stundenlang gesperrt wird und somit <br>anderen Nutzern nicht zur Verf\u00fcgung steht.<\/body><\/html>",
+ "lang_screenTextDefaultIdleKillLocked": "<html><body><br>Zum oben angegebenen Zeitpunkt wird die aktuell laufende Sitzung beendet, wenn sie zuvor nicht wieder entsperrt wird. <br>Alle noch laufenden Programme werden ohne Nachfrage geschlossen. <br>Stellen Sie daher sicher, bis zum angegebenen Zeitpunkt <br>s\u00e4mtliche sich in Bearbeitung befindlichen Daten abzuspeichern, bzw. die Sitzung wieder zu entsperren. <br><br>Dies dient dazu zu vermeiden, dass ein Rechner stundenlang gesperrt wird und somit<br>anderen Nutzern nicht zur Verf\u00fcgung steht.<\/body><\/html>",
+ "lang_screenTextDefaultShutdown": "<html><body>Achtung: Zum oben angegebenen Zeitpunkt wird der Computer heruntergefahren bzw. neugestartet. <br>Alle noch laufenden Programme werden ohne Nachfrage beendet. Stellen Sie daher sicher, bis <br>zum angegebenen Zeitpunkt s\u00e4mtliche Daten abzuspeichern und die Sitzung zu verlassen.<\/body><\/html>",
+ "lang_screenTextInherit": "Werte Erben",
"lang_screenTitleIdleKill": "Idle Kill",
"lang_screenTitleNoTimeout": "Ohne Timeout",
"lang_screenTitleShutdown": "Herunterfahren",
- "lang_screenText": "Inhaltstext Bearbeiten",
- "lang_screenTextDefaultIdleKill": "<html><body>Keine Nutzeraktivität festgestellt. <br>Zum oben angegebenen Zeitpunkt wird die aktuell laufende Sitzung beendet, wenn der Rechner nicht mehr verwendet wird. <br>Alle noch laufenden Programme <br>werden ohne Nachfrage geschlossen. Stellen Sie daher sicher, bis zum angegebenen Zeitpunkt <br>sämtliche sich in Bearbeitung befindlichen Daten abzuspeichern. <br><br>Dies dient dazu zu vermeiden, dass ein Rechner stundenlang gesperrt wird und somit <br>anderen Nutzern nicht zur Verfügung steht.</body></html>",
- "lang_screenTextDefaultIdleKillLocked": "<html><body><br>Zum oben angegebenen Zeitpunkt wird die aktuell laufende Sitzung beendet, wenn sie zuvor nicht wieder entsperrt wird. <br>Alle noch laufenden Programme werden ohne Nachfrage geschlossen. <br>Stellen Sie daher sicher, bis zum angegebenen Zeitpunkt <br>sämtliche sich in Bearbeitung befindlichen Daten abzuspeichern, bzw. die Sitzung wieder zu entsperren. <br><br>Dies dient dazu zu vermeiden, dass ein Rechner stundenlang gesperrt wird und somit<br>anderen Nutzern nicht zur Verfügung steht.</body></html>",
- "lang_screenTextDefaultShutdown": "<html><body>Achtung: Zum oben angegebenen Zeitpunkt wird der Computer heruntergefahren bzw. neugestartet. <br>Alle noch laufenden Programme werden ohne Nachfrage beendet. Stellen Sie daher sicher, bis <br>zum angegebenen Zeitpunkt sämtliche Daten abzuspeichern und die Sitzung zu verlassen.</body></html>",
- "lang_screenTextInherit": "Werte Erben",
"lang_screenUnlocked": "Bildschirmschoner",
"lang_searchBase": "Suchbasis",
"lang_selectFile": "Bitte w\u00e4hlen Sie ein Archiv",
@@ -150,7 +149,10 @@
"lang_show": "Ansehen",
"lang_showLong": "Inhalt des Moduls anzeigen.",
"lang_skip": "Weiter",
- "lang_sshMultipleHeadsup": "Wenn Sie mehrere Pubkeys angeben wollen, k\u00f6nnen Sie entsprechend mehrere Module vom Typ SSH zu einer Systemkonfiguration hinzuf\u00fcgen. In diesem Fall sollten Sie jedoch darauf achten, dass alle Konfigurationen die gleichen Einstellungen f\u00fcr Port und Passwortlogin haben, da ansonsten undefiniert ist, welche der Einstellungen greifen wird.",
+ "lang_sshAllowPass": "Login via Passwort zulassen",
+ "lang_sshAllowPassInfo": "Legt fest, ob sich per SSH mit Passwort eingeloggt werden darf, oder nur das pubkey-Verfahren erlaubt ist.",
+ "lang_sshAllowedUsers": "Zugelassene Nutzer",
+ "lang_sshAllowedUsersInfo": "Legt fest, welche Nutzer sich per SSH einloggen d\u00fcrfen. Der spezielle Nutzer \"demo\" kann sich generell nicht per SSH einloggen, unabh\u00e4ngig der Konfiguration.",
"lang_ssl": "SSL",
"lang_sslDescription": "Die Verbindung zum AD\/LDAP-Server mit SSL sichern. (Die Verbindung zwischen Client und Proxy wird in jedem Fall mit SSL abgewickelt.)",
"lang_supportedFiles": "Unterst\u00fctzte Archivformate",
@@ -167,5 +169,8 @@
"lang_userDirectory": "Benutzerverzeichnis",
"lang_userDirectoryInfo1": "Optionale Angabe: Wenn die Clients f\u00fcr die Benutzer ein eigenes Verzeichnis (Homeverzeichnis, Benutzerverzeichnis) von einem Server einbinden sollen, geben Sie bitte hier das Format in UNC-Notation an, also z.B.",
"lang_userDirectoryInfo2": "%s ist dabei ein Platzhalter f\u00fcr den Login-Namen des Benutzers.",
- "lang_userDirectoryInfo3": "Das Verzeichnis wird mit den gleichen Zugangsdaten eingebunden, die der Benutzer beim Login angibt. (D.h. kein Kerberos Support o.\u00e4.)"
-}
+ "lang_userDirectoryInfo3": "Das Verzeichnis wird mit den gleichen Zugangsdaten eingebunden, die der Benutzer beim Login angibt. (D.h. kein Kerberos Support o.\u00e4.)",
+ "lang_user_all": "Alle Nutzer",
+ "lang_user_root_only": "Nur root",
+ "lang_user_user_only": "Alle au\u00dfer root"
+} \ No newline at end of file
diff --git a/modules-available/sysconfig/lang/en/config-module.json b/modules-available/sysconfig/lang/en/config-module.json
index 6728f5fd..d4e1a8cc 100644
--- a/modules-available/sysconfig/lang/en/config-module.json
+++ b/modules-available/sysconfig/lang/en/config-module.json
@@ -9,11 +9,14 @@
"group_branding": "Branding",
"group_generic": "Generic",
"group_screensaver": "Screen saver styling",
- "group_sshconfig": "SSH",
+ "group_sshconfig": "SSH config",
+ "group_sshkey": "SSH key",
"ldapAuth_description": "This module enables you to create a simple LDAP authentication module.",
"ldapAuth_title": "LDAP Authentication",
"screensaver_title": "Screensaver customization",
"screensaver_description": "With this module you can customize the style (QSS) and texts of the screensaver.",
"sshconfig_description": "Here you can set whether the sshd on the clients will start, and what options it will use.",
- "sshconfig_title": "SSH daemon"
-} \ No newline at end of file
+ "sshconfig_title": "SSH daemon",
+ "sshkey_title": "SSH key",
+ "sshkey_description": "Add a public key to the authorized_keys file of the root user. You can then use the according private key to log in on a running client as root via SSH. root login needs to be enabled in the according SSH daemon module."
+}
diff --git a/modules-available/sysconfig/lang/en/template-tags.json b/modules-available/sysconfig/lang/en/template-tags.json
index 40484b5a..89f6886b 100644
--- a/modules-available/sysconfig/lang/en/template-tags.json
+++ b/modules-available/sysconfig/lang/en/template-tags.json
@@ -8,8 +8,6 @@
"lang_adText3": "Next the distinguished name of the user must be specified. You can determine this by dsquery command line program on a domain controller as the following call:",
"lang_adText4": "After entering all required data in the next step, it checks whether communication is possible with the AD.",
"lang_add": "Add",
- "lang_allowPass": "Allow password login",
- "lang_allowPassInfo": "When active, logins via username and password are allowed. Otherwise, only pubkey authentication is possible.",
"lang_asteriskMandatory": "Fields marked with (*) are mandatory",
"lang_availableModules": "Available Configuration Modules",
"lang_availableSystem": "Available System Configuration",
@@ -74,10 +72,10 @@
"lang_mapModeNativeFallback": "Natively map inside VM; fallback to VMware Shared Folders",
"lang_mapModeNone": "Don't map shares at all",
"lang_mapModeVmware": "VMware Shared Folders [VMwareTools]",
+ "lang_modStillUsedBy": "Module still in use by:",
"lang_mode": "Mode",
- "lang_modeEasy": "Easy Mode",
"lang_modeAdvanced": "Advanced Mode",
- "lang_modStillUsedBy": "Module still in use by:",
+ "lang_modeEasy": "Easy Mode",
"lang_moduleChoose": "Please select which type of configuration module you want to create.",
"lang_moduleConfiguration": "Module Configuration",
"lang_moduleName": "Module Name",
@@ -95,6 +93,7 @@
"lang_noValidCert": "The server did not supply a certificate, or the certificate is invalid.",
"lang_onProblemSearchBase": "If no users are found, please check the search base",
"lang_or": "or",
+ "lang_pwlogin_user_only": "Everyone except root",
"lang_rebuild": "Rebuild",
"lang_rebuildLong": "Rebuild module or configuration.",
"lang_rebuildOutdatedLong": "Rebuild module or configuration. The module\/configuration is outdated or missing and should be regenerated.",
@@ -102,11 +101,11 @@
"lang_replaces": "Replaces module: ",
"lang_restartWizard": "Restart wizard",
"lang_rootKey": "root pubkey",
- "lang_rootKeyInfo": "Here you can add the public key of a keypair that you want to use for authentication as root-user. Leave this field blank to disable the feature.",
+ "lang_rootKeyInfo": "Here you can add the public key of a keypair that you want to use for authentication as root-user.",
"lang_screenBackground": "Background",
"lang_screenBackgroundDescription": " - A background consisting of a gradient with two colors.",
- "lang_screenColor": "Color",
"lang_screenClock": "Clock",
+ "lang_screenColor": "Color",
"lang_screenDescriptionIdleKill": "A screensaver with a timeout which on it's expiration will close all running applications without further requests and logout the user.",
"lang_screenDescriptionNoTimeout": "A screensaver without a timeout.",
"lang_screenDescriptionShutdown": "A screensaver with a timeout which on it's expiration the PC will shutdown or restart. All applications will be closed without further requests.",
@@ -120,16 +119,16 @@
"lang_screenMessageDefaultShutdown": "Caution: Computer will shutdown in %1!",
"lang_screenMessageDefaultShutdownLocked": "Caution: Computer will shutdown in %1!",
"lang_screenQss": "QSS",
- "lang_screenQssDefault": "#Saver {\n background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #443, stop:1 #000)\n}\n\nQLabel {\n color: #f64;\n}\n\n#lblClock {\n color: #999;\n font-size: 20pt;\n}\n\n#lblHeader {\n font-size: 20pt;\n}\n",
+ "lang_screenQssDefault": "#Saver {\r\n background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #443, stop:1 #000)\r\n}\r\n\r\nQLabel {\r\n color: #f64;\r\n}\r\n\r\n#lblClock {\r\n color: #999;\r\n font-size: 20pt;\r\n}\r\n\r\n#lblHeader {\r\n font-size: 20pt;\r\n}\r\n",
"lang_screenSize": "Size",
+ "lang_screenText": "Edit Contenttext",
+ "lang_screenTextDefaultIdleKill": "<html><body>No user activity detected. <br>If the computer is not used until the time specified above, the session will end. <br> All running applications <br>will be closed without further requests. Make sure that all files and changes are saved <br> before the time runs out. <br><br>It prevents computers from beeing locked for hours and <br>not beeing available for other users.<\/body><\/html>",
+ "lang_screenTextDefaultIdleKillLocked": "<html><body><br>The current session will end by the time specified above if the computer isn't unlocked before. <br>All running applications will be closed without further requests. <br>Make sure that all files and changes are saved <br>or the session is unlocked before the time runs out. <br><br>It prevents computers from beeing locked for hours and <br>not beeing available for other users.<\/body><\/html>",
+ "lang_screenTextDefaultShutdown": "<html><body>Caution: The computer will shutdown or restart respectively at the specified time above. <br>All running applications will be closed without further requests. Make sure to save all files and changes and leave the session<br>before the time runs out.<\/body><\/html>",
+ "lang_screenTextInherit": "Inherit Values",
"lang_screenTitleIdleKill": "Idle Kill",
"lang_screenTitleNoTimeout": "No Timeout",
"lang_screenTitleShutdown": "Shutdown",
- "lang_screenText": "Edit Contenttext",
- "lang_screenTextDefaultIdleKill": "<html><body>No user activity detected. <br>If the computer is not used until the time specified above, the session will end. <br> All running applications <br>will be closed without further requests. Make sure that all files and changes are saved <br> before the time runs out. <br><br>It prevents computers from beeing locked for hours and <br>not beeing available for other users.</body></html>",
- "lang_screenTextDefaultIdleKillLocked": "<html><body><br>The current session will end by the time specified above if the computer isn't unlocked before. <br>All running applications will be closed without further requests. <br>Make sure that all files and changes are saved <br>or the session is unlocked before the time runs out. <br><br>It prevents computers from beeing locked for hours and <br>not beeing available for other users.</body></html>",
- "lang_screenTextDefaultShutdown": "<html><body>Caution: The computer will shutdown or restart respectively at the specified time above. <br>All running applications will be closed without further requests. Make sure to save all files and changes and leave the session<br>before the time runs out.</body></html>",
- "lang_screenTextInherit": "Inherit Values",
"lang_screenUnlocked": "Screensaver",
"lang_searchBase": "Search Base",
"lang_selectFile": "Please select an archive",
@@ -150,6 +149,10 @@
"lang_show": "Show",
"lang_showLong": "Show content of module.",
"lang_skip": "Next",
+ "lang_sshAllowPass": "Allow login with password",
+ "lang_sshAllowPassInfo": "Set whether users can log in via SSH using the account's password; otherwise, only pubkey-auth is enabled.",
+ "lang_sshAllowedUsers": "Allowed users",
+ "lang_sshAllowedUsersInfo": "Decides which users are allowed to log in via SSH. The special user account \"demo\" is never allowed to log in via SSH, regardless of this setting.",
"lang_sshMultipleHeadsup": "If you want to add multiple SSH keys to the system, you can simply create multiple modules of type SSH and add them all to your system config. Note that you should have matching port and password settings for those configs, as it is currently undefined which of the settings will apply to the final configuration.",
"lang_ssl": "SSL",
"lang_sslDescription": "Use SSL encryption to talk to AD\/LDAP server.",
@@ -167,5 +170,8 @@
"lang_userDirectory": "User Directory",
"lang_userDirectoryInfo1": "Optional: If the clients should embed a separate directory (home directory, user directory) from a server for the user, please enter here the format in UNC notation, eg",
"lang_userDirectoryInfo2": "%s is a placeholder for the user's login name.",
- "lang_userDirectoryInfo3": "The directory is loaded with the same credentials that the user specifies when login. (That is no Kerberos support, etc.)"
+ "lang_userDirectoryInfo3": "The directory is loaded with the same credentials that the user specifies when login. (That is no Kerberos support, etc.)",
+ "lang_user_all": "Everyone",
+ "lang_user_root_only": "Only root",
+ "lang_user_user_only": "Everyone except root"
} \ No newline at end of file
diff --git a/modules-available/sysconfig/templates/sshconfig-start.html b/modules-available/sysconfig/templates/sshconfig-start.html
index 33108161..df39feb0 100644
--- a/modules-available/sysconfig/templates/sshconfig-start.html
+++ b/modules-available/sysconfig/templates/sshconfig-start.html
@@ -5,33 +5,38 @@
<span class="input-group-addon">{{lang_moduleName}}</span>
<input type="text" name="title" value="{{title}}" class="form-control" autofocus="autofocus">
</div>
+ <br>
<div class="form-group">
- <div class="checkbox">
- <input type="checkbox" name="allowPasswordLogin" value="yes" {{#apl}}checked{{/apl}}>
- <label><b>{{lang_allowPass}}</b></label>
- </div>
+ <label>{{lang_sshAllowedUsers}}
+ <select class="form-control" name="allowedUsersLogin">
+ <option value="ROOT_ONLY" {{USR_ROOT_ONLY_selected}}>{{lang_user_root_only}}</option>
+ <option value="USER_ONLY" {{USR_USER_ONLY_selected}}>{{lang_user_user_only}}</option>
+ <option value="ALL" {{USR_ALL_selected}}>{{lang_user_all}}</option>
+ </select>
+ </label>
<div>
- <i>{{lang_allowPassInfo}}</i>
+ <i>{{lang_sshAllowedUsersInfo}}</i>
</div>
</div>
<div class="form-group">
- <label for="root-key">{{lang_rootKey}}</label>
- <input class="form-control" type="text" name="publicKey" value="{{publicKey}}" id="root-key" pattern="[a-z0-9\-]+ +[a-zA-Z0-9=/\+]+ +.*">
- <i>{{lang_rootKeyInfo}}</i>
+ <label>{{lang_sshAllowPass}}
+ <select class="form-control" name="allowPasswordLogin">
+ <option value="NO" {{PWD_NO_selected}}>{{lang_no}}</option>
+ <option value="USER_ONLY" {{PWD_USER_ONLY_selected}}>{{lang_pwlogin_user_only}}</option>
+ <option value="YES" {{PWD_YES_selected}}>{{lang_yes}}</option>
+ </select>
+ </label>
+ <div>
+ <i>{{lang_sshAllowPassInfo}}</i>
+ </div>
</div>
<div class="form-group">
<label for="port">{{lang_listenPort}}</label>
<input class="form-control" type="text" name="listenPort" value="{{listenPort}}" id="port" pattern="\d+" placeholder="22">
<i>{{lang_listenPortInfo}}</i>
</div>
- <p>
- <i>
- {{lang_sshMultipleHeadsup}}
- </i>
- </p>
<div class="btn-group pull-right">
<button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
<div class="clearfix"></div>
</form>
-
diff --git a/modules-available/sysconfig/templates/sshkey-start.html b/modules-available/sysconfig/templates/sshkey-start.html
new file mode 100644
index 00000000..52709984
--- /dev/null
+++ b/modules-available/sysconfig/templates/sshkey-start.html
@@ -0,0 +1,18 @@
+<form role="form" enctype="multipart/form-data" method="post" action="?do=SysConfig&amp;action=addmodule&amp;step={{step}}">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="edit" value="{{edit}}">
+ <div class="input-group">
+ <span class="input-group-addon">{{lang_moduleName}}</span>
+ <input type="text" name="title" value="{{title}}" class="form-control" autofocus="autofocus">
+ </div>
+ <div class="form-group">
+ <label for="root-key">{{lang_rootKey}}</label>
+ <input class="form-control" type="text" name="publicKey" value="{{publicKey}}" id="root-key" required pattern="[a-z0-9\-]+ +[a-zA-Z0-9=/\+]+ +.*">
+ <i>{{lang_rootKeyInfo}}</i>
+ </div>
+ <div class="btn-group pull-right">
+ <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ </div>
+ <div class="clearfix"></div>
+</form>
+