source: trunk/src/sh_restrict.c@ 501

Last change on this file since 501 was 484, checked in by katerina, 9 years ago

Fix for ticket #382 (no error message for invalid checksum skip condition list).

File size: 15.9 KB
RevLine 
[310]1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2011 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22#ifndef NULL
23#if !defined(__cplusplus)
24#define NULL ((void*)0)
25#else
26#define NULL (0)
27#endif
28#endif
29
30#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
31
32#ifdef HAVE_REGEX_H
33#include <sys/types.h>
34#include <regex.h>
35#endif
36#include <stdlib.h>
37#include <string.h>
38#include <ctype.h>
39
40#include "samhain.h"
41#include "sh_mem.h"
42#include "sh_error_min.h"
43#include "sh_string.h"
44#include "sh_utils.h"
45#include "sh_restrict.h"
46
47#define FIL__ _("sh_restrict.c")
48
49#define SH_COND_NOT (1 << 0)
50#define SH_COND_PREFIX (1 << 1)
51#define SH_COND_REGEX (1 << 2)
52#define SH_COND_SIZE (1 << 3)
53#define SH_COND_PERM (1 << 4)
54#define SH_COND_FTYPE (1 << 5)
55#define SH_COND_PINCL (1 << 6)
56
57#define SH_COND_MAX 6
58
59struct sh_restrict_cond {
60
61 unsigned char cond_type[SH_COND_MAX];
62
63#ifdef HAVE_REGEX_H
64 regex_t * cond_preg[SH_COND_MAX];
65#endif
66
67 char * cond_str[SH_COND_MAX];
68
69 UINT64 cond_int[SH_COND_MAX];
70
71 struct sh_restrict_cond * next;
72};
73
74static struct sh_restrict_cond * sh_restrict_list = NULL;
75
76extern int matches_filetype(SL_TICKET ft, char * test_type);
77
78#ifdef HAVE_REGEX_H
79static int matches_regex (const char * path, const regex_t * regex)
80{
81 SL_ENTER(_("matches_regex"));
82
83 if (0 == regexec(regex, path, 0, NULL, 0))
84 {
85 SL_RETURN(1, _("matches_regex"));
86 }
87 SL_RETURN(0, _("matches_regex"));
88}
89#else
90static int matches_string (const char * path, const char * string)
91{
92 SL_ENTER(_("matches_string"));
93
94 if (NULL == strstr(path, string))
95 {
96 SL_RETURN(0, _("matches_string"));
97 }
98 SL_RETURN(1, _("matches_string"));
99}
100#endif
101
102static int matches_prefix (const char * path, const char * prefix)
103{
104 size_t path_len;
105 size_t pref_len;
106
107 SL_ENTER(_("matches_prefix"));
108
[383]109 if (path && prefix)
[310]110 {
[383]111 path_len = sl_strlen(path);
112 pref_len = sl_strlen(prefix);
113
114 if (path_len >= pref_len)
[310]115 {
[383]116 if (0 == strncmp(path, prefix, pref_len))
117 {
118 SL_RETURN(1, _("matches_prefix"));
119 }
[310]120 }
121 }
122 SL_RETURN(0, _("matches_prefix"));
123}
124
125static int exceeds_size (UINT64 size, UINT64 maxsize)
126{
127 SL_ENTER(_("exceeds_size"));
128
129 if (size > maxsize)
130 {
131 SL_RETURN(1, _("exceeds_size"));
132 }
133 SL_RETURN(0, _("exceeds_size"));
134}
135
136static int matches_perm (UINT64 perm, UINT64 needed_perm)
137{
138 SL_ENTER(_("matches_perm"));
139
140 if (needed_perm == (perm & 07777))
141 {
142 SL_RETURN(1, _("matches_perm"));
143 }
144 SL_RETURN(0, _("matches_perm"));
145}
146
147static int includes_perm (UINT64 perm, UINT64 needed_perm)
148{
149 UINT64 tmp = perm & 07777;
150
151 SL_ENTER(_("includes_perm"));
152
153 if (needed_perm == (tmp & needed_perm))
154 {
155 SL_RETURN(1, _("includes_perm"));
156 }
157 SL_RETURN(0, _("includes_perm"));
158}
159
160static int sh_restrict_test(const char * path,
161 UINT64 size, UINT64 perm, SL_TICKET fh,
162 struct sh_restrict_cond * current)
163{
164 int i;
165 unsigned char flag;
166 int res = 0;
167
168 (void) fh;
169
170 SL_ENTER(_("sh_restrict_test"));
171
172 for (i = 0; i < SH_COND_MAX; ++i)
173 {
174 flag = current->cond_type[i];
175
176 if (flag != 0)
177 {
178 if ((flag & (SH_COND_PREFIX)) != 0) {
179 res = matches_prefix(path, current->cond_str[i]);
180 }
181 else if ((flag & (SH_COND_REGEX)) != 0) {
182#ifdef HAVE_REGEX_H
183 res = matches_regex(path, current->cond_preg[i]);
184#else
185 res = matches_string(path, current->cond_str[i]);
186#endif
187 }
188 else if ((flag & (SH_COND_SIZE)) != 0) {
189 res = exceeds_size(size, current->cond_int[i]);
190 }
191 else if ((flag & (SH_COND_PERM)) != 0) {
192 res = matches_perm(perm, current->cond_int[i]);
193 }
194 else if ((flag & (SH_COND_PINCL)) != 0) {
195 res = includes_perm(perm, current->cond_int[i]);
196 }
197 else if ((flag & (SH_COND_FTYPE)) != 0) {
198 res = matches_filetype(fh, current->cond_str[i]);
199 }
200
201 /* Does condition hold?
202 */
203 if ((flag & (SH_COND_NOT)) != 0) {
204 /*
205 * Condition negated, ok if false (res == 0)
206 */
207 if (0 != res) {
208 SL_RETURN(0, _("sh_restrict_this"));
209 }
210 }
211 else {
212 /* Condition ok if true (res != 0) */
213 if (0 == res) {
214 SL_RETURN(0, _("sh_restrict_this"));
215 }
216 }
217 }
218 else
219 {
220 break;
221 }
222 }
223
224 /* All conditions true, restricted
225 */
226 SL_RETURN(1, _("sh_restrict_this"));
227}
228
229/* >>>>>>>>>> Evaluate the list <<<<<<<<<< */
230
231int sh_restrict_this(const char * path, UINT64 size, UINT64 perm, SL_TICKET fh)
232{
233 struct sh_restrict_cond * current = sh_restrict_list;
234
235 SL_ENTER(_("sh_restrict_this"));
236
237 if (!current)
238 {
239 SL_RETURN(0, _("sh_restrict_this"));
240 }
241
242 while (current)
243 {
244 if (0 != sh_restrict_test(path, size, perm, fh, current))
245 {
246 /* The current conditions are true, restricted
247 */
248 SL_RETURN(1, _("sh_restrict_this"));
249 }
250 current = current->next;
251 }
252
253 SL_RETURN(0, _("sh_restrict_this"));
254}
255
256
257/* >>>>>>>>>> Purge the list <<<<<<<<<< */
258
259static void sh_restrict_delete (struct sh_restrict_cond * current)
260{
261 int i;
262
263 if (current->next)
264 {
265 sh_restrict_delete(current->next);
266 }
267
268 for (i = 0; i < SH_COND_MAX; ++i)
269 {
270 if (current->cond_str[i]) {
271 SH_FREE(current->cond_str[i]);
272 }
273#ifdef HAVE_REGEX_H
274 if (current->cond_preg[i]) {
275 regfree(current->cond_preg[i]);
276 SH_FREE(current->cond_preg[i]);
277 }
278#endif
279 }
280 SH_FREE(current);
281 return;
282}
283
284void sh_restrict_purge ()
285{
286 struct sh_restrict_cond * current = sh_restrict_list;
287
288 sh_restrict_list = NULL;
289 if (current)
290 sh_restrict_delete(current);
291
292 sh_restrict_add_ftype(NULL);
293
294 return;
295}
296
297/* >>>>>>>>>> Create the list <<<<<<<<<< */
298
299static char * get_com(char * str)
300{
301 char * s;
302 char * e;
303
304 /* skip leading WS
305 */
306 for (s = str; *s && isspace((int)*s); ++s) /* nothing */;
307
308 e = strchr(s, '(');
309 if (e && (e != s))
310 {
311 *e = '\0'; --e;
312 while ( (e != s) && isspace((int)*e) )
313 {
314 *e = '\0'; --e;
315 }
316 if (e != s)
317 return s;
318 }
319 return NULL;
320}
321
322static char * get_arg(char * str)
323{
324 char * s;
325 char * e;
326
327 s = strchr(str, '(');
328
329 if (s)
330 {
331 ++s;
332
333 /* skip leading WS
334 */
335 for (; *s && isspace((int)*s); ++s) /* nothing */;
336
337 e = strrchr(s, ')');
338 if (e && (e != s))
339 {
[484]340 /* check that nothing follows */
341 char * u = e;
342 ++u; for (; *u && isspace((int)*u); ++u) /* nothing */;
343 if (*u != '\0') return NULL;
344
[310]345 /* strip trailing space */
346 *e = '\0'; --e;
347 while ( (e != s) && isspace((int)*e) )
348 {
349 *e = '\0'; --e;
350 }
351
352 if (e != s)
353 return s;
354 }
355 }
356 return NULL;
357}
358
359static int set_cond(struct sh_restrict_cond * current, int i,
360 char * com, char * arg)
361{
362 if (!com || !arg || (i >= SH_COND_MAX))
363 return -1;
364
365 if (0 == strcmp(com, _("match_prefix")))
366 {
367 current->cond_str[i] = sh_util_strdup(arg);
368 current->cond_type[i] |= SH_COND_PREFIX;
369 }
370 else if (0 == strcmp(com, _("match_regex")))
371 {
372#ifdef HAVE_REGEX_H
373 regex_t * preg = SH_ALLOC(sizeof(regex_t));
374
375 if (0 != regcomp(preg, arg, REG_NOSUB|REG_EXTENDED))
376 {
377 SH_FREE(preg);
378 return (-1);
379 }
380 current->cond_preg[i] = preg;
381#else
382 current->cond_str[i] = sh_util_strdup(arg);
383#endif
384 current->cond_type[i] |= SH_COND_REGEX;
385 }
386 else if (0 == strcmp(com, _("size_exceeds")))
387 {
388 current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 0);
389 current->cond_type[i] |= SH_COND_SIZE;
390 }
391 else if (0 == strcmp(com, _("match_permission")))
392 {
393 current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 8);
394 current->cond_type[i] |= SH_COND_PERM;
395 }
396 else if (0 == strcmp(com, _("have_permission")))
397 {
398 current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 8);
399 current->cond_type[i] |= SH_COND_PINCL;
400 }
401 else if (0 == strcmp(com, _("match_filetype")))
402 {
403 current->cond_str[i] = sh_util_strdup(arg);
404 current->cond_type[i] |= SH_COND_FTYPE;
405 }
406 else
407 {
408 return (-1);
409 }
410 return 0;
411}
412
413/* Format is [!]cond1(arg), cond2(arg), ...
414 */
415int sh_restrict_define(const char * str)
416{
417 SL_ENTER(_("sh_restrict_define"));
418
419 if (str)
420 {
421 size_t lengths[SH_COND_MAX];
422 unsigned int nfields = SH_COND_MAX;
423 char ** array;
424 sh_string * def = sh_string_new_from_lchar(str, strlen(str));
425
426 array = split_array_list(sh_string_str(def), &nfields, lengths);
427
428 if (array && nfields > 0)
429 {
430 char * p;
431 char * q;
432 unsigned int i;
433 struct sh_restrict_cond * current =
434 SH_ALLOC(sizeof(struct sh_restrict_cond));
435
436 current->next = NULL;
437 for (i = 0; i < SH_COND_MAX; ++i)
438 {
439 current->cond_int[i] = 0;
440 current->cond_type[i] = 0;
441 current->cond_str[i] = NULL;
442#ifdef HAVE_REGEX_H
443 current->cond_preg[i] = NULL;
444#endif
445 }
446
447 for (i = 0; i < nfields; ++i)
448 {
449 if (i == SH_COND_MAX)
450 {
451 sh_restrict_delete (current);
452 sh_string_destroy(&def);
453 SH_FREE(array);
454 SL_RETURN((-1), _("sh_restrict_define"));
455 }
456
457 p = array[i];
458
459 if (*p == '!')
460 {
461 current->cond_type[i] |= SH_COND_NOT;
462 ++p;
463 }
464
465 q = get_arg(p);
466 p = get_com(p);
467
468 if (!q || !p || (0 != set_cond(current, i, p, q)))
469 {
470 sh_restrict_delete (current);
471 sh_string_destroy(&def);
472 SH_FREE(array);
473 SL_RETURN((-1), _("sh_restrict_define"));
474 }
475 }
476
477 SH_FREE(array);
478
479 current->next = sh_restrict_list;
480 sh_restrict_list = current;
481 }
482
483 sh_string_destroy(&def);
484 SL_RETURN(0, _("sh_restrict_define"));
485 }
486
487 SL_RETURN((-1), _("sh_restrict_define"));
488}
489
490
491/* #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
492#endif
493
494#ifdef SH_CUTEST
495#include "CuTest.h"
496
497void Test_restrict (CuTest *tc) {
498
499#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
500
501 char str[256];
502 char * p;
503 char * q;
504 int res;
505 SL_TICKET fd;
506 char buf[1024];
507
508 strcpy(str, "match(this)");
509 p = get_arg(str);
510 q = get_com(str);
511 CuAssertPtrNotNull(tc, p);
512 CuAssertPtrNotNull(tc, q);
513 CuAssertStrEquals(tc, "match", q);
514 CuAssertStrEquals(tc, "this", p);
515
516 strcpy(str, " match( this)");
517 p = get_arg(str);
518 q = get_com(str);
519 CuAssertPtrNotNull(tc, p);
520 CuAssertPtrNotNull(tc, q);
521 CuAssertStrEquals(tc, "match", q);
522 CuAssertStrEquals(tc, "this", p);
523
524 strcpy(str, " match ( this ) ");
525 p = get_arg(str);
526 q = get_com(str);
527 CuAssertPtrNotNull(tc, p);
528 CuAssertPtrNotNull(tc, q);
529 CuAssertStrEquals(tc, "match", q);
530 CuAssertStrEquals(tc, "this", p);
531
532 strcpy(str, " match (this ) ");
533 p = get_arg(str);
534 q = get_com(str);
535 CuAssertPtrNotNull(tc, p);
536 CuAssertPtrNotNull(tc, q);
537 CuAssertStrEquals(tc, "match", q);
538 CuAssertStrEquals(tc, "this", p);
539
540 strcpy(str, "size_exceeds(800), match_prefix(/home), match_regex(.*\\.mpg) ");
541 CuAssertTrue(tc, sh_restrict_list == NULL);
542 res = sh_restrict_define(str);
543 CuAssertIntEquals(tc,0,res);
544 CuAssertPtrNotNull(tc, sh_restrict_list);
545
546 sh_restrict_purge();
547 CuAssertTrue(tc, sh_restrict_list == NULL);
548
549 strcpy(str, "size_exceeds(800), match_prefix(/home), match_regex(.*\\.mpg), match_permission(0755) ");
550 CuAssertTrue(tc, sh_restrict_list == NULL);
551 res = sh_restrict_define(str);
552 CuAssertIntEquals(tc,0,res);
553 CuAssertPtrNotNull(tc, sh_restrict_list);
554
555 strcpy(str, "size_exceeds(800), match_prefix(/foo), have_permission(0100)");
556 res = sh_restrict_define(str);
557 CuAssertIntEquals(tc,0,res);
558 CuAssertPtrNotNull(tc, sh_restrict_list);
559
[484]560 strcpy(str, "size_exceeds(800); match_prefix(/foo), have_permission(0100)");
561 res = sh_restrict_define(str);
562 CuAssertIntEquals(tc,-1,res);
563 CuAssertPtrNotNull(tc, sh_restrict_list);
564
[310]565 res = sh_restrict_this("/home/foo.mpg", 1000, 0755, 0);
566 CuAssertIntEquals(tc,1,res);
567
568 res = sh_restrict_this("/foo.mpg", 1000, 0755, 0);
569 CuAssertIntEquals(tc,1,res);
570
571 /* size too small */
572 res = sh_restrict_this("/foo.mpg", 600, 0755, 0);
573 CuAssertIntEquals(tc,0,res);
574
575 /* no execute permission */
576 res = sh_restrict_this("/foo.mpg", 600, 0644, 0);
577 CuAssertIntEquals(tc,0,res);
578
579 /* regex does not match */
580 res = sh_restrict_this("/home/foo", 1000, 0755, 0);
581 CuAssertIntEquals(tc,0,res);
582
583 /* wrong permission */
584 res = sh_restrict_this("/home/foo.mpg", 1000, 0705, 0);
585 CuAssertIntEquals(tc,0,res);
586
587 /* size too small */
588 res = sh_restrict_this("/home/foo.mpg", 600, 0755, 0);
589 CuAssertIntEquals(tc,0,res);
590
591 /* wrong prefix */
592 res = sh_restrict_this("/hoff/foo.mpg", 1000, 0755, 0);
593 CuAssertIntEquals(tc,0,res);
594
595 sh_restrict_purge();
596 CuAssertTrue(tc, sh_restrict_list == NULL);
597
598 fd = sl_open_fastread(FIL__, __LINE__, "/bin/sh", SL_NOPRIV);
599 CuAssertTrue(tc, fd > 0);
600
601 strcpy(str, "match_prefix(/bin), match_filetype(EXECUTABLE:UNIX:ELF)");
602 res = sh_restrict_define(str);
603 CuAssertIntEquals(tc,0,res);
604 CuAssertPtrNotNull(tc, sh_restrict_list);
605
[341]606#if !defined(HOST_IS_CYGWIN)
[310]607 res = sh_restrict_this("/bin/sh", 1000, 0755, fd);
608 CuAssertIntEquals(tc,1,res);
[341]609#endif
[310]610
611 sl_close(fd);
612
613 sh_restrict_purge();
614 CuAssertTrue(tc, sh_restrict_list == NULL);
615
616 strcpy(str, "match_filetype(FILE:TEXT:COPYING)");
617 res = sh_restrict_define(str);
618 CuAssertIntEquals(tc,0,res);
619 CuAssertPtrNotNull(tc, sh_restrict_list);
620
621 p = getcwd(buf, sizeof(buf));
622 CuAssertPtrNotNull(tc, p);
623
624 strcpy(str, "0:0:0:FILE:TEXT:COPYING:Copying:=0a=53=41=4d=48=41=49=4e");
625 res = sh_restrict_add_ftype(str);
626 CuAssertIntEquals(tc,0,res);
627
628 sl_strlcat(buf, "/COPYING", sizeof(buf));
629 fd = sl_open_fastread(FIL__, __LINE__, buf, SL_NOPRIV);
630 CuAssertTrue(tc, fd > 0);
631
632 res = sh_restrict_this(buf, 1000, 0755, fd);
633 CuAssertIntEquals(tc,1,res);
634
635 res = sh_restrict_add_ftype(str);
636 CuAssertIntEquals(tc,0,res);
637 res = sh_restrict_add_ftype(str);
638 CuAssertIntEquals(tc,0,res);
639 res = sh_restrict_add_ftype(str);
640 CuAssertIntEquals(tc,0,res);
641
642 res = sh_restrict_add_ftype(str);
643 CuAssertIntEquals(tc,0,res);
644 res = sh_restrict_add_ftype(str);
645 CuAssertIntEquals(tc,0,res);
646 res = sh_restrict_add_ftype(str);
647 CuAssertIntEquals(tc,0,res);
648 res = sh_restrict_add_ftype(str);
649 CuAssertIntEquals(tc,0,res);
650
651 res = sh_restrict_add_ftype(str);
652 CuAssertIntEquals(tc,0,res);
653 res = sh_restrict_add_ftype(str);
654 CuAssertIntEquals(tc,0,res);
655 res = sh_restrict_add_ftype(str);
656 CuAssertIntEquals(tc,0,res);
657 res = sh_restrict_add_ftype(str);
658 CuAssertIntEquals(tc,0,res);
659
660 res = sh_restrict_add_ftype(str);
661 CuAssertIntEquals(tc,0,res);
662 res = sh_restrict_add_ftype(str);
663 CuAssertIntEquals(tc,0,res);
664 res = sh_restrict_add_ftype(str);
665 CuAssertIntEquals(tc,0,res);
666 res = sh_restrict_add_ftype(str);
667 CuAssertIntEquals(tc,0,res);
668
669 res = sh_restrict_add_ftype(str);
670 CuAssertIntEquals(tc,-1,res);
671
672 sh_restrict_purge();
673 CuAssertTrue(tc, sh_restrict_list == NULL);
674
675 res = sh_restrict_add_ftype(str);
676 CuAssertIntEquals(tc,0,res);
677
678#else
679 (void) tc;
680/* #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
681#endif
682
683}
684#endif
685
686
Note: See TracBrowser for help on using the repository browser.