libreschool-client-manager/root/usr/share/client-manager/index.php

254 lines
8.1 KiB
PHP

<?php
include_once("EsmithDatabase.php");
define('CONFIG_KEY', 'client-manager');
$hosts_db = new EsmithDatabase('hosts');
$config_db = new EsmithDatabase('configuration');
$dhcp_db = new EsmithDatabase('dhcp');
$uri = $_SERVER['REQUEST_URI'];
// add leading '/' to uri string, works if $uri is empty
$uri = (substr($uri, 0, 1) == '/') ? $uri : '/' . $uri;
$pos = strpos($uri, '?');
if (false !== $pos) {
$route = substr($uri, 0, (int) $pos);
} else {
$route = $uri;
}
// remove trailing '/'
$route = rtrim($route, '/');
$query_string = $_SERVER['QUERY_STRING'];
$method = $_SERVER["REQUEST_METHOD"];
$get_params = array();
parse_str($query_string, $get_params);
// determine internal function name (all lowercase, dash2underscore, named ROUTE_methodname_routename )
$function = preg_replace(':\-:', '_', strtolower($route));
$function = preg_replace(':^/:', 'ROUTE_'.$method.'_', $function);
if (function_exists($function)) {
$function();
} else {
die('Go away.');
}
function getClientFromUUID($uuid=false) {
global $hosts_db;
$hosts = $hosts_db->getAllByProp('uuid',$uuid);
if (count($hosts)>0) {
return array_pop($hosts);
} else {
return false;
}
}
function getClientFromIP($ip=false) {
global $hosts_db;
$hosts = $hosts_db->getAllByProp('IpAddress',$ip);
if (count($hosts)>0) {
return array_pop($hosts);
} else {
return false;
}
}
function getClientMac($ip=false) {
if (false === $ip) {
$ip = $_SERVER['REMOTE_ADDR'];
}
$result = pingHost($ip,1);
if (!$result) return false;
$macAddr=false;
$arptable=`arp -n $ip`;
$lines=explode("\n", $arptable);
foreach($lines as $line) {
$cols=preg_split('/\s+/', trim($line));
if ($cols[0]==$ip)
{
return $cols[2];
}
}
return false;
}
function pingHost($host, $timeout=1) {
$pingresult = exec("/bin/ping -c 1 -t 2 -W $timeout $host", $output, $retvar);
return (0 == $retvar);
}
function filtered_json() {
global $_filtered_json;
if (is_null($_filtered_json)) {
$ok_elements = array('client_uuid','server_uuid','last_config','hostname');
$data = json_decode(file_get_contents('php://input'), true);
$_filtered_json = array_intersect_key($data,array_flip($ok_elements));
}
return $_filtered_json;
}
function my_uuid() {
global $config_db;
$uuid = $config_db->getProp(CONFIG_KEY,'uuid');
if (empty($uuid)) {
$uuid=trim(shell_exec('/usr/bin/uuidgen'));
$config_db->setProp(CONFIG_KEY,array('uuid'=>$uuid));
}
return $uuid;
}
function find_free_ipaddress() {
global $hosts_db, $dhcp_db;
$ip = ip2long($ip_str);
if ( ! $ip_str_start = $dhcp_db->getProp('lan0','DhcpRangeStart') ) {
return false;
}
if ( ! $ip_str_end = $dhcp_db->getProp('lan0','DhcpRangeEnd') ) {
return false;
}
$ip_start = ip2long($ip_str_start)+1;
$ip_end = ip2long($ip_str_end);
while($ip_start <= $ip_end){
$hosts = $hosts_db->getAllByProp('IpAddress',long2ip($ip_start));
if (count($hosts)==0) {
return long2ip($ip_start);
}
$start_ip++;
}
return false;
}
function ROUTE_POST_ping() {
global $config_db, $hosts_db;
$data = filtered_json();
$server_uuid=my_uuid();
$out=array();
$domainName = (string)$config_db->getKeyValue('DomainName');
if (!isset($data['server_uuid'])) {
# client is unmanaged, let's fix that
$systemName = (string)$config_db->getKeyValue('SystemName');
$TCPPort = $config_db->getProp(CONFIG_KEY,'TCPPort');
$out['ping_url']="http://$systemName.$domainName:$TCPPort/ping";
$out['server_uuid']=$server_uuid;
} elseif ($data['server_uuid'] != $server_uuid) {
# this client belongs to someone else, let's ignore it
echo json_encode(array('error'=>'you\'re devoted to another master'));
exit;
}
if (!isset($data['client_uuid'])) {
# client hasn't sent its uuid. This is not allowed (client uuid is always generated client-side)
echo json_encode(array('error'=>'missing client uuid'));
exit;
}
$client_ip = $_SERVER['REMOTE_ADDR'];
$client = false;
if (! $client = getClientFromUUID($data['client_uuid'])) {
# client uuid not registered, let's search for IP
$mac = getClientMac();
if ($client = getClientFromIP($client_ip)) {
# we have one
if (isset($client['uuid'])) {
# with a registered UUID, that we know to be different from ours
# so it's an IP collision.
# we investigate:
if ($mac == $client['MacAddress']) {
# the macaddress is the same, but we have different uuid
echo json_encode(array('error'=>'uuid mismatch'));
exit;
} elseif (!$mac) {
# we don't have any macaddress info (maybe because we're on
# different networks, so no arp)
echo json_encode(array('error'=>'can\'t add host because no macaddress'));
exit;
} else {
# we have a macadrress different from the one we have
# registered for this IP address, so it's a real IP collision
# and we add a new host reservation
if (! $new_ip = find_free_ipaddress()) {
echo json_encode(array('error'=>'no more free ip addresses'));
exit;
}
$props = array(
'Description' => '',
'IpAddress' => $new_ip,
'MacAddress' => $mac,
'uuid' => $data['client_uuid']
);
if (!$hosts_db->setKey($data['hostname'], 'local', $props)) {
echo json_encode(array('error'=>'can\'t add new host'));
exit;
}
$client = getClientFromUUID($data['client_uuid']);
}
} else {
# the configured client doen't have the uuid
# so we update it
$props = array(
'uuid' => $data['client_uuid']
);
if (!$hosts_db->setProp($client['name'], $props)) {
echo json_encode(array('error'=>'can\'t update host'));
exit;
}
$client['uuid'] = $data['client_uuid'];
}
} else {
# no client registered with this uuid or this IP
if ($mac) {
# we have a client mac address,
# we can register a new host
if (isset($data['hostname'])) {
$props = array(
'Description' => '',
'IpAddress' => $client_ip,
'MacAddress' => $mac,
'uuid' => $data['client_uuid']
);
if (!$hosts_db->setKey($data['hostname'], 'local', $props)) {
echo json_encode(array('error'=>'can\'t add host'));
exit;
}
$client = getClientFromUUID($data['client_uuid']);
} else {
echo json_encode(array('error'=>'missing client hostname'));
exit;
}
} else {
# we don't have a mac address (maybe a different network)
# we can't register a new host
echo json_encode(array('error'=>'missing client mac address'));
exit;
}
}
}
$hosts_db->setProp($client['name'],array('LastSeen' => time()));
if (isset($data['last_config'])) {
$hosts_db->setProp($client['name'],array('LastConfig' => $data['last_config']));
$current_config = $config_db->getProp(CONFIG_KEY,'lastConfig');
if ($data['last_config'] != $current_config ) {
exec('/usr/bin/sudo /sbin/e-smith/signal-event client-reconfigure ' . $client['name'] . ' > /dev/null &');
}
}
$out['hostname']=$client['name'];
$out['domainname']=$domainName;
$out['ipaddress']=$client['IpAddress'];
$out['server_uuid']=$server_uuid;
echo json_encode($out);
}