Compare commits
16 Commits
feature/re
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
152d8d8777 | ||
|
6e28b501e9 | ||
|
6e5cfaa3eb | ||
|
9fc70cdbca | ||
|
9ed891b130 | ||
|
09b259c85e | ||
|
b214fee18a | ||
|
a0c5cda9d3 | ||
|
6aaf4327cd | ||
|
8f300559e1 | ||
|
a096463b5f | ||
|
6dd47d03ab | ||
|
9e7cb0eb8d | ||
|
a34b53249b | ||
|
d3e2889b24 | ||
|
06922fc679 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +0,0 @@
|
||||
tests/ export-ignore
|
13
.gitignore
vendored
13
.gitignore
vendored
@@ -2,17 +2,6 @@
|
||||
env/
|
||||
*~
|
||||
*.bak
|
||||
*.enc
|
||||
*.sgn
|
||||
.requirements_satisfied
|
||||
etc/nginx/site-available/nginx.rules
|
||||
etc/tftpd-hpa/tftpd.rules
|
||||
etc/certs/*.pem
|
||||
data/settings/*.cnf.xml
|
||||
data/settings/*.tlv
|
||||
data/settings/authorized_keys
|
||||
data/settings/*.jar
|
||||
data/settings/*.json
|
||||
vendor/
|
||||
bak/
|
||||
build/
|
||||
.requirements_satisfied
|
||||
|
25
Makefile
Normal file
25
Makefile
Normal file
@@ -0,0 +1,25 @@
|
||||
SHELL := /usr/bin/env bash
|
||||
PIP := /usr/bin/env pip
|
||||
PYTHON := /usr/bin/env python
|
||||
|
||||
.PHONY: bootstrap clean
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
all:
|
||||
|
||||
bootstrap: .requirements_satisfied tools/generate.py
|
||||
@echo "running generate"
|
||||
@$(PYTHON) tools/generate.py
|
||||
|
||||
.requirements_satisfied: tools/requirements.txt
|
||||
@echo "checking requirements"
|
||||
@$(PIP) install --user -r tools/requirements.txt
|
||||
@touch $@
|
||||
|
||||
clean:
|
||||
@find . -type f -name '*.pyc' -delete
|
||||
@find . -type f -name '*~' -delete
|
||||
@find . -type f -name '*.bak' -delete
|
||||
@find . -type f -name '.requirements_satisfied' -delete
|
||||
# @find . -type f -name 'etc/tftpd-hpa/rewrite.rules' -delete
|
||||
# @find . -type f -name 'etc/nginx/site-available/tftpboot' -delete
|
@@ -10,11 +10,6 @@ The project also serves as a repository of current / up to date cisco skinny/scc
|
||||
- [tftp-hpa](http://www.chschneider.eu/linux/server/tftpd-hpa.shtml)
|
||||
- [nginx](https://www.nginx.com/resources/wiki/)
|
||||
|
||||
## PHP Dependencies
|
||||
- php >= 7.x
|
||||
- php-cli
|
||||
- php-xml
|
||||
|
||||
## Usage
|
||||
- Clone the repository
|
||||
- Move the tftpboot directory (depends on your operating system):
|
||||
|
36
build.xml
36
build.xml
@@ -1,36 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- phing build file -->
|
||||
<project
|
||||
name="provision_sccp"
|
||||
default="build"
|
||||
basedir="."
|
||||
description="SCCP/Skinny Provisioner">
|
||||
|
||||
<target name="install">
|
||||
<exec command="./composer.phar install" checkreturn="true" passthru="true"/>
|
||||
<exec command="./composer.phar update" checkreturn="true" passthru="true"/>
|
||||
</target>
|
||||
|
||||
<target name="clean">
|
||||
<delete dir="build"/>
|
||||
</target>
|
||||
|
||||
<target name="prepare">
|
||||
<mkdir dir="build" mode="0755"/>
|
||||
</target>
|
||||
|
||||
<target name="fixstyle">
|
||||
<exec command="phpcbf --tab-width=4 --standard=PSR2 src test"
|
||||
checkreturn="true"
|
||||
passthru="false"/>
|
||||
</target>
|
||||
|
||||
<target name="test">
|
||||
<exec command="vendor/phpunit/phpunit/phpunit -v --debug tests"
|
||||
checkreturn="true"
|
||||
passthru="true"/>
|
||||
</target>
|
||||
|
||||
<target name="build" depends="clean, prepare, test"/>
|
||||
|
||||
</project>
|
@@ -1,46 +0,0 @@
|
||||
{
|
||||
"name": "chan-sccp/provisioner",
|
||||
"type": "library",
|
||||
"description": "SCCP/Skinny Provisioner",
|
||||
"keywords": ["sccp","skinny","sip","cisco","tftp","http","chan-sccp"],
|
||||
"homepage": "http://github.com/dkgroot/provision_sccp",
|
||||
"license": "Apache-2.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Diederik de Groot",
|
||||
"email": "ddegroot@talon.nl",
|
||||
"homepage": "http://github.com/chan-sccp/",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Marcello Ceschia",
|
||||
"email": "marcello@ceschia.de",
|
||||
"homepage": "https://github.com/marcelloceschia/",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/dkgroot/provision_sccp/issues",
|
||||
"wiki": "https://github.com/dkgroot/provision_sccp/wiki",
|
||||
"source": "https://github.com/dkgroot/provision_sccp"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PROVISION\\": "lib/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6.0",
|
||||
"psr/log": ">= 1.0.0",
|
||||
"myclabs/php-enum": ">= 1.7.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"phing/phing": "*",
|
||||
"phpunit/phpunit": "*",
|
||||
"codeclimate/php-test-reporter": "*",
|
||||
"php-coveralls/php-coveralls": "*",
|
||||
"phpmd/phpmd": ">=2.5.0",
|
||||
"squizlabs/php_codesniffer": ">=3.4.0",
|
||||
"sebastian/phpcpd": "*"
|
||||
}
|
||||
}
|
67
config.ini
67
config.ini
@@ -1,67 +0,0 @@
|
||||
[main]
|
||||
debug = TRUE ; 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
|
||||
auto_generate_settings = FALSE
|
||||
auto_sign = FALSE
|
||||
auto_encrypt = FALSE
|
||||
localnet = 192.168.178.0/24
|
||||
|
||||
[config]
|
||||
file = /etc/asterisk/sccp.conf
|
||||
database = asterisk
|
||||
database_driver = postgres
|
||||
|
||||
[security]
|
||||
cert_ca = NULL
|
||||
cert_priv = NULL
|
||||
cert_pub = NULL
|
||||
hash = NULL
|
||||
|
||||
;[subdirs]
|
||||
;tftproot = data
|
||||
;firmware = firmware
|
||||
;settings = settings
|
||||
;wallpapers = wallpapers
|
||||
;ringtones = ringtones
|
||||
;locales = locales
|
||||
;countries = countries
|
||||
;languages = languages
|
||||
|
||||
[settings]
|
||||
sshUserId = cisco
|
||||
sshPassword = cisco
|
||||
ipAddress = ipv4|ipv6 ; ipv4 | ipv4 | ipv4|ipv6 | ipv6|ipv4
|
||||
datetime.template = M/D/YA
|
||||
datetime.timezone = W. Europe Standard/Daylight Time
|
||||
datetime.ipaddress = 10.x.x.x
|
||||
datetime.mode = Unicast
|
||||
members.myhost.hostname = myhost.domain.com
|
||||
members.myhost.ipv4 = 10.x.x.x
|
||||
members.myhost.ipv6 = 2001:470::x:x
|
||||
members.myhost.port = 2000
|
||||
;srts.
|
||||
;common.
|
||||
;vendor.
|
||||
locale.country = United_States
|
||||
locale.language = English_United_States
|
||||
locale.langcode = en_US
|
||||
locale.charset = utf-8
|
||||
urls.security = FALSE
|
||||
urls.information = NULL
|
||||
urls.authentication = NULL
|
||||
urls.services = NULL
|
||||
urls.direcory = NULL
|
||||
urls.messages = NULL
|
||||
urls.proxyserver = NULL
|
||||
;vpn.
|
||||
;phoneservices.
|
||||
|
||||
[SEP001122334455]
|
||||
locale.country = Netherlands
|
||||
locale.language = Dutch Netherlands
|
||||
locale.langcode = nl_NL
|
||||
locale.charset = utf-8
|
@@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
outfile=Ringlist.xml
|
||||
echo -e "<CiscoIPPhoneRingList>" >$outfile
|
||||
for filename in *.pcm *.raw; do
|
||||
if [ -f $filename ]; then
|
||||
echo -e "\t<Ring>" >>$outfile
|
||||
echo -e "\t\t<DisplayName>${filename%.*}</DisplayName>" >>$outfile
|
||||
echo -e "\t\t<FileName>${filename}</FileName>" >>$outfile
|
||||
echo -e "\t</Ring>" >>$outfile
|
||||
fi
|
||||
done
|
||||
echo -e "</CiscoIPPhoneRingList>" >>$outfile
|
||||
[ -f DistinctiveRinglist.xml ] || ln -s Ringlist.xml DistinctiveRinglist.xml
|
||||
[ -f distinctiveringlist.xml ] || ln -s Ringlist.xml distinctiveringlist.xml
|
||||
[ -f ringlist.xml ] || ln -s Ringlist.xml ringlist.xml
|
||||
for x in *.pcm *.xml *.raw; do
|
||||
[ -f $x ] && ../../etc/certs/signfile $x
|
||||
done
|
@@ -1,62 +0,0 @@
|
||||
<CiscoIPPhoneRingList>
|
||||
<Ring>
|
||||
<DisplayName>drums1</DisplayName>
|
||||
<FileName>drums1.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>drums2</DisplayName>
|
||||
<FileName>drums2.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>loudc1</DisplayName>
|
||||
<FileName>loudc1.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>loudc2</DisplayName>
|
||||
<FileName>loudc2.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>loudlaser</DisplayName>
|
||||
<FileName>loudlaser.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>merlin2</DisplayName>
|
||||
<FileName>merlin2.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>merlin3</DisplayName>
|
||||
<FileName>merlin3.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>merlin4</DisplayName>
|
||||
<FileName>merlin4.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>merlin5</DisplayName>
|
||||
<FileName>merlin5.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>merlin6</DisplayName>
|
||||
<FileName>merlin6.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>merlin7</DisplayName>
|
||||
<FileName>merlin7.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>ringer1</DisplayName>
|
||||
<FileName>ringer1.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>ringer2</DisplayName>
|
||||
<FileName>ringer2.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>ringer3</DisplayName>
|
||||
<FileName>ringer3.pcm</FileName>
|
||||
</Ring>
|
||||
<Ring>
|
||||
<DisplayName>ringer4</DisplayName>
|
||||
<FileName>ringer4.pcm</FileName>
|
||||
</Ring>
|
||||
</CiscoIPPhoneRingList>
|
@@ -1,21 +1,29 @@
|
||||
Listen 6970
|
||||
<VirtualHost *:6970>
|
||||
DocumentRoot "/srv/web"
|
||||
DocumentRoot "/tftpboot"
|
||||
ErrorLog /var/log/httpd/tftp.error.log
|
||||
CustomLog /var/log/httpd/tftp.access.log combined
|
||||
|
||||
<Directory />
|
||||
<Directory /tftpboot>
|
||||
Options FollowSymlinks
|
||||
AllowOverride none
|
||||
Require all granted
|
||||
RewriteEngine on
|
||||
RewriteBase "/"
|
||||
RewriteCond "/%{REQUEST_FILENAME}" !-f
|
||||
RewriteCond "/%{REQUEST_FILENAME}" !-d
|
||||
RewriteRule "(.*)" "index.php?filename=$1" [PT,QSA]
|
||||
RewriteCond "/tftpboot/%{REQUEST_FILENAME}" !-f
|
||||
RewriteCond "/tftpboot/%{REQUEST_FILENAME}" !-d
|
||||
RewriteRule "(.*)" "index.php?id=$1" [PT,QSA]
|
||||
</Directory>
|
||||
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride all
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<Location />
|
||||
Require all granted
|
||||
</Location>
|
||||
|
||||
Alias / "/tftpboot/"
|
||||
</VirtualHost>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
ROOTDIR=/data/development/sccp/sources/tftp
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
# Encrypt SEPMAC.cnf.xml
|
||||
openssl enc -aes-256-cbc -salt -in $ROOTDIR/data/settings/${1} -out $ROOTDIR/data/settings/${1}.enc -k $ROOTDIR/etc/certs/tftp.pem
|
||||
../../tools/certutils/sgnfile -b $ROOTDIR/data/settings/${1}.enc -c $ROOTDIR/etc/certs/tftp.pem
|
||||
fi
|
||||
openssl enc -aes-256-cbc -salt -in ../../tftpboot/settings/${1} -out ../../tftpboot/settings/${1}.enc -k tftp.pem
|
||||
../../tools/certutils/sgnfile -b ../../tftpboot/settings/${1}.enc -c tftp.pem
|
||||
fi
|
@@ -2,16 +2,15 @@
|
||||
|
||||
if [ $# == 0 ]; then
|
||||
# Create ITLFile.tlv in the tftpboot provisioning directory, the certificate used to sign the .tlv file is automatically included as providing the SAST function.
|
||||
#../../tools/certutils/tlvfile -b ../../tftpboot/settings/ITLFile.tlv -c CA.pem -r asterisk.pem -f ccm -r capf.pem -f capf -r tvs.pem -f tvs -r tftp.pem -f tftp -r webserver.pem -f https -r vpn.pem -f https
|
||||
../../tools/certutils/tlvfile -b ../../tftpboot/settings/ITLFile.tlv -c CA.pem -r asterisk.pem -f ccm -r tftp.pem -f tftp -r webserver.pem -f https -r vpn.pem -f https
|
||||
../../tools/certutils/tlvfile -b ../../tftpboot/settings/ITLFile.tlv -c CA.pem -r asterisk.pem -f ccm -r capf.pem -f capf -r tvs.pem -f tvs -r tftp.pem -f tftp -r webserver.pem -f https
|
||||
|
||||
else
|
||||
# Optionally, the default ITLFile.tlv can be overridden using a file name based on the MAC address of the phone, eg: ITLSEP58971ECC97C1.tlv.
|
||||
#../../tools/certutils/tlvfile -b ../../tftpboot/settings/ITL${1}.tlv -c CA.pem -r vpn.pem -f https -F ITLFile.tlv
|
||||
../../tools/certutils/tlvfile -b ../../tftpboot/settings/ITL${1}.tlv -c CA.pem -r asterisk.pem -f ccm -r tftp.pem -f tftp -r webserver.pem -f https -r vpn.pem -f https -F ITLFile.tlv
|
||||
|
||||
# Optionally, additional certificates can be included using a file name based on the MAC address of the phone, eg: CTLSEP58971ECC97C1.tlv.
|
||||
# Example for the VPN certificate
|
||||
#../../tools/certutils/tlvfile -b ../../tftpboot/settings/CTL${1}.tlv -c CA.pem -r vpn.pem -f https -F CTLFile.tlv
|
||||
../../tools/certutils/tlvfile -b ../../tftpboot/settings/CTL${1}.tlv -c CA.pem -r vpn.pem -f https -F CTLFile.tlv
|
||||
|
||||
# Enable SIP-TLS mode by setting <transportLayerProtocol> to 3 and setting <deviceSecurityMode> to either 2 (Authenticated) or 3 (Encrypted) in SEPMAC.cnf.xml. Optionally, any XML services can be configured to use HTTPS.
|
||||
fi
|
||||
|
@@ -2,6 +2,5 @@
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
# Sign SEPMAC.cnf.xml
|
||||
#../../tools/certutils/sgnfile -b ../../tftpboot/settings/$1 -c tftp.pem
|
||||
../../tools/certutils/sgnfile -c ../../etc/certs/tftp.pem -b $*
|
||||
../../tools/certutils/sgnfile -b ../../tftpboot/settings/$1 -c tftp.pem
|
||||
fi
|
||||
|
51
etc/nginx/sites-available/nginx-tftpboot.conf
Normal file
51
etc/nginx/sites-available/nginx-tftpboot.conf
Normal file
@@ -0,0 +1,51 @@
|
||||
#
|
||||
# Nginx Configuration to support the starting load of the Cisco phones via HTTP
|
||||
#
|
||||
# "Php-fpm" installation and configuration is required.
|
||||
#
|
||||
#
|
||||
#
|
||||
server {
|
||||
listen 6970;
|
||||
server_name tftp.servername.org;
|
||||
#root /tftpboot;
|
||||
root /tftpboot;
|
||||
|
||||
# Normal Logging
|
||||
#access_log /var/log/nginx/tftp.access.log;
|
||||
#error_log /var/log/nginx/tftp.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 / {
|
||||
#rewrite ^([^.]*[^/])$ $1/ permanent;
|
||||
#try_files $uri $uri/ /index.php?id=$query_string;
|
||||
rewrite ^/(.*)$ /index.php?id=$1 last;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
proxy_read_timeout 61;
|
||||
fastcgi_read_timeout 61;
|
||||
try_files $uri $uri/ =404;
|
||||
fastcgi_pass unix:/var/run/php-fpm.sock;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
# 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;
|
||||
}
|
||||
}
|
@@ -1,29 +1,260 @@
|
||||
server {
|
||||
listen 6970;
|
||||
server_name tftp.servername.org;
|
||||
root /data/development/sccp/sources/tftp/srv/web;
|
||||
listen 6970;
|
||||
server_name tftp.servername.org;
|
||||
#root /tftpboot;
|
||||
root /data/development/sccp/sources/tftp/tftpboot;
|
||||
index XMLDefault.cnf.xml;
|
||||
|
||||
# Normal Logging
|
||||
access_log /var/log/nginx/tftp1.access.log;
|
||||
error_log /var/log/nginx/tftp1.error.log;
|
||||
# Normal Logging
|
||||
#access_log /var/log/nginx/tftp.access.log;
|
||||
#error_log /var/log/nginx/tftp.error.log;
|
||||
|
||||
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;
|
||||
}
|
||||
# Debug Rewrite Rules
|
||||
rewrite_log on;
|
||||
access_log /var/log/nginx/tftp.access.log;
|
||||
error_log /var/log/nginx/tftp.error.log notice;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php$is_args$args;
|
||||
rewrite ^/(.*)$ /index.php?filename=$1 last;
|
||||
}
|
||||
location / {
|
||||
# settings
|
||||
rewrite ^/((.*)(\.cnf\.xml|\.tlv|\.json|authorized_keys)(\.enc)?(\.sgn)?)$ /settings/$1 last;
|
||||
|
||||
error_page 404 /;
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
# 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;
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,11 @@
|
||||
#
|
||||
# TFTPd Rewrite for SCCP_Manager Custom remaping
|
||||
# /firmware
|
||||
# /settings
|
||||
# /wallpapers
|
||||
# /ringtones
|
||||
# /locales
|
||||
#
|
||||
# 6901 firmware (java-based)
|
||||
ri ^(APP6901SCCP)(.+\.sgn)$ firmware/6901/\1\2
|
||||
ri ^(KNL6901SCCP)(.+\.sgn)$ firmware/6901/\1\2
|
||||
@@ -50,13 +58,13 @@ ri ^(P00405000700.sbn)$ firmware/7910/\1
|
||||
ri ^(CP7912080004SCCP080108A.sbin)$ firmware/7912/\1
|
||||
|
||||
# 7915 firmware (ancient)
|
||||
ri ^(B015-1-0-4.SBN)$ firmware/7915/\1
|
||||
ri ^(B015-1-0-)(.+\.SBN)$ firmware/7915/\1\2
|
||||
|
||||
# 7916 firmware (ancient)
|
||||
ri ^(B016-1-0-4.SBN)$ firmware/7916/\1
|
||||
ri ^(B016-1-0-)(.+\.SBN)$ firmware/7916/\1\2
|
||||
|
||||
# 7920 firmware (ancient)
|
||||
ri ^(cmterm_7920.4.0-03-02.bin)$ firmware/7920/\1
|
||||
ri ^(cmterm_7920)(.+\.bin)$ firmware/7920/\1\2
|
||||
|
||||
# 7921_7925 firmware (ancient)
|
||||
ri ^(APPS-1.4.3.4.SBN)$ firmware/7921/\1
|
||||
@@ -98,14 +106,10 @@ ri ^(cmterm_7936.3-3-21-0.bin)$ firmware/7936/\1
|
||||
ri ^(apps37sccp.1-4-5-7.bin)$ firmware/7937/\1
|
||||
|
||||
# 7940_7960 firmware (ancient)
|
||||
ri ^(P0030801SR.bin)$ firmware/7940/\1
|
||||
ri ^(P0030801SR.loads)$ firmware/7940/\1
|
||||
ri ^(P0030801SR.sb2)$ firmware/7940/\1
|
||||
ri ^(P0030801SR.sbn)$ firmware/7940/\1
|
||||
ri ^(P0030801SR01.bin)$ firmware/7940/\1
|
||||
ri ^(P0030801SR01.loads)$ firmware/7940/\1
|
||||
ri ^(P0030801SR01.sb2)$ firmware/7940/\1
|
||||
ri ^(P0030801SR01.sbn)$ firmware/7940/\1
|
||||
ri ^(P0030801SR)(.+\.bin)$ firmware/7940/\1\2
|
||||
ri ^(P0030801SR)(.+\.loads)$ firmware/7940/\1\2
|
||||
ri ^(P0030801SR)(.+\.sb2)$ firmware/7940/\1\2
|
||||
ri ^(P0030801SR)(.+\.sbn)$ firmware/7940/\1\2
|
||||
|
||||
# 7941_7961 firmware (java-based)
|
||||
ri ^(apps41)(.+\.sbn)$ firmware/7941/\1\2
|
||||
@@ -167,12 +171,6 @@ ri ^(SCCP894x)(.+\.loads)$ firmware/894x/\1\2
|
||||
# ata186/ata188 firmware (ancient)
|
||||
ri ^(ATA030204SCCP090202A.zup)$ firmware/ata186/\1
|
||||
|
||||
# SPA
|
||||
ri ^(spa50x)(.+\.bin)$ firmware/spa50x/\1\2
|
||||
ri ^(spa51x)(.+\.bin)$ firmware/spa51x/\1\2
|
||||
ri ^(spa525)(.+\.bin)$ firmware/spa525/\1\2
|
||||
ri ^(spa941)(.+\.bin)$ firmware/spa941/\1\2
|
||||
|
||||
# Sub-Directory Handling
|
||||
|
||||
# settings
|
||||
@@ -187,21 +185,25 @@ ri ^\/((SPA504G-cfg.xml)(\.enc)?(\.sgn)?)$ settings/\1
|
||||
#ri ^(.+\.sbn)$ firmware/\1
|
||||
|
||||
# Keep locales in a separate directory (optional)
|
||||
ri ^(.+)\/(.+-sccp.jar(.+\.sgn)?)$ locales/languages/\1/\2
|
||||
ri ^(.+)\/(.+-dictionary.+.xml(.+\.sgn)?)$ locales/languages/\1/\2
|
||||
ri ^(.+)\/(.+-font.xml(.+\.sgn)?)$ locales/languages/\1/\2
|
||||
ri ^(.+)\/(.+-kate.+\.xml(.+\.sgn)?)$ locales/languages/\1/\2
|
||||
ri ^(.+)\/(CIPC_Locale\..+(.+\.sgn)?)$ locales/languages/\1/\2
|
||||
ri ^(.+)\/(.+-tones.xml(.+\.sgn)?)$ locales/countries/\1/\2
|
||||
ri ^(.+)\/(.+-sccp.jar)$ languages/\1/\2
|
||||
ri ^(.+)\/(.+-sip.jar)$ languages/\1/\2
|
||||
ri ^(.+)\/(.+-dictionary.xml)$ languages/\1/\2
|
||||
ri ^(.+)\/(.+-dictionary-ext.xml)$ languages/\1/\2
|
||||
ri ^(.+)\/(.+-tones.xml)$ languages/\1/\2
|
||||
ri ^(.+)\/(.+-font.xml)$ languages/\1/\2
|
||||
ri ^(.+)\/(.+-kate.xml)$ languages/\1/\2
|
||||
ri ^(.+)\/(gk.+)(\.cfg)$ languages/\1/\2\3
|
||||
|
||||
#ri ^(.+)\/(.+-tones.xml)$ locales/countries/\1/\2
|
||||
|
||||
# Keep ring-tones in a separate directory (optional)
|
||||
ri ^([R|r]ing[L|l]ist)(\.xml|-wb\.xml)(\.sgn)?$ ringtones/ringlist.xml
|
||||
ri ^(Distinctive[R|r]ing[L|l]ist)(\.xml|-wb\.xml)(\.sgn)?$ ringtones/ringlist.xml
|
||||
ri ^(.+)(\.raw|\.rwb)(\.sgn)?$ ringtones/\1\2\3
|
||||
ri ^(.+)(\.raw|\.rwb|\.pcm)(\.sgn)?$ ringtones/\1\2\3
|
||||
|
||||
# Rename Desktops to wallpapers (optional)
|
||||
ri ^Desktops/(.+)/(List\.xml)(\.sgn)?$ wallpapers/\1/\2\3
|
||||
ri ^Desktops/(.+)/(.+\.png)(\.sgn)?$ wallpapers/\1/\2\3
|
||||
#ri ^Desktops/(.+)/(List\.xml)(\.sgn)?$ wallpapers/\1/\2\3
|
||||
#ri ^Desktops/(.+)/(.+\.png)(\.sgn)?$ wallpapers/\1/\2\3
|
||||
|
||||
ri ^authorized_keys$ settings/authorized_keys
|
||||
|
||||
|
40
etc/tftpd-hpa/tftpd.rules1
Normal file
40
etc/tftpd-hpa/tftpd.rules1
Normal file
@@ -0,0 +1,40 @@
|
||||
ri ^(APP6901SCCP.9-2-1-a.zz.sgn|KNL6901SCCP.9-2-1-a.zz.sgn|SCCP6901.9-2-1-a.loads)$ /firmware/6901/\1
|
||||
ri ^(APP6911SCCP.9-2-1-a.zz.sgn|BFS6911SCCP.9-2-1-a.zz.sgn|KNL6911SCCP.9-2-1-a.zz.sgn|SCCP6911.9-2-1-a.loads)$ /firmware/6911/\1
|
||||
ri ^CP7902080002SCCP060817A.sbin$ /firmware/7902/\1
|
||||
ri ^CP7905080003SCCP070409A.(sbin|zup)$ /firmware/7905/\1
|
||||
ri ^P00405000700.(bin|sbn)$ /firmware/7910/\1
|
||||
ri ^(APPSS-1.4.1SR1.SBN|CP7926G-1.4.1SR1.LOADS|EA15FW-BF3-220.SBN|GUIS-1.4.1SR1.SBN|J(SYSS-1.4.1SR1.SBN|UIS-1.4.1SR1.SBN)|SYSS-1.4.1SR1.SBN|TNUX(RS-1.4.1SR1.SBN|S-1.4.1SR1.SBN)|WLANS-1.4.1SR1.SBN)$ /firmware/7926/\1
|
||||
ri ^(SCCP31.9-2-1S.loads|apps31.9-2-1TH1-13.sbn|c(nu31.9-2-1TH1-13.sbn|vm31sccp.9-2-1TH1-13.sbn)|dsp31.9-2-1TH1-13.sbn|jar31sccp.9-2-1TH1-13.sbn|term31.default.loads)$ /firmware/7931/\1
|
||||
ri ^P00503021900.bin$ /firmware/7935/\1
|
||||
ri ^cmterm_7936.3-3-21-0.bin$ /firmware/7936/\1
|
||||
ri ^(BOOT69xx.0-0-0-14.zz.sgn|DSP69xx.12-4-123-2.160119.zz.sgn|SCCP69xx.9-4-1-3SR3.(loads|zz.sgn))$ /firmware/6921/\1
|
||||
ri ^SCCP6945.9-3-1-3.(bin(1.sgn|2.sgn|3.sgn|4.sgn)|loads)$ /firmware/6945/\1
|
||||
ri ^(BOOT69xx.0-0-0-14.zz.sgn|DSP69xx.0-0-0-11-124120.zz.sgn|SCCP69xx.9-3-1-3.(loads|zz.sgn))$ /firmware/69xx/\1
|
||||
ri ^CP7912080004SCCP080108A.sbin$ /firmware/7912/\1
|
||||
ri ^cmterm_7920.4.0-03-02.bin$ /firmware/7920/\1
|
||||
ri ^apps37sccp.1-4-5-7.bin$ /firmware/7937/\1
|
||||
ri ^(SCCP75.9-4-2SR3-1S.loads|apps75.9-4-2ES26.sbn|c(nu75.9-4-2ES26.sbn|vm75sccp.9-4-2ES26.sbn)|dsp75.9-4-2ES26.sbn|jar75sccp.9-4-2ES26.sbn|term75.default.loads)$ /firmware/7975/\1
|
||||
ri ^cmterm_7985.4-1-7-0.bin$ /firmware/7985/\1
|
||||
ri ^(BOOT894x.0-0-2-0.bin.sgn|SCCP894x.9-4-2SR1-2.(bin(1.sgn|2.sgn|3.sgn|4.sgn|5.sgn|6.sgn|7.sgn|8.sgn|9.sgn)|loads))$ /firmware/894x/\1
|
||||
ri ^(APPSH-1.4.1SR1.SBN|CP7925G-1.4.1SR1.LOADS|GUIH-1.4.1SR1.SBN|J(SYSH-1.4.1SR1.SBN|UIH-1.4.1SR1.SBN)|SYSH-1.4.1SR1.SBN|TNUX(H-1.4.1SR1.SBN|RH-1.4.1SR1.SBN)|WLANH-1.4.1SR1.SBN)$ /firmware/7925/\1
|
||||
ri ^SPA504G-762.BIN$ /firmware/spa50x/\1
|
||||
ri ^SPA941-518.BIN$ /firmware/spa941/\1
|
||||
ri ^(39(05|11_3951)|69(01_6911|21_6941_6961|45)|79(0([25]|6_7911)|1[024-6]|2[0156]|3[15-7]|4(0_7960|1_7961|2_7962|5_7965)|7(0_7971|5)|85)|89(41_8945|61)|99(51|71)|ATA-18[6-8]|KEM_9971)$ /firmware/IP_Phones/\1
|
||||
ri ^S00105000400.sbn$ /firmware/7914/\1
|
||||
ri ^B015-1-0-4-2.SBN$ /firmware/7915/\1
|
||||
ri ^B016-1-0-4-2.SBN$ /firmware/7916/\1
|
||||
ri ^(apps11.9-4-2ES26.sbn|c(nu11.9-4-2ES26.sbn|vm11sccp.9-4-2ES26.sbn)|dsp11.9-4-2ES26.sbn|jar11sccp.9-4-2ES26.sbn|SCCP11.9-4-2SR3-1S.loads)$ /firmware/7906/\1
|
||||
ri ^(apps11.9-4-2ES26.sbn|c(nu11.9-4-2ES26.sbn|vm11sccp.9-4-2ES26.sbn)|dsp11.9-4-2ES26.sbn|jar11sccp.9-4-2ES26.sbn|SCCP11.9-4-2SR3-1S.loads)$ /firmware/7911/\1
|
||||
ri ^(APPS-1.4.6.3.SBN|CP7921G-1.4.6.3.LOADS|GUI-1.4.6.3.SBN|SYS-1.4.6.3.SBN|TNUX(-1.4.6.3.SBN|R-1.4.6.3.SBN)|WLAN-1.4.6.3.SBN)$ /firmware/7921/\1
|
||||
ri ^P0030801SR02.(bin|loads|sb[2n]|txt)$ /firmware/7940/\1
|
||||
ri ^P0030801SR02.(bin|loads|sb[2n]|txt)$ /firmware/7960/\1
|
||||
ri ^(SCCP41.9-4-2SR3-1S.loads|apps41.9-4-2ES26.sbn|c(nu41.9-4-2ES26.sbn|vm41sccp.9-4-2ES26.sbn)|dsp41.9-4-2ES26.sbn|jar41sccp.9-4-2ES26.sbn|term(41.default.loads|61.default.loads))$ /firmware/7941/\1
|
||||
ri ^(SCCP41.9-4-2SR3-1S.loads|apps41.9-4-2ES26.sbn|c(nu41.9-4-2ES26.sbn|vm41sccp.9-4-2ES26.sbn)|dsp41.9-4-2ES26.sbn|jar41sccp.9-4-2ES26.sbn|term(41.default.loads|61.default.loads))$ /firmware/7961/\1
|
||||
ri ^(SCCP42.9-4-2SR3-1S.loads|apps42.9-4-2ES26.sbn|c(nu42.9-4-2ES26.sbn|vm42sccp.9-4-2ES26.sbn)|dsp42.9-4-2ES26.sbn|jar42sccp.9-4-2ES26.sbn|term(42.default.loads|62.default.loads))$ /firmware/7942/\1
|
||||
ri ^(SCCP42.9-4-2SR3-1S.loads|apps42.9-4-2ES26.sbn|c(nu42.9-4-2ES26.sbn|vm42sccp.9-4-2ES26.sbn)|dsp42.9-4-2ES26.sbn|jar42sccp.9-4-2ES26.sbn|term(42.default.loads|62.default.loads))$ /firmware/7962/\1
|
||||
ri ^(SCCP45.9-3-1SR1-1S.loads|apps45.9-3-1ES8.sbn|c(nu45.9-3-1ES8.sbn|vm45sccp.9-3-1ES8.sbn)|dsp45.9-3-1ES8.sbn|jar45sccp.9-3-1ES8.sbn|term(45.default.loads|65.default.loads))$ /firmware/7945/\1
|
||||
ri ^(SCCP45.9-3-1SR1-1S.loads|apps45.9-3-1ES8.sbn|c(nu45.9-3-1ES8.sbn|vm45sccp.9-3-1ES8.sbn)|dsp45.9-3-1ES8.sbn|jar45sccp.9-3-1ES8.sbn|term(45.default.loads|65.default.loads))$ /firmware/7965/\1
|
||||
ri ^(SCCP70.9-4-2SR3-1S.loads|apps70.9-4-2ES26.sbn|c(nu70.9-4-2ES26.sbn|vm70sccp.9-4-2ES26.sbn)|dsp70.9-4-2ES26.sbn|jar70sccp.9-4-2ES26.sbn|term7(0.default.loads|1.default.loads))$ /firmware/7970/\1
|
||||
ri ^(SCCP70.9-4-2SR3-1S.loads|apps70.9-4-2ES26.sbn|c(nu70.9-4-2ES26.sbn|vm70sccp.9-4-2ES26.sbn)|dsp70.9-4-2ES26.sbn|jar70sccp.9-4-2ES26.sbn|term7(0.default.loads|1.default.loads))$ /firmware/7971/\1
|
||||
ri ^ATA030204SCCP090202A.zup$ /firmware/ata186/\1
|
||||
ri ^ATA030204SCCP090202A.zup$ /firmware/ata188/\1
|
@@ -1,202 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace PROVISION;
|
||||
|
||||
use PROVISION\Logger;
|
||||
use PROVISION\Utils;
|
||||
|
||||
class ConfigParser {
|
||||
private $config = Array();
|
||||
private $defaults = '
|
||||
[main]
|
||||
debug = TRUE
|
||||
cache_filename = /tmp/provision_sccp_resolver.cache
|
||||
default_language = English_United_States
|
||||
log_type = SYSLOG
|
||||
log_level = LOG_INFO
|
||||
;log_filename = provision.log
|
||||
auto_generate_settings = FALSE
|
||||
auto_sign = FALSE
|
||||
auto_encrypt = FALSE
|
||||
|
||||
[security]
|
||||
cert_ca = NULL
|
||||
cert_priv = NULL
|
||||
cert_pub = NULL
|
||||
hash = NULL
|
||||
|
||||
[subdirs]
|
||||
etc = etc
|
||||
data = data
|
||||
firmware = firmware
|
||||
settings = settings
|
||||
wallpapers = wallpapers
|
||||
ringtones = ringtones
|
||||
locales = locales
|
||||
countries = countries
|
||||
languages = languages
|
||||
|
||||
[settings]
|
||||
sshUserId = cisco
|
||||
sshPassword = cisco
|
||||
ipAddress = ipv4|ipv6
|
||||
datetime.template = M/D/YA
|
||||
datetime.timezone = W. Europe Standard/Daylight Time
|
||||
datetime.ipaddress = 10.x.x.x
|
||||
datetime.mode = Unicast
|
||||
members.myhost.hostname = myhost.domain.com
|
||||
members.myhost.ipv4 = 10.x.x.x
|
||||
members.myhost.ipv6 = 2001:470::x:x
|
||||
members.myhost.port = 2000
|
||||
;srts.
|
||||
;common.
|
||||
;vendor.
|
||||
locale.country = United_States
|
||||
locale.language = English_United_States
|
||||
locale.langcode = en_US
|
||||
locale.charset = utf-8
|
||||
urls.security = FALSE
|
||||
urls.information = NULL
|
||||
urls.authentication = NULL
|
||||
urls.services = NULL
|
||||
urls.direcory = NULL
|
||||
urls.messages = NULL
|
||||
urls.proxyserver = NULL
|
||||
;vpn.
|
||||
;phoneservices.
|
||||
';
|
||||
|
||||
function __construct($base_path, $config_file) {
|
||||
# Merge defaults with ini file
|
||||
$default_config = $this->parse_multi_ini_string($this->defaults,true,INI_SCANNER_TYPED);
|
||||
$ini_config = $this->parse_multi_ini_file("$base_path/$config_file", true, INI_SCANNER_TYPED);
|
||||
if (!empty($ini_config)) {
|
||||
$config = array_merge($default_config, $ini_config);
|
||||
}
|
||||
$config['main']['base_path'] = $base_path;
|
||||
$config['main']['data'] = (!empty($config['main']['data'])) ? $base_path . "data" : DIRECTORY_SEPARATOR . 'data';
|
||||
$config['subdirs'] = $this->replaceSubdirTreeStructure($config['subdirs']);
|
||||
$this->config = $config;
|
||||
$this->initializeLogger();
|
||||
}
|
||||
|
||||
private function initializeLogger() {
|
||||
global $logger;
|
||||
switch($this->config['main']['log_type']) {
|
||||
case 'SYSLOG':
|
||||
$logger = new Logger\Syslog($this->config['main']['log_level']);
|
||||
break;
|
||||
case 'FILE':
|
||||
if (!isempty($config['main']['log_file'])) {
|
||||
$logger = new Logger\Filename($this->config['main']['log_level'], $this->config['main']['log_file']);
|
||||
}
|
||||
break;
|
||||
case 'STDOUT':
|
||||
$logger = new Logger\Stdout($this->config['main']['log_level']);
|
||||
break;
|
||||
case 'STDERR':
|
||||
$logger = new Logger\Stderr($this->config['main']['log_level']);
|
||||
break;
|
||||
default:
|
||||
$logger = new Logger\Null($this->config['main']['log_level']);
|
||||
}
|
||||
$this->config['main']['logger'] = $logger;
|
||||
}
|
||||
|
||||
/*!
|
||||
* replace config['subdirs'] paths using tree_structure
|
||||
* method imported from old version (and rewritten)
|
||||
* Note: Still not sure if we actually need to do all this
|
||||
*/
|
||||
private function replaceSubdirTreeStructure($tmpSubdirs) {
|
||||
$tree_structure = Array(
|
||||
'etc' => array('parent' => NULL, "strip" => true),
|
||||
'data' => array('parent' => NULL, "strip" => true),
|
||||
'settings' => array('parent' => 'data', "strip" => true),
|
||||
'wallpapers' => array('parent' => 'data', "strip" => false),
|
||||
'ringtones' => array('parent' => 'data', "strip" => true),
|
||||
'locales' => array('parent' => 'data', "strip" => true),
|
||||
'firmware' => array('parent' => 'data', "strip" => true),
|
||||
'languages' => array('parent' => 'locales', "strip" => false),
|
||||
'countries' => array('parent' => 'locales', "strip" => false),
|
||||
);
|
||||
|
||||
$subdirs = Array();
|
||||
foreach ($tree_structure as $key => $value) {
|
||||
if (!empty($tmpSubdirs[$key])) {
|
||||
if (!$value['parent']) {
|
||||
$path = $tmpSubdirs[$key];
|
||||
} else {
|
||||
$path = $subdirs[$value['parent']]['path'] . DIRECTORY_SEPARATOR . $tmpSubdirs[$key];
|
||||
}
|
||||
$subdirs[$key] = array('path' => $path, 'strip' => $value['strip']);
|
||||
}
|
||||
}
|
||||
return $subdirs;
|
||||
}
|
||||
|
||||
/*!
|
||||
* config parser that understands multidimensional ini entries
|
||||
* using "." as the dimension separator
|
||||
* standin replacement for parse_ini_string
|
||||
*/
|
||||
private function parse_multi_ini_string($string, $process_sections = false, $scanner_mode = INI_SCANNER_NORMAL) {
|
||||
$explode_str = '.';
|
||||
$escape_char = "'";
|
||||
// load ini file the normal way
|
||||
$data = parse_ini_string($string, $process_sections, $scanner_mode);
|
||||
if (!$process_sections) {
|
||||
$data = array($data);
|
||||
}
|
||||
foreach ($data as $section_key => $section) {
|
||||
// loop inside the section
|
||||
foreach ($section as $key => $value) {
|
||||
if (strpos($key, $explode_str)) {
|
||||
if (substr($key, 0, 1) !== $escape_char) {
|
||||
// key has a dot. Explode on it, then parse each subkeys
|
||||
// and set value at the right place thanks to references
|
||||
$sub_keys = explode($explode_str, $key);
|
||||
$subs =& $data[$section_key];
|
||||
foreach ($sub_keys as $sub_key) {
|
||||
if (!isset($subs[$sub_key])) {
|
||||
$subs[$sub_key] = [];
|
||||
}
|
||||
$subs =& $subs[$sub_key];
|
||||
}
|
||||
// set the value at the right place
|
||||
$subs = $value;
|
||||
// unset the dotted key, we don't need it anymore
|
||||
unset($data[$section_key][$key]);
|
||||
}
|
||||
// we have escaped the key, so we keep dots as they are
|
||||
else {
|
||||
$new_key = trim($key, $escape_char);
|
||||
$data[$section_key][$new_key] = $value;
|
||||
unset($data[$section_key][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
if (!$process_sections) {
|
||||
$data = $data[0];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/*!
|
||||
* config file parser that understands multidimensional ini entries
|
||||
* using "." as the dimension separator
|
||||
* standin replacement for parse_ini_file
|
||||
*/
|
||||
private function parse_multi_ini_file($file, $process_sections = false, $scanner_mode = INI_SCANNER_NORMAL) {
|
||||
$string = file_get_contents($file);
|
||||
return $this->parse_multi_ini_string($string, $process_sections, $scanner_mode);
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getConfiguration() {
|
||||
return $this->config;
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Crypto;
|
||||
|
||||
class Certificate {
|
||||
function __construct(string $file) {
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
public function hashAsBase64(int $hashAlg) : string {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Crypto;
|
||||
|
||||
class Crypto {
|
||||
|
||||
public static function certificateHashAsBase64(string $certificateFile, int $hashAlg) : string {
|
||||
return new Certificate($certificateFile)
|
||||
.hashAsBase64($hashAlg);
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Crypto;
|
||||
|
||||
class HashAlgo // extends Enum
|
||||
{
|
||||
private const SHA1 = 0;
|
||||
private const SHA256 = 1;
|
||||
}
|
||||
?>
|
@@ -1,8 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Crypto;
|
||||
|
||||
class Signer {
|
||||
}
|
||||
?>
|
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
class AddonDevice extends Device
|
||||
{
|
||||
}
|
||||
?>
|
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
class CiscoDevice extends Device
|
||||
{
|
||||
}
|
||||
?>
|
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
use PROVISION\Device\Type as Type;
|
||||
use PROVISION\Device\Family as Family;
|
||||
use PROVISION\Device\Protocol as Protocol;
|
||||
use PROVISION\Device\Flags as Flags;
|
||||
|
||||
abstract class Device
|
||||
{
|
||||
private $name;
|
||||
private $family;
|
||||
private $prococol;
|
||||
private $flags;
|
||||
function __construct($name, $family, $protocol, $flags = null) {
|
||||
$this->name = $name;
|
||||
$this->family = $family;
|
||||
$this->protocol = $protocol;
|
||||
$this->flags = $flags;
|
||||
}
|
||||
function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,130 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
use PROVISION\Device\Type as Type;
|
||||
use PROVISION\Device\Family as Family;
|
||||
use PROVISION\Device\Protocol as Protocol;
|
||||
use PROVISION\Device\Flags as Flags;
|
||||
|
||||
class DeviceFactory
|
||||
{
|
||||
private $models = Array(
|
||||
Type::CiscoIPCommunicator => Array('name' => "Communicator", 'family' => Family::CiscoJava, 'protocol' => Protocol::SKINNY, 'flags' => Flags::Communicator),
|
||||
Type::CiscoIPPhone6901 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
Type::CiscoIPPhone6911 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
Type::CiscoIPPhone6921 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
Type::CiscoIPPhone6941 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
Type::CiscoIPPhone6945 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
Type::CiscoIPPhone6961 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
Type::CiscoIPPhone7902 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
Type::CiscoIPPhone7905 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
Type::CiscoIPPhone7906 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
Type::CiscoIPPhone7910 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
Type::CiscoIPPhone7911 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7912 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7920 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7921 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7925 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7926 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7931 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
Type::CiscoIPPhone7935 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::BOTH, 'flags' => Flags::Conference), // Conference Phone
|
||||
Type::CiscoIPPhone7936 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::BOTH, 'flags' => Flags::Conference), // Conference Phone
|
||||
Type::CiscoIPPhone7937 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::BOTH, 'flags' => Flags::Conference), // Conference Phone
|
||||
Type::CiscoIPPhone7940 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7941 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7941GE => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7942 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7945 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7960 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7961 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7961G => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7961GE => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7962 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7965 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7970 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7971 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7975 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone7985 => Array('name' => "", 'family' => Family::CiscoJava, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone8941 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoIPPhone8945 => Array('name' => "", 'family' => Family::Cisco, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
|
||||
Type::CiscoSPA303G => Array('name' => "", 'family' => Family::Spa, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoSPA502G => Array('name' => "", 'family' => Family::Spa, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoSPA504G => Array('name' => "", 'family' => Family::Spa, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoSPA509G => Array('name' => "", 'family' => Family::Spa, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoSPA512G => Array('name' => "", 'family' => Family::Spa, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoSPA514G => Array('name' => "", 'family' => Family::Spa, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoSPA521S => Array('name' => "", 'family' => Family::Spa, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoSPA521SG => Array('name' => "", 'family' => Family::Spa, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoSPA525G2 => Array('name' => "", 'family' => Family::Spa, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
Type::CiscoSPA525G => Array('name' => "", 'family' => Family::Spa, 'protocol' => Protocol::BOTH, 'flags' => null),
|
||||
|
||||
Type::NokiaESeries => Array('name' => "", 'family' => Family::ThirdParty, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
Type::NokiaICCclient => Array('name' => "", 'family' => Family::ThirdParty, 'protocol' => Protocol::SKINNY, 'flags' => null),
|
||||
|
||||
Type::CiscoIPAddon7914 => Array('name' => "", 'family' => Family::CiscoAddon, 'protocol' => Protocol::BOTH, 'flags' => null), //14-Button Line Expansion Module
|
||||
Type::CiscoIPAddon7915_1 => Array('name' => "", 'family' => Family::CiscoAddon, 'protocol' => Protocol::BOTH, 'flags' => null), //12-Button Line Expansion Module
|
||||
Type::CiscoIPAddon7915_2 => Array('name' => "", 'family' => Family::CiscoAddon, 'protocol' => Protocol::BOTH, 'flags' => null), //24-Button Line Expansion Module
|
||||
Type::CiscoIPAddon7916_1 => Array('name' => "", 'family' => Family::CiscoAddon, 'protocol' => Protocol::BOTH, 'flags' => null), //12-Button Line Expansion Module
|
||||
Type::CiscoIPAddon7916_2 => Array('name' => "", 'family' => Family::CiscoAddon, 'protocol' => Protocol::BOTH, 'flags' => null), //24-Button Line Expansion Module
|
||||
);
|
||||
|
||||
/**
|
||||
* Prevent direct object creation
|
||||
*/
|
||||
final private function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns new or existing Singleton instance
|
||||
* @return Singleton
|
||||
*/
|
||||
final public static function getInstance(){
|
||||
if(null !== static::$_instance){
|
||||
return static::$_instance;
|
||||
}
|
||||
static::$_instance = new static();
|
||||
return static::$_instance;
|
||||
}
|
||||
|
||||
private function createDeviceByModel($model) {
|
||||
switch($model['family']) {
|
||||
case Family::PreCisco:
|
||||
return new PreCiscoDevice($model['name'], $model['family'], $model['protocol'], $model['flags']);
|
||||
case Family::Cisco:
|
||||
return new CiscoDevice($model['name'], $model['family'], $model['protocol'], $model['flags']);
|
||||
case Family::CiscoJava:
|
||||
return new JavaDevice($model['name'], $model['family'], $model['protocol'], $model['flags']);
|
||||
case Family::PreCisco:
|
||||
return new SpaDevice($model['name'], $model['family'], $model['protocol'], $model['flags']);
|
||||
case Family::CiscoAddon:
|
||||
return new AddonDevice($model['name'], $model['family'], $model['protocol'], $model['flags']);
|
||||
case Family::SpaAddon:
|
||||
return new SpaAddonDevice($model['name'], $model['family'], $model['protocol'], $model['flags']);
|
||||
case Family::ThirdParty:
|
||||
return new ThirdPartyDevice($model['name'], $model['family'], $model['protocol'], $model['flags']);
|
||||
default:
|
||||
// return error
|
||||
return new Device($model['name'], $model['family'], $model['protocol'], $model['flags']);
|
||||
}
|
||||
}
|
||||
|
||||
public function createFromString($name) {
|
||||
foreach($this->models as $model) {
|
||||
if ($model['name'] == $name) {
|
||||
return $this->createDeviceByModel($model);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public function createFromModelNo($modelno) {
|
||||
if (array_key_exists($modelno, $this->models)) {
|
||||
$model = $models[$modelno];
|
||||
return $this->createDeviceByModel($model);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
abstract class Family extends \SplEnum {
|
||||
const PreCisco = 0;
|
||||
const Cisco = 1;
|
||||
const CiscoJava = 2;
|
||||
const Spa = 3;
|
||||
const CiscoAddon = 4;
|
||||
const SpaAddon = 5;
|
||||
const ThirdParty = 6;
|
||||
}
|
||||
?>
|
@@ -1,10 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
abstract class Flags extends \SplEnum {
|
||||
const Conference = 1<<0;
|
||||
const Communicator = 1<<1;
|
||||
}
|
||||
?>
|
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
class JavaDevice extends Device
|
||||
{
|
||||
}
|
||||
?>
|
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
abstract class Protocol extends \SplEnum {
|
||||
const SKINNY = 0;
|
||||
const SIP = 1;
|
||||
const BOTH = 2;
|
||||
}
|
||||
?>
|
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
class SelsiusDevice extends Device
|
||||
{
|
||||
}
|
||||
?>
|
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
class SpaAddonDevice extends Device
|
||||
{
|
||||
}
|
||||
?>
|
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
class SpaDevice extends Device
|
||||
{
|
||||
}
|
||||
?>
|
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
class ThirdPartyDevice extends Device
|
||||
{
|
||||
}
|
||||
?>
|
@@ -1,66 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PROVISION\Device;
|
||||
|
||||
abstract class Type extends \SplEnum
|
||||
{
|
||||
const CiscoIPCommunicator = 30016;
|
||||
const CiscoIPPhone6901 = 547;
|
||||
const CiscoIPPhone6911 = 548;
|
||||
const CiscoIPPhone6921 = 495;
|
||||
const CiscoIPPhone6941 = 496;
|
||||
const CiscoIPPhone6945 = 564;
|
||||
const CiscoIPPhone6961 = 497;
|
||||
const CiscoIPPhone7902 = 30008;
|
||||
const CiscoIPPhone7905 = 20000;
|
||||
const CiscoIPPhone7906 = 369;
|
||||
const CiscoIPPhone7910 = 006;
|
||||
const CiscoIPPhone7911 = 307;
|
||||
const CiscoIPPhone7912 = 30007;
|
||||
const CiscoIPPhone7920 = 30002;
|
||||
const CiscoIPPhone7921 = 365;
|
||||
const CiscoIPPhone7925 = 484;
|
||||
const CiscoIPPhone7926 = 577;
|
||||
const CiscoIPPhone7931 = 348;
|
||||
const CiscoIPPhone7935 = 9; // Conference Phone
|
||||
const CiscoIPPhone7936 = 30019;
|
||||
const CiscoIPPhone7937 = 431; // Conference Phone
|
||||
const CiscoIPPhone7940 = 8;
|
||||
const CiscoIPPhone7941 = 115;
|
||||
const CiscoIPPhone7941GE = 309;
|
||||
const CiscoIPPhone7942 = 434;
|
||||
const CiscoIPPhone7945 = 435;
|
||||
const CiscoIPPhone7960 = 7;
|
||||
const CiscoIPPhone7961 = 5;
|
||||
const CiscoIPPhone7961G = 30018;
|
||||
const CiscoIPPhone7961GE = 308;
|
||||
const CiscoIPPhone7962 = 404;
|
||||
const CiscoIPPhone7965 = 436;
|
||||
const CiscoIPPhone7970 = 30006;
|
||||
const CiscoIPPhone7971 = 119;
|
||||
const CiscoIPPhone7975 = 437;
|
||||
const CiscoIPPhone7985 = 302;
|
||||
const CiscoIPPhone8941 = 586;
|
||||
const CiscoIPPhone8945 = 585;
|
||||
|
||||
const CiscoSPA303G = 80011;
|
||||
const CiscoSPA502G = 80003;
|
||||
const CiscoSPA504G = 80004;
|
||||
const CiscoSPA509G = 80007;
|
||||
const CiscoSPA512G = 80012;
|
||||
const CiscoSPA514G = 80013;
|
||||
const CiscoSPA521S = 80000;
|
||||
const CiscoSPA521SG = 80001;
|
||||
const CiscoSPA525G2 = 80009;
|
||||
const CiscoSPA525G = 80005;
|
||||
const NokiaESeries = 275;
|
||||
const NokiaICCclient = 376;
|
||||
|
||||
const CiscoIPAddon7914 = 124; //14-Button Line Expansion Module
|
||||
const CiscoIPAddon7915_1 = 227; //12-Button Line Expansion Module
|
||||
const CiscoIPAddon7915_2 = 228; //24-Button Line Expansion Module
|
||||
const CiscoIPAddon7916_1 = 229; //12-Button Line Expansion Module
|
||||
const CiscoIPAddon7916_2 = 230; //24-Button Line Expansion Module
|
||||
}
|
||||
?>
|
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace PROVISION\Logger;
|
||||
|
||||
class 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 Filename extends Filehandle
|
||||
{
|
||||
function __construct($minimum, $filename, $dateformat = "r")
|
||||
{
|
||||
return parent::__construct($minimum, fopen($filename, "a"), $dateformat);
|
||||
}
|
||||
}
|
||||
|
||||
class Stderr extends Filehandle
|
||||
{
|
||||
function __construct($minimum, $dateformat = "r")
|
||||
{
|
||||
return parent::__construct($minimum, STDERR, $dateformat);
|
||||
}
|
||||
}
|
||||
class Stdout extends Filehandle
|
||||
{
|
||||
function __construct($minimum, $dateformat = "r")
|
||||
{
|
||||
return parent::__construct($minimum, STDOUT, $dateformat);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace PROVISION\Logger;
|
||||
|
||||
class Filename extends Filehandle
|
||||
{
|
||||
function __construct($minimum, $filename, $dateformat = "r")
|
||||
{
|
||||
return parent::__construct($minimum, fopen($filename, "a"), $dateformat);
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace PROVISION\Logger;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
?>
|
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace PROVISION\Logger;
|
||||
|
||||
class Null extends Logger
|
||||
{
|
||||
function log($priority, $message)
|
||||
{
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace PROVISION\Logger;
|
||||
|
||||
class Stderr extends Filehandle
|
||||
{
|
||||
function __construct($minimum, $dateformat = "r")
|
||||
{
|
||||
return parent::__construct($minimum, STDERR, $dateformat);
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace PROVISION\Logger;
|
||||
|
||||
class Stdout extends Filehandle
|
||||
{
|
||||
function __construct($minimum, $dateformat = "r")
|
||||
{
|
||||
return parent::__construct($minimum, STDOUT, $dateformat);
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace PROVISION\Logger;
|
||||
|
||||
class Syslog extends Logger
|
||||
{
|
||||
function log($priority, $message)
|
||||
{
|
||||
if($this->shouldlog($priority))
|
||||
syslog($priority,$message);
|
||||
}
|
||||
}
|
||||
?>
|
135
lib/Resolve.php
135
lib/Resolve.php
@@ -1,135 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PROVISION;
|
||||
use PROVISION\ResolveResult as ResolveResult;
|
||||
use PROVISION\ResolveCache as ResolveCache;
|
||||
use PROVISION\Utils as Utils;
|
||||
|
||||
/* Todo:
|
||||
✔️ setup logging
|
||||
✔️ read config.file
|
||||
|
||||
✔?️ improve error handling
|
||||
✔️? secure urlencoding/urldecoding
|
||||
✔️? don't allow browsing
|
||||
|
||||
- check source ip-range
|
||||
- check HTTPHeader for known BrowserTypes
|
||||
|
||||
- Could use some more test-cases, especially error ones
|
||||
*/
|
||||
class Resolve {
|
||||
private $isDirty = FALSE;
|
||||
private $cache;
|
||||
private $config;
|
||||
function __construct($config) {
|
||||
$this->config = $config;
|
||||
$this->cache = new ResolveCache\FileCache($this->config['main']['cache_filename']);
|
||||
if ($this->cache->isDirty()) {
|
||||
$this->rebuildCache();
|
||||
}
|
||||
}
|
||||
|
||||
public function searchForFile($filename) {
|
||||
$path = "";
|
||||
foreach($this->config['subdirs'] as $key => $value) {
|
||||
if ($key === "firmware" || $key === "data" || $key === "etc") {
|
||||
continue;
|
||||
}
|
||||
$path = realpath($this->config['main']['base_path'] . DIRECTORY_SEPARATOR . $value['path'] . DIRECTORY_SEPARATOR . $filename);
|
||||
if (!$path) {
|
||||
print("path: '" . $this->config['main']['base_path'] . DIRECTORY_SEPARATOR . $value['path'] . DIRECTORY_SEPARATOR . $filename . "' not found\n");
|
||||
return ResolveResult::FileNotFound;
|
||||
}
|
||||
$this->cache->addFile($filename, $path);
|
||||
return $path;
|
||||
}
|
||||
Utils::log_error("File '$filename' does not exist");
|
||||
return ResolveResult::FileNotFound;
|
||||
}
|
||||
|
||||
public function rebuildCache() {
|
||||
Utils::log_debug("Rebuilding Cache, standby...");
|
||||
foreach($this->config['subdirs'] as $key =>$value) {
|
||||
if ($key === "data" || $key === "etc") {
|
||||
continue;
|
||||
}
|
||||
$path = realpath($this->config['main']['base_path'] . DIRECTORY_SEPARATOR . $value['path'] . DIRECTORY_SEPARATOR);
|
||||
if (!$path) {
|
||||
print("path: '" . $this->config['main']['base_path'] . DIRECTORY_SEPARATOR . $value['path'] . "' not found\n");
|
||||
break;
|
||||
}
|
||||
$dir_iterator = new \RecursiveDirectoryIterator($path);
|
||||
$filter = new \RecursiveCallbackFilterIterator($dir_iterator, function ($current, $key, $iterator) {
|
||||
// Skip hidden files and directories.
|
||||
if ($current->getFilename()[0] === '.' || $current->getFilename() == "bak") {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
});
|
||||
$iterator = new \RecursiveIteratorIterator($filter, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->isFile()) {
|
||||
if ($value['strip']) {
|
||||
$this->cache->addFile($file->getFileName(), $file->getPathname());
|
||||
} else {
|
||||
$subdir = basename(dirname($file->getPathname()));
|
||||
$this->cache->addFile($subdir. DIRECTORY_SEPARATOR . $file->getFileName(), $file->getPathname());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->isDirty = TRUE;
|
||||
}
|
||||
|
||||
public 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 (!$request || empty($request)) {
|
||||
Utils::log_error("Request is empty");
|
||||
return ResolveResult::EmptyRequest;
|
||||
}
|
||||
if (!is_string($request)) {
|
||||
Utils::log_error("Request is not a string");
|
||||
return ResolveResult::RequestNotAString;
|
||||
}
|
||||
Utils::log_debug($request . ":" . escapeshellarg($request) . ":" . Utils::utf8_urldecode($request) . "\n");
|
||||
$escaped_request = escapeshellarg(Utils::utf8_urldecode($request));
|
||||
if ($escaped_request !== "'" . $request . "'") {
|
||||
Utils::log_error("Request '$request' contains invalid characters");
|
||||
return ResolveResult::RequestContainsInvalidChar;
|
||||
}
|
||||
if (strstr($escaped_request, "..")) {
|
||||
Utils::log_error("Request '$request' contains '..'");
|
||||
return ResolveResult::RequestContainsPathWalk;
|
||||
}
|
||||
return ResolveResult::Ok;
|
||||
}
|
||||
|
||||
public function resolve($request) /* canthrow */ {
|
||||
$path = '';
|
||||
$result = $this->validateRequest($request);
|
||||
if ($result !== ResolveResult::Ok) {
|
||||
return $result;
|
||||
}
|
||||
if (($path = $this->cache->getPath($request))) {
|
||||
if (!file_exists($path)) {
|
||||
$this->cache->removeFile($request);
|
||||
Utils::log_error("File '$request' does not exist on FS");
|
||||
return ResolveResult::FileNotFound;
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
if ($this->searchForFile($request)) {
|
||||
$path = $this->cache->getPath($request);
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
/* temporary */
|
||||
function printCache() {
|
||||
print_r($this->cache);
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,66 +0,0 @@
|
||||
<?php
|
||||
namespace PROVISION\ResolveCache;
|
||||
|
||||
use PROVISION\Utils as Utils;
|
||||
|
||||
class FileCache extends ResolveCache {
|
||||
private $_isDirty = false;
|
||||
private $_cache = array();
|
||||
private $_cache_file = NULL;
|
||||
|
||||
function __construct($filename) {
|
||||
$this->_cache_file = $filename;
|
||||
if (file_exists($this->_cache_file)) {
|
||||
$this->_cache = unserialize(file_get_contents($this->_cache_file));
|
||||
$this->_isDirty = false;
|
||||
} else {
|
||||
$this->_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
function __destruct() {
|
||||
if ($this->_isDirty) {
|
||||
/*if (!is_writable($this->_cache_file)) {
|
||||
log_error_and_throw("Could not write to file '".$this->_cache_file."' at Resolver::destruct");
|
||||
}*/
|
||||
if (!file_put_contents($this->_cache_file, serialize($this->_cache))) {
|
||||
Utils::log_error_and_throw("Could not write to file '".$this->_cache_file."' at Resolver::destruct");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function isDirty() {
|
||||
return $this->_isDirty;
|
||||
}
|
||||
|
||||
public function check($filename) {
|
||||
return array_key_exists($filename, $this->_cache);
|
||||
}
|
||||
|
||||
public function addFile($filename, $realpath) {
|
||||
if ($this->check($filename))
|
||||
Utils::log_error("Duplicate file:$filename"); /* should we prevent this ? */
|
||||
$this->_cache[$filename] = $realpath;
|
||||
$this->_isDirty =true;
|
||||
}
|
||||
|
||||
public function removeFile($filename) {
|
||||
if ($this->check($filename)) {
|
||||
unset($this->_cache[$filename]);
|
||||
$this->_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function getPath($filename) {
|
||||
if ($this->check($filename)) {
|
||||
return $this->_cache[$filename];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function printCache() {
|
||||
print_r($this->_cache);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
namespace PROVISION\ResolveCache;
|
||||
|
||||
abstract class ResolveCache {
|
||||
abstract protected function addFile($filename, $realpath);
|
||||
abstract protected function removeFile($filename);
|
||||
abstract protected function check($filename);
|
||||
abstract protected function getPath($filename);
|
||||
}
|
||||
|
||||
/*
|
||||
class SqliteCache extends ResolveCache {
|
||||
function __construct() {
|
||||
}
|
||||
function __destruct() {
|
||||
}
|
||||
public function addFile($filename, $realpath);
|
||||
public function removeFile($filename);
|
||||
public function check($filename);
|
||||
public function getPath($filename);
|
||||
}
|
||||
*/
|
||||
|
||||
?>
|
@@ -1,16 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PROVISION;
|
||||
|
||||
//abstract class ResolveResult extends \SplEnum {
|
||||
abstract class ResolveResult {
|
||||
const Ok = 0;
|
||||
const EmptyRequest = 1;
|
||||
const RequestNotAString = 2;
|
||||
const RequestContainsInvalidChar = 3;
|
||||
const RequestContainsPathWalk = 4;
|
||||
const FileNotFound = 5;
|
||||
const InvalidFilename = 6;
|
||||
const InvalidPath = 7;
|
||||
}
|
||||
?>
|
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* PHP TFTP Server
|
||||
*
|
||||
* Copyright (c) 2011 <mattias.wadman@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
namespace PROVISION\TFTP;
|
||||
|
||||
use PROVISION\Logger as Logger;
|
||||
|
||||
class Error
|
||||
{
|
||||
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;
|
||||
}
|
||||
?>
|
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace PROVISION;
|
||||
/*
|
||||
* PHP TFTP Server
|
||||
*
|
||||
* Copyright (c) 2011 <mattias.wadman@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
namespace PROVISION\TFTP;
|
||||
|
||||
use PROVISION\Logger as Logger;
|
||||
|
||||
class Opcode
|
||||
{
|
||||
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
|
||||
}
|
||||
?>
|
@@ -1,161 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* PHP TFTP Server
|
||||
*
|
||||
* Copyright (c) 2011 <mattias.wadman@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
namespace PROVISION\TFTP;
|
||||
|
||||
use PROVISION\Logger as Logger;
|
||||
use PROVISION\TFTP as TFTP;
|
||||
|
||||
class ReadTransfer extends TFTP\Transfer {
|
||||
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;
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,361 +0,0 @@
|
||||
<?php
|
||||
// origin: https://github.com/tm1000/tftpserver
|
||||
/*
|
||||
* PHP TFTP Server
|
||||
*
|
||||
* Copyright (c) 2011 <mattias.wadman@gmail.com>
|
||||
*
|
||||
* 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?
|
||||
*
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
namespace PROVISION\TFTP;
|
||||
|
||||
use PROVISION\Logger as Logger;
|
||||
|
||||
class Server {
|
||||
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);
|
||||
//$r = stream_select($read, $write = null, $excpt = null, 1);
|
||||
$write = null;
|
||||
$except = 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;
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,150 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* PHP TFTP Server
|
||||
*
|
||||
* Copyright (c) 2011 <mattias.wadman@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
namespace PROVISION\TFTP;
|
||||
|
||||
use PROVISION\Logger as Logger;
|
||||
|
||||
abstract class Transfer {
|
||||
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);
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* PHP TFTP Server
|
||||
*
|
||||
* Copyright (c) 2011 <mattias.wadman@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
namespace PROVISION\TFTP;
|
||||
|
||||
use PROVISION\Logger as Logger;
|
||||
|
||||
class TFTPTransferState
|
||||
{
|
||||
const READY = 1;
|
||||
const SENDING_WAIT_OACK = 2;
|
||||
const SENDING = 3;
|
||||
const RECEIVING = 4;
|
||||
const TERMINATING = 5;
|
||||
}
|
||||
?>
|
@@ -1,158 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* PHP TFTP Server
|
||||
*
|
||||
* Copyright (c) 2011 <mattias.wadman@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
namespace PROVISION\TFTP;
|
||||
|
||||
use PROVISION\Logger as Logger;
|
||||
use PROVISION\TFTP as TFTP;
|
||||
|
||||
class TFTPWriteTransfer extends TFTP\Transfer {
|
||||
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;
|
||||
}
|
||||
}
|
||||
?>
|
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
//
|
||||
// Helper functions
|
||||
//
|
||||
declare(strict_types=1);
|
||||
namespace PROVISION;
|
||||
|
||||
class Utils {
|
||||
static function utf8_urldecode($str) {
|
||||
$str = preg_replace("/%u([0-9a-f]{3,4})/i","&#x\\1;",urldecode($str));
|
||||
return html_entity_decode($str,0,'UTF-8');;
|
||||
}
|
||||
|
||||
static public function log_debug($message) {
|
||||
global $logger;
|
||||
if ($logger) {
|
||||
$logger->log('LOG_DEBUG', $message);
|
||||
}
|
||||
}
|
||||
|
||||
static function log_error($message) {
|
||||
global $logger;
|
||||
if ($logger) {
|
||||
$logger->log('LOG_ERROR', $message);
|
||||
}
|
||||
}
|
||||
|
||||
static function log_error_and_throw($message) {
|
||||
log_error($message);
|
||||
throw new Exception($message);
|
||||
}
|
||||
}
|
||||
?>
|
56
lib/XML.php
56
lib/XML.php
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace PROVISION;
|
||||
//use PROVISION\ConfigParser;
|
||||
|
||||
class XML {
|
||||
private $config;
|
||||
private $data;
|
||||
private $values;
|
||||
private $index;
|
||||
private $parser;
|
||||
function __construct($config) {
|
||||
$this->config = $config;
|
||||
$this->parser = xml_parser_create();
|
||||
//xml_error_string
|
||||
}
|
||||
function __destruct() {
|
||||
xml_parser_free($this->parser);
|
||||
}
|
||||
function readStr($content) {
|
||||
xml_parse_into_struct($this->parser , $content , $this->values, $this->index);
|
||||
}
|
||||
function readFile($filename) {
|
||||
$content = file_get_contents($filename);
|
||||
$this->read($content);
|
||||
}
|
||||
function write() {
|
||||
}
|
||||
function addAttr($elem, $attr) {
|
||||
}
|
||||
function removeAttr($elem, $attr) {
|
||||
}
|
||||
function updateAttr($elem, $attr) {
|
||||
}
|
||||
function add($parent) {
|
||||
}
|
||||
function remove($parent) {
|
||||
}
|
||||
function update($parent) {
|
||||
}
|
||||
}
|
||||
|
||||
// Testing
|
||||
if(defined('STDIN') ) {
|
||||
$xml = new XML($config);
|
||||
$test_cases = Array(
|
||||
);
|
||||
foreach($test_cases as $test) {
|
||||
try {
|
||||
$xml->readStr("<device></device>");
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
unset($resolver);
|
||||
}
|
||||
?>
|
@@ -1,105 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require(implode(DIRECTORY_SEPARATOR, array(
|
||||
__DIR__,
|
||||
'..',
|
||||
'..',
|
||||
'vendor',
|
||||
'autoload.php'
|
||||
)));
|
||||
|
||||
use PROVISION\TFTP;
|
||||
use PROVISION\ConfigParser;
|
||||
use PROVISION\Resolve;
|
||||
use PROVISION\Logger;
|
||||
use PROVISION\Utils;
|
||||
|
||||
class TFTPProvisioner extends TFTP\Server
|
||||
{
|
||||
private $_debug;
|
||||
private $_resolve;
|
||||
private $_settings_path;
|
||||
|
||||
function __construct($server_url, $config, $logger = NULL, $debug = false)
|
||||
{
|
||||
$this->_config = $config;
|
||||
if (!$logger) {
|
||||
$logger = new Logger_NULL('LOG_ERROR');
|
||||
}
|
||||
parent::__construct($server_url, $logger);
|
||||
$this->_debug = $debug;
|
||||
$this->max_put_size = 60000000;
|
||||
$this->_resolve = new Resolve($config);
|
||||
$this->_settings_path = $this->_config['main']['base_path'] . DIRECTORY_SEPARATOR
|
||||
. $this->_config['subdirs']['settings']['path'] . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
public function writable($peer, $req_filename)
|
||||
{
|
||||
$filename = $this->_settings_path . basename($req_filename);
|
||||
if (file_exists($filename)) {
|
||||
return is_writable($filename);
|
||||
}
|
||||
return is_writable($this->_settings_path);
|
||||
}
|
||||
|
||||
public function get($peer, $req_filename, $mode)
|
||||
{
|
||||
$filename = $this->_resolve->resolve($req_filename);
|
||||
if (file_exists($filename) && is_readable($filename))
|
||||
return file_get_contents($filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
public function put($peer, $req_filename, $mode, $content)
|
||||
{
|
||||
// (SPA phones can write to tftpboot -> redirect PUT request to 'settings' folder)
|
||||
$filename = $this->_settings_path . basename($req_filename);
|
||||
return file_put_contents($filename, $content);
|
||||
}
|
||||
|
||||
/*
|
||||
* STDOUT Log functions
|
||||
*/
|
||||
private function log($peer, $level, $message)
|
||||
{
|
||||
echo(date("H:i:s") . " $level $peer $message\n");
|
||||
}
|
||||
|
||||
public function log_debug($peer, $message)
|
||||
{
|
||||
if($this->_debug)
|
||||
$this->log($peer, "D", $message);
|
||||
}
|
||||
|
||||
public function log_info($peer, $message)
|
||||
{
|
||||
$this->log($peer, "I", $message);
|
||||
}
|
||||
|
||||
public function log_warning($peer, $message)
|
||||
{
|
||||
$this->log($peer, "W", $message);
|
||||
}
|
||||
|
||||
public function log_error($peer, $message)
|
||||
{
|
||||
$this->log($peer, "E", $message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$host = "127.0.0.1";
|
||||
$port = 10069;
|
||||
$url = "udp://$host:$port";
|
||||
$base_path = realpath(__DIR__ . DIRECTORY_SEPARATOR . "../..");
|
||||
|
||||
echo "\nStarting TFTP Provisioner...\n";
|
||||
$configParser = new ConfigParser($base_path, "config.ini");
|
||||
$server = new TFTPProvisioner($url, $configParser->getConfiguration(), $logger);
|
||||
if(!$server->loop($error))
|
||||
die("$error\n");
|
||||
?>
|
||||
|
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
require(implode(DIRECTORY_SEPARATOR, array(
|
||||
__DIR__,
|
||||
'..',
|
||||
'..',
|
||||
'vendor',
|
||||
'autoload.php'
|
||||
)));
|
||||
|
||||
use PROVISION\ConfigParser;
|
||||
use PROVISION\Resolve;
|
||||
$request = $_REQUEST ?? null;
|
||||
|
||||
function send_fallback_html($message) {
|
||||
global $request;
|
||||
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="
|
||||
<html>
|
||||
<header>
|
||||
</header>
|
||||
<body>
|
||||
<h1>provision_sccp</h1>
|
||||
<p>Request:" . json_encode($request) . "</p>
|
||||
<p>Message:" . $message . "</p>
|
||||
</body>
|
||||
</html>
|
||||
";
|
||||
print ($content);
|
||||
ob_flush();
|
||||
flush();
|
||||
}
|
||||
|
||||
function sendfile($filename) {
|
||||
if (file_exists($filename)) {
|
||||
while (ob_get_level()) {ob_end_clean();}
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Disposition: attachment; filename=' . basename($filename));
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate');
|
||||
header('Pragma: public');
|
||||
header('Content-Length: ' . filesize($filename));
|
||||
|
||||
/* want to stream out, so don't use file_get_contents() in this case */
|
||||
return readfile ($filename, FALSE);
|
||||
}
|
||||
}
|
||||
if (!$request || empty($request) || !array_key_exists('filename',$request) || empty($request['filename'])) {
|
||||
send_fallback_html("Empty 'filename' request sent");
|
||||
exit();
|
||||
}
|
||||
try {
|
||||
$base_path = realpath(__DIR__ . DIRECTORY_SEPARATOR . "../..");
|
||||
//global $base_path;
|
||||
$req_filename=$request['filename'];
|
||||
$configParser = new ConfigParser($base_path, "config.ini");
|
||||
$resolve = new Resolve($configParser->getConfiguration());
|
||||
if (($filename = $resolve->resolve($req_filename))) {
|
||||
sendfile($filename);
|
||||
}
|
||||
unset($resolve);
|
||||
} catch(Exception $e) {
|
||||
send_fallback_html($e->getMessage());
|
||||
}
|
||||
?>
|
@@ -1,31 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
require(implode(DIRECTORY_SEPARATOR, array(
|
||||
__DIR__,
|
||||
'..',
|
||||
'vendor',
|
||||
'autoload.php'
|
||||
)));
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PROVISION\ConfigParser as ConfigParser;
|
||||
|
||||
final class ConfigParserTest extends TestCase
|
||||
{
|
||||
public function testCanBeCreated(): void
|
||||
{
|
||||
$base_path = realpath(__DIR__ . DIRECTORY_SEPARATOR . "..");
|
||||
$configParser = new ConfigParser($base_path, "config.ini");
|
||||
$this->assertInstanceOf(
|
||||
ConfigParser::class,
|
||||
$configParser
|
||||
);
|
||||
}
|
||||
public function testCanGetConfig(): void
|
||||
{
|
||||
$base_path = realpath(__DIR__ . DIRECTORY_SEPARATOR . "..");
|
||||
$configParser = new ConfigParser($base_path, "config.ini");
|
||||
$config = $configParser->getConfiguration();
|
||||
$this->assertNotEmpty($config);
|
||||
}
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
require(implode(DIRECTORY_SEPARATOR, array(
|
||||
__DIR__,
|
||||
'..',
|
||||
'vendor',
|
||||
'autoload.php'
|
||||
)));
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PROVISION\ConfigParser as ConfigParser;
|
||||
use PROVISION\Resolve as Resolve;
|
||||
use PROVISION\ResolveResult as ResolveResult;
|
||||
|
||||
final class ResolverTest extends TestCase
|
||||
{
|
||||
private function getConfig()
|
||||
{
|
||||
$base_path = realpath(__DIR__ . DIRECTORY_SEPARATOR . "..");
|
||||
$configParser = new ConfigParser($base_path, "config.ini");
|
||||
return $configParser->getConfiguration();
|
||||
}
|
||||
|
||||
public function testCanBeCreated(): void
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
$resolve = new Resolve($config);
|
||||
$this->assertInstanceOf(
|
||||
Resolve::class,
|
||||
$resolve
|
||||
);
|
||||
}
|
||||
|
||||
private $test_cases = Array(
|
||||
Array('request' => 'jar70sccp.9-4-2ES26.sbn', 'expected' => '/data/firmware/7970/jar70sccp.9-4-2ES26.sbn'),
|
||||
Array('request' => 'Russian_Russian_Federation/be-sccp.jar', 'expected' => '/data/locales/languages/Russian_Russian_Federation/be-sccp.jar'),
|
||||
Array('request' => 'Spain/g3-tones.xml', 'expected' => '/data/locales/countries/Spain/g3-tones.xml'),
|
||||
Array('request' => '320x196x4/Chan-SCCP-b.png', 'expected' => '/data/wallpapers/320x196x4/Chan-SCCP-b.png'),
|
||||
Array('request' => 'XMLDefault.cnf.xml', 'expected' => '/data/settings/XMLDefault.cnf.xml'),
|
||||
Array('request' => '../XMLDefault.cnf.xml', 'expected' => ResolveResult::RequestContainsPathWalk),
|
||||
Array('request' => 'XMLDefault.cnf.xml/../../text.xml', 'expected' => ResolveResult::RequestContainsPathWalk),
|
||||
);
|
||||
|
||||
public function testCanResolveFiles(): void
|
||||
{
|
||||
$base_path = realpath(__DIR__ . DIRECTORY_SEPARATOR . "..");
|
||||
$config = $this->getConfig();
|
||||
|
||||
$resolve = new Resolve($config);
|
||||
foreach($this->test_cases as $test) {
|
||||
try {
|
||||
$result = $resolve->resolve($test['request']);
|
||||
if (is_string($result)) {
|
||||
$this->assertStringContainsString($result, $base_path . $test['expected']);
|
||||
} else {
|
||||
$this->assertEquals($result, $test['expected']);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
print("'" . $test['request'] . "' => throws error as expected\n");
|
||||
print("Exception: " . $e->getMessage() . "\n");
|
||||
}
|
||||
}
|
||||
unset($resolve);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user