source: trunk/src/sh_restrict.c @ 452

Last change on this file since 452 was 383, checked in by katerina, 10 years ago

Fix for ticket #281 (warnings from clang static analyzer).

File size: 15.6 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  if (path && prefix)
110    {
111      path_len = sl_strlen(path);
112      pref_len = sl_strlen(prefix);
113     
114      if (path_len >= pref_len)
115        {
116          if (0 == strncmp(path, prefix, pref_len))
117            {
118              SL_RETURN(1, _("matches_prefix"));
119            }
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        {
340          /* strip trailing space */
341          *e = '\0'; --e;
342          while ( (e != s) && isspace((int)*e) )
343            {
344              *e = '\0'; --e;
345            }
346         
347          if (e != s)
348            return s;
349        }
350    }
351  return NULL;
352}
353
354static int set_cond(struct sh_restrict_cond * current, int i, 
355                    char * com, char * arg)
356{
357  if (!com || !arg || (i >= SH_COND_MAX))
358    return -1;
359
360  if      (0 == strcmp(com, _("match_prefix")))
361    {
362      current->cond_str[i] = sh_util_strdup(arg);
363      current->cond_type[i] |= SH_COND_PREFIX;
364    }
365  else if (0 == strcmp(com, _("match_regex")))
366    {
367#ifdef HAVE_REGEX_H
368      regex_t * preg = SH_ALLOC(sizeof(regex_t)); 
369
370      if (0 != regcomp(preg, arg, REG_NOSUB|REG_EXTENDED))
371        {
372          SH_FREE(preg);
373          return (-1);
374        }
375      current->cond_preg[i] = preg;
376#else
377      current->cond_str[i] = sh_util_strdup(arg);
378#endif
379      current->cond_type[i] |= SH_COND_REGEX;
380    }
381  else if (0 == strcmp(com, _("size_exceeds")))
382    {
383      current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 0);
384      current->cond_type[i] |= SH_COND_SIZE;
385    }
386  else if (0 == strcmp(com, _("match_permission")))
387    {
388      current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 8);
389      current->cond_type[i] |= SH_COND_PERM;
390    }
391  else if (0 == strcmp(com, _("have_permission")))
392    {
393      current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 8);
394      current->cond_type[i] |= SH_COND_PINCL;
395    }
396  else if (0 == strcmp(com, _("match_filetype")))
397    {
398      current->cond_str[i] = sh_util_strdup(arg);
399      current->cond_type[i] |= SH_COND_FTYPE;
400    }
401  else
402    {
403      return (-1);
404    }
405  return 0;
406}
407
408/* Format is [!]cond1(arg), cond2(arg), ...
409 */
410int sh_restrict_define(const char * str)
411{
412  SL_ENTER(_("sh_restrict_define"));
413
414  if (str) 
415    {
416      size_t lengths[SH_COND_MAX];
417      unsigned int nfields = SH_COND_MAX;
418      char ** array;
419      sh_string * def = sh_string_new_from_lchar(str, strlen(str));
420
421      array = split_array_list(sh_string_str(def), &nfields, lengths);
422
423      if (array && nfields > 0)
424        {
425          char * p;
426          char * q;
427          unsigned int i;
428          struct sh_restrict_cond * current = 
429            SH_ALLOC(sizeof(struct sh_restrict_cond));
430
431          current->next = NULL;
432          for (i = 0; i < SH_COND_MAX; ++i)
433            {
434              current->cond_int[i]  = 0; 
435              current->cond_type[i] = 0;
436              current->cond_str[i] = NULL;
437#ifdef HAVE_REGEX_H
438              current->cond_preg[i] = NULL;
439#endif
440            }
441     
442          for (i = 0; i < nfields; ++i) 
443            {
444              if (i == SH_COND_MAX)
445                {
446                  sh_restrict_delete (current);
447                  sh_string_destroy(&def);
448                  SH_FREE(array);
449                  SL_RETURN((-1), _("sh_restrict_define"));
450                }
451             
452              p = array[i];
453
454              if (*p == '!')
455                {
456                  current->cond_type[i] |= SH_COND_NOT;
457                  ++p;
458                }
459
460              q = get_arg(p);
461              p = get_com(p);
462
463              if (!q || !p || (0 != set_cond(current, i, p, q)))
464                {
465                  sh_restrict_delete (current);
466                  sh_string_destroy(&def);
467                  SH_FREE(array);
468                  SL_RETURN((-1), _("sh_restrict_define"));
469                }
470            }
471
472          SH_FREE(array);
473
474          current->next = sh_restrict_list;
475          sh_restrict_list = current;
476        }
477
478      sh_string_destroy(&def);
479      SL_RETURN(0, _("sh_restrict_define"));
480    }
481
482  SL_RETURN((-1), _("sh_restrict_define"));
483}
484
485
486/* #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
487#endif
488
489#ifdef SH_CUTEST
490#include "CuTest.h"
491
492void Test_restrict (CuTest *tc) {
493
494#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
495
496  char str[256];
497  char * p;
498  char * q;
499  int  res;
500  SL_TICKET fd;
501  char buf[1024];
502
503  strcpy(str, "match(this)");
504  p = get_arg(str);
505  q = get_com(str);
506  CuAssertPtrNotNull(tc, p);
507  CuAssertPtrNotNull(tc, q);
508  CuAssertStrEquals(tc, "match", q);
509  CuAssertStrEquals(tc, "this",  p);
510 
511  strcpy(str, "  match( this)");
512  p = get_arg(str);
513  q = get_com(str);
514  CuAssertPtrNotNull(tc, p);
515  CuAssertPtrNotNull(tc, q);
516  CuAssertStrEquals(tc, "match", q);
517  CuAssertStrEquals(tc, "this",  p);
518 
519  strcpy(str, "  match ( this ) ");
520  p = get_arg(str);
521  q = get_com(str);
522  CuAssertPtrNotNull(tc, p);
523  CuAssertPtrNotNull(tc, q);
524  CuAssertStrEquals(tc, "match", q);
525  CuAssertStrEquals(tc, "this",  p);
526 
527  strcpy(str, "  match   (this   ) ");
528  p = get_arg(str);
529  q = get_com(str);
530  CuAssertPtrNotNull(tc, p);
531  CuAssertPtrNotNull(tc, q);
532  CuAssertStrEquals(tc, "match", q);
533  CuAssertStrEquals(tc, "this",  p);
534 
535  strcpy(str, "size_exceeds(800), match_prefix(/home), match_regex(.*\\.mpg) ");
536  CuAssertTrue(tc, sh_restrict_list == NULL);
537  res = sh_restrict_define(str);
538  CuAssertIntEquals(tc,0,res);
539  CuAssertPtrNotNull(tc, sh_restrict_list);
540
541  sh_restrict_purge();
542  CuAssertTrue(tc, sh_restrict_list == NULL);
543
544  strcpy(str, "size_exceeds(800), match_prefix(/home), match_regex(.*\\.mpg), match_permission(0755) ");
545  CuAssertTrue(tc, sh_restrict_list == NULL);
546  res = sh_restrict_define(str);
547  CuAssertIntEquals(tc,0,res);
548  CuAssertPtrNotNull(tc, sh_restrict_list);
549
550  strcpy(str, "size_exceeds(800), match_prefix(/foo), have_permission(0100)");
551  res = sh_restrict_define(str);
552  CuAssertIntEquals(tc,0,res);
553  CuAssertPtrNotNull(tc, sh_restrict_list);
554
555  res = sh_restrict_this("/home/foo.mpg", 1000, 0755, 0);
556  CuAssertIntEquals(tc,1,res);
557
558  res = sh_restrict_this("/foo.mpg",      1000, 0755, 0);
559  CuAssertIntEquals(tc,1,res);
560
561  /* size too small */
562  res = sh_restrict_this("/foo.mpg",       600, 0755, 0);
563  CuAssertIntEquals(tc,0,res);
564
565  /* no execute permission */
566  res = sh_restrict_this("/foo.mpg",       600, 0644, 0);
567  CuAssertIntEquals(tc,0,res);
568
569  /* regex does not match */
570   res = sh_restrict_this("/home/foo",     1000, 0755, 0);
571  CuAssertIntEquals(tc,0,res);
572
573  /* wrong permission */
574  res = sh_restrict_this("/home/foo.mpg", 1000, 0705, 0);
575  CuAssertIntEquals(tc,0,res);
576 
577  /* size too small */
578  res = sh_restrict_this("/home/foo.mpg",  600, 0755, 0);
579  CuAssertIntEquals(tc,0,res);
580 
581  /* wrong prefix */
582  res = sh_restrict_this("/hoff/foo.mpg", 1000, 0755, 0);
583  CuAssertIntEquals(tc,0,res);
584 
585  sh_restrict_purge();
586  CuAssertTrue(tc, sh_restrict_list == NULL);
587
588  fd = sl_open_fastread(FIL__, __LINE__, "/bin/sh", SL_NOPRIV);
589  CuAssertTrue(tc, fd > 0);
590
591  strcpy(str, "match_prefix(/bin), match_filetype(EXECUTABLE:UNIX:ELF)");
592  res = sh_restrict_define(str);
593  CuAssertIntEquals(tc,0,res);
594  CuAssertPtrNotNull(tc, sh_restrict_list);
595
596#if !defined(HOST_IS_CYGWIN)
597  res = sh_restrict_this("/bin/sh", 1000, 0755, fd);
598  CuAssertIntEquals(tc,1,res);
599#endif
600
601  sl_close(fd);
602
603  sh_restrict_purge();
604  CuAssertTrue(tc, sh_restrict_list == NULL);
605
606  strcpy(str, "match_filetype(FILE:TEXT:COPYING)");
607  res = sh_restrict_define(str);
608  CuAssertIntEquals(tc,0,res);
609  CuAssertPtrNotNull(tc, sh_restrict_list);
610
611  p = getcwd(buf, sizeof(buf));
612  CuAssertPtrNotNull(tc, p);
613
614  strcpy(str, "0:0:0:FILE:TEXT:COPYING:Copying:=0a=53=41=4d=48=41=49=4e");
615  res = sh_restrict_add_ftype(str);
616  CuAssertIntEquals(tc,0,res);
617
618  sl_strlcat(buf, "/COPYING", sizeof(buf));
619  fd = sl_open_fastread(FIL__, __LINE__, buf, SL_NOPRIV);
620  CuAssertTrue(tc, fd > 0);
621
622  res = sh_restrict_this(buf, 1000, 0755, fd);
623  CuAssertIntEquals(tc,1,res);
624
625  res = sh_restrict_add_ftype(str);
626  CuAssertIntEquals(tc,0,res);
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
632  res = sh_restrict_add_ftype(str);
633  CuAssertIntEquals(tc,0,res);
634  res = sh_restrict_add_ftype(str);
635  CuAssertIntEquals(tc,0,res);
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
641  res = sh_restrict_add_ftype(str);
642  CuAssertIntEquals(tc,0,res);
643  res = sh_restrict_add_ftype(str);
644  CuAssertIntEquals(tc,0,res);
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
650  res = sh_restrict_add_ftype(str);
651  CuAssertIntEquals(tc,0,res);
652  res = sh_restrict_add_ftype(str);
653  CuAssertIntEquals(tc,0,res);
654  res = sh_restrict_add_ftype(str);
655  CuAssertIntEquals(tc,0,res);
656  res = sh_restrict_add_ftype(str);
657  CuAssertIntEquals(tc,0,res);
658
659  res = sh_restrict_add_ftype(str);
660  CuAssertIntEquals(tc,-1,res);
661
662  sh_restrict_purge();
663  CuAssertTrue(tc, sh_restrict_list == NULL);
664
665  res = sh_restrict_add_ftype(str);
666  CuAssertIntEquals(tc,0,res);
667 
668#else
669  (void) tc;
670/* #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
671#endif
672
673}
674#endif
675
676
Note: See TracBrowser for help on using the repository browser.