diff options
31 files changed, 650 insertions, 387 deletions
diff --git a/inc/paginate.inc.php b/inc/paginate.inc.php index cdb4adf1..b212e252 100644 --- a/inc/paginate.inc.php +++ b/inc/paginate.inc.php @@ -65,8 +65,6 @@ class Paginate $countQuery = preg_replace('/ORDER\s+BY\s.*?(\sASC|\sDESC|$)/is', '', $this->query); $countQuery = preg_replace('/SELECT\s.*?\sFROM\s/is', 'SELECT Count(*) AS rowcount FROM ', $countQuery); $countRes = Database::queryFirst($countQuery, $args); - $args['limit_start'] = $this->currentPage; - $args['limit_count'] = $this->perPage; $query = $this->query . ' LIMIT ' . ($this->currentPage * $this->perPage) . ', ' . $this->perPage; $retval = Database::simpleQuery($query, $args); $this->totalRows = (int)$countRes['rowcount']; diff --git a/modules-available/baseconfig_partitions_cdn/lang/de/permissions.json b/modules-available/baseconfig_partitions_cdn/lang/de/permissions.json new file mode 100644 index 00000000..d5805e3d --- /dev/null +++ b/modules-available/baseconfig_partitions_cdn/lang/de/permissions.json @@ -0,0 +1,7 @@ +{ + "show": "Zeige Partitionen. Wird nicht benötigt, wenn Nutzer eine der anderen Rechte hat.", + "partitions.add": "Füge eine neue Partition hinzu.", + "partitions.delete": "Lösche eine Partition.", + "partitions.edit": "Speichere Änderungen an Partitionen.", + "partitions.reset": "Setze Partitionen auf Standardwerte zurück." +}
\ No newline at end of file diff --git a/modules-available/baseconfig_partitions_cdn/lang/en/permissions.json b/modules-available/baseconfig_partitions_cdn/lang/en/permissions.json new file mode 100644 index 00000000..f751a839 --- /dev/null +++ b/modules-available/baseconfig_partitions_cdn/lang/en/permissions.json @@ -0,0 +1,7 @@ +{ + "show": "Show Partitions. Not needed if User has any of the other permissions.", + "partitions.add": "Add a new partition.", + "partitions.delete": "Delete a partition.", + "partitions.edit": "Save changes of partitions.", + "partitions.reset": "Reset partitions to default." +}
\ No newline at end of file diff --git a/modules-available/baseconfig_partitions_cdn/lang/en/template-tags.json b/modules-available/baseconfig_partitions_cdn/lang/en/template-tags.json index 04ce6c80..472e5870 100644 --- a/modules-available/baseconfig_partitions_cdn/lang/en/template-tags.json +++ b/modules-available/baseconfig_partitions_cdn/lang/en/template-tags.json @@ -1,9 +1,9 @@ { "lang_areYouSureNoUndo": "Are you sure? This cannot be undone!", - "lang_confirm": "Would you like to save the settings on [ \/srv\/openslx\/www\/boot\/config ] ?", + "lang_confirm": "Would you like to save the settings on \/srv\/openslx\/www\/boot\/config?", "lang_create": "Create", "lang_discardChanges": "Discard Changes", - "lang_explanationText": "Here you can configure what kind of partitions will be created on the client computers, and where they will be mounted", + "lang_explanationText": "Here you can configure what kind of partitions will be created on the client computers, and where they will be mounted.", "lang_helpId": "Partition Id", "lang_helpMountPoint": "Must be a directory: \/example\/directory\/", "lang_helpOptions": "Currently, only option 'bootable' is available", diff --git a/modules-available/baseconfig_partitions_cdn/page.inc.php b/modules-available/baseconfig_partitions_cdn/page.inc.php index a1d1445f..b61ea448 100644 --- a/modules-available/baseconfig_partitions_cdn/page.inc.php +++ b/modules-available/baseconfig_partitions_cdn/page.inc.php @@ -10,23 +10,39 @@ class Page_BaseConfig_Partitions_CDN extends Page $action = Request::post('action'); if($action == 'new_partition') { - $this->addPartition(); + if (User::hasPermission("partitions.add")) { + $this->addPartition(); + } } if($action == 'reset') { - $this->resetConfig(); + if (User::hasPermission("partitions.reset")) { + $this->resetConfig(); + } } $deletePartition = Request::get('deletePartition'); if($deletePartition !== false) { // TODO: CSRF: Actions that change/update/delete anything should be POST - $this->deletePartition($deletePartition); + if (User::hasPermission("partitions.delete")) { + $this->deletePartition($deletePartition); + } } - $this->updatePartitions(); + if(User::hasPermission("partitions.edit")) { + $this->updatePartitions(); + } } protected function doRender() { - if (!User::hasPermission('baseconfig_local')) { + if (!User::isLoggedIn()) { + Message::addError('main.no-permission'); + Util::redirect('?do=Main'); + } + + $hasAnyRight = User::hasPermission("partitions.add") || User::hasPermission("partitions.delete") + || User::hasPermission("partitions.edit") || User::hasPermission("partitions.reset"); + + if (!(User::hasPermission("show") || $hasAnyRight)) { Message::addError('main.no-permission'); Util::redirect('?do=Main'); } @@ -48,7 +64,11 @@ class Page_BaseConfig_Partitions_CDN extends Page Render::addTemplate('_page', array( 'partitions' => $partitions, - 'user' => User::getId() + 'user' => User::getId(), + 'allowedToAdd' => User::hasPermission("partitions.add"), + 'allowedToDelete' => User::hasPermission("partitions.delete"), + 'allowedToEdit' => User::hasPermission("partitions.edit"), + 'allowedToReset' => User::hasPermission("partitions.reset") )); } @@ -92,9 +112,9 @@ class Page_BaseConfig_Partitions_CDN extends Page private function updatePartitions(){ $partitions = array(); foreach($_POST as $key => $value){ - if(substr($key,0,9) == 'partition'){ - $id = substr($key,10,1); - $type = substr($key,12); + + if (substr($key, 0, 9) == 'partition') { + list($key, $id, $type) = explode("-", $key); $partitions[$id][$type] = $value; } } @@ -111,6 +131,8 @@ class Page_BaseConfig_Partitions_CDN extends Page Database::exec('UPDATE setting_partition SET partition_id=:partition_id, size=:size, mount_point=:mount_point, options=:options WHERE id=:id AND user=:user;', $data); } + + if (!empty($partitions)) { Message::addSuccess('partitions-updated'); Util::redirect('?do=BaseConfig_Partitions_CDN'); @@ -129,5 +151,6 @@ class Page_BaseConfig_Partitions_CDN extends Page Database::exec ( "INSERT INTO setting_partition SET partition_id = '40', size = '20G', mount_point = '/cache/export/dnbd3', user = :user", $data ); Database::exec ( "INSERT INTO setting_partition SET partition_id = '41', size = '5G', mount_point = '/home', user = :user", $data ); Database::exec ( "INSERT INTO setting_partition SET partition_id = '82', size = '1G', user = :user", $data ); + Util::redirect('?do=BaseConfig_Partitions_CDN'); } }
\ No newline at end of file diff --git a/modules-available/baseconfig_partitions_cdn/permissions/permissions.json b/modules-available/baseconfig_partitions_cdn/permissions/permissions.json new file mode 100644 index 00000000..286a975b --- /dev/null +++ b/modules-available/baseconfig_partitions_cdn/permissions/permissions.json @@ -0,0 +1,7 @@ +[ + "show", + "partitions.add", + "partitions.delete", + "partitions.edit", + "partitions.reset" +]
\ No newline at end of file diff --git a/modules-available/baseconfig_partitions_cdn/style.css b/modules-available/baseconfig_partitions_cdn/style.css new file mode 100644 index 00000000..d55e5e5b --- /dev/null +++ b/modules-available/baseconfig_partitions_cdn/style.css @@ -0,0 +1,4 @@ +.missingInput { + border-color: rgba(255, 0, 0, 0.8); + box-shadow: 0 1px 1px rgba(255, 0, 0, 0.075) inset, 0 0 8px rgba(255, 0, 0, 0.6); +}
\ No newline at end of file diff --git a/modules-available/baseconfig_partitions_cdn/templates/_page.html b/modules-available/baseconfig_partitions_cdn/templates/_page.html index 71cbb7db..2cb3f2a6 100644 --- a/modules-available/baseconfig_partitions_cdn/templates/_page.html +++ b/modules-available/baseconfig_partitions_cdn/templates/_page.html @@ -21,7 +21,7 @@ <input name='partition-{{id}}-options' type='text' class='form-control' size='30' value='{{options}}' placeholder='{{lang_partitionOptions}}'/> </div> <div class='col-sm-1 col-md-2'> - <a class='btn btn-danger' href='?do=BaseConfig_Partitions_CDN&deletePartition={{id}}&token={{token}}'> + <a class='btn btn-danger btn-sm {{allowedToDelete}}disabled{{allowedToDelete}}' href='?do=BaseConfig_Partitions_CDN&deletePartition={{id}}&token={{token}}'> <span class='glyphicon glyphicon-trash'></span> </a> </div> @@ -30,16 +30,16 @@ {{/partitions}} <div class='list-group-item clearfix'> <div class="pull-right"> - <a class='btn btn-success ' data-toggle='modal' data-target='#add-partition'> + <button {{^allowedToAdd}}disabled{{/allowedToAdd}} type="button" class='btn btn-success' data-toggle='modal' data-target='#add-partition'> <span class='glyphicon glyphicon-plus'></span> {{lang_newPartition}} - </a> + </button> </div> </div> </div> <div class="pull-right"> - <a class="btn btn-default" data-toggle="modal" data-target="#downloadModal"><span class="glyphicon glyphicon-download-alt"></span> Download</a> + <button type="button" class="btn btn-default" data-toggle="modal" data-target="#downloadModal"><span class="glyphicon glyphicon-download-alt"></span> Download</button> <button class="btn btn-warning" type="reset"><span class="glyphicon glyphicon-refresh"></span> {{lang_discardChanges}}</button> - <button class="btn btn-primary" type="submit"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button> + <button {{^allowedToEdit}}disabled{{/allowedToEdit}} class="btn btn-primary" type="submit"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button> </div> <div class ="modal fade" id="downloadModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> @@ -49,8 +49,10 @@ {{lang_confirm}} </div> <div class="modal-footer"> - <button type="button" onclick="saveConfig(false)" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button> - <button type="button" onclick="saveConfig(true)" class="btn btn-sm btn-danger" name="download"> Download</button> + <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button> + <button type="button" onclick="saveConfig()" class="btn btn-primary" name="download"> + <span class="glyphicon glyphicon-download-alt"></span> Download + </button> </div> </div> </div> @@ -60,7 +62,7 @@ <form method="post" action="?do=BaseConfig_Partitions_CDN"> <input type="hidden" name="token" value="{{token}}"> <input type="hidden" name="action" value="reset"> - <button class="btn btn-danger" type="button" data-toggle="modal" data-target="#resetDefaultModal">{{lang_resetDefault}}</button> + <button {{^allowedToReset}}disabled{{/allowedToReset}} class="btn btn-danger" type="button" data-toggle="modal" data-target="#resetDefaultModal">{{lang_resetDefault}}</button> <div class ="modal fade" id="resetDefaultModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" style="width: 400px" role="document"> @@ -70,7 +72,7 @@ </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button> - <button type="submit" class="btn btn-sm btn-danger" name="resetDefault"> {{lang_resetDefault}}</button> + <button type="submit" class="btn btn-danger" name="resetDefault"> {{lang_resetDefault}}</button> </div> </div> </div> @@ -78,7 +80,7 @@ </form> <!-- Create Partition Window --> -<form action="?do=BaseConfig_Partitions_CDN" method="post"> +<form id="createPartitionForm" action="?do=BaseConfig_Partitions_CDN" method="post"> <div class="modal fade" id="add-partition" tabindex="-1" role="dialog"> <div class="modal-dialog"> @@ -89,12 +91,12 @@ <div class="modal-body"> <div class="input-group"> - <span class="input-group-addon" style="min-width:140px;">{{lang_partitionId}}</span> + <span class="input-group-addon" style="min-width:140px;">{{lang_partitionId}} *</span> <input name="new-partition-id" class="form-control" type="text"> </div> <p class="help-block">{{lang_helpId}}</p> <div class="input-group"> - <span class="input-group-addon" style="min-width:140px;">{{lang_partitionSize}}</span> + <span class="input-group-addon" style="min-width:140px;">{{lang_partitionSize}} *</span> <input name="new-partition-size" class="form-control" type="text"> </div> <p class="help-block">{{lang_helpSize}}</p> @@ -111,8 +113,10 @@ </div> <div class="modal-footer"> - <a class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</a> - <input type="submit" class="btn btn-primary" value="{{lang_create}}"> + <button class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button> + <button type="submit" class="btn btn-success"> + <span class='glyphicon glyphicon-plus'></span> {{lang_create}} + </button> </div> </div> </div> @@ -120,12 +124,28 @@ <input type="hidden" name="action" value="new_partition"> <input type="hidden" name="token" value="{{token}}"> </form> + <script type="text/javascript"> - function saveConfig(download){ - if(download) - window.location = 'api.php?do=baseconfig&user={{user}}&save=true'; - else - window.location = 'api.php?do=baseconfig&user={{user}}'; - } + document.addEventListener("DOMContentLoaded", function () { + $("#createPartitionForm").submit(function () { + var input1 = $("input[name=new-partition-id]"); + var input2 = $("input[name=new-partition-size]"); + var id = $.trim(input1.val()); + var size = $.trim(input2.val()); + if (!id) { + input1.addClass("missingInput"); + } + if (!size) { + input2.addClass("missingInput"); + } + if (!id || !size) { + return false; + } + }); + }); + + function saveConfig(){ + window.location = 'api.php?do=baseconfig&user={{user}}&save=true'; + } </script>
\ No newline at end of file diff --git a/modules-available/locations/page.inc.php b/modules-available/locations/page.inc.php index 0cfa5b90..9112e810 100644 --- a/modules-available/locations/page.inc.php +++ b/modules-available/locations/page.inc.php @@ -446,7 +446,6 @@ class Page_Locations extends Page } $addAllowedLocs = User::getAllowedLocations("location.add"); - $addAllowedLocs[] = 0; $addAllowedList = Location::getLocations(0, 0, true); foreach ($addAllowedList as &$loc) { if (!in_array($loc["locationid"], $addAllowedLocs)) { diff --git a/modules-available/minilinux/lang/de/permissions.json b/modules-available/minilinux/lang/de/permissions.json new file mode 100644 index 00000000..372ffc88 --- /dev/null +++ b/modules-available/minilinux/lang/de/permissions.json @@ -0,0 +1,4 @@ +{ + "show": "Zeige Komponenten des Minilinux. Wird nicht benötigt, wenn Nutzer eine der anderen Rechte hat.", + "update": "Aktualisieren von Komponenten des Minilinux." +}
\ No newline at end of file diff --git a/modules-available/minilinux/lang/en/permissions.json b/modules-available/minilinux/lang/en/permissions.json new file mode 100644 index 00000000..878388b0 --- /dev/null +++ b/modules-available/minilinux/lang/en/permissions.json @@ -0,0 +1,4 @@ +{ + "show": "Show list of minilinux components. Not needed if User has any of the other permissions.", + "update": "Update minilinux components." +}
\ No newline at end of file diff --git a/modules-available/minilinux/page.inc.php b/modules-available/minilinux/page.inc.php index 98b0191d..710ffd15 100644 --- a/modules-available/minilinux/page.inc.php +++ b/modules-available/minilinux/page.inc.php @@ -7,7 +7,12 @@ class Page_MiniLinux extends Page { User::load(); - if (!User::hasPermission('superadmin')) { + if (!User::isLoggedIn()) { + Message::addError('main.no-permission'); + Util::redirect('?do=Main'); + } + + if (!(User::hasPermission("show") || User::hasPermission("update"))) { Message::addError('main.no-permission'); Util::redirect('?do=Main'); } @@ -82,48 +87,51 @@ class Page_MiniLinux extends Page $system['version'] = $selected['version']; } $data['versions'] = array_values($versionNumbers); + $data['allowedToUpdate'] = User::hasPermission("update"); echo Render::parse('filelist', $data); return; case 'download': - $id = Request::post('id'); - $name = Request::post('name'); - if (!$id || !$name || strpos("$id$name", '/') !== false) { - echo "Invalid download request"; - return; - } - $file = false; - $gpg = 'missing'; - foreach ($data['systems'] as &$system) { - if ($system['id'] !== $id) continue; - foreach ($system['versions'] as &$version) { - if ($version['version'] != $selectedVersion) continue; - foreach ($version['files'] as &$f) { - if ($f['name'] !== $name) continue; - $file = $f; - if (!empty($f['gpg'])) $gpg = $f['gpg']; - break; + if (User::hasPermission("update")) { + $id = Request::post('id'); + $name = Request::post('name'); + if (!$id || !$name || strpos("$id$name", '/') !== false) { + echo "Invalid download request"; + return; + } + $file = false; + $gpg = 'missing'; + foreach ($data['systems'] as &$system) { + if ($system['id'] !== $id) continue; + foreach ($system['versions'] as &$version) { + if ($version['version'] != $selectedVersion) continue; + foreach ($version['files'] as &$f) { + if ($f['name'] !== $name) continue; + $file = $f; + if (!empty($f['gpg'])) $gpg = $f['gpg']; + break; + } } } - } - if ($file === false) { - echo "Nonexistent system/file: $id / $name"; - return; - } - $task = Taskmanager::submit('DownloadFile', array( - 'url' => CONFIG_REMOTE_ML . '/' . $id . '/' . $selectedVersion . '/' . $name, - 'destination' => CONFIG_HTTP_DIR . '/' . $id . '/' . $name, - 'gpg' => $gpg - )); - if (!isset($task['id'])) { - echo 'Error launching download task: ' . $task['statusCode']; + if ($file === false) { + echo "Nonexistent system/file: $id / $name"; + return; + } + $task = Taskmanager::submit('DownloadFile', array( + 'url' => CONFIG_REMOTE_ML . '/' . $id . '/' . $selectedVersion . '/' . $name, + 'destination' => CONFIG_HTTP_DIR . '/' . $id . '/' . $name, + 'gpg' => $gpg + )); + if (!isset($task['id'])) { + echo 'Error launching download task: ' . $task['statusCode']; + return; + } + Property::setDownloadTask($file['md5'], $task['id']); + echo Render::parse('download', array( + 'name' => $name, + 'task' => $task['id'] + )); return; } - Property::setDownloadTask($file['md5'], $task['id']); - echo Render::parse('download', array( - 'name' => $name, - 'task' => $task['id'] - )); - return; } } diff --git a/modules-available/minilinux/permissions/permissions.json b/modules-available/minilinux/permissions/permissions.json new file mode 100644 index 00000000..457d9810 --- /dev/null +++ b/modules-available/minilinux/permissions/permissions.json @@ -0,0 +1,4 @@ +[ + "show", + "update" +]
\ No newline at end of file diff --git a/modules-available/minilinux/templates/filelist.html b/modules-available/minilinux/templates/filelist.html index a1d0aa48..34138c14 100644 --- a/modules-available/minilinux/templates/filelist.html +++ b/modules-available/minilinux/templates/filelist.html @@ -18,7 +18,7 @@ <p> {{lang_canUpdate1}} <b>{{title}}</b> {{lang_canUpdate2}} </p> - <p><span class="btn btn-primary" onclick="slxUpdateAll(this, 'download-{{id}}')">{{lang_update}}</span></p> + <button {{^allowedToUpdate}}disabled{{/allowedToUpdate}} class="btn btn-primary" onclick="slxUpdateAll(this, 'download-{{id}}')"><span class="glyphicon glyphicon-refresh"></span> {{lang_update}}<span></span></button> {{/systemChanged}} {{^systemChanged}} <p>{{lang_systemUpdated}}</p> @@ -35,8 +35,8 @@ {{#fileChanged}}<span class="glyphicon glyphicon-exclamation-sign"></span> <b>{{lang_outdated}}</b>{{/fileChanged}} </div> <div class="col-xs-2"> - {{#fileChanged}}<span class="btn btn-primary btn-xs update-button" onclick="slxUpdate('{{uid}}', '{{id}}', '{{name}}')">{{lang_update}}</span>{{/fileChanged}} - {{^fileChanged}}<span class="btn btn-default btn-xs" onclick="slxUpdate('{{uid}}', '{{id}}', '{{name}}')">{{lang_redownload}}</span>{{/fileChanged}} + {{#fileChanged}}<button {{^allowedToUpdate}}disabled{{/allowedToUpdate}} class="btn btn-primary btn-xs update-button" onclick="slxUpdate('{{uid}}', '{{id}}', '{{name}}')"><span class="glyphicon glyphicon-refresh"></span> {{lang_update}}</button> {{/fileChanged}} + {{^fileChanged}}<button {{^allowedToUpdate}}disabled{{/allowedToUpdate}} class="btn btn-default btn-xs" onclick="slxUpdate('{{uid}}', '{{id}}', '{{name}}')"><span class="glyphicon glyphicon-download-alt"></span> {{lang_redownload}}</button> {{/fileChanged}} </div> </div> {{{download}}} diff --git a/modules-available/rebootcontrol/lang/de/permissions.json b/modules-available/rebootcontrol/lang/de/permissions.json new file mode 100644 index 00000000..92eeb37e --- /dev/null +++ b/modules-available/rebootcontrol/lang/de/permissions.json @@ -0,0 +1,5 @@ +{ + "shutdown": "Client herunterfahren.", + "reboot": "Client neustarten.", + "newkeypair": "Neues Schlüsselpaar generieren." +}
\ No newline at end of file diff --git a/modules-available/rebootcontrol/lang/en/permissions.json b/modules-available/rebootcontrol/lang/en/permissions.json new file mode 100644 index 00000000..077890fb --- /dev/null +++ b/modules-available/rebootcontrol/lang/en/permissions.json @@ -0,0 +1,5 @@ +{ + "shutdown": "Shutdown Client.", + "reboot": "Reboot Client.", + "newkeypair": "Generate new Keypair." +}
\ No newline at end of file diff --git a/modules-available/rebootcontrol/page.inc.php b/modules-available/rebootcontrol/page.inc.php index fc3ded8f..fa34a05a 100644 --- a/modules-available/rebootcontrol/page.inc.php +++ b/modules-available/rebootcontrol/page.inc.php @@ -4,6 +4,9 @@ class Page_RebootControl extends Page { private $action = false; + private $allowedShutdownLocs = []; + private $allowedRebootLocs = []; + private $allowedLocs = []; /** * Called before any page rendering happens - early hook to check parameters etc. @@ -17,21 +20,40 @@ class Page_RebootControl extends Page Util::redirect('?do=Main'); // does not return } + $this->allowedShutdownLocs = User::getAllowedLocations("shutdown"); + $this->allowedRebootLocs = User::getAllowedLocations("reboot"); + $this->allowedLocs = array_unique(array_merge($this->allowedShutdownLocs, $this->allowedRebootLocs)); + $this->action = Request::any('action', 'show', 'string'); if ($this->action === 'startReboot' || $this->action === 'startShutdown') { - $clients = Request::post('clients'); - if (!is_array($clients) || empty($clients)) { - Message::addError('no-clients-selected'); - Util::redirect(); - } + $locationId = Request::post('locationId', false, 'int'); if ($locationId === false) { Message::addError('locations.invalid-location-id', $locationId); Util::redirect(); } + $shutdown = $this->action === "startShutdown"; + // Check user permission (if user has no permission, the getAllowed-list will be empty and the check will fail) + if ($shutdown) { + if (!in_array($locationId, $this->allowedShutdownLocs)) { + Message::addError('main.no-permission'); + Util::redirect(); + } + } else { + if (!in_array($locationId, $this->allowedRebootLocs)) { + Message::addError('main.no-permission'); + Util::redirect(); + } + } + + $clients = Request::post('clients'); + if (!is_array($clients) || empty($clients)) { + Message::addError('no-clients-selected'); + Util::redirect(); + } $minutes = Request::post('minutes', 0, 'int'); $list = RebootQueries::getMachinesByUuid($clients); @@ -72,12 +94,34 @@ class Page_RebootControl extends Page //location you want to see, default are "not assigned" clients $requestedLocation = Request::get('location', 0, 'int'); - $data['data'] = RebootQueries::getMachineTable($requestedLocation); - $data['locations'] = Location::getLocations($requestedLocation, 0, true); + // only fill table if user has at least one permission for the location + if (in_array($requestedLocation, $this->allowedLocs)) { + $data['data'] = RebootQueries::getMachineTable($requestedLocation); + $data['allowedToSelect'] = True; + } + $data['locations'] = Location::getLocations($requestedLocation, 0, true); + // Always show public key (it's public, isn't it?) $data['pubKey'] = SSHKey::getPublicKey(); + // disable each location user has no permission for + foreach ($data['locations'] as &$loc) { + if (!in_array($loc["locationid"], $this->allowedLocs)) { + $loc["disabled"] = "disabled"; + } + } + + // Only enable shutdown/reboot-button if user has permission for the location + if (in_array($requestedLocation, $this->allowedShutdownLocs)) { + $data['allowedToShutdown'] = True; + } + if (in_array($requestedLocation, $this->allowedRebootLocs)) { + $data['allowedToReboot'] = True; + } + $data['allowedToGenerateKey'] = User::hasPermission("newkeypair"); + Render::addTemplate('_page', $data); + } } } @@ -86,8 +130,12 @@ class Page_RebootControl extends Page { $this->action = Request::post('action', false, 'string'); if ($this->action === 'generateNewKeypair') { - Property::set("rebootcontrol-private-key", false); - echo SSHKey::getPublicKey(); + if (User::hasPermission("newkeypair")) { + Property::set("rebootcontrol-private-key", false); + echo SSHKey::getPublicKey(); + } else { + echo 'No permission.'; + } } else { echo 'Invalid action.'; } diff --git a/modules-available/rebootcontrol/permissions/permissions.json b/modules-available/rebootcontrol/permissions/permissions.json new file mode 100644 index 00000000..5230c9bd --- /dev/null +++ b/modules-available/rebootcontrol/permissions/permissions.json @@ -0,0 +1,5 @@ +[ + "shutdown", + "reboot", + "newkeypair" +]
\ No newline at end of file diff --git a/modules-available/rebootcontrol/style.css b/modules-available/rebootcontrol/style.css index 442cd5de..f10a6157 100644 --- a/modules-available/rebootcontrol/style.css +++ b/modules-available/rebootcontrol/style.css @@ -16,11 +16,8 @@ margin-bottom: 0; } -#rebootButton, #settingsButton, #selectAllButton, #unselectAllButton { +.controlButtons { margin-left: 10px; -} - -#rebootButton, #shutdownButton, #selectAllButton, #unselectAllButton { width: 140px; } diff --git a/modules-available/rebootcontrol/templates/_page.html b/modules-available/rebootcontrol/templates/_page.html index 1bef8dd4..e540cafb 100644 --- a/modules-available/rebootcontrol/templates/_page.html +++ b/modules-available/rebootcontrol/templates/_page.html @@ -8,58 +8,58 @@ <input type="hidden" name="token" value="{{token}}"> <div class="row"> <div class="col-md-12"> - <label>{{lang_location}}: - <select id="locationDropdown" name="locationId" class="form-control" onchange="selectLocation()"> - {{#locations}} - <option value="{{locationid}}" {{#selected}}selected{{/selected}}>{{locationpad}} {{locationname}}</option> - {{/locations}} - </select> - </label> - <button type="button" id="selectAllButton" class="btn btn-primary pull-right" onclick="selectAllRows()"><span class="glyphicon glyphicon-check"></span> {{lang_selectall}}</button> - <button type="button" id="unselectAllButton" class="btn btn-default pull-right" onclick="unselectAllRows()" style="display: none;"><span class="glyphicon glyphicon-unchecked"></span> {{lang_unselectall}}</button> - <button type="button" id="rebootButton" class="btn btn-warning pull-right" data-toggle="modal" data-target="#rebootModal" disabled><span class="glyphicon glyphicon-repeat"></span> {{lang_rebootButton}}</button> - <button type="button" id="shutdownButton" class="btn btn-danger pull-right" data-toggle="modal" data-target="#shutdownModal" disabled><span class="glyphicon glyphicon-off"></span> {{lang_shutdownButton}}</button> + <label>{{lang_location}}: + <select id="locationDropdown" name="locationId" class="form-control" onchange="selectLocation()"> + {{#locations}} + <option value="{{locationid}}" {{disabled}} {{#selected}}selected{{/selected}}>{{locationpad}} {{locationname}}</option> + {{/locations}} + </select> + </label> + <button type="button" id="selectAllButton" {{^allowedToSelect}}disabled{{/allowedToSelect}} class="btn btn-primary pull-right controlButtons" onclick="selectAllRows()"><span class="glyphicon glyphicon-check"></span> {{lang_selectall}}</button> + <button type="button" id="unselectAllButton" {{^allowedToSelect}}disabled{{/allowedToSelect}} class="btn btn-default pull-right controlButtons" onclick="unselectAllRows()" style="display: none;"><span class="glyphicon glyphicon-unchecked"></span> {{lang_unselectall}}</button> + <button type="button" {{#allowedToReboot}}id="rebootButton"{{/allowedToReboot}} class="btn btn-warning pull-right controlButtons" data-toggle="modal" data-target="#rebootModal" disabled><span class="glyphicon glyphicon-repeat"></span> {{lang_rebootButton}}</button> + <button type="button" {{#allowedToShutdown}}id="shutdownButton"{{/allowedToShutdown}} class="btn btn-danger pull-right controlButtons" data-toggle="modal" data-target="#shutdownModal" disabled><span class="glyphicon glyphicon-off"></span> {{lang_shutdownButton}}</button> </div> </div> <div class="row"> <div class="col-md-12"> <table class="table table-condensed table-hover stupidtable" id="dataTable"> <thead> - <tr> - <th data-sort="string">{{lang_client}}</th> - <th data-sort="ipv4">{{lang_ip}}</th> - <th data-sort="string">{{lang_status}}</th> - <th data-sort="string">{{lang_session}}</th> - <th data-sort="string">{{lang_user}}</th> - <th data-sort="int" data-sort-default="desc">{{lang_selected}}</th> - </tr> + <tr> + <th data-sort="string">{{lang_client}}</th> + <th data-sort="ipv4">{{lang_ip}}</th> + <th data-sort="string">{{lang_status}}</th> + <th data-sort="string">{{lang_session}}</th> + <th data-sort="string">{{lang_user}}</th> + <th data-sort="int" data-sort-default="desc">{{lang_selected}}</th> + </tr> </thead> <tbody> {{#data}} - <tr> - <td> - {{hostname}} - {{^hostname}}{{clientip}}{{/hostname}} - </td> - <td>{{clientip}}</td> - <td class="statusColumn"> - {{#status}} - <span class="text-success">{{lang_on}}</span> - {{/status}} - {{^status}} - <span class="text-danger">{{lang_off}}</span> - {{/status}} - </td> - <td>{{#status}}{{currentsession}}{{/status}}</td> - <td>{{#status}}{{currentuser}}{{/status}}</td> - <td data-sort-value="0" class="checkboxColumn"> - <div class="checkbox"> - <input id="m-{{machineuuid}}" type="checkbox" name="clients[]" value='{{machineuuid}}'> - <label for="m-{{machineuuid}}"></label> - </div> - </td> - </tr> + <tr> + <td> + {{hostname}} + {{^hostname}}{{clientip}}{{/hostname}} + </td> + <td>{{clientip}}</td> + <td class="statusColumn"> + {{#status}} + <span class="text-success">{{lang_on}}</span> + {{/status}} + {{^status}} + <span class="text-danger">{{lang_off}}</span> + {{/status}} + </td> + <td>{{#status}}{{currentsession}}{{/status}}</td> + <td>{{#status}}{{currentuser}}{{/status}}</td> + <td data-sort-value="0" class="checkboxColumn"> + <div class="checkbox"> + <input id="m-{{machineuuid}}" type="checkbox" name="clients[]" value='{{machineuuid}}'> + <label for="m-{{machineuuid}}"></label> + </div> + </td> + </tr> {{/data}} </tbody> </table> @@ -79,7 +79,7 @@ </div> <div class="modal-body"> <span id="pubKeyTitle">{{lang_pubKey}}</span> - <button class="btn btn-s btn-warning pull-right" onclick="generateNewKeypair()" type="button"><span class="glyphicon glyphicon-refresh"></span> {{lang_genNew}}</button> + <button {{^allowedToGenerateKey}}disabled{{/allowedToGenerateKey}} class="btn btn-s btn-warning pull-right" onclick="generateNewKeypair()" type="button"><span class="glyphicon glyphicon-refresh"></span> {{lang_genNew}}</button> <pre id="pubKey">{{pubKey}}</pre> </div> <div class="modal-footer"> @@ -100,7 +100,7 @@ </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button> - <button type="submit" name="action" value="startReboot" class="btn btn-warning"><span class="glyphicon glyphicon-repeat"></span> {{lang_reboot}}</button> + <button type="submit" {{^allowedToReboot}}disabled{{/allowedToReboot}} name="action" value="startReboot" class="btn btn-warning"><span class="glyphicon glyphicon-repeat"></span> {{lang_reboot}}</button> </div> </div> </div> @@ -115,11 +115,11 @@ </div> <div class="modal-body"> {{lang_shutdownCheck}} - {{lang_shutdownIn}} <input id="shutdownTimer" name="minutes" title="{{lang_shutdownIn}}" type="number" value="0" min="0" onkeypress="return isNumberKey(event)"> {{lang_minutes}} + {{lang_shutdownIn}} <input id="shutdownTimer" name="minutes" title="{{lang_shutdownIn}}" type="number" value="0" min="0" onkeypress="return isNumberKey(event)"> {{lang_minutes}} </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_cancel}}</button> - <button type="submit" name="action" value="startShutdown" class="btn btn-danger"><span class="glyphicon glyphicon-off"></span> {{lang_shutdownButton}}</button> + <button type="submit" {{^allowedToShutdown}}disabled{{/allowedToShutdown}} name="action" value="startShutdown" class="btn btn-danger"><span class="glyphicon glyphicon-off"></span> {{lang_shutdownButton}}</button> </div> </div> </div> @@ -162,7 +162,7 @@ $('#rebootButton').prop('disabled', false); $('#shutdownButton').prop('disabled', false); } - }); + }); $('.checkboxColumn').click(function(e) { if (e.target === this) { $(this).find('input[type="checkbox"]').click(); diff --git a/modules-available/syslog/lang/de/permissions.json b/modules-available/syslog/lang/de/permissions.json new file mode 100644 index 00000000..0cd05451 --- /dev/null +++ b/modules-available/syslog/lang/de/permissions.json @@ -0,0 +1,3 @@ +{ + "view": "Client Log anschauen." +}
\ No newline at end of file diff --git a/modules-available/syslog/lang/en/permissions.json b/modules-available/syslog/lang/en/permissions.json new file mode 100644 index 00000000..497e199e --- /dev/null +++ b/modules-available/syslog/lang/en/permissions.json @@ -0,0 +1,3 @@ +{ + "view": "View client log." +}
\ No newline at end of file diff --git a/modules-available/syslog/page.inc.php b/modules-available/syslog/page.inc.php index e63ada85..a26ed9be 100644 --- a/modules-available/syslog/page.inc.php +++ b/modules-available/syslog/page.inc.php @@ -27,6 +27,13 @@ class Page_SysLog extends Page protected function doRender() { + Render::addTemplate("heading"); + + if (!User::hasPermission("view")) { + Message::addError('main.no-permission'); + return; + } + $cutoff = strtotime('-1 month'); $res = Database::simpleQuery("SELECT logtypeid, Count(*) AS counter FROM clientlog WHERE dateline > $cutoff GROUP BY logtypeid ORDER BY counter ASC"); $types = array(); @@ -69,9 +76,22 @@ class Page_SysLog extends Page $whereClause .= "machineuuid='" . preg_replace('/[^0-9a-zA-Z\-]/', '', Request::get('machineuuid', '', 'string')) . "'"; } + + $allowedLocations = User::getAllowedLocations("view"); + $joinClause = ""; + if (!in_array(0, $allowedLocations)) { + $joinClause = "INNER JOIN machine USING (machineuuid)"; + if (empty($whereClause)) + $whereClause .= ' WHERE '; + else + $whereClause .= ' AND '; + + $whereClause .= 'locationid IN (:allowedLocations)'; + } + $lines = array(); - $paginate = new Paginate("SELECT logid, dateline, logtypeid, clientip, machineuuid, description, extra FROM clientlog $whereClause ORDER BY logid DESC", 50); - $res = $paginate->exec(); + $paginate = new Paginate("SELECT logid, dateline, logtypeid, clientlog.clientip, clientlog.machineuuid, description, extra FROM clientlog $joinClause $whereClause ORDER BY logid DESC", 50); + $res = $paginate->exec(array("allowedLocations" => $allowedLocations)); while ($row = $res->fetch(PDO::FETCH_ASSOC)) { $row['date'] = Util::prettyTime($row['dateline']); $row['icon'] = $this->eventToIconName($row['logtypeid']); diff --git a/modules-available/syslog/permissions/permissions.json b/modules-available/syslog/permissions/permissions.json new file mode 100644 index 00000000..f04ea714 --- /dev/null +++ b/modules-available/syslog/permissions/permissions.json @@ -0,0 +1,3 @@ +[ + "view" +]
\ No newline at end of file diff --git a/modules-available/syslog/templates/heading.html b/modules-available/syslog/templates/heading.html new file mode 100644 index 00000000..d6790a21 --- /dev/null +++ b/modules-available/syslog/templates/heading.html @@ -0,0 +1 @@ +<h1>{{lang_clientLog}}</h1>
\ No newline at end of file diff --git a/modules-available/syslog/templates/page-syslog.html b/modules-available/syslog/templates/page-syslog.html index 585aa310..7ab81067 100644 --- a/modules-available/syslog/templates/page-syslog.html +++ b/modules-available/syslog/templates/page-syslog.html @@ -1,7 +1,6 @@ <button type="button" class="btn btn-default pull-right" data-toggle="modal" data-target="#modal-settings"> <span class="glyphicon glyphicon-cog"></span> {{lang_settings}} </button> -<h1>{{lang_clientLog}}</h1> <style type="text/css"> .selectize-dropdown { max-width: 500px; diff --git a/modules-available/systemstatus/lang/de/permissions.json b/modules-available/systemstatus/lang/de/permissions.json new file mode 100644 index 00000000..8fbae7a7 --- /dev/null +++ b/modules-available/systemstatus/lang/de/permissions.json @@ -0,0 +1,13 @@ +{ + "show.overview.diskstat": "Zeige Speicherplatzwerte auf Übersichtsseite.", + "show.overview.services": "Zeige Dienste auf Übersichtsseite.", + "show.overview.addresses": "Zeige Adresskonfiguration auf Übersichtsseite.", + "show.overview.systeminfo": "Zeige Systemwerte auf Übersichtsseite.", + "show.overview.dmsdusers": "Zeige dmsd-Werte auf Übersichtsseite.", + "show.logs.bwlpserver": "Zeige bwlp-Server Logs.", + "show.logs.netstat": "Zeige netstat Logs.", + "show.logs.pslist": "Zeige ps-list Logs.", + "show.logs.ldapad": "Zeige ldap und ad Logs.", + "show.logs.lighttpd": "Zeige light-tpd Logs.", + "serverreboot": "Server neustarten." +}
\ No newline at end of file diff --git a/modules-available/systemstatus/lang/en/permissions.json b/modules-available/systemstatus/lang/en/permissions.json new file mode 100644 index 00000000..f297ff53 --- /dev/null +++ b/modules-available/systemstatus/lang/en/permissions.json @@ -0,0 +1,13 @@ +{ + "show.overview.diskstat": "Show diskstats on overview page.", + "show.overview.services": "Show services on overview page.", + "show.overview.addresses": "Show addresses on overview page.", + "show.overview.systeminfo": "Show systeminfo on overview page.", + "show.overview.dmsdusers": "Show dmsd-stats on overview page.", + "show.logs.bwlpserver": "Show bwlp-server logs.", + "show.logs.netstat": "Show netstat logs.", + "show.logs.pslist": "Show ps-list logs.", + "show.logs.ldapad": "Show ldap+ad logs.", + "show.logs.lighttpd": "Show light-tpd logs.", + "serverreboot": "Reboot server." +}
\ No newline at end of file diff --git a/modules-available/systemstatus/page.inc.php b/modules-available/systemstatus/page.inc.php index 8a0e5f87..df0548fc 100644 --- a/modules-available/systemstatus/page.inc.php +++ b/modules-available/systemstatus/page.inc.php @@ -15,7 +15,12 @@ class Page_SystemStatus extends Page } if (Request::post('action') === 'reboot') { - $this->rebootTask = Taskmanager::submit('Reboot'); + if (User::hasPermission("serverreboot")) { + $this->rebootTask = Taskmanager::submit('Reboot'); + } else { + Message::addError('main.no-permission'); + Util::redirect('?do=Main'); + } } } @@ -33,6 +38,7 @@ class Page_SystemStatus extends Page 'name' => Dictionary::translate('tab_' . $tab) ); } + $data['allowedToReboot'] = User::hasPermission("serverreboot"); Render::addTemplate('_page', $data); } @@ -54,109 +60,122 @@ class Page_SystemStatus extends Page protected function ajaxDmsdUsers() { - $ret = Download::asStringPost('http://127.0.0.1:9080/status/fileserver', false, 2, $code); - $args = array(); - if ($code != 200) { - $args['dmsd_error'] = true; - } else { - $data = @json_decode($ret, true); - if (is_array($data)) { - $args['uploads'] = $data['activeUploads']; - $args['downloads'] = $data['activeDownloads']; + if (User::hasPermission("show.overview.dmsdusers")) { + $ret = Download::asStringPost('http://127.0.0.1:9080/status/fileserver', false, 2, $code); + $args = array(); + if ($code != 200) { + $args['dmsd_error'] = true; + } else { + $data = @json_decode($ret, true); + if (is_array($data)) { + $args['uploads'] = $data['activeUploads']; + $args['downloads'] = $data['activeDownloads']; + } } + if (file_exists('/run/reboot-required.pkgs')) { + $lines = file('/run/reboot-required.pkgs', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $lines = array_unique($lines); + $args['packages'] = implode(', ', $lines); + } + echo Render::parse('ajax-reboot', $args); + } else { + echo "No permission to view this section."; } - if (file_exists('/run/reboot-required.pkgs')) { - $lines = file('/run/reboot-required.pkgs', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $lines = array_unique($lines); - $args['packages'] = implode(', ', $lines); - } - echo Render::parse('ajax-reboot', $args); } protected function ajaxDiskStat() { - $task = Taskmanager::submit('DiskStat'); - if ($task === false) - return; - $task = Taskmanager::waitComplete($task, 3000); + if (User::hasPermission("show.overview.diskstat")) { + $task = Taskmanager::submit('DiskStat'); + if ($task === false) + return; + $task = Taskmanager::waitComplete($task, 3000); - if (!isset($task['data']['list']) || empty($task['data']['list'])) { - Taskmanager::addErrorMessage($task); - return; - } - $store = Property::getVmStoreUrl(); - $storeUsage = false; - $systemUsage = false; - if ($store !== false) { - if ($store === '<local>') - $storePoint = '/'; - else - $storePoint = CONFIG_VMSTORE_DIR; - // Determine free space - foreach ($task['data']['list'] as $entry) { - if ($entry['mountPoint'] === $storePoint) { - $storeUsage = array( - 'percent' => $entry['usedPercent'], - 'size' => Util::readableFileSize($entry['sizeKb'] * 1024), - 'free' => Util::readableFileSize($entry['freeKb'] * 1024), - 'color' => $this->usageColor($entry['usedPercent']) - ); + if (!isset($task['data']['list']) || empty($task['data']['list'])) { + Taskmanager::addErrorMessage($task); + return; + } + $store = Property::getVmStoreUrl(); + $storeUsage = false; + $systemUsage = false; + if ($store !== false) { + if ($store === '<local>') + $storePoint = '/'; + else + $storePoint = CONFIG_VMSTORE_DIR; + // Determine free space + foreach ($task['data']['list'] as $entry) { + if ($entry['mountPoint'] === $storePoint) { + $storeUsage = array( + 'percent' => $entry['usedPercent'], + 'size' => Util::readableFileSize($entry['sizeKb'] * 1024), + 'free' => Util::readableFileSize($entry['freeKb'] * 1024), + 'color' => $this->usageColor($entry['usedPercent']) + ); + } + if ($entry['mountPoint'] === '/') { + $systemUsage = array( + 'percent' => $entry['usedPercent'], + 'size' => Util::readableFileSize($entry['sizeKb'] * 1024), + 'free' => Util::readableFileSize($entry['freeKb'] * 1024), + 'color' => $this->usageColor($entry['usedPercent']) + ); + } } - if ($entry['mountPoint'] === '/') { - $systemUsage = array( - 'percent' => $entry['usedPercent'], - 'size' => Util::readableFileSize($entry['sizeKb'] * 1024), - 'free' => Util::readableFileSize($entry['freeKb'] * 1024), - 'color' => $this->usageColor($entry['usedPercent']) - ); + $data = array( + 'store' => $storeUsage, + 'system' => $systemUsage + ); + // Determine if proper vm store is being used + if ($store !== '<local>') { + $data['storeMissing'] = $store; } - } - $data = array( - 'store' => $storeUsage, - 'system' => $systemUsage - ); - // Determine if proper vm store is being used - if ($store !== '<local>') { - $data['storeMissing'] = $store; - } - foreach ($task['data']['list'] as $entry) { - if ($entry['mountPoint'] !== CONFIG_VMSTORE_DIR) - continue; - if ($store !== $entry['fileSystem']) { - $data['wrongStore'] = $entry['fileSystem']; - break; + foreach ($task['data']['list'] as $entry) { + if ($entry['mountPoint'] !== CONFIG_VMSTORE_DIR) + continue; + if ($store !== $entry['fileSystem']) { + $data['wrongStore'] = $entry['fileSystem']; + break; + } + $data['storeMissing'] = false; } - $data['storeMissing'] = false; + } else { + $data['notConfigured'] = true; } + echo Render::parse('diskstat', $data); } else { - $data['notConfigured'] = true; + echo "No permission to view this section."; } - echo Render::parse('diskstat', $data); } protected function ajaxAddressList() { - $task = Taskmanager::submit('LocalAddressesList'); - if ($task === false) - return; - $task = Taskmanager::waitComplete($task, 3000); + if (User::hasPermission("show.overview.addresses")) { + $task = Taskmanager::submit('LocalAddressesList'); + if ($task === false) + return; + $task = Taskmanager::waitComplete($task, 3000); - if (!isset($task['data']['addresses']) || empty($task['data']['addresses'])) { - Taskmanager::addErrorMessage($task); - return; - } + if (!isset($task['data']['addresses']) || empty($task['data']['addresses'])) { + Taskmanager::addErrorMessage($task); + return; + } - $sort = array(); - $primary = Property::getServerIp(); - foreach ($task['data']['addresses'] as &$addr) { - $sort[] = $addr['type'] . $addr['ip']; - if ($addr['ip'] === $primary) - $addr['primary'] = true; + $sort = array(); + $primary = Property::getServerIp(); + foreach ($task['data']['addresses'] as &$addr) { + $sort[] = $addr['type'] . $addr['ip']; + if ($addr['ip'] === $primary) + $addr['primary'] = true; + } + array_multisort($sort, SORT_STRING, $task['data']['addresses']); + echo Render::parse('addresses', array( + 'addresses' => $task['data']['addresses'] + )); + } else { + echo "No permission to view this section."; } - array_multisort($sort, SORT_STRING, $task['data']['addresses']); - echo Render::parse('addresses', array( - 'addresses' => $task['data']['addresses'] - )); + } private function sysInfo() @@ -178,39 +197,43 @@ class Page_SystemStatus extends Page protected function ajaxSystemInfo() { - $cpuInfo = file_get_contents('/proc/cpuinfo'); - $uptime = file_get_contents('/proc/uptime'); - $cpuCount = preg_match_all('/\bprocessor\s/', $cpuInfo, $out); - //$cpuCount = count($out); - $data = array( - 'cpuCount' => $cpuCount, - 'memTotal' => '???', - 'memFree' => '???', - 'swapTotal' => '???', - 'swapUsed' => '???', - 'uptime' => '???' - ); - if (preg_match('/^(\d+)\D/', $uptime, $out)) { - $data['uptime'] = floor($out[1] / 86400) . ' ' . Dictionary::translate('lang_days') . ', ' . floor(($out[1] % 86400) / 3600) . ' ' . Dictionary::translate('lang_hours'); - } - $info = $this->sysInfo(); - if (isset($info['MemTotal']) && isset($info['MemFree']) && isset($info['SwapTotal'])) { - $data['memTotal'] = Util::readableFileSize($info['MemTotal'] * 1024); - $data['memFree'] = Util::readableFileSize(($info['MemFree'] + $info['Buffers'] + $info['Cached']) * 1024); - $data['memPercent'] = 100 - round((($info['MemFree'] + $info['Buffers'] + $info['Cached']) / $info['MemTotal']) * 100); - $data['swapTotal'] = Util::readableFileSize($info['SwapTotal'] * 1024); - $data['swapUsed'] = Util::readableFileSize(($info['SwapTotal'] - $info['SwapFree']) * 1024); - $data['swapPercent'] = 100 - round(($info['SwapFree'] / $info['SwapTotal']) * 100); - $data['swapWarning'] = ($data['swapPercent'] > 50 || ($info['SwapTotal'] - $info['SwapFree']) > 200000); - } - if (isset($info['CpuIdle']) && isset($info['CpuSystem']) && isset($info['CpuTotal'])) { - $data['cpuLoad'] = 100 - round(($info['CpuIdle'] / $info['CpuTotal']) * 100); - $data['cpuSystem'] = round(($info['CpuSystem'] / $info['CpuTotal']) * 100); - $data['cpuLoadOk'] = true; - $data['CpuTotal'] = $info['CpuTotal']; - $data['CpuIdle'] = $info['CpuIdle']; + if (User::hasPermission("show.overview.systeminfo")) { + $cpuInfo = file_get_contents('/proc/cpuinfo'); + $uptime = file_get_contents('/proc/uptime'); + $cpuCount = preg_match_all('/\bprocessor\s/', $cpuInfo, $out); + //$cpuCount = count($out); + $data = array( + 'cpuCount' => $cpuCount, + 'memTotal' => '???', + 'memFree' => '???', + 'swapTotal' => '???', + 'swapUsed' => '???', + 'uptime' => '???' + ); + if (preg_match('/^(\d+)\D/', $uptime, $out)) { + $data['uptime'] = floor($out[1] / 86400) . ' ' . Dictionary::translate('lang_days') . ', ' . floor(($out[1] % 86400) / 3600) . ' ' . Dictionary::translate('lang_hours'); + } + $info = $this->sysInfo(); + if (isset($info['MemTotal']) && isset($info['MemFree']) && isset($info['SwapTotal'])) { + $data['memTotal'] = Util::readableFileSize($info['MemTotal'] * 1024); + $data['memFree'] = Util::readableFileSize(($info['MemFree'] + $info['Buffers'] + $info['Cached']) * 1024); + $data['memPercent'] = 100 - round((($info['MemFree'] + $info['Buffers'] + $info['Cached']) / $info['MemTotal']) * 100); + $data['swapTotal'] = Util::readableFileSize($info['SwapTotal'] * 1024); + $data['swapUsed'] = Util::readableFileSize(($info['SwapTotal'] - $info['SwapFree']) * 1024); + $data['swapPercent'] = 100 - round(($info['SwapFree'] / $info['SwapTotal']) * 100); + $data['swapWarning'] = ($data['swapPercent'] > 50 || ($info['SwapTotal'] - $info['SwapFree']) > 200000); + } + if (isset($info['CpuIdle']) && isset($info['CpuSystem']) && isset($info['CpuTotal'])) { + $data['cpuLoad'] = 100 - round(($info['CpuIdle'] / $info['CpuTotal']) * 100); + $data['cpuSystem'] = round(($info['CpuSystem'] / $info['CpuTotal']) * 100); + $data['cpuLoadOk'] = true; + $data['CpuTotal'] = $info['CpuTotal']; + $data['CpuIdle'] = $info['CpuIdle']; + } + echo Render::parse('systeminfo', $data); + } else { + echo "No permission to view this section."; } - echo Render::parse('systeminfo', $data); } protected function ajaxSysPoll() @@ -228,181 +251,208 @@ class Page_SystemStatus extends Page protected function ajaxServices() { - $data = array('services' => array()); - $tasks = array(); + if (User::hasPermission("show.overview.services")) { + $data = array('services' => array()); + $tasks = array(); - $todo = ['dmsd', 'atftpd']; - if (Module::isAvailable('dnbd3') && Dnbd3::isEnabled()) { - $todo[] = 'dnbd3-server'; - } + $todo = ['dmsd', 'atftpd']; + if (Module::isAvailable('dnbd3') && Dnbd3::isEnabled()) { + $todo[] = 'dnbd3-server'; + } - foreach ($todo as $svc) { + foreach ($todo as $svc) { + $tasks[] = array( + 'name' => $svc, + 'task' => Taskmanager::submit('Systemctl', ['service' => $svc, 'operation' => 'is-active']) + ); + } $tasks[] = array( - 'name' => $svc, - 'task' => Taskmanager::submit('Systemctl', ['service' => $svc, 'operation' => 'is-active']) + 'name' => 'LDAP/AD-Proxy', + 'task' => Trigger::ldadp() ); - } - $tasks[] = array( - 'name' => 'LDAP/AD-Proxy', - 'task' => Trigger::ldadp() - ); - $deadline = time() + 10; - do { - $done = true; - foreach ($tasks as &$task) { - if (!is_string($task['task']) && (Taskmanager::isFailed($task['task']) || Taskmanager::isFinished($task['task']))) - continue; - $task['task'] = Taskmanager::waitComplete($task['task'], 100); - if (!Taskmanager::isFailed($task['task']) && !Taskmanager::isFinished($task['task'])) { - $done = false; + $deadline = time() + 10; + do { + $done = true; + foreach ($tasks as &$task) { + if (!is_string($task['task']) && (Taskmanager::isFailed($task['task']) || Taskmanager::isFinished($task['task']))) + continue; + $task['task'] = Taskmanager::waitComplete($task['task'], 100); + if (!Taskmanager::isFailed($task['task']) && !Taskmanager::isFinished($task['task'])) { + $done = false; + } } - } - unset($task); - } while (!$done && time() < $deadline); - - foreach ($tasks as $task) { - $fail = Taskmanager::isFailed($task['task']); - $data['services'][] = array( - 'name' => $task['name'], - 'fail' => $fail, - 'data' => isset($task['data']) ? $task['data'] : null, - 'unknown' => $task['task'] === false - ); - } - - echo Render::parse('services', $data); - } + unset($task); + } while (!$done && time() < $deadline); - protected function ajaxDmsdLog() - { - $fh = @fopen('/var/log/dmsd.log', 'r'); - if ($fh === false) { - echo 'Error opening log file'; - return; - } - fseek($fh, -6000, SEEK_END); - $data = fread($fh, 6000); - @fclose($fh); - if ($data === false) { - echo 'Error reading from log file'; - return; - } - // If we could read less, try the .1 file too - $amount = 6000 - strlen($data); - if ($amount > 100) { - $fh = @fopen('/var/log/dmsd.log.1', 'r'); - if ($fh !== false) { - fseek($fh, -$amount, SEEK_END); - $data = fread($fh, $amount) . $data; - @fclose($fh); + foreach ($tasks as $task) { + $fail = Taskmanager::isFailed($task['task']); + $data['services'][] = array( + 'name' => $task['name'], + 'fail' => $fail, + 'data' => isset($task['data']) ? $task['data'] : null, + 'unknown' => $task['task'] === false + ); } - } - if (strlen($data) < 5990) { - $start = 0; + + echo Render::parse('services', $data); } else { - $start = strpos($data, "\n") + 1; + echo "No permission to view this section."; } - echo '<pre>', htmlspecialchars(substr($data, $start), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; } - protected function ajaxLighttpdLog() + protected function ajaxDmsdLog() { - $fh = @fopen('/var/log/lighttpd/error.log', 'r'); - if ($fh === false) { - echo 'Error opening log file'; - return; - } - fseek($fh, -6000, SEEK_END); - $data = fread($fh, 6000); - @fclose($fh); - if ($data === false) { - echo 'Error reading from log file'; - return; - } - // If we could read less, try the .1 file too - $amount = 6000 - strlen($data); - if ($amount > 100) { - $fh = @fopen('/var/log/lighttpd/error.log.1', 'r'); - if ($fh !== false) { - fseek($fh, -$amount, SEEK_END); - $data = fread($fh, $amount) . $data; - @fclose($fh); + if (User::hasPermission("show.logs.bwlpserver")) { + $fh = @fopen('/var/log/dmsd.log', 'r'); + if ($fh === false) { + echo 'Error opening log file'; + return; } - } - if (strlen($data) < 5990) { - $start = 0; + fseek($fh, -6000, SEEK_END); + $data = fread($fh, 6000); + @fclose($fh); + if ($data === false) { + echo 'Error reading from log file'; + return; + } + // If we could read less, try the .1 file too + $amount = 6000 - strlen($data); + if ($amount > 100) { + $fh = @fopen('/var/log/dmsd.log.1', 'r'); + if ($fh !== false) { + fseek($fh, -$amount, SEEK_END); + $data = fread($fh, $amount) . $data; + @fclose($fh); + } + } + if (strlen($data) < 5990) { + $start = 0; + } else { + $start = strpos($data, "\n") + 1; + } + echo '<pre>', htmlspecialchars(substr($data, $start), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; } else { - $start = strpos($data, "\n") + 1; + echo "No permission to view this section."; } - echo '<pre>', htmlspecialchars(substr($data, $start), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; } - protected function ajaxLdadpLog() + protected function ajaxLighttpdLog() { - $haveSysconfig = Module::isAvailable('sysconfig'); - $files = glob('/var/log/ldadp/*.log', GLOB_NOSORT); - if ($files === false || empty($files)) echo('No logs found'); - $now = time(); - foreach ($files as $file) { - $mod = filemtime($file); - if ($now - $mod > 86400) continue; - // New enough - handle - preg_match(',/(\d+)\.log,', $file, $out); - $module = $haveSysconfig ? ConfigModule::get($out[1]) : false; - if ($module === false) { - echo '<h4>Module ', $out[1], '</h4>'; - } else { - echo '<h4>Module ', htmlspecialchars($module->title()), '</h4>'; - } - $fh = @fopen($file, 'r'); + if (User::hasPermission("show.logs.lighttpd")) { + $fh = @fopen('/var/log/lighttpd/error.log', 'r'); if ($fh === false) { - echo '<pre>Error opening log file</pre>'; - continue; + echo 'Error opening log file'; + return; } - fseek($fh, -5000, SEEK_END); - $data = fread($fh, 5000); + fseek($fh, -6000, SEEK_END); + $data = fread($fh, 6000); @fclose($fh); if ($data === false) { - echo '<pre>Error reading from log file</pre>'; - continue; + echo 'Error reading from log file'; + return; + } + // If we could read less, try the .1 file too + $amount = 6000 - strlen($data); + if ($amount > 100) { + $fh = @fopen('/var/log/lighttpd/error.log.1', 'r'); + if ($fh !== false) { + fseek($fh, -$amount, SEEK_END); + $data = fread($fh, $amount) . $data; + @fclose($fh); + } } - if (strlen($data) < 4990) { + if (strlen($data) < 5990) { $start = 0; } else { $start = strpos($data, "\n") + 1; } echo '<pre>', htmlspecialchars(substr($data, $start), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; + } else { + echo "No permission to view this section."; + } + + } + + protected function ajaxLdadpLog() + { + if (User::hasPermission("show.logs.ldapad")) { + $haveSysconfig = Module::isAvailable('sysconfig'); + $files = glob('/var/log/ldadp/*.log', GLOB_NOSORT); + if ($files === false || empty($files)) echo('No logs found'); + $now = time(); + foreach ($files as $file) { + $mod = filemtime($file); + if ($now - $mod > 86400) continue; + // New enough - handle + preg_match(',/(\d+)\.log,', $file, $out); + $module = $haveSysconfig ? ConfigModule::get($out[1]) : false; + if ($module === false) { + echo '<h4>Module ', $out[1], '</h4>'; + } else { + echo '<h4>Module ', htmlspecialchars($module->title()), '</h4>'; + } + $fh = @fopen($file, 'r'); + if ($fh === false) { + echo '<pre>Error opening log file</pre>'; + continue; + } + fseek($fh, -5000, SEEK_END); + $data = fread($fh, 5000); + @fclose($fh); + if ($data === false) { + echo '<pre>Error reading from log file</pre>'; + continue; + } + if (strlen($data) < 4990) { + $start = 0; + } else { + $start = strpos($data, "\n") + 1; + } + echo '<pre>', htmlspecialchars(substr($data, $start), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; + } + } else { + echo "No permission to view this section."; } } protected function ajaxNetstat() { - $taskId = Taskmanager::submit('Netstat'); - if ($taskId === false) - return; - $status = Taskmanager::waitComplete($taskId, 3500); + if(User::hasPermission("show.logs.netstat")) { + $taskId = Taskmanager::submit('Netstat'); + if ($taskId === false) + return; + $status = Taskmanager::waitComplete($taskId, 3500); - if (isset($status['data']['messages'])) - $data = $status['data']['messages']; - else - $data = 'Taskmanager error'; + if (isset($status['data']['messages'])) + $data = $status['data']['messages']; + else + $data = 'Taskmanager error'; + + echo '<pre>', htmlspecialchars($data, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; + } else { + echo "No permission to view this section."; + } - echo '<pre>', htmlspecialchars($data, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; } protected function ajaxPsList() { - $taskId = Taskmanager::submit('PsList'); - if ($taskId === false) - return; - $status = Taskmanager::waitComplete($taskId, 3500); + if (User::hasPermission("show.logs.pslist")) { + $taskId = Taskmanager::submit('PsList'); + if ($taskId === false) + return; + $status = Taskmanager::waitComplete($taskId, 3500); + + if (isset($status['data']['messages'])) + $data = $status['data']['messages']; + else + $data = 'Taskmanager error'; - if (isset($status['data']['messages'])) - $data = $status['data']['messages']; - else - $data = 'Taskmanager error'; + echo '<pre>', htmlspecialchars($data, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; + } else { + echo "No permission to view this section."; + } - echo '<pre>', htmlspecialchars($data, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; } private function usageColor($percent) diff --git a/modules-available/systemstatus/permissions/permissions.json b/modules-available/systemstatus/permissions/permissions.json new file mode 100644 index 00000000..0333564b --- /dev/null +++ b/modules-available/systemstatus/permissions/permissions.json @@ -0,0 +1,13 @@ +[ + "show.overview.diskstat", + "show.overview.services", + "show.overview.adresses", + "show.overview.systeminfo", + "show.overview.dmsdusers", + "show.logs.bwlpserver", + "show.logs.netstat", + "show.logs.pslist", + "show.logs.ldapad", + "show.logs.lighttpd", + "serverreboot" +]
\ No newline at end of file diff --git a/modules-available/systemstatus/templates/_page.html b/modules-available/systemstatus/templates/_page.html index 0de94cad..715fd233 100644 --- a/modules-available/systemstatus/templates/_page.html +++ b/modules-available/systemstatus/templates/_page.html @@ -86,7 +86,7 @@ <form class="form-adduser" action="?do=SystemStatus" method="post"> <input type="hidden" name="token" value="{{token}}"> <input type="hidden" name="action" value="reboot"> - <button class="btn btn-warning" type="button" data-toggle="modal" data-target="#rebootServerModal"><span class="glyphicon glyphicon-repeat"></span> {{lang_serverReboot}}</button> + <button {{^allowedToReboot}}disabled{{/allowedToReboot}} class="btn btn-warning" type="button" data-toggle="modal" data-target="#rebootServerModal"><span class="glyphicon glyphicon-repeat"></span> {{lang_serverReboot}}</button> <div class ="modal fade" id="rebootServerModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> |