Passed
Push — master ( 300cc7...278791 )
by Patrick
01:59
created

Rule::eval_cleanup()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

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