From a4ebaee7766c4fdba8cd93044dad43836d9eda1a Mon Sep 17 00:00:00 2001 From: Diederik de Groot Date: Sat, 15 Feb 2020 19:30:00 +0100 Subject: [PATCH] Initial checkin of resolver.php - use \\ instead of just \ in FileName - Use file_put_contents instead of open/write - Use file_exist instead of stat - Added /lib directory - Moved /tftpboot/index.cfg -> /config.ini - Moved /tftpboot/resolver.php -> /lib/resolver.php - Added /lib/config.php - include /lib/config.php in resolver.php and index.php - Changed $config array - Remove print_r($config['main']['base_path']) from config.php - Add isValidRequest() function - Use Boolean in tree_base data - Simplify config['subdirs'] substitution - Add lib/utils.php file - Added simple shell/utf/html escape checking - Added a collection of test cases (we need some more escape checking ones) - Added lib/logger.php (copied from tftpserver.php, so that it can be reused for that). - Clarify config.ini logformat - Update logger implementation - Replaced index.php with version that uses lib/resolver.php - Replaced ../etc/nginx/sites-available/tftpboot Example file --- config.ini | 17 ++ etc/nginx/sites-available/tftpboot | 277 ++-------------------- lib/config.php | 80 +++++++ lib/logger.php | 94 ++++++++ lib/resolver.php | 168 ++++++++++++++ lib/utils.php | 10 + tftpboot/index.cnf | 13 -- tftpboot/index.php | 361 +++++------------------------ tftpboot/ringtones/mkringlist.sh | 4 +- 9 files changed, 454 insertions(+), 570 deletions(-) create mode 100644 config.ini create mode 100644 lib/config.php create mode 100644 lib/logger.php create mode 100644 lib/resolver.php create mode 100644 lib/utils.php delete mode 100644 tftpboot/index.cnf diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..21f7036 --- /dev/null +++ b/config.ini @@ -0,0 +1,17 @@ +[main] +debug = on ; The output in the browser window for more information +cache_filename = "/tmp/provision_sccp_resolver.cache" +default_language = English_United_States +log_type = SYSLOG ; SYSLOG|STDERR|STDOUT|NULL|FILE +log_level = LOG_INFO ; LOG_EMERG|LOG_ALERT|LOG_CRIT|LOG_ERR|LOG_WARNING|LOG_NOTICE|LOG_INFO|LOG_DEBUG +;log_filename = provision.log ; only in case of log_type = FILE + +[subdirs] +tftproot = tftpboot +firmware = firmware +settings = settings +wallpapers = wallpapers +ringtones = ringtones +locales = locales +countries = countries +languages = languages diff --git a/etc/nginx/sites-available/tftpboot b/etc/nginx/sites-available/tftpboot index 23f3772..9d9c4ce 100644 --- a/etc/nginx/sites-available/tftpboot +++ b/etc/nginx/sites-available/tftpboot @@ -1,260 +1,29 @@ server { - listen 6970; - server_name tftp.servername.org; - #root /tftpboot; - root /data/development/sccp/sources/tftp/tftpboot; - index XMLDefault.cnf.xml; + listen 6970; + server_name tftp.servername.org; + root /data/development/sccp/sources/tftp/tftpboot; - # Normal Logging - #access_log /var/log/nginx/tftp.access.log; - #error_log /var/log/nginx/tftp.error.log; + # Normal Logging + access_log /var/log/nginx/tftp1.access.log; + error_log /var/log/nginx/tftp1.error.log; - # Debug Rewrite Rules - rewrite_log on; - access_log /var/log/nginx/tftp.access.log; - error_log /var/log/nginx/tftp.error.log notice; + index index.php; + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:/var/run/php/php7.3-fpm.sock; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include fastcgi_params; + } - location / { - # settings - rewrite ^/((.*)(\.cnf\.xml|\.tlv|authorized_keys)(\.enc)?(\.sgn)?)$ /settings/$1 last; + location / { + try_files $uri $uri/ /index.php$is_args$args; + rewrite ^/(.*)$ /index.php?filename=$1 last; + } - # firmware - rewrite ^/((.*).(bin|bin.|loads|LOADS|sbn|SBN|sb2|sbin|zz|zup)(\.sgn)?)$ /firmware/$1 last; - - # locales - rewrite ^/(.*)/((.*)-tones\.xml(\.sgn)?)$ /locales/countries/$1/$2 last; - rewrite ^/(.*)/((.*)(-dictionary(.*)\.xml)(\.sgn)?)$ /locales/languages/$1/$2 last; - rewrite ^/(.*)/((.*)(-kate(.*)\.xml)(\.sgn)?)$ /locales/languages/$1/$2 last; - rewrite ^/(.*)/((.*)(-sccp\.jar)(\.sgn)?)$ /locales/languages/$1/$2 last; - rewrite ^/(.*)/((.*)(-font\.xml)(\.sgn)?)$ /locales/languages/$1/$2 last; - rewrite ^/(.*)/(CIPC_Locale\.(.*))(\.sgn)?)$ /locales/languages/$1/$2 last; - - rewrite ^/(.*)/((.*)(-tones.xml)(\.sgn)?)$ /locales/countries/$1/$2 last; - - # ringtones - rewrite ^/([D|d]istinctive)?([R|r]ing[L|l]ist)\.(xml|XML)(\.sgn)?$ /ringtones/ringlist.xml last; - #rewrite ^/((.*)(\.raw|\.pcm)(\.sgn))?$ /ringtones/$1 last; - - # wallpapers - rewrite ^/Desktops/(.*)/((.*)(\.sgn)?)$ /wallpapers/$1/$2 last; - try_files $uri $uri/ =404; - autoindex off; - } - - # settings - location /settings { - try_files $uri $uri/ =404; - autoindex off; - } - - # firmware - location /firmware { - # 6901 firmware (java-based) - rewrite ^/firmware/(APP6901SCCP.+\.sgn)$ /firmware/6901/$1 last; - rewrite ^/firmware/(KNL6901SCCP.+\.sgn)$ /firmware/6901/$1 last; - rewrite ^/firmware/(SCCP6901.+\.loads)$ /firmware/6901/$1 last; - - # 6911 firmware (java-based) - rewrite ^/firmware/(APP6911SCCP.+\.sgn)$ /firmware/6911/$1 last; - rewrite ^/firmware/(BFS6911SCCP.+\.sgn)$ /firmware/6911/$1 last; - rewrite ^/firmware/(KNL6911SCCP.+\.sgn)$ /firmware/6911/$1 last; - rewrite ^/firmware/(SCCP6911.+\.loads)$ /firmware/6911/$1 last; - - # 6921 firmware (java-based) - rewrite ^/firmware/(BOOT69xx.+\.sgn)$ /firmware/6921/$1 last; - rewrite ^/firmware/(DSP69xx.+\.sgn)$ /firmware/6921/$1 last; - rewrite ^/firmware/(SCCP69xx.+\.loads)$ /firmware/6921/$1 last; - rewrite ^/firmware/(SCCP69xx.+\.sgn)$ /firmware/6921/$1 last; - - # 6945 firmware (java-based) - rewrite ^/firmware/(SCCP6945.+\.sgn)$ /firmware/6945/$1 last; - rewrite ^/firmware/(SCCP6945.+\.loads)$ /firmware/6945/$1 last; - - # 69xx firmware (java-based) - rewrite ^/firmware/(BOOT69xx.+\.sgn)$ /firmware/69xx/$1 last; - rewrite ^/firmware/(DSP69xx.+\.sgn)$ /firmware/69xx/$1 last; - rewrite ^/firmware/(SCCP69xx.+\.loads)$ /firmware/69xx/$1 last; - rewrite ^/firmware/(SCCP69xx.+\.sgn)$ /firmware/69xx/$1 last; - - # 7902 firmware (ancient) - rewrite ^/firmware/(CP7902080002SCCP060817A.sbin)$ /firmware/7902/$1 last; - - # 7905 firmware (ancient) - rewrite ^/firmware/(CP7905080003SCCP070409A.sbin)$ /firmware/7905/$1 last; - rewrite ^/firmware/(CP7905080003SCCP070409A.zup)$ /firmware/7905/$1 last; - - # 7906_7911 firmware (java-based) - rewrite ^/firmware/(apps11.+\.sbn)$ /firmware/7906_7911/$1 last; - rewrite ^/firmware/(cnu11.+\.sbn)$ /firmware/7906_7911/$1 last; - rewrite ^/firmware/(cvm11sccp.+\.sbn)$ /firmware/7906_7911/$1 last; - rewrite ^/firmware/(dsp11.+\.sbn)$ /firmware/7906_7911/$1 last; - rewrite ^/firmware/(jar11sccp.+\.sbn)$ /firmware/7906_7911/$1 last; - rewrite ^/firmware/(SCCP11.+\.loads)$ /firmware/7906_7911/$1 last; - rewrite ^/firmware/(term06.+\.loads)$ /firmware/7906_7911/$1 last; - rewrite ^/firmware/(term11.+\.loads)$ /firmware/7906_7911/$1 last; - - # 7910 firmware (ancient) - rewrite ^/firmware/(P00405000700.bin)$ /firmware/7910/$1 last; - rewrite ^/firmware/(P00405000700.sbn)$ /firmware/7910/$1 last; - - # 7912 firmware (ancient) - rewrite ^/firmware/(CP7912080004SCCP080108A.sbin)$ /firmware/7912/$1 last; - - # 7915 firmware (ancient) - rewrite ^/firmware/(B015-1-0-4.SBN)$ /firmware/7915/$1 last; - - # 7916 firmware (ancient) - rewrite ^/firmware/(B016-1-0-4.SBN)$ /firmware/7916/$1 last; - - # 7920 firmware (ancient) - rewrite ^/firmware/(cmterm_7920.4.0-03-02.bin)$ /firmware/7920/$1 last; - - # 7921_7925 firmware (ancient) - rewrite ^/firmware/(APPS-1.4.3.4.SBN)$ /firmware/7921_7925/$1 last; - rewrite ^/firmware/(CP7921G-1.4.3.4.LOADS)$ /firmware/7921_7925/$1 last; - rewrite ^/firmware/(GUI-1.4.3.4.SBN)$ /firmware/7921_7925/$1 last; - rewrite ^/firmware/(SYS-1.4.3.4.SBN)$ /firmware/7921_7925/$1 last; - rewrite ^/firmware/(TNUX-1.4.3.4.SBN)$ /firmware/7921_7925/$1 last; - rewrite ^/firmware/(TNUXR-1.4.3.4.SBN)$ /firmware/7921_7925/$1 last; - rewrite ^/firmware/(WLAN-1.4.3.4.SBN)$ /firmware/7921_7925/$1 last; - - # 7926 firmware (ancient) - rewrite ^/firmware/(APPSS-1.4.1SR1.SBN)$ /firmware/7926/$1 last; - rewrite ^/firmware/(CP7926G-1.4.1SR1.LOADS)$ /firmware/7926/$1 last; - rewrite ^/firmware/(EA15FW-BF3-220.SBN)$ /firmware/7926/$1 last; - rewrite ^/firmware/(GUIS-1.4.1SR1.SBN)$ /firmware/7926/$1 last; - rewrite ^/firmware/(JSYSS-1.4.1SR1.SBN)$ /firmware/7926/$1 last; - rewrite ^/firmware/(JUIS-1.4.1SR1.SBN)$ /firmware/7926/$1 last; - rewrite ^/firmware/(SYSS-1.4.1SR1.SBN)$ /firmware/7926/$1 last; - rewrite ^/firmware/(TNUXRS-1.4.1SR1.SBN)$ /firmware/7926/$1 last; - rewrite ^/firmware/(TNUXS-1.4.1SR1.SBN)$ /firmware/7926/$1 last; - rewrite ^/firmware/(WLANS-1.4.1SR1.SBN)$ /firmware/7926/$1 last; - - # 7931 firmware (java-based) - rewrite ^/firmware/(apps31.+\.sbn)$ /firmware/7931/$1 last; - rewrite ^/firmware/(cnu31.+\.sbn)$ /firmware/7931/$1 last; - rewrite ^/firmware/(cvm31sccp.+\.sbn)$ /firmware/7931/$1 last; - rewrite ^/firmware/(dsp31.+\.sbn)$ /firmware/7931/$1 last; - rewrite ^/firmware/(jar31sccp.+\.sbn)$ /firmware/7931/$1 last; - rewrite ^/firmware/(SCCP31.+\.loads)$ /firmware/7931/$1 last; - rewrite ^/firmware/(term31.+\.loads)$ /firmware/7931/$1 last; - - # 7935 firmware (ancient) - rewrite ^/firmware/(P00503021900.bin)$ /firmware/7935/$1 last; - - # 7936 firmware (ancient) - rewrite ^/firmware/(cmterm_7936.3-3-21-0.bin)$ /firmware/7936/$1 last; - - # 7937 firmware (ancient) - rewrite ^/firmware/(apps37sccp.1-4-5-7.bin)$ /firmware/7937/$1 last; - - # 7940_7960 firmware (ancient) - rewrite ^/firmware/(P0030801SR.+\.bin)$ /firmware/7940_7960/$1 last; - rewrite ^/firmware/(P0030801SR.+\.loads)$ /firmware/7940_7960/$1 last; - rewrite ^/firmware/(P0030801SR.+\.sb2)$ /firmware/7940_7960/$1 last; - rewrite ^/firmware/(P0030801SR.+\.sbn)$ /firmware/7940_7960/$1 last; - - # 7941_7961 firmware (java-based) - rewrite ^/firmware/(apps41.+\.sbn)$ /firmware/7941_7961/$1 last; - rewrite ^/firmware/(cnu41.+\.sbn)$ /firmware/7941_7961/$1 last; - rewrite ^/firmware/(cvm41sccp.+\.sbn)$ /firmware/7941_7961/$1 last; - rewrite ^/firmware/(dsp41.+\.sbn)$ /firmware/7941_7961/$1 last; - rewrite ^/firmware/(jar41sccp.+\.sbn)$ /firmware/7941_7961/$1 last; - rewrite ^/firmware/(SCCP41.+\.loads)$ /firmware/7941_7961/$1 last; - rewrite ^/firmware/(term41.+\.loads)$ /firmware/7941_7961/$1 last; - rewrite ^/firmware/(term61.+\.loads)$ /firmware/7941_7961/$1 last; - - # 7942_7962 firmware (java-based) - rewrite ^/firmware/(apps42.+\.sbn)$ /firmware/7942_7962/$1 last; - rewrite ^/firmware/(cnu42.+\.sbn)$ /firmware/7942_7962/$1 last; - rewrite ^/firmware/(cvm42sccp.+\.sbn)$ /firmware/7942_7962/$1 last; - rewrite ^/firmware/(dsp42.+\.sbn)$ /firmware/7942_7962/$1 last; - rewrite ^/firmware/(jar42sccp.+\.sbn)$ /firmware/7942_7962/$1 last; - rewrite ^/firmware/(SCCP42.+\.loads)$ /firmware/7942_7962/$1 last; - rewrite ^/firmware/(term42.+\.loads)$ /firmware/7942_7962/$1 last; - rewrite ^/firmware/(term62.+\.loads)$ /firmware/7942_7962/$1 last; - - # 7945_7965 firmware (java-based) - rewrite ^/firmware/(apps45.+\.sbn)$ /firmware/7945_7965/$1 last; - rewrite ^/firmware/(cnu45.+\.sbn)$ /firmware/7945_7965/$1 last; - rewrite ^/firmware/(cvm45sccp.+\.sbn)$ /firmware/7945_7965/$1 last; - rewrite ^/firmware/(dsp45.+\.sbn)$ /firmware/7945_7965/$1 last; - rewrite ^/firmware/(jar45sccp.+\.sbn)$ /firmware/7945_7965/$1 last; - rewrite ^/firmware/(SCCP45.+\.loads)$ /firmware/7945_7965/$1 last; - rewrite ^/firmware/(term45.+\.loads)$ /firmware/7945_7965/$1 last; - rewrite ^/firmware/(term65.+\.loads)$ /firmware/7945_7965/$1 last; - - # 7970_7971 firmware (java-based) - rewrite ^/firmware/(apps70.+\.sbn)$ /firmware/7970_7971/$1 last; - rewrite ^/firmware/(cnu70.+\.sbn)$ /firmware/7970_7971/$1 last; - rewrite ^/firmware/(cvm70sccp.+\.sbn)$ /firmware/7970_7971/$1 last; - rewrite ^/firmware/(dsp70.+\.sbn)$ /firmware/7970_7971/$1 last; - rewrite ^/firmware/(jar70sccp.+\.sbn)$ /firmware/7970_7971/$1 last; - rewrite ^/firmware/(SCCP70.+\.loads)$ /firmware/7970_7971/$1 last; - rewrite ^/firmware/(term70.+\.loads)$ /firmware/7970_7971/$1 last; - rewrite ^/firmware/(term71.+\.loads)$ /firmware/7970_7971/$1 last; - - # 7975 firmware (java-based) - rewrite ^/firmware/(apps75.+\.sbn)$ /firmware/7975/$1 last; - rewrite ^/firmware/(cnu75.+\.sbn)$ /firmware/7975/$1 last; - rewrite ^/firmware/(cvm75sccp.+\.sbn)$ /firmware/7975/$1 last; - rewrite ^/firmware/(dsp75.+\.sbn)$ /firmware/7975/$1 last; - rewrite ^/firmware/(jar75sccp.+\.sbn)$ /firmware/7975/$1 last; - rewrite ^/firmware/(SCCP75.+\.loads)$ /firmware/7975/$1 last; - rewrite ^/firmware/(term75.+\.loads)$ /firmware/7975/$1 last; - - # 7985 firmware (ancient) - rewrite ^/firmware/(cmterm_7985.4-1-7-0.bin)$ /firmware/7985/$1 last; - - # 894x firmware (java-based) - rewrite ^/firmware/(BOOT894x.+\.sgn)$ /firmware/894x/$1 last; - rewrite ^/firmware/(SCCP894x.+\.sgn)$ /firmware/894x/$1 last; - rewrite ^/firmware/(SCCP894x.+\.loads)$ /firmware/894x/$1 last; - - # ata186 firmware (ancient) - rewrite ^/firmware/(ATA030204SCCP090202A.zup)$ /firmware/ata186/$1 last; - - # ata188 firmware (ancient) - rewrite ^/firmware/(ATA030204SCCP090202A.zup)$ /firmware/ata188/$1 last; - - # SPA50x - rewrite ^/firmware/(spa50x.+\.bin)$ /firmware/spa50x/$1 last; - rewrite ^/firmware/(spa51x.+\.bin)$ /firmware/spa51x/$1 last; - rewrite ^/firmware/(spa515.+\.bin)$ /firmware/spa525/$1 last; - rewrite ^/firmware/(spa941.+\.bin)$ /firmware/spa941/$1 last; - - try_files $uri $uri/ =404; - autoindex off; - } - - # locales - - location /locales { - try_files $uri $uri/ =404; - autoindex off; - } - - # ringtones - location /ringtones { - try_files $uri $uri/ =404; - autoindex off; - } - - # wallpapers - location /wallpapers { - try_files $uri $uri/ =404; - autoindex off; - } - - # Deny access to .htaccess - location ~ /\.ht { - deny all; - } - - error_page 404 /; - - error_page 500 502 503 504 /50x.html; - location = /50x.html { - root /usr/share/nginx/html; - } + error_page 404 /; + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } } diff --git a/lib/config.php b/lib/config.php new file mode 100644 index 0000000..0106c13 --- /dev/null +++ b/lib/config.php @@ -0,0 +1,80 @@ + Array( + 'debug' => 1, + 'default_language' => 'English_United_States', + 'log_type' => "NULL", + 'log_level' => LOG_EMERG + ), + 'subdirs' => Array( + 'tftproot' => 'tftpboot', + 'firmware' => 'firmware', + 'settings' => 'settings', + 'wallpapers' => 'wallpapers', + 'ringtones' => 'ringtones', + 'locales' => 'locales', + 'countries' => 'countries', + 'languages' => 'languages', + ) +); +$tree_base = Array( + 'settings' => array('path' => 'tftproot', "strip" => TRUE), + 'wallpapers' => array('path' => 'tftproot', "strip" => FALSE), + 'ringtones' => array('path' => 'tftproot', "strip" => TRUE), + 'locales' => array('path' => 'tftproot', "strip" => TRUE), + 'firmware' => array('path' => 'tftproot', "strip" => TRUE), + 'languages' => array('path' => 'locales', "strip" => FALSE), + 'countries' => array('path' => 'locales', "strip" => FALSE), + 'default_language' => array('path' => 'locales', "strip" => TRUE), +); + +# Merge config +$ini_array = parse_ini_file('../config.ini', TRUE, INI_SCANNER_TYPED); +if (!empty($ini_array)) { + $config = array_merge($base_config, $ini_array); +} + +# build new config['subdirs'] paths substituting bases from tree_base +foreach ($tree_base as $key => $value) { + $tmp = $config; + if (!empty($tmp['subdirs'][$key])) { + if (substr($tmp['subdirs'][$key], 0, 1) !== "/") { + if (is_array($tmp['subdirs'][$value['path']])) { + $path = $tmp['subdirs'][$value['path']]['path'].'/'.$tmp['subdirs'][$key]; + } else { + $path = $tmp['subdirs'][$value['path']].'/'.$tmp['subdirs'][$key]; + } + } + $config['subdirs'][$key] = array('path' => $path, 'strip' => $value['strip']); + } +} + +$config['main']['base_path'] = $base_path; +$config['main']['tftproot'] = (!empty($config['main']['tftproot'])) ? $base_path . "tftpboot" : '/tftpboot'; + +switch($config['main']['log_type']) { + case 'SYSLOG': + $logger = new Logger_Syslog($config['main']['log_level']); + break; + case 'FILE': + if (!isempty($config['main']['log_file'])) { + $logger = new Logger_Filename($config['main']['log_level'], $config['main']['log_file']); + } + break; + case 'STDOUT': + $logger = new Logger_Stdout($config['main']['log_level']); + break; + case 'STDERR': + $logger = new Logger_Stderr($config['main']['log_level']); + break; + default: + $logger = new Logger_Null($config['main']['log_level']); +} + +# Fixup debug +$print_debug = (!empty($config['main']['debug'])) ? $config['main']['debug'] : 'off'; +$print_debug = ($print_debug == 1) ? 'on' : $print_debug; +?> diff --git a/lib/logger.php b/lib/logger.php new file mode 100644 index 0000000..249d121 --- /dev/null +++ b/lib/logger.php @@ -0,0 +1,94 @@ +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); + } +} +?> \ No newline at end of file diff --git a/lib/resolver.php b/lib/resolver.php new file mode 100644 index 0000000..579b10b --- /dev/null +++ b/lib/resolver.php @@ -0,0 +1,168 @@ +config = $config; + //$this->logger = $logger; + if(file_exists($this->config['main']['cache_filename'])) { + $this->cache = unserialize(file_get_contents($config['main']['cache_filename'])); + } else { + $this->buildCleanCache(); + } + } + function __destruct() { + // $this->printCache() + if ($this->isDirty) { + if (!file_put_contents($this->config['main']['cache_filename'], serialize($this->cache))) { + $this->log_error_and_throw("Could not write to file '".$this->config['cache_filename']."' at Resolver::destruct"); + } + } + } + function log_error_and_throw($message) { + global $logger; + $logger->log('LOG_ERROR', $message); + throw new Exception($message); + } + function log_debug($message) { + global $logger; + $logger->log('LOG_DEBUG', $message); + } + function searchForFile($filename) { + foreach($this->config['subdirs'] as $key => $value) { + if ($key === "firmware" || $key === "tftproot" ) { + continue; + } + $path = realpath($this->config['main']['base_path'] . "/" . $value['path'] . "/$filename"); + if (file_exists($path)) { + $this-> addFile($filename, $path); + return $path; + } + } + $this->log_error_and_throw("File '$filename' does not exist"); + } + function buildCleanCache() { + foreach($this->config['subdirs'] as $key =>$value) { + if ($key === "tftproot") { + continue; + } + $path = $this->config['main']['base_path'] . "/" . $value['path'] . "/"; + $dir_iterator = new RecursiveDirectoryIterator($path); + $iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST); + foreach ($iterator as $file) { + if ($file->isFile()) { + if ($value['strip']) { + $this->addFile($file->getFileName(), $file->getPathname()); + } else { + $subdir = basename(dirname($file->getPathname())); + $this->addFile('$subpath/'.$file->getFileName(), $file->getPathname()); + } + } + } + } + $this->isDirty = TRUE; + } + function addFile($requestpath, $truepath) { + //$this->logger->log('LOG_DEBUG', "Adding $requestpath"); + $this->log_debug("Adding $requestpath"); + $this->cache[$requestpath] = $truepath; + $this->isDirty =TRUE; + } + function removeFile($requestpath) { + $this->log_debug("Removing $hash"); + unset($this->cache[$requestpath]); + $this->isDirty = TRUE; + } + function validateRequest($request) { + /* make sure request does not startwith or contain: "/", "../" or "/./" */ + /* make sure request only starts with filename or one of $config[$subdir]['locale'] or $config[$subdir]['wallpaper'] */ + /* check uri/url decode */ + if (!is_string($request)) { + $this->log_error_and_throw("Request is not a string"); + } + $this->log_debug($request . ":" . escapeshellarg($request) . ":" . utf8_urldecode($request) . "\n"); + $escaped_request = escapeshellarg(utf8_urldecode($request)); + if ($escaped_request !== "'" . $request . "'") { + $this->log_error_and_throw("Request '$request' contains invalid characters"); + } + if (strstr($escaped_request, "..")) { + $this->log_error_and_throw("Request '$request' containst '..'"); + } + } + function resolve($request) /* canthrow */ { + $this->validateRequest($request); + $path = ''; + if (array_key_exists($request, $this->cache)) { + if ($path = $this->cache[$request]) { + if (!file_exists($path)) { + $this->removeFile($request); + $this->log_error_and_throw("File '$request' does not exist on FS"); + } + return $path; + } + } + if ($this->searchForFile($request)) { + return $this->cache[$request]; + } + return $path; + } + /* temporary */ + function printCache() { + print_r($this->cache); + } +} + +// Testing +if(defined('STDIN') ) { + $resolver = new Resolver($config); + + $test_cases = Array( + Array('request' => 'jar70sccp.9-4-2ES26.sbn', 'expected' => '/tftpboot/firmware/7970/jar70sccp.9-4-2ES26.sbn', 'throws' => FALSE), + Array('request' => 'Russian_Russian_Federation/be-sccp.jar', 'expected' => '/tftpboot/locales/languages/Russian_Russian_Federation/be-sccp.jar', 'throws' => FALSE), + Array('request' => 'Spain/g3-tones.xml', 'expected' => '/tftpboot/locales/countries/Spain/g3-tones.xml', 'throws' => FALSE), + Array('request' => '320x196x4/Chan-SCCP-b.png', 'expected' => '/tftpboot/wallpapers/320x196x4/Chan-SCCP-b.png', 'throws' => FALSE), + Array('request' => 'XMLDefault.cnf.xml', 'expected' => '/tftpboot/settings/bak/XMLDefault.cnf.xml', 'throws' => FALSE), + Array('request' => '../XMLDefault.cnf.xml', 'expected' => '', 'throws' => TRUE), + Array('request' => 'XMLDefault.cnf.xml/../../text.xml', 'expected' => '', 'throws' => TRUE), + + ); + foreach($test_cases as $test) { + try { + $result = $resolver->resolve($test['request']); + if ($result !== $base_path . $test['expected']) { + print("Error: expected result does not match what we got\n"); + print("request:'".$test['request']."', result:'" . $base_path . $test['expected'] . "'\n"); + } else { + print("'" . $test['request'] . "' => '" . $result . "'\n"); + } + } catch (Exception $e) { + if (!$test['throws']) { + print("Error: request was expected to throw: $e\n"); + } else { + print("'" . $test['request'] . "' => throws error as expected\n"); + } + } + } + unset($resolver); + #unlink($CACHEFILE_NAME); +} +?> diff --git a/lib/utils.php b/lib/utils.php new file mode 100644 index 0000000..28e7652 --- /dev/null +++ b/lib/utils.php @@ -0,0 +1,10 @@ + diff --git a/tftpboot/index.cnf b/tftpboot/index.cnf deleted file mode 100644 index 9ec78d3..0000000 --- a/tftpboot/index.cnf +++ /dev/null @@ -1,13 +0,0 @@ -[main] -debug = on ; The output in the browser window for more information -tftproot = /tftpboot -;default_language = English_United_States - -firmware = firmware -settings = settings -wallpapers = wallpapers -ringtones = ringtones -locales = locales -countries = countries -languages = languages -;log = /tftpboot/provision.log diff --git a/tftpboot/index.php b/tftpboot/index.php index 495d0ce..c7024b3 100644 --- a/tftpboot/index.php +++ b/tftpboot/index.php @@ -1,308 +1,67 @@ 1, - 'tftproot' => $base_path, - 'default_language' => 'English_United_States', - 'firmware' => 'firmware', 'settings' => 'settings', 'wallpapers' => 'wallpapers', 'ringtones' => 'ringtones', - 'locales' => 'locales', 'countries' => 'countries', 'languages' => 'languages' -); -$base_tree = Array('settings' => 'tftproot', 'wallpapers' => 'tftproot', 'ringtones'=>'tftproot', - 'locales' => 'tftproot', 'firmware' => 'tftproot', 'languages' => 'locales', - 'countries' => 'locales', 'default_language' => 'locales'); - -# Merge config -$ini_array = parse_ini_file('index.cnf'); -if (!empty($ini_array)) { - $config = array_merge($base_config, $ini_array); +function send_fallback_html($message) { + while (ob_get_level()) {ob_end_clean();} + if (ob_get_length() === false) { + ob_start(); + header('Content-Description: README'); + header('Content-Type: text/html'); + header('Expires: 0'); + header('Cache-Control: must-revalidate'); + header('Pragma: public'); + } + $content=" + +
+
+ +

provision_sccp

+

Request:" . json_encode($request) . "

+

Message:" . $message . "

+ + + "; + print ($content); + ob_flush(); + flush(); } -foreach ($base_tree as $key => $value) { - if (!empty($config[$key])) { - if (substr($config[$key],0,1) != "/") { - $config[$key] = $config[$value].'/'.$config[$key]; - } - } +function sendfile($file) { + if (file_exists($file)) { + while (ob_get_level()) {ob_end_clean();} + header('Content-Description: File Transfer'); + header('Content-Type: application/octet-stream'); + header('Content-Disposition: attachment; filename=' . basename($file)); + header('Content-Transfer-Encoding: binary'); + header('Expires: 0'); + header('Cache-Control: must-revalidate'); + header('Pragma: public'); + header('Content-Length: ' . filesize($file)); + + /* want to stream out, so don't use file_get_contents() in this case */ + if ($fd = fopen($file, 'rb')) { + while (!feof($fd)) { + print fread($fd, 1024); + } + fclose($fd); + } + } } - -#$config['tftproot'] = (!empty($config['tftproot'])) ? $config['tftproot'] : '/tftpboot'; - -# Fixup debug -$print_debug = (!empty($config['debug'])) ? $config['debug'] : 'off'; -$print_debug = ($print_debug == 1) ? 'on' : $print_debug; - -# Parse request -$request = $_REQUEST; -$req_file = !empty($request['id']) ? $request['id'] : ''; - -# directory content extensions map -$fw_suffix = array('.bin', '.loads', '.sbn', '.sb2', '.sbin', '.zz', '.zup', '.loads'); - -//$settings_suffix = array('cnf.xml'); - -$ringtones_list = array('distinctive.xml', 'ringlist.xml','distinctiveringlist.xml'); -$ringtones_suffix = array('.raw', '.pcm', '.rwb'); - -$locale_list = array('-dictionary.', 'dictionary-ext.', '-dictionary.utf-8.', '-kate.xml', '-font.xml', '-font.dat','-tones.xml', - 'be-sccp.jar', 'tc-sccp.jar', 'td-sccp.jar', 'ipc-sccp.jar', 'mk-sccp.jar', '_locale.loads', 'i-button-help.xml', - 'tc-sip.jar', 'td-sipp.jar'); - -# Show debug output -if ($print_debug == 'on') { - print_r("
Config:
");
-    print_r($config);
-    print("
"); - print_r("
Request:
");
-    print_r($request);
-    print("
"); +if (!$request || empty($request) || !array_key_exists('filename',$request) || empty($request['filename'])) { + send_fallback_html("Empty request sent"); + exit(); } - -# Start parsing the request -$req_file_full_path = '' ; - -if (!empty($req_file)) { - $signed = FALSE; - $req_data_ar = explode('/', $req_file); - $req_data_len = count($req_data_ar) - 1; - - $orig_req_file_name = end($req_data_ar); - $req_file_name = $orig_req_file_name; - - if (strpos('.sgn;', strtolower($orig_req_file_name).';') !== FALSE) { // handle signed files - $signed = TRUE; - $req_file_name = basename($orig_req_file_name, '.sgn'); // strip signed part - } - - - if (file_exists($config['tftproot'].'/'.$req_file_name)) // prevent "/../...//" browsing - (eliminate back door) - { - $req_file_full_path = $config['tftproot'].'/'.$req_file_name; - } - else - { - $tmp_file = explode('.', $req_file_name); - - if (strpos_array($req_file_name, $fw_suffix,'any') !== FALSE) { // Firmware file was requested - $firmware_list = find_all_files($config['firmware']); - $pos2 = strpos_array($firmware_list, $req_file_name, 'any'); // case unsensitive - if ($pos2 !== FALSE) { // Request Firmware - $req_file_full_path = $firmware_list[$pos2]; - } - if ($print_debug == 'on'){ print_r('
Requested Firmware: '. $req_file_full_path. '
');} - } - else - { - $tmp_file = ''; - - //if (strpos_array($req_file_name, $settings_suffix, 'any') !== FALSE) { // Request Settings - if (strpos(strtolower($req_file_name), '.cnf.xml') !== FALSE) { // Request Settings - $tmp_file = $config['settings'].'/'.$req_file_name; - } - else if (strpos(strtolower($req_file), 'desktops/') !== FALSE) { // Request Wallpapers - $tmp_file = $config['wallpapers'].'/'. $req_data_ar[$req_data_len-1].'/'. $req_file_name; - } - else if (strpos_array($ringtones_list, $req_file_name, 'any') !== FALSE) { // Request RingTones - $tmp_file = $config['ringtones'].'/'.$req_file_name; - if (!file_exists($tmp_file)) { - $tmp_file = $config['ringtones'].'/ringlist.xml'; - } - } - else if(strpos_array($req_file_name, $ringtones_suffix,'any') !== FALSE) { // Firmware file was requested - $tmp_file = $config['ringtones'].'/'.$req_file_name; - } - else if (strpos_array($req_file, $locale_list, 'any') !== FALSE) { // Request Languages - if (!empty($req_data_ar[$req_data_len-1])) { - $tmp_file = $config['languages'].'/'. $req_data_ar[$req_data_len-1].'/'. $req_file_name; - } else { - $tmp_file = $config['default_language'].'/'. $req_file_name; - } - } - -/* - else if (strpos(strtolower($req_file), '-tones.xml') !== FALSE) { // Request Countries - $tmp_file = $config['countries'].'/'. $req_data_ar[$req_data_len-1].'/'. $req_data_ar[$req_data_len]; - } - - else if (strpos(strtolower($req_file), '-dictionary.') !== FALSE) { // Request Countries - $tmp_file = $config['languages'].'/'. $req_data_ar[$req_data_len-1].'/'. $req_data_ar[$req_data_len]; - } - - else if (strpos_array($req_file, $locale_list, 'any') !== FALSE) { // Request Languages - $tmp_file = $config['languages'].'/'. $req_data_ar[$req_data_len-1].'/'. $req_data_ar[$req_data_len]; - } - - else if (strpos(strtolower($req_file), '-dictionary.jar') !== FALSE) { // Request Countries - $tmp_file = $config['languages'].'/'. $req_data_ar[$req_data_len-1].'/'. $req_data_ar[$req_data_len]; - } -*/ - if ($print_debug == 'on'){ print_r('
File : '. $orig_req_file_name. ' not found.
');} - if (empty($tmp_file)) { - if (!empty($config['log'])) { to_log(array('GET ('.$req_file.'):'.$orig_req_file_name, 'no match found'),'E',$config['log']); } - header("HTTP/1.0 404 Not Found"); - die('ERROR: no match found.'); - } - $req_file_full_path = $tmp_file; - } - } - if (!empty($config['log'])) { to_log(array('GET ('.$req_file.') :'.$orig_req_file_name, 'Remap :'.$req_file_full_path),'i',$config['log']); } - - if (!empty($req_file_full_path)) { - if ($signed) { - $req_file_full_path .= '.sgn'; - } - if (!file_exists($req_file_full_path)) { - header("HTTP/1.0 404 Not Found"); - die('Could not find:'. $req_file_full_path); - } - if ($print_debug == 'on'){ print_r('
Returning: '. $req_file_full_path. '
');} - file_force_download($req_file_full_path); - } -} - -/* - * Helper functiosn - */ -function file_force_download($file) { - if (file_exists($file)) { - - if (ob_get_level()) { - ob_end_clean(); - } - - header('Content-Description: File Transfer'); - header('Content-Type: application/octet-stream'); - header('Content-Disposition: attachment; filename=' . basename($file)); - header('Content-Transfer-Encoding: binary'); - header('Expires: 0'); - header('Cache-Control: must-revalidate'); - header('Pragma: public'); - header('Content-Length: ' . filesize($file)); - - if ($fd = fopen($file, 'rb')) { - while (!feof($fd)) { - print fread($fd, 1024); - } - fclose($fd); - } - exit; - } +try { + $req_filename=$request['filename']; + $resolver = new Resolver($config); + if (($filename = $resolver->resolve($req_filename))) { + sendfile($filename); + } + unset($resolver); +} catch(Exception $e) { + send_fallback_html($e->getMessage()); } - -/* - * Founds any string from array in array - */ -function strpos_array($haystack, $needles, $mode='any') { - if (is_array($needles)) { - foreach ($needles as $str) { - $pos = strpos_array($haystack, $str, $mode); - if ($pos !== FALSE) { - return $pos; - } - } - } else { - if (is_array($haystack)) { - foreach ($haystack as $key => $subtr) { - $pos = strpos_array($subtr, $needles, $mode); - if ($pos !== FALSE) { - return $key; - } - } - return FALSE; - } else { - if ($mode == 'any') { - return strpos(strtolower($haystack), strtolower($needles)); - } else { - if ($mode == 'full') { - if ($haystack == $needles) { - return 0; - } else { - return FALSE; - } - } else { - return strpos($haystack, $needles); - } - - } - } - } - return FALSE; -} - -function to_log($text, $level='i', $file) { - switch (strtolower($level)) { - case 'e': - case 'error': - $level='ERROR'; - break; - case 'i': - case 'info': - $level='INFO'; - break; - case 'd': - case 'debug': - $level='DEBUG'; - break; - default: - $level='INFO'; - } - if (is_array($text)) { - $to_log = ''; - foreach ($text as $value) { - $to_log .= $value."\t"; - } - } else { - $to_log .= $text; - } - $_txt = date('d.m.Y h:i:s')."\t[".$level."]\t ".$to_log."\n"; - if (empty($file)) { - error_log($_txt, 0); - } else { - error_log($_txt, 3, $file); - } -} - -function find_all_files($dir, $file_mask=null, $mode='full'){ - - $result = NULL; - if (empty($dir) || (!file_exists($dir))) { - return $result; - } - - $root = scandir($dir); - foreach($root as $value) { - if($value === '.' || $value === '..') {continue;} - if(is_file("$dir/$value")) { - $filter = FALSE; - if (!empty($file_mask)) { - if (is_array($file_mask)) { - foreach ($file_mask as $k){ - if (strpos(strtolower($value), strtolower($k)) !== FALSE) {$filter = true;} - } - } else { - if (strpos(strtolower($value), strtolower($file_mask)) !== FALSE) {$filter = true;} - } - } else {$filter = true;} - if ($filter) { - if ($mode=='fileonly'){ - $result[]="$value"; - } else { - $result[]="$dir/$value"; - } - } else {$result[]=null;} - continue; - } - $sub_fiend = find_all_files("$dir/$value", $file_mask, $mode); - if (!empty($sub_fiend)) { - foreach($sub_fiend as $sub_value) { - if (!empty($sub_value)) { - $result[]=$sub_value; - } - } - } - } - return $result; -} +?> \ No newline at end of file diff --git a/tftpboot/ringtones/mkringlist.sh b/tftpboot/ringtones/mkringlist.sh index 598ce26..3403e45 100755 --- a/tftpboot/ringtones/mkringlist.sh +++ b/tftpboot/ringtones/mkringlist.sh @@ -6,7 +6,7 @@ if [ ! -z "`ls *.pcm 2>/dev/null`" ]; then basename=`basename ${filename} .pcm` echo -e "\t" >>$outfile echo -e "\t\t${basename}" >>$outfile - echo -e "\t\tringtones\${filename}" >>$outfile + echo -e "\t\tringtones\\${filename}" >>$outfile echo -e "\t" >>$outfile done fi @@ -15,7 +15,7 @@ if [ ! -z "`ls *.raw 2>/dev/null`" ]; then basename=`basename ${filename} .raw` echo -e "\t" >>$outfile echo -e "\t\t${basename}" >>$outfile - echo -e "\t\tringtones\${filename}" >>$outfile + echo -e "\t\tringtones\\${filename}" >>$outfile echo -e "\t" >>$outfile done fi