source: trunk/src/sh_hash.c

Last change on this file was 580, checked in by katerina, 11 months ago

Fix for ticket #468 (file attributes). Also add option to switch off check.

File size: 79.4 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 1999, 2000, 2001, 2002 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 <stdlib.h>
23#include <string.h>
24#include <stdio.h>
25#include <sys/types.h>
26#ifdef HAVE_SYS_SYSMACROS_H
27#include <sys/sysmacros.h>
28#endif
29#include <sys/stat.h>
30#include <unistd.h>
31#include <ctype.h>
32
33#ifdef MAJOR_IN_MKDEV
34#include <sys/mkdev.h>
35#else
36#ifdef MAJOR_IN_SYSMACROS
37#include <sys/sysmacros.h>
38#endif
39#endif
40
41#ifdef HAVE_MEMORY_H
42#include <memory.h>
43#endif
44
45
46#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
47
48#include "samhain.h"
49#include "sh_utils.h"
50#include "sh_unix.h"
51#include "sh_dbIO_int.h"
52#include "sh_dbIO.h"
53#include "sh_hash.h"
54#include "sh_error.h"
55#include "sh_tiger.h"
56#include "sh_sig.h"
57#include "sh_unix.h"
58#include "sh_files.h"
59#include "sh_ignore.h"
60#include "sh_pthread.h"
61
62#if defined(SH_WITH_CLIENT)
63#include "sh_xfer.h"
64#endif
65
66
67#define SH_KEY_NULL _("000000000000000000000000000000000000000000000000")
68
69
70#undef FIL__
71#define FIL__ _("sh_hash.c")
72
73SH_MUTEX_INIT(mutex_hash,PTHREAD_MUTEX_INITIALIZER);
74
75static char * all_items (file_type * theFile, char * fileHash, int is_new);
76
77static const char *policy[] = {
78 N_("[]"),
79 N_("[ReadOnly]"),
80 N_("[LogFiles]"),
81 N_("[GrowingLogs]"),
82 N_("[IgnoreNone]"),
83 N_("[IgnoreAll]"),
84 N_("[Attributes]"),
85 N_("[User0]"),
86 N_("[User1]"),
87 N_("[User2]"),
88 N_("[User3]"),
89 N_("[User4]"),
90 N_("[Prelink]"),
91 NULL
92};
93
94static int report_checkflags = S_FALSE;
95int set_report_checkflags(const char * c)
96{
97 return sh_util_flagval(c, &report_checkflags);
98}
99int get_report_checkflags()
100{
101 return report_checkflags;
102}
103
104
105
106const char * sh_hash_getpolicy(int class)
107{
108 if (class > 0 && class < SH_ERR_T_DIR)
109 return _(policy[class]);
110 return _("[indef]");
111}
112
113/**********************************
114 *
115 * hash table functions
116 *
117 **********************************
118 */
119
120#include "sh_hash.h"
121
122
123/**************************************************************
124 *
125 * create a file_type from a sh_file_t
126 *
127 **************************************************************/
128file_type * sh_hash_create_ft (const sh_file_t * p, char * fileHash)
129{
130 file_type * theFile;
131
132 SL_ENTER(_("sh_hash_create_ft"));
133
134 theFile = SH_ALLOC(sizeof(file_type));
135
136 sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11);
137 theFile->mode = p->theFile.mode;
138#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
139 sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, ATTRBUF_SIZE);
140 theFile->attributes = p->theFile.attributes;
141#endif
142
143 sl_strlcpy(theFile->fullpath, p->fullpath, PATH_MAX);
144 if (p->linkpath != NULL /* && theFile->c_mode[0] == 'l' */)
145 {
146 theFile->link_path = sh_util_strdup(p->linkpath);
147 }
148 else
149 {
150 theFile->link_path = NULL;
151 }
152 sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
153
154 theFile->mtime = p->theFile.mtime;
155 theFile->ctime = p->theFile.ctime;
156 theFile->atime = p->theFile.atime;
157
158 theFile->size = p->theFile.size;
159
160 sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2);
161 theFile->group = p->theFile.group;
162 sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2);
163 theFile->owner = p->theFile.owner;
164
165 theFile->ino = p->theFile.ino;
166 theFile->rdev = p->theFile.rdev;
167 theFile->dev = p->theFile.dev;
168 theFile->hardlinks = p->theFile.hardlinks;
169 theFile->check_flags = p->theFile.checkflags;
170
171 if (p->attr_string)
172 theFile->attr_string = sh_util_strdup(p->attr_string);
173 else
174 theFile->attr_string = NULL;
175
176 SL_RETURN((theFile), _("sh_hash_create_ft"));
177}
178
179struct two_sh_file_t {
180 sh_file_t * prev;
181 sh_file_t * this;
182};
183
184static sh_file_t * hashsearch (const char * s);
185static int hashsearch_prev (const char * s, struct two_sh_file_t * a, int * index);
186
187
188/**************************************************************
189 *
190 * >>>> The internal database <<<
191 *
192 **************************************************************/
193
194static sh_file_t * tab[TABSIZE];
195
196sh_file_t ** get_default_data_table()
197{
198 return tab;
199}
200
201/**************************************************************
202 *
203 * compute hash function
204 *
205 **************************************************************/
206
207static int hashfunc(const char *s)
208{
209 unsigned int n = 0;
210
211 for ( ; *s; s++)
212 n = 31 * n + *s;
213
214 return n & (TABSIZE - 1); /* % TABSIZE */;
215}
216
217
218int hashreport_missing( char *fullpath, int level)
219{
220 sh_file_t * p;
221 char * tmp;
222 char fileHash[KEY_LEN + 1];
223 file_type * theFile;
224 char * str;
225 char hashbuf[KEYBUF_SIZE];
226 volatile int retval;
227
228 /* -------- find the entry for the file ---------------- */
229
230 SH_MUTEX_LOCK(mutex_hash);
231
232 retval = 0;
233
234 if (sl_strlen(fullpath) <= MAX_PATH_STORE)
235 p = hashsearch(fullpath);
236 else
237 p = hashsearch( sh_tiger_hash(fullpath,
238 TIGER_DATA,
239 sl_strlen(fullpath),
240 hashbuf, sizeof(hashbuf))
241 );
242 if (p == NULL)
243 {
244 retval = -1;
245 goto unlock_and_return;
246 }
247
248 theFile = sh_hash_create_ft (p, fileHash);
249 str = all_items(theFile, fileHash, 0);
250 tmp = sh_util_safe_name(fullpath);
251
252 SH_MUTEX_LOCK(mutex_thread_nolog);
253 if (!sh_global_check_silent)
254 sh_error_handle (level, FIL__, __LINE__, 0,
255 MSG_FI_MISS2, tmp, str);
256 SH_MUTEX_UNLOCK(mutex_thread_nolog);
257 ++sh.statistics.files_report;
258
259 SH_FREE(tmp);
260 SH_FREE(str);
261 if (theFile->attr_string) SH_FREE(theFile->attr_string);
262 if (theFile->link_path) SH_FREE(theFile->link_path);
263 SH_FREE(theFile);
264
265 unlock_and_return:
266 ; /* 'label at end of compound statement */
267 SH_MUTEX_UNLOCK(mutex_hash);
268
269 /* remove here to avoid second message from hash_unvisited */
270 if (retval == 0)
271 sh_hash_remove (fullpath);
272
273 return retval;
274}
275
276
277/**************************************************************
278 *
279 * search for files not visited, and check whether they exist
280 *
281 **************************************************************/
282static sh_file_t * delete_db_entry(sh_file_t *p)
283{
284 if (p->fullpath)
285 {
286 SH_FREE(p->fullpath);
287 p->fullpath = NULL;
288 }
289 if (p->linkpath)
290 {
291 SH_FREE(p->linkpath);
292 p->linkpath = NULL;
293 }
294 if (p->attr_string)
295 {
296 SH_FREE(p->attr_string);
297 p->attr_string = NULL;
298 }
299 SH_FREE(p);
300 return NULL;
301}
302
303static void hash_unvisited (int j,
304 sh_file_t *prev, sh_file_t *p, ShErrLevel level)
305{
306 struct stat buf;
307 int i;
308 char * tmp;
309 char * ptr;
310 char fileHash[KEY_LEN + 1];
311 file_type * theFile;
312 char * str;
313
314 SL_ENTER(_("hash_unvisited"));
315
316 if (p->next != NULL)
317 hash_unvisited (j, p, p->next, level);
318
319 if (p->fullpath == NULL)
320 {
321 SL_RET0(_("hash_unvisited"));
322 }
323
324 /* Not a fully qualified path, i.e. some info stored by some module
325 */
326 if (p->fullpath[0] != '/')
327 {
328 SL_RET0(_("hash_unvisited"));
329 }
330
331 /* visited flag not set: not seen;
332 * checked flag set: not seen (i.e. missing), and already checked
333 * reported flag not set: not reported yet
334 * allignore flag not set: not under IgnoreAll
335 *
336 * Files/directories under IgnoreAll are noticed as missing already
337 * during the file check.
338 */
339 if (((!SH_FFLAG_VISITED_SET(p->fflags)) || SH_FFLAG_CHECKED_SET(p->fflags))
340 && (!SH_FFLAG_REPORTED_SET(p->fflags))
341 /* && (!SH_FFLAG_ALLIGNORE_SET(p->fflags)) */)
342 {
343 i = retry_lstat(FIL__, __LINE__, p->fullpath, &buf);
344
345 /* if file does not exist
346 */
347 if (0 != i)
348 {
349 ptr = sh_util_dirname (p->fullpath);
350 if (ptr)
351 {
352 /* If any of the parent directories is under IgnoreAll
353 */
354 if ((0 != sh_files_is_allignore(ptr)) || SH_FFLAG_ALLIGNORE_SET(p->fflags))
355 level = ShDFLevel[SH_LEVEL_ALLIGNORE];
356 SH_FREE(ptr);
357 }
358
359 /* Only report if !SH_FFLAG_CHECKED_SET
360 */
361 if (!SH_FFLAG_CHECKED_SET(p->fflags))
362 {
363 if (S_FALSE == sh_ignore_chk_del(p->fullpath))
364 {
365 tmp = sh_util_safe_name(p->fullpath);
366
367 theFile = sh_hash_create_ft (p, fileHash);
368 str = all_items(theFile, fileHash, 0);
369 if (!sh_global_check_silent)
370 sh_error_handle (level, FIL__, __LINE__, 0,
371 MSG_FI_MISS2, tmp, str);
372 ++sh.statistics.files_report;
373 SH_FREE(str);
374 if (theFile->attr_string) SH_FREE(theFile->attr_string);
375 if (theFile->link_path) SH_FREE(theFile->link_path);
376 SH_FREE(theFile);
377
378 SH_FREE(tmp);
379 }
380 }
381
382 /* We rewrite the db on update, thus we need to keep this
383 * if the user does not want to purge it from the db.
384 */
385
386 if ((sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) ||
387 (S_TRUE == sh.flag.update && S_TRUE == sh_util_ask_update(p->fullpath)))
388 {
389 /* Remove the old entry
390 */
391 if (prev == p)
392 tab[j] = p->next;
393 else
394 prev->next = p->next;
395
396 delete_db_entry(p);
397
398 SL_RET0(_("hash_unvisited"));
399 }
400 }
401 }
402
403 else if (SH_FFLAG_VISITED_SET(p->fflags) && SH_FFLAG_REPORTED_SET(p->fflags)
404 && (!SH_FFLAG_ALLIGNORE_SET(p->fflags)))
405 {
406 if (S_FALSE == sh_ignore_chk_new(p->fullpath))
407 {
408 tmp = sh_util_safe_name(p->fullpath);
409
410 theFile = sh_hash_create_ft (p, fileHash);
411 str = all_items(theFile, fileHash, 0);
412 if (!sh_global_check_silent)
413 sh_error_handle (level, FIL__, __LINE__, 0,
414 MSG_FI_MISS2, tmp, str);
415 ++sh.statistics.files_report;
416 SH_FREE(str);
417 if (theFile->attr_string)
418 SH_FREE(theFile->attr_string);
419 SH_FREE(theFile);
420
421 SH_FREE(tmp);
422 }
423
424 CLEAR_SH_FFLAG_REPORTED(p->fflags);
425 }
426
427 if (sh.flag.reportonce == S_FALSE)
428 CLEAR_SH_FFLAG_REPORTED(p->fflags);
429
430 CLEAR_SH_FFLAG_VISITED(p->fflags);
431 CLEAR_SH_FFLAG_CHECKED(p->fflags);
432 SET_SH_FFLAG_ENOENT(p->fflags);
433
434 SL_RET0(_("hash_unvisited"));
435}
436
437
438
439/*********************************************************************
440 *
441 * Search for files in the database that have been deleted from disk.
442 *
443 *********************************************************************/
444void sh_hash_unvisited (ShErrLevel level)
445{
446 int i;
447
448 SL_ENTER(_("sh_hash_unvisited"));
449
450 SH_MUTEX_LOCK(mutex_hash);
451 for (i = 0; i < TABSIZE; ++i)
452 {
453 if (tab[i] != NULL)
454 hash_unvisited (i, tab[i], tab[i], level);
455 }
456 SH_MUTEX_UNLOCK(mutex_hash);
457
458 SL_RET0(_("hash_unvisited"));
459}
460
461/*********************************************************************
462 *
463 * Remove a single file from the database.
464 *
465 *********************************************************************/
466void sh_hash_remove_unconditional (const char * path)
467{
468 struct two_sh_file_t entries;
469 int index;
470
471 SL_ENTER(_("sh_hash_remove_unconditional"));
472
473 SH_MUTEX_LOCK(mutex_hash);
474 if (0 == hashsearch_prev (path, &entries, &index))
475 {
476 sh_file_t * p = entries.this;
477
478 /* Remove the old entry
479 */
480 if (entries.prev == p)
481 tab[index] = p->next;
482 else
483 entries.prev->next = p->next;
484
485 delete_db_entry(p);
486 }
487 SH_MUTEX_UNLOCK(mutex_hash);
488
489 SL_RET0(_("sh_hash_remove_unconditional"));
490}
491
492void sh_hash_remove (const char * path)
493{
494 SL_ENTER(_("sh_hash_remove"));
495
496 if ((sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) ||
497 (S_TRUE == sh.flag.update && S_TRUE == sh_util_ask_update(path)))
498 {
499 sh_hash_remove_unconditional (path);
500 }
501 SL_RET0(_("sh_hash_remove"));
502}
503
504
505/*********************************************************************
506 *
507 * Search for unvisited entries in the database, custom error handler.
508 *
509 *********************************************************************/
510void sh_hash_unvisited_custom (char prefix, void(*handler)(const char * key))
511{
512 int i;
513 sh_file_t *p = NULL;
514 sh_file_t *prev = NULL;
515 sh_file_t *next = NULL;
516
517 SL_ENTER(_("sh_hash_unvisited_custom"));
518
519 SH_MUTEX_LOCK(mutex_hash);
520 for (i = 0; i < TABSIZE; ++i)
521 {
522 if (tab[i] != NULL)
523 {
524 p = tab[i]; prev = p;
525
526 do
527 {
528 next = p->next;
529
530 if (p->fullpath &&
531 prefix == p->fullpath[0])
532 {
533 if ((!SH_FFLAG_VISITED_SET(p->fflags))
534 && (!SH_FFLAG_REPORTED_SET(p->fflags)))
535 {
536 handler(p->fullpath);
537
538 if (!SH_FFLAG_CHECKED_SET(p->fflags))
539 {
540 /* delete */
541 if (tab[i] == p)
542 {
543 tab[i] = p->next;
544 prev = tab[i];
545 next = prev;
546 }
547 else
548 {
549 prev->next = p->next;
550 next = prev->next;
551 }
552
553 p = delete_db_entry(p);
554 }
555 }
556 if (p)
557 {
558 CLEAR_SH_FFLAG_VISITED(p->fflags);
559 CLEAR_SH_FFLAG_CHECKED(p->fflags);
560 }
561 }
562 if (p)
563 prev = p;
564 p = next;
565 }
566 while (p);
567 }
568 }
569 SH_MUTEX_UNLOCK(mutex_hash);
570
571 SL_RET0(_("hash_unvisited_custom"));
572}
573
574
575/**********************************************************************
576 *
577 * delete hash array
578 *
579 **********************************************************************/
580static void hash_kill (sh_file_t *p)
581{
582 SL_ENTER(_("hash_kill"));
583
584 if (p == NULL)
585 SL_RET0(_("hash_kill"));
586
587 if (p->next != NULL)
588 hash_kill (p->next);
589
590 if (p->fullpath)
591 {
592 SH_FREE(p->fullpath);
593 p->fullpath = NULL;
594 }
595 if (p->linkpath)
596 {
597 SH_FREE(p->linkpath);
598 p->linkpath = NULL;
599 }
600 if (p->attr_string)
601 {
602 SH_FREE(p->attr_string);
603 p->attr_string = NULL;
604 }
605 SH_FREE(p);
606 p = NULL;
607 SL_RET0(_("hash_kill"));
608}
609
610
611/***********************************************************************
612 *
613 * get info out of hash array
614 *
615 ***********************************************************************/
616static sh_file_t * hashsearch (const char * s)
617{
618 sh_file_t * p;
619
620 SL_ENTER(_("hashsearch"));
621
622 if (s)
623 {
624 for (p = tab[hashfunc(s)]; p; p = p->next)
625 if ((p->fullpath != NULL) && (0 == strcmp(s, p->fullpath)))
626 SL_RETURN( p, _("hashsearch"));
627 }
628 SL_RETURN( NULL, _("hashsearch"));
629}
630
631static int hashsearch_prev (const char * s, struct two_sh_file_t * a, int * index)
632{
633 sh_file_t * this;
634 sh_file_t * prev = NULL;
635
636 SL_ENTER(_("hashsearch_prev"));
637
638 if (s)
639 {
640 *index = hashfunc(s);
641 this = tab[*index];
642 prev = this;
643
644 if (this)
645 {
646 do {
647 if ((this->fullpath != NULL) && (0 == strcmp(s, this->fullpath)))
648 {
649 a->prev = prev;
650 a->this = this;
651 SL_RETURN( 0, _("hashsearch_prev"));
652 }
653 prev = this;
654 this = this->next;
655 } while(this);
656 }
657 }
658 SL_RETURN( -1, _("hashsearch"));
659}
660
661
662/***********************************************************************
663 *
664 * insert into hash array
665 *
666 ***********************************************************************/
667void hashinsert (sh_file_t * mtab[TABSIZE], sh_file_t * s)
668{
669 sh_file_t * p;
670 sh_file_t * q;
671 int key;
672
673 SL_ENTER(_("hashinsert"));
674
675 key = hashfunc(s->fullpath);
676
677 if (mtab[key] == NULL)
678 {
679 mtab[key] = s;
680 mtab[key]->next = NULL;
681 SL_RET0(_("hashinsert"));
682 }
683 else
684 {
685 p = mtab[key];
686 while (1)
687 {
688 if (p && p->fullpath && 0 == strcmp(s->fullpath, p->fullpath))
689 {
690 q = p->next;
691 SH_FREE(p->fullpath);
692 if(p->linkpath) SH_FREE(p->linkpath);
693 if(p->attr_string) SH_FREE(p->attr_string);
694 memcpy(p, s, sizeof(sh_file_t));
695 p->next = q;
696 SH_FREE(s); s = NULL;
697 SL_RET0(_("hashinsert"));
698 }
699 else if (p && p->next == NULL)
700 {
701 p->next = s;
702 p->next->next = NULL;
703 SL_RET0(_("hashinsert"));
704 }
705 if (p)
706 p = p->next;
707 else /* cannot really happen, but llvm/clang does not know */
708 break;
709 }
710 }
711 /* notreached */
712}
713
714
715
716/******************************************************************
717 *
718 * ------- Check functions -------
719 *
720 ******************************************************************/
721
722static int IsInit = 0;
723
724void sh_hash_set_initialized()
725{
726 IsInit = 1;
727 return;
728}
729
730int sh_hash_get_initialized()
731{
732 return IsInit;
733}
734
735
736/******************************************************************
737 *
738 * Initialize
739 *
740 ******************************************************************/
741void sh_hash_init ()
742{
743 volatile int retval = 0;
744 volatile int exitval = EXIT_SUCCESS;
745
746 SL_ENTER(_("sh_hash_init"));
747
748 if ( sh.flag.checkSum == SH_CHECK_INIT )
749 {
750 dlog(1, FIL__, __LINE__,
751 _("Attempt to load the baseline database during initialisation. This is an internal error, please report it to the developer.\n"));
752 SH_ABORT;
753 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
754 }
755
756 SH_MUTEX_LOCK(mutex_hash);
757
758 if (IsInit == 1)
759 {
760 goto unlock_and_return;
761 }
762
763 /* Initialization completed.
764 */
765 retval = sh_dbIO_load_db(tab);
766
767 if (0 == retval)
768 IsInit = 1;
769 else
770 exitval = EXIT_FAILURE;
771
772 unlock_and_return:
773 ; /* 'label at end of compound statement */
774 SH_MUTEX_UNLOCK(mutex_hash);
775 if (retval == 0)
776 {
777 SL_RET0(_("sh_hash_init"));
778 }
779 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1, sh.prg_name);
780 aud_exit (FIL__, __LINE__, exitval);
781}
782
783void sh_hash_init_and_checksum()
784{
785 TPT((0, FIL__, __LINE__, _("msg=<Get checksum of the database.>\n")))
786 if (sh.flag.checkSum == SH_CHECK_CHECK)
787 {
788 if (0 != sl_strcmp(file_path('D', 'R'), _("REQ_FROM_SERVER")))
789 {
790 char hashbuf[KEYBUF_SIZE];
791 (void) sl_strlcpy(sh.data.hash,
792 sh_tiger_hash (file_path('D', 'R'),
793 TIGER_FILE, TIGER_NOLIM,
794 hashbuf, sizeof(hashbuf)),
795 KEY_LEN+1);
796 }
797
798 /* this eventually fetches the file from server to get checksum
799 */
800 sh_hash_init ();
801 }
802 return;
803}
804
805/*****************************************************************
806 *
807 * delete hash array
808 *
809 *****************************************************************/
810void sh_hash_hashdelete ()
811{
812 int i;
813
814 SL_ENTER(_("sh_hash_hashdelete"));
815
816 /* need deadlock detection here if called from exit handler
817 */
818 SH_MUTEX_TRYLOCK(mutex_hash);
819
820 if (IsInit == 0)
821 goto unlock_and_exit;
822
823 for (i = 0; i < TABSIZE; ++i)
824 if (tab[i] != NULL)
825 {
826 hash_kill (tab[i]);
827 tab[i] = NULL;
828 }
829 IsInit = 0;
830
831 unlock_and_exit:
832 ; /* 'label at end of compound statement */
833 SH_MUTEX_TRYLOCK_UNLOCK(mutex_hash);
834
835 SL_RET0(_("sh_hash_hashdelete"));
836}
837
838static int sh_loosedircheck = S_FALSE;
839
840int sh_hash_loosedircheck(const char * str)
841{
842 return sh_util_flagval(str, &sh_loosedircheck);
843}
844
845
846
847
848/*********************************************************************
849 *
850 * Check whether a file is present in the database.
851 *
852 *********************************************************************/
853static sh_file_t * sh_hash_have_it_int (const char * newname)
854{
855 sh_file_t * p;
856 char hashbuf[KEYBUF_SIZE];
857
858 SL_ENTER(_("sh_hash_have_it_int"));
859
860 if (newname == NULL)
861 SL_RETURN( (NULL), _("sh_hash_have_it_int"));
862
863 if (sl_strlen(newname) <= MAX_PATH_STORE)
864 p = hashsearch(newname);
865 else
866 p = hashsearch ( sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname),
867 hashbuf, sizeof(hashbuf)) );
868 if (p == NULL)
869 SL_RETURN( (NULL), _("sh_hash_have_it_int"));
870
871 SL_RETURN( (p), _("sh_hash_have_it_int"));
872}
873
874int sh_hash_have_it (const char * newname)
875{
876 sh_file_t * p;
877 int retval;
878
879 if (IsInit != 1)
880 sh_hash_init();
881
882 SH_MUTEX_LOCK(mutex_hash);
883
884 retval = 0;
885
886 p = sh_hash_have_it_int (newname);
887
888 if (!p)
889 retval = (-1);
890 else if ((!SH_FFLAG_ALLIGNORE_SET(p->fflags)) &&
891 (p->modi_mask & MODI_CHK) != 0 &&
892 (p->modi_mask & MODI_MOD) != 0)
893 retval = 1;
894 SH_MUTEX_UNLOCK(mutex_hash);
895
896 return retval;
897}
898
899int sh_hash_get_it (const char * newname, file_type * tmpFile, char * fileHash)
900{
901 sh_file_t * p;
902 int retval;
903
904 if (IsInit != 1)
905 sh_hash_init();
906
907 tmpFile->link_path = NULL;
908 tmpFile->attr_string = NULL;
909
910 SH_MUTEX_LOCK(mutex_hash);
911
912 retval = (-1);
913
914 p = sh_hash_have_it_int (newname);
915 if (p)
916 {
917 sl_strlcpy(tmpFile->fullpath, p->fullpath, PATH_MAX);
918 if (p->linkpath)
919 tmpFile->link_path = sh_util_strdup (p->linkpath);
920 tmpFile->size = p->theFile.size;
921 tmpFile->mtime = p->theFile.mtime;
922 tmpFile->ctime = p->theFile.ctime;
923 tmpFile->atime = p->theFile.atime;
924
925 if (NULL != fileHash)
926 sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
927
928 tmpFile->attr_string = NULL;
929 retval = 0;
930 }
931 SH_MUTEX_UNLOCK(mutex_hash);
932
933 return retval;
934}
935
936int sh_hash_getflags (char * filename)
937{
938 sh_file_t * p;
939 int retval = 0;
940
941 if ( sh.flag.checkSum != SH_CHECK_INIT )
942 {
943 if (IsInit != 1)
944 sh_hash_init();
945
946 SH_MUTEX_LOCK(mutex_hash);
947 p = sh_hash_have_it_int (filename);
948 if (p)
949 retval = p->fflags;
950 else
951 retval = -1;
952 SH_MUTEX_UNLOCK(mutex_hash);
953 }
954 return retval;
955}
956
957int sh_hash_setflags (char * filename, int flags)
958{
959 sh_file_t * p;
960 int retval = 0;
961
962 if ( sh.flag.checkSum != SH_CHECK_INIT )
963 {
964 if (IsInit != 1)
965 sh_hash_init();
966
967 SH_MUTEX_LOCK(mutex_hash);
968 p = sh_hash_have_it_int (filename);
969 if (p)
970 {
971 p->fflags = flags;
972 retval = 0;
973 }
974 else
975 retval = -1;
976 SH_MUTEX_UNLOCK(mutex_hash);
977 }
978 return retval;
979}
980
981/* needs lock to be threadsafe
982 */
983void sh_hash_set_flag (char * filename, int flag_to_set)
984{
985 sh_file_t * p;
986
987 if ( sh.flag.checkSum != SH_CHECK_INIT )
988 {
989 if (IsInit != 1)
990 sh_hash_init();
991
992 SH_MUTEX_LOCK(mutex_hash);
993 p = sh_hash_have_it_int (filename);
994 if (p)
995 {
996 p->fflags |= flag_to_set;
997 }
998 SH_MUTEX_UNLOCK(mutex_hash);
999 }
1000 return;
1001}
1002
1003/* needs lock to be threadsafe
1004 */
1005void sh_hash_clear_flag (char * filename, int flag_to_clear)
1006{
1007 sh_file_t * p;
1008
1009 if ( sh.flag.checkSum != SH_CHECK_INIT )
1010 {
1011 if (IsInit != 1)
1012 sh_hash_init();
1013
1014 SH_MUTEX_LOCK(mutex_hash);
1015 p = sh_hash_have_it_int (filename);
1016 if (p)
1017 {
1018 p->fflags &= ~flag_to_clear;
1019 }
1020 SH_MUTEX_UNLOCK(mutex_hash);
1021 }
1022 return;
1023}
1024
1025
1026/*****************************************************************
1027 *
1028 * Set a file's status to 'visited'. This is required for
1029 * files that should be ignored, and may be present in the
1030 * database, but not on disk.
1031 *
1032 *****************************************************************/
1033static int sh_hash_set_visited_int (char * newname, int flag)
1034{
1035 sh_file_t * p;
1036 char hashbuf[KEYBUF_SIZE];
1037 int retval;
1038
1039 SL_ENTER(_("sh_hash_set_visited_int"));
1040
1041 if (newname == NULL)
1042 SL_RETURN((-1), _("sh_hash_set_visited_int"));
1043
1044 if (IsInit != 1)
1045 sh_hash_init();
1046
1047 SH_MUTEX_LOCK(mutex_hash);
1048
1049 if (sl_strlen(newname) <= MAX_PATH_STORE)
1050 p = hashsearch(newname);
1051 else
1052 p = hashsearch (sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname),
1053 hashbuf, sizeof(hashbuf)));
1054
1055 if (p)
1056 {
1057 if (flag == SH_FFLAG_CHECKED)
1058 {
1059 CLEAR_SH_FFLAG_REPORTED(p->fflags);
1060 CLEAR_SH_FFLAG_VISITED(p->fflags);
1061 SET_SH_FFLAG_CHECKED(p->fflags);
1062 }
1063 else
1064 {
1065 SET_SH_FFLAG_VISITED(p->fflags);
1066 CLEAR_SH_FFLAG_CHECKED(p->fflags);
1067 if (flag == SH_FFLAG_REPORTED)
1068 SET_SH_FFLAG_REPORTED(p->fflags);
1069 else
1070 CLEAR_SH_FFLAG_REPORTED(p->fflags);
1071 }
1072 retval = 0;
1073 }
1074 else
1075 retval = -1;
1076
1077 SH_MUTEX_UNLOCK(mutex_hash);
1078 SL_RETURN((retval), _("sh_hash_set_visited_int"));
1079}
1080
1081
1082/* cause the record to be deleted without a 'missing' message
1083 */
1084int sh_hash_set_missing (char * newname)
1085{
1086 int i;
1087 SL_ENTER(_("sh_hash_set_missing"));
1088
1089 i = sh_hash_set_visited_int(newname, SH_FFLAG_CHECKED);
1090
1091 if (sh.flag.checkSum != SH_CHECK_INIT) {
1092 sh_hash_remove(newname);
1093 }
1094
1095 SL_RETURN(i, _("sh_hash_set_missing"));
1096}
1097
1098/* mark the file as visited and reported
1099 */
1100int sh_hash_set_visited (char * newname)
1101{
1102 int i;
1103 SL_ENTER(_("sh_hash_set_visited"));
1104 i = sh_hash_set_visited_int(newname, SH_FFLAG_REPORTED);
1105 SL_RETURN(i, _("sh_hash_set_visited"));
1106}
1107
1108/* mark the file as visited and NOT reported
1109 * used to avoid deletion of file from internal database
1110 */
1111int sh_hash_set_visited_true (char * newname)
1112{
1113 int i;
1114 SL_ENTER(_("sh_hash_set_visited_true"));
1115 i = sh_hash_set_visited_int(newname, 0);
1116 SL_RETURN(i, _("sh_hash_set_visited_true"));
1117}
1118
1119
1120/******************************************************************
1121 *
1122 * Data entry for arbitrary data into database
1123 *
1124 ******************************************************************/
1125
1126void sh_hash_push2db (const char * key, struct store2db * save)
1127{
1128 int i = 0;
1129 char * p;
1130 char i2h[2];
1131 file_type * tmpFile = SH_ALLOC(sizeof(file_type));
1132
1133 int size = save->size;
1134 unsigned char * str = save->str;
1135
1136
1137 tmpFile->attr_string = NULL;
1138 tmpFile->link_path = NULL;
1139
1140 sl_strlcpy(tmpFile->fullpath, key, PATH_MAX);
1141 tmpFile->size = save->val0;
1142 tmpFile->mtime = save->val1;
1143 tmpFile->ctime = save->val2;
1144 tmpFile->atime = save->val3;
1145
1146 tmpFile->mode = 0;
1147 tmpFile->owner = 0;
1148 tmpFile->group = 0;
1149 sl_strlcpy(tmpFile->c_owner, _("root"), 5);
1150 sl_strlcpy(tmpFile->c_group, _("root"), 5);
1151
1152 tmpFile->check_flags = 0;
1153
1154 if ((str != NULL) && (size < (PATH_MAX/2)-1))
1155 {
1156 tmpFile->c_mode[0] = 'l';
1157 tmpFile->c_mode[1] = 'r'; tmpFile->c_mode[2] = 'w';
1158 tmpFile->c_mode[3] = 'x'; tmpFile->c_mode[4] = 'r';
1159 tmpFile->c_mode[5] = 'w'; tmpFile->c_mode[6] = 'x';
1160 tmpFile->c_mode[7] = 'r'; tmpFile->c_mode[8] = 'w';
1161 tmpFile->c_mode[9] = 'x'; tmpFile->c_mode[10] = '\0';
1162 tmpFile->link_path = SH_ALLOC((size * 2) + 2);
1163 for (i = 0; i < size; ++i)
1164 {
1165 p = sh_util_charhex (str[i],i2h);
1166 tmpFile->link_path[2*i] = p[0];
1167 tmpFile->link_path[2*i+1] = p[1];
1168 tmpFile->link_path[2*i+2] = '\0';
1169 }
1170 }
1171 else
1172 {
1173 for (i = 0; i < 10; ++i)
1174 tmpFile->c_mode[i] = '-';
1175 tmpFile->c_mode[10] = '\0';
1176 tmpFile->link_path = sh_util_strdup("-");
1177 }
1178
1179 if (sh.flag.checkSum == SH_CHECK_INIT)
1180 sh_dbIO_data_write (tmpFile,
1181 (save->checksum[0] == '\0') ? SH_KEY_NULL : save->checksum);
1182 else
1183 sh_hash_pushdata_memory (tmpFile,
1184 (save->checksum[0] == '\0') ? SH_KEY_NULL : save->checksum);
1185
1186 if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
1187 SH_FREE(tmpFile);
1188 return;
1189}
1190
1191extern int sh_util_hextobinary (char * binary, char * hex, int bytes);
1192
1193char * sh_hash_db2pop (const char * key, struct store2db * save)
1194{
1195 size_t len;
1196 char * p;
1197 int i;
1198 char * retval = NULL;
1199 char fileHash[KEY_LEN+1];
1200 file_type * tmpFile = SH_ALLOC(sizeof(file_type));
1201
1202 save->size = 0;
1203
1204 if (0 == sh_hash_get_it (key, tmpFile, fileHash))
1205 {
1206 save->val0 = tmpFile->size;
1207 save->val1 = tmpFile->mtime;
1208 save->val2 = tmpFile->ctime;
1209 save->val3 = tmpFile->atime;
1210
1211 sl_strlcpy(save->checksum, fileHash, KEY_LEN+1);
1212
1213 if (tmpFile->link_path && tmpFile->link_path[0] != '-')
1214 {
1215 len = strlen(tmpFile->link_path);
1216
1217 p = SH_ALLOC((len/2)+1);
1218 i = sh_util_hextobinary (p, tmpFile->link_path, len);
1219
1220 if (i == 0)
1221 {
1222 save->size = (len/2);
1223 p[save->size] = '\0';
1224 retval = p;
1225 }
1226 else
1227 {
1228 SH_FREE(p);
1229 save->size = 0;
1230 }
1231 }
1232 else
1233 {
1234 save->size = 0;
1235 }
1236 }
1237 else
1238 {
1239 save->size = -1;
1240 save->val0 = 0;
1241 save->val1 = 0;
1242 save->val2 = 0;
1243 save->val3 = 0;
1244 }
1245 if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
1246 SH_FREE(tmpFile);
1247 return retval;
1248}
1249
1250
1251
1252
1253/******************************************************************
1254 *
1255 * Data entry in hash table
1256 *
1257 ******************************************************************/
1258sh_file_t * sh_hash_push_int (file_type * buf, char * fileHash)
1259{
1260 sh_file_t * fp = NULL;
1261 sh_filestore_t p;
1262
1263 size_t len;
1264 char * fullpath;
1265 char * linkpath;
1266 char * attr_string = NULL;
1267 char hashbuf[KEYBUF_SIZE];
1268
1269 SL_ENTER(_("sh_hash_push_int"));
1270
1271 if (!buf)
1272 SL_RETURN(NULL, _("sh_hash_push_int"));
1273
1274 fp = SH_ALLOC(sizeof(sh_file_t));
1275
1276 p.mark = REC_MAGIC;
1277 if (buf->attr_string)
1278 p.mark |= REC_FLAGS_ATTR;
1279 sl_strlcpy(p.c_mode, buf->c_mode, 11);
1280 sl_strlcpy(p.c_group, buf->c_group, GROUP_MAX+1);
1281 sl_strlcpy(p.c_owner, buf->c_owner, USER_MAX+1);
1282 sl_strlcpy(p.checksum, fileHash, KEY_LEN+1);
1283#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1284 sl_strlcpy(p.c_attributes, buf->c_attributes, 13);
1285#endif
1286
1287#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1288 p.attributes = (UINT32) buf->attributes;
1289#endif
1290 p.linkmode = (UINT32) buf->linkmode;
1291 p.hardlinks = (UINT32) buf->hardlinks;
1292 p.dev = (UINT64) buf->dev;
1293 p.rdev = (UINT64) buf->rdev;
1294 p.mode = (UINT32) buf->mode;
1295 p.ino = (UINT32) buf->ino;
1296 p.size = (UINT64) buf->size;
1297 p.mtime = (UINT64) buf->mtime;
1298 p.atime = (UINT64) buf->atime;
1299 p.ctime = (UINT64) buf->ctime;
1300 p.owner = (UINT32) buf->owner;
1301 p.group = (UINT32) buf->group;
1302
1303 p.checkflags = (UINT32) buf->check_flags;
1304
1305 memcpy( &(*fp).theFile, &p, sizeof(sh_filestore_t) );
1306 fp->fflags = 0; /* init fflags */
1307 fp->modi_mask = 0L;
1308
1309 if (buf->attr_string)
1310 attr_string = sh_util_strdup(buf->attr_string);
1311 fp->attr_string = attr_string;
1312
1313 len = sl_strlen(buf->fullpath);
1314 if (len <= MAX_PATH_STORE)
1315 {
1316 fullpath = SH_ALLOC(len+1);
1317 sl_strlcpy(fullpath, buf->fullpath, len+1);
1318 }
1319 else
1320 {
1321 fullpath = SH_ALLOC(KEY_LEN + 1);
1322 sl_strlcpy(fullpath,
1323 sh_tiger_hash (buf->fullpath, TIGER_DATA, len,
1324 hashbuf, sizeof(hashbuf)),
1325 KEY_LEN+1);
1326 }
1327 fp->fullpath = fullpath;
1328
1329 if (buf->link_path)
1330 {
1331 len = sl_strlen(buf->link_path);
1332 if (len <= MAX_PATH_STORE)
1333 {
1334 linkpath = SH_ALLOC(len+1);
1335 sl_strlcpy(linkpath, buf->link_path, len+1);
1336 }
1337 else
1338 {
1339 linkpath = SH_ALLOC(KEY_LEN + 1);
1340 sl_strlcpy(linkpath,
1341 sh_tiger_hash (buf->link_path, TIGER_DATA, len,
1342 hashbuf, sizeof(hashbuf)),
1343 KEY_LEN+1);
1344 }
1345 fp->linkpath = linkpath;
1346 }
1347 else
1348 fp->linkpath = NULL;
1349
1350 SL_RETURN( fp, _("sh_hash_push_int"));
1351}
1352
1353#ifdef HAVE_INTTYPES_H
1354#include <inttypes.h>
1355#else
1356#ifdef HAVE_STDINT_H
1357#include <stdint.h>
1358#endif
1359#endif
1360
1361#ifndef PRIu64
1362#ifdef HAVE_LONG_32
1363#define PRIu64 "llu"
1364#else
1365#define PRIu64 "lu"
1366#endif
1367#endif
1368
1369char * sh_hash_size_format()
1370{
1371 static char form_rval[81];
1372
1373 SL_ENTER(_("sh_hash_size_format"));
1374
1375
1376#ifdef SH_USE_XML
1377 sl_snprintf(form_rval, 80, _("%s%s%s%s%s"),
1378 _("size_old=\"%"), PRIu64, _("\" size_new=\"%"), PRIu64, "\" ");
1379#else
1380 sl_snprintf(form_rval, 80, _("%s%s%s%s%s"),
1381 _("size_old=<%"), PRIu64, _(">, size_new=<%"), PRIu64, ">, ");
1382#endif
1383
1384 SL_RETURN( form_rval, _("sh_hash_size_format"));
1385}
1386
1387
1388#ifdef SH_USE_XML
1389static char * all_items (file_type * theFile, char * fileHash, int is_new)
1390{
1391 char timstr1c[32];
1392 char timstr1a[32];
1393 char timstr1m[32];
1394
1395 char * tmp_lnk;
1396 char * format;
1397
1398 char * tmp = SH_ALLOC(SH_MSG_BUF);
1399 char * msg = SH_ALLOC(SH_MSG_BUF);
1400
1401 tmp[0] = '\0';
1402 msg[0] = '\0';
1403
1404 if (report_checkflags != S_FALSE)
1405 {
1406 if (is_new)
1407 format = _("checkflags_new=\"0%lo\" ");
1408 else
1409 format = _("checkflags_old=\"0%lo\" ");
1410 sl_snprintf(tmp, SH_MSG_BUF, format,
1411 (unsigned long) theFile->check_flags);
1412 sl_strlcat(msg, tmp, SH_MSG_BUF);
1413 }
1414
1415#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1416 if (is_new)
1417 format = _("mode_new=\"%s\" attr_new=\"%s\" imode_new=\"%ld\" iattr_new=\"%ld\" ");
1418 else
1419 format = _("mode_old=\"%s\" attr_old=\"%s\" imode_old=\"%ld\" iattr_old=\"%ld\" ");
1420 sl_snprintf(tmp, SH_MSG_BUF, format,
1421 theFile->c_mode,
1422 theFile->c_attributes,
1423 (long) theFile->mode,
1424 (long) theFile->attributes
1425 );
1426#else
1427 if (is_new)
1428 format = _("mode_new=\"%s\" imode_new=\"%ld\" ");
1429 else
1430 format = _("mode_old=\"%s\" imode_old=\"%ld\" ");
1431
1432 sl_snprintf(tmp, SH_MSG_BUF, format,
1433 theFile->c_mode,
1434 (long) theFile->mode
1435 );
1436#endif
1437 sl_strlcat(msg, tmp, SH_MSG_BUF);
1438
1439 if (is_new)
1440 format = _("hardlinks_new=\"%lu\" ");
1441 else
1442 format = _("hardlinks_old=\"%lu\" ");
1443 sl_snprintf(tmp, SH_MSG_BUF, format,
1444 (unsigned long) theFile->hardlinks);
1445 sl_strlcat(msg, tmp, SH_MSG_BUF);
1446
1447
1448 if (is_new)
1449 format = _("idevice_new=\"%lu\" ");
1450 else
1451 format = _("idevice_old=\"%lu\" ");
1452 sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->rdev);
1453 sl_strlcat(msg, tmp, SH_MSG_BUF);
1454
1455
1456 if (is_new)
1457 format = _("inode_new=\"%lu\" ");
1458 else
1459 format = _("inode_old=\"%lu\" ");
1460 sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->ino);
1461 sl_strlcat(msg, tmp, SH_MSG_BUF);
1462
1463 /*
1464 * also report device for prelude
1465 */
1466#if defined(HAVE_LIBPRELUDE)
1467 if (is_new)
1468 format = _("dev_new=\"%lu,%lu\" ");
1469 else
1470 format = _("dev_old=\"%lu,%lu\" ");
1471 sl_snprintf(tmp, SH_MSG_BUF, format,
1472 (unsigned long) major(theFile->dev),
1473 (unsigned long) minor(theFile->dev));
1474 sl_strlcat(msg, tmp, SH_MSG_BUF);
1475#endif
1476
1477
1478 if (is_new)
1479 format = _("owner_new=\"%s\" iowner_new=\"%ld\" ");
1480 else
1481 format = _("owner_old=\"%s\" iowner_old=\"%ld\" ");
1482 sl_snprintf(tmp, SH_MSG_BUF, format,
1483 theFile->c_owner, (long) theFile->owner);
1484 sl_strlcat(msg, tmp, SH_MSG_BUF);
1485
1486
1487 if (is_new)
1488 format = _("group_new=\"%s\" igroup_new=\"%ld\" ");
1489 else
1490 format = _("group_old=\"%s\" igroup_old=\"%ld\" ");
1491 sl_snprintf(tmp, SH_MSG_BUF, format,
1492 theFile->c_group, (long) theFile->group);
1493 sl_strlcat(msg, tmp, SH_MSG_BUF);
1494
1495
1496 if (is_new)
1497 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
1498 (UINT64) 0, (UINT64) theFile->size);
1499 else
1500 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
1501 (UINT64) theFile->size, (UINT64) 0);
1502 sl_strlcat(msg, tmp, SH_MSG_BUF);
1503
1504
1505 (void) sh_unix_gmttime (theFile->ctime, timstr1c, sizeof(timstr1c));
1506 if (is_new)
1507 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_new=\"%s\" "), timstr1c);
1508 else
1509 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=\"%s\" "), timstr1c);
1510 sl_strlcat(msg, tmp, SH_MSG_BUF);
1511
1512 (void) sh_unix_gmttime (theFile->atime, timstr1a, sizeof(timstr1a));
1513 if (is_new)
1514 sl_snprintf(tmp, SH_MSG_BUF, _("atime_new=\"%s\" "), timstr1a);
1515 else
1516 sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=\"%s\" "), timstr1a);
1517 sl_strlcat(msg, tmp, SH_MSG_BUF);
1518
1519 (void) sh_unix_gmttime (theFile->mtime, timstr1m, sizeof(timstr1m));
1520 if (is_new)
1521 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_new=\"%s\" "), timstr1m);
1522 else
1523 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=\"%s\" "), timstr1m);
1524 sl_strlcat(msg, tmp, SH_MSG_BUF);
1525
1526 if (is_new)
1527 sl_snprintf(tmp, SH_MSG_BUF, _("chksum_new=\"%s\" "), fileHash);
1528 else
1529 sl_snprintf(tmp, SH_MSG_BUF, _("chksum_old=\"%s\" "), fileHash);
1530 sl_strlcat(msg, tmp, SH_MSG_BUF);
1531
1532 if (theFile->c_mode[0] == 'l' ||
1533 (theFile->link_path != NULL && theFile->link_path[0] != '-'))
1534 {
1535 tmp_lnk = sh_util_safe_name(theFile->link_path);
1536 if (tmp_lnk)
1537 {
1538 if (is_new)
1539 sl_snprintf(tmp, SH_MSG_BUF, _("link_new=\"%s\" "), tmp_lnk);
1540 else
1541 sl_snprintf(tmp, SH_MSG_BUF, _("link_old=\"%s\" "), tmp_lnk);
1542 SH_FREE(tmp_lnk);
1543 sl_strlcat(msg, tmp, SH_MSG_BUF);
1544 }
1545 }
1546
1547 if (theFile->attr_string)
1548 {
1549 tmp_lnk = sh_util_safe_name(theFile->attr_string);
1550 if (tmp_lnk)
1551 {
1552 if (is_new)
1553 sl_snprintf(tmp, SH_MSG_BUF, _("acl_new=\"%s\" "), tmp_lnk);
1554 else
1555 sl_snprintf(tmp, SH_MSG_BUF, _("acl_old=\"%s\" "), tmp_lnk);
1556 SH_FREE(tmp_lnk);
1557 sl_strlcat(msg, tmp, SH_MSG_BUF);
1558 }
1559 }
1560
1561
1562 SH_FREE(tmp);
1563 return (msg);
1564}
1565#else
1566static char * all_items (file_type * theFile, char * fileHash, int is_new)
1567{
1568 char timstr1c[32];
1569 char timstr1a[32];
1570 char timstr1m[32];
1571
1572 char * tmp_lnk;
1573 char * format;
1574
1575 char * tmp = SH_ALLOC(SH_MSG_BUF);
1576 char * msg = SH_ALLOC(SH_MSG_BUF);
1577
1578 tmp[0] = '\0';
1579 msg[0] = '\0';
1580
1581 if (report_checkflags == S_TRUE)
1582 {
1583 if (is_new)
1584 format = _("checkflags_new=<0%lo> ");
1585 else
1586 format = _("checkflags_old=<0%lo> ");
1587 sl_snprintf(tmp, SH_MSG_BUF, format,
1588 (unsigned long) theFile->check_flags);
1589 sl_strlcat(msg, tmp, SH_MSG_BUF);
1590 }
1591
1592
1593#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1594 if (is_new)
1595 format = _("mode_new=<%s>, attr_new=<%s>, imode_new=<%ld>, iattr_new=<%ld>, ");
1596 else
1597 format = _("mode_old=<%s>, attr_old=<%s>, imode_old=<%ld>, iattr_old=<%ld>, ");
1598 sl_snprintf(tmp, SH_MSG_BUF, format,
1599 theFile->c_mode,
1600 theFile->c_attributes,
1601 (long) theFile->mode,
1602 (long) theFile->attributes
1603 );
1604#else
1605 if (is_new)
1606 format = _("mode_new=<%s>, imode_new=<%ld>, ");
1607 else
1608 format = _("mode_old=<%s>, imode_old=<%ld>, ");
1609
1610 sl_snprintf(tmp, SH_MSG_BUF, format,
1611 theFile->c_mode,
1612 (long) theFile->mode
1613 );
1614#endif
1615 sl_strlcat(msg, tmp, SH_MSG_BUF);
1616
1617 if (is_new)
1618 format = _("hardlinks_new=<%lu>, ");
1619 else
1620 format = _("hardlinks_old=<%lu>, ");
1621 sl_snprintf(tmp, SH_MSG_BUF, format,
1622 (unsigned long) theFile->hardlinks);
1623 sl_strlcat(msg, tmp, SH_MSG_BUF);
1624
1625
1626 if (is_new)
1627 format = _("idevice_new=<%lu>, ");
1628 else
1629 format = _("idevice_old=<%lu>, ");
1630 sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->rdev);
1631 sl_strlcat(msg, tmp, SH_MSG_BUF);
1632
1633
1634 if (is_new)
1635 format = _("inode_new=<%lu>, ");
1636 else
1637 format = _("inode_old=<%lu>, ");
1638 sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->ino);
1639 sl_strlcat(msg, tmp, SH_MSG_BUF);
1640
1641
1642 /*
1643 * also report device for prelude
1644 */
1645#if defined(HAVE_LIBPRELUDE)
1646 if (is_new)
1647 format = _("dev_new=<%lu,%lu>, ");
1648 else
1649 format = _("dev_old=<%lu,%lu>, ");
1650 sl_snprintf(tmp, SH_MSG_BUF, format,
1651 (unsigned long) major(theFile->dev),
1652 (unsigned long) minor(theFile->dev));
1653 sl_strlcat(msg, tmp, SH_MSG_BUF);
1654#endif
1655
1656 if (is_new)
1657 format = _("owner_new=<%s>, iowner_new=<%ld>, ");
1658 else
1659 format = _("owner_old=<%s>, iowner_old=<%ld>, ");
1660 sl_snprintf(tmp, SH_MSG_BUF, format,
1661 theFile->c_owner, (long) theFile->owner);
1662 sl_strlcat(msg, tmp, SH_MSG_BUF);
1663
1664
1665 if (is_new)
1666 format = _("group_new=<%s>, igroup_new=<%ld>, ");
1667 else
1668 format = _("group_old=<%s>, igroup_old=<%ld>, ");
1669 sl_snprintf(tmp, SH_MSG_BUF, format,
1670 theFile->c_group, (long) theFile->group);
1671 sl_strlcat(msg, tmp, SH_MSG_BUF);
1672
1673
1674 if (is_new)
1675 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
1676 (UINT64) 0, (UINT64) theFile->size);
1677 else
1678 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
1679 (UINT64) theFile->size, (UINT64) 0);
1680 sl_strlcat(msg, tmp, SH_MSG_BUF);
1681
1682
1683 (void) sh_unix_gmttime (theFile->ctime, timstr1c, sizeof(timstr1c));
1684 if (is_new)
1685 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_new=<%s>, "), timstr1c);
1686 else
1687 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=<%s>, "), timstr1c);
1688 sl_strlcat(msg, tmp, SH_MSG_BUF);
1689
1690 (void) sh_unix_gmttime (theFile->atime, timstr1a, sizeof(timstr1a));
1691 if (is_new)
1692 sl_snprintf(tmp, SH_MSG_BUF, _("atime_new=<%s>, "), timstr1a);
1693 else
1694 sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=<%s>, "), timstr1a);
1695 sl_strlcat(msg, tmp, SH_MSG_BUF);
1696
1697 (void) sh_unix_gmttime (theFile->mtime, timstr1m, sizeof(timstr1m));
1698 if (is_new)
1699 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_new=<%s>, "), timstr1m);
1700 else
1701 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=<%s>, "), timstr1m);
1702 sl_strlcat(msg, tmp, SH_MSG_BUF);
1703
1704 if (is_new)
1705 sl_snprintf(tmp, SH_MSG_BUF, _("chksum_new=<%s>"), fileHash);
1706 else
1707 sl_snprintf(tmp, SH_MSG_BUF, _("chksum_old=<%s>"), fileHash);
1708 sl_strlcat(msg, tmp, SH_MSG_BUF);
1709
1710 if (theFile->c_mode[0] == 'l' ||
1711 (theFile->link_path != NULL && theFile->link_path[0] != '-'))
1712 {
1713 tmp_lnk = sh_util_safe_name(theFile->link_path);
1714 if (tmp_lnk)
1715 {
1716 if (is_new)
1717 sl_snprintf(tmp, SH_MSG_BUF, _(", link_new=<%s> "), tmp_lnk);
1718 else
1719 sl_snprintf(tmp, SH_MSG_BUF, _(", link_old=<%s> "), tmp_lnk);
1720 SH_FREE(tmp_lnk);
1721 sl_strlcat(msg, tmp, SH_MSG_BUF);
1722 }
1723 }
1724
1725 if (theFile->attr_string)
1726 {
1727 tmp_lnk = sh_util_safe_name(theFile->attr_string);
1728 if (tmp_lnk)
1729 {
1730 if (is_new)
1731 sl_snprintf(tmp, SH_MSG_BUF, _(", acl_new=<%s> "), tmp_lnk);
1732 else
1733 sl_snprintf(tmp, SH_MSG_BUF, _(", acl_old=<%s> "), tmp_lnk);
1734 SH_FREE(tmp_lnk);
1735 sl_strlcat(msg, tmp, SH_MSG_BUF);
1736 }
1737 }
1738
1739 SH_FREE(tmp);
1740 return (msg);
1741}
1742#endif
1743
1744void sh_hash_pushdata_memory (file_type * theFile, char * fileHash)
1745{
1746 sh_file_t * p;
1747
1748 SL_ENTER(_("sh_hash_pushdata_memory"));
1749
1750 p = sh_hash_push_int(theFile, fileHash);
1751 if (p)
1752 {
1753 SH_MUTEX_LOCK(mutex_hash);
1754 hashinsert (tab, p);
1755 p->modi_mask = theFile->check_flags;
1756 SH_MUTEX_UNLOCK(mutex_hash);
1757 }
1758
1759 SL_RET0(_("sh_hash_pushdata_memory"));
1760}
1761
1762int sh_hash_is_null_file(file_type * theFile)
1763{
1764 if (theFile->hardlinks == SH_DEADFILE && theFile->mode == 0 &&
1765 theFile->ino == 0 && theFile->ctime == 0)
1766 {
1767 return S_TRUE;
1768 }
1769 return S_FALSE;
1770}
1771
1772int sh_hash_is_null_record(sh_filestore_t * theFile)
1773{
1774 if (theFile->hardlinks == SH_DEADFILE && theFile->mode == 0 &&
1775 theFile->ino == 0 && theFile->ctime == 0)
1776 {
1777 return S_TRUE;
1778 }
1779 return S_FALSE;
1780}
1781
1782void sh_hash_insert_null(char * str)
1783{
1784 file_type theFile = { 0, 0, {'\0'}, 0, 0, 0, 0, 0,
1785#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1786 0, {'\0'},
1787#endif
1788 {'\0'}, 0, {'\0'}, 0, {'\0'},
1789 0, 0, 0, 0, 0, 0, 0, NULL, 0, {'\0'}, 0, NULL
1790 }; /* clang compiler bails out on standard conforming init with just {0} */
1791 char fileHash[KEY_LEN+1];
1792 char hashbuf[KEYBUF_SIZE];
1793
1794 sl_strlcpy(fileHash, SH_KEY_NULL, sizeof(fileHash));
1795 theFile.hardlinks = SH_DEADFILE;
1796
1797 if (sl_strlen(str) < PATH_MAX)
1798 sl_strlcpy(theFile.fullpath, str, PATH_MAX);
1799 else
1800 sl_strlcpy(theFile.fullpath,
1801 sh_tiger_hash(str, TIGER_DATA, sl_strlen(str),
1802 hashbuf, sizeof(hashbuf)),
1803 PATH_MAX);
1804
1805 sh_hash_pushdata_memory(&theFile, fileHash);
1806 return;
1807}
1808
1809static int handle_notfound(int log_severity, int class,
1810 file_type * theFile, char * fileHash)
1811{
1812 sh_file_t * p;
1813 int retval = 0;
1814
1815 if (!theFile)
1816 return retval;
1817
1818 if (S_FALSE == sh_ignore_chk_new(theFile->fullpath))
1819 {
1820 char * tmp = sh_util_safe_name(theFile->fullpath);
1821 char * str;
1822
1823 sh_files_fixup_mask(class, &(theFile->check_flags));
1824 str = all_items (theFile, fileHash, 1);
1825
1826 if (!sh_global_check_silent)
1827 sh_error_handle (log_severity, FIL__, __LINE__, 0,
1828 MSG_FI_ADD2,
1829 tmp, str);
1830 ++sh.statistics.files_report;
1831 SH_FREE(str);
1832 SH_FREE(tmp);
1833 }
1834
1835 if (sh.flag.reportonce == S_TRUE)
1836 SET_SH_FFLAG_REPORTED(theFile->file_reported);
1837
1838 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
1839 {
1840 p = sh_hash_push_int(theFile, fileHash);
1841 if (p)
1842 {
1843 hashinsert (tab, p);
1844 p->modi_mask = theFile->check_flags;
1845 p->theFile.checkflags = p->modi_mask;
1846 }
1847 }
1848
1849 else if (S_TRUE == sh.flag.update)
1850 {
1851 if (S_TRUE == sh_util_ask_update (theFile->fullpath))
1852 {
1853 p = sh_hash_push_int(theFile, fileHash);
1854 if (p)
1855 {
1856 hashinsert (tab, p);
1857 p->modi_mask = theFile->check_flags;
1858 p->theFile.checkflags = p->modi_mask;
1859 }
1860 }
1861 else
1862 retval = 1;
1863 }
1864 return retval;
1865}
1866
1867/*****************************************************************
1868 *
1869 * Compare a file with the database status.
1870 *
1871 *****************************************************************/
1872int sh_hash_compdata (int class, file_type * theFile, char * fileHash,
1873 char * policy_override, int severity_override)
1874{
1875 char * msg;
1876 sh_file_t * p;
1877 char * tmp;
1878 char * tmp_path;
1879 char * tmp_lnk;
1880 char * tmp_lnk_old;
1881
1882 char timstr1c[32];
1883 char timstr2c[32];
1884 char timstr1a[32];
1885 char timstr2a[32];
1886 char timstr1m[32];
1887 char timstr2m[32];
1888 char linkHash[KEY_LEN+1];
1889 char * linkComp;
1890 int maxcomp;
1891 volatile int checksum_flag = 0;
1892
1893 char change_code[16];
1894 int i;
1895
1896 unsigned long modi_mask;
1897
1898 char log_policy[32];
1899 volatile int log_severity;
1900 char hashbuf[KEYBUF_SIZE];
1901 struct {
1902 unsigned long oldflags;
1903 unsigned long newflags;
1904 } cf_report;
1905
1906 int retval;
1907
1908 SL_ENTER(_("sh_hash_compdata"));
1909
1910 if (!theFile)
1911 SL_RETURN(0, _("sh_hash_compdata"));
1912
1913 if (IsInit != 1) sh_hash_init();
1914
1915 if (severity_override < 0)
1916 log_severity = ShDFLevel[class];
1917 else
1918 log_severity = severity_override;
1919
1920 if (policy_override != NULL)
1921 sl_strlcpy (log_policy, policy_override, 32);
1922
1923 /* -------- find the entry for the file ---------------- */
1924
1925 SH_MUTEX_LOCK(mutex_hash);
1926
1927 modi_mask = 0;
1928 retval = 0;
1929
1930 if (sl_strlen(theFile->fullpath) <= MAX_PATH_STORE)
1931 p = hashsearch(theFile->fullpath);
1932 else
1933 p = hashsearch( sh_tiger_hash(theFile->fullpath,
1934 TIGER_DATA,
1935 sl_strlen(theFile->fullpath),
1936 hashbuf, sizeof(hashbuf))
1937 );
1938
1939
1940 /* --------- Not found in database. ------------
1941 */
1942
1943 if (p == NULL)
1944 {
1945 retval = handle_notfound(log_severity, class, theFile, fileHash);
1946 goto unlock_and_return;
1947 }
1948
1949 /* --------- Skip if we don't want to report changes. ------------
1950 */
1951
1952 if (S_TRUE == sh_ignore_chk_mod(theFile->fullpath))
1953 {
1954 MODI_SET(theFile->check_flags, MODI_NOCHECK);
1955 p->modi_mask = theFile->check_flags;
1956 p->theFile.checkflags = p->modi_mask;
1957 goto unlock_and_return;
1958 }
1959
1960 cf_report.oldflags = p->theFile.checkflags;
1961 cf_report.newflags = theFile->check_flags;
1962
1963 p->modi_mask = theFile->check_flags;
1964 p->theFile.checkflags = p->modi_mask;
1965
1966 /* initialize change_code */
1967 for (i = 0; i < 15; ++i)
1968 change_code[i] = '-';
1969 change_code[15] = '\0';
1970
1971 TPT ((0, FIL__, __LINE__, _("file=<%s>, cs_old=<%s>, cs_new=<%s>\n"),
1972 theFile->fullpath, fileHash, p->theFile.checksum));
1973
1974 if ( (fileHash != NULL) &&
1975 (strncmp (fileHash, p->theFile.checksum, KEY_LEN) != 0) &&
1976 (theFile->check_flags & MODI_CHK) != 0)
1977 {
1978 checksum_flag = 1;
1979
1980 if ((theFile->check_flags & MODI_SGROW) == 0)
1981 {
1982 modi_mask |= MODI_CHK;
1983 change_code[0] = 'C';
1984 TPT ((0, FIL__, __LINE__, _("mod=<checksum>")));
1985 }
1986 else
1987 {
1988 if (0 != strncmp (&fileHash[KEY_LEN + 1], p->theFile.checksum, KEY_LEN))
1989 {
1990 if (S_FALSE == sh_check_rotated_log (theFile->fullpath, (UINT64) p->theFile.size,
1991 (UINT64) p->theFile.ino, p->theFile.checksum,
1992 p->theFile.checkflags))
1993 {
1994 modi_mask |= MODI_CHK;
1995 change_code[0] = 'C';
1996 TPT ((0, FIL__, __LINE__, _("mod=<checksum>")));
1997 }
1998 else
1999 {
2000 /* logfile has been rotated */
2001 p->theFile.size = theFile->size;
2002 p->theFile.ino = theFile->ino;
2003 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
2004 }
2005 }
2006 else
2007 {
2008 p->theFile.size = theFile->size;
2009 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
2010 }
2011 }
2012 }
2013
2014 if (p->theFile.c_mode[0] == 'l')
2015 {
2016 if (!(theFile->link_path) &&
2017 (theFile->check_flags & MODI_LNK) != 0)
2018 {
2019 linkComp = NULL;
2020 modi_mask |= MODI_LNK;
2021 change_code[1] = 'L';
2022 TPT ((0, FIL__, __LINE__, _("mod=<link>")));
2023 }
2024 else
2025 {
2026 if (sl_strlen(theFile->link_path) >= MAX_PATH_STORE)
2027 {
2028 sl_strlcpy(linkHash,
2029 sh_tiger_hash(theFile->link_path,
2030 TIGER_DATA,
2031 sl_strlen(theFile->link_path),
2032 hashbuf, sizeof(hashbuf)),
2033 sizeof(linkHash));
2034 linkComp = linkHash;
2035 maxcomp = KEY_LEN;
2036 }
2037 else
2038 {
2039 linkComp = theFile->link_path;
2040 maxcomp = MAX_PATH_STORE;
2041 }
2042
2043 if ( sl_strncmp (linkComp, p->linkpath, maxcomp) != 0 &&
2044 (theFile->check_flags & MODI_LNK) != 0)
2045 {
2046 modi_mask |= MODI_LNK;
2047 change_code[1] = 'L';
2048 TPT ((0, FIL__, __LINE__, _("mod=<link>")));
2049 }
2050 }
2051 }
2052
2053 if (p->theFile.c_mode[0] == 'c' || p->theFile.c_mode[0] == 'b')
2054 {
2055 if ( ( major(theFile->rdev) != major((dev_t)p->theFile.rdev) ||
2056 minor(theFile->rdev) != minor((dev_t)p->theFile.rdev) ) &&
2057 (theFile->check_flags & MODI_RDEV) != 0)
2058 {
2059 modi_mask |= MODI_RDEV;
2060 change_code[2] = 'D';
2061 TPT ((0, FIL__, __LINE__, _("mod=<rdev>")));
2062 }
2063 }
2064
2065 /* cast to UINT32 in case ino_t is not 32bit
2066 */
2067 if ( (UINT32) theFile->ino != (UINT32) p->theFile.ino &&
2068 (theFile->check_flags & MODI_INO) != 0)
2069 {
2070 if ((theFile->check_flags & MODI_SGROW) == 0)
2071 {
2072 modi_mask |= MODI_INO;
2073 change_code[3] = 'I';
2074 TPT ((0, FIL__, __LINE__, _("mod=<inode>")));
2075 }
2076 else
2077 {
2078 /* growing log, checksum ok but inode changed
2079 */
2080 if (checksum_flag == 0)
2081 {
2082 if (S_FALSE == sh_check_rotated_log (theFile->fullpath, (UINT64) p->theFile.size,
2083 (UINT64) p->theFile.ino, p->theFile.checksum,
2084 p->theFile.checkflags))
2085 {
2086 modi_mask |= MODI_INO;
2087 change_code[3] = 'I';
2088 TPT ((0, FIL__, __LINE__, _("mod=<inode>")));
2089 }
2090 else
2091 {
2092 /* logfile has been rotated */
2093 p->theFile.size = theFile->size;
2094 p->theFile.ino = theFile->ino;
2095 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
2096 }
2097 }
2098 else
2099 {
2100 modi_mask |= MODI_INO;
2101 change_code[3] = 'I';
2102 TPT ((0, FIL__, __LINE__, _("mod=<inode>")));
2103 }
2104 }
2105 }
2106
2107 if ( theFile->hardlinks != (nlink_t) p->theFile.hardlinks &&
2108 (theFile->check_flags & MODI_HLN) != 0)
2109 {
2110 modi_mask |= MODI_HLN;
2111 change_code[4] = 'H';
2112 TPT ((0, FIL__, __LINE__, _("mod=<hardlink>")));
2113 }
2114
2115
2116 if ( ( (theFile->mode != p->theFile.mode)
2117#if defined(USE_ACL) || defined(USE_XATTR)
2118 || ( (sh_unix_check_selinux|sh_unix_check_acl) &&
2119 (
2120 (theFile->attr_string == NULL && p->attr_string != NULL) ||
2121 (theFile->attr_string != NULL && p->attr_string == NULL) ||
2122 (theFile->attr_string != NULL && 0 != strcmp(theFile->attr_string, p->attr_string))
2123 )
2124 )
2125#endif
2126#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2127 || (theFile->attributes != p->theFile.attributes)
2128#endif
2129 )
2130 && (theFile->check_flags & MODI_MOD) != 0)
2131 {
2132 modi_mask |= MODI_MOD;
2133 change_code[5] = 'M';
2134 TPT ((0, FIL__, __LINE__, _("mod=<mode>")));
2135 /*
2136 * report link path if switch link/no link
2137 */
2138 if ((theFile->check_flags & MODI_LNK) != 0 &&
2139 (theFile->c_mode[0] != p->theFile.c_mode[0]) &&
2140 (theFile->c_mode[0] == 'l' || p->theFile.c_mode[0] == 'l'))
2141 {
2142 modi_mask |= MODI_LNK;
2143 change_code[1] = 'L';
2144 TPT ((0, FIL__, __LINE__, _("mod=<link>")));
2145 }
2146 }
2147
2148 if ( theFile->owner != (uid_t) p->theFile.owner &&
2149 (theFile->check_flags & MODI_USR) != 0)
2150 {
2151 modi_mask |= MODI_USR;
2152 change_code[6] = 'U';
2153 TPT ((0, FIL__, __LINE__, _("mod=<user>")));
2154 }
2155
2156 if ( theFile->group != (gid_t) p->theFile.group &&
2157 (theFile->check_flags & MODI_GRP) != 0)
2158 {
2159 modi_mask |= MODI_GRP;
2160 change_code[7] = 'G';
2161 TPT ((0, FIL__, __LINE__, _("mod=<group>")));
2162 }
2163
2164
2165 if ( theFile->mtime != (time_t) p->theFile.mtime &&
2166 (theFile->check_flags & MODI_MTM) != 0)
2167 {
2168 modi_mask |= MODI_MTM;
2169 change_code[8] = 'T';
2170 TPT ((0, FIL__, __LINE__, _("mod=<mtime>")));
2171 }
2172
2173 if ( (theFile->check_flags & MODI_ATM) != 0 &&
2174 theFile->atime != (time_t) p->theFile.atime)
2175 {
2176 modi_mask |= MODI_ATM;
2177 change_code[8] = 'T';
2178 TPT ((0, FIL__, __LINE__, _("mod=<atime>")));
2179 }
2180
2181
2182 /* Resetting the access time will set a new ctime. Thus, either we ignore
2183 * the access time or the ctime for NOIGNORE
2184 */
2185 if ( theFile->ctime != (time_t) p->theFile.ctime &&
2186 (theFile->check_flags & MODI_CTM) != 0)
2187 {
2188 modi_mask |= MODI_CTM;
2189 change_code[8] = 'T';
2190 TPT ((0, FIL__, __LINE__, _("mod=<ctime>")));
2191 }
2192
2193 if ( theFile->size != (off_t) p->theFile.size &&
2194 (theFile->check_flags & MODI_SIZ) != 0)
2195 {
2196 if ((theFile->check_flags & MODI_SGROW) == 0 ||
2197 theFile->size < (off_t) p->theFile.size)
2198 {
2199 modi_mask |= MODI_SIZ;
2200 change_code[9] = 'S';
2201 TPT ((0, FIL__, __LINE__, _("mod=<size>")));
2202 }
2203 }
2204 change_code[10] = '\0';
2205
2206 /* --- Directories special case ---
2207 */
2208 if (p->theFile.c_mode[0] == 'd' &&
2209 0 == (modi_mask & ~(MODI_SIZ|MODI_ATM|MODI_CTM|MODI_MTM)) &&
2210 sh_loosedircheck == S_TRUE)
2211 {
2212 modi_mask = 0;
2213 }
2214
2215 /* --- Report full details. ---
2216 */
2217 if (modi_mask != 0 && sh.flag.fulldetail == S_TRUE)
2218 {
2219 if ((theFile->check_flags & MODI_ATM) == 0)
2220 modi_mask = MASK_READONLY_;
2221 else
2222 modi_mask = MASK_NOIGNORE_;
2223 }
2224
2225 /* --- Report on modified files. ---
2226 */
2227 if (modi_mask != 0 && (!SH_FFLAG_REPORTED_SET(p->fflags)))
2228 {
2229 tmp = SH_ALLOC(SH_MSG_BUF);
2230 msg = SH_ALLOC(SH_MSG_BUF);
2231 msg[0] = '\0';
2232
2233 sh_files_fixup_mask(class, &(cf_report.newflags));
2234
2235 if ( (report_checkflags != S_FALSE) && (cf_report.oldflags != cf_report.newflags))
2236 {
2237 sl_snprintf(tmp, SH_MSG_BUF,
2238#ifdef SH_USE_XML
2239 _("checkflags_old=\"0%lo\" checkflags_new=\"0%lo\" "),
2240#else
2241 _("checkflags_old=<0%lo>, checkflags_new=<0%lo>, "),
2242#endif
2243 cf_report.oldflags, cf_report.newflags);
2244 sl_strlcat(msg, tmp, SH_MSG_BUF);
2245 }
2246
2247 if ( ((modi_mask & MODI_MOD) != 0)
2248#if defined(HAVE_LIBPRELUDE)
2249 || ((modi_mask & MODI_USR) != 0)
2250 || ((modi_mask & MODI_GRP) != 0)
2251#endif
2252 )
2253 {
2254#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2255 sl_snprintf(tmp, SH_MSG_BUF,
2256#ifdef SH_USE_XML
2257 _("mode_old=\"%s\" mode_new=\"%s\" attr_old=\"%s\" attr_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" iattr_old=\"%ld\" iattr_new=\"%ld\" "),
2258#else
2259 _("mode_old=<%s>, mode_new=<%s>, attr_old=<%s>, attr_new=<%s>, imode_old=<%ld>, imode_new=<%ld>, iattr_old=<%ld>, iattr_new=<%ld>, "),
2260#endif
2261 p->theFile.c_mode, theFile->c_mode,
2262 p->theFile.c_attributes, theFile->c_attributes,
2263
2264 (long) p->theFile.mode, (long) theFile->mode,
2265 (long) p->theFile.attributes,
2266 (long) theFile->attributes
2267 );
2268#else
2269#ifdef SH_USE_XML
2270 sl_snprintf(tmp, SH_MSG_BUF,
2271 _("mode_old=\"%s\" mode_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" "),
2272 p->theFile.c_mode, theFile->c_mode,
2273 (long) p->theFile.mode, (long) theFile->mode);
2274#else
2275 sl_snprintf(tmp, SH_MSG_BUF, _("mode_old=<%s>, mode_new=<%s>, "),
2276 p->theFile.c_mode, theFile->c_mode);
2277#endif
2278#endif
2279 sl_strlcat(msg, tmp, SH_MSG_BUF);
2280
2281#if defined(USE_ACL) || defined(USE_XATTR)
2282 if (theFile->attr_string != NULL || p->attr_string != NULL)
2283 {
2284 sl_snprintf(tmp, SH_MSG_BUF,
2285#ifdef SH_USE_XML
2286 _("acl_old=\"%s\" acl_new=\"%s\" "),
2287#else
2288 _("acl_old=<%s>, acl_new=<%s>, "),
2289#endif
2290 (p->attr_string) ? p->attr_string : _("none"),
2291 (theFile->attr_string) ? theFile->attr_string : _("none"));
2292
2293 sl_strlcat(msg, tmp, SH_MSG_BUF);
2294 }
2295#endif
2296
2297 if ((modi_mask & MODI_MOD) != 0)
2298 {
2299 /*
2300 * We postpone update if sh.flag.update == S_TRUE because
2301 * in interactive mode the user may not accept the change.
2302 */
2303 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2304 {
2305 sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11);
2306 p->theFile.mode = theFile->mode;
2307#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2308 sl_strlcpy(p->theFile.c_attributes,theFile->c_attributes,16);
2309 p->theFile.attributes = theFile->attributes;
2310#endif
2311#if defined(USE_ACL) || defined(USE_XATTR)
2312 if (p->attr_string == NULL && theFile->attr_string != NULL)
2313 { p->attr_string = sh_util_strdup (theFile->attr_string); }
2314 else if (p->attr_string != NULL && theFile->attr_string == NULL)
2315 { SH_FREE(p->attr_string); p->attr_string = NULL; }
2316 else if (theFile->attr_string != NULL && p->attr_string != NULL)
2317 {
2318 if (0 != strcmp(theFile->attr_string, p->attr_string))
2319 {
2320 SH_FREE(p->attr_string);
2321 p->attr_string = sh_util_strdup (theFile->attr_string);
2322 }
2323 }
2324#endif
2325 }
2326 }
2327
2328 }
2329
2330 if ((modi_mask & MODI_HLN) != 0)
2331 {
2332 sl_snprintf(tmp, SH_MSG_BUF,
2333#ifdef SH_USE_XML
2334 _("hardlinks_old=\"%lu\" hardlinks_new=\"%lu\" "),
2335#else
2336 _("hardlinks_old=<%lu>, hardlinks_new=<%lu>, "),
2337#endif
2338 (unsigned long) p->theFile.hardlinks,
2339 (unsigned long) theFile->hardlinks);
2340 sl_strlcat(msg, tmp, SH_MSG_BUF);
2341
2342 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2343 p->theFile.hardlinks = theFile->hardlinks;
2344 }
2345
2346 if ((modi_mask & MODI_RDEV) != 0)
2347 {
2348 sl_snprintf(tmp, SH_MSG_BUF,
2349#ifdef SH_USE_XML
2350 _("device_old=\"%lu,%lu\" device_new=\"%lu,%lu\" idevice_old=\"%lu\" idevice_new=\"%lu\" "),
2351#else
2352 _("device_old=<%lu,%lu>, device_new=<%lu,%lu>, "),
2353#endif
2354 (unsigned long) major(p->theFile.rdev),
2355 (unsigned long) minor(p->theFile.rdev),
2356 (unsigned long) major(theFile->rdev),
2357 (unsigned long) minor(theFile->rdev)
2358#ifdef SH_USE_XML
2359 , (unsigned long) p->theFile.rdev,
2360 (unsigned long) theFile->rdev
2361#endif
2362 );
2363 sl_strlcat(msg, tmp, SH_MSG_BUF);
2364
2365 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2366 p->theFile.rdev = theFile->rdev;
2367 }
2368
2369 if ((modi_mask & MODI_INO) != 0)
2370 {
2371 sl_snprintf(tmp, SH_MSG_BUF,
2372#ifdef SH_USE_XML
2373 _("inode_old=\"%lu\" inode_new=\"%lu\" "),
2374#else
2375 _("inode_old=<%lu>, inode_new=<%lu>, "),
2376#endif
2377 (unsigned long) p->theFile.ino,
2378 (unsigned long) theFile->ino);
2379 sl_strlcat(msg, tmp, SH_MSG_BUF);
2380
2381 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2382 {
2383 p->theFile.ino = theFile->ino;
2384 p->theFile.dev = theFile->dev;
2385 }
2386 }
2387
2388
2389 /*
2390 * also report device for prelude
2391 */
2392#if defined(HAVE_LIBPRELUDE)
2393 if ((modi_mask & MODI_INO) != 0)
2394 {
2395 sl_snprintf(tmp, SH_MSG_BUF,
2396#ifdef SH_USE_XML
2397 _("dev_old=\"%lu,%lu\" dev_new=\"%lu,%lu\" "),
2398#else
2399 _("dev_old=<%lu,%lu>, dev_new=<%lu,%lu>, "),
2400#endif
2401 (unsigned long) major(p->theFile.dev),
2402 (unsigned long) minor(p->theFile.dev),
2403 (unsigned long) major(theFile->dev),
2404 (unsigned long) minor(theFile->dev)
2405 );
2406 sl_strlcat(msg, tmp, SH_MSG_BUF);
2407
2408 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2409 p->theFile.dev = theFile->dev;
2410 }
2411#endif
2412
2413 if ( ((modi_mask & MODI_USR) != 0)
2414#if defined(HAVE_LIBPRELUDE)
2415 || ((modi_mask & MODI_MOD) != 0)
2416#endif
2417 )
2418 {
2419#ifdef SH_USE_XML
2420 sl_snprintf(tmp, SH_MSG_BUF,
2421 _("owner_old=\"%s\" owner_new=\"%s\" iowner_old=\"%ld\" iowner_new=\"%ld\" "),
2422#else
2423 sl_snprintf(tmp, SH_MSG_BUF,
2424 _("owner_old=<%s>, owner_new=<%s>, iowner_old=<%ld>, iowner_new=<%ld>, "),
2425#endif
2426 p->theFile.c_owner, theFile->c_owner,
2427 (long) p->theFile.owner, (long) theFile->owner
2428 );
2429 sl_strlcat(msg, tmp, SH_MSG_BUF);
2430
2431 if ((modi_mask & MODI_USR) != 0) {
2432 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2433 {
2434 sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2);
2435 p->theFile.owner = theFile->owner;
2436 }
2437 }
2438 }
2439
2440 if ( ((modi_mask & MODI_GRP) != 0)
2441#if defined(HAVE_LIBPRELUDE)
2442 || ((modi_mask & MODI_MOD) != 0)
2443#endif
2444 )
2445 {
2446#ifdef SH_USE_XML
2447 sl_snprintf(tmp, SH_MSG_BUF,
2448 _("group_old=\"%s\" group_new=\"%s\" igroup_old=\"%ld\" igroup_new=\"%ld\" "),
2449 p->theFile.c_group, theFile->c_group,
2450 (long) p->theFile.group, (long) theFile->group);
2451#else
2452 sl_snprintf(tmp, SH_MSG_BUF,
2453 _("group_old=<%s>, group_new=<%s>, igroup_old=<%ld>, igroup_new=<%ld>, "),
2454 p->theFile.c_group, theFile->c_group,
2455 (long) p->theFile.group, (long) theFile->group);
2456#endif
2457
2458 sl_strlcat(msg, tmp, SH_MSG_BUF);
2459
2460 if ((modi_mask & MODI_GRP) != 0) {
2461 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2462 {
2463 sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2);
2464 p->theFile.group = theFile->group;
2465 }
2466 }
2467 }
2468
2469 if ((modi_mask & MODI_SIZ) != 0)
2470 {
2471 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
2472 (UINT64) p->theFile.size,
2473 (UINT64) theFile->size);
2474 sl_strlcat(msg, tmp, SH_MSG_BUF);
2475
2476 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2477 p->theFile.size = theFile->size;
2478 }
2479
2480 if ((modi_mask & MODI_CTM) != 0)
2481 {
2482 (void) sh_unix_gmttime (p->theFile.ctime, timstr1c, sizeof(timstr1c));
2483 (void) sh_unix_gmttime (theFile->ctime, timstr2c, sizeof(timstr2c));
2484#ifdef SH_USE_XML
2485 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=\"%s\" ctime_new=\"%s\" "),
2486 timstr1c, timstr2c);
2487#else
2488 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=<%s>, ctime_new=<%s>, "),
2489 timstr1c, timstr2c);
2490#endif
2491 sl_strlcat(msg, tmp, SH_MSG_BUF);
2492
2493 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2494 p->theFile.ctime = theFile->ctime;
2495 }
2496
2497 if ((modi_mask & MODI_ATM) != 0)
2498 {
2499 (void) sh_unix_gmttime (p->theFile.atime, timstr1a, sizeof(timstr1a));
2500 (void) sh_unix_gmttime (theFile->atime, timstr2a, sizeof(timstr2a));
2501#ifdef SH_USE_XML
2502 sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=\"%s\" atime_new=\"%s\" "),
2503 timstr1a, timstr2a);
2504#else
2505 sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=<%s>, atime_new=<%s>, "),
2506 timstr1a, timstr2a);
2507#endif
2508 sl_strlcat(msg, tmp, SH_MSG_BUF);
2509
2510 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2511 p->theFile.atime = theFile->atime;
2512 }
2513
2514 if ((modi_mask & MODI_MTM) != 0)
2515 {
2516 (void) sh_unix_gmttime (p->theFile.mtime, timstr1m, sizeof(timstr1m));
2517 (void) sh_unix_gmttime (theFile->mtime, timstr2m, sizeof(timstr2m));
2518#ifdef SH_USE_XML
2519 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=\"%s\" mtime_new=\"%s\" "),
2520 timstr1m, timstr2m);
2521#else
2522 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=<%s>, mtime_new=<%s>, "),
2523 timstr1m, timstr2m);
2524#endif
2525 sl_strlcat(msg, tmp, SH_MSG_BUF);
2526
2527 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2528 p->theFile.mtime = theFile->mtime;
2529 }
2530
2531
2532 if ((modi_mask & MODI_CHK) != 0)
2533 {
2534 sl_snprintf(tmp, SH_MSG_BUF,
2535#ifdef SH_USE_XML
2536 _("chksum_old=\"%s\" chksum_new=\"%s\" "),
2537#else
2538 _("chksum_old=<%s>, chksum_new=<%s>, "),
2539#endif
2540 p->theFile.checksum, fileHash);
2541 sl_strlcat(msg, tmp, SH_MSG_BUF);
2542
2543 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2544 {
2545 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
2546 if ((theFile->check_flags & MODI_SGROW) != 0)
2547 p->theFile.size = theFile->size;
2548 }
2549
2550
2551 if (theFile->c_mode[0] != 'l' && theFile->link_path &&
2552 strlen(theFile->link_path) > 2)
2553 modi_mask |= MODI_LNK;
2554 }
2555
2556
2557 if ((modi_mask & MODI_LNK) != 0 /* && theFile->c_mode[0] == 'l' */)
2558 {
2559 if (theFile->link_path)
2560 tmp_lnk = sh_util_safe_name(theFile->link_path);
2561 else
2562 tmp_lnk = sh_util_strdup("-");
2563 if (p->linkpath)
2564 tmp_lnk_old = sh_util_safe_name(p->linkpath);
2565 else
2566 tmp_lnk_old = sh_util_strdup("-");
2567#ifdef SH_USE_XML
2568 sl_snprintf(tmp, SH_MSG_BUF, _("link_old=\"%s\" link_new=\"%s\" "),
2569 tmp_lnk_old, tmp_lnk);
2570#else
2571 sl_snprintf(tmp, SH_MSG_BUF, _("link_old=<%s>, link_new=<%s>, "),
2572 tmp_lnk_old, tmp_lnk);
2573#endif
2574 SH_FREE(tmp_lnk);
2575 SH_FREE(tmp_lnk_old);
2576 sl_strlcat(msg, tmp, SH_MSG_BUF);
2577
2578 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
2579 {
2580 if (p->linkpath != NULL)
2581 SH_FREE(p->linkpath);
2582 if (!(theFile->link_path))
2583 p->linkpath = sh_util_strdup("-");
2584 else
2585 p->linkpath = sh_util_strdup(theFile->link_path);
2586 }
2587 }
2588
2589 if (MODI_AUDIT_ENABLED(theFile->check_flags))
2590 {
2591 char result[256];
2592
2593 sh_error_handle (SH_ERR_INFO, FIL__, __LINE__,
2594 0, MSG_E_SUBGPATH,
2595 _("Fetching audit record"),
2596 _("sh_hash"), theFile->fullpath );
2597
2598 if (NULL != sh_audit_fetch (theFile->fullpath, theFile->mtime, theFile->ctime, theFile->atime,
2599 result, sizeof(result)))
2600 {
2601#ifdef SH_USE_XML
2602 sl_strlcat(msg, _("obj=\""), SH_MSG_BUF);
2603#else
2604 sl_strlcat(msg, _("obj=<"), SH_MSG_BUF);
2605#endif
2606
2607 sl_strlcat(msg, result, SH_MSG_BUF);
2608
2609#ifdef SH_USE_XML
2610 sl_strlcat(msg, _("\" "), SH_MSG_BUF);
2611#else
2612 sl_strlcat(msg, _(">"), SH_MSG_BUF);
2613#endif
2614 }
2615 }
2616
2617 /****************************************************
2618 *
2619 * REPORT on file change
2620 *
2621 ****************************************************/
2622 tmp_path = sh_util_safe_name(theFile->fullpath);
2623 if (!sh_global_check_silent)
2624 sh_error_handle(log_severity, FIL__, __LINE__,
2625 (long) modi_mask, MSG_FI_CHAN,
2626 (policy_override == NULL) ? _(policy[class]):log_policy,
2627 change_code, tmp_path, msg);
2628 ++sh.statistics.files_report;
2629
2630 SH_FREE(tmp_path);
2631 SH_FREE(tmp);
2632 SH_FREE(msg);
2633
2634 if (S_TRUE == sh.flag.update)
2635 {
2636 if (S_FALSE == sh_util_ask_update(theFile->fullpath))
2637 {
2638 /* user does not want to update, thus we replace
2639 * with data from the baseline database
2640 */
2641 sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11);
2642 theFile->mode = p->theFile.mode;
2643#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2644 sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, 16);
2645 theFile->attributes = p->theFile.attributes;
2646#endif
2647#if defined(USE_ACL) || defined(USE_XATTR)
2648 if (theFile->attr_string == NULL && p->attr_string != NULL)
2649 { theFile->attr_string = sh_util_strdup (p->attr_string); }
2650 else if (theFile->attr_string != NULL && p->attr_string == NULL)
2651 { SH_FREE(theFile->attr_string); theFile->attr_string = NULL; }
2652 else if (theFile->attr_string != NULL && p->attr_string != NULL)
2653 {
2654 if (0 != strcmp(theFile->attr_string, p->attr_string))
2655 {
2656 SH_FREE(theFile->attr_string);
2657 theFile->attr_string = sh_util_strdup (p->attr_string);
2658 }
2659 }
2660#endif
2661
2662 if (theFile->c_mode[0] == 'l') /* c_mode is already copied */
2663 {
2664 if (theFile->link_path)
2665 SH_FREE(theFile->link_path);
2666 if (p->linkpath)
2667 theFile->link_path = sh_util_strdup(p->linkpath);
2668 else
2669 theFile->link_path = sh_util_strdup("-");
2670 }
2671 else
2672 {
2673 if (theFile->link_path)
2674 SH_FREE(theFile->link_path);
2675 if (p->linkpath)
2676 theFile->link_path = sh_util_strdup(p->linkpath);
2677 else
2678 theFile->link_path = NULL;
2679 }
2680
2681 sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
2682
2683 theFile->mtime = p->theFile.mtime;
2684 theFile->ctime = p->theFile.ctime;
2685 theFile->atime = p->theFile.atime;
2686
2687 theFile->size = p->theFile.size;
2688
2689 sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2);
2690 theFile->group = p->theFile.group;
2691 sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2);
2692 theFile->owner = p->theFile.owner;
2693
2694 theFile->ino = p->theFile.ino;
2695 theFile->rdev = p->theFile.rdev;
2696 theFile->dev = p->theFile.dev;
2697 theFile->hardlinks = p->theFile.hardlinks;
2698
2699 SET_SH_FFLAG_VISITED(p->fflags);
2700 CLEAR_SH_FFLAG_CHECKED(p->fflags);
2701 retval = 1;
2702 goto unlock_and_return;
2703 }
2704 else /* if (sh.flag.reportonce == S_TRUE) */
2705 {
2706 /* we replace the data in the in-memory copy of the
2707 * baseline database, because otherwise we would get
2708 * another warning if the suidcheck runs
2709 */
2710 sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11);
2711 p->theFile.mode = theFile->mode;
2712#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2713 sl_strlcpy(p->theFile.c_attributes, theFile->c_attributes, 16);
2714 p->theFile.attributes = theFile->attributes;
2715#endif
2716#if defined(USE_ACL) || defined(USE_XATTR)
2717 if (p->attr_string == NULL && theFile->attr_string != NULL)
2718 { p->attr_string = sh_util_strdup (theFile->attr_string); }
2719 else if (p->attr_string != NULL && theFile->attr_string == NULL)
2720 { SH_FREE(p->attr_string); p->attr_string = NULL; }
2721 else if (theFile->attr_string != NULL && p->attr_string != NULL)
2722 {
2723 if (0 != strcmp(theFile->attr_string, p->attr_string))
2724 {
2725 SH_FREE(p->attr_string);
2726 p->attr_string = sh_util_strdup (theFile->attr_string);
2727 }
2728 }
2729#endif
2730
2731 if (theFile->c_mode[0] == 'l' || theFile->link_path)
2732 {
2733 if (p->linkpath != NULL)
2734 SH_FREE(p->linkpath);
2735 p->linkpath = sh_util_strdup(theFile->link_path);
2736 }
2737 else
2738 {
2739 if (p->linkpath != NULL)
2740 SH_FREE(p->linkpath);
2741 p->linkpath = sh_util_strdup("-");
2742 }
2743
2744 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
2745
2746 p->theFile.mtime = theFile->mtime;
2747 p->theFile.ctime = theFile->ctime;
2748 p->theFile.atime = theFile->atime;
2749
2750 p->theFile.size = theFile->size;
2751
2752 sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2);
2753 p->theFile.group = theFile->group;
2754 sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2);
2755 p->theFile.owner = theFile->owner;
2756
2757 p->theFile.ino = theFile->ino;
2758 p->theFile.rdev = theFile->rdev;
2759 p->theFile.dev = theFile->dev;
2760 p->theFile.hardlinks = theFile->hardlinks;
2761 }
2762 }
2763 }
2764
2765 SET_SH_FFLAG_VISITED(p->fflags);
2766 CLEAR_SH_FFLAG_CHECKED(p->fflags);
2767
2768 unlock_and_return:
2769 ; /* 'label at end of compound statement */
2770 SH_MUTEX_UNLOCK(mutex_hash);
2771 SL_RETURN(retval, _("sh_hash_compdata"));
2772}
2773
2774int hash_full_tree ()
2775{
2776 sh_file_t * p;
2777 int i;
2778
2779 SL_ENTER(_("hash_full_tree"));
2780
2781 if (IsInit != 1)
2782 SL_RETURN(0, _("hash_full_tree"));
2783
2784 SH_MUTEX_LOCK_UNSAFE(mutex_hash);
2785 for (i = 0; i < TABSIZE; ++i)
2786 {
2787 for (p = tab[i]; p; p = p->next)
2788 CLEAR_SH_FFLAG_ALLIGNORE(p->fflags);
2789 }
2790 SH_MUTEX_UNLOCK_UNSAFE(mutex_hash);
2791 SL_RETURN (0, _("hash_full_tree"));
2792}
2793
2794#if !defined(SH_CUTEST)
2795static
2796#endif
2797int hash_remove_tree_test(char * s, char * fullpath, size_t len_s)
2798{
2799 size_t len_p;
2800 char * test;
2801
2802 len_p = strlen(fullpath);
2803
2804 if (len_p >= len_s)
2805 {
2806 if (0 == strncmp(s, fullpath, len_s))
2807 {
2808 if (len_p > len_s)
2809 {
2810 /* continue if not inside directory;
2811 * len_s > 1 because everything is inside '/'
2812 */
2813 if ((len_s > 1) && (fullpath[len_s] != '/'))
2814 return S_FALSE;
2815
2816 test = sh_files_find_mostspecific_dir(fullpath);
2817
2818 if (test && 0 != strcmp(test, s)) {
2819 /* There is a more specific directory, continue */
2820 return S_FALSE;
2821 }
2822
2823 if (NULL == sh_files_findfile(fullpath)) {
2824 /* SET_SH_FFLAG_ALLIGNORE(p->fflags); */
2825 return S_TRUE;
2826 }
2827 }
2828 else /* len_p == len */
2829 {
2830 /* it is 's' itself, mark and continue
2831 * unless there is a policy for the inode itself
2832 */
2833 if (NULL == sh_files_findfile(fullpath)) {
2834 /* SET_SH_FFLAG_ALLIGNORE(p->fflags); */
2835 return S_TRUE;
2836 }
2837 else {
2838 return S_FALSE;
2839 }
2840 }
2841
2842 } /* if path is in tree */
2843 } /* if path is possibly in tree */
2844 return S_FALSE;
2845}
2846
2847
2848int hash_remove_tree (char * s)
2849{
2850 sh_file_t * p;
2851 size_t len_s;
2852 unsigned int i;
2853
2854 SL_ENTER(_("hash_remove_tree"));
2855
2856 if (!s || *s == '\0')
2857 SL_RETURN ((-1), _("hash_remove_tree"));
2858
2859 len_s = sl_strlen(s);
2860
2861 if (IsInit != 1)
2862 sh_hash_init();
2863
2864 SH_MUTEX_LOCK_UNSAFE(mutex_hash);
2865 for (i = 0; i < TABSIZE; ++i)
2866 {
2867 for (p = tab[i]; p; p = p->next)
2868 {
2869 if (p->fullpath)
2870 {
2871 /* if (0 == strncmp(s, p->fullpath, len_s)) *//* old */
2872 if (S_TRUE == hash_remove_tree_test(s, p->fullpath, len_s)) {
2873 SET_SH_FFLAG_ALLIGNORE(p->fflags);
2874 MODI_SET(p->theFile.checkflags, MODI_ALLIGNORE);
2875 }
2876 } /* if path is not null */
2877
2878 }
2879 }
2880 SH_MUTEX_UNLOCK_UNSAFE(mutex_hash);
2881 SL_RETURN ((0), _("hash_remove_tree"));
2882}
2883
2884#if TIME_WITH_SYS_TIME
2885#include <sys/time.h>
2886#include <time.h>
2887#else
2888#if HAVE_SYS_TIME_H
2889#include <sys/time.h>
2890#else
2891#include <time.h>
2892#endif
2893#endif
2894
2895static int ListFullDetail = S_FALSE;
2896static int ListWithDelimiter = S_FALSE;
2897static char * ListFile = NULL;
2898
2899int set_list_file (const char * c)
2900{
2901 ListFile = sh_util_strdup(c);
2902 return 0;
2903}
2904char * get_list_file()
2905{
2906 return ListFile;
2907}
2908
2909int set_full_detail (const char * c)
2910{
2911 (void) c;
2912 ListFullDetail = S_TRUE;
2913 return 0;
2914}
2915
2916int set_list_delimited (const char * c)
2917{
2918 (void) c;
2919 ListFullDetail = S_TRUE;
2920 ListWithDelimiter = S_TRUE;
2921 return 0;
2922}
2923
2924/* Always quote the string, except if it is empty. Quote quotes by
2925 * doubling them.
2926 */
2927char * csv_escape(const char * str)
2928{
2929 const char * p = str;
2930 const char * q;
2931
2932 size_t size = 0;
2933 size_t flag_quote = 0;
2934
2935 char * new;
2936 char * pnew;
2937
2938 if (p)
2939 {
2940
2941 while (*p)
2942 {
2943 if (*p == '"')
2944 ++flag_quote;
2945
2946 ++size; ++p;
2947 }
2948
2949 if (sl_ok_adds(size, flag_quote))
2950 size += flag_quote; /* double each quote */
2951 else
2952 return NULL;
2953
2954 if (sl_ok_adds(size, 3))
2955 size += 3; /* two quotes and terminating null */
2956 else
2957 return NULL;
2958
2959 new = SH_ALLOC(size);
2960
2961 if (flag_quote != 0)
2962 {
2963 new[0] = '"';
2964 pnew = &new[1];
2965 q = str;
2966 while (*q)
2967 {
2968 *pnew = *q;
2969 if (*pnew == '"')
2970 {
2971 ++pnew; *pnew = '"';
2972 }
2973 ++pnew; ++q;
2974 }
2975 *pnew = '"'; ++pnew;
2976 *pnew = '\0';
2977 }
2978 else
2979 {
2980 if (size > 3)
2981 {
2982 new[0] = '"';
2983 sl_strlcpy (&new[1], str, size-1);
2984 new[size-2] = '"';
2985 new[size-1] = '\0';
2986 }
2987 else
2988 {
2989 new[0] = '\0';
2990 }
2991 }
2992
2993 return new;
2994 }
2995 return NULL;
2996}
2997
2998int isHexKey(char * s)
2999{
3000 int i;
3001
3002 for (i = 0; i < KEY_LEN; ++i)
3003 {
3004 if (*s)
3005 {
3006 if ((*s >= '0' && *s <= '9') ||
3007 (*s >= 'A' && *s <= 'F') ||
3008 (*s >= 'a' && *s <= 'f'))
3009 {
3010 ++s;
3011 continue;
3012 }
3013 }
3014 return S_FALSE;
3015 }
3016 return S_TRUE;
3017}
3018
3019#include "sh_checksum.h"
3020
3021static char * KEYBUFtolower (char * s, char * result)
3022{
3023 char * r = result;
3024 if (s)
3025 {
3026 for (; *s; ++s)
3027 {
3028 *r = tolower((unsigned char) *s); ++r;
3029 }
3030 *r = '\0';
3031 }
3032 return result;
3033}
3034
3035void sh_hash_list_db_entry_full_detail (sh_file_t * p)
3036{
3037 char * tmp;
3038 char * esc;
3039 char str[81];
3040 char hexdigest[SHA256_DIGEST_STRING_LENGTH];
3041 char keybuffer[KEYBUF_SIZE];
3042
3043 if (ListWithDelimiter == S_TRUE)
3044 {
3045 printf(_("%7ld, %7ld, %10s, %5d, %12s, %5d, %3d, %-8s, %5d, %-8s, %5d, "),
3046 (unsigned long) p->theFile.ino, (unsigned long) p->theFile.dev,
3047 p->theFile.c_mode, (int) p->theFile.mode,
3048 p->theFile.c_attributes, (int) p->theFile.attributes,
3049 (int) p->theFile.hardlinks,
3050 p->theFile.c_owner, (int) p->theFile.owner,
3051 p->theFile.c_group, (int) p->theFile.group);
3052 }
3053 else
3054 {
3055 printf(_("%7ld %7ld %10s %5d %12s %5d %3d %-8s %5d %-8s %5d "),
3056 (unsigned long) p->theFile.ino, (unsigned long) p->theFile.dev,
3057 p->theFile.c_mode, (int) p->theFile.mode,
3058 p->theFile.c_attributes, (int) p->theFile.attributes,
3059 (int) p->theFile.hardlinks,
3060 p->theFile.c_owner, (int) p->theFile.owner,
3061 p->theFile.c_group, (int) p->theFile.group);
3062 }
3063
3064 if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0])
3065 sl_snprintf(str, sizeof(str), "%"PRIu64, p->theFile.rdev);
3066 else
3067 sl_snprintf(str, sizeof(str), "%"PRIu64, p->theFile.size);
3068
3069 printf( _(" %8s"), str);
3070 if (ListWithDelimiter == S_TRUE)
3071 putchar(',');
3072
3073 printf( _(" %s"), sh_unix_gmttime (p->theFile.ctime, str, sizeof(str)));
3074 if (ListWithDelimiter == S_TRUE)
3075 putchar(',');
3076 printf( _(" %s"), sh_unix_gmttime (p->theFile.mtime, str, sizeof(str)));
3077 if (ListWithDelimiter == S_TRUE)
3078 putchar(',');
3079 printf( _(" %s"), sh_unix_gmttime (p->theFile.atime, str, sizeof(str)));
3080 if (ListWithDelimiter == S_TRUE)
3081 putchar(',');
3082
3083 if (isHexKey(p->theFile.checksum))
3084 printf( _(" %s"), KEYBUFtolower(p->theFile.checksum, keybuffer));
3085 else
3086 printf( _(" %s"), SHA256_Base2Hex(p->theFile.checksum, hexdigest));
3087 if (ListWithDelimiter == S_TRUE)
3088 putchar(',');
3089
3090 tmp = sh_util_safe_name(p->fullpath);
3091 if (ListWithDelimiter != S_TRUE)
3092 {
3093 printf( _(" %s"), tmp);
3094 }
3095 else
3096 {
3097 esc = csv_escape(tmp);
3098 printf( _(" %s,"), (esc != NULL) ? esc : _("(null)"));
3099 if (esc)
3100 SH_FREE(esc);
3101 }
3102 SH_FREE(tmp);
3103
3104 if ('l' == p->theFile.c_mode[0])
3105 {
3106 tmp = sh_util_safe_name(p->linkpath);
3107 if (ListWithDelimiter != S_TRUE)
3108 {
3109 printf(_(" -> %s"), tmp);
3110 }
3111 else
3112 {
3113 esc = csv_escape(tmp);
3114 printf( _(" %s,"), (esc != NULL) ? esc : _("(null)"));
3115 if (esc)
3116 SH_FREE(esc);
3117 }
3118 SH_FREE(tmp);
3119 }
3120
3121 if (p->attr_string)
3122 {
3123 tmp = sh_util_safe_name(p->attr_string);
3124 if (ListWithDelimiter != S_TRUE)
3125 {
3126 printf(_(" %s"), tmp);
3127 }
3128 else
3129 {
3130 esc = csv_escape(tmp);
3131 printf( _(" %s"), (esc != NULL) ? esc : _("(null)"));
3132 if (esc)
3133 SH_FREE(esc);
3134 }
3135 SH_FREE(tmp);
3136 }
3137 else
3138 {
3139 if (ListWithDelimiter == S_TRUE)
3140 printf("%s",_(" no_attr"));
3141 }
3142 putchar('\n');
3143
3144 return;
3145}
3146
3147void sh_hash_list_db_entry (sh_file_t * p)
3148{
3149 char nowtime[128];
3150 char thetime[128];
3151 char * tmp;
3152 time_t now = time(NULL);
3153 time_t then = (time_t) p->theFile.mtime;
3154 struct tm * time_ptr;
3155
3156#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
3157 struct tm time_tm;
3158#endif
3159
3160 if (ListFullDetail != S_FALSE)
3161 {
3162 sh_hash_list_db_entry_full_detail (p);
3163 return;
3164 }
3165
3166#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
3167 time_ptr = gmtime_r(&then, &time_tm);
3168 if (!time_ptr)
3169 return;
3170 strftime(thetime, 127, _("%b %d %Y"), time_ptr);
3171 time_ptr = gmtime_r(&now, &time_tm);
3172 if (!time_ptr)
3173 return;
3174 strftime(nowtime, 127, _("%b %d %Y"), time_ptr);
3175 if (0 == strncmp(&nowtime[7], &thetime[7], 4))
3176 {
3177 time_ptr = gmtime_r(&then, &time_tm);
3178 if (!time_ptr)
3179 return;
3180 strftime(thetime, 127, _("%b %d %H:%M"), time_ptr);
3181 }
3182#else
3183 time_ptr = gmtime(&then);
3184 if (!time_ptr)
3185 return;
3186 strftime(thetime, 127, _("%b %d %Y"), time_ptr);
3187 time_ptr = gmtime(&now);
3188 if (!time_ptr)
3189 return;
3190 strftime(nowtime, 127, _("%b %d %Y"), time_ptr);
3191 if (0 == strncmp(&nowtime[7], &thetime[7], 4))
3192 {
3193 time_ptr = gmtime(&then);
3194 if (!time_ptr)
3195 return;
3196 strftime(thetime, 127, _("%b %d %H:%M"), time_ptr);
3197 }
3198#endif
3199
3200 tmp = sh_util_safe_name(p->fullpath);
3201 if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0])
3202 printf(_("%10s %3d %-8s %-8s %3d,%4d %s %s"),
3203 p->theFile.c_mode, (int) p->theFile.hardlinks,
3204 p->theFile.c_owner, p->theFile.c_group,
3205 (int) major((dev_t)p->theFile.rdev),
3206 (int) minor((dev_t)p->theFile.rdev),
3207 thetime,
3208 tmp);
3209 else
3210 printf(_("%10s %3d %-8s %-8s %8ld %s %s"),
3211 p->theFile.c_mode, (int) p->theFile.hardlinks,
3212 p->theFile.c_owner, p->theFile.c_group, (long) p->theFile.size,
3213 thetime,
3214 tmp);
3215 SH_FREE(tmp);
3216
3217 if ('l' == p->theFile.c_mode[0])
3218 {
3219 tmp = sh_util_safe_name(p->linkpath);
3220 printf(_(" -> %s\n"), tmp);
3221 SH_FREE(tmp);
3222 }
3223 else
3224 printf("\n");
3225
3226 return;
3227}
3228
3229#ifdef HAVE_LIBZ
3230#include <zlib.h>
3231#endif
3232
3233int sh_hash_printcontent(char * linkpath)
3234{
3235#ifdef HAVE_LIBZ
3236 unsigned char * decoded;
3237 unsigned char * decompressed = NULL;
3238 size_t dlen;
3239 unsigned long clen;
3240 unsigned long clen_o;
3241 int res;
3242
3243 if (linkpath && *linkpath != '-')
3244 {
3245 dlen = sh_util_base64_dec_alloc (&decoded,
3246 (unsigned char *)linkpath,
3247 strlen(linkpath));
3248
3249 clen = dlen * 2 + 1;
3250
3251 do {
3252 if (decompressed)
3253 SH_FREE(decompressed);
3254 clen += dlen; clen_o = clen;
3255 decompressed = SH_ALLOC(clen);
3256 res = uncompress(decompressed, &clen, decoded, dlen);
3257 if (res == Z_MEM_ERROR)
3258 { fprintf(stderr, "%s",_("Error: Not enough memory\n")); return -1; }
3259 if (res == Z_DATA_ERROR)
3260 { fprintf(stderr, "%s",_("Error: Data corrupt or incomplete\n")); return -1; }
3261 } while (res == Z_BUF_ERROR || clen == clen_o);
3262
3263 decompressed[clen] = '\0';
3264 fputs( (char*) decompressed, stdout);
3265 SH_FREE(decompressed);
3266 return 0;
3267 }
3268#else
3269 (void) linkpath;
3270#endif
3271 fprintf(stderr, "%s",_("Error: No data available\n"));
3272 return -1;
3273}
3274
3275/* if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
3276#endif
Note: See TracBrowser for help on using the repository browser.