source: trunk/src/sh_files.c@ 369

Last change on this file since 369 was 367, checked in by katerina, 13 years ago

Modifications for ticket #265 (inotify support). Needs testing.

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