1<?php 2 3require_once "parser.php"; 4require_once "tokenizer.php"; 5require_once "exceptions.php"; 6 7use \AST\ElementDefinition; 8use \AST\TokenDefinition; 9use \AST\InvalidExpressionException; 10use \AST\MalformedExpressionException; 11use \AST\Fixing; 12 13 14class EvaluationContext { 15 public $SIMULATE_IN_GROUPS = null; 16 public $SIMULATE_USERS = null; 17 18 public function belongToGroup($group) { 19 if (is_array($this->SIMULATE_IN_GROUPS)) { 20 if (in_array($group, $this->SIMULATE_IN_GROUPS)) { 21 return true; 22 } 23 } 24 global $INFO; 25 $key1 = 'userinfo'; 26 $key2 = 'grps'; 27 if (is_array($INFO) && array_key_exists($key1, $INFO)) { 28 if (is_array($INFO[$key1]) && array_key_exists($key2, $INFO[$key1])) { 29 return in_array($group, $INFO[$key1][$key2]); 30 } 31 } 32 return false; 33 } 34 35 public function isUser($user) { 36 if (is_array($this->SIMULATE_USERS)) { 37 if (in_array($user, $this->SIMULATE_USERS)) { 38 return true; 39 } 40 } 41 $key = 'REMOTE_USER'; 42 if (array_key_exists($key, $_SERVER)) { 43 return $_SERVER[$key] == $user; 44 } 45 return false; 46 } 47} 48 49function auth_expr_evaluation_context() { 50 static $ctx = null; 51 if ($ctx === null) { 52 $ctx = new EvaluationContext(); 53 } 54 return $ctx; 55} 56 57 58class Literal extends ElementDefinition { 59 public function __construct() { 60 $T_LITERAL = new TokenDefinition(null, 'LIT', '/[\w.-]+|".+?(?<!\\\\)(\\\\\\\\)*"/'); 61 parent::__construct('Literal', Fixing::None, $T_LITERAL, 0); 62 } 63 public static function unquote($strValue) { 64 // No multibyte variant, here we just operate on bytes 65 $strValue = str_replace('\\\\', '\\', $strValue); 66 $strValue = str_replace('\\"', '"', $strValue); 67 $strValue = substr($strValue, 1, strlen($strValue) - 2); 68 return $strValue; 69 } 70 public static function isQuoted($strValue) { 71 if (TokenDefinition::supportsMultibyte()) { 72 return mb_strlen($strValue) > 0 && mb_substr($strValue, 0, 1) == '"'; 73 } else { 74 return strlen($strValue) > 0 && substr($strValue, 0, 1) == '"'; 75 } 76 } 77 public static function getInstanceLiteralValue($elmInstance) { 78 $strValue = $elmInstance->getStringValue(); 79 if (self::isQuoted($strValue)) { 80 return self::unquote($strValue); 81 } 82 return $strValue; 83 } 84 public function _evaluateWellFormed($elmInstance) { 85 $userName = self::getInstanceLiteralValue($elmInstance); 86 return auth_expr_evaluation_context()->isUser($userName); 87 } 88} 89 90class SubExpr extends ElementDefinition { 91 public function __construct() { 92 $T_OPEN_PAREN = new TokenDefinition('(', 'OPENP'); 93 $T_CLOSE_PAREN = new TokenDefinition(')', 'CLOSEP'); 94 parent::__construct('SubExpr', Fixing::Wrap, array($T_OPEN_PAREN, $T_CLOSE_PAREN), 1, null, true); 95 } 96 public function ensureWellFormed($elmInstance) { 97 parent::ensureWellFormed($elmInstance); 98 if (count($elmInstance->args()) != 1) { 99 throw new MalformedExpressionException($elmInstance, 'A subexpression must have exactly one root'); 100 } 101 } 102 public function _evaluateWellFormed($elmInstance) { 103 return $elmInstance->evaluateArgs()[0]; 104 } 105} 106 107class OpInGroup extends ElementDefinition { 108 public function __construct() { 109 $T_AT = new TokenDefinition('@', 'AT'); 110 parent::__construct('InGroup', Fixing::Prefix, $T_AT, 2); 111 } 112 public function ensureWellFormed($elmInstance) { 113 parent::ensureWellFormed($elmInstance); 114 if (!($elmInstance->args()[0]->definition() instanceof Literal)) { 115 throw new MalformedExpressionException($elmInstance, 'A in-group operator <@> must take exactly one literal argument.'); 116 } 117 } 118 public function _evaluateWellFormed($elmInstance) { 119 $literalInstance = $elmInstance->args()[0]; 120 $groupName = Literal::getInstanceLiteralValue($literalInstance); 121 return auth_expr_evaluation_context()->belongToGroup($groupName); 122 } 123} 124 125class OpNot extends ElementDefinition { 126 public function __construct() { 127 $T_EXCL = new TokenDefinition('!', 'EXCL'); 128 parent::__construct('Not', Fixing::Prefix, $T_EXCL, 3); 129 } 130 public function _evaluateWellFormed($elmInstance) { 131 $argValues = $elmInstance->evaluateArgs(); 132 if (!is_bool($argValues[0])) { 133 throw new InvalidExpressionException($elmInstance, 'Not called on a non-boolean argument.'); 134 } 135 return !$argValues[0]; 136 } 137} 138 139class OpAnd extends ElementDefinition { 140 public function __construct() { 141 $T_AND = new TokenDefinition('&&', 'AND'); 142 parent::__construct('And', Fixing::Infix, $T_AND, 4); 143 } 144 public function _evaluateWellFormed($elmInstance) { 145 $argValues = $elmInstance->evaluateArgs(); 146 foreach ($argValues as $arg) { 147 if (!is_bool($arg)) { 148 throw new InvalidExpressionException($elmInstance, 'And called on non-boolean arguments.'); 149 } 150 if (!$arg) { 151 return false; 152 } 153 } 154 return true; 155 } 156} 157 158class OpOr extends ElementDefinition { 159 public function __construct() { 160 $T_OR = new TokenDefinition('||', 'OR', '/(\|\||,)/'); 161 parent::__construct('Or', Fixing::Infix, $T_OR, 5); 162 } 163 public function _evaluateWellFormed($elmInstance) { 164 $argValues = $elmInstance->evaluateArgs(); 165 foreach ($argValues as $arg) { 166 if (!is_bool($arg)) { 167 throw new InvalidExpressionException($elmInstance, 'Or called on non-boolean arguments.'); 168 } 169 if ($arg) { 170 return true; 171 } 172 } 173 return false; 174 } 175} 176 177function auth_expr_all_elements() { 178 static $ALL_ELEMENTS = null; 179 if ($ALL_ELEMENTS === null) { 180 $ALL_ELEMENTS = array(new Literal(), new SubExpr(), new OpInGroup(), new OpNot(), new OpAnd(), new OpOr()); 181 } 182 return $ALL_ELEMENTS; 183} 184 185function auth_expr_ignore_tokens() { 186 static $IGNORE_TOKENS = null; 187 if ($IGNORE_TOKENS === null) { 188 $IGNORE_TOKENS = array(new TokenDefinition(' ', 'SPC', '/\s+/')); 189 } 190 return $IGNORE_TOKENS; 191} 192 193function auth_expr_all_tokens() { 194 static $ALL_TOKENS = null; 195 if ($ALL_TOKENS === null) { 196 $ALL_TOKENS = array_merge(auth_expr_ignore_tokens(), ElementDefinition::extractUsedTokens(auth_expr_all_elements())); 197 } 198 return $ALL_TOKENS; 199} 200 201function auth_expr_parse($expr) { 202 return \AST\parse(\AST\tokenize($expr, auth_expr_all_tokens(), auth_expr_ignore_tokens()), auth_expr_all_elements()); 203} 204 205?>