diff --git a/app/tftp/app_config.php b/app/tftp/app_config.php deleted file mode 100644 index c40508e148..0000000000 --- a/app/tftp/app_config.php +++ /dev/null @@ -1,57 +0,0 @@ - \ No newline at end of file diff --git a/app/tftp/app_defaults.php b/app/tftp/app_defaults.php deleted file mode 100644 index 838097a9fc..0000000000 --- a/app/tftp/app_defaults.php +++ /dev/null @@ -1,33 +0,0 @@ - - Portions created by the Initial Developer are Copyright (C) 2016 - the Initial Developer. All Rights Reserved. - - Contributor(s): - Sebastian Krupinski -*/ - -//process this code online once - if ($domains_processed == 1) { - - } - -?> diff --git a/app/tftp/app_languages.php b/app/tftp/app_languages.php deleted file mode 100644 index 8c355dce97..0000000000 --- a/app/tftp/app_languages.php +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/app/tftp/app_menu.php b/app/tftp/app_menu.php deleted file mode 100644 index 15c5adc7fa..0000000000 --- a/app/tftp/app_menu.php +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/app/tftp/resources/dbhelper.php b/app/tftp/resources/dbhelper.php deleted file mode 100644 index 9d2252ed8a..0000000000 --- a/app/tftp/resources/dbhelper.php +++ /dev/null @@ -1,293 +0,0 @@ - - Portions created by the Initial Developer are Copyright (C) 2016 - the Initial Developer. All Rights Reserved. - - Contributor(s): - Sebastian Krupinski -*/ - -class database { - - /** - * generate dsn statement - * @param string $type - sqlite, mysql, pgsql, etc - * @param string $host - fqdn or ip address - * @param string $port - port number - * @param string $name - name of database or filename when using sqlite - * @return object pdo - */ - private static function _dsn($type,$host=null,$port=null,$name) - { - switch ($type) { - case 'sqlite': - return "$type:$name;"; - break; - default: - return "$type:host=$host;port=$port;"; - break; - } - } - - /** - * connect to database - * @param string $type - sqlite, mysql, pgsql, etc - * @param string $host - fqdn or ip address - * @param string $port - port number - * @param string $name - name of database or filename when using sqlite - * @param string $username - authentication username - * @param string $password - authentication password - * @param array $options - array of database options - * @return object pdo - */ - public static function connect($type,$host=null,$port=null,$name,$username=null,$password=null,$options) - { - try - { - $db = new PDO(self::_dsn($type,$host,$port,$name), $username, $password, $options); - } - catch (PDOException $exception) - { - echo "Exception: ".$exception->getMessage(); - } - if ($db!==null) return $db; - else return false; - } - - /** - * disconnect from database - * @param pdo $db - database object as pdo type - */ - public static function disconnect($db) - { - try - { - $db=null; - return true; - } - catch (Exception $exception) - { - echo "Exception: ".$exception->getMessage(); - return false; - } - } - - /** - * begin a transaction. - * @param pdo $db - database object as pdo type - */ - public static function begin_transaction($db) - { - $db->setAttribute(PDO::ATTR_AUTOCOMMIT, 0); - $db->beginTransaction(); - } - - /** - * end the transaction. - * @param pdo $db - database object as pdo type - */ - public static function end_transaction($db) - { - $db->commit(); - $db->setAttribute(PDO::ATTR_AUTOCOMMIT, 1); - } - - /** - * revert the transaction. - * @param pdo $db - database object as pdo type - */ - public static function revert_transactions($db) - { - $db->rollBack(); - $db->setAttribute(PDO::ATTR_AUTOCOMMIT, 1); - } - - /** - * get last insert id - * @return int last insert id - */ - public static function get_lastid() - { - return $db->lastInsertId(); - } - - /** - * get only single row - * @param pdo $db - database object as pdo type - * @param string $table - table name - * @param string $filterc - filter column - * @param string $filterv - filter value - * @return array table row - */ - public static function get_row($db,$table,$filterc,$filterv) - { - $db->prepare("SELECT * FROM $table WHERE $filterc=?"); - $db->execute($filterv); - $data = $db->fetch(); - return $data; - } - - /** - * get only single column - * @param pdo $db - database object as pdo type - * @param string $table - table name - * @param string $column - column to return value from - * @param array $filter - ["filter column",">","filter value"] - * @return array table row - */ - public static function get_col($db,$table,$column,$filter) - { - $db->prepare("SELECT $column FROM $table WHERE $filter[0] $filter[1] ?"); - $db->execute($filter[2]); - $data = $cmd->fetchAll(); - return $data; - } - - /** - * get only single value - * @param pdo $db - database object as pdo type - * @param string $table - table name - * @param string $column - column to return value from - * @param string $filterc - filter column - * @param string $filterv - filter value - * @return mixed data in field - */ - public static function get_value($db,$table,$column,$filterc,$filterv) - { - $cmd = $db->prepare("SELECT $column FROM $table WHERE $filterc=?"); - $cmd->bindValue(1, $filterv); - $cmd->execute(); - $data = $cmd->fetchColumn(0); - return $data; - } - - /** - * get count of rows - * @param pdo $db - database object as pdo type - * @param string $table - table name - * @param array $filter - ["filter column",">","filter value"] - * @return mixed data in field - */ - public static function get_count($db,$table,$filter) - { - - $cmd = $db->prepare("SELECT COUNT(0) FROM $table WHERE $filter[0] $filter[1] ?"); - $cmd->bindValue(1, $filter[2]); - $cmd->execute(); - $data = $cmd->fetchColumn(0); - } - - /** - * get specific columns and rows - * @param pdo $db - database object as pdo type - * @param string $table - table name - * @param array $columns - specific columns to return - * @param array $filter - ["filter column",">","filter value"] - * @return array selected tables and rows - */ - public static function get_table($db,$table,$columns,$filter) - { - if($columns === null) $columns=array("*"); - $cmd = $db->prepare("SELECT ".implode(',', $columns)." FROM $table WHERE $filter[0] $filter[1] ?"); - $cmd->bindValue(1, $filter[2]); - $cmd->execute(); - $data = $cmd->fetchAll(); - return $data; - } - - /** - * get data with custom sql statment - * @param pdo $db - database object as pdo type - * @param string $sql - custom sql statment - * @return mixed - any returned data - */ - public static function execute($db,$sql) - { - if($sql === null) return null; - $cmd = $db->prepare($sql); - $cmd->execute(); - $data = $cmd->fetchAll(); - return $data; - } - - /** - * set single row - * @param pdo $db - database object as pdo type - * @param string $table - table name - * @param array $data - associative array 'col'=>'val' - * @param string $filterc - primary key column name or any other columns name - * @param string $filterv - value to match the condition field to - * @param int $val key value - */ - public static function set_row($db,$table,$data,$filterc,$filterv) { - - if($data === null) - exit; - elseif ($filterc !== null&&$filterv !== null) - { - // get values - $v = array_values($data); - // add condition value - array_push($v,$filterv); - // get keys - $c=array(); - foreach (array_keys($data) as $k) { - $c[]=$k."=?"; - } - // phrase command - $cmd=$db->prepare("UPDATE $table SET ".implode(', ', $c)." WHERE $filterc=?;"); - $cmd->execute($v); - } - else - { - // get values - $v = array_values($data); - // get keys - $c=implode(', ', array_keys($data)); - // phrase command - $cmd=$db->prepare("INSERT INTO $table ($c) values (".str_repeat("?,",count($c)-1)."?)"); - $cmd->execute($v); - } - } - - /** - * delete row - * @param string $table table name - * @param string $where column name for condition (commonly primay key column name) - * @param int $id key value - */ - public static function delete_row($db,$table,$filterc,$filterv) { - $cmd=$db->prepare("DELETE FROM $table WHERE $filterc=?"); - $cmd->execute($filterv); - } - - /** - * delete rows - * @param string $table table name - * @param string $where column name for condition (commonly primay key column name) - * @param int $id key value - */ - public static function delete_rows($db,$table,$filterc,$filterv) { - $cmd=$db->prepare("DELETE FROM $table WHERE $filterc=?"); - $cmd->execute($filterv); - } -} -?> \ No newline at end of file diff --git a/app/tftp/resources/systemd.service.template b/app/tftp/resources/systemd.service.template deleted file mode 100644 index d207be0ac4..0000000000 --- a/app/tftp/resources/systemd.service.template +++ /dev/null @@ -1,26 +0,0 @@ -[Unit] -Description={$fullname} -After=syslog.target network.target {$database} -Requires={$database} - -[Service] -Type=simple -PIDFile=/run/{$shortname}.pid -WorkingDirectory={$scriptfolder} -StandardOutput=null -StandardError=syslog -ExecStart=/usr/bin/php {$scriptpath} -ExecStop=/bin/kill $MAINPID -PrivateTmp=true -InaccessibleDirectories=/home /root /boot /opt /mnt /media -ReadOnlyDirectories=/etc /usr - -;Permissions -User=root -Group=daemon - -;Limits -LimitCORE=1 - -[Install] -WantedBy=multi-user.target \ No newline at end of file diff --git a/app/tftp/resources/tftpserver.class.php b/app/tftp/resources/tftpserver.class.php deleted file mode 100644 index 768ac69ef7..0000000000 --- a/app/tftp/resources/tftpserver.class.php +++ /dev/null @@ -1,873 +0,0 @@ - - * - * MIT License: - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * - * Extend TFTPServer class and then call loop method with UDP URL. - * Possible methods to override: - * exists($peer, $filename) - * Check if file exist, default always true. - * readable($peer, $filename) - * Check if file is readable, default always true. - * get($peer, $filename, $mode) - * Return content of file, default always false. - * Only called if both exists and readable returns true. - * writable($peer, $filename) - * Check if file is writable, default always false. - * put($peer, $filename, $mode, $content) - * Write content to file. - * Only falled if both exists and writable returns true. - * - * $peer is $ip:$port, source ip and port of client - * $filename is filename specified by client - * $mode is probably "octet" or "netascii" - * $content is file content - * - * The server support multiple concurrent read and writes, but the method calls - * are serialized, so make sure to return quickly. - * - * TODO: - * select must handle EINTR, how? - * multiple recv per select? - * - */ - -/* Note about the Logger class: - * The "priority" and "minimum should be one of the constants used for syslog. - * See: http://php.net/manual/en/function.syslog.php - * They are: LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, - * LOG_INFO, LOG_DEBUG - * Note that LOG_EMERG, LOG_ALERT, and LOG_CRIT are not really relevant to a - * tftp server - these represent instability in the entire operating system. - * Note that the number they are represented by are in reverse order - - * LOG_EMERG is the lowest, LOG_DEBUG the highest. - */ - -abstract class Logger -{ - function __construct($minimum) - { - $this->minimum = $minimum; - } - - function shouldlog($priority) - { - // Note: this looks reversed, but is correct - // the priority must be AT LEAST the minimum, - // because higher priorities represent lower numbers. - return $priority <= $this->minimum; - } - - abstract function log($priority, $message); -} - -class Logger_Null extends Logger -{ - function log($priority, $message) - { - } -} - -class Logger_Syslog extends Logger -{ - function log($priority, $message) - { - if($this->shouldlog($priority)) - syslog($priority,$message); - } -} - -class Logger_Filehandle extends Logger -{ - private $priority_map = array( - LOG_DEBUG => "D", - LOG_INFO => "I", - LOG_NOTICE => "N", - LOG_WARNING => "W", - LOG_ERR => "E", - LOG_CRIT => "C", - LOG_ALERT => "A", - LOG_EMERG => "!" - ); - function __construct($minimum, $filehandle, $dateformat = "r") - { - $this->filehandle = $filehandle; - $this->dateformat = $dateformat; - return parent::__construct($minimum); - } - - function log($priority, $message) - { - if($this->shouldlog($priority)) - fwrite($this->filehandle, date($this->dateformat) . ": " . $this->priority_map[$priority] . " $message\n"); - } -} - -class Logger_Filename extends Logger_Filehandle -{ - function __construct($minimum, $filename, $dateformat = "r") - { - return parent::__construct($minimum, fopen($filename, "a"), $dateformat); - } -} - -class Logger_Stderr extends Logger_Filehandle -{ - function __construct($minimum, $dateformat = "r") - { - return parent::__construct($minimum, STDERR, $dateformat); - } -} -class Logger_Stdout extends Logger_Filehandle -{ - function __construct($minimum, $dateformat = "r") - { - return parent::__construct($minimum, STDOUT, $dateformat); - } -} - -class TFTPOpcode -{ - public static function name($v) - { - static $names = array(TFTPOpcode::RRQ => "RRQ", - TFTPOpcode::WRQ => "WRQ", - TFTPOpcode::DATA => "DATA", - TFTPOpcode::ACK => "ACK", - TFTPOpcode::ERROR => "ERROR", - TFTPOpcode::OACK => "OACK"); - if(isset($names[$v])) - return $names[$v]; - else - return "UNKNOWN"; - } - - const RRQ = 1; // read request - const WRQ = 2; // write request - const DATA = 3; // send data - const ACK = 4; // ack data - const ERROR = 5; - const OACK = 6; // option ack, instead of first ACK/DATA -} - -class TFTPError -{ - const NOT_DEFINED = 0; // see error message instead of error code - const FILE_NOT_FOUND = 1; - const ACCESS_VIOLATION = 2; - const DISK_FULL = 3; - const ILLEGAL_OPERATION = 4; - const UNKNOWN_TID = 5; // unknown transfer (id is ip:port pair) - const FILE_ALREADY_EXISTS = 6; - const NO_SUCH_USER = 7; - const OACK_FAILURE = 8; -} - -class TFTPTransferState -{ - const READY = 1; - const SENDING_WAIT_OACK = 2; - const SENDING = 3; - const RECEIVING = 4; - const TERMINATING = 5; -} - -abstract class TFTPTransfer { - public $state; - public $peer; - public $retransmit_timeout; - public $block_size; - public $tsize; - protected $_server; // TFTPServer reference - - function __construct($server, $peer, $extensions) - { - $this->state = TFTPTransferState::READY; - $this->peer = $peer; - $this->retransmit_timeout = $server->retransmit_timeout; - $this->block_size = $server->block_size; - $this->tsize = 0; - $this->_server = $server; - - if(isset($extensions["timeout"])) { - $timeout = (int)$extensions["timeout"]; - if($timeout > 0 && $timeout < 256) - $this->retransmit_timeout = $timeout; - } - - if(isset($extensions["blksize"])) { - $blksize = (int)$extensions["blksize"]; - if($blksize > 0 && $blksize <= $server->max_block_size) - $this->block_size = $blksize; - } - - // tsize is only checked for in write transfers - } - - protected function log_debug($message) - { - $this->_server->log_debug($this->peer, $message); - } - - protected function log_info($message) - { - $this->_server->log_info($this->peer, $message); - } - - protected function log_warning($message) - { - $this->_server->log_warning($this->peer, $message); - } - - protected function log_error($message) - { - $this->_server->log_error($this->peer, $message); - } - - protected function terminal_info($error, $message) - { - $this->log_info($message); - $this->state = TFTPTransferState::TERMINATING; - return TFTPServer::packet_error($error, $message); - } - - protected function terminal_error($op, $error, $message) - { - $this->log_debug("$op: $message"); - $this->state = TFTPTransferState::TERMINATING; - return TFTPServer::packet_error($error, $message); - } - - protected function illegal_operation($op, $message = "Illegal operation") - { - return $this->terminal_error($op, TFTPError::ILLEGAL_OPERATION, $message); - } - - public function rrq($filename, $mode) - { - return $this->illegal_operation("RRQ"); - } - - public function wrq($filename, $mode) - { - return $this->illegal_operation("WRQ"); - } - - public function data($block, $data) - { - return $this->illegal_operation("DATA"); - } - - public function ack($block) - { - return $this->illegal_operation("ACK"); - } - - public function error($error, $message) - { - $this->log_debug("ERROR: $error: $message"); - $this->state = TFTPTransferState::TERMINATING; - } - - protected function use_extensions() { - return - $this->retransmit_timeout != $this->_server->retransmit_timeout || - $this->block_size != $this->_server->block_size || - $this->tsize != 0; - } - - protected function packet_oack() { - $options = array(); - - if($this->retransmit_timeout != $this->_server->retransmit_timeout) - $options["timeout"] = (string)$this->retransmit_timeout; - - if($this->block_size != $this->_server->block_size) - $options["blksize"] = (string)$this->block_size; - - if($this->tsize != 0) - $options["tsize"] = (string)$this->tsize; - - return TFTPServer::packet_oack($options); - } -} - -class TFTPReadTransfer extends TFTPTransfer { - private $_last_recv_ack; - private $_last_sent_data; - private $_buffer; - private $_block; - private $_last_block; - - function __construct($server, $peer, $extensions) - { - parent::__construct($server, $peer, $extensions); - $this->_last_recv_ack = time(); - $this->_last_sent_data = $this->_last_recv_ack; - $this->_buffer = false; - $this->_block = 1; - $this->_last_block = 1; - - $this->log_debug("new read transfer"); - } - - private function current_block() - { - return substr($this->_buffer, - ($this->_block - 1) * $this->block_size, - $this->block_size); - } - - private function packet_data_current() - { - $this->_last_sent_data = time(); - - if($this->state == TFTPTransferState::SENDING_WAIT_OACK) - return $this->packet_oack(); - else - return TFTPServer::packet_data($this->_block, $this->current_block()); - } - - public function rrq($filename, $mode) - { - $this->log_debug("RRQ: filename $filename in $mode mode"); - - if($this->state != TFTPTransferState::READY) - return $this->illegal_operation("RRQ", "Not in ready state"); - - if(!$this->_server->exists($this->peer, $filename)) - return $this->terminal_info(TFTPError::FILE_NOT_FOUND, - "File $filename does not exist"); - - if(!$this->_server->readable($this->peer, $filename)) - return $this->terminal_info(TFTPError::ACCESS_VIOLATION, - "File $filename is not readable"); - - $this->_buffer = $this->_server->get($this->peer, $filename, $mode); - if($this->_buffer === false) - return $this->terminal_info(TFTPError::FILE_NOT_FOUND, - "Failed to read $filename"); - - $this->log_info("Reading $filename (" . - strlen($this->_buffer) . " bytes)"); - - if($this->use_extensions()) - $this->state = TFTPTransferState::SENDING_WAIT_OACK; - else - $this->state = TFTPTransferState::SENDING; - $this->_last_block = floor(strlen($this->_buffer) / - $this->block_size) + 1; - - $this->log_debug("RRQ: send first block or OACK"); - return $this->packet_data_current(); - } - - public function ack($block) - { - if($this->state == TFTPTransferState::SENDING_WAIT_OACK) { - if($block != 0) { - $this->log_debug("ACK: waiting OACK ACK got block $block"); - return false; - } - - $this->state = TFTPTransferState::SENDING; - $this->log_debug("ACK: got OACK ACK, send first block"); - return $this->packet_data_current(); - } - - if($this->state != TFTPTransferState::SENDING) - return $this->illegal_operation("ACK", "Not in sending state"); - - $this->log_debug("ACK: block $block"); - $this->_last_recv_ack = time(); - - if($block < $this->_block) { - $this->log_debug("ACK: duplicate block $block"); - // just ignore it - return false; - } - - if($block > $this->_last_block) - return $this->illegal_operation("ACK", - "Block $block outside " . - "range 1-{$this->_last_block}"); - - if($block == $this->_last_block) { - $this->log_debug("ACK: last block, done"); - $this->state = TFTPTransferState::TERMINATING; - return false; - } - - // move to next block - $this->_block = $block + 1; - - $this->log_debug("ACK: sending block {$this->_block}"); - return $this->packet_data_current(); - } - - public function retransmit($now) - { - if($now - $this->_last_recv_ack > $this->_server->timeout) { - $this->log_debug("retransmit: timeout"); - $this->state = TFTPTransferState::TERMINATING; - return false; - } - - if($now - $this->_last_sent_data > $this->retransmit_timeout) { - $this->log_debug("retransmit: resending block {$this->_block} or OACK"); - return $this->packet_data_current(); - } - - return false; - } -} - -class TFTPWriteTransfer extends TFTPTransfer { - private $_last_sent_ack; - private $_last_recv_data; - private $_buffer; - private $_buffer_size; - private $_next_block; - private $_filename; - private $_mode; - - function __construct($server, $peer, $extensions) - { - parent::__construct($server, $peer, $extensions); - $this->_last_sent_ack = time(); - $this->_last_recv_data = $this->_last_sent_ack; - $this->_buffer = array(); - $this->_buffer_size = 0; - $this->_last_recv_block = 0; - $this->_filename = false; - $this->_mode = false; - - if(isset($extensions["tsize"])) - $this->tsize = (int)$extensions["tsize"]; - - $this->log_debug("new write transfer"); - } - - private function packet_ack_current() - { - $this->_last_sent_ack = time(); - - if($this->_last_recv_block == 0 && $this->use_extensions()) - return $this->packet_oack(); - else - return TFTPServer::packet_ack($this->_last_recv_block); - } - - public function wrq($filename, $mode) - { - $this->log_debug("WRQ: filename $filename in $mode mode"); - - if($this->state != TFTPTransferState::READY) - return $this->illegal_operation("WRQ", "Not in ready state"); - - if(!$this->_server->writable($this->peer, $filename)) - return $this->terminal_info(TFTPError::ACCESS_VIOLATION, - "File $filename is not writable"); - - if($this->tsize != 0 && $this->tsize > $this->_server->max_put_size) - return $this->terminal_info(TFTPError::DISK_FULL, - "File too big, " . - $this->tsize . "(tsize) > " . - $this->_server->max_put_size); - - $this->state = TFTPTransferState::RECEIVING; - $this->_filename = $filename; - $this->_mode = $mode; - $this->_last_sent_ack = time(); - - $this->log_debug("WRQ: ack request"); - if($this->use_extensions()) - return $this->packet_oack(); - else - return TFTPServer::packet_ack(0); - } - - public function data($block, $data) - { - if($this->state != TFTPTransferState::RECEIVING) - return $this->illegal_operation("DATA", "Not in receiving state"); - - $this->log_debug("DATA: block $block"); - $this->last_recv_data = time(); - - if($block <= $this->_last_recv_block) { - $this->log_debug("DATA: duplicate block $block"); - // just ignore it - return false; - } - - if($block != $this->_last_recv_block + 1) - return $this->illegal_operation("DATA", - "Expected block " . - ($this->_last_recv_block + 1) . - " got $block"); - - $this->_last_recv_block = $block; - $this->_last_recv_data = time(); - array_push($this->_buffer, $data); - $this->_buffer_size += strlen($data); - - if($this->_buffer_size > $this->_server->max_put_size) - return $this->terminal_info(TFTPError::DISK_FULL, - "File too big, " . - $this->_buffer_size . " > " . - $this->_server->max_put_size); - - if(strlen($data) < $this->block_size) { - $this->log_debug("DATA: last, done"); - $this->state = TFTPTransferState::TERMINATING; - $this->log_info("Writing {$this->_filename} " . - "({$this->_buffer_size} bytes)"); - $this->_server->put($this->peer, $this->_filename, $this->_mode, - implode("", $this->_buffer)); - return $this->packet_ack_current(); - } - - $this->log_debug("DATA: ack block $block"); - return $this->packet_ack_current(); - } - - public function retransmit($now) - { - if($now - $this->_last_recv_data > $this->_server->timeout) { - $this->log_debug("retransmit: timeout"); - $this->state = TFTPTransferState::TERMINATING; - return false; - } - - if($now - $this->_last_sent_ack > $this->retransmit_timeout) { - $this->log_debug("retransmit: reack block {$this->_last_recv_block}"); - return $this->packet_ack_current(); - } - - return false; - } -} - -class TFTPServer { - public $block_size = 512; - public $max_block_size = 65464; // max block size from rfc2348 - public $timeout = 10; - public $retransmit_timeout = 1; - public $max_put_size = 10485760; // 10 Mibi - private $_socket_url; - private $_socket; - private $_transfers = array(); - private $_logger = NULL; - - function __construct($socket_url, $logger = NULL) - { - $this->_socket_url = $socket_url; - $this->_logger = $logger; - } - - public function exists($peer, $filename) - { - return true; - } - - public function readable($peer, $filename) - { - return true; - } - - public function get($peer, $filename, $mode) - { - return false; - } - - public function writable($peer, $filename) - { - return false; - } - - public function put($peer, $filename, $mode, $content) - { - } - - public function logger_log($priority, $message) { - if($this->_logger === NULL) - return; - - $this->_logger->log($priority, $message); - } - - public function log_debug($peer, $message) - { - $this->logger_log(LOG_DEBUG, "$peer $message"); - } - - public function log_info($peer, $message) - { - $this->logger_log(LOG_INFO, "$peer $message"); - } - - public function log_warning($peer, $message) - { - $this->logger_log(LOG_WARNING, "$peer $message"); - } - - public function log_error($peer, $message) - { - $this->logger_log(LOG_ERR, "$peer $message"); - } - - public static function packet_ack($block) - { - return pack("nn", TFTPOpcode::ACK, $block); - } - - public static function packet_data($block, $data) - { - return pack("nn", TFTPOpcode::DATA, $block) . $data; - } - - public static function packet_error($code, $message = "") - { - return pack("nn", TFTPOpcode::ERROR, $code) . $message . "\0"; - } - - public static function packet_oack($options) - { - $data = ""; - foreach($options as $key => $value) - $data .= "$key\0$value\0"; - return pack("n", TFTPOpcode::OACK) . $data; - } - - public static function escape_string($str) - { - $b = ""; - $l = strlen($str); - for($i = 0; $i < $l; $i++) { - $c = $str[$i]; - if(ctype_print($c)) - $b .= $c; - else - $b .= sprintf("\\x%'02x", ord($c)); - } - - return $b; - } - - public function loop(&$error = false, $user = null) - { - $this->_socket = - stream_socket_server($this->_socket_url, $errno, $errstr, - STREAM_SERVER_BIND); - if(!$this->_socket) { - if($error !== false) - $error = "$errno: $errstr"; - return false; - } - - if($user != null) { - posix_seteuid($user["uid"]); - posix_setegid($user["gid"]); - } - - stream_set_blocking($this->_socket, false); - - return $this->loop_ex(); - } - - private function loop_ex() - { - $now = $last = time(); - - while(true) { - $read = array($this->_socket); - $write = null; - $excpt = null; - $r = stream_select($read, $write, $excpt, 1); - - if($r === false) { - $this->log_error("server", "select returned false"); - continue; - } - - if(count($read) > 0) { - $packet = stream_socket_recvfrom($this->_socket, - 65535, // max udp packet size - 0, // no flags - $peer); - // ipv6 hack, convert to [host]:port format - if(strpos($peer, ".") === false) { - $portpos = strrpos($peer, ":"); - $host = substr($peer, 0, $portpos); - $port = substr($peer, $portpos + 1); - $peer = "[$host]:$port"; - } - $this->log_debug($peer, "request: ".strlen($packet)." bytes"); - $this->log_debug($peer, "request: ".TFTPServer::escape_string($packet)); - $reply = $this->request($peer, $packet); - if($reply !== false) { - $this->log_debug($peer, "reply: " . - TFTPServer::escape_string($reply)); - stream_socket_sendto($this->_socket, $reply, 0, $peer); - } - } - - $now = time(); - if($now != $last) { - $last = $now; - $this->retransmit($now); - } - } - } - - private function retransmit($now) - { - foreach($this->_transfers as $peer => $transfer) { - $reply = $transfer->retransmit($now); - if($reply !== false) { - $this->log_debug($peer, "resend: " . - TFTPServer::escape_string($reply)); - stream_socket_sendto($this->_socket, $reply, 0, $peer); - } - - if($transfer->state == TFTPTransferState::TERMINATING) - unset($this->_transfers[$peer]); - } - } - - private function request($peer, $packet) - { - if(strlen($packet) < 4) { - $this->log_debug($peer, "request: short packet"); - return false; - } - - $reply = false; - $transfer = false; - if(isset($this->_transfers[$peer])) { - $this->log_debug($peer, "request: existing transfer"); - $transfer = $this->_transfers[$peer]; - } - - $fields = unpack("n", $packet); - $op = $fields[1]; - $this->log_debug($peer, "request: opcode " . - TFTPOpcode::name($op) . " ($op)"); - switch($op) { - case TFTPOpcode::WRQ: - case TFTPOpcode::RRQ: - $a = explode("\0", substr($packet, 2)); - if(count($a) < 3 || $a[count($a) - 1] != "") { - $this->log_warning($peer, "request: malformed " . - TFTPOpcode::name($op)); - return false; - } - - $rawexts = array_slice($a, 2, -1); - - // Cisco IP Phone 7941 (and possibly others) return an extra null - // at the end; a breach of RFC rfc2347. This is a workaround. - // If odd count strip last and continue if empty, else warn and ignore - if(count($rawexts) % 2 != 0) { - if(array_pop($rawexts)!="") { - $this->log_warning($peer, "request: malformed extension " . - "key/value pairs " . TFTPOpcode::name($op)); - return false; - } - } - - $extensions = array(); - foreach(array_chunk($rawexts, 2) as $pair) - $extensions[strtolower($pair[0])] = $pair[1]; - - if($transfer === false) { - if($op == TFTPOpcode::RRQ) - $transfer = new TFTPReadTransfer($this, $peer, $extensions); - else - $transfer = new TFTPWriteTransfer($this, $peer, $extensions); - - $this->_transfers[$peer] = $transfer; - } - - if($op == TFTPOpcode::RRQ) - $reply = $transfer->rrq($a[0], $a[1]); - else - $reply = $transfer->wrq($a[0], $a[1]); - - break; - case TFTPOpcode::ACK: - if(strlen($packet) != 4) { - $this->log_warning($peer, "request: malformed ACK"); - return false; - } - - $a = unpack("n", substr($packet, 2)); - if($transfer === false) { - // do not warn, some clients like BSD tftp sends ack on read error - $this->log_debug($peer, "request: ack from unknwon peer"); - } else - $reply = $transfer->ack($a[1]); - break; - case TFTPOpcode::DATA: - if(strlen($packet) < 4) { - $this->log_warning($peer, "request: malformed DATA"); - return false; - } - - $a = unpack("n", substr($packet, 2)); - $data = substr($packet, 4, strlen($packet) - 4); - if($transfer === false) { - $this->log_warning($peer, "request: data from unknwon peer"); - $reply = TFTPServer::packet_error(TFTPError::UNKNOWN_TID, - "Unknown TID for DATA"); - } else - $reply = $transfer->data($a[1], $data); - break; - case TFTPOpcode::ERROR: - $a = unpack("n", substr($packet, 2, 2)); - $message = substr($packet, 4, strlen($packet) - 5); - - if($transfer === false) - $this->log_warning($peer, "request: error from unknwon peer, " . - "{$a[1]}:$message"); - else - $transfer->error($a[1], $message); - break; - default: - break; - } - - if($transfer !== false && - $transfer->state == TFTPTransferState::TERMINATING) { - $this->log_debug($peer, "request: terminating"); - unset($this->_transfers[$transfer->peer]); - } - - return $reply; - } -} - -?> diff --git a/app/tftp/resources/tftpservice.class.php b/app/tftp/resources/tftpservice.class.php deleted file mode 100644 index 0aaa27f758..0000000000 --- a/app/tftp/resources/tftpservice.class.php +++ /dev/null @@ -1,178 +0,0 @@ - - Portions created by the Initial Developer are Copyright (C) 2016 - the Initial Developer. All Rights Reserved. - - Contributor(s): - Sebastian Krupinski -*/ - -// load required files -require_once 'tftpserver.class.php'; - -class tftpservice extends TFTPServer -{ - private $_headless=true; - private $_debug=false; - private $_dbtype; - private $_dbhost; - private $_dbport; - private $_dbname; - private $_dbusername; - private $_dbpassword; - private $_fileslocation; - - function __construct($server_url, $config) - { - parent::__construct($server_url); - if (isset($config['headless'])) $this->_headless=$config['headless']; - if (isset($config['debug'])) $this->_debug=$config['debug']; - if (isset($config['db_type'])) $this->_dbtype=$config['db_type']; - if (isset($config['db_host'])) $this->_dbhost=$config['db_host']; - if (isset($config['db_port'])) $this->_dbport=$config['db_port']; - if (isset($config['db_name'])) $this->_dbname=$config['db_name']; - if (isset($config['db_username'])) $this->_dbusername=$config['db_username']; - if (isset($config['db_password'])) $this->_dbpassword=$config['db_password']; - if (isset($config['files_location'])) $this->_fileslocation=$config['files_location']; - - if (!file_exists($_fileslocation)) { - $_fileslocation = (strpos(PHP_OS,"WIN") !== false) ? $_SERVER["TMP"] : "/tmp"; - } - } - - private function log($client, $level, $message) { - if(!$this->_headless && ($level!='D' || $this->_debug)) { - echo - date("H:i:s") . " " . - $level . " " . - $client . " " . - $message . "\n"; - } - - } - - public function get($client, $filepath, $mode) - { - $this->log($client,"N", "Requested File ".$filepath); - - try { - $regex_filter='/provision\/(?\b(?:(?-)[A-Za-z0-9-\_]{1,63}(?-)\.)+[A-Za-z]{1,63}\b|\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b)\/(?\b(?:[0-9a-fA-F]{2}(?:\-|\:)?){6}\b)/'; - - preg_match($regex_filter,$filepath,$regex_matches); - - // check if filepath is in a specific format and respond acordingly - if ($regex_matches['domain']&&$regex_matches['mac']) - { - // generate file from db - $filedata = $this->generate_file($client,$regex_matches['domain'],$regex_matches['mac']); - } - else - { - // retrieve file from disk - $filedata = $this->retrieve_file($client,$filepath); - } - - if($filedata !== false) - { - $this->log($client,"N", "Transmitting File ".$filepath); - - return $filedata; - } - else - { - return false; - } - } - catch (Exception $exception) - { - $this->log($client,"E", "Exception: ".$exception->getMessage()); - return false; - } - } - - public function generate_file($client, $domain, $mac) - { - // load required files - require_once __DIR__.'/dbhelper.php'; - require_once __DIR__.'/../../../resources/functions.php'; - require_once __DIR__.'/../../../resources/classes/template.php'; - require_once __DIR__.'/../../provision/resources/classes/provision.php'; - - $this->log($client,"D", "Generating File ".$domain." ".$mac); - - // connect to database - $db = database::connect($this->_dbtype,$this->_dbhost,$this->_dbport,$this->_dbname,$this->_dbusername,$this->_dbpassword); - - // get domain uuid - $domain_uuid = database::get_value($db,'v_domains','domain_uuid','domain_name',$domain); - - // set temporary folder for template engine - $_SESSION['server']['temp']['dir'] = (strpos(PHP_OS,"WIN") !== false) ? $_SERVER["TMP"] : "/tmp"; - - // update device provisioned status - $data=array('device_provisioned_date'=>date("Y-m-d H:i:s"),'device_provisioned_method'=>'tftp','device_provisioned_ip'=>$client); - database::set_row($db,'v_devices',$data,'device_mac_address',$mac); - - // generate file - $prov = new provision; - $prov->db = $db; - $prov->domain_uuid = $domain_uuid; - $prov->mac = $mac; - $data = $prov->render(); - - // return data or false - if($data === false) - { - $this->log($client,"W", "Generating File Failed ".$domain." ".$mac); - return false; - } - else - { - return $data; - } - } - - public function retrieve_file($client, $path){ - - $this->log($client,"D", "Retrieve File ".$path); - // check for reletive path directive - if(strstr($path, "../") != false || strstr($path, "/..") != false) return false; - // combine base and path - $path = rtrim($this->_fileslocation,'/').'/'.ltrim($path,'/'); - if(substr($path, 0, strlen($this->_fileslocation)) != $this->_fileslocation) return false; - // read contents - if($this->_debug) $this->log($client,"D", "Reading File ".$path); - $data = @file_get_contents($path); - // return data or false - if($data === false) - { - $this->log($client,"W", "Retrieving File Failed ".$path); - return false; - } - else - { - return $data; - } - - } -} - -?> \ No newline at end of file diff --git a/app/tftp/tftpservice.php b/app/tftp/tftpservice.php deleted file mode 100644 index a613f96c2f..0000000000 --- a/app/tftp/tftpservice.php +++ /dev/null @@ -1,344 +0,0 @@ -#!/usr/bin/env php - - Portions created by the Initial Developer are Copyright (C) 2016 - the Initial Developer. All Rights Reserved. - - Contributor(s): - Sebastian Krupinski -*/ - -// define variables and constants -$appname = "fusionpbx-tftp"; -$appdesc = "FusionPBX TFTP Service"; -$pid=null; -$pidfile = (strpos(PHP_OS,"WIN") !== false) ? $_SERVER["TMP"]."\\$appname.pid" : "/var/run/$appname.pid"; -$tftpservice_address="0.0.0.0"; -$tftpservice_port=69; -$tftpservice_file_path=(strpos(PHP_OS,"WIN") !== false) ? $_SERVER["TMP"] : "/tmp"; - -function Service_Install() -{ - global $appname; - global $appdesc; - - // install for specific os - if (strpos(PHP_OS,"WIN") !== false) - { - // check if we found the executable binary - if (file_exists(PHP_BINARY)) - { - win32_create_service( Array( - 'service' => $appname, - 'display' => $appdesc, - 'params' => __FILE__ . " --Service", - 'path' => PHP_BINARY - )); - - //exec('sc create '.$appname.' type=own binPath="'.PHP_BINARY.' '.$_SERVER["SCRIPT_FILENAME"].'" DisplayName="'.$appdesc.'" start=auto'); - die($appdesc." was successfully installed.\n"); - } - else - { - die($appdesc." could not be installed because the php executable was not found.\n"); - } - } - else - { - // load required files - require_once __DIR__.'/../../resources/config.php'; //required for database type - - // read template file - $template=file_get_contents(dirname(__FILE__).'/resources/systemd.service.template'); - - // service short name - $template=str_replace('{$shortname}',$appname,$template); - // service full name - $template=str_replace('{$fullname}',$appdesc,$template); - // service dependencies - switch ($db_type) { - case 'pgsql': - $template=str_replace('{$database}','postgresql.service',$template); - break; - case 'mysql': - $template=str_replace('{$database}','mariadb.service',$template); - break; - default: - $template=str_replace('{$database}','',$template); - break; - } - // script path - $template=str_replace('{$scriptpath}',__FILE__,$template); - // script folder - $template=str_replace('{$scriptfolder}',dirname(__FILE__),$template); - // script filename - $template=str_replace('{$scriptfilename}',basename(__FILE__),$template); - - // write service file - file_put_contents('/lib/systemd/system/'.$appname.'.service', $template); - // reload systemd and enable service - exec('systemctl daemon-reload'); - exec('systemctl enable '.$appname); - - die($appdesc." was successfully installed.\n"); - } -} - -function Service_Uninstall() -{ - global $appname; - global $appdesc; - - // uninstall for specific os - if (strpos(PHP_OS,"WIN") !== false) - { - win32_delete_service($appname); - //exec('sc delete "'.$appname.'"'); - die($appdesc." was successfully uninstalled.\n"); - } - else - { - // stop service and disable in systemd - exec('systemctl stop '.$appname); - exec('systemctl disable '.$appname); - // delete systemd service file - unlink('/lib/systemd/system/'.$appname.'.service'); - die($appdesc." was successfully uninstalled.\n"); - } -} - -function Service_Run() -{ - global $appname; - global $appdesc; - global $pid; - global $pidfile; - - // check for existing process - if (file_exists($pidfile)) { - $pid = file_get_contents($pidfile); - if (is_numeric($pid)) { - if (strpos(PHP_OS,"WIN") !== false) - { - exec('tasklist -NH -FO TABLE -FI "PID eq '.$pid.'" 2>NUL', $data); - foreach($data as $line) - { - if (strpos($line,$pid) !== false) die($appdesc." already running with process id ".$pid); - } - - Service_Windows_Run(); - } - else - { - if (file_exists('/proc/'.$pid)) die($appdesc." already running with process id".$pid); - - Service_Linux_Run(); - } - } - } - -} - -function Service_Linux_Run() -{ - global $appname; - global $appdesc; - global $pid; - global $pidfile; - global $tftpservice_address; - global $tftpservice_port; - global $tftpservice_file_path; - - // write pid file - file_put_contents($pidfile, getmypid()); - - // load required files - require_once __DIR__.'/../../resources/config.php'; - require_once 'resources/dbhelper.php'; - - // get service settings from database - // connect to database - $db = database::connect($db_type,$db_host,$db_port,$db_name,$db_username,$db_password); - // get settings - $s = database::get_table($db,'v_default_settings',array('default_setting_subcategory','default_setting_value'),array('default_setting_subcategory','LIKE','tftp_service_%')); - // set local variables - foreach ($s as $i) { - switch ($i[0]) { - case 'tftp_service_address': - $tftpservice_address=$i[1]; - break; - case 'tftp_service_port': - $tftpservice_port=$i[1]; - break; - case 'tftp_service_file_path': - $tftpservice_file_path=$i[1]; - break; - } - } - // disconnect from database - unset($db); - // destroy data - unset($s); - - // load required files - require_once 'resources/tftpservice.class.php'; - - // start service - $server = new tftpservice("udp://$tftpservice_address:$tftpservice_port", array("headless"=>true, "db_type"=>$db_type, "db_host"=>$db_host, "db_port"=>$db_port, "db_name"=>$db_name, "db_username"=>$db_username, "db_password"=>$db_password, "files_location"=>$tftpservice_file_path)); - if(!$server->loop($error, $user)) die("$error\n"); -} - -function Service_Windows_Run() -{ - global $appname; - global $appdesc; - global $pid; - global $pidfile; - global $tftpservice_address; - global $tftpservice_port; - global $tftpservice_file_path; - - // write pid file - file_put_contents($pidfile, getmypid()); - - // load required files - require_once __DIR__.'/../../resources/config.php'; - require_once 'resources/dbhelper.php'; - - // get service settings from database - // connect to database - $db = database::connect($db_type,$db_host,$db_port,$db_name,$db_username,$db_password); - // get settings - $s = database::get_table($db,'v_default_settings',array('default_setting_subcategory','default_setting_value'),array('default_setting_subcategory','LIKE','tftp_service_%')); - // set local variables - foreach ($s as $i) { - switch ($i[0]) { - case 'tftp_service_address': - $tftpservice_address=$i[1]; - break; - case 'tftp_service_port': - $tftpservice_port=$i[1]; - break; - case 'tftp_service_file_path': - $tftpservice_file_path=$i[1]; - break; - } - } - // disconnect from database - unset($db); - // destroy data - unset($s); - - // load required files - require_once 'resources/tftpservice.class.php'; - - // start service - $server = new tftpservice("udp://$tftpservice_address:$tftpservice_port", array("headless"=>true, "db_type"=>$db_type, "db_host"=>$db_host, "db_port"=>$db_port, "db_name"=>$db_name, "db_username"=>$db_username, "db_password"=>$db_password, "files_location"=>$tftpservice_file_path)); - // signal running to service controller - win32_start_service_ctrl_dispatcher($appname); - win32_set_service_status(WIN32_SERVICE_RUNNING); - // execute run loop - if(!$server->loop($error, $user)) die("$error\n"); - // signal stopped to service controller - win32_set_service_status(WIN32_SERVICE_STOPPED); -} - -function Run() -{ - global $appname; - global $appdesc; - global $pid; - global $pidfile; - global $tftpservice_address; - global $tftpservice_port; - global $tftpservice_file_path; - - // check for existing process - if (file_exists($pidfile)) { - $pid = file_get_contents($pidfile); - if (is_numeric($pid)) { - if (strpos(PHP_OS,"WIN") !== false) - { - exec('tasklist -NH -FO TABLE -FI "PID eq '.$pid.'" 2>NUL', $data); - foreach($data as $line) - { - if (strpos($line,$pid) !== false) die($appdesc." already running with process id ".$pid); - } - } - else - { - if (file_exists('/proc/'.$pid)) die($appdesc." already running with process id".$pid); - } - } - } - - // write pid file - file_put_contents($pidfile, getmypid()); - - // load required files - require_once __DIR__.'/../../resources/config.php'; - require_once 'resources/dbhelper.php'; - - // get service settings from database - // connect to database - $db = database::connect($db_type,$db_host,$db_port,$db_name,$db_username,$db_password); - // get settings - $s = database::get_table($db,'v_default_settings',array('default_setting_subcategory','default_setting_value'),array('default_setting_subcategory','LIKE','tftp_service_%')); - // set local variables - foreach ($s as $i) { - switch ($i[0]) { - case 'tftp_service_address': - $tftpservice_address=$i[1]; - break; - case 'tftp_service_port': - $tftpservice_port=$i[1]; - break; - case 'tftp_service_file_path': - $tftpservice_file_path=$i[1]; - break; - } - } - // disconnect from database - unset($db); - // destroy data - unset($s); - - // load required files - require_once 'resources/tftpservice.class.php'; - - // start service - $server = new tftpservice("udp://$tftpservice_address:$tftpservice_port", array('db_type'=>$db_type,'db_host'=>$db_host, "db_port"=>$db_port, "db_name"=>$db_name, "db_username"=>$db_username, "db_password"=>$db_password, "files_location"=>$tftpservice_file_path)); - echo $appdesc." has started.\n"; - if(!$server->loop($error, $user)) die("$error\n"); - echo $appdesc." has stopped.\n"; -} - -if (php_sapi_name() === 'cli') { - if(isset($_SERVER["argv"][1])&&$_SERVER["argv"][1]=="--InstallService") - Service_Install(); // Install System Service - elseif(isset($_SERVER["argv"][1])&&$_SERVER["argv"][1]=="--UninstallService") - Service_Uninstall(); // Uninstall System Service - elseif(isset($_SERVER["argv"][1])&&$_SERVER["argv"][1]=="--Service") - Service_Run(); // Run as a Service - else - Run(); // Run -} -?>