File manager - Edit - /usr/local/lswsbak/admin/html.open/lib/CValidation.php
Back
<?php class CValidation { protected $_disp; protected $_go_flag; public function __construct() { } public function ExtractPost($disp) { $this->_disp = $disp; $this->_go_flag = 1; $tid = $disp->GetLast(DInfo::FLD_TID); $tbl = DTblDef::GetInstance()->GetTblDef($tid); $extracted = new CNode(CNode::K_EXTRACTED, '', CNode::T_KB); $attrs = $tbl->Get(DTbl::FLD_DATTRS); foreach ($attrs as $attr) { if ($attr->bypassSavePost()) { continue; } $needCheck = $attr->extractPost($extracted); if ($needCheck) { if ($attr->_type == 'sel1' || $attr->_type == 'sel2') { if ($this->_disp->Get(DInfo::FLD_ACT) == 'c') { $needCheck = false; // for changed top category } else { $attr->SetDerivedSelOptions($disp->GetDerivedSelOptions($tid, $attr->_minVal, $extracted)); } } $dlayer = $extracted->GetChildren($attr->GetKey()); if ($needCheck) { $this->validateAttr($attr, $dlayer); } if (($tid == 'V_TOPD' || $tid == 'V_BASE') && $attr->_type == 'vhname') { $vhname = $dlayer->Get(CNode::FLD_VAL); $disp->Set(DInfo::FLD_ViewName, $vhname); } } } $res = $this->validatePostTbl($tbl, $extracted); $this->setValid($res); // if 0 , make it always point to curr page if ($this->_go_flag <= 0) { $extracted->SetErr('Input error detected. Please resolve the error(s). '); } $this->_disp = null; return $extracted; } protected function setValid($res) { if ($this->_go_flag != -1) { if ($res == -1) { $this->_go_flag = -1; } elseif ($res == 0 && $this->_go_flag == 1) { $this->_go_flag = 0; } } if ($res == 2) { $this->_go_flag = 2; } } protected function validatePostTbl($tbl, $extracted) { $tid = $tbl->Get(DTbl::FLD_ID); if (($index = $tbl->Get(DTbl::FLD_INDEX)) != null) { $keynode = $extracted->GetChildren($index); if ($keynode != null) { $holderval = $keynode->Get(CNode::FLD_VAL); $extracted->SetVal($holderval); if ($holderval != $this->_disp->GetLast(DInfo::FLD_REF)) { // check conflict $ref = $this->_disp->GetParentRef(); $location = DPageDef::GetPage($this->_disp)->GetTblMap()->FindTblLoc($tid); if ($location[0] == '*') { // allow multiple $confdata = $this->_disp->Get(DInfo::FLD_ConfData); $existingkeys = $confdata->GetChildrenValues($location, $ref); if (in_array($holderval, $existingkeys)) { $keynode->SetErr('This value has been used! Please choose a unique one.'); return -1; } } } } } if (($defaultExtract = $tbl->Get(DTbl::FLD_DEFAULTEXTRACT)) != null) { foreach ($defaultExtract as $k => $v) { $extracted->AddChild(new CNode($k, $v)); } } $view = $this->_disp->Get(DInfo::FLD_View); if ($tid == 'L_GENERAL' || $tid == 'ADM_L_GENERAL') { return $this->chkPostTbl_L_GENERAL($extracted); } elseif ($view == 'sl' || $view == 'al') { // will ignore vhlevel if ($tid == 'LVT_SSL_CERT') { return $this->chkPostTbl_L_SSL_CERT($extracted); } } elseif ($view == 'admin') { if ($tid == 'ADM_USR') { return $this->chkPostTbl_ADM_USR($extracted); } elseif ($tid == 'ADM_USR_NEW') { return $this->chkPostTbl_ADM_USR_NEW($extracted); } } elseif ($tid == 'V_UDB') { return $this->chkPostTbl_ADM_USR_NEW($extracted); } return 1; } protected function encryptPass($val) { $valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/."; $limit = strlen($valid_chars) - 1; $isMac = (strtoupper(PHP_OS) === 'DARWIN'); if (CRYPT_MD5 == 1 && !$isMac) { $salt = '$1$'; for ($i = 0; $i < 8; $i++) { $salt .= $valid_chars[rand(0, $limit)]; } $salt .= '$'; } else { $salt = $valid_chars[rand(0, $limit)]; $salt .= $valid_chars[rand(0, $limit)]; } $pass = crypt($val, $salt); return $pass; } protected function chkPostTbl_ADM_USR($d) { $isValid = 1; $oldpass = $d->GetChildVal('oldpass'); if ($oldpass == null) { $d->SetChildErr('oldpass', 'Missing Old password!'); $isValid = -1; } else { $file = SERVER_ROOT . 'admin/conf/htpasswd'; $udb = $this->_disp->Get(DInfo::FLD_ConfData); $oldusername = $this->_disp->GetLast(DInfo::FLD_REF); $passwd = $udb->GetChildVal('*index$name:passwd', $oldusername); $encypt = crypt($oldpass, $passwd); if ($encypt != $passwd) { $d->SetChildErr('oldpass', 'Invalid old password!'); $isValid = -1; } } $pass = $d->GetChildVal('pass'); if ($pass == null) { $d->SetChildErr('pass', 'Missing new password!'); $isValid = -1; } elseif ($pass != $d->GetChildVal('pass1')) { $d->SetChildErr('pass', 'New passwords do not match!'); $isValid = -1; } if ($isValid == -1) { return -1; } $newpass = $this->encryptPass($pass); $d->AddChild(new CNode('passwd', $newpass)); return 1; } protected function chkPostTbl_ADM_USR_NEW($d) { $isValid = 1; $pass = $d->GetChildVal('pass'); if ($pass == null) { $d->SetChildErr('pass', 'Missing new password!'); $isValid = -1; } elseif ($pass != $d->GetChildVal('pass1')) { $d->SetChildErr('pass', 'New passwords do not match!'); $isValid = -1; } if ($isValid == -1) { return -1; } $newpass = $this->encryptPass($pass); $d->AddChild(new CNode('passwd', $newpass)); return 1; } protected function chkPostTbl_L_GENERAL($d) { $isValid = 1; $ip = $d->GetChildVal('ip'); $port = $d->GetChildVal('port'); $is_v6ip = ($ip == '[ANY]') || (strpos($ip, ':') !== false); $confdata = $this->_disp->Get(DInfo::FLD_ConfData); $lastref = $this->_disp->GetLast(DInfo::FLD_REF); $nodes = $confdata->GetRootNode()->GetChildren('listener'); foreach ($nodes as $ref => $node) { if ($ref == $lastref) { continue; } $nodeport = $node->GetChildVal('port'); if ($port != $nodeport) { continue; } $nodeip = $node->GetChildVal('ip'); $is_v6node = ($nodeip == '[ANY]') || (strpos($nodeip, ':') !== false); if (($ip == $nodeip) || ($ip == '[ANY]' && $is_v6node) || ($is_v6ip && $nodeip == '[ANY]') || ($ip == 'ANY' && !$is_v6node) || (!$is_v6ip && $nodeip == 'ANY')) { // ANY is IPv4, [ANY] is IPv6 $d->SetChildErr('port', 'This port is already in use.'); $isValid = -1; break; } } $ip0 = ($ip == 'ANY') ? '*' : $ip; $d->AddChild(new CNode('address', "$ip0:$port")); return $isValid; } protected function isCurrentListenerSecure() { $confdata = $this->_disp->Get(DInfo::FLD_ConfData); $listener = $confdata->GetChildNodeById('listener', $this->_disp->Get(DInfo::FLD_ViewName)); $secure = $listener->GetChildVal('secure'); return ($secure == 1); } protected function chkPostTbl_L_SSL_CERT($d) { $isValid = 1; if ($this->isCurrentListenerSecure()) { $err = 'Value must be set for secured listener. '; if ($d->GetChildVal('keyFile') == null) { $d->SetChildErr('keyFile', $err); $isValid = -1; } if ($d->GetChildVal('certFile') == null) { $d->SetChildErr('certFile', $err); $isValid = -1; } } return $isValid; } protected function validateAttr($attr, $dlayer) { if (is_array($dlayer)) { foreach ($dlayer as $node) { $res = $this->isValidAttr($attr, $node); $this->setValid($res); } } else { $res = $this->isValidAttr($attr, $dlayer); $this->setValid($res); } } protected function isValidAttr($attr, $node) { if ($node == null || $node->HasErr()) { return -1; } if (!$node->HasVal()) { if (!$attr->IsFlagOn(DAttr::BM_NOTNULL)) { return 1; } $node->SetErr('value must be set. '); return -1; } $notchk = array('cust', 'domain', 'subnet'); if (in_array($attr->_type, $notchk)) { return 1; } $chktype = array('uint', 'name', 'vhname', 'dbname', 'admname', 'sel', 'sel1', 'sel2', 'bool', 'file', 'filep', 'file0', 'file1', 'filetp', 'filevh', 'path', 'note', 'uri', 'expuri', 'url', 'httpurl', 'email', 'dir', 'addr', 'wsaddr', 'parse'); if (!in_array($attr->_type, $chktype)) { 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) { $vals = preg_split("/, /", $node->Get(CNode::FLD_VAL), -1, PREG_SPLIT_NO_EMPTY); $err = []; $funcname .= '_val'; foreach ($vals as $i => $v) { $res = $this->$funcname($attr, $v, $err[$i]); $this->setValid($res); } $error = trim(implode(' ', $err)); if ($error != '') $node->SetErr($error); return 1; } else { return $this->$funcname($attr, $node); } } protected function chkAttr_sel($attr, $node) { $err = ''; $res = $this->chkAttr_sel_val($attr, $node->Get(CNode::FLD_VAL), $err); if ($err != '') { $node->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_admname($attr, $node) { $val = preg_replace("/\s+/", ' ', $node->Get(CNode::FLD_VAL)); $node->SetVal($val); $err = ''; if (strlen($val) > 25) { $err = 'name cannot be longer than 25 characters'; } else { $v1 = escapeshellcmd($val); if ($v1 !== $val) { $err = 'invalid characters in name'; } } if ($err != '') { $node->SetErr($err); return -1; } return 1; } protected function chkAttr_name($attr, $node) { $node->SetVal(preg_replace("/\s+/", ' ', $node->Get(CNode::FLD_VAL))); $res = $this->chkAttr_name_val($attr, $node->Get(CNode::FLD_VAL), $err); if ($err != '') { $node->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 cannot be longer than 100 characters'; return -1; } return 1; } protected function chkAttr_note($attr, $node) { $m = []; if (preg_match("/[{}<]/", $node->Get(CNode::FLD_VAL), $m)) { // avoid <script, also {} for conf format $node->SetErr("character $m[0] not allowed"); return -1; } return 1; } protected function chkAttr_dbname($attr, $node) { return $this->chkAttr_vhname($attr, $node); } protected function chkAttr_vhname($attr, $node) { $node->SetVal(preg_replace("/\s+/", ' ', $node->Get(CNode::FLD_VAL))); $val = $node->Get(CNode::FLD_VAL); if (preg_match("/[,;<>&%=\(\)\"']/", $val)) { $node->SetErr('Invalid characters found in name'); return -1; } if (strpos($val, ' ') !== false) { $node->SetErr('No space allowed in the name'); return -1; } if (strlen($val) > 100) { $node->SetErr('name can not be longer than 100 characters'); return -1; } return 1; } protected function allow_create($attr, $absname) { if (strpos($attr->_maxVal, 'c') === false) { return false; } if ($attr->_minVal >= 2 && ( strpos($absname, SERVER_ROOT) === 0 )) { return true; } //other places need to manually create return false; } 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 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) { if ($attr->_maxVal == null) { return 1; // no permission test } $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:lst_createFile(\'' . $attr->GetKey() . '\')">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; } return 1; } protected function chkAttr_file($attr, $node) { $val = $node->Get(CNode::FLD_VAL); $err = ''; $res = $this->chkAttr_file_val($attr, $val, $err); $node->SetVal($val); if ($err != '') { $node->SetErr($err); } return $res; } protected function chkAttr_dir($attr, $node) { $val = $node->Get(CNode::FLD_VAL); $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); } $node->SetVal($val); if ($err != '') { $node->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 ksh zsh $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_ROOT . 'conf/templates/'; if (strstr($path, $pathtp) === false) { $err = ' Template file must locate within $SERVER_ROOT/conf/templates/'; $res = -1; } else if (substr($path, -5) != '.conf') { $err = ' Template file name needs to be ".conf"'; $res = -1; } } elseif ($attr->_type == 'filevh') { $pathvh = SERVER_ROOT . 'conf/vhosts/'; if (strstr($path, $pathvh) === false) { $err = ' VHost config file must locate within $SERVER_ROOT/conf/vhosts/, suggested value is $SERVER_ROOT/conf/vhosts/$VH_NAME/vhconf.conf'; $res = -1; } else if (substr($path, -5) != '.conf') { $err = ' VHost config file name needs to be ".conf"'; $res = -1; } } if ($res == -1 && isset($_POST['file_create']) && $_POST['file_create'] == $attr->GetKey() && $this->allow_create($attr, $path)) { if (PathTool::createFile($path, $err, $attr->GetKey())) { $err = "$path has been created successfully."; } $res = 0; // make it always point to curr page } return $res; } 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->_disp->Get(DInfo::FLD_ViewName), $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_ROOT . substr($path, 13); } elseif ($s == '$') { $err = 'only accept absolute path or path relative to $SERVER_ROOT: ' . $path; return -1; } else { $path = SERVER_ROOT . $path; // treat as relative to SERVER_ROOT } } elseif ($attr_minVal == 3) { if (strncasecmp('$SERVER_ROOT', $path, 12) == 0) { $path = SERVER_ROOT . substr($path, 13); } elseif (strncasecmp('$VH_ROOT', $path, 8) == 0) { $vhroot = $this->_disp->GetVHRoot(); if ($vhroot == null) { $err = 'Fail to find $VH_ROOT'; return -1; } $path = $vhroot . substr($path, 9); } elseif ($s == '$') { $err = 'only accept absolute path or path relative to $SERVER_ROOT or $VH_ROOT: ' . $path; return -1; } else { $path = SERVER_ROOT . $path; // treat as relative to SERVER_ROOT } } return 1; } protected function chk_file1($attr, &$path, &$err) { $res = $this->get_abs_path($attr->_minVal, $path, $err); if ($res == 1) { return $this->test_file($path, $err, $attr); } return $res; } protected function chkAttr_uri($attr, $node) { $val = $node->Get(CNode::FLD_VAL); if ($val[0] != '/') { $node->SetErr('URI must start with "/"'); return -1; } return 1; } protected function chkAttr_expuri($attr, $node) { $val = $node->Get(CNode::FLD_VAL); if (substr($val, 0, 1) == '/' || strncmp($val, 'exp:', 4) == 0) { return 1; } $node->SetErr('URI must start with "/" or "exp:"'); return -1; } protected function chkAttr_url($attr, $node) { $val = $node->Get(CNode::FLD_VAL); if (( substr($val, 0, 1) != '/' ) && ( strncmp($val, 'http://', 7) != 0 ) && ( strncmp($val, 'https://', 8) != 0 )) { $node->SetErr('URL must start with "/" or "http(s)://"'); return -1; } return 1; } protected function chkAttr_httpurl($attr, $node) { $val = $node->Get(CNode::FLD_VAL); if (strncmp($val, 'http://', 7) != 0) { $node->SetErr('Http URL must start with "http://"'); return -1; } return 1; } protected function chkAttr_email($attr, $node) { $err = ''; $res = $this->chkAttr_email_val($attr, $node->Get(CNode::FLD_VAL), $err); if ($err != '') { $node->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 chkAttr_addr($attr, $node) { $v = $node->Get(CNode::FLD_VAL); if (preg_match("/^([[:alnum:]._-]+|\[[[:xdigit:]:]+\]):(\d)+$/", $v)) { return 1; } if ($this->isUdsAddr($v)) { return 1; } $node->SetErr('invalid address: correct syntax is "IPV4|IPV6_address:port" or UDS://path or unix:path'); return -1; } protected function isUdsAddr($v) { // check UDS:// unix: $m = []; 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_wsaddr($attr, $node) { $v = $node->Get(CNode::FLD_VAL); if (preg_match("/^((http|https):\/\/)?([[:alnum:]._-]+|\[[[:xdigit:]:]+\])(:\d+)?$/", $v)) { return 1; } if ($this->isUdsAddr($v)) { return 1; } $node->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, $node) { $val = $node->Get(CNode::FLD_VAL); if ($val === '1' || $val === '0') { return 1; } $node->SetErr('invalid value'); return -1; } protected function chkAttr_parse($attr, $node) { $err = ''; $res = $this->chkAttr_parse_val($attr, $node->Get(CNode::FLD_VAL), $err); if ($err != '') { $node->SetErr($err); } return $res; } protected function chkAttr_parse_val($attr, $val, &$err) { if (preg_match($attr->_minVal, $val)) { return 1; } if ($attr->_maxVal) { // has parse_help $err = "invalid format \"$val\". Syntax is {$attr->_minVal} - {$attr->_maxVal}"; } else { // when no parse_help, do not show syntax, e.g. used for not allowed value. $err = "invalid value \"$val\"."; } return -1; } protected function getKNum($strNum) { $tag = strtoupper(substr($strNum, -1)); switch ($tag) { case 'K': $multi = 1024; break; case 'M': $multi = 1048576; break; case 'G': $multi = 1073741824; break; default: return intval($strNum); } return (intval(substr($strNum, 0, -1)) * $multi); } protected function chkAttr_uint($attr, $node) { $val = $node->Get(CNode::FLD_VAL); if (preg_match("/^(-?\d+)([KkMmGg]?)$/", $val)) { $val1 = $this->getKNum($val); if (isset($attr->_minVal)) { $min = $this->getKNum($attr->_minVal); if ($val1 < $min) { $node->SetErr('number is less than the minimum required'); return -1; } } if (isset($attr->_maxVal)) { $max = $this->getKNum($attr->_maxVal); if ($val1 > $max) { $node->SetErr('number exceeds maximum allowed'); return -1; } } return 1; } $node->SetErr('invalid number format'); return -1; } }
| ver. 1.4 |
Github
|
.
| PHP 8.2.28 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings