Current File : //proc/thread-self/root/usr/local/lsws/admin/html.6.2.2/classes/CValidation.php |
<?php
class CValidation
{
protected $_info;
public function __construct() {
$this->_info = null;
}
public function ExtractPost($tbl, &$d, $disp)
{
$this->_info = $disp->_info;
$goFlag = 1 ;
$index = array_keys($tbl->_dattrs);
foreach ( $index as $i ) {
$attr = $tbl->_dattrs[$i];
if ( $attr == null || $attr->bypassSavePost())
continue;
$d[$attr->_key] = $attr->extractPost();
$needCheck = true;
if ( $attr->_type == 'sel1' || $attr->_type == 'sel2' ) {
if ( $disp->_act == 'c' ) {
$needCheck = false;
}
else {
$attr->populate_sel1_options($this->_info, $d);
}
}
if ( $needCheck ) {
$res = $this->validateAttr($attr, $d[$attr->_key]);
$this->setValid($goFlag, $res);
}
}
$res = $this->validatePostTbl($tbl, $d);
$this->setValid($goFlag, $res);
$this->_info = null;
// if 0 , make it always point to curr page
return $goFlag;
}
protected function checkListener(&$listener)
{
if ( $listener['secure']->GetVal() == '0' ) {
if ( isset($listener['certFile']) && !$listener['certFile']->HasVal() ) {
$listener['certFile']->SetErr(null);
}
if ( isset($listener['keyFile']) && !$listener['keyFile']->HasVal() ) {
$listener['keyFile']->SetErr(null);
}
} else {
$tids = array('L_SSL_CERT');
$this->validateElement($tids, $listener);
}
}
protected function validateElement($tids, &$data)
{
$tblDef = DTblDef::GetInstance();
$valid = 1;
foreach ( $tids as $tid ) {
$tbl = $tblDef->GetTblDef($tid);
$d = &DUtil::locateData( $data, $tbl->_dataLoc );
if ( $d == null ) continue;
if ( $tbl->_holderIndex != null ) {
$keys = array_keys( $d );
foreach( $keys as $key ) {
$res = $this->validateTblAttr($tblDef, $tbl, $d[$key]);
$this->setValid($valid, $res);
}
} else {
$res = $this->validateTblAttr($tblDef, $tbl, $d);
$this->setValid($valid, $res);
}
}
return $valid;
}
protected function setValid(&$valid, $res)
{
if ( $valid != -1 ) {
if ( $res == -1 ) {
$valid = -1;
} elseif ( $res == 0 && $valid == 1 ) {
$valid = 0;
}
}
if ( $res == 2 ) {
$valid = 2;
}
}
protected function validatePostTbl($tbl, &$d)
{
$isValid = 1;
if ( $tbl->_holderIndex != null && isset($d[$tbl->_holderIndex])) {
$newref = $d[$tbl->_holderIndex]->GetVal();
$oldref = null;
if(isset($this->_info['holderIndex_cur'])) {
$oldref = $this->_info['holderIndex_cur'];
}
//echo "oldref = $oldref newref = $newref \n";
if ( $oldref == null || $newref != $oldref ) {
if (isset($this->_info['holderIndex']) && $this->_info['holderIndex'] != null
&& in_array($newref, $this->_info['holderIndex']) ) {
$d[$tbl->_holderIndex]->SetErr('This value has been used! Please choose a unique one.');
$isValid = -1;
}
}
}
$checkedTids = array( 'VH_TOP_D', 'VH_BASE', 'VH_UDB',
'ADMIN_USR', 'ADMIN_USR_NEW',
'L_GENERAL', 'L_GENERAL1', 'ADMIN_L_GENERAL', 'ADMIN_L_GENERAL1', // WS
'L_GENERAL_NEW', 'L_GENERAL_DEL', 'LT_GENERAL_NEW', 'LT_GENERAL', // LSLB
'L_SSL_CERT',
'TP', 'TP1' ) ;
if ( in_array($tbl->_id, $checkedTids) ) {
switch ($tbl->_id) {
case 'TP':
case 'TP1':
$isValid = $this->chkPostTbl_TP($d);
break;
case 'VH_BASE':
case 'VH_TOP_D':
$isValid = $this->chkPostTbl_VH_BASE($d);
break;
case 'VH_UDB':
$isValid = $this->chkPostTbl_VH_UDB($d);
break;
case 'ADMIN_USR':
$isValid = $this->chkPostTbl_ADMIN_USR($d);
break;
case 'ADMIN_USR_NEW':
$isValid = $this->chkPostTbl_ADMIN_USR_NEW($d);
break;
case 'L_GENERAL_NEW': // for lb
case 'L_GENERAL_DEL':
case 'L_GENERAL':
case 'LT_GENERAL_NEW':
case 'LT_GENERAL':
case 'L_GENERAL1': // for ws
case 'ADMIN_L_GENERAL':
case 'ADMIN_L_GENERAL1':
$isValid = $this->chkPostTbl_L_GENERAL($d);
break;
case 'L_SSL_CERT':
$isValid = $this->chkPostTbl_L_SSL_CERT($d);
break;
}
}
return $isValid;
}
protected function chkPostTbl_TP(&$d)
{
$isValid = 1;
$confCenter = ConfCenter::singleton();
$oldName = trim($confCenter->GetDispInfo()->_name);
$newName = trim($d['name']->GetVal());
if($oldName != $newName && array_key_exists($newName, $confCenter->_serv->_data['tpTop'])) {
$d['name']->SetErr("Template: \"$newName\" already exists. Please use a different name.");
$isValid = -1;
}
return $isValid;
}
protected function chkPostTbl_VH_BASE(&$d)
{
$isValid = 1;
$confCenter = ConfCenter::singleton();
$oldName = trim($confCenter->GetDispInfo()->_name);
$newName = trim($d['name']->GetVal());
if($oldName != $newName && array_key_exists($newName, $confCenter->_serv->_data['vhTop'])) {
$d['name']->SetErr("Virtual Hostname: \"$newName\" already exists. Please use a different name.");
$isValid = -1;
}
return $isValid;
}
protected function chkPostTbl_VH_UDB(&$d)
{
$isValid = 1;
if ( $d['pass']->GetVal() != $d['pass1']->GetVal() ) {
$d['pass']->SetErr('Passwords do not match!');
$isValid = -1;
}
if ( !$d['pass']->HasVal() ) { //new user
$d['pass']->SetErr('Missing password!');
$isValid = -1;
}
if ( $isValid == -1 ) {
return -1;
}
if ( strlen($d['pass']->GetVal()) > 0 ) {
$newpass = $this->encryptPass($d['pass']->GetVal());
$d['passwd'] = new CVal($newpass);
}
return 1;
}
protected function encryptPass($val)
{
$pass = password_hash($val, PASSWORD_BCRYPT);
return $pass;
}
protected function chk_admname($name)
{
if (!$name->HasErr()) {
$val = $name->GetVal();
if (strlen($val) > 25) {
$name->SetErr('name cannot be longer than 25 characters');
} else {
$v1 = escapeshellcmd($val);
if (($v1 !== $val) || preg_match('/[:\/]/', $val)) {
$name->SetErr('invalid characters in name');
}
}
}
return $name->HasErr();
}
protected function chkPostTbl_ADMIN_USR(&$d)
{
$isValid = 1;
$this->chk_admname($d['name']);
if ($d['name']->HasErr()) {
$isValid = -1;
} elseif ( !$d['oldpass']->HasVal() ) {
$d['oldpass']->SetErr('Missing Old password!');
$isValid = -1;
} else {
$file = $_SERVER['LS_SERVER_ROOT'] . 'admin/conf/htpasswd';
$udb = ConfigFileEx::loadUserDB($file);
$olduser = $this->_info['holderIndex_cur'];
$passwd = $udb[$olduser]['passwd']->GetVal();
$oldpass = $d['oldpass']->GetVal();
$encypt = crypt($oldpass, $passwd);
if ( $encypt != $passwd ) {
$d['oldpass']->SetErr('Invalid old password!');
$isValid = -1;
}
}
if ( !$d['pass']->HasVal() ) {
$d['pass']->SetErr('Missing new password!');
$isValid = -1;
} elseif ( $d['pass']->GetVal() != $d['pass1']->GetVal() ) {
$d['pass']->SetErr('New passwords do not match!');
$isValid = -1;
}
if ( $isValid == -1 ) {
return -1;
}
$newpass = $this->encryptPass($d['pass']->GetVal());
$d['passwd'] = new CVal($newpass);
return 1;
}
protected function chkPostTbl_ADMIN_USR_NEW(&$d)
{
$isValid = 1;
$this->chk_admname($d['name']);
if ($d['name']->HasErr()) {
$isValid = -1;
}
if ( !$d['pass']->HasVal() ) {
$d['pass']->SetErr('Missing new password!');
$isValid = -1;
} elseif ( $d['pass']->GetVal() != $d['pass1']->GetVal() ) {
$d['pass']->SetErr('New passwords do not match!');
$isValid = -1;
}
if ( $isValid == -1 ) {
return -1;
}
$newpass = $this->encryptPass($d['pass']->GetVal());
$d['passwd'] = new CVal($newpass);
return 1;
}
protected function chkPostTbl_L_GENERAL(&$d)
{
$isValid = 1;
$ip = $d['ip']->GetVal();
if ( $ip == 'ANY' ) {
$ip = '*';
}
$port = $d['port']->GetVal();
$d['address'] = new CVal("$ip:$port");
$confCenter = ConfCenter::singleton();
$oldName = trim($confCenter->GetDispInfo()->_name);
$newName = trim($d['name']->GetVal());
if($oldName != $newName && array_key_exists($newName, $confCenter->_serv->_data['listeners'])) {
$d['name']->SetErr("Listener \"$newName\" already exists. Please use a different name.");
$isValid = -1;
}
return $isValid;
}
protected function isCurrentListenerSecure()
{
$confCenter = ConfCenter::singleton();
$listenerName = trim($confCenter->GetDispInfo()->_name);
$l = $confCenter->_serv->_data['listeners'][$listenerName];
return ($l['secure']->GetVal() == 1);
}
protected function chkPostTbl_L_SSL_CERT(&$d)
{
$isValid = 1;
if ($this->isCurrentListenerSecure()) {
$err = 'Value must be set for secured listener';
if (!$d['keyFile']->HasVal()) {
$d['keyFile']->SetErr($err);
$isValid = -1;
}
if (!$d['certFile']->HasVal()) {
$d['certFile']->SetErr($err);
$isValid = -1;
}
}
return $isValid;
}
protected function validateTblAttr($tblDef, $tbl, &$data)
{
$valid = 1;
if ( $tbl->_subTbls ) {
$tid = DUtil::getSubTid($tbl->_subTbls, $data);
if ( $tid == null ) {
return;
}
$tbl1 = $tblDef->GetTblDef($tid);
} else {
$tbl1 = $tbl;
}
$index = array_keys($tbl1->_dattrs);
foreach ( $index as $i ) {
$attr = $tbl1->_dattrs[$i];
if ( $attr->_type == 'sel1' || $attr->_type == 'sel2' ) {
$attr->populate_sel1_options($this->_info, $data);
}
$res = $this->validateAttr($attr, $data[$attr->_key]);
$this->setValid($valid, $res);
}
return $valid;
}
protected function validateAttr($attr, &$cvals)
{
$valid = 1;
if ( is_array($cvals) ) {
for ( $i = 0 ; $i < count($cvals) ; ++$i ) {
$res = $this->isValidAttr($attr, $cvals[$i]);
$this->setValid($valid, $res);
}
} else {
$valid = $this->isValidAttr($attr, $cvals);
}
return $valid;
}
protected function isValidAttr($attr, $cval)
{
if ($cval == null || $cval->HasErr())
return -1;
if ( !$cval->HasVal()) {
if ( $attr->_allowNull ) {
return 1;
}
$cval->SetErr('value must be set');
return -1;
}
if ( $attr->_type == 'cust' ) {
return 1;
}
$chktype = array('uint', 'name', 'vhname', 'dbname', 'sel','sel1','sel2',
'bool','file','filep','file0','file1', 'filetp', 'path', 'note',
'uri','expuri','url', 'httpurl', 'email', 'dir', 'addr', 'ipport', 'wsaddr', 'parse');
if ( !in_array($attr->_type, $chktype) ) {
// not checked type ('domain', 'subnet'
return 1;
}
$type3 = substr($attr->_type, 0, 3);
if ( $type3 == 'sel' ) {
// for sel, sel1, sel2
$funcname = 'chkAttr_sel';
}
elseif ( $type3 == 'fil' || $type3 == 'pat' ) {
$funcname = 'chkAttr_file';
}
else {
$funcname = 'chkAttr_' . $attr->_type;
}
if ( $attr->_multiInd == 1 ) {
$valid = 1;
$vals = DUtil::splitMultiple($cval->GetVal());
$err = [];
$funcname .= '_val';
foreach( $vals as $i=>$v ) {
$res = $this->$funcname($attr, $v, $err[$i]);
$this->setValid($valid, $res);
}
$cval->SetErr(trim(implode(' ', $err)));
return $valid;
}else {
return $this->$funcname($attr, $cval);
}
}
protected function chkAttr_sel($attr, $cval)
{
$err = '';
$res = $this->chkAttr_sel_val($attr, $cval->GetVal(), $err);
$cval->SetErr($err);
return $res;
}
protected function chkAttr_sel_val($attr, $val, &$err)
{
if ( isset( $attr->_maxVal )
&& !array_key_exists($val, $attr->_maxVal) ) {
$err = "invalid value: $val";
return -1;
}
return 1;
}
protected function chkAttr_name($attr, $cval)
{
$cval->SetVal( preg_replace("/\s+/", ' ', $cval->GetVal()));
$res = $this->chkAttr_name_val($attr, $cval->GetVal(), $err);
$cval->SetErr($err);
return $res;
}
protected function chkAttr_name_val($attr, $val, &$err)
{
if ( preg_match( "/[{}<>&%]/", $val) ) {
$err = 'invalid characters in name';
return -1;
}
if ( strlen($val) > 100 ) {
$err = 'name can not be longer than 100 characters';
return -1;
}
return 1;
}
protected function chkAttr_dbname($attr, $cval)
{
$cval->SetVal(preg_replace("/\s+/", ' ', $cval->GetVal()));
$val = $cval->GetVal();
if ( preg_match( "/[,;<>&%=\(\)\"']/", $val ) ) {
$cval->SetErr('Invalid characters found in name');
return -1;
}
if ( strpos($val, ' ') !== false ) {
$cval->SetErr('No space allowed in the name');
return -1;
}
if ( strlen($val) > 100 ) {
$cval->SetErr('name can not be longer than 100 characters');
return -1;
}
return 1;
}
protected function chkAttr_note($attr, $cval)
{
$m = [];
if (preg_match("/[{}<]/", $cval->GetVal(), $m)) { // avoid <script, also {} for conf format
$cval->SetErr("character $m[0] not allowed");
return -1;
}
return 1;
}
protected function chkAttr_vhname($attr, $cval)
{
$res = $this->chkAttr_dbname($attr, $cval);
if ($res == 1) {
$this->_info['VH_NAME'] = $cval->GetVal();
}
return $res;
}
protected function allow_create($attr, $absname)
{
if (strpos($attr->_maxVal, 'c') === false) {
return false;
}
if ($attr->_minVal >= 2 && ( strpos($absname, $_SERVER['LS_SERVER_ROOT']) === 0 )) {
return true;
}
if (isset($this->_info['VH_ROOT'])) {
$VH_ROOT = $this->_info['VH_ROOT'];
} else {
$VH_ROOT = null;
}
if (isset($this->_info['DOC_ROOT'])) {
$DOC_ROOT = $this->_info['DOC_ROOT'];
}
if ($attr->_minVal >= 3 && ( strpos($absname, $VH_ROOT) === 0 )) {
return true;
}
if ($attr->_minVal == 4 && ( strpos($absname, $DOC_ROOT) === 0 )) {
return true;
}
return false;
}
protected function clean_absolute_path($abspath)
{
$absname = PathTool::clean($abspath);
if ( isset( $_SERVER['LS_CHROOT'] ) ) {
$root = $_SERVER['LS_CHROOT'];
$len = strlen($root);
if ( strncmp( $absname, $root, $len ) == 0 ) {
$absname = substr($absname, $len);
}
}
return $absname;
}
protected function test_file(&$absname, &$err, $attr)
{
$absname = $this->clean_absolute_path($absname);
if ($attr->_type == 'file0') {
if (!file_exists($absname)) {
return 1; //allow non-exist
}
}
if ($attr->_type == 'path' || $attr->_type == 'filep' || $attr->_type == 'dir') {
$type = 'path';
} else {
$type = 'file';
}
if (($type == 'path' && !is_dir($absname)) || ($type == 'file' && !is_file($absname))) {
$err = $type . ' ' . htmlspecialchars($absname) . ' does not exist.';
if ($this->allow_create($attr, $absname)) {
$err .= ' <a href="javascript:createFile(\'' . $attr->_htmlName . '\')">CLICK TO CREATE</a>';
} else {
$err .= ' Please create manually.';
}
return -1;
}
if ((strpos($attr->_maxVal, 'r') !== false) && !is_readable($absname)) {
$err = $type . ' ' . htmlspecialchars($absname) . ' is not readable';
return -1;
}
if ((strpos($attr->_maxVal, 'w') !== false) && !is_writable($absname)) {
$err = $type . ' ' . htmlspecialchars($absname) . ' is not writable';
return -1;
}
if ((strpos($attr->_maxVal, 'x') !== false) && !is_executable($absname)) {
$err = $type . ' ' . htmlspecialchars($absname) . ' is not executable';
return -1;
}
return 1;
}
protected function chkAttr_file($attr, $cval)
{
$val = $cval->GetVal();
$err = '';
$res = $this->chkAttr_file_val($attr, $val, $err);
$cval->SetVal($val);
$cval->SetErr($err);
return $res;
}
protected function chkAttr_dir($attr, $cval)
{
$val = $cval->GetVal();
$err = '';
if ( substr($val,-1) == '*' ) {
$res = $this->chkAttr_file_val($attr, substr($val,0,-1), $err);
} else {
$res = $this->chkAttr_file_val($attr, $val, $err);
}
$cval->SetVal($val);
$cval->SetErr($err);
return $res;
}
protected function isNotAllowedPath($path)
{
$blocked = '/admin/html/';
if (strpos($path, $blocked) !== false) {
return true;
}
return false;
}
protected function isNotAllowedExtension($path)
{
$ext = substr($path, -4);
$notallowed = ['.php', '.cgi', '.pl', '.shtml'];
foreach ($notallowed as $test) {
if (strcasecmp($ext, $test) == 0) {
return true;
}
}
return false;
}
protected function check_cmd_invalid_str($cmd)
{
// check if it's allowed command, do not allow ' " -c -i /dev/tcp bash sh csh tcsh zsh ksh
$cmd = str_replace('.', 'a', $cmd); // replace . with char before pattern check
$pattern = '#("|\'|;|-c|-i|/dev/tcp|curl|wget|fetch|\Wbash\W|\Wsh\W|\Wcsh\W|\Wtcsh\W|\Wzsh\W|\Wksh\W)#';
$m = [];
if (preg_match($pattern, $cmd, $m)) {
return $m[0];
}
$cmd = str_replace('\\', '', $cmd); // remove all escape & try again
if (preg_match($pattern, $cmd, $m)) {
return $m[0];
}
return null;
}
public function chkAttr_file_val($attr, $val, &$err)
{
// apply to all
if ($this->isNotAllowedPath($val)) {
$err = 'Directory not allowed';
return -1;
}
if ( $attr->_type == 'file0' && $this->isNotAllowedExtension($val)) {
$err = 'File extension not allowed';
return -1;
}
clearstatcache();
$err = null;
if ( $attr->_type == 'filep' ) {
$path = substr($val, 0, strrpos($val,'/'));
} else {
$path = $val;
if ($attr->_type == 'file1') { // file1 is command
$invalid_str = $this->check_cmd_invalid_str($path);
if ($invalid_str) {
$err = 'Cannot contain string ' . htmlspecialchars($invalid_str, ENT_QUOTES);
return -1;
}
$pos = strpos($val, ' ');
if ($pos > 0) {
$path = substr($val, 0, $pos); // check first part is valid path
}
}
}
$res = $this->chk_file1($attr, $path, $err);
if ($attr->_type == 'filetp') {
$pathtp = $_SERVER['LS_SERVER_ROOT'] . 'conf/templates/';
if (strstr($path, $pathtp) === false) {
$err = ' Template file must locate within $SERVER_ROOT/conf/templates/';
$res = -1;
}
else if (substr($path, -4) != '.xml') {
$err = ' Template file name needs to be ".xml"';
$res = -1;
}
}
if ($res == -1 && $_POST['file_create'] == $attr->_htmlName && $this->allow_create($attr,
$path)) {
if (PathTool::createFile($path, $err, $attr->_htmlName)) {
$err = "$path has been created successfully.";
}
$res = 0; // make it always point to curr page
}
if ( $attr->_key == 'vhRoot' ) {
if ( substr($path,-1) != '/' ) {
$path .= '/';
}
if ($res == -1) {
// do not check path for vhroot, it may be different owner
$err = '';
$res = 1;
}
$this->_info['VH_ROOT'] = $path;
}
elseif ($attr->_key == 'docRoot') {
if ($res == -1) {
// do not check path for vhroot, it may be different owner
$err = '';
$res = 1;
}
}
return $res;
}
protected function chk_file1($attr, &$path, &$err)
{
if ($this->get_abs_path($attr->_minVal, $path, $err) == 1) {
return $this->test_file($path, $err, $attr);
}
}
protected function get_cleaned_abs_path($attr_minVal, &$path, &$err)
{
if ($this->get_abs_path($attr_minVal, $path, $err) == 1) {
$absname = $this->clean_absolute_path($path);
return $absname;
}
return null;
}
protected function get_abs_path($attr_minVal, &$path, &$err)
{
if(!strlen($path)) {
$err = "Invalid Path.";
return -1;
}
$s = substr($path, 0, 1);
if ( strpos($path, '$VH_NAME') !== false ) {
$path = str_replace('$VH_NAME', $this->_info['VH_NAME'], $path);
}
if ( $s == '/' ) {
return 1;
}
if ( $attr_minVal == 1 ) {
$err = 'only accept absolute path';
return -1;
}
elseif ( $attr_minVal == 2 ) {
if (strncasecmp('$SERVER_ROOT', $path, 12) == 0) {
$path = $_SERVER['LS_SERVER_ROOT'] . substr($path, 13);
} elseif ($s == '$') {
$err = 'only accept absolute path or path relative to $SERVER_ROOT: ' . $path;
return -1;
} else {
$path = $_SERVER['LS_SERVER_ROOT'] . $path; // treat as relative to SERVER_ROOT
}
}
elseif ( $attr_minVal == 3 ) {
if ( strncasecmp('$SERVER_ROOT', $path, 12) == 0 ) {
$path = $_SERVER['LS_SERVER_ROOT'] . substr($path, 13);
} elseif ( strncasecmp('$VH_ROOT', $path, 8) == 0 ) {
if (isset($this->_info['VH_ROOT'])) {
$path = $this->_info['VH_ROOT'] . substr($path, 9);
}
} elseif ($s == '$') {
$err = 'only accept absolute path or path relative to $SERVER_ROOT or $VH_ROOT';
return -1;
} else {
$path = $_SERVER['LS_SERVER_ROOT'] . $path; // treat as relative to SERVER_ROOT
}
}
elseif ( $attr_minVal == 4 ) {
if ( strncasecmp('$SERVER_ROOT', $path, 12) == 0 ) {
$path = $_SERVER['LS_SERVER_ROOT'] . substr($path, 13);
} elseif ( strncasecmp('$VH_ROOT', $path, 8) == 0 ) {
$path = $this->_info['VH_ROOT'] . substr($path, 9);
} elseif ( strncasecmp('$DOC_ROOT', $path, 9) == 0 ) {
$path = $this->_info['DOC_ROOT'] . substr($path, 10);
} else {
$path = $this->_info['DOC_ROOT'] . $path;
}
}
return 1;
}
protected function chkAttr_uri($attr, $cval)
{
$val = $cval->GetVal();
if ( $val[0] != '/' ) {
$cval->SetErr('URI must start with "/"');
return -1;
}
return 1;
}
protected function chkAttr_expuri($attr, $cval)
{
$val = $cval->GetVal();
if ( substr($val, 0, 1) == '/' || strncmp( $val, 'exp:', 4 ) == 0 ) {
return 1;
}
$cval->SetErr('URI must start with "/" or "exp:"');
return -1;
}
protected function chkAttr_url($attr, $cval)
{
$val = $cval->GetVal();
if (( substr($val, 0, 1) != '/' ) && ( strncmp($val, 'http://', 7) != 0 ) && ( strncmp($val, 'https://', 8) != 0 )) {
$cval->SetErr('URL must start with "/" or "http(s)://"');
return -1;
}
return 1;
}
protected function chkAttr_httpurl($attr, $cval)
{
$val = $cval->GetVal();
if (strncmp($val, 'http://', 7) != 0) {
$cval->SetErr('Http URL must start with "http://"');
return -1;
}
return 1;
}
protected function chkAttr_email($attr, $cval)
{
$err = '';
$res = $this->chkAttr_email_val($attr, $cval->GetVal(), $err);
$cval->SetErr($err);
return $res;
}
protected function chkAttr_email_val($attr, $val, &$err)
{
if ( preg_match("/^[[:alnum:]._-]+@.+/", $val ) ) {
return 1;
}
$err = 'invalid email format: ' . $val;
return -1;
}
protected function isUdsAddr($v)
{
$m = [];
// check UDS:// unix:
if (preg_match('/^(UDS:\/\/|unix:)(.+)$/i', $v, $m)) {
$v = $m[2];
$supportedvar = ['$SERVER_ROOT', '$VH_NAME', '$VH_ROOT', '$DOC_ROOT'];
$v = str_replace($supportedvar, 'VAR', $v);
if (preg_match("/^[a-z0-9\-_\/\.]+$/i", $v)) {
return 1;
}
}
return 0;
}
protected function chkAttr_addr($attr, $cval)
{
$v = $cval->GetVal();
if (preg_match("/^([[:alnum:]._-]+|\[[[:xdigit:]:]+\]):(\d)+$/", $v)) {
return 1;
}
if ($this->isUdsAddr($v)) {
return 1;
}
$cval->SetErr('invalid address: correct syntax is "IPV4|IPV6_address:port" or UDS://path or unix:path');
return -1;
}
protected function chkAttr_ipport($attr, $cval)
{
if ( preg_match("/^([[:alnum:]._-]+|\[[[:xdigit:]:]+\]|\*):(\d)+$/", $cval->GetVal()) ) {
return 1;
}
$cval->SetErr('invalid address: correct syntax is "IPV4|IPV6_address:port" or "*:port" for any IP.');
return -1;
}
protected function chkAttr_wsaddr($attr, $cval)
{
$v = $cval->GetVal();
if ( preg_match("/^((http|https):\/\/)?([[:alnum:]._-]+|\[[[:xdigit:]:]+\])(:\d+)?$/", $v) ) {
return 1;
}
if ($this->isUdsAddr($v)) {
return 1;
}
$cval->SetErr('invalid address: correct syntax is "[http|https://]IPV4|IPV6_address[:port]" or Unix Domain Socket address "UDS://path or unix:path".');
return -1;
}
protected function chkAttr_bool($attr, $cval)
{
$val = $cval->GetVal();
if ( $val === '1' || $val === '0' ) {
return 1;
}
$cval->SetErr('invalid value');
return -1;
}
protected function chkAttr_parse($attr, $cval)
{
$err = '';
$res = $this->chkAttr_parse_val($attr, $cval->GetVal(), $err);
$cval->SetErr($err);
return $res;
}
protected function chkAttr_parse_val($attr, $val, &$err)
{
if (preg_match($attr->_minVal, $val)) {
return 1;
}
if ($attr->_maxVal) {
$err = "invalid format - $val, please check syntax";
} else {
$err = "invalid value - $val";
}
return -1;
}
protected function getKNum($strNum)
{
$tag = substr($strNum, -1);
switch( $tag ) {
case 'K':
case 'k': $multi = 1024; break;
case 'M':
case 'm': $multi = 1048576; break;
case 'G':
case 'g': $multi = 1073741824; break;
default: return intval($strNum);
}
return (intval(substr($strNum, 0, -1)) * $multi);
}
protected function chkAttr_uint($attr, $cval)
{
$val = $cval->GetVal();
if ( preg_match("/^(-?\d+)([KkMmGg]?)$/", $val) ) {
$val1 = $this->getKNum($val);
if (isset($attr->_minVal)) {
$min = $this->getKNum($attr->_minVal);
if ($val1 < $min) {
$cval->SetErr('number is less than the minumum required');
return -1;
}
}
if (isset($attr->_maxVal)) {
$max = $this->getKNum($attr->_maxVal);
if ( $val1 > $max ) {
$cval->SetErr('number exceeds maximum allowed');
return -1;
}
}
return 1;
}
$cval->SetErr('invalid number format');
return -1;
}
protected function chkDups(&$data, &$checkList, $key)
{
if ( in_array( $data[$key]->GetVal(), $checkList ) ) {
$data[$key]->SetErr( "This $key \"" . $data[$key]->GetVal() . '\" already exists. Please enter a different one.');
return false;
}
return true;
}
protected function chkExtApp(&$data, &$attr)
{
$isValid = true;
if ( $data['autoStart']->GetVal() ) {
if ( !$data['path']->HasVal() ) {
$data['path']->SetErr('must provide path when autoStart is enabled');
$isValid = false;
}
if ( !$data['backlog']->HasVal() ) {
$data['backlog']->SetErr('must enter backlog value when autoStart is enabled');
$isValid = false;
}
if ( !$data['instances']->HasVal() ) {
$data['instances']->SetErr('must give number of instances when autoStart is enabled');
$isValid = false;
}
}
if ( isset($attr['names']) && (!$this->chkDups($to, $attr['names'], 'name')) ) {
$isValid = false;
}
return $isValid;
}
protected function chkScriptHandler(&$to, &$attr)
{
$vals = DUtil::splitMultiple( $to['suffix']->GetVal() );
$isValid = true;
foreach( $vals as $suffix ) {
if ( in_array( $suffix, $attr['names'] ) ) {
$t[] = $suffix;
$isValid = false;
}
}
if ( !$isValid ) {
$to['suffix']->SetErr(' Suffix ' . implode(', ', $t) . ' already exists. Please use a different suffix.');
}
return $isValid;
}
}