254 lines
8.1 KiB
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);
|
||
|
}
|