check as $r){ $rtr[$r->name] = $r->value; } return $rtr; } public function getReplyArray(){ $rtr = array(); foreach($this->reply as $r){ $rtr[$r->name] = $r->value; } return $rtr; } } class AccessServiceManager { private $sql_host = 'mysql'; private $sql_user = "root"; private $sql_pass = ""; private $sql_db = 'freeradius'; private $delete_group = true; private function getSqlCon(){ $sql_db = $this->sql_db; $sql_host = $this->sql_host; $sql_user = "root"; //(getenv("MYSQL_USER"))?(getenv("MYSQL_USER")):$this->sql_user; $sql_pass = (getenv("MYSQL_ROOT_PASSWORD"))?(getenv("MYSQL_ROOT_PASSWORD")):$this->sql_pass; $dbh = new PDO("mysql:host=$sql_host;dbname=$sql_db", $sql_user, $sql_pass); return $dbh; } /** *Add a RadiusRecord on the Radius database in case the record exists the record is updated it returns True on success and False if a failure exists * @param RadiusRecord * @return Boolean */ function addRadiusRecord(RadiusRecord $rr){ $this->deleteRadiusRecord($rr); $this->addRadiusGroup($rr->group); syslog(LOG_DEBUG, __FUNCTION__); $dbh = $this->getSqlCon(); $login = $rr->user; $Passwd = $rr->password; $values[] = "('$login','Password',':=','$Passwd')"; foreach($rr->check as $k){ $values[] = sprintf("('$login','%s',':=','%s')", $k->name, $k->value); } $values = implode(',', $values); $sql = "INSERT INTO radcheck (UserName,Attribute,op,Value) VALUES $values;"; $rtr0 = $dbh->exec($sql); syslog(LOG_ALERT, $sql); $group = $rr->group; $sql="INSERT INTO radusergroup (UserName,GroupName) VALUES ('$login', '$group->name');"; $rtr1 = $dbh->exec($sql); syslog(LOG_DEBUG, $sql); $rtr2 = true; $replys = array(); foreach($rr->reply as $k) $replys[] = sprintf("('$login','%s','=','%s')", $k->name, $k->value); $rtr2 = true; if(!empty($replys)){ $replysValue = implode(',', $replys); $sql="INSERT INTO radreply (UserName,Attribute,op,Value) VALUES $replysValue;"; $rtr2 = $dbh->exec($sql); syslog(LOG_ALERT, $sql); } if($rtr0 and $rtr1 and $rtr2) return true; else return false; } protected function getRadiusGroupFromDb($groupName){ $dbh = $this->getSqlCon(); $tables = array('reply' => 'radgroupreply', 'check' => 'radgroupcheck'); $rg_db = new RadiusGroup; $rg_db->name = $groupName; foreach($tables as $key => $table){ $sql = sprintf("SELECT id, Attribute, op, Value FROM %s WHERE GroupName='%s'", $table, $groupName); $rtr = $dbh->query($sql); $props = array(); foreach($rtr as $rr){ $props[] = $p = new RadiusProp; $p->name = $rr['Attribute']; $p->value = $rr['Value']; } $rg_db->$key = $props; } return $rg_db; } protected function safeRadiusGroup(RadiusGroup $rg){ $rg->name = preg_replace("|[^A-Za-z0-9]|", "-", $rg->name); return $rg; } /** * @param RadiusGroup * * @return Boolean */ function deleteRadiusGroup(RadiusGroup $rg) { $rg = $this->safeRadiusGroup($rg); $sql = sprintf("SELECT COUNT( * ) AS `Filas` , `groupname` FROM `radusergroup` WHERE groupname = '%s' GROUP BY `groupname`", $rg->name); $dbh = $this->getSqlCon(); $rtr = $dbh->query($sql); $total = 0; foreach($rtr as $t) $total = $t['Filas']; if($total == 0){ $sql = "DELETE FROM `%s` WHERE GroupName = '%s'"; foreach(array('radgroupcheck', 'radgroupreply',) as $table) $dbh->exec(sprintf($sql,$table, $rg->name)); } //Residuos $sql = "DELETE FROM `radgroupcheck` WHERE `GroupName` NOT IN (SELECT DISTINCT (`groupname`) FROM `radusergroup` WHERE 1);"; $dbh->exec($sql); $sql = "DELETE FROM `radgroupreply` WHERE `GroupName` NOT IN (SELECT DISTINCT (`groupname`) FROM `radusergroup` WHERE 1);"; $dbh->exec($sql); return true; } /** * @param RadiusGroup * * @return Boolean */ function addRadiusGroup(RadiusGroup $rg) { $rg = $this->safeRadiusGroup($rg); $dbh = $this->getSqlCon(); $rgDB = $this->getRadiusGroupFromDb($rg->name); $props = array('check' => $rg->getCheckArray(), 'reply' => $rg->getReplyArray()); $propsDB = array('check' => $rgDB->getCheckArray(), 'reply' => $rgDB->getReplyArray()); foreach(array('check' => array('table' => 'radgroupcheck', 'op' => ':='), 'reply' => array('table' => 'radgroupreply', 'op' => '=')) as $op => $config) { $table = $config['table']; $key = array_keys($props[$op]); $keyDB = array_keys($propsDB[$op]); $agregar = array_diff($key, $keyDB); $borrar = array_diff($keyDB, $key); $actualizar = array_diff($key, array_merge($agregar, $borrar)); if(!empty($borrar)){ $borrar = array_map(array($dbh, "quote"), $borrar); $sql = sprintf("DELETE FROM %s WHERE GroupName='%s' AND Attribute IN (%s);", $table, $rg->name, implode(", ", $borrar)); $dbh->exec($sql); } if(!empty($agregar)){ foreach($agregar as $attribute){ $sql = sprintf("INSERT INTO `%s` ( `GroupName` , `Attribute` , `op` , `Value` ) VALUES (%s, %s, %s, %s);", $table, $dbh->quote($rg->name), $dbh->quote($attribute), $dbh->quote($config['op']), $dbh->quote($props[$op][$attribute])); $dbh->exec($sql); } } if(!empty($actualizar)){ foreach($actualizar as $attribute){ $sql = sprintf("UPDATE `%s` SET `op`='%s', `Value` = %s WHERE GroupName=%s AND Attribute=%s;", $table, $config['op'], $dbh->quote($props[$op][$attribute]), //Value $dbh->quote($rg->name), //GroupName $dbh->quote($attribute) //GroupName ); $dbh->exec($sql); } } } return true; } /** *Update a RadiusRecord on the Radius database in case the record dosn't exists the record is updated * it returns True on success and False if a failure exists * @param RadiusRecord * @return boolean */ function updateRadiusRecord(RadiusRecord $rr){ $this->deleteRadiusRecord($rr); return $this->addRadiusRecord($rr); } /** *Delete a RadiusRecord from the Radius database. * it returns True on success and False if a failure exists, such as the Record is not found. * @param RadiusRecord $rr * @return boolean */ function deleteRadiusRecord(RadiusRecord $rr){ $dbh = $this->getSqlCon(); $login = $rr->user; $Passwd = $rr->password; $sql = "DELETE FROM radcheck WHERE UserName='$login';"; $rtr0 = $dbh->exec($sql); if(empty($rr->group)) $rr->group = 'Full'; $group = $rr->group; $sql="DELETE FROM radusergroup WHERE username='$login';"; $rtr1 = $dbh->exec($sql); $rtr2 = true; $sql="DELETE FROM radreply WHERE UserName='$login';"; $rtr2 = $dbh->exec($sql); $this->deleteRadiusGroup($rr->group); shell_exec($cmd = sprintf("php /etc/freeradius/close_radius_session.php --username=%s &", $login)); syslog(LOG_INFO, $cmd); $this->disconnectRadiusRecord($rr); return $rtr0; } /** * Send a disconnect message to the nas server on all of the user active connections * @param RadiusRecord $rr * @return int number of connection succesfully reseted. */ function disconnectRadiusRecord(RadiusRecord $rr){ $mac_auth = false; if(preg_match("/([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i",$rr->user,$matches)){ $mac_auth = true; } $dbh = $this->getSqlCon(); $nasSQL = "SELECT nasname, secret FROM nas"; $nasInfo = array(); $rtr = 0; foreach($dbh->query($nasSQL) as $nas){ if(preg_match( "/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" . "(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/", $nas['nasname'])) $ip = $nas['nasname']; else $ip = gethostbyname($nas['nasname']); $nasInfo[$ip] = $nas['secret']; } $sql = "SELECT * FROM `radacct` WHERE `username` = ? AND ( `acctstoptime` IS NULL) ORDER BY `radacct`.`radacctid` DESC"; $stmt = $dbh->prepare($sql); $rtr0 = $stmt->execute(array($rr->user)); $return_var = 0; $rads = $stmt->fetchall(); foreach ($rads as $rad) { $force_close = false; $user = $rr->user; if($mac_auth){ unset($matches[0]); $mac_user1 = implode(":",$matches); $mac_user2 = implode("-",$matches); if($rad['callingstationid'] == $mac_user1 or $rad['callingstationid'] === $mac_user2 ){ $user = $rad['callingstationid']; } } if(isset($nasInfo[$rad['nasipaddress']])){ $cmd = sprintf("/bin/bash " . getcwd()."/scripts/raddisconnect.sh %s %s %s", escapeshellarg($rad['nasipaddress']), escapeshellarg($nasInfo[$rad['nasipaddress']]), escapeshellarg($user)); if(!empty($rad['framedipaddress'])){ $cmd = sprintf("%s %s", $cmd, escapeshellarg($rad['framedipaddress'])); } $rtr_cmd= system ( "$cmd", $return_var); $radacctid = $rad['radacctid']; if($return_var == 0){ $rtr++; syslog(LOG_INFO, basename(__FILE__) . " running cmd (OK) (radacctid $radacctid) ROW {$stmt->rowCount()}" . $cmd); }else{ syslog(LOG_INFO, basename(__FILE__) . " running cmd (FAIL - $return_var) (radacctid $radacctid) ROW {$stmt->rowCount()}" . $cmd); $force_close = true; } }else{ syslog(LOG_ALERT, sprintf("Can't find the nas %s IP on the nas table.",$rad['nasipaddress'])); $force_close = true; } if($force_close){ $sql = sprintf("UPDATE `radius`.`radacct` SET `acctstoptime` = NOW( ) , `acctterminatecause` = 'unresponsive session (radius WS)' WHERE `radacct`.`radacctid` =%d", $rad['radacctid']); $dbh->exec($sql); } } return $rtr; } /** *Search all RadiusRecord with the matching pattern * @param String $pattern the patter to search for * @param Boolean $exact specify if the match shuld be exact otherwise, will match ani username containing the patter * @return RadiusRecord[] */ function listRadiusRecord($pattern, $exact = true){ if(is_null($exact)) $exact = true; $dbh = $this->getSqlCon(); $sql = "SELECT UserName, Value FROM radcheck WHERE Attribute='Password' AND op=':=' AND UserName LIKE '%s'"; if(!$exact) $pattern = '%' . $pattern . '%'; $sql = sprintf($sql, $pattern); $rtr = array(); foreach($dbh->query($sql) as $rr){ $rtr[$rr['UserName']] = $r = new RadiusRecord(); $r->user = $rr['UserName']; $r->password = $rr['Value']; } $sql = "SELECT UserName, GroupName FROM radusergroup WHERE UserName LIKE '%s'"; $sql = sprintf($sql, $pattern); foreach($dbh->query($sql) as $info){ if(($rtr[$info['UserName']])) { $rr = $rtr[$info['UserName']]; $rr->group = $info['GroupName']; } } $sql = "SELECT UserName, Value FROM radreply WHERE Attribute='Framed-IP-Address' AND op = '=' AND UserName LIKE '%s'"; $sql = sprintf($sql, $pattern); foreach($dbh->query($sql) as $info){ if(($rtr[$info['UserName']])) { $rr = $rtr[$info['UserName']]; $rr->ipAddress = $info['Value']; } } return $rtr; } /** * Add (or update) a entry in the NAS (radius Client) table * @param RadiusClient $radclient the radcliente, it is identified by its nasname (IP) * * @return Boolean */ function addRadiusClient(RadiusClient $radcliente) { $dbh = $this->getSqlCon(); $stm = $dbh->prepare("DELETE FROM nas WHERE nasname = ?;"); $rtr = $stm->execute(array($radcliente->nasname)); $sql2 = "INSERT INTO `nas` (`nasname`, `shortname`, `type`, `ports`, `secret`, `community`, `description`, `server`, `acct_enabled`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);"; $stm2 = $dbh->prepare($sql2); $rtr2 = $stm2->execute(array( $radcliente->nasname, $radcliente->shortname, $radcliente->type, $radcliente->ports, $radcliente->secret, $radcliente->community, $radcliente->description, $radcliente->server, $radcliente->acct_enabled )); syslog(shell_exec('sudo kill -9 $(pgrep freeradius)')); return $rtr2; } /** * delete a entry in the NAS (radius Client) table * @param RadiusClient $radclient the radcliente, it is identified by its nasname (IP) * * @return Boolean */ function deleteRadiusClient(RadiusClient $radcliente) { $dbh = $this->getSqlCon(); $stm = $dbh->prepare("DELETE FROM nas WHERE nasname = ?;"); $rtr = $stm->execute(array($radcliente->nasname)); syslog(shell_exec('sudo kill -9 $(pgrep freeradius)')); return $rtr; } /** * Find all RadAct * @param RadAct $crit, NULL attributes are ignored in the query * @param Integer $inicio * @param Integer $count * @return RadAct[] */ function findRadAct(RadAct $crit, $inicio, $count){ $sql = "SELECT * FROM radacct"; $where = array(); $rtr = array(); foreach($crit as $key => $val){ if(!is_null($val)) $where[] = "$key = '$val'"; } if(!empty($where)){ $sql .= " WHERE " . implode(' AND ', $where); } $sql .= " ORDER BY `acctstarttime` DESC"; $sql .= " LIMIT $inicio, $count"; $dbh = $this->getSqlCon(); foreach($dbh->query($sql) as $row){ $rtr [] = $obj = new RadAct; foreach($row as $k => $v) $obj->$k = $v; } return $rtr; } /** * Find RadAct for the $username address * @param String $username * @return RadAct[] */ function getRadActByUsername($username) { $radAct = new RadAct(); $radAct->username = $username; return $this->findRadAct($radAct, 0, 50); } } require_once "wshelper/common.php"; $WSClasses = array('AccessServiceManager'); $WSStructures = array( 'RadAct' => 'RadAct', 'RadiusGroup' => 'RadiusGroup', 'RadiusProp' => 'RadiusProp', 'RadiusRecord' => 'RadiusRecord', 'RadiusClient' => 'RadiusClient'); require_once "servicioSoap.php";