<?php
// Api call for reserving a client
if (Request::any('action') === 'reserve') {
$lectureid = Request::any('lectureid', '', 'string');
$editid = Request::any('editid', '', 'string');
$now = time();
// For now only considere pcs, that are already in the remote db and pc in idle state
//$client = Database::queryFirst("SELECT m.machineuuid, m.clientip, r.password, r.vncport FROM machine m INNER JOIN remoteaccess_machine r ON r.machineuuid = m.machineuuid WHERE m.currentsession IS NULL AND m.state = 'IDLE'");
// Sometimes currentsession is not null while pc is in idle state ... bug?
$client = Database::queryFirst("SELECT m.machineuuid, m.clientip, r.password, r.vncport FROM machine m INNER JOIN remoteaccess_machine r ON r.machineuuid = m.machineuuid WHERE m.state = 'IDLE'");
// If there is a client reserve it
if ($client && $editid) {
Database::exec("UPDATE remoteaccess_machine SET timestamp=:now, lectureid=:lectureid, editid=:editid WHERE machineuuid=:machineuuid", ['now' => $now, 'lectureid' => $lectureid, 'editid' => $editid, 'machineuuid' => $client['machineuuid']]);
echo json_encode($client);
} else {
echo "Currently all machines are occupied, try again later!";
}
// Exit the call, so the rest doesn't get executed
exit(0);
} elseif (Request::any('action') === 'scp') {
// Start scp taskmanager task to download the qemu snapshot
$editid = Request::any('editid', '', 'string');
$client = Database::queryFirst("SELECT m.machineuuid, m.clientip, r.editid, r.lectureid FROM machine m INNER JOIN remoteaccess_machine r ON r.machineuuid = m.machineuuid WHERE editid=:editid", ['editid' => $editid]);
if (!$client) {
die("Invalid edit id");
}
// Check if client edit was allowed anyways.
// TODO does slx-admin even has the information if a user can edit a specific vm?
// Start taskmanager task
$task = Taskmanager::submit('ScpSnapshot', array(
'clientIp' => $client['clientip'],
'editId' => $client['editid'],
'lectureId' => $client['lectureid'],
));
if (Taskmanager::isTask($task)) {
die(json_encode($task));
} else {
die('Taskmanager could not start the task');
}
exit(0);
}
$ip = $_SERVER['REMOTE_ADDR'];
if (substr($ip, 0, 7) === '::ffff:') $ip = substr($ip, 7);
$password = Request::post('password', false, 'string');
if ($password !== false) {
$c = Database::queryFirst("SELECT machineuuid FROM machine WHERE clientip = :ip", ['ip' => $ip]);
if ($c !== false) {
$vncport = Request::post('vncport', 5900, 'int');
Database::exec("INSERT INTO remoteaccess_machine (machineuuid, password, vncport)
VALUES (:uuid, :passwd, :vncport)
ON DUPLICATE KEY UPDATE
password = VALUES(password), vncport = VALUES(vncport)",
['uuid' => $c['machineuuid'], 'passwd' => $password, 'vncport' => $vncport]);
}
exit;
}
$range = IpUtil::parseCidr(Property::get(RemoteAccess::PROP_ALLOWED_VNC_NET));
if ($range === false) {
die('No allowed IP defined');
}
$iplong = ip2long($ip);
if (PHP_INT_SIZE === 4) {
$iplong = sprintf('%u', $iplong);
}
if ($iplong < $range['start'] || $iplong > $range['end']) {
die('Access denied');
}
$headers = getallheaders();
$version = false;
if (!empty($headers['Bwlp-Plugin-Build-Revision'])) {
$version = substr($headers['Bwlp-Plugin-Build-Revision'], 0, 6);
if (!empty($headers['Bwlp-Plugin-Build-Timestamp'])) {
$ts = $headers['Bwlp-Plugin-Build-Timestamp'];
if (is_numeric($ts)) {
if ($ts > 9999999999) {
$ts = round($ts / 1000);
}
$ts = date('d.m.Y H:i', $ts);
}
$version .= ' (' . $ts . ')';
}
}
Property::set(RemoteAccess::PROP_PLUGIN_VERSION, $version, 2880);
Header('Content-Type: application/json');
$remoteLocations = RemoteAccess::getEnabledLocations();
if (empty($remoteLocations)) {
$rows = [];
} else {
// TODO fail-counter for WOL, so we can ignore machines that apparently can't be woken up
// -> Reset counter in our ~poweron hook, but only if the time roughly matches a WOL attempt (within ~5 minutes)
$rows = Database::queryAll("SELECT m.clientip, m.locationid, m.state, ram.password, ram.vncport, ram.woltime FROM machine m
LEFT JOIN remoteaccess_machine ram ON (ram.machineuuid = m.machineuuid AND (ram.password IS NOT NULL OR m.state <> 'IDLE'))
LEFT JOIN runmode r ON (r.machineuuid = m.machineuuid)
WHERE m.locationid IN (:locs)
AND r.machineuuid IS NULL",
['locs' => $remoteLocations]);
$wolCut = time() - 90;
foreach ($rows as &$row) {
if (($row['state'] === 'OFFLINE' || $row['state'] === 'STANDBY') && $row['woltime'] > $wolCut) {
$row['wol_in_progress'] = true;
}
settype($row['locationid'], 'int');
settype($row['vncport'], 'int');
unset($row['woltime']);
}
}
$groups = Database::queryAll("SELECT g.groupid AS id, g.groupname AS name,
GROUP_CONCAT(l.locationid) AS locationids, g.passwd AS password
FROM remoteaccess_group g INNER JOIN remoteaccess_x_location l USING (groupid)
WHERE g.active = 1
GROUP BY g.groupid");
foreach ($groups as &$group) {
$group['locationids'] = explode(',', $group['locationids']);
if (empty($group['password'])) {
unset($group['password']);
}
settype($group['id'], 'int');
foreach ($group['locationids'] as &$lid) {
settype($lid, 'int');
}
}
$fakeid = 100000;
echo json_encode(['clients' => $rows, 'locations' => $groups]);
// WTF, this makes the server return a 500 -.-
//fastcgi_finish_request();
RemoteAccess::ensureMachinesRunning();