source: trunk/src/sh_files.c @ 481

Last change on this file since 481 was 481, checked in by katerina, 6 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

File size: 81.1 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 1999 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#if defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
23#define _XOPEN_SOURCE 500
24#endif
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <ctype.h>
30#include <limits.h>
31
32#include <errno.h>
33
34/* Must be before <utime.h> on FreeBSD
35 */
36#include <sys/types.h>
37#include <unistd.h>
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <fcntl.h>
41
42#if !defined(O_NOATIME)
43#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__PPC__))
44#define O_NOATIME 01000000
45#endif
46#endif
47
48#include <utime.h>
49
50#ifdef HAVE_DIRENT_H
51#include <dirent.h>
52#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
53#else
54#define dirent direct
55#define NAMLEN(dirent) (dirent)->d_namlen
56#ifdef HAVE_SYS_NDIR_H
57#include <sys/ndir.h>
58#endif
59#ifdef HAVE_SYS_DIR_H
60#include <sys/dir.h>
61#endif
62#ifdef HAVE_NDIR_H
63#include <ndir.h>
64#endif
65#endif
66#define NEED_ADD_DIRENT
67
68#ifdef HAVE_GLOB_H
69#include <glob.h>
70#endif
71#ifdef HAVE_FNMATCH_H
72#include <fnmatch.h>
73#endif
74
75
76#include "samhain.h"
77
78#if (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
79
80#include "sh_pthread.h"
81#include "sh_error.h"
82#include "sh_utils.h"
83#include "sh_unix.h"
84#include "sh_files.h"
85#include "sh_tiger.h"
86#include "sh_hash.h"
87#include "sh_ignore.h"
88#include "sh_inotify.h"
89#include "zAVLTree.h"
90#include "sh_dbIO.h"
91
92#undef  FIL__
93#define FIL__  _("sh_files.c")
94
95extern sh_watches sh_file_watches;
96
97static char * sh_files_C_dequote (char * s, size_t * length)
98{
99  size_t i, len = *length;
100  int    flag = 0;
101  char  *p, *q, *po, *pend;
102 
103  /* search for backslash
104   */
105  for (i = 0; i < len; ++i)
106    {
107      if (s[i] == '\\')
108        {
109          flag = 1;
110          break;
111        }
112    }
113
114  if (flag == 0 || *s == '\0')
115    return s;
116
117  po = SH_ALLOC(len+1); *po = '\0'; p = po; pend = &po[len];
118
119  q = s;
120
121  do
122    {
123      if (*q == '\\')
124        {
125          ++q;
126
127          if (*q == '\0')
128            { *p = *q; flag = 0; break; }
129          else if (*q == 'a')
130            { *p = '\a'; ++p; ++q; }
131          else if (*q == 'b')
132            { *p = '\b'; ++p; ++q; }
133          else if (*q == 'f')
134            { *p = '\f'; ++p; ++q; }
135          else if (*q == 'n')
136            { *p = '\n'; ++p; ++q; }
137          else if (*q == 'r')
138            { *p = '\r'; ++p; ++q; }
139          else if (*q == 't')
140            { *p = '\t'; ++p; ++q; }
141          else if (*q == 'v')
142            { *p = '\v'; ++p; ++q; }
143          else if (*q == '\\')
144            { *p = '\\'; ++p; ++q; }
145          else if (*q == '\'')
146            { *p = '\''; ++p; ++q; }
147          else if (*q == '"')
148            { *p = '"';  ++p; ++q; }
149          else if (*q == 'x')
150            {
151              if (isxdigit((int) q[1]) && isxdigit((int) q[2]))
152                {
153                  /* hexadecimal value following */
154                  unsigned char cc = (16 * sh_util_hexchar(q[1])) 
155                    + sh_util_hexchar(q[2]);
156                  *p = (char) cc;
157                  ++p; q += 3;
158                }
159              else
160                {
161                  *p = '\0'; flag = 0; break;
162                }
163            }
164          else if (isdigit((int)*q))
165            {
166              if (isdigit((int) q[1]) && q[1] < '8' && 
167                  isdigit((int) q[2]) && q[2] < '8')
168                {
169                  /* octal value following */
170                  char tmp[4];  unsigned char cc;
171                  tmp[0] = *q; ++q; tmp[1] = *q; ++q; tmp[2] = *q; ++q; 
172                  tmp[3] = '\0';
173                  cc = strtol(tmp, NULL, 8);
174                  *p = (char) cc; ++p;
175                }
176              else
177                {
178                  *p = '\0'; flag = 0; break;
179                }
180            }
181          else
182            {
183              /* invalid escape sequence */
184              *p = '\0'; flag = 0; break;
185            }
186        }
187      else
188        {
189          *p = *q; 
190          ++p; ++q;
191        }
192    } while (*q && p <= pend);
193
194  SL_REQUIRE (p <= pend, _("p <= pend"));
195
196  if (flag)
197    {
198      *p = '\0';
199      *length = strlen(po);
200    }
201  else
202    {
203      SH_FREE(po);
204      po = NULL;
205      *length = 0;
206    }
207
208  SL_REQUIRE (*length <= len, _("*length <= len"));
209
210  SH_FREE(s);
211  return po;
212}
213
214char * sh_files_parse_input(const char * str_s, size_t * len)
215{
216  char  * p;
217
218  if (!str_s || *str_s == '\0')
219    return NULL;
220
221  *len = sl_strlen(str_s);
222
223  if ( (str_s[0] == '"'  && str_s[*len-1] == '"' ) ||
224       (str_s[0] == '\'' && str_s[*len-1] == '\'') )
225    {
226      if (*len < 3)
227        return NULL;
228      --(*len);
229      p = sh_util_strdup_l(&str_s[1], *len);
230      p[*len-1] = '\0';
231      --(*len);
232    }
233  else
234    {
235      p = sh_util_strdup_l(str_s, *len);
236    }
237
238  p = sh_files_C_dequote(p, len);
239
240  return p;
241}
242
243
244extern int flag_err_debug;
245extern int flag_err_info;
246
247int sh_files_reportonce(const char * c)
248{
249  int i;
250  SL_ENTER(_("sh_files_reportonce"));
251  i = sh_util_flagval(c, &(sh.flag.reportonce));
252
253  SL_RETURN(i, _("sh_files_reportonce"));
254}
255   
256int sh_files_fulldetail(const char * c)
257{
258  int i;
259  SL_ENTER(_("sh_files_fulldetail"));
260  i = sh_util_flagval(c, &(sh.flag.fulldetail));
261
262  SL_RETURN((i), _("sh_files_fulldetail"));
263}
264   
265
266typedef struct dir_struct {
267  long    NumRegular;
268  long    NumDirs;
269  long    NumSymlinks;
270  long    NumFifos;
271  long    NumSockets;
272  long    NumCDev;
273  long    NumBDev;
274  long    NumDoor;
275  long    NumPort;
276  long    NumAll;
277  long    TotalBytes;
278  char    DirPath[PATH_MAX];
279} dir_type;
280
281typedef struct dirstack_entry {
282  char                  * name;
283  int                     class;
284  unsigned long           check_flags;
285  int                     rdepth;
286  short                   checked;
287  short                   childs_checked;
288  short                   is_reported;
289  /* struct dirstack_entry * next; */
290} dirstack_t;
291
292
293/* the destructor
294 */
295void free_dirstack (void * inptr)
296{
297  dirstack_t * here;
298
299  SL_ENTER(_("free_dirstack"));
300  if (inptr == NULL)
301    SL_RET0(_("free_dirstack"));
302  else
303    here = (dirstack_t *) inptr;
304
305  if (here->name != NULL)
306    SH_FREE(here->name);
307  SH_FREE(here);
308  SL_RET0(_("free_dirstack"));
309}
310
311/* Function to return the key for indexing
312 * the argument
313 */
314zAVLKey zdirstack_key (void const * arg)
315{
316  const dirstack_t * sa = (const dirstack_t *) arg;
317  return (zAVLKey) sa->name;
318}
319
320#define SH_LIST_FILE 0
321#define SH_LIST_DIR1 1
322#define SH_LIST_DIR2 2
323
324
325static int which_dirList = SH_LIST_DIR1;
326
327static zAVLTree * zdirListOne   = NULL;
328static zAVLTree * zdirListTwo   = NULL;
329static zAVLTree * zfileList     = NULL;
330
331SH_MUTEX_STATIC(mutex_zfiles,      PTHREAD_MUTEX_INITIALIZER);
332SH_MUTEX_STATIC(mutex_zglob,       PTHREAD_MUTEX_INITIALIZER);
333SH_MUTEX_RECURSIVE(mutex_zdirs);
334
335static int        sh_files_fullpath  (const char * testdir, 
336                                      const char * d_name, 
337                                      char * statpath);
338static int        sh_files_pushdir   (int class, const char * str_s);
339static int        sh_files_pushfile  (int class, const char * str_s);
340
341static long MaxRecursionLevel = 0;
342
343/* set default recursion level
344 */
345int sh_files_setrecursion (const char * flag_s)
346{
347  long flag = 0;
348  static int reject = 0;
349
350  SL_ENTER( _("sh_files_setrecursion"));
351
352  if (reject == 1)
353    SL_RETURN((-1), _("sh_files_setrecursion"));
354
355  if (sh.flag.opts == S_TRUE) 
356    reject = 1;
357
358  if (flag_s != NULL) 
359    flag = (int)(atof(flag_s));
360
361  if (flag >= 0 && flag <= 99)
362    MaxRecursionLevel = flag;
363  else
364    SL_RETURN((-1), _("sh_files_setrecursion"));
365
366  SL_RETURN((0), _("sh_files_setrecursion"));
367}
368
369static int handle_filecheck_ret(dirstack_t * ptr, char * tmp_in, int status)
370{
371  int fcount = 0;
372  char * tmp;
373
374  if (!tmp_in)
375    tmp = sh_util_safe_name (ptr->name);
376  else
377    tmp = tmp_in;
378
379  if (status == SH_FILE_UNKNOWN && (!SH_FFLAG_REPORTED_SET(ptr->is_reported)))
380    {
381      TPT(( 0, FIL__, __LINE__, _("msg=<file: %s> status=<%d>\n"), 
382            tmp, status));
383     
384      if ( sh.flag.checkSum == SH_CHECK_INIT  || 
385           sh_hash_have_it (ptr->name) >= 0)
386        {
387          if (S_FALSE == sh_ignore_chk_del(ptr->name))
388            {
389              if (0 != hashreport_missing(ptr->name, 
390                                          (ptr->class == SH_LEVEL_ALLIGNORE) ? 
391                                          ShDFLevel[ptr->class] : 
392                                          ShDFLevel[SH_ERR_T_FILE])) {
393                if (tmp == NULL) 
394                  tmp = sh_util_safe_name (ptr->name);
395                sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ? 
396                                 ShDFLevel[ptr->class] : 
397                                 ShDFLevel[SH_ERR_T_FILE],
398                                 FIL__, __LINE__, 0, MSG_FI_MISS,
399                                 tmp);
400                ++sh.statistics.files_report;
401              }
402            }
403        }
404      else /* not there at init, and still missing */
405        {
406          if (tmp == NULL) 
407            tmp = sh_util_safe_name (ptr->name);
408          sh_error_handle (SH_ERR_NOTICE,
409                           FIL__, __LINE__, 0,
410                           MSG_FI_FAIL,
411                           tmp);
412        }
413
414      if (sh.flag.checkSum != SH_CHECK_INIT) 
415        sh_hash_set_missing(ptr->name);
416
417      if (sh.flag.reportonce == S_TRUE)
418        SET_SH_FFLAG_REPORTED(ptr->is_reported);
419    }
420  else 
421    {
422      /* exists (status >= 0), but was missing (reported == TRUE)
423       */
424      if (status != SH_FILE_UNKNOWN && SH_FFLAG_REPORTED_SET(ptr->is_reported))
425        {
426          CLEAR_SH_FFLAG_REPORTED(ptr->is_reported);
427          sh_hash_clear_flag(ptr->name, SH_FFLAG_ENOENT);
428        }
429     
430      /* Catchall
431       */
432      else if (status == SH_FILE_UNKNOWN)
433        {
434          /* Thu Mar  7 15:09:40 CET 2002 Make sure missing file
435           * is reported if ptr->reported == S_TRUE because the
436           * file has been added.
437           */
438          if (sh_hash_have_it (ptr->name) >= 0 && 
439              !SH_FFLAG_REPORTED_SET(ptr->is_reported))
440            {
441              if (S_FALSE == sh_ignore_chk_del(ptr->name))
442                {
443                  if (0 != hashreport_missing(ptr->name, 
444                                              (ptr->class == SH_LEVEL_ALLIGNORE) ? 
445                                              ShDFLevel[ptr->class] : 
446                                              ShDFLevel[SH_ERR_T_FILE])) {
447                    if (tmp == NULL) 
448                      tmp = sh_util_safe_name (ptr->name);
449                    sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE)? 
450                                     ShDFLevel[ptr->class] : 
451                                     ShDFLevel[SH_ERR_T_FILE],
452                                     FIL__, __LINE__, 0, MSG_FI_MISS,
453                                     tmp);
454                    ++sh.statistics.files_report;
455                  }
456                }
457
458              /* delete from database
459               */
460              if (sh.flag.checkSum != SH_CHECK_INIT) 
461                sh_hash_set_missing(ptr->name);
462            }
463          else
464            {
465              if (tmp == NULL) 
466                tmp = sh_util_safe_name (ptr->name);
467              sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0,
468                               MSG_FI_FAIL,
469                               tmp);
470              if (sh.flag.checkSum != SH_CHECK_INIT)
471                sh_hash_set_visited_true(ptr->name);
472            }
473        }
474     
475      ++fcount;
476    }
477  if (!tmp_in)
478    SH_FREE(tmp);
479
480  return fcount;
481}
482
483
484unsigned long sh_files_chk ()
485{
486  zAVLCursor    cursor;
487  ShFileType    status;
488  unsigned long fcount = 0;
489
490  char       * tmp = NULL;
491
492  dirstack_t * ptr;
493  char       * dir;
494  char       * file;
495  int          tmp_reported;
496 
497  SL_ENTER(_("sh_files_chk"));
498
499  for (ptr = (dirstack_t *) zAVLFirst(&cursor, zfileList); ptr;
500       ptr = (dirstack_t *) zAVLNext(&cursor))
501    {
502
503      if (sig_urgent > 0) {
504        SL_RETURN(fcount, _("sh_files_chk"));
505      }
506
507      if (ptr->checked == S_FALSE)
508        {
509          dir  = sh_util_dirname (ptr->name);
510          file = sh_util_basename (ptr->name);
511#if defined(WITH_TPT)
512          tmp = sh_util_safe_name (ptr->name);
513#endif
514
515         
516          if (flag_err_info == S_TRUE)
517            {
518              char pstr[32];
519#if !defined(WITH_TPT)
520              tmp = sh_util_safe_name (ptr->name);
521#endif
522              sl_strlcpy(pstr, sh_hash_getpolicy(ptr->class), sizeof(pstr));
523              sh_error_handle ((-1),  FIL__, __LINE__, 0, 
524                               MSG_FI_CHK, pstr, tmp);
525            }
526
527          if ((sh.flag.inotify & SH_INOTIFY_INSCAN) != 0)
528            {
529              sh_inotify_add_watch_later(ptr->name, &sh_file_watches, NULL,
530                                         ptr->class, ptr->check_flags, 
531                                         SH_INOTIFY_FILE, 0);
532            }
533
534          BREAKEXIT(sh_files_filecheck);
535          tmp_reported = ptr->is_reported; /* fix aliasing warning */ 
536          status = sh_files_filecheck (ptr->class, ptr->check_flags, dir, file, 
537                                       &tmp_reported, 0);
538          ptr->is_reported = tmp_reported;
539         
540          TPT(( 0, FIL__, __LINE__, 
541                _("msg=<filecheck complete: %s> status=<%d> reported=<%d>\n"), 
542                tmp, status, ptr->is_reported));
543
544          fcount += handle_filecheck_ret(ptr, tmp, status);
545         
546          if (tmp != NULL)
547            {
548              SH_FREE(tmp);
549              tmp = NULL;
550            }
551          if (file)
552            SH_FREE(file);
553          if (dir)
554            SH_FREE(dir);
555
556          ptr->checked = S_TRUE;
557        }
558    }
559
560  SL_RETURN(fcount, _("sh_files_chk"));
561}
562
563static zAVLTree * fileTree = NULL;
564static zAVLTree * dirTree  = NULL;
565
566static void clear_lists()
567{
568  if (fileTree) {
569    zAVL_string_reset(fileTree);
570    fileTree  = NULL;
571  }
572  if (dirTree) {
573    zAVL_string_reset(dirTree);
574    dirTree  = NULL;
575  }
576  return;
577}
578
579static void add_to_filelist(zAVLTree * tree)
580{
581  dirstack_t * ptr;
582  zAVLCursor   avlcursor;
583
584  SL_ENTER(_("add_to_filelist"));
585
586  SH_MUTEX_LOCK(mutex_zfiles);
587  for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
588       ptr = (dirstack_t *) zAVLNext(&avlcursor))
589    zAVL_string_set (&fileTree, ptr->name);
590  SH_MUTEX_UNLOCK(mutex_zfiles);
591  SL_RET0(_("add_to_filelist"));
592}
593static void add_to_dirlist(zAVLTree * tree)
594{
595  dirstack_t * ptr;
596  zAVLCursor   avlcursor;
597
598  SL_ENTER(_("add_to_dirlist"));
599
600  SH_MUTEX_LOCK(mutex_zfiles);
601  for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
602       ptr = (dirstack_t *) zAVLNext(&avlcursor))
603    zAVL_string_set (&dirTree, ptr->name);
604  SH_MUTEX_UNLOCK(mutex_zfiles);
605  SL_RET0(_("add_to_dirlist"));
606}
607char * sh_files_findfile(const char * path)
608{
609  return zAVL_string_get (fileTree, path);
610}
611
612void * sh_dummy_621_candidate;
613
614static char * intern_find_morespecific_dir(zAVLTree * tree, 
615                                           const char * path, size_t * len)
616{
617  dirstack_t * ptr;
618  zAVLCursor   avlcursor;
619  size_t       l_path = strlen(path);
620  size_t       l_name;
621  char *       candidate = NULL;
622  size_t       l_candidate = 0;
623 
624  if (NULL == tree)
625    return NULL;
626
627  sh_dummy_621_candidate = (void *) &candidate;
628
629  SH_MUTEX_LOCK(mutex_zfiles);
630  for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
631       ptr = (dirstack_t *) zAVLNext(&avlcursor))
632    {
633      l_name = strlen(ptr->name);
634      if (l_name <= l_path)
635        {
636          if (0 == strncmp(ptr->name, path, l_name))
637            {
638              if ((l_name == l_path) || (path[l_name] == '/'))
639                {
640                  if (!candidate || (l_candidate < l_name))
641                    {
642                      candidate = ptr->name;
643                      l_candidate = l_name;
644                      *len = l_candidate;
645                    }
646                }
647            }
648        }
649    }
650  SH_MUTEX_UNLOCK(mutex_zfiles);
651  return candidate;
652}
653char * sh_files_find_mostspecific_dir(const char * path)
654{
655  size_t l_one = 0;
656  size_t l_two = 0;
657  char * one;
658  char * two;
659
660  one = intern_find_morespecific_dir(zdirListOne, path, &l_one);
661  two = intern_find_morespecific_dir(zdirListTwo, path, &l_two);
662
663  if      (l_one > l_two) return one;
664  else                    return two;
665}
666
667int sh_files_delfilestack ()
668{
669  SL_ENTER(_("sh_files_delfilestack"));
670
671  SH_MUTEX_LOCK(mutex_zfiles);
672  zAVLFreeTree (zfileList, free_dirstack);
673  zfileList = NULL;
674  SH_MUTEX_UNLOCK(mutex_zfiles);
675
676  SL_RETURN(0, _("sh_files_delfilestack"));
677}
678 
679int sh_files_setrec_int (zAVLTree * tree)
680{
681  dirstack_t * ptr;
682  zAVLCursor   avlcursor;
683
684  SL_ENTER(_("sh_files_setrec"));
685  if (tree != NULL) {
686    for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
687         ptr = (dirstack_t *) zAVLNext(&avlcursor))
688      {
689        if (ptr->rdepth < (-1) || ptr->rdepth > 99)
690          {
691            ptr->rdepth = MaxRecursionLevel;
692          }
693
694        if ( (ptr->rdepth      == (-1)) && 
695             (ptr->class       == SH_LEVEL_ALLIGNORE) && 
696             (sh.flag.checkSum != SH_CHECK_INIT))
697          hash_remove_tree (ptr->name);
698      }
699  }
700  SL_RETURN(0, _("sh_files_setrec"));
701}
702
703int sh_files_setrec ()
704{
705  volatile int ret;
706  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
707  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
708  clear_lists();
709  add_to_dirlist(zdirListOne);
710  add_to_dirlist(zdirListTwo);
711  add_to_filelist(zfileList);
712  sh_files_setrec_int(zdirListOne);
713  ret = sh_files_setrec_int(zdirListTwo);
714  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
715
716  return ret;
717}
718
719zAVLTree * sh_files_deldirstack_int (zAVLTree * ptr)
720{
721  SL_ENTER(_("sh_files_deldirstack"));
722
723  zAVLFreeTree (ptr, free_dirstack);
724
725  SL_RETURN(NULL, _("sh_files_deldirstack"));
726}
727
728int sh_files_deldirstack ()
729{
730  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
731  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
732  zdirListOne = sh_files_deldirstack_int(zdirListOne);
733  zdirListTwo = sh_files_deldirstack_int(zdirListTwo);
734  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
735  return 0;
736}
737
738void sh_files_reset()
739{
740  dirstack_t * ptr;
741  zAVLCursor   avlcursor;
742
743  SL_ENTER(_("sh_files_reset"));
744
745  SH_MUTEX_LOCK(mutex_zfiles);
746  for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, zfileList); ptr;
747       ptr = (dirstack_t *) zAVLNext(&avlcursor))
748    ptr->checked = 0;
749  SH_MUTEX_UNLOCK(mutex_zfiles);
750  SL_RET0(_("sh_files_reset"));
751}
752
753void sh_dirs_reset()
754{
755  dirstack_t * ptr;
756  zAVLCursor   avlcursor1;
757  zAVLCursor   avlcursor2;
758
759  SL_ENTER(_("sh_dirs_reset"));
760
761  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
762  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
763  for (ptr = (dirstack_t *) zAVLFirst(&avlcursor1, zdirListOne); ptr;
764       ptr = (dirstack_t *) zAVLNext(&avlcursor1))
765    ptr->checked = 0;
766
767  for (ptr = (dirstack_t *) zAVLFirst(&avlcursor2, zdirListTwo); ptr;
768       ptr = (dirstack_t *) zAVLNext(&avlcursor2))
769    ptr->checked = 0;
770  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
771
772  SL_RET0(_("sh_dirs_reset"));
773}
774
775
776int sh_files_pushfile_prelink (const char * str_s)
777{
778  return (sh_files_pushfile (SH_LEVEL_PRELINK, str_s));
779}
780
781int sh_files_pushfile_user0 (const char * str_s)
782{
783  return (sh_files_pushfile (SH_LEVEL_USER0, str_s));
784}
785
786int sh_files_pushfile_user1 (const char * str_s)
787{
788  return (sh_files_pushfile (SH_LEVEL_USER1, str_s));
789}
790
791int sh_files_pushfile_user2 (const char * str_s)
792{
793  return (sh_files_pushfile (SH_LEVEL_USER2, str_s));
794}
795
796int sh_files_pushfile_user3 (const char * str_s)
797{
798  return (sh_files_pushfile (SH_LEVEL_USER3, str_s));
799}
800
801int sh_files_pushfile_user4 (const char * str_s)
802{
803  return (sh_files_pushfile (SH_LEVEL_USER4, str_s));
804}
805
806
807int sh_files_pushfile_ro (const char * str_s)
808{
809  return (sh_files_pushfile (SH_LEVEL_READONLY, str_s));
810}
811
812int sh_files_pushfile_attr (const char * str_s)
813{
814  return (sh_files_pushfile (SH_LEVEL_ATTRIBUTES, str_s));
815}
816
817int sh_files_pushfile_log (const char * str_s)
818{
819  return (sh_files_pushfile (SH_LEVEL_LOGFILES, str_s));
820}
821
822int sh_files_pushfile_glog (const char * str_s)
823{
824  return (sh_files_pushfile (SH_LEVEL_LOGGROW, str_s));
825}
826
827int sh_files_pushfile_noig (const char * str_s)
828{
829  return (sh_files_pushfile (SH_LEVEL_NOIGNORE, str_s));
830}
831
832int sh_files_pushfile_allig (const char * str_s)
833{
834  return (sh_files_pushfile (SH_LEVEL_ALLIGNORE, str_s));
835}
836
837
838static void sh_files_set_mask (unsigned long * mask, 
839                               unsigned long val, int act)
840{
841  SL_ENTER(_("sh_files_set_mask"));
842
843  if       (act == 0)
844    (*mask)  = val;
845  else if  (act > 0)
846    (*mask) |= val;
847  else 
848    (*mask) &= ~val;
849
850  SL_RET0(_("sh_files_set_mask"));
851}
852
853/* set mask(class)
854 */
855static int sh_files_parse_mask (unsigned long * mask, const char * str)
856{
857  int l, i = 0, act = 0, k = 0;
858  char  myword[64];
859 
860  SL_ENTER(_("sh_files_parse_mask"));
861
862  myword[0] = '\0';
863
864  if (str == NULL)
865    {
866      SL_RETURN ( (-1), _("sh_files_parse_mask"));
867    }
868  else
869    l = sl_strlen(str);
870
871  while (i < l) {
872
873    if (str[i] == '\0')
874      break;
875
876    if (str[i] == ' ' || str[i] == '\t' || str[i] == ',')
877      {
878        ++i;
879        continue;
880      }
881
882    if (str[i] == '+')
883      {
884        act = +1; ++i;
885        myword[0] = '\0';
886        goto getword;
887      }
888    else if (str[i] == '-')
889      {
890        act = -1; ++i;
891        myword[0] = '\0';
892        goto getword;
893      }
894    else /* a word */
895      {
896      getword:
897        k = 0;
898        while (k < 63 && str[i] != ' ' && str[i] != '\t' && str[i] != ','
899               && str[i] != '+' && str[i] != '-' && str[i] != '\0') {
900          myword[k] = str[i]; 
901          ++i; ++k;
902        }
903        myword[k] = '\0';
904
905        if (sl_strlen(myword) == 0)
906          {
907            SL_RETURN ( (-1), _("sh_files_parse_mask"));
908          }
909
910/* checksum     */
911        if      (0 == strcmp(myword, _("CHK")))
912          sh_files_set_mask (mask, MODI_CHK, act);
913/* link         */
914        else if (0 == strcmp(myword, _("LNK")))
915          sh_files_set_mask (mask, MODI_LNK, act);
916/* inode        */
917        else if (0 == strcmp(myword, _("RDEV")))
918          sh_files_set_mask (mask, MODI_RDEV, act);
919/* inode        */
920        else if (0 == strcmp(myword, _("INO")))
921          sh_files_set_mask (mask, MODI_INO, act);
922/* user         */
923        else if (0 == strcmp(myword, _("USR")))
924          sh_files_set_mask (mask, MODI_USR, act);
925/* group        */
926        else if (0 == strcmp(myword, _("GRP")))
927          sh_files_set_mask (mask, MODI_GRP, act);
928/* mtime        */
929        else if (0 == strcmp(myword, _("MTM")))
930          sh_files_set_mask (mask, MODI_MTM, act);
931/* ctime        */
932        else if (0 == strcmp(myword, _("CTM")))
933          sh_files_set_mask (mask, MODI_CTM, act);
934/* atime        */
935        else if (0 == strcmp(myword, _("ATM")))
936          sh_files_set_mask (mask, MODI_ATM, act);
937/* size         */
938        else if (0 == strcmp(myword, _("SIZ")))
939          sh_files_set_mask (mask, MODI_SIZ, act);
940/* file mode    */
941        else if (0 == strcmp(myword, _("MOD")))
942          sh_files_set_mask (mask, MODI_MOD, act);
943/* hardlinks    */
944        else if (0 == strcmp(myword, _("HLN")))
945          sh_files_set_mask (mask, MODI_HLN, act);
946/* size may grow */
947        else if (0 == strcmp(myword, _("SGROW")))
948          sh_files_set_mask (mask, MODI_SGROW, act);
949/* use prelink */
950        else if (0 == strcmp(myword, _("PRE")))
951          sh_files_set_mask (mask, MODI_PREL, act);
952/* get content */
953        else if (0 == strcmp(myword, _("TXT")))
954          sh_files_set_mask (mask, MODI_TXT, act);
955/* get content */
956        else if (0 == strcmp(myword, _("AUDIT")))
957          sh_files_set_mask (mask, MODI_AUDIT, act);
958        else
959          {
960            SL_RETURN ( (-1), _("sh_files_parse_mask"));
961          }
962        act       = 0;
963        myword[0] = '\0';
964      }
965  }
966  SL_RETURN ( (0), _("sh_files_parse_mask"));
967}
968
969int sh_files_redef_prelink(const char * str)
970{
971  return (sh_files_parse_mask(&mask_PRELINK, str));
972} 
973int sh_files_redef_user0(const char * str)
974{
975  return (sh_files_parse_mask(&mask_USER0, str));
976} 
977int sh_files_redef_user1(const char * str)
978{
979  return (sh_files_parse_mask(&mask_USER1, str));
980} 
981int sh_files_redef_user2(const char * str)
982{
983  return (sh_files_parse_mask(&mask_USER2, str));
984} 
985int sh_files_redef_user3(const char * str)
986{
987  return (sh_files_parse_mask(&mask_USER3, str));
988} 
989int sh_files_redef_user4(const char * str)
990{
991  return (sh_files_parse_mask(&mask_USER4, str));
992} 
993int sh_files_redef_readonly(const char * str)
994{
995  return (sh_files_parse_mask(&mask_READONLY, str));
996} 
997int sh_files_redef_loggrow(const char * str)
998{
999  return (sh_files_parse_mask(&mask_LOGGROW, str));
1000} 
1001int sh_files_redef_logfiles(const char * str)
1002{
1003  return (sh_files_parse_mask(&mask_LOGFILES, str));
1004} 
1005int sh_files_redef_attributes(const char * str)
1006{
1007  return (sh_files_parse_mask(&mask_ATTRIBUTES, str));
1008} 
1009int sh_files_redef_noignore(const char * str)
1010{
1011  return (sh_files_parse_mask(&mask_NOIGNORE, str));
1012} 
1013int sh_files_redef_allignore(const char * str)
1014{
1015  return (sh_files_parse_mask(&mask_ALLIGNORE, str));
1016} 
1017
1018unsigned long sh_files_maskof (int class)
1019{
1020  switch (class)
1021    {
1022    case SH_LEVEL_READONLY:
1023      return (unsigned long) (mask_READONLY | MODI_INIT);
1024    case SH_LEVEL_ATTRIBUTES:
1025      return (unsigned long) (mask_ATTRIBUTES | MODI_INIT);
1026    case SH_LEVEL_LOGFILES:
1027      return (unsigned long) (mask_LOGFILES | MODI_INIT);
1028    case SH_LEVEL_LOGGROW:
1029      return (unsigned long) (mask_LOGGROW | MODI_INIT);
1030    case SH_LEVEL_ALLIGNORE:
1031      return (unsigned long) (mask_ALLIGNORE | MODI_INIT);
1032    case SH_LEVEL_NOIGNORE:
1033      return (unsigned long) (mask_NOIGNORE | MODI_INIT);
1034    case SH_LEVEL_USER0:
1035      return (unsigned long) (mask_USER0 | MODI_INIT);
1036    case SH_LEVEL_USER1:
1037      return (unsigned long) (mask_USER1 | MODI_INIT);
1038    case SH_LEVEL_USER2:
1039      return (unsigned long) (mask_USER2 | MODI_INIT);
1040    case SH_LEVEL_USER3:
1041      return (unsigned long) (mask_USER3 | MODI_INIT);
1042    case SH_LEVEL_USER4:
1043      return (unsigned long) (mask_USER4 | MODI_INIT);
1044    case SH_LEVEL_PRELINK:
1045      return (unsigned long) (mask_PRELINK | MODI_INIT);
1046    default:
1047      return (unsigned long) 0;
1048    }
1049}
1050
1051#ifdef HAVE_GLOB_H
1052int sh_files_has_metachar (const char * str)
1053{
1054  SL_ENTER(_("sh_files_has_metachar"));
1055  if      (NULL != strchr(str, '*'))
1056    SL_RETURN(1, _("sh_files_has_metachar"));
1057  else if (NULL != strchr(str, '?'))
1058    SL_RETURN(1, _("sh_files_has_metachar"));
1059  else if (NULL != (strchr(str, '[')))
1060    SL_RETURN(1, _("sh_files_has_metachar"));
1061  else
1062    SL_RETURN(0, _("sh_files_has_metachar"));
1063}
1064
1065
1066int sh_files_globerr (const char * epath, int errnum)
1067{
1068  char * p;
1069  char errbuf[SH_ERRBUF_SIZE];
1070
1071  SL_ENTER(_("sh_files_globerr"));
1072
1073  if (errnum == ENOTDIR || errnum == ENOENT)
1074    {
1075      SL_RETURN(0, _("sh_files_globerr"));
1076    }
1077
1078  p = sh_util_safe_name (epath);
1079  sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_FI_GLOB,
1080                   sh_error_message (errnum, errbuf, sizeof(errbuf)), p);
1081  SH_FREE(p);
1082
1083  SL_RETURN(0, _("sh_files_globerr"));
1084}
1085
1086/* #ifdef HAVE_GLOB_H
1087 */
1088#endif
1089
1090int sh_files_push_file_int (int class, const char * str_s, size_t len, 
1091                            unsigned long check_flags)
1092{
1093  dirstack_t * new_item_ptr;
1094  char  * fileName;
1095  int     ret;
1096  volatile int     count = 0;
1097
1098  SL_ENTER(_("sh_files_push_file_int"));
1099
1100  fileName = SH_ALLOC(len+1);
1101  sl_strlcpy(fileName, str_s, len+1);
1102
1103  new_item_ptr = (dirstack_t *) SH_ALLOC (sizeof(dirstack_t));
1104
1105  new_item_ptr->name           = fileName;
1106  new_item_ptr->class          = class;
1107  new_item_ptr->check_flags     = check_flags;
1108  new_item_ptr->rdepth         = 0;
1109  new_item_ptr->checked        = S_FALSE;
1110  new_item_ptr->is_reported    = 0;
1111  new_item_ptr->childs_checked = S_FALSE;
1112
1113  SH_MUTEX_LOCK(mutex_zfiles);
1114  if (zfileList == NULL)
1115    {
1116      zfileList = zAVLAllocTree (zdirstack_key, zAVL_KEY_STRING);
1117      if (zfileList == NULL) 
1118        {
1119          (void) safe_logger (0, 0, NULL);
1120          aud__exit(FIL__, __LINE__, EXIT_FAILURE);
1121        }
1122    }
1123
1124  ret = zAVLInsert (zfileList, new_item_ptr);
1125  SH_MUTEX_UNLOCK(mutex_zfiles);
1126
1127  if (-1 == ret)
1128    {
1129      (void) safe_logger (0, 0, NULL);
1130      aud__exit(FIL__, __LINE__, EXIT_FAILURE);
1131    }
1132  else if (3 == ret)
1133    { 
1134      if (sh.flag.started != S_TRUE)
1135        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
1136                         fileName);
1137      SH_FREE(fileName);
1138      SH_FREE(new_item_ptr);
1139      new_item_ptr = NULL;
1140    }
1141  else
1142    {
1143      int           reported;
1144      unsigned long check_flags = sh_files_maskof(class);
1145
1146      if ((sh.flag.inotify & SH_INOTIFY_INSCAN) != 0)
1147        {
1148          sh_files_filecheck (class, check_flags, str_s, NULL,
1149                              &reported, 0);
1150          if (SH_FFLAG_REPORTED_SET(reported))
1151            sh_files_set_file_reported(str_s);
1152          sh_inotify_add_watch_later(str_s, &sh_file_watches, NULL,
1153                                     class, check_flags, 
1154                                     SH_INOTIFY_FILE, 0);
1155        }
1156
1157      if (MODI_AUDIT_ENABLED(check_flags))
1158        {
1159          sh_audit_mark(str_s);
1160        }
1161      ++count;
1162    }
1163  SL_RETURN(count, _("sh_files_push_file_int"));
1164}
1165
1166int sh_files_push_dir_int (int class, char * tail, size_t len, int rdepth, unsigned long check_flags);
1167
1168#ifdef HAVE_GLOB_H
1169
1170typedef struct globstack_entry {
1171  char                  * name;
1172  int                     class;
1173  unsigned long           check_flags;
1174  int                     rdepth;
1175  short                   type;
1176  /* struct dirstack_entry * next; */
1177} sh_globstack_t;
1178
1179static zAVLTree * zglobList   = NULL;
1180
1181static int sh_files_pushglob (int class, int type, const char * p, int rdepth,
1182                               unsigned long check_flags_in, int flag)
1183{
1184  int     globstatus = -1;
1185  unsigned int     gloop;
1186  glob_t  pglob;
1187
1188  volatile int     count = 0;
1189  volatile unsigned long check_flags = (flag == 0) ? sh_files_maskof(class) : check_flags_in;
1190 
1191  SL_ENTER(_("sh_files_pushglob"));
1192
1193  pglob.gl_offs = 0;
1194  globstatus    = glob (p, 0, sh_files_globerr, &pglob);
1195 
1196  if (globstatus == 0 && pglob.gl_pathc > 0)
1197    {
1198
1199      if (sh.flag.checkSum != SH_CHECK_INIT)
1200        {
1201          sh_globstack_t * new_item_ptr;
1202          char  * fileName;
1203          int     ret;
1204         
1205          SH_MUTEX_TRYLOCK(mutex_zfiles);
1206          fileName = sh_util_strdup (p);
1207         
1208          new_item_ptr = (sh_globstack_t *) SH_ALLOC (sizeof(sh_globstack_t));
1209         
1210          new_item_ptr->name           = fileName;
1211          new_item_ptr->class          = class;
1212          new_item_ptr->check_flags     = check_flags;
1213          new_item_ptr->rdepth         = rdepth;
1214          new_item_ptr->type           = type;
1215         
1216          if (zglobList == NULL)
1217            {
1218              zglobList = zAVLAllocTree (zdirstack_key, zAVL_KEY_STRING);
1219              if (zglobList == NULL) 
1220                {
1221                  (void) safe_logger (0, 0, NULL);
1222                  aud__exit(FIL__, __LINE__, EXIT_FAILURE);
1223                }
1224            }
1225     
1226          ret = zAVLInsert (zglobList, new_item_ptr);
1227
1228          if (ret != 0) /* already in list */
1229            {
1230              SH_FREE(fileName);
1231              SH_FREE(new_item_ptr);
1232            }
1233          SH_MUTEX_TRYLOCK_UNLOCK(mutex_zfiles);
1234        }
1235
1236      for (gloop = 0; gloop < (unsigned int) pglob.gl_pathc; ++gloop)
1237        {
1238          if (type == SH_LIST_FILE)
1239            {
1240              count += sh_files_push_file_int (class, pglob.gl_pathv[gloop], 
1241                                               sl_strlen(pglob.gl_pathv[gloop]), check_flags);
1242            }
1243          else
1244            {
1245              which_dirList = type;
1246
1247              count += sh_files_push_dir_int  (class, pglob.gl_pathv[gloop], 
1248                                               sl_strlen(pglob.gl_pathv[gloop]), rdepth, check_flags);
1249            }
1250        }
1251    }
1252  else
1253    {
1254      char * tmp = sh_util_safe_name (p);
1255     
1256      if (pglob.gl_pathc == 0
1257#ifdef GLOB_NOMATCH
1258          || globstatus == GLOB_NOMATCH
1259#endif
1260          )
1261        sh_error_handle ((sh.flag.started != S_TRUE) ? SH_ERR_ERR : SH_ERR_NOTICE, 
1262                         FIL__, __LINE__, 
1263                         globstatus, MSG_FI_GLOB,
1264                         _("No matches found"), tmp);
1265#ifdef GLOB_NOSPACE
1266      else if (globstatus == GLOB_NOSPACE)
1267        sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
1268                         globstatus, MSG_FI_GLOB,
1269                         _("Out of memory"), tmp);
1270#endif
1271#ifdef GLOB_ABORTED
1272      else if (globstatus == GLOB_ABORTED)
1273        sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
1274                         globstatus, MSG_FI_GLOB,
1275                         _("Read error"), tmp);
1276#endif
1277      else 
1278        sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
1279                         globstatus, MSG_FI_GLOB,
1280                         _("Unknown error"), tmp);
1281     
1282      SH_FREE(tmp);
1283     
1284    }
1285 
1286  globfree(&pglob);
1287  SL_RETURN(count, _("sh_files_pushglob"));
1288  return count;
1289}
1290
1291void sh_files_check_globFilePatterns()
1292{
1293  sh_globstack_t * testPattern;
1294  zAVLCursor   cursor;
1295
1296  SL_ENTER(_("sh_files_check_globPatterns"));
1297
1298  SH_MUTEX_LOCK(mutex_zglob);
1299  for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList); 
1300       testPattern;
1301       testPattern = (sh_globstack_t *) zAVLNext  (&cursor))
1302    {
1303      if (testPattern->type == SH_LIST_FILE)
1304        {
1305          sh_files_pushglob(testPattern->class, testPattern->type, 
1306                            testPattern->name, testPattern->rdepth,
1307                            testPattern->check_flags, 1);
1308        }
1309    }
1310  SH_MUTEX_UNLOCK(mutex_zglob);
1311  SL_RET0(_("sh_files_check_globPatterns"));
1312}
1313
1314void sh_files_check_globPatterns()
1315{
1316  sh_globstack_t * testPattern;
1317  zAVLCursor   cursor;
1318
1319  SL_ENTER(_("sh_files_check_globPatterns"));
1320
1321  SH_MUTEX_LOCK(mutex_zglob);
1322  for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList); 
1323       testPattern;
1324       testPattern = (sh_globstack_t *) zAVLNext  (&cursor))
1325    {
1326      sh_files_pushglob(testPattern->class, testPattern->type, 
1327                        testPattern->name, testPattern->rdepth,
1328                        testPattern->check_flags, 1);
1329    }
1330  SH_MUTEX_UNLOCK(mutex_zglob);
1331  SL_RET0(_("sh_files_check_globPatterns"));
1332}
1333
1334/* the destructor
1335 */
1336void free_globstack (void * inptr)
1337{
1338  sh_globstack_t * here;
1339
1340  SL_ENTER(_("free_globstack"));
1341  if (inptr == NULL)
1342    SL_RET0(_("free_globstack"));
1343  else
1344    here = (sh_globstack_t *) inptr;
1345
1346  if (here->name != NULL)
1347    SH_FREE(here->name);
1348  SH_FREE(here);
1349  SL_RET0(_("free_globstack"));
1350}
1351
1352int sh_files_delglobstack ()
1353{
1354  SL_ENTER(_("sh_files_delglobstack"));
1355
1356  SH_MUTEX_LOCK(mutex_zglob);
1357  zAVLFreeTree (zglobList, free_globstack);
1358  zglobList = NULL;
1359  SH_MUTEX_UNLOCK(mutex_zglob);
1360
1361  SL_RETURN(0, _("sh_files_delglobstack"));
1362}
1363 
1364
1365#else
1366void sh_files_check_globPatterns()
1367{
1368  return;
1369}
1370int sh_files_delglobstack ()
1371{
1372  return 0;
1373}
1374#endif
1375
1376static int sh_files_pushfile (int class, const char * str_s)
1377{
1378  size_t  len;
1379  char  * tmp;
1380  char  * p;
1381
1382  static int reject = 0;
1383
1384  SL_ENTER(_("sh_files_pushfile"));
1385
1386  if (reject == 1)
1387    SL_RETURN((-1),_("sh_files_pushfile"));
1388
1389  /* if we push a filename from the command line, make sure it
1390   * is the only one -- and will stay the only one
1391   */
1392  if (sh.flag.opts == S_TRUE) 
1393    {
1394      sh_files_delfilestack ();
1395      sh_files_deldirstack ();
1396      sh_files_delglobstack ();
1397      reject = 1;
1398    }
1399
1400  p = sh_files_parse_input(str_s, &len);
1401  if (!p || len == 0)
1402    SL_RETURN((-1), _("sh_files_pushfile"));
1403
1404  if (len >= PATH_MAX) 
1405    {
1406      /* Name too long
1407       */
1408      tmp = sh_util_safe_name (p);
1409      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_2LONG,
1410                       tmp);
1411      SH_FREE(tmp);
1412      SL_RETURN((-1),_("sh_files_pushfile"));
1413    } 
1414  else if (p[0] != '/') 
1415    {
1416      /* Not an absolute path
1417       */
1418      tmp = sh_util_safe_name (p);
1419      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NOPATH,
1420                       tmp);
1421      SH_FREE(tmp);
1422      SL_RETURN((-1),_("sh_files_pushfile"));
1423    } 
1424  else 
1425    {
1426      /* remove a terminating '/', take care of the
1427       * special case of the root directory.
1428       */
1429      if (p[len-1] == '/' && len > 1)
1430        {
1431          p[len-1] = '\0';
1432          --len;
1433        }
1434    } 
1435
1436#ifdef HAVE_GLOB_H
1437  if (0 == sh_files_has_metachar(p))
1438    {
1439      sh_files_push_file_int (class, p, len, sh_files_maskof(class));
1440    }
1441  else
1442    {
1443      sh_files_pushglob (class, SH_LIST_FILE, p, 0, 0, 0);
1444    }
1445
1446#else
1447  sh_files_push_file_int (class, p, len, sh_files_maskof(class));
1448#endif
1449
1450  SH_FREE(p);
1451  SL_RETURN((0),_("sh_files_pushfile"));
1452}
1453
1454
1455/* ------ directories ----- */
1456
1457int sh_files_is_allignore_int (char * str, zAVLTree * tree)
1458{
1459  dirstack_t * ptr;
1460
1461  SL_ENTER(_("sh_files_is_allignore"));
1462
1463  if (tree)
1464    {
1465      ptr = zAVLSearch(tree, str);
1466      if (ptr)
1467        {
1468          if (ptr->class == SH_LEVEL_ALLIGNORE)
1469            SL_RETURN( 1, _("sh_files_is_allignore"));
1470          else
1471            SL_RETURN( 0, _("sh_files_is_allignore"));
1472        }
1473    }
1474  SL_RETURN( 0, _("sh_files_is_allignore"));
1475}
1476
1477int sh_files_is_allignore (char * str)
1478{
1479  int retval = 0;
1480
1481  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
1482  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
1483  retval = sh_files_is_allignore_int(str, zdirListOne);
1484
1485  if (NULL != zdirListTwo && retval == 0)
1486    {
1487      retval = sh_files_is_allignore_int(str, zdirListTwo);
1488    }
1489  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
1490  return retval;
1491}
1492
1493void * sh_dummy_1493_ptr;
1494
1495unsigned long sh_dirs_chk (int which)
1496{
1497  zAVLTree   * tree;
1498  zAVLCursor   cursor;
1499  dirstack_t * ptr;
1500  dirstack_t * dst_ptr;
1501  int          status;
1502  int          tmp_reported;
1503  volatile int          filetype = SH_FILE_UNKNOWN;
1504  volatile unsigned long dcount = 0;
1505  char       * tmp;
1506 
1507  SL_ENTER(_("sh_dirs_chk"));
1508
1509  sh_dummy_1493_ptr = (void *) &ptr;
1510 
1511  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
1512  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
1513  if (which == 1)
1514    tree = zdirListOne;
1515  else
1516    tree = zdirListTwo;
1517
1518  for (ptr = (dirstack_t *) zAVLFirst(&cursor, tree); ptr;
1519       ptr = (dirstack_t *) zAVLNext(&cursor))
1520    {
1521      if (sig_urgent > 0) {
1522        goto out;
1523      }
1524
1525      if (ptr->checked == S_FALSE)
1526        {
1527          SH_MUTEX_LOCK(mutex_zfiles);
1528          /* 28 Aug 2001 check the top level directory
1529           */
1530          status        = S_FALSE;
1531          dst_ptr       = zAVLSearch(zfileList, ptr->name);
1532          if (dst_ptr) 
1533            {
1534              if (dst_ptr->checked == S_FALSE)
1535                {
1536                  BREAKEXIT(sh_files_filecheck);
1537                  tmp_reported = dst_ptr->is_reported;
1538                  filetype = sh_files_filecheck (dst_ptr->class, dst_ptr->check_flags, 
1539                                                 ptr->name, 
1540                                                 NULL,  &tmp_reported, 0);
1541                  dst_ptr->is_reported = tmp_reported;
1542                  (void) handle_filecheck_ret(dst_ptr, NULL, filetype);
1543
1544                  dst_ptr->checked = S_TRUE;
1545                  status           = S_TRUE;
1546                }
1547              else
1548                {
1549                  status           = S_TRUE;
1550                }
1551            }
1552          SH_MUTEX_UNLOCK(mutex_zfiles);
1553
1554          if (status == S_FALSE)
1555            {
1556              tmp_reported = ptr->is_reported;
1557              filetype = sh_files_filecheck (ptr->class,  ptr->check_flags, 
1558                                             ptr->name,  NULL,  &tmp_reported, 0);
1559              ptr->is_reported = tmp_reported;
1560              (void) handle_filecheck_ret(ptr, NULL, filetype);
1561            }
1562
1563          BREAKEXIT(sh_files_checkdir);
1564          status = sh_files_checkdir (ptr->class, ptr->check_flags, 
1565                                      ptr->rdepth, ptr->name, 
1566                                      ptr->name);
1567
1568          if (status < 0 && (!SH_FFLAG_REPORTED_SET(ptr->is_reported))) 
1569            {
1570              /* directory is missing
1571               */
1572              if (S_FALSE == sh_ignore_chk_del(ptr->name))
1573                {
1574                  if (0 != hashreport_missing(ptr->name, 
1575                                              (ptr->class == SH_LEVEL_ALLIGNORE) ? 
1576                                              ShDFLevel[ptr->class] : 
1577                                              ShDFLevel[SH_ERR_T_DIR])) {
1578                    tmp = sh_util_safe_name (ptr->name);
1579                    sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ? 
1580                                     ShDFLevel[ptr->class] : 
1581                                     ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__,
1582                                     0, MSG_FI_MISS, tmp);
1583                    ++sh.statistics.files_report;
1584                    SH_FREE(tmp);
1585                  }
1586                }
1587              if (sh.flag.reportonce == S_TRUE)
1588                SET_SH_FFLAG_REPORTED(ptr->is_reported);
1589            } 
1590          else 
1591            {
1592              /* exists (status >= 0), but was missing (reported == TRUE)
1593               */
1594              if (status >= 0 && SH_FFLAG_REPORTED_SET(ptr->is_reported))
1595                {
1596                  CLEAR_SH_FFLAG_REPORTED(ptr->is_reported);
1597                  sh_hash_clear_flag(ptr->name, SH_FFLAG_ENOENT);
1598#if 0
1599                  /* obsoleted (really?) by the mandatory sh_files_filecheck()
1600                   * above, which will catch missing directories anyway
1601                   */
1602                  tmp = sh_util_safe_name (ptr->name);
1603                  sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ?
1604                                   ShDFLevel[ptr->class] :
1605                                   ShDFLevel[SH_ERR_T_DIR],
1606                                   FIL__, __LINE__, 0, MSG_FI_ADD,
1607                                   tmp);
1608                  ++sh.statistics.files_report;
1609                  SH_FREE(tmp);
1610#endif
1611                }
1612              else if (status == SH_FILE_UNKNOWN)
1613                {
1614                  /* catchall
1615                   */
1616                  tmp = sh_util_safe_name (ptr->name);
1617                  sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0,
1618                                   MSG_FI_FAIL,
1619                                   tmp);
1620                  SH_FREE(tmp);
1621                  if (sh.flag.checkSum != SH_CHECK_INIT)
1622                    sh_hash_set_visited_true(ptr->name);
1623                }
1624
1625              ++dcount;
1626            }
1627          ptr->checked        = S_TRUE;
1628          ptr->childs_checked = S_TRUE;
1629        }
1630
1631      if (sig_urgent > 0) {
1632        goto out;
1633      }
1634
1635    }
1636 out:
1637  ; /* 'label at end of compound statement' */
1638  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
1639
1640  SL_RETURN(dcount, _("sh_dirs_chk"));
1641}
1642
1643int sh_files_pushdir_prelink (const char * str_s)
1644{
1645  return (sh_files_pushdir (SH_LEVEL_PRELINK, str_s));
1646}
1647
1648int sh_files_pushdir_user0 (const char * str_s)
1649{
1650  return (sh_files_pushdir (SH_LEVEL_USER0, str_s));
1651}
1652
1653int sh_files_pushdir_user1 (const char * str_s)
1654{
1655  return (sh_files_pushdir (SH_LEVEL_USER1, str_s));
1656}
1657
1658int sh_files_pushdir_user2 (const char * str_s)
1659{
1660  return (sh_files_pushdir (SH_LEVEL_USER2, str_s));
1661}
1662
1663int sh_files_pushdir_user3 (const char * str_s)
1664{
1665  return (sh_files_pushdir (SH_LEVEL_USER3, str_s));
1666}
1667
1668int sh_files_pushdir_user4 (const char * str_s)
1669{
1670  return (sh_files_pushdir (SH_LEVEL_USER4, str_s));
1671}
1672
1673int sh_files_pushdir_attr (const char * str_s)
1674{
1675  return (sh_files_pushdir (SH_LEVEL_ATTRIBUTES, str_s));
1676}
1677
1678int sh_files_pushdir_ro (const char * str_s)
1679{
1680  return (sh_files_pushdir (SH_LEVEL_READONLY, str_s));
1681}
1682
1683int sh_files_pushdir_log (const char * str_s)
1684{
1685  return (sh_files_pushdir (SH_LEVEL_LOGFILES, str_s));
1686}
1687
1688int sh_files_pushdir_glog (const char * str_s)
1689{
1690  return (sh_files_pushdir (SH_LEVEL_LOGGROW, str_s));
1691}
1692
1693int sh_files_pushdir_noig (const char * str_s)
1694{
1695  return (sh_files_pushdir (SH_LEVEL_NOIGNORE, str_s));
1696}
1697
1698int sh_files_pushdir_allig (const char * str_s)
1699{
1700  return (sh_files_pushdir (SH_LEVEL_ALLIGNORE, str_s));
1701}
1702
1703int set_dirList (int which)
1704{
1705  if (which == 2)
1706    which_dirList = SH_LIST_DIR2;
1707  else
1708    which_dirList = SH_LIST_DIR1;
1709  return 0;
1710}
1711
1712int sh_files_push_dir_int (int class, char * tail, size_t len, int rdepth, unsigned long check_flags)
1713{
1714  zAVLTree   * tree;
1715  dirstack_t * new_item_ptr;
1716  char       * dirName;
1717  int          ret;
1718
1719  SL_ENTER(_("sh_files_push_dir_int"));
1720
1721  dirName = SH_ALLOC(len+1);
1722  sl_strlcpy(dirName, tail, len+1);
1723
1724  new_item_ptr = (dirstack_t * ) SH_ALLOC (sizeof(dirstack_t));
1725
1726  new_item_ptr->name           = dirName;
1727  new_item_ptr->class          = class;
1728  new_item_ptr->check_flags     = check_flags;
1729  new_item_ptr->rdepth         = rdepth;
1730  new_item_ptr->checked        = S_FALSE;
1731  new_item_ptr->is_reported    = 0;
1732  new_item_ptr->childs_checked = S_FALSE;
1733
1734  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
1735  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
1736  if (which_dirList == SH_LIST_DIR1)
1737    {
1738      tree = zdirListOne;
1739    }
1740  else
1741    {
1742      tree = zdirListTwo;
1743    }
1744
1745  if (tree == NULL)
1746    {
1747      tree = zAVLAllocTree (zdirstack_key, zAVL_KEY_STRING);
1748      if (tree == NULL) 
1749        {
1750          (void) safe_logger (0, 0, NULL);
1751          aud__exit(FIL__, __LINE__, EXIT_FAILURE);
1752        }
1753      if (which_dirList == SH_LIST_DIR1)
1754        zdirListOne = tree;
1755      else
1756        zdirListTwo = tree;
1757    }
1758
1759  ret = zAVLInsert (tree, new_item_ptr);
1760  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
1761
1762  if (-1 == ret)
1763    {
1764      (void) safe_logger (0, 0, NULL);
1765      aud__exit(FIL__, __LINE__, EXIT_FAILURE);
1766    }
1767  if (3 == ret)
1768    { 
1769      if (sh.flag.started != S_TRUE)
1770        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
1771                         dirName);
1772      SH_FREE(dirName);
1773      SH_FREE(new_item_ptr);
1774      new_item_ptr = NULL;
1775    }
1776  else
1777    {
1778      if (MODI_AUDIT_ENABLED(check_flags))
1779        {
1780          sh_audit_mark(tail);
1781        }
1782    }
1783  SL_RETURN(0, _("sh_files_push_dir_int"));
1784}
1785
1786static int sh_files_pushdir (int class, const char * str_s)
1787{
1788  char  * tmp;
1789  size_t  len;
1790  int     rdepth = 0;
1791  char  * tail = NULL;
1792  char  * p;
1793
1794  SL_ENTER(_("sh_files_pushdir"));
1795
1796  if (sh.flag.opts == S_TRUE) {
1797    sh_files_delfilestack ();
1798    sh_files_deldirstack ();
1799    sh_files_delglobstack ();
1800  }
1801
1802  p = sh_files_parse_input(str_s, &len);
1803  if (!p || len == 0)
1804    SL_RETURN((-1),_("sh_files_pushdir"));
1805
1806  if (p[0] != '/')
1807    {
1808      rdepth = strtol(p, &tail, 10);
1809      if (tail == p)
1810        {
1811          SH_FREE(p);
1812          SL_RETURN((-1), _("sh_files_pushdir"));
1813        }
1814    }
1815  else
1816    tail   = p;
1817 
1818
1819  if (tail == p)
1820    {
1821      /* Setting to an invalid number will force MaxRecursionLevel,
1822       * see sh_files_setrec_int()
1823       */
1824      rdepth = (-2);
1825    }
1826  else if ( (rdepth < (-1) || rdepth > 99) || 
1827            ((rdepth == (-1)) && (class != SH_LEVEL_ALLIGNORE)) )
1828    {
1829      SH_FREE(p);
1830      SL_RETURN((-1), _("sh_files_pushdir"));
1831    }
1832
1833  len = sl_strlen(tail);
1834
1835  if (len >= PATH_MAX) 
1836    {
1837      tmp = sh_util_safe_name (tail);
1838      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_2LONG,
1839                       tmp);
1840      SH_FREE(tmp);
1841      SH_FREE(p);
1842      SL_RETURN((-1), _("sh_files_pushdir"));
1843    } 
1844  else if (len < 1) 
1845    {
1846      SH_FREE(p);
1847      SL_RETURN((-1), _("sh_files_pushdir"));
1848    } 
1849  else if (tail[0] != '/') 
1850    {
1851      tmp = sh_util_safe_name (tail);
1852      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NOPATH,
1853                       tmp);
1854      SH_FREE(tmp);
1855      SH_FREE(p);
1856      SL_RETURN((-1), _("sh_files_pushdir"));
1857    } 
1858  else 
1859    {
1860      if (tail[len-1] == '/' && len > 1)
1861        {
1862          tail[len-1] = '\0';
1863          --len;
1864        }
1865    } 
1866
1867#ifdef HAVE_GLOB_H
1868  if (0 == sh_files_has_metachar(tail))
1869    {
1870      sh_files_push_dir_int (class, tail, len, rdepth, sh_files_maskof(class));
1871    }
1872  else
1873    {
1874      sh_files_pushglob (class, which_dirList, tail, rdepth, 0, 0);
1875    }
1876#else 
1877  sh_files_push_dir_int (class, tail, len, rdepth, sh_files_maskof(class));
1878#endif
1879
1880  SH_FREE(p);
1881  SL_RETURN((0), _("sh_files_pushdir"));
1882}
1883
1884/**
1885struct sh_dirent {
1886  char             * sh_d_name;
1887  struct sh_dirent * next;
1888};
1889**/
1890
1891void kill_sh_dirlist (struct sh_dirent * dirlist)
1892{
1893  struct sh_dirent * this;
1894
1895  while (dirlist)
1896    {
1897      this    = dirlist->next;
1898      SH_FREE(dirlist->sh_d_name);
1899      SH_FREE(dirlist);
1900      dirlist = this;
1901    }
1902  return;
1903}
1904 
1905/* -- add an entry to a directory listing
1906 */
1907struct sh_dirent * addto_sh_dirlist (struct dirent * thisEntry, 
1908                                     struct sh_dirent * dirlist)
1909{
1910  struct sh_dirent * this;
1911  size_t len;
1912
1913  if (thisEntry == NULL)
1914    return dirlist;
1915 
1916  len = sl_strlen(thisEntry->d_name);
1917  if (len == 0)
1918    return dirlist;
1919  ++len;
1920 
1921  this = SH_ALLOC(sizeof(struct sh_dirent));
1922  if (!this)
1923    return dirlist;
1924
1925  this->sh_d_name = SH_ALLOC(len);
1926  sl_strlcpy(this->sh_d_name, thisEntry->d_name, len);
1927
1928  this->next = dirlist;
1929  return this;
1930}
1931
1932static int sh_check_hardlinks = S_TRUE;
1933
1934/* Simply sets our boolean as to whether this check is active
1935 */
1936int sh_files_check_hardlinks (const char * opt)
1937{
1938  int i;
1939  SL_ENTER(_("sh_files_check_hardlinks"));
1940  i = sh_util_flagval(opt, &sh_check_hardlinks);
1941  SL_RETURN(i, _("sh_files_check_hardlinks"));
1942}
1943
1944struct sh_hle_struct {
1945  long   offset;
1946  char * path;
1947  struct sh_hle_struct * next;
1948};
1949
1950static struct sh_hle_struct * sh_hl_exc = NULL;
1951
1952int sh_files_hle_reg (const char * str)
1953{
1954  long   offset;
1955  size_t len;
1956  char * path;
1957 
1958  struct sh_hle_struct * tmp = sh_hl_exc;
1959
1960  SL_ENTER(_("sh_files_hle_reg"));
1961
1962  /* Free the linked list if called with NULL argument
1963   */
1964  if (str == NULL)
1965    {
1966      while (tmp)
1967        {
1968          sh_hl_exc = tmp->next;
1969          SH_FREE(tmp->path);
1970          SH_FREE(tmp);
1971          tmp = sh_hl_exc;
1972        }
1973      sh_hl_exc = NULL;
1974      SL_RETURN(0, _("sh_files_hle_reg"));
1975    }
1976
1977  /* We expect 'offset:/path'
1978   */
1979  offset = strtol(str, &path, 0);
1980  if ((path == NULL) || (*path == '\0') || (*path != ':') || (path[1] != '/'))
1981    {
1982      SL_RETURN(-1, _("sh_files_hle_reg"));
1983    }
1984  ++path;
1985  len = 1 + sl_strlen(path);
1986
1987  tmp         = SH_ALLOC(sizeof(struct sh_hle_struct));
1988  tmp->path   = SH_ALLOC(len);
1989  sl_strlcpy (tmp->path, path, len);
1990  tmp->offset = offset;
1991  tmp->next   = sh_hl_exc;
1992  sh_hl_exc   = tmp;
1993
1994  SL_RETURN(0, _("sh_files_hle_reg"));
1995}
1996
1997#if !defined(HOST_IS_DARWIN)
1998static int sh_files_hle_test (int offset, char * path)
1999{
2000  struct sh_hle_struct * tmp = sh_hl_exc;
2001
2002  SL_ENTER(_("sh_files_hle_reg"));
2003
2004  while(tmp)
2005    {
2006      if ((offset == tmp->offset) && (0 == strcmp(path, tmp->path)))
2007        {
2008          SL_RETURN(0, _("sh_files_hle_test"));
2009        }
2010      tmp = tmp->next;
2011    }
2012#ifdef HAVE_FNMATCH_H
2013  if ( (offset == 1) && (0 == fnmatch(_("/run/user/*"), path, FNM_PATHNAME)) )
2014    {
2015      /* gvfs directory in /run/user/username/ */
2016      SL_RETURN(0, _("sh_files_hle_test"));
2017    }
2018#endif
2019
2020  SL_RETURN(-1, _("sh_files_hle_test"));
2021}
2022#endif
2023
2024static void * sh_dummy_dirlist;
2025static void * sh_dummy_tmpcat;
2026
2027/* -- Check a single directory and its content. Does not
2028 *    check the directory inode itself.
2029 */
2030int sh_files_checkdir (int iclass, unsigned long check_flags, 
2031                       int idepth, char * iname, 
2032                       char * relativeName)
2033{
2034  struct sh_dirent * dirlist;
2035  struct sh_dirent * dirlist_orig;
2036
2037  DIR *           thisDir = NULL;
2038  struct dirent * thisEntry;
2039  int             status;
2040  int             dummy = S_FALSE;
2041  dir_type      * theDir;
2042  ShFileType      checkit;
2043  static unsigned int state = 1;
2044
2045  file_type     * theFile;
2046  char          * tmpname;
2047  char          * tmpcat;
2048  char errbuf[SH_ERRBUF_SIZE];
2049
2050  int             rdepth = 0;
2051  int             class  = 0;
2052  volatile int    rdepth_next;
2053  volatile int    class_next;
2054  volatile int    file_class_next;
2055  volatile unsigned long   check_flags_next;
2056  volatile unsigned long   file_check_flags_next;
2057
2058  volatile int    checked_flag  = S_FALSE;
2059  volatile int    cchecked_flag = S_FALSE;
2060
2061  dirstack_t *    dst_ptr;
2062  dirstack_t *    tmp_ptr;
2063
2064  int             hardlink_num = 0;
2065#if !defined(HOST_IS_DARWIN)
2066  size_t          len;
2067#endif
2068
2069  SL_ENTER(_("sh_files_checkdir"));
2070
2071  if (sig_urgent > 0) {
2072    SL_RETURN((0), _("sh_files_checkdir"));
2073  }
2074
2075  if (iname == NULL || idepth < (-1))
2076    SL_RETURN((-1), _("sh_files_checkdir"));
2077 
2078  if (idepth < 0)
2079    {
2080      /* hash_remove_tree (iname); */
2081      SL_RETURN((0), _("sh_files_checkdir"));
2082    }
2083 
2084  rdepth = idepth;
2085  class  = iclass;
2086 
2087  tmpname = sh_util_safe_name (iname);
2088
2089  /* ---- check for obscure name ----
2090   */
2091  if (iclass != SH_LEVEL_ALLIGNORE)
2092    {
2093      sh_util_obscurename (ShDFLevel[SH_ERR_T_NAME], iname, S_TRUE);
2094    }
2095
2096  if (flag_err_info == S_TRUE)
2097    {
2098      char pstr[32];
2099
2100      sl_strlcpy(pstr, sh_hash_getpolicy(iclass), sizeof(pstr));
2101      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_CHK, pstr, tmpname);
2102    }
2103
2104  /* ---- check input ----
2105   */
2106  if ( sl_strlen(iname) >= PATH_MAX) 
2107    {
2108      sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0, 
2109                       MSG_FI_2LONG,
2110                       tmpname);
2111      SH_FREE(tmpname);
2112      SL_RETURN((-1), _("sh_files_checkdir"));
2113    }
2114 
2115  /* ---- check for absolute path ---- */
2116  if ( iname[0] != '/') 
2117    {
2118      sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0, 
2119                       MSG_FI_NOPATH,
2120                       tmpname);
2121      SH_FREE(tmpname);
2122      SL_RETURN((-1), _("sh_files_checkdir"));
2123    }
2124
2125  /* ---- stat the directory ----
2126   */
2127  theFile = SH_ALLOC(sizeof(file_type));
2128  sl_strlcpy (theFile->fullpath, iname, PATH_MAX);
2129  theFile->attr_string = NULL;
2130  theFile->link_path   = NULL;
2131  theFile->check_flags  = check_flags;
2132
2133  (void) relativeName;
2134  status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_DIR], 
2135                            iname,
2136                            theFile, NULL, iclass);
2137
2138  if ((sig_termfast == 1) || (sig_terminate == 1)) 
2139    {
2140      if (theFile->attr_string) SH_FREE(theFile->attr_string);
2141      if (theFile->link_path)   SH_FREE(theFile->link_path);
2142      SH_FREE(theFile);
2143      SH_FREE(tmpname);
2144      SL_RETURN((0), _("sh_files_checkdir"));
2145    }
2146
2147  if (status == -1)
2148    {
2149      if (theFile->attr_string) SH_FREE(theFile->attr_string);
2150      if (theFile->link_path)   SH_FREE(theFile->link_path);
2151      SH_FREE(theFile);
2152      SH_FREE(tmpname);
2153      SL_RETURN((-1), _("sh_files_checkdir"));
2154    }
2155
2156  if (theFile->c_mode[0] != 'd') 
2157    { 
2158      sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
2159                       MSG_FI_NODIR,
2160                       tmpname);
2161      ++sh.statistics.files_nodir;
2162      if (theFile->attr_string) SH_FREE(theFile->attr_string);
2163      if (theFile->link_path)   SH_FREE(theFile->link_path);
2164      SH_FREE(theFile);
2165      SH_FREE(tmpname);
2166      SL_RETURN((-1), _("sh_files_checkdir"));
2167    }
2168
2169  if ((sh.flag.inotify & SH_INOTIFY_INSCAN) != 0)
2170    {
2171      sh_inotify_add_watch_later(iname, &sh_file_watches, &status,
2172                                 iclass, check_flags, SH_INOTIFY_DIR, idepth);
2173    }
2174   
2175  hardlink_num = theFile->hardlinks;
2176
2177  if (theFile->attr_string) SH_FREE(theFile->attr_string);
2178  if (theFile->link_path)   SH_FREE(theFile->link_path);
2179  SH_FREE(theFile);
2180
2181  /* ---- open directory for reading ----
2182   *
2183   * opendir() will fail with ENOTDIR if the path has been changed
2184   * to a non-directory in between lstat() and opendir().
2185   */
2186  thisDir = opendir (iname);
2187
2188  if (thisDir == NULL) 
2189    {
2190      status = errno;
2191      sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0, 
2192                       MSG_E_OPENDIR,
2193                       sh_error_message (status, errbuf, sizeof(errbuf)), tmpname);
2194      SH_FREE(tmpname); 
2195      SL_RETURN((-1), _("sh_files_checkdir"));
2196    }
2197
2198  theDir = SH_ALLOC(sizeof(dir_type));
2199
2200  theDir->NumRegular  = 0;
2201  theDir->NumDirs     = 0;
2202  theDir->NumSymlinks = 0;
2203  theDir->NumFifos    = 0;
2204  theDir->NumSockets  = 0;
2205  theDir->NumCDev     = 0;
2206  theDir->NumBDev     = 0;
2207  theDir->NumDoor     = 0;
2208  theDir->NumPort     = 0;
2209  theDir->NumAll      = 0;
2210  theDir->TotalBytes  = 0;
2211  sl_strlcpy (theDir->DirPath, iname, PATH_MAX); 
2212
2213
2214  sh_dummy_dirlist = (void *) &dirlist;
2215  sh_dummy_tmpcat  = (void *) &tmpcat;
2216
2217  /* ---- read ----
2218   */
2219  SH_MUTEX_LOCK(mutex_readdir);
2220
2221  dirlist = NULL;
2222  dirlist_orig = NULL;
2223
2224  do {
2225      thisEntry = readdir (thisDir);
2226      if (thisEntry != NULL) 
2227        {
2228          ++theDir->NumAll;
2229          if (sl_strcmp (thisEntry->d_name, ".") == 0)
2230            { 
2231              ++theDir->NumDirs;
2232              continue;
2233            }
2234          if (sl_strcmp (thisEntry->d_name, "..") == 0)
2235            {
2236              ++theDir->NumDirs;
2237              continue;
2238            }
2239          dirlist = addto_sh_dirlist (thisEntry, dirlist);
2240        }
2241  } while (thisEntry != NULL);
2242
2243  SH_MUTEX_UNLOCK(mutex_readdir);
2244
2245  closedir (thisDir);
2246
2247  ++sh.statistics.dirs_checked;
2248
2249  dirlist_orig = dirlist;
2250
2251  do {
2252
2253    /* If the directory is empty, dirlist = NULL
2254     */
2255    if (!dirlist)
2256      break;
2257
2258    if (sig_termfast == 1) 
2259      {
2260        SH_FREE(theDir);
2261        SH_FREE(tmpname);
2262        SL_RETURN((0), _("sh_files_checkdir"));
2263      }
2264
2265    BREAKEXIT(sh_derr);
2266
2267#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_RAND_R)
2268    if (0 == (rand_r(&state) % 5)) (void) sh_derr();
2269#else
2270    if (0 == state * (rand() % 5)) (void) sh_derr();
2271#endif
2272   
2273    /* ---- Check the file. ----
2274     */
2275    tmpcat = SH_ALLOC(PATH_MAX);
2276    sl_strlcpy(tmpcat, iname,                   PATH_MAX);
2277    if (sl_strlen(tmpcat) > 1 || tmpcat[0] != '/')
2278      sl_strlcat(tmpcat, "/",                   PATH_MAX);
2279    sl_strlcat(tmpcat, dirlist->sh_d_name,      PATH_MAX);
2280   
2281    rdepth_next     = rdepth - 1;
2282    class_next      = class;
2283    check_flags_next = check_flags;
2284    file_class_next = class;
2285    file_check_flags_next = check_flags;
2286    checked_flag    = -1;
2287    cchecked_flag   = -1;
2288
2289    /* Wed Aug 24 2005 compare against dirListOne, dirListTwo
2290     * this fixes the problem that the directory special file
2291     * is checked with the policy of the parent directory
2292     */
2293    SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
2294    SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
2295    dst_ptr         = (dirstack_t *) zAVLSearch(zdirListOne, tmpcat);
2296
2297    if (dst_ptr) 
2298      {
2299        /* Tue Aug  6 22:13:27 CEST 2002 introduce file_class_next
2300         * this fixes the problem that a policy for the directory
2301         * inode erroneously becomes a policy for the directory itself.
2302         */
2303        file_class_next    = dst_ptr->class;
2304        file_check_flags_next = dst_ptr->check_flags;
2305        checked_flag       = dst_ptr->checked;
2306        cchecked_flag      = dst_ptr->childs_checked;
2307      }
2308
2309    if (checked_flag == -1)
2310      {
2311        dst_ptr         = (dirstack_t *) zAVLSearch(zdirListTwo, tmpcat);
2312
2313        if (dst_ptr) 
2314          {
2315            /* Tue Aug  6 22:13:27 CEST 2002 introduce file_class_next
2316             * this fixes the problem that a policy for the directory
2317             * inode erroneously becomes a policy for the directory itself.
2318             */
2319            file_class_next    = dst_ptr->class;
2320            file_check_flags_next = dst_ptr->check_flags;
2321            checked_flag       = dst_ptr->checked;
2322            cchecked_flag      = dst_ptr->childs_checked;
2323          }
2324      }
2325    SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
2326
2327    SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
2328    dst_ptr         = (dirstack_t *) zAVLSearch(zfileList, tmpcat);
2329
2330    if (dst_ptr) 
2331      {
2332        /* Tue Aug  6 22:13:27 CEST 2002 introduce file_class_next
2333         * this fixes the problem that a policy for the directory
2334         * inode erroneously becomes a policy for the directory itself.
2335         */
2336        file_class_next    = dst_ptr->class;
2337        file_check_flags_next = dst_ptr->check_flags;
2338        checked_flag       = dst_ptr->checked;
2339        /* not set, hence always FALSE                   */
2340        /* cchecked_flag      = dst_ptr->childs_checked; */
2341
2342        if (checked_flag != S_TRUE)
2343          {
2344            /* -- need to check the file itself --
2345             */
2346            if (sh.flag.reportonce == S_TRUE)
2347              dummy = dst_ptr->is_reported;
2348          }
2349      }
2350    SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
2351   
2352    /* ---- Has been checked already. ----
2353     */
2354    if (checked_flag == S_TRUE && cchecked_flag == S_TRUE)
2355      {
2356        /* Mar 11 2004 get ftype for complete directory count
2357         */
2358        checkit = sh_unix_get_ftype(tmpcat);
2359        if (checkit == SH_FILE_DIRECTORY) 
2360          {
2361            ++theDir->NumDirs;
2362          }
2363        SH_FREE(tmpcat);
2364        dirlist = dirlist->next;
2365        continue;
2366      }
2367   
2368    /* --- May be true, false, or not found. ---
2369     */
2370    if (checked_flag == S_TRUE)
2371      {
2372        /* -- need only the file type --
2373         */
2374        checkit = sh_unix_get_ftype(tmpcat);
2375      }
2376    else
2377      {
2378        /* -- need to check the file itself --
2379         */
2380        /* -- moved up --
2381         * if (dst_ptr && sh.flag.reportonce == S_TRUE)
2382         *   dummy = dst_ptr->is_reported;
2383         */
2384
2385        checkit = sh_files_filecheck (file_class_next, file_check_flags_next, 
2386                                      iname, 
2387                                      dirlist->sh_d_name,
2388                                      &dummy, 0);
2389
2390       
2391        SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
2392        dst_ptr         = (dirstack_t *) zAVLSearch(zfileList, tmpcat);
2393
2394        if (dst_ptr && checked_flag == S_FALSE)
2395          dst_ptr->checked = S_TRUE;
2396
2397        /* Thu Mar  7 15:09:40 CET 2002 Propagate the 'reported' flag
2398         */
2399        if (dst_ptr && sh.flag.reportonce == S_TRUE)
2400          dst_ptr->is_reported = dummy;
2401
2402        if (dst_ptr)
2403          dst_ptr->childs_checked = S_TRUE;
2404        SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
2405      }
2406   
2407    if      (checkit == SH_FILE_REGULAR)   
2408      ++theDir->NumRegular;
2409   
2410    else if (checkit == SH_FILE_DIRECTORY) 
2411      {
2412        ++theDir->NumDirs;
2413
2414        if (rdepth_next >= 0 && cchecked_flag != S_TRUE) 
2415          {
2416            rdepth_next = rdepth - 1;
2417           
2418            /* check whether the new directory is in the
2419             * list with a recursion depth already defined
2420             */
2421            checked_flag  = -1;
2422            cchecked_flag = -1;
2423           
2424            SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
2425            SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
2426            tmp_ptr     = (dirstack_t *) zAVLSearch(zdirListOne, tmpcat);
2427
2428            if (tmp_ptr) 
2429              {
2430                TPT((0, FIL__, __LINE__, 
2431                     _("msg=<%s -> recursion depth %d\n>"),
2432                     tmp_ptr->name, tmp_ptr->rdepth));
2433                rdepth_next   = tmp_ptr->rdepth;
2434                class_next    = tmp_ptr->class;
2435                check_flags_next = tmp_ptr->check_flags;
2436                /* 28. Aug 2001 reversed
2437                 */
2438                cchecked_flag = tmp_ptr->childs_checked;
2439                checked_flag  = tmp_ptr->checked;
2440              }
2441           
2442            if (checked_flag == -1)
2443              {
2444                tmp_ptr     = (dirstack_t *) zAVLSearch(zdirListTwo, tmpcat);
2445
2446                if (tmp_ptr) 
2447                  {
2448                    TPT((0, FIL__, __LINE__, 
2449                         _("msg=<%s -> recursion depth %d\n>"),
2450                         tmp_ptr->name, tmp_ptr->rdepth));
2451                    rdepth_next   = tmp_ptr->rdepth;
2452                    class_next    = tmp_ptr->class;
2453                    check_flags_next = tmp_ptr->check_flags;
2454                    /* 28. Aug 2001 reversed
2455                     */
2456                    cchecked_flag = tmp_ptr->childs_checked;
2457                    checked_flag  = tmp_ptr->checked;
2458                  }
2459              }
2460
2461            if (tmp_ptr && cchecked_flag == S_FALSE)
2462              {
2463                tmp_ptr->childs_checked = S_TRUE;
2464                /*
2465                 * 04. Feb 2006 avoid double checking
2466                 */
2467                tmp_ptr->checked        = S_TRUE;
2468              }
2469            SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
2470
2471            if (cchecked_flag == S_FALSE)
2472              {
2473                sh_files_checkdir (class_next, check_flags_next, rdepth_next, 
2474                                   tmpcat, dirlist->sh_d_name);
2475                /*
2476                  tmp_ptr->childs_checked = S_TRUE;
2477                  tmp_ptr->checked        = S_TRUE;
2478                */
2479              }
2480            else if (checked_flag == -1)
2481              sh_files_checkdir (class_next, check_flags_next, rdepth_next, 
2482                                 tmpcat, dirlist->sh_d_name);
2483           
2484          }
2485      }
2486   
2487    else if (checkit == SH_FILE_SYMLINK)   ++theDir->NumSymlinks;
2488    else if (checkit == SH_FILE_FIFO)      ++theDir->NumFifos;
2489    else if (checkit == SH_FILE_SOCKET)    ++theDir->NumSockets;
2490    else if (checkit == SH_FILE_CDEV)      ++theDir->NumCDev;
2491    else if (checkit == SH_FILE_BDEV)      ++theDir->NumBDev;
2492    else if (checkit == SH_FILE_DOOR)      ++theDir->NumDoor;
2493    else if (checkit == SH_FILE_PORT)      ++theDir->NumPort;
2494   
2495    SH_FREE(tmpcat);
2496   
2497    if ((sig_termfast == 1) || (sig_terminate == 1)) 
2498      {
2499        SH_FREE(theDir);
2500        sh_dummy_dirlist = NULL;
2501        SH_FREE(tmpname);
2502        SL_RETURN((0), _("sh_files_checkdir"));
2503      }
2504   
2505    dirlist = dirlist->next;
2506
2507    /* -- moved up, only affects zfileList anyway
2508     * if (dst_ptr)
2509     *   dst_ptr->childs_checked = S_TRUE;
2510     */
2511
2512  } while (dirlist != NULL);
2513
2514  if (flag_err_info == S_TRUE)
2515    {
2516      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DSUM,
2517                       theDir->NumDirs,
2518                       theDir->NumRegular,
2519                       theDir->NumSymlinks,
2520                       theDir->NumFifos,
2521                       theDir->NumSockets,
2522                       theDir->NumCDev,
2523                       theDir->NumBDev);
2524    }
2525
2526  kill_sh_dirlist (dirlist_orig);
2527
2528#if !defined(HOST_IS_DARWIN)
2529  /*
2530   * Hardlink check; not done on MacOS X because of resource forks
2531   */
2532  if ((sh_check_hardlinks == S_TRUE) && (hardlink_num != theDir->NumDirs)) 
2533    {
2534      if (0 != sh_files_hle_test(hardlink_num-theDir->NumDirs, iname))
2535        {
2536          len = strlen(tmpname);
2537          if (sl_ok_adds(len, 256)) 
2538            len += 256;
2539          tmpcat = SH_ALLOC(len);
2540          sl_snprintf(tmpcat, len, 
2541                      _("%s: subdirectory count (%d) != hardlinks (%d)"),
2542                      tmpname, theDir->NumDirs, hardlink_num);
2543          sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0, 
2544                           MSG_E_SUBGEN, tmpcat, _("sh_files_checkdir"));
2545          SH_FREE(tmpcat);
2546        }
2547    }
2548#endif
2549
2550  SH_FREE(tmpname);
2551  SH_FREE(theDir);
2552
2553  sh_dummy_dirlist = NULL;
2554
2555  SL_RETURN((0), _("sh_files_checkdir"));
2556}
2557
2558void sh_files_fixup_mask (int class, unsigned long * check_flags)
2559{
2560  if (class == SH_LEVEL_ALLIGNORE)
2561    MODI_SET((*check_flags), MODI_ALLIGNORE);
2562  sh_tiger_get_mask_hashtype(check_flags);
2563  return;
2564}
2565
2566int get_the_fd (SL_TICKET ticket);
2567
2568static int sh_use_rsrc = S_FALSE;
2569
2570int sh_files_use_rsrc(const char * str)
2571{
2572  return sh_util_flagval(str, &sh_use_rsrc);
2573}
2574
2575static void * sh_dummy_fileName;
2576static void * sh_dummy_tmpname;
2577static void * sh_dummy_tmpdir;
2578
2579ShFileType sh_files_filecheck (int class, unsigned long check_flags,
2580                               const char * dirName, 
2581                               const char * infileName,
2582                               int * reported, 
2583                               int rsrcflag)
2584{
2585  /* 28 Aug 2001 allow NULL fileName
2586   */
2587  char          * fullpath;
2588  char            fileHash[2*(KEY_LEN + 1)];
2589  int             status;
2590  file_type     * theFile;
2591  char          * tmpdir;
2592  char          * tmpname;
2593  const char    * fileName;
2594#if !defined(O_NOATIME)
2595  struct utimbuf  utime_buf;
2596#endif
2597  static unsigned int state = 1;
2598  char            sc;
2599
2600  SL_ENTER(_("sh_files_filecheck"));
2601
2602  fullpath = SH_ALLOC(PATH_MAX);
2603  theFile  = SH_ALLOC(sizeof(file_type));
2604
2605  /* Take the address to keep gcc from putting it into a register.
2606   * Avoids the 'clobbered by longjmp' warning.
2607   */
2608  sh_dummy_fileName = (void *) &fileName;
2609  sh_dummy_tmpname  = (void *) &tmpname;
2610  sh_dummy_tmpdir   = (void *) &tmpdir;
2611
2612  BREAKEXIT(sh_derr);
2613
2614#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_RAND_R)
2615  if (0 == (rand_r(&state) % 2)) (void) sh_derr();
2616#else
2617  if (0 == state * (rand() % 2)) (void) sh_derr();
2618#endif
2619
2620  if (dirName && infileName && (dirName[0] == '/') && (dirName[1] == '\0')
2621      && (infileName[0] == '/') && (infileName[1] == '\0'))
2622    {
2623      fileName = NULL;
2624    }
2625  else
2626    {
2627      fileName = infileName;
2628    }
2629
2630  /* fileName may be NULL if this is a directory
2631   */
2632  if (dirName == NULL /* || fileName == NULL */)
2633    {
2634      SH_MUTEX_LOCK(mutex_thread_nolog);
2635      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NULL);
2636      SH_MUTEX_UNLOCK(mutex_thread_nolog);
2637      SH_FREE(fullpath);
2638      SH_FREE(theFile);
2639      SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
2640    }
2641
2642  if ((fileName != NULL) && (class != SH_LEVEL_ALLIGNORE) && 
2643      (0 != sh_util_obscurename (ShDFLevel[SH_ERR_T_NAME], 
2644                                 fileName, S_FALSE))) 
2645    {
2646      if ((dirName != NULL) && (dirName[0] == '/') && (dirName[1] == '\0')) 
2647        {
2648          tmpname = sh_util_safe_name (fileName);
2649          SH_MUTEX_LOCK(mutex_thread_nolog);
2650          sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, 0,
2651                           MSG_FI_OBSC2,
2652                           "", tmpname);
2653          SH_MUTEX_UNLOCK(mutex_thread_nolog);
2654          SH_FREE(tmpname);
2655        }
2656      else
2657        {
2658          tmpdir  = sh_util_safe_name (dirName);
2659          tmpname = sh_util_safe_name (fileName);
2660          SH_MUTEX_LOCK(mutex_thread_nolog);
2661          sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, 0,
2662                           MSG_FI_OBSC2,
2663                           tmpdir, tmpname);
2664          SH_MUTEX_UNLOCK(mutex_thread_nolog);
2665          SH_FREE(tmpname);
2666          SH_FREE(tmpdir);
2667        }
2668    }   
2669
2670  /* sh_files_fullpath accepts NULL fileName
2671   */
2672  if (0 != sh_files_fullpath (dirName, fileName, fullpath)) 
2673    { 
2674      tmpdir  = sh_util_safe_name (dirName);
2675      tmpname = sh_util_safe_name (fileName);
2676      SH_MUTEX_LOCK(mutex_thread_nolog);
2677      sh_error_handle (ShDFLevel[SH_ERR_T_FILE],  FIL__, __LINE__, 0,
2678                       MSG_FI_2LONG2,
2679                       tmpdir, tmpname);
2680      SH_MUTEX_UNLOCK(mutex_thread_nolog);
2681      SH_FREE(tmpname);
2682      SH_FREE(tmpdir);
2683      SH_FREE(fullpath);
2684      SH_FREE(theFile);
2685      SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
2686    } 
2687
2688  /* stat the file and determine checksum (if a regular file)
2689   */
2690  sl_strlcpy (theFile->fullpath, fullpath, PATH_MAX);
2691  theFile->check_flags    = check_flags /* sh_files_maskof(class) */;
2692  theFile->file_reported = (*reported);
2693  theFile->attr_string   = NULL;
2694  theFile->link_path     = NULL;
2695
2696  TPT(( 0, FIL__, __LINE__, _("msg=<checking file: %s>\n"),  fullpath));
2697
2698  status = sh_unix_getinfo ( (class == SH_LEVEL_ALLIGNORE) ? 
2699                             ShDFLevel[class] : ShDFLevel[SH_ERR_T_FILE], 
2700                             fileName,
2701                             theFile, fileHash, class);
2702
2703  if (status != 0)
2704    {
2705      TPT(( 0, FIL__, __LINE__, _("msg=<file: %s> status=<%d>\n"), 
2706            fullpath, status));
2707      if (class == SH_LEVEL_ALLIGNORE && sh.flag.checkSum != SH_CHECK_INIT)
2708        sh_hash_set_visited_true (fullpath);
2709      if (theFile->attr_string) SH_FREE(theFile->attr_string);
2710      if (theFile->link_path)   SH_FREE(theFile->link_path);
2711      SH_FREE(fullpath);
2712      SH_FREE(theFile);
2713      SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
2714    }
2715 
2716  if (sig_termfast == 1) {
2717    goto ret_point;
2718  }
2719
2720  /* report
2721   */
2722  if ((flag_err_debug == S_TRUE) && (theFile->c_mode[0] == '-'))
2723    {
2724      tmpname = sh_util_safe_name (fullpath); /* fixed in 1.5.4 */
2725      SH_MUTEX_LOCK(mutex_thread_nolog);
2726      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_CSUM,
2727                       fileHash, tmpname);
2728      SH_MUTEX_UNLOCK(mutex_thread_nolog);
2729      SH_FREE(tmpname);
2730    } 
2731  ++sh.statistics.files_checked;
2732     
2733  if ( sh.flag.checkSum == SH_CHECK_INIT) 
2734    {
2735      if (class == SH_LEVEL_ALLIGNORE)
2736        MODI_SET(theFile->check_flags, MODI_ALLIGNORE);
2737      if (S_TRUE == sh_ignore_chk_mod(theFile->fullpath))
2738        MODI_SET(theFile->check_flags, MODI_NOCHECK);
2739      sh_tiger_get_mask_hashtype(&(theFile->check_flags));
2740      sh_dbIO_data_write (theFile, fileHash);
2741    }
2742  else if (sh.flag.checkSum == SH_CHECK_CHECK
2743           /* && theFile.c_mode[0] == '-' */
2744           /* && class != SH_LEVEL_ALLIGNORE */
2745           ) 
2746    {
2747      if (sh.flag.update == S_TRUE)
2748        {
2749          if (class == SH_LEVEL_ALLIGNORE)
2750            MODI_SET(theFile->check_flags, MODI_ALLIGNORE);
2751          if (S_TRUE == sh_ignore_chk_mod(theFile->fullpath))
2752            MODI_SET(theFile->check_flags, MODI_NOCHECK);
2753          sh_tiger_get_mask_hashtype(&(theFile->check_flags));
2754        }
2755      sh_hash_compdata (class, theFile, fileHash, NULL, -1);
2756    }
2757 
2758  (*reported) = theFile->file_reported;
2759
2760  /* reset the access time
2761   */
2762#if !defined(O_NOATIME)
2763  if (class == SH_LEVEL_NOIGNORE && (theFile->check_flags & MODI_ATM) != 0)
2764    {
2765      utime_buf.actime   = (time_t) theFile->atime;
2766      utime_buf.modtime  = (time_t) theFile->mtime;
2767
2768      retry_aud_utime (FIL__, __LINE__, fullpath, &utime_buf);
2769    }
2770#endif
2771 
2772#if defined(HOST_IS_DARWIN)
2773  /*
2774   * Check for resource fork
2775   */
2776  if ( (sh_use_rsrc == S_TRUE) && (theFile->c_mode[0] != 'd') && (rsrcflag == 0) )
2777    {
2778      int  dummy;
2779      static int rsrc_init = 0;
2780      static char rsrc[17];
2781      char * testpath = SH_ALLOC(PATH_MAX);
2782
2783      if (rsrc_init == 0) {
2784        sl_strlcpy(rsrc, _("..namedfork/rsrc"), 17);
2785        rsrc_init = 1;
2786      }
2787      sl_strlcpy (testpath, fullpath, PATH_MAX);
2788      sl_strlcat (testpath,      "/", PATH_MAX);
2789      sl_strlcat (testpath,     rsrc, PATH_MAX);
2790
2791      if (sl_strlen(testpath) == (17 + sl_strlen(fullpath)))
2792        {
2793          if (S_TRUE == sh_unix_file_exists (testpath))
2794            {
2795              sh_files_filecheck (class, check_flags, fullpath, rsrc, &dummy, 1);
2796            }
2797        }
2798      SH_FREE(testpath);
2799    }
2800#else
2801  (void) rsrcflag; /* avoid compiler warning */
2802#endif
2803
2804 ret_point:
2805
2806  sc = theFile->c_mode[0];
2807
2808  if (theFile->attr_string) SH_FREE(theFile->attr_string);
2809  if (theFile->link_path)   SH_FREE(theFile->link_path);
2810  SH_FREE(fullpath);
2811  SH_FREE(theFile);
2812
2813  switch (sc) 
2814    {
2815    case '-': SL_RETURN(SH_FILE_REGULAR, _("sh_files_filecheck"));   
2816    case 'l': SL_RETURN(SH_FILE_SYMLINK, _("sh_files_filecheck"));   
2817    case 'd': SL_RETURN(SH_FILE_DIRECTORY, _("sh_files_filecheck")); 
2818    case 'c': SL_RETURN(SH_FILE_CDEV, _("sh_files_filecheck"));     
2819    case 'b': SL_RETURN(SH_FILE_BDEV, _("sh_files_filecheck"));     
2820    case '|': SL_RETURN(SH_FILE_FIFO, _("sh_files_filecheck"));     
2821    case 'D': SL_RETURN(SH_FILE_DOOR, _("sh_files_filecheck"));   
2822    case 'P': SL_RETURN(SH_FILE_PORT, _("sh_files_filecheck"));   
2823    case 's': SL_RETURN(SH_FILE_SOCKET, _("sh_files_filecheck"));   
2824    default:  SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));   
2825    }
2826 
2827  /* notreached */
2828}
2829
2830/* concatenate statpath = testdir"/"d_name
2831 */
2832static int sh_files_fullpath (const char * testdir, const char * d_name, 
2833                              char * statpath)
2834{
2835  int llen = 0;
2836
2837  SL_ENTER(_("sh_files_fullpath"));
2838
2839  if (testdir != NULL) 
2840    {
2841      if ( (llen = sl_strlen(testdir)) > (PATH_MAX-2) ) 
2842        SL_RETURN((-1),_("sh_files_fullpath"));
2843      sl_strlcpy(statpath, testdir,    PATH_MAX - 1);
2844    }
2845  if (d_name != NULL) 
2846    {
2847      if (llen > 1 || statpath[0] != '/')
2848        sl_strlcat(statpath, "/",   PATH_MAX);
2849      if ((sl_strlen(d_name) + sl_strlen(statpath)) >= PATH_MAX)
2850        SL_RETURN((-1),_("sh_files_fullpath"));
2851      sl_strlcat(statpath, d_name,   PATH_MAX);
2852    }
2853  if (statpath == NULL) 
2854    SL_RETURN((-1),_("sh_files_fullpath"));
2855  SL_RETURN((0),_("sh_files_fullpath"));
2856}
2857
2858/* -----------------------------------
2859 * Routines required for inotify
2860 * -----------------------------------
2861 */
2862int sh_files_search_dir(char * name, int * class, 
2863                        unsigned long *check_flags, int *reported,
2864                        int * rdepth)
2865{
2866  volatile int retval = 0;
2867#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
2868  sh_globstack_t * testPattern;
2869  zAVLCursor   cursor;
2870#endif
2871  dirstack_t * item;
2872
2873  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
2874  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
2875
2876  item = zAVLSearch(zdirListOne, name);
2877
2878  if (item)
2879    {
2880      *check_flags = item->check_flags;
2881      *class      = item->class;
2882      *reported   = item->is_reported;
2883      *rdepth     = item->rdepth;
2884      item->checked        = S_FALSE;
2885      item->childs_checked = S_FALSE;
2886      item->is_reported    = S_FALSE;
2887      retval = 1;
2888      goto out;
2889    }
2890
2891  item = zAVLSearch(zdirListTwo, name);
2892
2893  if (item)
2894    {
2895      *check_flags = item->check_flags;
2896      *class      = item->class;
2897      *reported   = item->is_reported;
2898      *rdepth     = item->rdepth;
2899      item->checked        = S_FALSE;
2900      item->childs_checked = S_FALSE;
2901      item->is_reported    = S_FALSE;
2902      retval = 1;
2903      goto out;
2904    }
2905
2906#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
2907  SH_MUTEX_LOCK(mutex_zglob);
2908  for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList); 
2909       testPattern;
2910       testPattern = (sh_globstack_t *) zAVLNext  (&cursor))
2911    {
2912      if (testPattern->type == SH_LIST_DIR1 || 
2913          testPattern->type == SH_LIST_DIR2)
2914        {
2915          if (0 == fnmatch(testPattern->name, name, FNM_PATHNAME|FNM_PERIOD))
2916            {
2917              *check_flags = testPattern->check_flags;
2918              *class      = testPattern->class;
2919              *rdepth     = testPattern->rdepth;
2920              retval = 1;
2921              break;
2922            }
2923       
2924        }
2925    }
2926  SH_MUTEX_UNLOCK(mutex_zglob);
2927#endif
2928 out:
2929  ; /* 'label at end of compound statement' */
2930  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
2931  return retval;
2932}
2933
2934int sh_files_search_file(char * name, int * class, 
2935                         unsigned long *check_flags, int *reported)
2936{
2937  volatile int retval = 0;
2938#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
2939  sh_globstack_t * testPattern;
2940  zAVLCursor   cursor;
2941#endif
2942  dirstack_t * item;
2943
2944  SH_MUTEX_LOCK(mutex_zfiles);
2945  item = zAVLSearch(zfileList, name);
2946
2947  if (item)
2948    {
2949      *check_flags = item->check_flags;
2950      *class      = item->class;
2951      *reported   = item->is_reported;
2952      retval = 1;
2953    }
2954  SH_MUTEX_UNLOCK(mutex_zfiles);
2955
2956#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
2957  if (retval == 0)
2958    {
2959      SH_MUTEX_LOCK(mutex_zglob);
2960      for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList); 
2961           testPattern;
2962           testPattern = (sh_globstack_t *) zAVLNext  (&cursor))
2963        {
2964          if (testPattern->type == SH_LIST_FILE)
2965            {
2966              if (0 == fnmatch(testPattern->name, name, 
2967                               FNM_PATHNAME|FNM_PERIOD))
2968                {
2969                  *check_flags = testPattern->check_flags;
2970                  *class      = testPattern->class;
2971                  retval = 1;
2972                  break;
2973                }
2974             
2975            }
2976        }
2977      SH_MUTEX_UNLOCK(mutex_zglob);
2978    }
2979#endif
2980
2981  return retval;
2982}
2983
2984void sh_files_set_file_reported(const char * name)
2985{
2986  dirstack_t * item;
2987
2988  SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
2989  item = zAVLSearch(zfileList, name);
2990
2991  if (item)
2992    {
2993      if (sh.flag.reportonce == S_TRUE)
2994        SET_SH_FFLAG_REPORTED(item->is_reported);
2995    }
2996  SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
2997  return;
2998}
2999
3000void sh_files_clear_file_reported(const char * name)
3001{
3002  dirstack_t * item;
3003
3004  SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
3005  item = zAVLSearch(zfileList, name);
3006
3007  if (item)
3008    {
3009      CLEAR_SH_FFLAG_REPORTED(item->is_reported);
3010    }
3011  SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
3012  return;
3013}
3014
3015/* -----------------------------------
3016 *
3017 *  The following two routines serve to
3018 *  verify that the user has selected
3019 *  a proper setup for file policies.
3020 *
3021 * -----------------------------------
3022 */
3023static int check_file(char * name)
3024{
3025  dirstack_t * pfilL;
3026  zAVLCursor   cursor;
3027  volatile int retval = -1;
3028
3029  SL_ENTER(_("check_file"));
3030
3031  if (SH_FILE_DIRECTORY == sh_unix_get_ftype(name))
3032    SL_RETURN(0, _("check_file"));
3033
3034  for (pfilL = (dirstack_t *) zAVLFirst (&cursor, zfileList); pfilL;
3035       pfilL = (dirstack_t *) zAVLNext  (&cursor))
3036    {
3037      if (0 == strcmp(name, pfilL->name) &&
3038          (pfilL->check_flags & MODI_ATM) == 0 &&
3039          (pfilL->check_flags & MODI_CTM) == 0 &&
3040          (pfilL->check_flags & MODI_MTM) == 0)
3041        {
3042          retval = 0;
3043          break;
3044        }
3045    }
3046
3047  SL_RETURN(retval, _("check_file"));
3048}
3049
3050static void * sh_dummy_pdirL;
3051
3052int sh_files_test_setup_int (zAVLTree * tree)
3053{
3054  int dlen, flen;
3055  zAVLCursor   cursor1;
3056  zAVLCursor   cursor2;
3057
3058  dirstack_t * pdirL; 
3059  dirstack_t * pfilL;
3060
3061  SL_ENTER(_("sh_files_test_setup"));
3062
3063  sh_dummy_pdirL = (void *) &pdirL;
3064
3065  for (pdirL = (dirstack_t *) zAVLFirst (&cursor1, tree); pdirL;
3066       pdirL = (dirstack_t *) zAVLNext  (&cursor1))
3067    {
3068      dlen = strlen(pdirL->name);
3069
3070      SH_MUTEX_LOCK(mutex_zfiles);
3071      for (pfilL = (dirstack_t *) zAVLFirst (&cursor2, zfileList); pfilL;
3072           pfilL = (dirstack_t *) zAVLNext  (&cursor2))
3073        {
3074          flen = strlen(pfilL->name);
3075
3076          /* check whether file is in tree of dir
3077           */
3078          if ((pfilL->class == SH_LEVEL_READONLY) ||
3079              (pfilL->class == SH_LEVEL_NOIGNORE))
3080            {
3081              ;  /* do nothing */
3082            }
3083          else
3084            {
3085              if ((flen > (dlen+1)) && 
3086                  (pfilL->name[dlen] == '/') &&
3087                  (NULL == strchr(&(pfilL->name[dlen+1]), '/')) && /*30-5-01*/
3088                  (0 == strncmp(pfilL->name, pdirL->name, dlen)))
3089                {
3090                  if ((pdirL->check_flags & MODI_ATM) != 0  ||
3091                      (pdirL->check_flags & MODI_MTM) != 0  ||
3092                      (pdirL->check_flags & MODI_CTM) != 0)
3093                    {
3094                      if (check_file (pdirL->name) != 0)
3095                        sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_COLL,
3096                                         pdirL->name, pfilL->name);
3097                    }
3098                }
3099            }
3100        }
3101      SH_MUTEX_UNLOCK(mutex_zfiles);
3102    }
3103
3104  SL_RETURN((0), _("sh_files_test_setup"));
3105}
3106     
3107int sh_files_test_double (zAVLTree * firstList, zAVLTree * secondList)
3108{
3109  int          retval = 0;
3110  zAVLCursor   cursor;
3111  dirstack_t * first;
3112
3113  for (first = (dirstack_t *) zAVLFirst (&cursor, firstList); first;
3114       first = (dirstack_t *) zAVLNext  (&cursor))
3115    {
3116
3117      if (NULL != zAVLSearch(secondList, first->name))
3118        {
3119          sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
3120                           first->name);
3121          retval = 1;
3122        }
3123    }
3124  return retval;
3125}
3126
3127extern void     aud_exit   (const char * file, int line, int fd);
3128     
3129int sh_files_test_setup ()
3130{
3131  int retval;
3132
3133  SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
3134  SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
3135  /* Test for modifications allowed in ReadOnly directory
3136   */ 
3137  sh_files_test_setup_int (zdirListOne);
3138  sh_files_test_setup_int (zdirListTwo);
3139
3140  /* Test for files/dirz defined twice
3141   */ 
3142  retval = sh_files_test_double (zdirListOne, zdirListTwo);
3143  if (retval != 0)
3144    aud_exit(FIL__, __LINE__, EXIT_FAILURE);
3145
3146  retval = sh_files_test_double (zdirListTwo, zdirListOne);
3147  if (retval != 0)
3148    aud_exit(FIL__, __LINE__, EXIT_FAILURE);
3149  SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
3150
3151  return 0;
3152}
3153
3154#endif
3155
3156#ifdef SH_CUTEST
3157#include "CuTest.h"
3158
3159void Test_file_lists (CuTest *tc)
3160{
3161#if (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
3162
3163  extern int hash_remove_tree_test(char * s, char * fullpath, size_t len_s);
3164
3165  char * test;
3166  int ret;
3167
3168  sh_files_pushfile_ro("/usr/test");
3169  sh_files_pushfile_ro("/usr/bin/test");
3170  sh_files_pushfile_ro("/usr/bin/foo/test");
3171
3172  sh_files_pushdir_ro("/usr");
3173  sh_files_pushdir_attr("/usr/bin");
3174  sh_files_pushdir_ro("/usr/bin/foo");
3175
3176  add_to_dirlist(zdirListOne);
3177  add_to_dirlist(zdirListTwo);
3178  add_to_filelist(zfileList);
3179
3180  test = sh_files_findfile("/usr/tes");
3181  CuAssertTrue(tc, test == NULL);
3182  test = sh_files_findfile("/usr/test");
3183  CuAssertPtrNotNull(tc, test);
3184  test = sh_files_findfile("/usr/testi");
3185  CuAssertTrue(tc, test == NULL);
3186  test = sh_files_findfile("/test");
3187  CuAssertTrue(tc, test == NULL);
3188
3189  test = sh_files_find_mostspecific_dir("/usr/bin/foo/test");
3190  CuAssertStrEquals(tc, "/usr/bin/foo", test);
3191  test = sh_files_find_mostspecific_dir("/usr/bin/test");
3192  CuAssertStrEquals(tc, "/usr/bin", test);
3193  test = sh_files_find_mostspecific_dir("/usr/test");
3194  CuAssertStrEquals(tc, "/usr", test);
3195  test = sh_files_find_mostspecific_dir("/test");
3196  CuAssertTrue(tc, test == NULL);
3197  test = sh_files_find_mostspecific_dir("/usr/foo/test");
3198  CuAssertStrEquals(tc, "/usr", test);
3199
3200  test = sh_files_find_mostspecific_dir("/usr/bin");
3201  CuAssertStrEquals(tc, "/usr/bin", test);
3202
3203  ret = hash_remove_tree_test("/usr", "/usr/test", strlen("/usr"));
3204  CuAssertIntEquals(tc, S_FALSE, ret);
3205  ret = hash_remove_tree_test("/usr", "/usr/testi", strlen("/usr"));
3206  CuAssertIntEquals(tc, S_TRUE, ret);
3207  ret = hash_remove_tree_test("/usr", "/usr/tes", strlen("/usr"));
3208  CuAssertIntEquals(tc, S_TRUE, ret);
3209
3210  ret = hash_remove_tree_test("/usr/bin", "/usr/test", strlen("/usr/bin"));
3211  CuAssertIntEquals(tc, S_FALSE, ret);
3212  ret = hash_remove_tree_test("/usr/bin", "/usr/testi", strlen("/usr/bin"));
3213  CuAssertIntEquals(tc, S_FALSE, ret);
3214  ret = hash_remove_tree_test("/usr/bin", "/usr/tes", strlen("/usr/bin"));
3215  CuAssertIntEquals(tc, S_FALSE, ret);
3216
3217  ret = hash_remove_tree_test("/usr/bin", "/usr/bin/test", strlen("/usr/bin"));
3218  CuAssertIntEquals(tc, S_FALSE, ret);
3219  ret = hash_remove_tree_test("/usr/bin", "/usr/bin/testi", strlen("/usr/bin"));
3220  CuAssertIntEquals(tc, S_TRUE, ret);
3221  ret = hash_remove_tree_test("/usr/bin", "/usr/bin/tes", strlen("/usr/bin"));
3222  CuAssertIntEquals(tc, S_TRUE, ret);
3223
3224  ret = hash_remove_tree_test("/usr/bin", "/usr/bin", strlen("/usr/bin"));
3225  CuAssertIntEquals(tc, S_TRUE, ret);
3226  ret = hash_remove_tree_test("/usr", "/usr", strlen("/usr"));
3227  CuAssertIntEquals(tc, S_TRUE, ret);
3228  ret = hash_remove_tree_test("/usr", "/usrbin", strlen("/usr"));
3229  CuAssertIntEquals(tc, S_FALSE, ret);
3230  ret = hash_remove_tree_test("/", "/usrbin", strlen("/"));
3231  CuAssertIntEquals(tc, S_TRUE, ret);
3232  ret = hash_remove_tree_test("/", "/usr", strlen("/"));
3233  CuAssertIntEquals(tc, S_FALSE, ret);
3234
3235#else
3236  (void) tc; /* fix compiler warning */
3237  return;
3238#endif
3239}
3240
3241void Test_file_dequote (CuTest *tc)
3242{
3243#if (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
3244
3245  char str1[]  = "1234567890";
3246  char str1a[] = "123456\\\"789\\r";
3247  char str1b[] = "12345678\\r9";
3248  char str1c[] = "12345678\\x0a_9";
3249  char str1d[] = "12345678\\007_9";
3250  char str1e[] = "123456789\\\\";
3251
3252  char str2[] = "1234567890\\xw";
3253  char str3[] = "1234567890\\xw99";
3254  char str4[] = "1234567890\\0ww";
3255  char str5[] = "12345\\g67890";
3256  char str6[] = "1234567890\\009a";
3257
3258  char *s, *p, *q;
3259  size_t lo, lr;
3260
3261  s = SH_ALLOC(64); sl_strlcpy(s, str1, 64); p = s; lo = strlen(s); lr = lo;
3262  q = sh_files_C_dequote(s, &lr);
3263  CuAssertPtrNotNull(tc, q);
3264  CuAssertTrue(tc, p  == q);
3265  CuAssertTrue(tc, lr == lo);
3266
3267  s = SH_ALLOC(64); sl_strlcpy(s, str1a, 64); p = s; lo = strlen(s); lr = lo;
3268  q = sh_files_C_dequote(s, &lr);
3269  CuAssertPtrNotNull(tc, q);
3270  CuAssertTrue(tc, p  != q);
3271  CuAssertTrue(tc, 0 == strcmp(q, "123456\"789\r"));
3272  CuAssertTrue(tc, lr == (lo-2));
3273
3274  s = SH_ALLOC(64); sl_strlcpy(s, str1b, 64); p = s; lo = strlen(s); lr = lo;
3275  q = sh_files_C_dequote(s, &lr);
3276  CuAssertPtrNotNull(tc, q);
3277  CuAssertTrue(tc, p  != q);
3278  CuAssertTrue(tc, 0 == strcmp(q, "12345678\r9"));
3279  CuAssertTrue(tc, lr == (lo-1));
3280
3281  s = SH_ALLOC(64); sl_strlcpy(s, str1c, 64); p = s; lo = strlen(s); lr = lo;
3282  q = sh_files_C_dequote(s, &lr);
3283  CuAssertPtrNotNull(tc, q);
3284  CuAssertTrue(tc, p  != q);
3285  CuAssertTrue(tc, 0 == strcmp(q, "12345678\x0a_9"));
3286  CuAssertTrue(tc, lr == (lo-3));
3287
3288  s = SH_ALLOC(64); sl_strlcpy(s, str1d, 64); p = s; lo = strlen(s); lr = lo;
3289  q = sh_files_C_dequote(s, &lr);
3290  CuAssertPtrNotNull(tc, q);
3291  CuAssertTrue(tc, p  != q);
3292  CuAssertTrue(tc, 0 == strcmp(q, "12345678\007_9"));
3293  CuAssertTrue(tc, lr == (lo-3));
3294
3295  s = SH_ALLOC(64); sl_strlcpy(s, str1e, 64); p = s; lo = strlen(s); lr = lo;
3296  q = sh_files_C_dequote(s, &lr);
3297  CuAssertPtrNotNull(tc, q);
3298  CuAssertTrue(tc, p  != q);
3299  CuAssertTrue(tc, 0 == strcmp(q, "123456789\\"));
3300  CuAssertTrue(tc, lr == (lo-1));
3301
3302  s = SH_ALLOC(64); sl_strlcpy(s, str2, 64); p = s; lo = strlen(s); lr = lo;
3303  q = sh_files_C_dequote(s, &lr);
3304  CuAssertTrue(tc, q == NULL);
3305  CuAssertTrue(tc, lr == 0);
3306
3307  s = SH_ALLOC(64); sl_strlcpy(s, str3, 64); p = s; lo = strlen(s); lr = lo;
3308  q = sh_files_C_dequote(s, &lr);
3309  CuAssertTrue(tc, q == NULL);
3310  CuAssertTrue(tc, lr == 0);
3311
3312  s = SH_ALLOC(64); sl_strlcpy(s, str4, 64); p = s; lo = strlen(s); lr = lo;
3313  q = sh_files_C_dequote(s, &lr);
3314  CuAssertTrue(tc, q == NULL);
3315  CuAssertTrue(tc, lr == 0);
3316
3317  s = SH_ALLOC(64); sl_strlcpy(s, str5, 64); p = s; lo = strlen(s); lr = lo;
3318  q = sh_files_C_dequote(s, &lr);
3319  CuAssertTrue(tc, q == NULL);
3320  CuAssertTrue(tc, lr == 0);
3321
3322  s = SH_ALLOC(64); sl_strlcpy(s, str6, 64); p = s; lo = strlen(s); lr = lo;
3323  q = sh_files_C_dequote(s, &lr);
3324  CuAssertTrue(tc, q == NULL);
3325  CuAssertTrue(tc, lr == 0);
3326
3327  return;
3328#else
3329  (void) tc; /* fix compiler warning */
3330  return;
3331#endif
3332}
3333#endif
3334
Note: See TracBrowser for help on using the repository browser.