source: trunk/src/sh_restrict.c@ 323

Last change on this file since 323 was 310, checked in by katerina, 14 years ago

Add option to skip checksum for certain files (ticket #232). Also fix for #231 (missing warning on invalid recursion depth).

File size: 15.5 KB
Line 
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
109 path_len = sl_strlen(path);
110 pref_len = sl_strlen(prefix);
111
112 if (path_len >= pref_len)
113 {
114 if (0 == strncmp(path, prefix, pref_len))
115 {
116 SL_RETURN(1, _("matches_prefix"));
117 }
118 }
119 SL_RETURN(0, _("matches_prefix"));
120}
121
122static int exceeds_size (UINT64 size, UINT64 maxsize)
123{
124 SL_ENTER(_("exceeds_size"));
125
126 if (size > maxsize)
127 {
128 SL_RETURN(1, _("exceeds_size"));
129 }
130 SL_RETURN(0, _("exceeds_size"));
131}
132
133static int matches_perm (UINT64 perm, UINT64 needed_perm)
134{
135 SL_ENTER(_("matches_perm"));
136
137 if (needed_perm == (perm & 07777))
138 {
139 SL_RETURN(1, _("matches_perm"));
140 }
141 SL_RETURN(0, _("matches_perm"));
142}
143
144static int includes_perm (UINT64 perm, UINT64 needed_perm)
145{
146 UINT64 tmp = perm & 07777;
147
148 SL_ENTER(_("includes_perm"));
149
150 if (needed_perm == (tmp & needed_perm))
151 {
152 SL_RETURN(1, _("includes_perm"));
153 }
154 SL_RETURN(0, _("includes_perm"));
155}
156
157static int sh_restrict_test(const char * path,
158 UINT64 size, UINT64 perm, SL_TICKET fh,
159 struct sh_restrict_cond * current)
160{
161 int i;
162 unsigned char flag;
163 int res = 0;
164
165 (void) fh;
166
167 SL_ENTER(_("sh_restrict_test"));
168
169 for (i = 0; i < SH_COND_MAX; ++i)
170 {
171 flag = current->cond_type[i];
172
173 if (flag != 0)
174 {
175 if ((flag & (SH_COND_PREFIX)) != 0) {
176 res = matches_prefix(path, current->cond_str[i]);
177 }
178 else if ((flag & (SH_COND_REGEX)) != 0) {
179#ifdef HAVE_REGEX_H
180 res = matches_regex(path, current->cond_preg[i]);
181#else
182 res = matches_string(path, current->cond_str[i]);
183#endif
184 }
185 else if ((flag & (SH_COND_SIZE)) != 0) {
186 res = exceeds_size(size, current->cond_int[i]);
187 }
188 else if ((flag & (SH_COND_PERM)) != 0) {
189 res = matches_perm(perm, current->cond_int[i]);
190 }
191 else if ((flag & (SH_COND_PINCL)) != 0) {
192 res = includes_perm(perm, current->cond_int[i]);
193 }
194 else if ((flag & (SH_COND_FTYPE)) != 0) {
195 res = matches_filetype(fh, current->cond_str[i]);
196 }
197
198 /* Does condition hold?
199 */
200 if ((flag & (SH_COND_NOT)) != 0) {
201 /*
202 * Condition negated, ok if false (res == 0)
203 */
204 if (0 != res) {
205 SL_RETURN(0, _("sh_restrict_this"));
206 }
207 }
208 else {
209 /* Condition ok if true (res != 0) */
210 if (0 == res) {
211 SL_RETURN(0, _("sh_restrict_this"));
212 }
213 }
214 }
215 else
216 {
217 break;
218 }
219 }
220
221 /* All conditions true, restricted
222 */
223 SL_RETURN(1, _("sh_restrict_this"));
224}
225
226/* >>>>>>>>>> Evaluate the list <<<<<<<<<< */
227
228int sh_restrict_this(const char * path, UINT64 size, UINT64 perm, SL_TICKET fh)
229{
230 struct sh_restrict_cond * current = sh_restrict_list;
231
232 SL_ENTER(_("sh_restrict_this"));
233
234 if (!current)
235 {
236 SL_RETURN(0, _("sh_restrict_this"));
237 }
238
239 while (current)
240 {
241 if (0 != sh_restrict_test(path, size, perm, fh, current))
242 {
243 /* The current conditions are true, restricted
244 */
245 SL_RETURN(1, _("sh_restrict_this"));
246 }
247 current = current->next;
248 }
249
250 SL_RETURN(0, _("sh_restrict_this"));
251}
252
253
254/* >>>>>>>>>> Purge the list <<<<<<<<<< */
255
256static void sh_restrict_delete (struct sh_restrict_cond * current)
257{
258 int i;
259
260 if (current->next)
261 {
262 sh_restrict_delete(current->next);
263 }
264
265 for (i = 0; i < SH_COND_MAX; ++i)
266 {
267 if (current->cond_str[i]) {
268 SH_FREE(current->cond_str[i]);
269 }
270#ifdef HAVE_REGEX_H
271 if (current->cond_preg[i]) {
272 regfree(current->cond_preg[i]);
273 SH_FREE(current->cond_preg[i]);
274 }
275#endif
276 }
277 SH_FREE(current);
278 return;
279}
280
281void sh_restrict_purge ()
282{
283 struct sh_restrict_cond * current = sh_restrict_list;
284
285 sh_restrict_list = NULL;
286 if (current)
287 sh_restrict_delete(current);
288
289 sh_restrict_add_ftype(NULL);
290
291 return;
292}
293
294/* >>>>>>>>>> Create the list <<<<<<<<<< */
295
296static char * get_com(char * str)
297{
298 char * s;
299 char * e;
300
301 /* skip leading WS
302 */
303 for (s = str; *s && isspace((int)*s); ++s) /* nothing */;
304
305 e = strchr(s, '(');
306 if (e && (e != s))
307 {
308 *e = '\0'; --e;
309 while ( (e != s) && isspace((int)*e) )
310 {
311 *e = '\0'; --e;
312 }
313 if (e != s)
314 return s;
315 }
316 return NULL;
317}
318
319static char * get_arg(char * str)
320{
321 char * s;
322 char * e;
323
324 s = strchr(str, '(');
325
326 if (s)
327 {
328 ++s;
329
330 /* skip leading WS
331 */
332 for (; *s && isspace((int)*s); ++s) /* nothing */;
333
334 e = strrchr(s, ')');
335 if (e && (e != s))
336 {
337 /* strip trailing space */
338 *e = '\0'; --e;
339 while ( (e != s) && isspace((int)*e) )
340 {
341 *e = '\0'; --e;
342 }
343
344 if (e != s)
345 return s;
346 }
347 }
348 return NULL;
349}
350
351static int set_cond(struct sh_restrict_cond * current, int i,
352 char * com, char * arg)
353{
354 if (!com || !arg || (i >= SH_COND_MAX))
355 return -1;
356
357 if (0 == strcmp(com, _("match_prefix")))
358 {
359 current->cond_str[i] = sh_util_strdup(arg);
360 current->cond_type[i] |= SH_COND_PREFIX;
361 }
362 else if (0 == strcmp(com, _("match_regex")))
363 {
364#ifdef HAVE_REGEX_H
365 regex_t * preg = SH_ALLOC(sizeof(regex_t));
366
367 if (0 != regcomp(preg, arg, REG_NOSUB|REG_EXTENDED))
368 {
369 SH_FREE(preg);
370 return (-1);
371 }
372 current->cond_preg[i] = preg;
373#else
374 current->cond_str[i] = sh_util_strdup(arg);
375#endif
376 current->cond_type[i] |= SH_COND_REGEX;
377 }
378 else if (0 == strcmp(com, _("size_exceeds")))
379 {
380 current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 0);
381 current->cond_type[i] |= SH_COND_SIZE;
382 }
383 else if (0 == strcmp(com, _("match_permission")))
384 {
385 current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 8);
386 current->cond_type[i] |= SH_COND_PERM;
387 }
388 else if (0 == strcmp(com, _("have_permission")))
389 {
390 current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 8);
391 current->cond_type[i] |= SH_COND_PINCL;
392 }
393 else if (0 == strcmp(com, _("match_filetype")))
394 {
395 current->cond_str[i] = sh_util_strdup(arg);
396 current->cond_type[i] |= SH_COND_FTYPE;
397 }
398 else
399 {
400 return (-1);
401 }
402 return 0;
403}
404
405/* Format is [!]cond1(arg), cond2(arg), ...
406 */
407int sh_restrict_define(const char * str)
408{
409 SL_ENTER(_("sh_restrict_define"));
410
411 if (str)
412 {
413 size_t lengths[SH_COND_MAX];
414 unsigned int nfields = SH_COND_MAX;
415 char ** array;
416 sh_string * def = sh_string_new_from_lchar(str, strlen(str));
417
418 array = split_array_list(sh_string_str(def), &nfields, lengths);
419
420 if (array && nfields > 0)
421 {
422 char * p;
423 char * q;
424 unsigned int i;
425 struct sh_restrict_cond * current =
426 SH_ALLOC(sizeof(struct sh_restrict_cond));
427
428 current->next = NULL;
429 for (i = 0; i < SH_COND_MAX; ++i)
430 {
431 current->cond_int[i] = 0;
432 current->cond_type[i] = 0;
433 current->cond_str[i] = NULL;
434#ifdef HAVE_REGEX_H
435 current->cond_preg[i] = NULL;
436#endif
437 }
438
439 for (i = 0; i < nfields; ++i)
440 {
441 if (i == SH_COND_MAX)
442 {
443 sh_restrict_delete (current);
444 sh_string_destroy(&def);
445 SH_FREE(array);
446 SL_RETURN((-1), _("sh_restrict_define"));
447 }
448
449 p = array[i];
450
451 if (*p == '!')
452 {
453 current->cond_type[i] |= SH_COND_NOT;
454 ++p;
455 }
456
457 q = get_arg(p);
458 p = get_com(p);
459
460 if (!q || !p || (0 != set_cond(current, i, p, q)))
461 {
462 sh_restrict_delete (current);
463 sh_string_destroy(&def);
464 SH_FREE(array);
465 SL_RETURN((-1), _("sh_restrict_define"));
466 }
467 }
468
469 SH_FREE(array);
470
471 current->next = sh_restrict_list;
472 sh_restrict_list = current;
473 }
474
475 sh_string_destroy(&def);
476 SL_RETURN(0, _("sh_restrict_define"));
477 }
478
479 SL_RETURN((-1), _("sh_restrict_define"));
480}
481
482
483/* #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
484#endif
485
486#ifdef SH_CUTEST
487#include "CuTest.h"
488
489void Test_restrict (CuTest *tc) {
490
491#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
492
493 char str[256];
494 char * p;
495 char * q;
496 int res;
497 SL_TICKET fd;
498 char buf[1024];
499
500 strcpy(str, "match(this)");
501 p = get_arg(str);
502 q = get_com(str);
503 CuAssertPtrNotNull(tc, p);
504 CuAssertPtrNotNull(tc, q);
505 CuAssertStrEquals(tc, "match", q);
506 CuAssertStrEquals(tc, "this", p);
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, "size_exceeds(800), match_prefix(/home), match_regex(.*\\.mpg) ");
533 CuAssertTrue(tc, sh_restrict_list == NULL);
534 res = sh_restrict_define(str);
535 CuAssertIntEquals(tc,0,res);
536 CuAssertPtrNotNull(tc, sh_restrict_list);
537
538 sh_restrict_purge();
539 CuAssertTrue(tc, sh_restrict_list == NULL);
540
541 strcpy(str, "size_exceeds(800), match_prefix(/home), match_regex(.*\\.mpg), match_permission(0755) ");
542 CuAssertTrue(tc, sh_restrict_list == NULL);
543 res = sh_restrict_define(str);
544 CuAssertIntEquals(tc,0,res);
545 CuAssertPtrNotNull(tc, sh_restrict_list);
546
547 strcpy(str, "size_exceeds(800), match_prefix(/foo), have_permission(0100)");
548 res = sh_restrict_define(str);
549 CuAssertIntEquals(tc,0,res);
550 CuAssertPtrNotNull(tc, sh_restrict_list);
551
552 res = sh_restrict_this("/home/foo.mpg", 1000, 0755, 0);
553 CuAssertIntEquals(tc,1,res);
554
555 res = sh_restrict_this("/foo.mpg", 1000, 0755, 0);
556 CuAssertIntEquals(tc,1,res);
557
558 /* size too small */
559 res = sh_restrict_this("/foo.mpg", 600, 0755, 0);
560 CuAssertIntEquals(tc,0,res);
561
562 /* no execute permission */
563 res = sh_restrict_this("/foo.mpg", 600, 0644, 0);
564 CuAssertIntEquals(tc,0,res);
565
566 /* regex does not match */
567 res = sh_restrict_this("/home/foo", 1000, 0755, 0);
568 CuAssertIntEquals(tc,0,res);
569
570 /* wrong permission */
571 res = sh_restrict_this("/home/foo.mpg", 1000, 0705, 0);
572 CuAssertIntEquals(tc,0,res);
573
574 /* size too small */
575 res = sh_restrict_this("/home/foo.mpg", 600, 0755, 0);
576 CuAssertIntEquals(tc,0,res);
577
578 /* wrong prefix */
579 res = sh_restrict_this("/hoff/foo.mpg", 1000, 0755, 0);
580 CuAssertIntEquals(tc,0,res);
581
582 sh_restrict_purge();
583 CuAssertTrue(tc, sh_restrict_list == NULL);
584
585 fd = sl_open_fastread(FIL__, __LINE__, "/bin/sh", SL_NOPRIV);
586 CuAssertTrue(tc, fd > 0);
587
588 strcpy(str, "match_prefix(/bin), match_filetype(EXECUTABLE:UNIX:ELF)");
589 res = sh_restrict_define(str);
590 CuAssertIntEquals(tc,0,res);
591 CuAssertPtrNotNull(tc, sh_restrict_list);
592
593 res = sh_restrict_this("/bin/sh", 1000, 0755, fd);
594 CuAssertIntEquals(tc,1,res);
595
596 sl_close(fd);
597
598 sh_restrict_purge();
599 CuAssertTrue(tc, sh_restrict_list == NULL);
600
601 strcpy(str, "match_filetype(FILE:TEXT:COPYING)");
602 res = sh_restrict_define(str);
603 CuAssertIntEquals(tc,0,res);
604 CuAssertPtrNotNull(tc, sh_restrict_list);
605
606 p = getcwd(buf, sizeof(buf));
607 CuAssertPtrNotNull(tc, p);
608
609 strcpy(str, "0:0:0:FILE:TEXT:COPYING:Copying:=0a=53=41=4d=48=41=49=4e");
610 res = sh_restrict_add_ftype(str);
611 CuAssertIntEquals(tc,0,res);
612
613 sl_strlcat(buf, "/COPYING", sizeof(buf));
614 fd = sl_open_fastread(FIL__, __LINE__, buf, SL_NOPRIV);
615 CuAssertTrue(tc, fd > 0);
616
617 res = sh_restrict_this(buf, 1000, 0755, fd);
618 CuAssertIntEquals(tc,1,res);
619
620 res = sh_restrict_add_ftype(str);
621 CuAssertIntEquals(tc,0,res);
622 res = sh_restrict_add_ftype(str);
623 CuAssertIntEquals(tc,0,res);
624 res = sh_restrict_add_ftype(str);
625 CuAssertIntEquals(tc,0,res);
626
627 res = sh_restrict_add_ftype(str);
628 CuAssertIntEquals(tc,0,res);
629 res = sh_restrict_add_ftype(str);
630 CuAssertIntEquals(tc,0,res);
631 res = sh_restrict_add_ftype(str);
632 CuAssertIntEquals(tc,0,res);
633 res = sh_restrict_add_ftype(str);
634 CuAssertIntEquals(tc,0,res);
635
636 res = sh_restrict_add_ftype(str);
637 CuAssertIntEquals(tc,0,res);
638 res = sh_restrict_add_ftype(str);
639 CuAssertIntEquals(tc,0,res);
640 res = sh_restrict_add_ftype(str);
641 CuAssertIntEquals(tc,0,res);
642 res = sh_restrict_add_ftype(str);
643 CuAssertIntEquals(tc,0,res);
644
645 res = sh_restrict_add_ftype(str);
646 CuAssertIntEquals(tc,0,res);
647 res = sh_restrict_add_ftype(str);
648 CuAssertIntEquals(tc,0,res);
649 res = sh_restrict_add_ftype(str);
650 CuAssertIntEquals(tc,0,res);
651 res = sh_restrict_add_ftype(str);
652 CuAssertIntEquals(tc,0,res);
653
654 res = sh_restrict_add_ftype(str);
655 CuAssertIntEquals(tc,-1,res);
656
657 sh_restrict_purge();
658 CuAssertTrue(tc, sh_restrict_list == NULL);
659
660 res = sh_restrict_add_ftype(str);
661 CuAssertIntEquals(tc,0,res);
662
663#else
664 (void) tc;
665/* #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
666#endif
667
668}
669#endif
670
671
Note: See TracBrowser for help on using the repository browser.