Passed
Push — master ( 782f23...8a769b )
by Patrick
02:09
created

Rule::get_string()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
nc 1
nop 2
dl 0
loc 8
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Trapdirector;
4
5
use Exception;
6
7
class Rule
8
{
9
    use \RuleUtils;
1 ignored issue
show
Bug introduced by
The trait RuleUtils requires the property $pluginClass which is not provided by Trapdirector\Rule.
Loading history...
10
    
11
    /** @var Logging $logging logging class*/
12
    protected $logging;
13
    
14
    /** @var Trap $trapClass */
15
    protected $trapClass;
16
    
17
18
    /**
19
     * Setup Rule Class
20
     * @param Trap $trapClass : To get logging class & plugin class
21
     */
22
    function __construct($trapClass)
23
    {
24
        $this->trapClass=$trapClass;
25
        $this->logging=$trapClass->logging;
26
    }
27
    
28
    
29
    protected function eval_getElement($rule,&$item)
30
    {
31
        if ($item >= strlen($rule))
32
        {
33
            throw new Exception("Early end of string ".$rule ." at " .$item );
34
        }
35
        while ($rule[$item]==' ') $item++;
36
        if (preg_match('/[\-0-9\.]/',$rule[$item]))
37
        { // number
38
            return $this->get_number($rule, $item);
39
        }
40
        if ($rule[$item] == '"')
41
        { // string
42
            return $this->get_string($rule, $item);
43
        }
44
        
45
        if ($rule[$item] == '(')
46
        { // grouping
47
            return $this->get_group($rule, $item);
48
        }
49
        if ($rule[$item] == '_')
50
        { // function
51
            return $this->get_function($rule, $item);
52
        }
53
        throw new Exception("number/string not found in ".$rule ." at " .$item . ' : ' .$rule[$item]);
54
        
55
    }
56
    
57
    protected function eval_getNext($rule,$item,$tok)
58
    {
59
        while (
60
            ($rule[$item] != $tok ) 
61
            && ($item < strlen($rule))) 
62
        { 
63
            $item++;
64
        }
65
        if ($item==strlen($rule)) {
66
            throw new Exception("closing '".$tok."' not found in ".$rule ." at " .$item);
67
        }
68
        return $item+1;
69
    }
70
    
71
    protected function eval_getOper($rule,&$item)
72
    {
73
        while ($rule[$item]==' ') $item++;
74
        switch ($rule[$item])
75
        {
76
            case '<':
77
                if ($rule[$item+1]=='=') { $item+=2; return array(0,"<=");}
78
                $item++; return array(0,"<");
79
            case '>':
80
                if ($rule[$item+1]=='=') { $item+=2; return array(0,">=");}
81
                $item++; return array(0,">");
82
            case '=':
83
                $item++; return array(0,"=");
84
            case '!':
85
                if ($rule[$item+1]=='=') { $item+=2; return array(0,"!=");}
86
                throw new Exception("Erreur in expr - incorrect operator '!'  found in ".$rule ." at " .$item);
87
            case '~':
88
                $item++; return array(0,"~");
89
            case '|':
90
                $item++; return array(1,"|");
91
            case '&':
92
                $item++; return array(1,"&");
93
            default	:
94
                throw new Exception("Erreur in expr - operator not found in ".$rule ." at " .$item);
95
        }
96
    }
97
    
98
    private function check_negate_first($rule,&$item)
99
    {
100
        if ( $rule[$item] == '!') // If '!' found, negate next expression.
101
        {
102
            $item++;
103
            return true;
104
        }
105
        else
106
        {
107
            return false;
108
        }
109
    }
110
111
    private function do_compare($val1,$val2,$comp,$negate)
112
    {
113
        switch ($comp){
114
            case '<':	$retVal= ($val1 < $val2); break;
115
            case '<=':	$retVal= ($val1 <= $val2); break;
116
            case '>':	$retVal= ($val1 > $val2); break;
117
            case '>=':	$retVal= ($val1 >= $val2); break;
118
            case '=':	$retVal= ($val1 == $val2); break;
119
            case '!=':	$retVal= ($val1 != $val2); break;
120
            case '~':	$retVal= (preg_match('/'.preg_replace('/"/','',$val2).'/',$val1)); break;
121
            case '|':	$retVal= ($val1 || $val2); break;
122
            case '&':	$retVal= ($val1 && $val2); break;
123
            default:  throw new Exception("Error in expression - unknown comp : ".$comp);
124
        }
125
        if ($negate === true) $retVal = ! $retVal; // Inverse result if negate before expression
126
        
127
        return $retVal;
128
    }
129
    
130
    /** Evaluation : makes token and evaluate.
131
     *	Public function for expressions testing
132
     *	accepts : < > = <= >= !=  (typec = 0)
133
     *	operators : & | (typec=1)
134
     *	with : integers/float  (type 0) or strings "" (type 1) or results (type 2)
135
     *   comparison int vs strings will return null (error)
136
     *	return : bool or null on error
137
     */
138
    public function evaluation($rule,&$item)
139
    {
140
        //echo "Evaluation of ".substr($rule,$item)."\n";
141
        $negate=$this->check_negate_first($rule, $item);
142
        // First element : number, string or ()
143
        list($type1,$val1) = $this->eval_getElement($rule,$item);
144
        //echo "Elmt1: ".$val1."/".$type1." : ".substr($rule,$item)."\n";
145
        
146
        if ($item==strlen($rule)) // If only element, return value, but only boolean
147
        {
148
            if ($type1 != 2) throw new Exception("Cannot use num/string as boolean : ".$rule);
149
            if ($negate === true) $val1= ! $val1;
150
            return $val1;
151
        }
152
        
153
        // Second element : operator
154
        list($typec,$comp) = $this->eval_getOper($rule,$item);
155
        //echo "Comp : ".$comp." : ".substr($rule,$item)."\n";
156
        
157
        // Third element : number, string or ()
158
        if ( $rule[$item] == '!') // starts with a ! so evaluate whats next
159
        {
160
            $item++;
161
            if ($typec != 1) throw new Exception("Mixing boolean and comparison : ".$rule);
162
            $val2= ! $this->evaluation($rule,$item);
163
            $type2=2; // result is a boolean
164
        }
165
        else
166
        {
167
            list($type2,$val2) = $this->eval_getElement($rule,$item);
168
        }
169
        //echo "Elmt2: ".$val2."/".$type2." : ".substr($rule,$item)."\n";
170
        
171
        if ($type1!=$type2)  // cannot compare different types
172
        {
173
            throw new Exception("Cannot compare string & number : ".$rule);
174
        }
175
        if ($typec==1 && $type1 !=2) // cannot use & or | with string/number
176
        {
177
            throw new Exception("Cannot use boolean operators with string & number : ".$rule);
178
        }
179
        
180
        $retVal = $this->do_compare($val1, $val2, $comp, $negate);
181
        
182
        if ($item==strlen($rule)) return $retVal; // End of string : return evaluation
183
        // check for logical operator :
184
        switch ($rule[$item])
185
        {
186
            case '|':	$item++; return ($retVal || $this->evaluation($rule,$item) );
187
            case '&':	$item++; return ($retVal && $this->evaluation($rule,$item) );
188
            
189
            default:  throw new Exception("Erreur in expr - garbadge at end of expression : ".$rule[$item]);
190
        }
191
    }
192
    
193
    // Remove all whitespaces (when not quoted)
194
    public function eval_cleanup($rule)
195
    {
196
        $item=0;
197
        $rule2='';
198
        while ($item < strlen($rule))
199
        {
200
            if ($rule[$item]==' ') { $item++; continue; }
201
            if ($rule[$item]=='"')
202
            {
203
                $rule2.=$rule[$item];
204
                $item++;
205
                while (($item < strlen($rule)) && ($rule[$item]!='"') )
206
                {
207
                    $rule2.=$rule[$item];
208
                    $item++;
209
                }
210
                if ($item == strlen ($rule)) throw new Exception("closing '\"' not found in ".$rule ." at " .$item);
211
                $rule2.=$rule[$item];
212
                $item++;
213
                continue;
214
            }
215
            
216
            $rule2.=$rule[$item];
217
            $item++;
218
        }
219
        
220
        return $rule2;
221
    }
222
223
224
    /**
225
     * Get '*' or '**' and transform in [0-9]+ or .* in return string
226
     * @param string $oid OID in normal or regexp format. '*' will be escaped ('\*')
227
     * @return string correct regexp format
228
     */
229
    public function regexp_eval(string &$oid)
230
    {
231
        // ** replaced by .*
232
        $oidR=preg_replace('/\*\*/', '.*', $oid);
233
        // * replaced by [0-9]+
234
        $oidR=preg_replace('/\*/', '[0-9]+', $oidR);
235
        
236
        // replace * with \* in oid for preg_replace
237
        $oid=preg_replace('/\*/', '\*', $oid);
238
        
239
        $this->logging->log('Regexp eval : '.$oid.' / '.$oidR,DEBUG );
240
        
241
        return $oidR;
242
    }
243
    
244
    
245
    /** Evaluation rule (uses eval_* functions recursively)
246
     *	@param string $rule : rule ( _OID(.1.3.6.1.4.1.8072.2.3.2.1)=_OID(.1.3.6.1.2.1.1.3.0) )
247
     *  @param array $oidList : OIDs values to sustitute.
248
     *	@return bool : true : rule match, false : rule don't match , throw exception on error.
249
     */   
250
    public function eval_rule($rule,$oidList)
251
    {
252
        if ($rule==null || $rule == '') // Empty rule is always true
253
        {
254
            return true;
255
        }
256
        $matches=array();
257
        while (preg_match('/_OID\(([0-9\.\*]+)\)/',$rule,$matches) == 1)
258
        {
259
            $oid=$matches[1];
260
            $found=0;
261
            // Test and transform regexp
262
            $oidR = $this->regexp_eval($oid);
263
            
264
            foreach($oidList as $val)
265
            {
266
                if (preg_match("/^$oidR$/",$val->oid) == 1)
267
                {
268
                    if (!preg_match('/^-?[0-9]*\.?[0-9]+$/',$val->value))
269
                    { // If not a number, change " to ' and put " around it
270
                        $val->value=preg_replace('/"/',"'",$val->value);
271
                        $val->value='"'.$val->value.'"';
272
                    }
273
                    $rep=0;
274
                    $rule=preg_replace('/_OID\('.$oid.'\)/',$val->value,$rule,-1,$rep);
275
                    if ($rep==0)
276
                    {
277
                        $this->logging->log("Error in rule_eval",WARN,'');
278
                        return false;
279
                    }
280
                    $found=1;
281
                    break;
282
                }
283
            }
284
            if ($found==0)
285
            {	// OID not found : throw error
286
                throw new Exception('OID '.$oid.' not found in trap');
287
            }
288
        }
289
        $item=0;
290
        $rule=$this->eval_cleanup($rule);
291
        $this->logging->log('Rule after clenup: '.$rule,INFO );
292
        
293
        return  $this->evaluation($rule,$item);
294
    }
295
    
296
}