summaryrefslogblamecommitdiffstats
path: root/modules-available/remoteaccess/api.inc.php
blob: bebe076788c480aad769bac39f4248b9b54f538b (plain) (tree)
1
     













































                                                                                                                                                                                                                                                                







                                                                                                         





                                                                                                     















                                                                              


                                                     
                                                                        
                                                              







                                                              



                                                                  








                                                                                                                
                                                                                                                                   











                                                                                                                                   
                                                


























                                                                                      
<?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();