source: trunk/src/sh_hash.c@ 460

Last change on this file since 460 was 458, checked in by katerina, 10 years ago

Fix for ticket #358 (repetitive lstat warning) and #359 (reporting of added/deleted top level directories).

File size: 105.9 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/* define this if you want version 1.3 style database file */
23/* #define OLD_BUG */
24
25/* make sure state changes of a file are always reported, even
26 * with reportonlyonce=true
27 */
28/* #define REPLACE_OLD *//* moved to samhain.h */
29
30#include <stdlib.h>
31#include <string.h>
32#include <stdio.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <unistd.h>
36#include <ctype.h>
37
38#ifdef MAJOR_IN_MKDEV
39#include <sys/mkdev.h>
40#else
41#ifdef MAJOR_IN_SYSMACROS
42#include <sys/sysmacros.h>
43#endif
44#endif
45
46#ifdef HAVE_MEMORY_H
47#include <memory.h>
48#endif
49
50#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
51
52#include "sh_hash.h"
53#include "sh_utils.h"
54#include "sh_error.h"
55#include "sh_tiger.h"
56#include "sh_gpg.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_forward.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_STATIC(mutex_hash,PTHREAD_MUTEX_INITIALIZER);
74
75const char notalink[2] = { '-', '\0' };
76
77static char * all_items (file_type * theFile, char * fileHash, int is_new);
78
79#define QUOTE_CHAR '='
80
81char * unquote_string (const char * str, size_t len)
82{
83 int i = 0, t1, t2;
84 char * tmp = NULL;
85 size_t l2, j, k = 0;
86
87 SL_ENTER(_("unquote_string"));
88
89 if (str != NULL)
90 {
91 l2 = len - 2;
92 tmp = SH_ALLOC(len + 1);
93
94 for (j = 0; j <= len; ++j)
95 {
96 if (str[j] != QUOTE_CHAR)
97 {
98 tmp[k] = str[j];
99 }
100 else if (str[j] == QUOTE_CHAR && j < l2)
101 {
102 t1 = sh_util_hexchar(str[j+1]);
103 t2 = sh_util_hexchar(str[j+2]);
104 if ((t1|t2) >= 0)
105 {
106 i = 16 * t1 + t2;
107 tmp[k] = i;
108 j += 2;
109 }
110 else
111 {
112 tmp[k] = str[j];
113 }
114 }
115 else
116 tmp[k] = str[j];
117 ++k;
118 }
119 }
120 SL_RETURN(tmp, _("unquote_string"));
121}
122
123
124static char * int2hex (unsigned char i, char * i2h)
125{
126 static char hexchars[] = "0123456789ABCDEF";
127
128 i2h[0] = hexchars[(((i) & 0xF0) >> 4)]; /* high */
129 i2h[1] = hexchars[((i) & 0x0F)]; /* low */
130
131 return i2h;
132}
133
134
135char * quote_string (const char * str, size_t len)
136{
137 char * tmp;
138 char * tmp2;
139 size_t l2, j, i = 0, k = 0;
140 char i2h[2];
141
142 SL_ENTER(_("quote_string"));
143
144 if (str == NULL)
145 {
146 SL_RETURN(NULL, _("quote_string"));
147 }
148
149 for (j = 0; j < len; ++j)
150 if (str[j] == '\n' || str[j] == QUOTE_CHAR) ++i;
151
152 l2 = len + 1;
153 if (sl_ok_muls(3, i) && sl_ok_adds(l2, (3*i)))
154 {
155 tmp = SH_ALLOC(len + 1 + 3*i);
156 }
157 else
158 {
159 sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
160 _("integer overflow"),
161 _("quote_string"));
162 SL_RETURN(NULL, _("quote_string"));
163 }
164
165 for (j = 0; j <= len; ++j)
166 {
167 if (str[j] == '\n')
168 {
169 tmp2 = int2hex((unsigned char) '\n', i2h); /* was 'n', fixed in 1.5.4 */
170 tmp[k] = QUOTE_CHAR; ++k;
171 tmp[k] = tmp2[0]; ++k;
172 tmp[k] = tmp2[1];
173 }
174 else if (str[j] == QUOTE_CHAR)
175 {
176 tmp2 = int2hex((unsigned char) QUOTE_CHAR, i2h);
177 tmp[k] = QUOTE_CHAR; ++k;
178 tmp[k] = tmp2[0]; ++k;
179 tmp[k] = tmp2[1];
180 }
181 else
182 {
183 tmp[k] = str[j];
184 }
185 ++k;
186 }
187 SL_RETURN(tmp, _("quote_string"));
188}
189
190static UINT32 * swap_32 (UINT32 * iptr)
191{
192#ifdef WORDS_BIGENDIAN
193 unsigned char swap;
194 unsigned char * ii = (unsigned char *) iptr;
195 swap = ii[0]; ii[0] = ii[3]; ii[3] = swap;
196 swap = ii[1]; ii[1] = ii[2]; ii[2] = swap;
197 return iptr;
198#else
199 return iptr;
200#endif
201}
202
203static UINT64 * swap_64 (UINT64 * iptr)
204{
205#ifdef WORDS_BIGENDIAN
206#ifdef UINT64_IS_32
207 swap_32 ((UINT32*) iptr);
208#else
209 unsigned char swap;
210 unsigned char * ii = (unsigned char *) iptr;
211 swap = ii[0]; ii[0] = ii[7]; ii[7] = swap;
212 swap = ii[1]; ii[1] = ii[6]; ii[6] = swap;
213 swap = ii[2]; ii[2] = ii[5]; ii[5] = swap;
214 swap = ii[3]; ii[3] = ii[4]; ii[4] = swap;
215#endif
216 return iptr;
217#else
218 return iptr;
219#endif
220}
221
222static unsigned short * swap_short (unsigned short * iptr)
223{
224#ifdef WORDS_BIGENDIAN
225 if (sizeof(short) == 4)
226 swap_32 ((UINT32*) iptr);
227 else
228 {
229 /* alignment problem */
230 unsigned char swap;
231 static unsigned short ooop;
232 unsigned char * ii;
233 ooop = *iptr;
234 ii = (unsigned char *) &ooop;
235 /* printf("SWAP0: %hd %d\n", *iptr, sizeof(unsigned short)); */
236 swap = ii[0]; ii[0] = ii[1]; ii[1] = swap;
237 /* printf("SWAP1: %hd\n", (unsigned short) ooop); */
238#ifndef OLD_BUG
239 return &ooop;
240#endif
241 }
242 return iptr;
243#else
244 return iptr;
245#endif
246}
247
248
249typedef struct store_info {
250
251 UINT32 mode;
252 UINT32 linkmode;
253
254 UINT64 dev;
255 UINT64 rdev;
256 UINT32 hardlinks;
257 UINT32 ino;
258 UINT64 size;
259 UINT64 atime;
260 UINT64 mtime;
261 UINT64 ctime;
262 UINT32 owner;
263 UINT32 group;
264
265#ifdef OLD_BUG
266#if defined(__linux__)
267 UINT32 attributes;
268 char c_attributes[ATTRBUF_SIZE];
269#endif
270#else
271 /* #if defined(__linux__) */
272 UINT32 attributes;
273 char c_attributes[ATTRBUF_SIZE];
274 /* endif */
275#endif
276 unsigned short mark;
277 char c_owner[USER_MAX+2];
278 char c_group[GROUP_MAX+2];
279 char c_mode[CMODE_SIZE];
280 char checksum[KEY_LEN+1];
281} sh_filestore_t;
282
283typedef struct file_info {
284 sh_filestore_t theFile;
285 char * fullpath;
286 char * linkpath;
287 char * attr_string;
288 int fflags;
289 unsigned long modi_mask;
290 struct file_info * next;
291} sh_file_t;
292
293 static const char *policy[] = {
294 N_("[]"),
295 N_("[ReadOnly]"),
296 N_("[LogFiles]"),
297 N_("[GrowingLogs]"),
298 N_("[IgnoreNone]"),
299 N_("[IgnoreAll]"),
300 N_("[Attributes]"),
301 N_("[User0]"),
302 N_("[User1]"),
303 N_("[User2]"),
304 N_("[User3]"),
305 N_("[User4]"),
306 N_("[Prelink]"),
307 NULL
308 };
309
310const char * sh_hash_getpolicy(int class)
311{
312 if (class > 0 && class < SH_ERR_T_DIR)
313 return _(policy[class]);
314 return _("[indef]");
315}
316
317/**********************************
318 *
319 * hash table functions
320 *
321 **********************************
322 */
323
324#include "sh_hash.h"
325
326/* must fit an int */
327/* #define TABSIZE 2048 */
328#define TABSIZE 65536
329
330/* must fit an unsigned short */
331/* changed for V0.8, as the */
332/* database format has changed */
333
334/* changed again for V0.9 */
335/* #define REC_MAGIC 19 */
336/* changed again for V1.3 */
337#ifdef OLD_BUG
338#define REC_MAGIC 20
339#else
340/* changed again for V1.4 */
341#define REC_MAGIC 21
342#endif
343
344#define REC_FLAGS_ATTR (1<<8)
345#define REC_FLAGS_MASK 0xFF00
346
347/**************************************************************
348 *
349 * create a file_type from a sh_file_t
350 *
351 **************************************************************/
352static file_type * sh_hash_create_ft (const sh_file_t * p, char * fileHash)
353{
354 file_type * theFile;
355
356 SL_ENTER(_("sh_hash_create_ft"));
357
358 theFile = SH_ALLOC(sizeof(file_type));
359
360 sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11);
361 theFile->mode = p->theFile.mode;
362#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
363 sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, ATTRBUF_SIZE);
364 theFile->attributes = p->theFile.attributes;
365#endif
366
367 sl_strlcpy(theFile->fullpath, p->fullpath, PATH_MAX);
368 if (p->linkpath != NULL /* && theFile->c_mode[0] == 'l' */)
369 {
370 theFile->link_path = sh_util_strdup(p->linkpath);
371 }
372 else
373 {
374 theFile->link_path = NULL;
375 }
376 sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
377
378 theFile->mtime = p->theFile.mtime;
379 theFile->ctime = p->theFile.ctime;
380 theFile->atime = p->theFile.atime;
381
382 theFile->size = p->theFile.size;
383
384 sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2);
385 theFile->group = p->theFile.group;
386 sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2);
387 theFile->owner = p->theFile.owner;
388
389 theFile->ino = p->theFile.ino;
390 theFile->rdev = p->theFile.rdev;
391 theFile->dev = p->theFile.dev;
392 theFile->hardlinks = p->theFile.hardlinks;
393
394 if (p->attr_string)
395 theFile->attr_string = sh_util_strdup(p->attr_string);
396 else
397 theFile->attr_string = NULL;
398
399 SL_RETURN((theFile), _("sh_hash_create_ft"));
400}
401
402struct two_sh_file_t {
403 sh_file_t * prev;
404 sh_file_t * this;
405};
406
407static sh_file_t * hashsearch (const char * s);
408static int hashsearch_prev (const char * s, struct two_sh_file_t * a, int * index);
409
410static sh_file_t * tab[TABSIZE];
411
412/**************************************************************
413 *
414 * compute hash function
415 *
416 **************************************************************/
417
418static int hashfunc(const char *s)
419{
420 unsigned int n = 0;
421
422 for ( ; *s; s++)
423 n = 31 * n + *s;
424
425 return n & (TABSIZE - 1); /* % TABSIZE */;
426}
427
428
429int hashreport_missing( char *fullpath, int level)
430{
431 sh_file_t * p;
432 char * tmp;
433 char fileHash[KEY_LEN + 1];
434 file_type * theFile;
435 char * str;
436 char hashbuf[KEYBUF_SIZE];
437 volatile int retval;
438
439 /* -------- find the entry for the file ---------------- */
440
441 SH_MUTEX_LOCK(mutex_hash);
442
443 retval = 0;
444
445 if (sl_strlen(fullpath) <= MAX_PATH_STORE)
446 p = hashsearch(fullpath);
447 else
448 p = hashsearch( sh_tiger_hash(fullpath,
449 TIGER_DATA,
450 sl_strlen(fullpath),
451 hashbuf, sizeof(hashbuf))
452 );
453 if (p == NULL)
454 {
455 retval = -1;
456 goto unlock_and_return;
457 }
458
459 theFile = sh_hash_create_ft (p, fileHash);
460 str = all_items(theFile, fileHash, 0);
461 tmp = sh_util_safe_name(fullpath);
462
463 SH_MUTEX_LOCK(mutex_thread_nolog);
464 sh_error_handle (level, FIL__, __LINE__, 0,
465 MSG_FI_MISS2, tmp, str);
466 SH_MUTEX_UNLOCK(mutex_thread_nolog);
467 ++sh.statistics.files_report;
468
469 SH_FREE(tmp);
470 SH_FREE(str);
471 if (theFile->attr_string) SH_FREE(theFile->attr_string);
472 if (theFile->link_path) SH_FREE(theFile->link_path);
473 SH_FREE(theFile);
474
475 unlock_and_return:
476 ; /* 'label at end of compound statement */
477 SH_MUTEX_UNLOCK(mutex_hash);
478
479 /* remove here to avoid second message from hash_unvisited */
480 if (retval == 0)
481 sh_hash_remove (fullpath);
482
483 return retval;
484}
485
486
487/**************************************************************
488 *
489 * search for files not visited, and check whether they exist
490 *
491 **************************************************************/
492static sh_file_t * delete_db_entry(sh_file_t *p)
493{
494 if (p->fullpath)
495 {
496 SH_FREE(p->fullpath);
497 p->fullpath = NULL;
498 }
499 if (p->linkpath)
500 {
501 if (p->linkpath != notalink)
502 SH_FREE(p->linkpath);
503 p->linkpath = NULL;
504 }
505 if (p->attr_string)
506 {
507 SH_FREE(p->attr_string);
508 p->attr_string = NULL;
509 }
510 SH_FREE(p);
511 return NULL;
512}
513
514static void hash_unvisited (int j,
515 sh_file_t *prev, sh_file_t *p, ShErrLevel level)
516{
517 struct stat buf;
518 int i;
519 char * tmp;
520 char * ptr;
521 char fileHash[KEY_LEN + 1];
522 file_type * theFile;
523
524 char * str;
525
526
527 SL_ENTER(_("hash_unvisited"));
528
529 if (p->next != NULL)
530 hash_unvisited (j, p, p->next, level);
531
532 if (p->fullpath == NULL)
533 {
534 SL_RET0(_("hash_unvisited"));
535 }
536
537 /* Not a fully qualified path, i.e. some info stored by some module
538 */
539 if (p->fullpath[0] != '/')
540 {
541 SL_RET0(_("hash_unvisited"));
542 }
543
544 /* visited flag not set: not seen;
545 * checked flag set: not seen (i.e. missing), and already checked
546 * reported flag not set: not reported yet
547 * allignore flag not set: not under IgnoreAll
548 *
549 * Files/directories under IgnoreAll are noticed as missing already
550 * during the file check.
551 */
552 if (((!SH_FFLAG_VISITED_SET(p->fflags)) || SH_FFLAG_CHECKED_SET(p->fflags))
553 && (!SH_FFLAG_REPORTED_SET(p->fflags))
554 && (!SH_FFLAG_ALLIGNORE_SET(p->fflags)))
555 {
556 i = retry_lstat(FIL__, __LINE__, p->fullpath, &buf);
557
558 /* if file does not exist
559 */
560 if (0 != i)
561 {
562 ptr = sh_util_dirname (p->fullpath);
563 if (ptr)
564 {
565 /* If any of the parent directories is under IgnoreAll
566 */
567 if (0 != sh_files_is_allignore(ptr))
568 level = ShDFLevel[SH_LEVEL_ALLIGNORE];
569 SH_FREE(ptr);
570 }
571
572 /* Only report if !SH_FFLAG_CHECKED_SET
573 */
574 if (!SH_FFLAG_CHECKED_SET(p->fflags))
575 {
576 if (S_FALSE == sh_ignore_chk_del(p->fullpath))
577 {
578 tmp = sh_util_safe_name(p->fullpath);
579
580 theFile = sh_hash_create_ft (p, fileHash);
581 str = all_items(theFile, fileHash, 0);
582 sh_error_handle (level, FIL__, __LINE__, 0,
583 MSG_FI_MISS2, tmp, str);
584 ++sh.statistics.files_report;
585 SH_FREE(str);
586 if (theFile->attr_string) SH_FREE(theFile->attr_string);
587 if (theFile->link_path) SH_FREE(theFile->link_path);
588 SH_FREE(theFile);
589
590 SH_FREE(tmp);
591 }
592 }
593
594 /* We rewrite the db on update, thus we need to keep this
595 * if the user does not want to purge it from the db.
596 */
597
598 if ((sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) ||
599 (S_TRUE == sh.flag.update && S_TRUE == sh_util_ask_update(p->fullpath)))
600 {
601#ifdef REPLACE_OLD
602 /* Remove the old entry
603 */
604 if (prev == p)
605 tab[j] = p->next;
606 else
607 prev->next = p->next;
608
609 delete_db_entry(p);
610
611 SL_RET0(_("hash_unvisited"));
612#else
613 SET_SH_FFLAG_REPORTED(p->fflags);
614#endif
615 }
616 }
617 }
618
619 else if (SH_FFLAG_VISITED_SET(p->fflags) && SH_FFLAG_REPORTED_SET(p->fflags)
620 && (!SH_FFLAG_ALLIGNORE_SET(p->fflags)))
621 {
622 if (S_FALSE == sh_ignore_chk_new(p->fullpath))
623 {
624 tmp = sh_util_safe_name(p->fullpath);
625
626 theFile = sh_hash_create_ft (p, fileHash);
627 str = all_items(theFile, fileHash, 0);
628 sh_error_handle (level, FIL__, __LINE__, 0,
629 MSG_FI_MISS2, tmp, str);
630 ++sh.statistics.files_report;
631 SH_FREE(str);
632 if (theFile->attr_string)
633 SH_FREE(theFile->attr_string);
634 SH_FREE(theFile);
635
636 SH_FREE(tmp);
637 }
638
639 CLEAR_SH_FFLAG_REPORTED(p->fflags);
640 }
641
642 if (sh.flag.reportonce == S_FALSE)
643 CLEAR_SH_FFLAG_REPORTED(p->fflags);
644
645 CLEAR_SH_FFLAG_VISITED(p->fflags);
646 CLEAR_SH_FFLAG_CHECKED(p->fflags);
647 SET_SH_FFLAG_ENOENT(p->fflags);
648
649 SL_RET0(_("hash_unvisited"));
650}
651
652
653
654/*********************************************************************
655 *
656 * Search for files in the database that have been deleted from disk.
657 *
658 *********************************************************************/
659void sh_hash_unvisited (ShErrLevel level)
660{
661 int i;
662
663 SL_ENTER(_("sh_hash_unvisited"));
664
665 SH_MUTEX_LOCK(mutex_hash);
666 for (i = 0; i < TABSIZE; ++i)
667 {
668 if (tab[i] != NULL)
669 hash_unvisited (i, tab[i], tab[i], level);
670 }
671 SH_MUTEX_UNLOCK(mutex_hash);
672
673 SL_RET0(_("hash_unvisited"));
674}
675
676/*********************************************************************
677 *
678 * Remove a single file from the database.
679 *
680 *********************************************************************/
681void sh_hash_remove (const char * path)
682{
683 struct two_sh_file_t entries;
684 int index;
685
686 SL_ENTER(_("sh_hash_remove"));
687
688 SH_MUTEX_LOCK(mutex_hash);
689
690 if ((sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) ||
691 (S_TRUE == sh.flag.update && S_TRUE == sh_util_ask_update(path)))
692 {
693 if (0 == hashsearch_prev (path, &entries, &index))
694 {
695 sh_file_t * p = entries.this;
696#ifdef REPLACE_OLD
697 /* Remove the old entry
698 */
699 if (entries.prev == p)
700 tab[index] = p->next;
701 else
702 entries.prev->next = p->next;
703
704 delete_db_entry(p);
705
706 goto end;
707#else
708 SET_SH_FFLAG_REPORTED(p->fflags);
709#endif
710 }
711 }
712
713 end:
714 ; /* 'label at end of compound statement' */
715 SH_MUTEX_UNLOCK(mutex_hash);
716
717 SL_RET0(_("sh_hash_remove"));
718}
719
720
721/*********************************************************************
722 *
723 * Search for unvisited entries in the database, custom error handler.
724 *
725 *********************************************************************/
726void sh_hash_unvisited_custom (char prefix, void(*handler)(const char * key))
727{
728 int i;
729 sh_file_t *p = NULL;
730 sh_file_t *prev = NULL;
731 sh_file_t *next = NULL;
732
733 SL_ENTER(_("sh_hash_unvisited_custom"));
734
735 SH_MUTEX_LOCK(mutex_hash);
736 for (i = 0; i < TABSIZE; ++i)
737 {
738 if (tab[i] != NULL)
739 {
740 p = tab[i]; prev = p;
741
742 do
743 {
744 next = p->next;
745
746 if (p->fullpath &&
747 prefix == p->fullpath[0])
748 {
749 if ((!SH_FFLAG_VISITED_SET(p->fflags))
750 && (!SH_FFLAG_REPORTED_SET(p->fflags)))
751 {
752 handler(p->fullpath);
753
754 if (!SH_FFLAG_CHECKED_SET(p->fflags))
755 {
756 /* delete */
757 if (tab[i] == p)
758 {
759 tab[i] = p->next;
760 prev = tab[i];
761 next = prev;
762 }
763 else
764 {
765 prev->next = p->next;
766 next = prev->next;
767 }
768
769 p = delete_db_entry(p);
770 }
771 }
772 if (p)
773 {
774 CLEAR_SH_FFLAG_VISITED(p->fflags);
775 CLEAR_SH_FFLAG_CHECKED(p->fflags);
776 }
777 }
778 if (p)
779 prev = p;
780 p = next;
781 }
782 while (p);
783 }
784 }
785 SH_MUTEX_UNLOCK(mutex_hash);
786
787 SL_RET0(_("hash_unvisited_custom"));
788}
789
790
791/**********************************************************************
792 *
793 * delete hash array
794 *
795 **********************************************************************/
796static void hash_kill (sh_file_t *p)
797{
798 SL_ENTER(_("hash_kill"));
799
800 if (p == NULL)
801 SL_RET0(_("hash_kill"));
802
803 if (p->next != NULL)
804 hash_kill (p->next);
805
806 if (p->fullpath)
807 {
808 SH_FREE(p->fullpath);
809 p->fullpath = NULL;
810 }
811 if (p->linkpath)
812 {
813 if (p->linkpath != notalink)
814 SH_FREE(p->linkpath);
815 p->linkpath = NULL;
816 }
817 if (p->attr_string)
818 {
819 SH_FREE(p->attr_string);
820 p->attr_string = NULL;
821 }
822 SH_FREE(p);
823 p = NULL;
824 SL_RET0(_("hash_kill"));
825}
826
827
828/***********************************************************************
829 *
830 * get info out of hash array
831 *
832 ***********************************************************************/
833static sh_file_t * hashsearch (const char * s)
834{
835 sh_file_t * p;
836
837 SL_ENTER(_("hashsearch"));
838
839 if (s)
840 {
841 for (p = tab[hashfunc(s)]; p; p = p->next)
842 if ((p->fullpath != NULL) && (0 == strcmp(s, p->fullpath)))
843 SL_RETURN( p, _("hashsearch"));
844 }
845 SL_RETURN( NULL, _("hashsearch"));
846}
847
848static int hashsearch_prev (const char * s, struct two_sh_file_t * a, int * index)
849{
850 sh_file_t * this;
851 sh_file_t * prev = NULL;
852
853 SL_ENTER(_("hashsearch_prev"));
854
855 if (s)
856 {
857 *index = hashfunc(s);
858
859 this = tab[*index];
860
861 prev = this;
862
863 if (this)
864 {
865 do {
866
867 if ((this->fullpath != NULL) && (0 == strcmp(s, this->fullpath)))
868 {
869 a->prev = prev;
870 a->this = this;
871
872 SL_RETURN( 0, _("hashsearch_prev"));
873 }
874
875 prev = this;
876 this = this->next;
877
878 } while(this);
879 }
880 }
881 SL_RETURN( -1, _("hashsearch"));
882}
883
884
885/***********************************************************************
886 *
887 * insert into hash array
888 *
889 ***********************************************************************/
890static void hashinsert (sh_file_t * s)
891{
892 sh_file_t * p;
893 sh_file_t * q;
894 int key;
895
896 SL_ENTER(_("hashinsert"));
897
898 key = hashfunc(s->fullpath);
899
900 if (tab[key] == NULL)
901 {
902 tab[key] = s;
903 tab[key]->next = NULL;
904 SL_RET0(_("hashinsert"));
905 }
906 else
907 {
908 p = tab[key];
909 while (1)
910 {
911 if (p && p->fullpath &&
912 0 == strcmp(s->fullpath, p->fullpath))
913 {
914 q = p->next;
915 SH_FREE(p->fullpath);
916 if(p->linkpath && p->linkpath != notalink)
917 SH_FREE(p->linkpath);
918 if(p->attr_string)
919 SH_FREE(p->attr_string);
920 memcpy(p, s, sizeof(sh_file_t));
921 p->next = q;
922 SH_FREE(s);
923 s = NULL;
924 SL_RET0(_("hashinsert"));
925 }
926 else if (p && p->next == NULL)
927 {
928 p->next = s;
929 p->next->next = NULL;
930 SL_RET0(_("hashinsert"));
931 }
932 if (p)
933 p = p->next;
934 else /* cannot really happen, but llvm/clang does not know */
935 break;
936 }
937 }
938 /* notreached */
939}
940
941
942/******************************************************************
943 *
944 * Get a single line
945 *
946 ******************************************************************/
947static FILE * sh_fin_fd = NULL;
948
949static int sh_hash_getline (FILE * fd, char * line, int sizeofline)
950{
951 register int n = 0;
952 char * res;
953
954 if (sizeofline < 2) {
955 if (sizeofline > 0) line[0] = '\0';
956 return 0;
957 }
958 res = fgets(line, sizeofline, fd);
959 if (res == NULL)
960 {
961 line[0] = '\0';
962 return -1;
963 }
964 n = strlen(line);
965 if (n > 0) {
966 --n;
967 line[n] = '\0'; /* remove terminating '\n' */
968 }
969 return n;
970}
971
972static void sh_hash_getline_end (void)
973{
974 sl_fclose (FIL__, __LINE__, sh_fin_fd);
975 sh_fin_fd = NULL;
976 return;
977}
978
979/******************************************************************
980 *
981 * ------- Check functions -------
982 *
983 ******************************************************************/
984
985static int IsInit = 0;
986
987
988/******************************************************************
989 *
990 * Fast forward to start of data
991 *
992 ******************************************************************/
993int sh_hash_setdataent (SL_TICKET fd, char * line, int size, const char * file)
994{
995 long i;
996 extern int get_the_fd (SL_TICKET ticket);
997
998 SL_ENTER(_("sh_hash_setdataent"));
999
1000 sl_rewind (fd);
1001
1002 if (sh_fin_fd != NULL)
1003 {
1004 sl_fclose (FIL__, __LINE__, sh_fin_fd);
1005 sh_fin_fd = NULL;
1006 }
1007
1008 sh_fin_fd = fdopen(dup(get_the_fd(fd)), "rb");
1009 if (!sh_fin_fd)
1010 {
1011 dlog(1, FIL__, __LINE__,
1012 _("The file signature database: %s is not readable.\n"),
1013 (NULL == file) ? _("(null)") : file);
1014 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
1015 ( (NULL == file) ? _("(null)") : file)
1016 );
1017 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1018 }
1019
1020 while (1)
1021 {
1022 i = sh_hash_getline (sh_fin_fd, line, size);
1023 if (i < 0 )
1024 {
1025 SH_FREE(line);
1026 dlog(1, FIL__, __LINE__,
1027 _("The file signature database: %s does not\ncontain any data, or the start-of-file marker is missing (unlikely,\nunless modified by hand).\n"),
1028 (NULL == file) ? _("(null)") : file);
1029
1030 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
1031 ( (NULL == file) ? _("(null)") : file)
1032 );
1033 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1034 }
1035
1036#if defined(SH_STEALTH)
1037 if (0 == sl_strncmp (line, N_("[SOF]"), 5))
1038#else
1039 if (0 == sl_strncmp (line, _("[SOF]"), 5))
1040#endif
1041 break;
1042 }
1043 SL_RETURN( 1, _("sh_hash_setdataent"));
1044}
1045
1046static int sh_hash_setdataent_old (SL_TICKET fd, char * line, int size,
1047 char * file)
1048{
1049 long i;
1050
1051 SL_ENTER(_("sh_hash_setdataent_old"));
1052
1053 sl_rewind (fd);
1054
1055 while (1)
1056 {
1057 i = sh_unix_getline (fd, line, size-1);
1058 if (i < 0 )
1059 {
1060 SH_FREE(line);
1061 dlog(1, FIL__, __LINE__,
1062 _("The file signature database: %s does not\ncontain any data, or the start-of-file marker is missing (unlikely,\nunless modified by hand).\n"),
1063 (NULL == file) ? _("(null)") : file);
1064
1065 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
1066 ( (NULL == file) ? _("(null)") : file)
1067 );
1068 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1069 }
1070
1071#if defined(SH_STEALTH)
1072 if (0 == sl_strncmp (line, N_("[SOF]"), 5))
1073#else
1074 if (0 == sl_strncmp (line, _("[SOF]"), 5))
1075#endif
1076 break;
1077 }
1078 SL_RETURN( 1, _("sh_hash_setdataent_old"));
1079}
1080
1081/******************************************************************
1082 *
1083 * Read next record
1084 *
1085 ******************************************************************/
1086sh_file_t * sh_hash_getdataent (SL_TICKET fd, char * line, int size)
1087{
1088 sh_file_t * p;
1089 sh_filestore_t ft;
1090 long i;
1091 size_t len;
1092 char * fullpath;
1093 char * linkpath;
1094 char * attr_string = NULL;
1095 char * tmp;
1096
1097 SL_ENTER(_("sh_hash_getdataent"));
1098
1099 (void) fd;
1100
1101 /* Read next record -- Part One
1102 */
1103 p = SH_ALLOC(sizeof(sh_file_t));
1104
1105 i = fread (&ft, sizeof(sh_filestore_t), 1, sh_fin_fd);
1106 /* i = sl_read(fd, &ft, sizeof(sh_filestore_t)); */
1107 /* if ( SL_ISERROR(i) || i == 0) */
1108 if (i < 1)
1109 {
1110 SH_FREE(p);
1111 SL_RETURN( NULL, _("sh_hash_getdataent"));
1112 }
1113
1114 swap_32(&(ft.mode));
1115 swap_32(&(ft.linkmode));
1116 swap_64(&(ft.dev));
1117 swap_64(&(ft.rdev));
1118 swap_32(&(ft.hardlinks));
1119 swap_32(&(ft.ino));
1120 swap_64(&(ft.size));
1121 swap_64(&(ft.atime));
1122 swap_64(&(ft.mtime));
1123 swap_64(&(ft.ctime));
1124 swap_32(&(ft.owner));
1125 swap_32(&(ft.group));
1126#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1127 swap_32(&(ft.attributes));
1128#endif
1129#ifdef OLD_BUG
1130 swap_short(&(ft.mark));
1131#else
1132 ft.mark = *(swap_short(&(ft.mark)));
1133#endif
1134
1135 if ((ft.mark & ~REC_FLAGS_MASK) != REC_MAGIC)
1136 {
1137 SH_FREE(p);
1138 SL_RETURN( NULL, _("sh_hash_getdataent"));
1139 }
1140
1141 /* Read next record -- Part Two -- Fullpath
1142 */
1143 i = sh_hash_getline (sh_fin_fd, line, size);
1144 if (i <= 0 )
1145 {
1146 SH_FREE(line);
1147 SH_FREE(p);
1148 dlog(1, FIL__, __LINE__,
1149 _("There is a corrupt record in the file signature database: %s\nThe file path is missing.\n"),
1150 (NULL == file_path('D', 'R'))? _("(null)"):file_path('D', 'R'));
1151 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
1152 ( (NULL == file_path('D', 'R')) ? _("(null)") :
1153 file_path('D', 'R'))
1154 );
1155 aud_exit (FIL__, __LINE__,EXIT_FAILURE);
1156 }
1157
1158 tmp = unquote_string (line, i);
1159 len = sl_strlen(tmp)+1;
1160 fullpath = SH_ALLOC(len);
1161 (void) sl_strlcpy (fullpath, tmp, len);
1162 if (tmp)
1163 SH_FREE(tmp);
1164 if (fullpath[len-2] == '\n')
1165 fullpath[len-2] = '\0';
1166
1167 /* Read next record -- Part Three -- Linkpath
1168 */
1169 i = sh_hash_getline (sh_fin_fd, line, size);
1170 if (i <= 0 )
1171 {
1172 SH_FREE(line);
1173 SH_FREE(fullpath);
1174 SH_FREE(p);
1175 dlog(1, FIL__, __LINE__,
1176 _("There is a corrupt record in the file signature database: %s\nThe link path (or its placeholder) is missing.\n"),
1177 (NULL == file_path('D', 'R'))? _("(null)"):file_path('D', 'R'));
1178 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
1179 ( (NULL == file_path('D', 'R')) ? _("(null)") :
1180 file_path('D', 'R'))
1181 );
1182 aud_exit (FIL__, __LINE__,EXIT_FAILURE);
1183 }
1184
1185 tmp = unquote_string (line, i);
1186
1187 if ( tmp && tmp[0] == '-' &&
1188 (tmp[1] == '\0' || (tmp[1] == '\n' && tmp[2] == '\0')))
1189 {
1190 linkpath = (char *)notalink;
1191 }
1192 else
1193 {
1194 len = sl_strlen(tmp);
1195 linkpath = sh_util_strdup_l(tmp, len);
1196 if (len > 0 && linkpath[len-1] == '\n')
1197 linkpath[len-1] = '\0';
1198 }
1199
1200 if (tmp)
1201 SH_FREE(tmp);
1202
1203 /* Read next record -- Part Four -- attr_string
1204 */
1205 if ((ft.mark & REC_FLAGS_ATTR) != 0)
1206 {
1207 i = sh_hash_getline (sh_fin_fd, line, size);
1208 if (i <= 0 )
1209 {
1210 SH_FREE(line);
1211 SH_FREE(fullpath);
1212 if (linkpath != notalink)
1213 SH_FREE(linkpath);
1214 SH_FREE(p);
1215 dlog(1, FIL__, __LINE__,
1216 _("There is a corrupt record in the file signature database: %s\nThe attribute string is missing.\n"),
1217 (NULL == file_path('D', 'R'))? _("(null)"):file_path('D', 'R'));
1218 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
1219 ( (NULL == file_path('D', 'R')) ? _("(null)") :
1220 file_path('D', 'R'))
1221 );
1222 aud_exit (FIL__, __LINE__,EXIT_FAILURE);
1223 }
1224
1225 tmp = unquote_string (line, i);
1226
1227 len = sl_strlen(tmp)+1;
1228 attr_string = SH_ALLOC(len);
1229 (void) sl_strlcpy (attr_string, tmp, len);
1230 if (tmp)
1231 SH_FREE(tmp);
1232 if (attr_string[len-2] == '\n')
1233 attr_string[len-2] = '\0';
1234 }
1235
1236 /* Read next record -- Part Four -- Decode
1237 */
1238#if defined(SH_STEALTH)
1239 sh_do_decode(fullpath, sl_strlen(fullpath));
1240
1241#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1242 sh_do_decode(ft.c_attributes, sl_strlen(ft.c_attributes));
1243#endif
1244
1245 sh_do_decode(ft.c_mode, sl_strlen(ft.c_mode));
1246 sh_do_decode(ft.c_owner, sl_strlen(ft.c_owner));
1247 sh_do_decode(ft.c_group, sl_strlen(ft.c_group));
1248 sh_do_decode(ft.checksum, sl_strlen(ft.checksum));
1249
1250 /* TXT entries are c_mode[0] != 'l' and do not get decoded
1251 */
1252 if (ft.c_mode[0] == 'l' && linkpath != notalink)
1253 {
1254 sh_do_decode(linkpath, sl_strlen(linkpath));
1255 }
1256
1257 if ((ft.mark & REC_FLAGS_ATTR) != 0)
1258 {
1259 sh_do_decode(attr_string, sl_strlen(attr_string));
1260 }
1261#endif
1262
1263 memcpy( &(*p).theFile, &ft, sizeof(sh_filestore_t) );
1264
1265 /* init fflags, such that suid files in
1266 * database are recognized as such
1267 */
1268 {
1269 mode_t mode = (mode_t) ft.mode;
1270
1271 if (S_ISREG(mode) &&
1272 (0 !=(S_ISUID & mode) ||
1273#if defined(HOST_IS_LINUX)
1274 (0 !=(S_ISGID & mode) &&
1275 0 !=(S_IXGRP & mode))
1276#else
1277 0 !=(S_ISGID & mode)
1278#endif
1279 )
1280 )
1281 p->fflags = SH_FFLAG_SUIDCHK;
1282
1283 else
1284 p->fflags = 0;
1285 }
1286
1287 p->modi_mask = 0L;
1288 p->fullpath = fullpath;
1289 p->linkpath = linkpath;
1290
1291 p->attr_string = attr_string;
1292
1293 /* set to an invalid value
1294 */
1295 ft.mark = (REC_MAGIC + 5);
1296
1297 SL_RETURN( p, _("sh_hash_getdataent"));
1298}
1299
1300/******************************************************************
1301 *
1302 * Initialize
1303 *
1304 ******************************************************************/
1305void sh_hash_init ()
1306{
1307
1308#define FGETS_BUF 16384
1309
1310 sh_file_t * p;
1311 SL_TICKET fd;
1312 long i;
1313 int count = 0;
1314 char * line = NULL;
1315
1316#if defined(WITH_GPG) || defined(WITH_PGP)
1317 extern int get_the_fd (SL_TICKET ticket);
1318
1319 SL_TICKET fdTmp = (-1);
1320#endif
1321 char hashbuf[KEYBUF_SIZE];
1322
1323 volatile int retval = 0;
1324 volatile int exitval = EXIT_SUCCESS;
1325
1326 SL_ENTER(_("sh_hash_init"));
1327
1328 SH_MUTEX_LOCK(mutex_hash);
1329
1330 if (IsInit == 1)
1331 {
1332 goto unlock_and_return;
1333 }
1334
1335 fd = (-1);
1336
1337#if defined(SH_WITH_CLIENT)
1338
1339 /* Data file from Server
1340 */
1341
1342 if (fd == (-1) && 0 == sl_strcmp(file_path('D', 'R'), _("REQ_FROM_SERVER")))
1343 {
1344 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_D_DSTART);
1345 fd = sh_forward_req_file(_("DATA"));
1346 if (SL_ISERROR(fd))
1347 {
1348 dlog(1, FIL__, __LINE__,
1349 _("Could not retrieve the file signature database from the server(errnum = %ld).\nPossible reasons include:\n - the server is not running,\n - session key negotiation failed (see the manual for proper setup), or\n - the server cannot access the file.\n"), fd);
1350 sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_EXIT_ABORT1,
1351 sh.prg_name);
1352 retval = 1; exitval = EXIT_FAILURE;
1353 goto unlock_and_return;
1354 }
1355 sl_rewind (fd);
1356
1357 sl_strlcpy (sh.data.hash,
1358 sh_tiger_hash (file_path('D', 'R'),
1359 fd, TIGER_NOLIM, hashbuf, sizeof(hashbuf)),
1360 KEY_LEN+1);
1361 sl_rewind (fd);
1362 }
1363 else
1364#endif
1365 /* Local data file
1366 */
1367
1368 if (fd == (-1))
1369 {
1370 if ( SL_ISERROR(fd = sl_open_read(FIL__, __LINE__,
1371 file_path('D', 'R'), SL_YESPRIV)))
1372 {
1373 TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s>\n"),
1374 file_path('D', 'R')));
1375 dlog(1, FIL__, __LINE__,
1376 _("Could not open the local file signature database for reading because\nof the following error: %s (errnum = %ld)\nIf this is a permission problem, you need to change file permissions\nto make the file readable for the effective UID: %d\n"),
1377 sl_get_errmsg(), fd, (int) sl_ret_euid());
1378 sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_EXIT_ABORT1,
1379 sh.prg_name);
1380 retval = 1; exitval = EXIT_FAILURE;
1381 goto unlock_and_return;
1382 }
1383
1384 TPT(( 0, FIL__, __LINE__, _("msg=<Opened database: %s>\n"),
1385 file_path('D', 'R')));
1386
1387 if (0 != sl_strncmp(sh.data.hash,
1388 sh_tiger_hash (file_path('D', 'R'), fd, TIGER_NOLIM,
1389 hashbuf, sizeof(hashbuf)),
1390 KEY_LEN)
1391 && sh.flag.checkSum != SH_CHECK_INIT)
1392 {
1393 dlog(1, FIL__, __LINE__,
1394 _("The checksum of the file signature database has changed since startup: %s -> %s\n"),
1395 sh.data.hash, sh_tiger_hash (file_path('D', 'R'), fd, TIGER_NOLIM,
1396 hashbuf, sizeof(hashbuf)));
1397 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_AUTH,
1398 ( (NULL == file_path('D', 'R')) ? _("(null)") :
1399 file_path('D', 'R') )
1400 );
1401 retval = 1; exitval = EXIT_FAILURE;
1402 goto unlock_and_return;
1403 }
1404 sl_rewind (fd);
1405
1406 } /* new 1.4.8 */
1407
1408 if (sig_termfast == 1) /* SIGTERM */
1409 {
1410 TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
1411 --sig_raised; --sig_urgent;
1412 retval = 1; exitval = EXIT_SUCCESS;
1413 goto unlock_and_return;
1414 }
1415
1416#if defined(WITH_GPG) || defined(WITH_PGP)
1417
1418 /* extract the data and copy to temporary file
1419 */
1420 fdTmp = sh_gpg_extract_signed(fd);
1421
1422 if (sig_termfast == 1) /* SIGTERM */
1423 {
1424 TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
1425 --sig_raised; --sig_urgent;
1426 retval = 1; exitval = EXIT_SUCCESS;
1427 goto unlock_and_return;
1428 }
1429
1430 sl_close(fd);
1431 fd = fdTmp;
1432
1433 /* Validate signature of open file.
1434 */
1435 if (0 != sh_gpg_check_sign (0, fd, 2))
1436 {
1437 retval = 1; exitval = EXIT_FAILURE;
1438 goto unlock_and_return;
1439 }
1440 sl_rewind (fd);
1441#endif
1442
1443 line = SH_ALLOC(MAX_PATH_STORE+2);
1444
1445 /* fast forward to start of data
1446 */
1447 sh_hash_setdataent(fd, line, MAX_PATH_STORE+1, file_path('D', 'R'));
1448
1449 for (i = 0; i < TABSIZE; ++i)
1450 tab[i] = NULL;
1451
1452 while (1)
1453 {
1454 if (sig_termfast == 1) /* SIGTERM */
1455 {
1456 TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
1457 --sig_raised; --sig_urgent;
1458 retval = 1; exitval = EXIT_SUCCESS;
1459 SH_FREE(line);
1460 line = NULL;
1461 goto unlock_and_return;
1462 }
1463
1464 p = sh_hash_getdataent (fd, line, MAX_PATH_STORE+1);
1465 if (p != NULL)
1466 {
1467 hashinsert (p);
1468 ++count;
1469 }
1470 else
1471 break;
1472 }
1473
1474 /* Initialization completed.
1475 */
1476 IsInit = 1;
1477
1478 if (line != NULL)
1479 SH_FREE(line);
1480
1481 /* Always keep db in memory, so we have no open file
1482 */
1483 sl_close (fd);
1484 sh_hash_getline_end();
1485 /* fd = -1; */
1486
1487 unlock_and_return:
1488 ; /* 'label at end of compound statement */
1489 SH_MUTEX_UNLOCK(mutex_hash);
1490 if (retval == 0)
1491 {
1492 SL_RET0(_("sh_hash_init"));
1493 }
1494 aud_exit (FIL__, __LINE__, exitval);
1495}
1496
1497/*****************************************************************
1498 *
1499 * delete hash array
1500 *
1501 *****************************************************************/
1502void sh_hash_hashdelete ()
1503{
1504 int i;
1505
1506 SL_ENTER(_("sh_hash_hashdelete"));
1507
1508 /* need deadlock detection here if called from exit handler
1509 */
1510 SH_MUTEX_TRYLOCK(mutex_hash);
1511
1512 if (IsInit == 0)
1513 goto unlock_and_exit;
1514
1515 for (i = 0; i < TABSIZE; ++i)
1516 if (tab[i] != NULL)
1517 {
1518 hash_kill (tab[i]);
1519 tab[i] = NULL;
1520 }
1521 IsInit = 0;
1522
1523 unlock_and_exit:
1524 ; /* 'label at end of compound statement */
1525 SH_MUTEX_TRYLOCK_UNLOCK(mutex_hash);
1526
1527 SL_RET0(_("sh_hash_hashdelete"));
1528}
1529
1530/******************************************************************
1531 *
1532 * Insert a file into the database.
1533 *
1534 ******************************************************************/
1535static int pushdata_isfirst = 1;
1536static SL_TICKET pushdata_fd = -1;
1537
1538static int pushdata_stdout = S_FALSE;
1539
1540static char * sh_db_version_string = NULL;
1541
1542int sh_hash_pushdata_stdout (const char * str)
1543{
1544 if (!str)
1545 { pushdata_stdout = S_TRUE; return 0; }
1546 return -1;
1547}
1548
1549int sh_hash_version_string(const char * str)
1550{
1551 if (str)
1552 {
1553 if (sh_db_version_string != NULL) {
1554 SH_FREE(sh_db_version_string);
1555 }
1556 if (0 == sl_strncmp(str, _("NULL"), 4))
1557 {
1558 sh_db_version_string = NULL;
1559 return 0;
1560 }
1561 sh_db_version_string = sh_util_strdup(str);
1562 return 0;
1563 }
1564 return -1;
1565}
1566
1567static int sh_loosedircheck = S_FALSE;
1568
1569int sh_hash_loosedircheck(const char * str)
1570{
1571 return sh_util_flagval(str, &sh_loosedircheck);
1572}
1573
1574
1575static void sh_hash_pushdata_int (file_type * buf, char * fileHash)
1576{
1577 static long p_count = 0;
1578
1579 int status = 0;
1580
1581 char * tmp;
1582 size_t tmp_len = 0;
1583 size_t old_len = 0;
1584 size_t path_len = 0;
1585
1586 sh_filestore_t p;
1587
1588 struct stat sbuf;
1589
1590 char * fullpath = NULL;
1591 char * linkpath = NULL;
1592 char * attr_string = NULL;
1593
1594 char * line = NULL;
1595
1596 char timestring[81];
1597
1598#if !defined(__linux__) && !defined(HAVE_STAT_FLAGS)
1599 int i;
1600#endif
1601
1602 SL_ENTER(_("sh_hash_pushdata_int"));
1603
1604 fullpath = SH_ALLOC(MAX_PATH_STORE+1);
1605 linkpath = SH_ALLOC(MAX_PATH_STORE+1);
1606
1607 linkpath[0] = '-';
1608 linkpath[1] = '\0';
1609 fullpath[0] = '-';
1610 fullpath[1] = '\0';
1611
1612 if (!buf) {
1613 memset(&p, '\0', sizeof(sh_filestore_t));
1614 }
1615
1616 if ((pushdata_stdout == S_TRUE) && (sh.flag.update == S_TRUE))
1617 {
1618 dlog(1, FIL__, __LINE__,
1619 _("You cannot write the database to stdout when you use update rather than init.\n"));
1620 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
1621 _("Writing database to stdout with update"),
1622 sh.prg_name,
1623 _("sh_hash_pushdata_int"));
1624 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1625 }
1626
1627 if ((pushdata_stdout == S_TRUE) && (sl_is_suid()))
1628 {
1629 dlog(1, FIL__, __LINE__,
1630 _("You cannot write the database to stdout when running with suid privileges.\n"));
1631 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
1632 _("Writing database to stdout when suid"),
1633 sh.prg_name,
1634 _("sh_hash_pushdata_int"));
1635 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1636 }
1637
1638
1639 if ((pushdata_isfirst == 1) && (pushdata_stdout == S_FALSE) &&
1640 ( (NULL == file_path('D', 'W')) ||
1641 (0 == sl_strcmp(file_path('D', 'W'), _("REQ_FROM_SERVER"))) ))
1642 {
1643 dlog(1, FIL__, __LINE__,
1644 _("You need to configure a local path for initializing the database\nlike ./configure --with-data-file=REQ_FROM_SERVER/some/local/path\n"));
1645 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
1646 _("No local path for database specified"),
1647 sh.prg_name,
1648 _("sh_hash_pushdata_int"));
1649 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1650 }
1651
1652
1653 if ((pushdata_isfirst == 1) && (pushdata_stdout == S_FALSE))
1654 {
1655 /* Warn that file already exists; file_path != NULL here because
1656 * checked above
1657 */
1658 if (0 == retry_lstat(FIL__, __LINE__, file_path('D', 'W'), &sbuf))
1659 {
1660 if (sh.flag.update == S_FALSE)
1661 {
1662 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_FI_DBEX,
1663 file_path('D', 'W'));
1664 }
1665 }
1666 }
1667
1668
1669 if (sh.flag.update == S_FALSE)
1670 {
1671 if (pushdata_stdout == S_FALSE && pushdata_fd == -1)
1672 {
1673 if ( SL_ISERROR(pushdata_fd = sl_open_write(FIL__, __LINE__,
1674 file_path('D', 'W'),
1675 SL_YESPRIV)))
1676 {
1677 SH_FREE(fullpath);
1678 SH_FREE(linkpath);
1679 sh_error_handle((-1), FIL__, __LINE__, pushdata_fd, MSG_E_ACCESS,
1680 geteuid(), file_path('D', 'W'));
1681 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1682 }
1683
1684 if (SL_ISERROR(status = sl_lock (pushdata_fd)))
1685 {
1686 SH_FREE(fullpath);
1687 SH_FREE(linkpath);
1688 sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
1689 _("Failed to lock baseline database"), _("sh_hash_pushdata_int"),
1690 file_path('D', 'W'));
1691 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1692 }
1693
1694 if ( SL_ISERROR(status = sl_forward(pushdata_fd)))
1695 {
1696 SH_FREE(fullpath);
1697 SH_FREE(linkpath);
1698 sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
1699 _("Failed to seek to end of baseline database"),
1700 _("sh_hash_pushdata_int"),
1701 file_path('D', 'W'));
1702 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1703 }
1704 }
1705 }
1706 else /* update == TRUE */
1707 {
1708 if (pushdata_isfirst == 1)
1709 {
1710 TPT((0, FIL__, __LINE__, _("msg=<Update.>\n")))
1711 if ( SL_ISERROR(pushdata_fd = sl_open_rdwr(FIL__, __LINE__,
1712 file_path('D', 'W'),
1713 SL_YESPRIV))){
1714 SH_FREE(fullpath);
1715 SH_FREE(linkpath);
1716 sh_error_handle((-1), FIL__, __LINE__, pushdata_fd, MSG_E_ACCESS,
1717 geteuid(), file_path('D', 'W'));
1718 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1719 }
1720
1721 if (SL_ISERROR(status = sl_lock (pushdata_fd)))
1722 {
1723 SH_FREE(fullpath);
1724 SH_FREE(linkpath);
1725 sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
1726 _("Failed to lock baseline database"), _("sh_hash_pushdata_int"),
1727 file_path('D', 'W'));
1728 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1729 }
1730
1731 line = SH_ALLOC(MAX_PATH_STORE+1);
1732 if (SL_ISERROR(sh_hash_setdataent_old (pushdata_fd, line,
1733 MAX_PATH_STORE,
1734 file_path('D', 'W'))))
1735 {
1736 SH_FREE(fullpath);
1737 SH_FREE(linkpath);
1738 SH_FREE(line);
1739 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1740 }
1741 SH_FREE(line);
1742 }
1743 }
1744
1745 if (buf != NULL && buf->fullpath != NULL) {
1746
1747 old_len = sl_strlen(buf->fullpath);
1748#if defined(SH_STEALTH)
1749 sh_do_encode(buf->fullpath, old_len);
1750#endif
1751 tmp = quote_string(buf->fullpath, old_len);
1752 tmp_len = sl_strlen(tmp);
1753#if defined(SH_STEALTH)
1754 sh_do_decode(buf->fullpath, old_len);
1755#endif
1756
1757 if (tmp && tmp_len <= MAX_PATH_STORE)
1758 {
1759 sl_strlcpy(fullpath, buf->fullpath, MAX_PATH_STORE+1);
1760 }
1761 else
1762 {
1763 char hashbuf[KEYBUF_SIZE];
1764
1765 sl_strlcpy(fullpath,
1766 sh_tiger_hash (buf->fullpath,
1767 TIGER_DATA, old_len,
1768 hashbuf, sizeof(hashbuf)),
1769 KEY_LEN+1);
1770 }
1771 if (tmp) SH_FREE(tmp);
1772 }
1773
1774 path_len = sl_strlen(fullpath);
1775#if defined(SH_STEALTH)
1776 sh_do_encode(fullpath, path_len);
1777#endif
1778
1779 tmp = quote_string(fullpath, path_len);
1780 if (tmp) {
1781 sl_strlcpy(fullpath, tmp, MAX_PATH_STORE+1);
1782 SH_FREE(tmp);
1783 }
1784
1785 /* NOTE: TXT entries are c_mode[0] != 'l' and do not get decoded
1786 */
1787 if (buf != NULL /* && buf->c_mode[0] == 'l' */ && buf->link_path != NULL)
1788 {
1789
1790 old_len = sl_strlen(buf->link_path);
1791#if defined(SH_STEALTH)
1792 if (buf->c_mode[0] == 'l')
1793 sh_do_encode(buf->link_path, old_len);
1794#endif
1795 tmp = quote_string(buf->link_path, old_len);
1796 tmp_len = sl_strlen(tmp);
1797#if defined(SH_STEALTH)
1798 if (buf->c_mode[0] == 'l')
1799 sh_do_decode(buf->link_path, old_len);
1800#endif
1801
1802 if (tmp && tmp_len <= MAX_PATH_STORE)
1803 {
1804 sl_strlcpy(linkpath, buf->link_path, MAX_PATH_STORE+1);
1805 }
1806 else
1807 {
1808 char hashbuf[KEYBUF_SIZE];
1809 sl_strlcpy(linkpath,
1810 sh_tiger_hash (buf->link_path,
1811 TIGER_DATA, old_len,
1812 hashbuf, sizeof(hashbuf)),
1813 KEY_LEN+1);
1814 }
1815 if (tmp) SH_FREE(tmp);
1816
1817 path_len = sl_strlen(linkpath);
1818#if defined(SH_STEALTH)
1819 if (buf->c_mode[0] == 'l')
1820 sh_do_encode(linkpath, path_len);
1821#endif
1822 tmp = quote_string(linkpath, path_len);
1823 if (tmp)
1824 {
1825 sl_strlcpy(linkpath, tmp, MAX_PATH_STORE+1);
1826 SH_FREE(tmp);
1827 }
1828 }
1829
1830 if (buf != NULL && buf->attr_string != NULL)
1831 {
1832 old_len = sl_strlen(buf->attr_string);
1833#if defined(SH_STEALTH)
1834 sh_do_encode(buf->attr_string, old_len);
1835#endif
1836 tmp = quote_string(buf->attr_string, old_len);
1837 if (tmp)
1838 {
1839 attr_string = tmp;
1840 tmp = NULL;
1841 }
1842#if defined(SH_STEALTH)
1843 sh_do_decode(buf->attr_string, old_len);
1844#endif
1845 }
1846
1847
1848 if (buf != NULL) {
1849 p.mark = REC_MAGIC;
1850 if (attr_string)
1851 p.mark |= REC_FLAGS_ATTR;
1852 sl_strlcpy(p.c_mode, buf->c_mode, CMODE_SIZE);
1853 sl_strlcpy(p.c_group, buf->c_group, GROUP_MAX+1);
1854 sl_strlcpy(p.c_owner, buf->c_owner, USER_MAX+1);
1855 if (fileHash) {
1856 sl_strlcpy(p.checksum, fileHash, KEY_LEN+1);
1857 }
1858#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1859 sl_strlcpy(p.c_attributes, buf->c_attributes, ATTRBUF_SIZE);
1860#else
1861 for (i = 0; i < ATTRBUF_USED; ++i) p.c_attributes[i] = '-';
1862 p.c_attributes[ATTRBUF_USED] = '\0';
1863#endif
1864
1865#if defined(SH_STEALTH)
1866 sh_do_encode(p.c_mode, sl_strlen(p.c_mode));
1867 sh_do_encode(p.c_owner, sl_strlen(p.c_owner));
1868 sh_do_encode(p.c_group, sl_strlen(p.c_group));
1869 sh_do_encode(p.checksum, sl_strlen(p.checksum));
1870
1871 sh_do_encode(p.c_attributes, sl_strlen(p.c_attributes));
1872#endif
1873
1874#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1875 p.attributes = (UINT32) buf->attributes;
1876#else
1877 p.attributes = 0;
1878#endif
1879 p.linkmode = (UINT32) buf->linkmode;
1880 p.hardlinks = (UINT32) buf->hardlinks;
1881 p.dev = (UINT64) buf->dev;
1882 p.rdev = (UINT64) buf->rdev;
1883 p.mode = (UINT32) buf->mode;
1884 p.ino = (UINT32) buf->ino;
1885 p.size = (UINT64) buf->size;
1886 p.mtime = (UINT64) buf->mtime;
1887 p.atime = (UINT64) buf->atime;
1888 p.ctime = (UINT64) buf->ctime;
1889 p.owner = (UINT32) buf->owner;
1890 p.group = (UINT32) buf->group;
1891
1892 swap_32(&(p.mode));
1893 swap_32(&(p.linkmode));
1894 swap_64(&(p.dev));
1895 swap_64(&(p.rdev));
1896 swap_32(&(p.hardlinks));
1897 swap_32(&(p.ino));
1898 swap_64(&(p.size));
1899 swap_64(&(p.atime));
1900 swap_64(&(p.mtime));
1901 swap_64(&(p.ctime));
1902 swap_32(&(p.owner));
1903 swap_32(&(p.group));
1904 swap_32(&(p.attributes));
1905
1906#ifdef OLD_BUG
1907 swap_short(&(p.mark));
1908#else
1909 p.mark = *(swap_short(&(p.mark)));
1910#endif
1911 }
1912
1913 /* write the start marker
1914 */
1915 if (pushdata_isfirst == 1)
1916 {
1917 if (sh.flag.update == S_FALSE)
1918 {
1919 if (sh_db_version_string != NULL)
1920 {
1921 if (pushdata_stdout == S_FALSE)
1922 {
1923 sl_write (pushdata_fd, _("\n#Host "), 7);
1924 sl_write (pushdata_fd, sh.host.name,
1925 sl_strlen(sh.host.name));
1926 sl_write (pushdata_fd, _(" Version "), 9);
1927 sl_write (pushdata_fd, sh_db_version_string,
1928 sl_strlen(sh_db_version_string));
1929 sl_write (pushdata_fd, _(" Date "), 6);
1930 (void) sh_unix_time(0, timestring, sizeof(timestring));
1931 sl_write (pushdata_fd, timestring, strlen(timestring));
1932 sl_write (pushdata_fd, "\n", 1);
1933 } else {
1934 printf ("%s",_("\n#Host "));
1935 printf ("%s", sh.host.name);
1936 printf ("%s",_(" Version "));
1937 printf ("%s", sh_db_version_string);
1938 printf ("%s",_(" Date "));
1939 (void) sh_unix_time(0, timestring, sizeof(timestring));
1940 printf ("%s\n", timestring);
1941 }
1942 }
1943
1944 if (pushdata_stdout == S_FALSE)
1945 {
1946#if defined(SH_STEALTH)
1947 sl_write (pushdata_fd, "\n", 1);
1948 sl_write_line (pushdata_fd, N_("[SOF]"), 5);
1949#else
1950 sl_write_line (pushdata_fd, _("\n[SOF]"), 6);
1951#endif
1952 }
1953 else
1954 {
1955#if defined(SH_STEALTH)
1956 printf ("\n%s\n", N_("[SOF]"));
1957#else
1958 printf ("%s\n", _("\n[SOF]"));
1959#endif
1960 }
1961 }
1962 pushdata_isfirst = 0;
1963 }
1964
1965 if (pushdata_stdout == S_FALSE)
1966 {
1967 sl_write (pushdata_fd, &p, sizeof(sh_filestore_t));
1968 sl_write_line_fast (pushdata_fd, fullpath, sl_strlen(fullpath));
1969 sl_write_line_fast (pushdata_fd, linkpath, sl_strlen(linkpath));
1970 if (attr_string)
1971 sl_write_line_fast (pushdata_fd, attr_string, sl_strlen(attr_string));
1972 } else {
1973 if (fwrite (&p, sizeof(sh_filestore_t), 1, stdout))
1974 {
1975 printf ("%s\n", fullpath);
1976 printf ("%s\n", linkpath);
1977 if (attr_string)
1978 printf ("%s\n", attr_string);
1979 }
1980 else
1981 {
1982 perror(_("Error writing database"));
1983 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1984 }
1985 }
1986
1987 ++p_count;
1988
1989 if ((sh.flag.update != S_TRUE) && (pushdata_stdout == S_FALSE))
1990 {
1991 if (sh.flag.checkSum != SH_CHECK_INIT || (buf == NULL && fileHash == NULL))
1992 {
1993 sl_close (pushdata_fd);
1994 pushdata_fd = -1;
1995 }
1996 }
1997
1998 SH_FREE(fullpath);
1999 SH_FREE(linkpath);
2000 if (attr_string)
2001 SH_FREE(attr_string);
2002
2003 SL_RET0(_("sh_hash_pushdata_int"));
2004}
2005
2006SH_MUTEX_STATIC(mutex_writeout,PTHREAD_MUTEX_INITIALIZER);
2007
2008void sh_hash_pushdata (file_type * buf, char * fileHash)
2009{
2010 SH_MUTEX_LOCK(mutex_writeout);
2011 sh_hash_pushdata_int (buf, fileHash);
2012 SH_MUTEX_UNLOCK(mutex_writeout);
2013 return;
2014}
2015
2016
2017int sh_hash_writeout()
2018{
2019 sh_file_t * p;
2020 int i;
2021 file_type * f;
2022 char fileHash[KEY_LEN + 1];
2023
2024 SL_ENTER(_("sh_hash_writeout"));
2025
2026 if (S_TRUE == file_is_remote())
2027 {
2028 sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGEN,
2029 _("Baseline database is remote"), _("sh_hash_writeout"));
2030 SL_RETURN (1, _("sh_hash_writeout"));
2031 }
2032
2033 SH_MUTEX_LOCK(mutex_writeout);
2034 if (!SL_ISERROR(pushdata_fd))
2035 {
2036 sl_close(pushdata_fd);
2037 pushdata_fd = -1;
2038 }
2039 pushdata_isfirst = 1;
2040
2041
2042 SH_MUTEX_LOCK(mutex_hash);
2043 for (i = 0; i < TABSIZE; ++i)
2044 {
2045 for (p = tab[i]; p; p = p->next)
2046 {
2047 f = sh_hash_create_ft (p, fileHash);
2048 sh_hash_pushdata_int (f, fileHash);
2049 if (f->attr_string) SH_FREE(f->attr_string);
2050 if (f->link_path) SH_FREE(f->link_path);
2051 SH_FREE(f);
2052 }
2053 }
2054 SH_MUTEX_UNLOCK(mutex_hash);
2055
2056 if (!SL_ISERROR(pushdata_fd))
2057 {
2058 sl_close(pushdata_fd);
2059 pushdata_fd = -1;
2060 }
2061 pushdata_isfirst = 1;
2062 SH_MUTEX_UNLOCK(mutex_writeout);
2063
2064 SL_RETURN (0, _("sh_hash_writeout"));
2065}
2066
2067
2068/*********************************************************************
2069 *
2070 * Check whether a file is present in the database.
2071 *
2072 *********************************************************************/
2073static sh_file_t * sh_hash_have_it_int (const char * newname)
2074{
2075 sh_file_t * p;
2076 char hashbuf[KEYBUF_SIZE];
2077
2078 SL_ENTER(_("sh_hash_have_it_int"));
2079
2080 if (newname == NULL)
2081 SL_RETURN( (NULL), _("sh_hash_have_it_int"));
2082
2083 if (sl_strlen(newname) <= MAX_PATH_STORE)
2084 p = hashsearch(newname);
2085 else
2086 p = hashsearch ( sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname),
2087 hashbuf, sizeof(hashbuf)) );
2088 if (p == NULL)
2089 SL_RETURN( (NULL), _("sh_hash_have_it_int"));
2090
2091 SL_RETURN( (p), _("sh_hash_have_it_int"));
2092}
2093
2094int sh_hash_have_it (const char * newname)
2095{
2096 sh_file_t * p;
2097 int retval;
2098
2099 if (IsInit != 1)
2100 sh_hash_init();
2101
2102 SH_MUTEX_LOCK(mutex_hash);
2103
2104 retval = 0;
2105
2106 p = sh_hash_have_it_int (newname);
2107
2108 if (!p)
2109 retval = (-1);
2110 else if ((!SH_FFLAG_ALLIGNORE_SET(p->fflags)) &&
2111 (p->modi_mask & MODI_CHK) != 0 &&
2112 (p->modi_mask & MODI_MOD) != 0)
2113 retval = 1;
2114 SH_MUTEX_UNLOCK(mutex_hash);
2115
2116 return retval;
2117}
2118
2119int sh_hash_get_it (const char * newname, file_type * tmpFile, char * fileHash)
2120{
2121 sh_file_t * p;
2122 int retval;
2123
2124 if (IsInit != 1)
2125 sh_hash_init();
2126
2127 tmpFile->link_path = NULL;
2128 tmpFile->attr_string = NULL;
2129
2130 SH_MUTEX_LOCK(mutex_hash);
2131
2132 retval = (-1);
2133
2134 p = sh_hash_have_it_int (newname);
2135 if (p)
2136 {
2137 sl_strlcpy(tmpFile->fullpath, p->fullpath, PATH_MAX);
2138 if (p->linkpath)
2139 tmpFile->link_path = sh_util_strdup (p->linkpath);
2140 tmpFile->size = p->theFile.size;
2141 tmpFile->mtime = p->theFile.mtime;
2142 tmpFile->ctime = p->theFile.ctime;
2143 tmpFile->atime = p->theFile.atime;
2144
2145 if (NULL != fileHash)
2146 sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
2147
2148 tmpFile->attr_string = NULL;
2149 retval = 0;
2150 }
2151 SH_MUTEX_UNLOCK(mutex_hash);
2152
2153 return retval;
2154}
2155
2156int sh_hash_getflags (char * filename)
2157{
2158 sh_file_t * p;
2159 int retval;
2160
2161 if (IsInit != 1)
2162 sh_hash_init();
2163
2164 SH_MUTEX_LOCK(mutex_hash);
2165 p = sh_hash_have_it_int (filename);
2166 if (p)
2167 retval = p->fflags;
2168 else
2169 retval = -1;
2170 SH_MUTEX_UNLOCK(mutex_hash);
2171 return retval;
2172}
2173
2174int sh_hash_setflags (char * filename, int flags)
2175{
2176 sh_file_t * p;
2177 int retval;
2178
2179 if (IsInit != 1)
2180 sh_hash_init();
2181
2182 SH_MUTEX_LOCK(mutex_hash);
2183 p = sh_hash_have_it_int (filename);
2184 if (p)
2185 {
2186 p->fflags = flags;
2187 retval = 0;
2188 }
2189 else
2190 retval = -1;
2191 SH_MUTEX_UNLOCK(mutex_hash);
2192 return retval;
2193}
2194
2195/* needs lock to be threadsafe
2196 */
2197void sh_hash_set_flag (char * filename, int flag_to_set)
2198{
2199 sh_file_t * p;
2200
2201 if (IsInit != 1)
2202 sh_hash_init();
2203
2204 SH_MUTEX_LOCK(mutex_hash);
2205 p = sh_hash_have_it_int (filename);
2206 if (p)
2207 {
2208 p->fflags |= flag_to_set;
2209 }
2210 SH_MUTEX_UNLOCK(mutex_hash);
2211 return;
2212}
2213
2214/* needs lock to be threadsafe
2215 */
2216void sh_hash_clear_flag (char * filename, int flag_to_clear)
2217{
2218 sh_file_t * p;
2219
2220 if (IsInit != 1)
2221 sh_hash_init();
2222
2223 SH_MUTEX_LOCK(mutex_hash);
2224 p = sh_hash_have_it_int (filename);
2225 if (p)
2226 {
2227 p->fflags &= ~flag_to_clear;
2228 }
2229 SH_MUTEX_UNLOCK(mutex_hash);
2230 return;
2231}
2232
2233
2234/*****************************************************************
2235 *
2236 * Set a file's status to 'visited'. This is required for
2237 * files that should be ignored, and may be present in the
2238 * database, but not on disk.
2239 *
2240 *****************************************************************/
2241static int sh_hash_set_visited_int (char * newname, int flag)
2242{
2243 sh_file_t * p;
2244 char hashbuf[KEYBUF_SIZE];
2245 int retval;
2246
2247 SL_ENTER(_("sh_hash_set_visited_int"));
2248
2249 if (newname == NULL)
2250 SL_RETURN((-1), _("sh_hash_set_visited_int"));
2251
2252 if (IsInit != 1)
2253 sh_hash_init();
2254
2255 SH_MUTEX_LOCK(mutex_hash);
2256
2257 if (sl_strlen(newname) <= MAX_PATH_STORE)
2258 p = hashsearch(newname);
2259 else
2260 p = hashsearch (sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname),
2261 hashbuf, sizeof(hashbuf)));
2262
2263 if (p)
2264 {
2265 if (flag == SH_FFLAG_CHECKED)
2266 {
2267 CLEAR_SH_FFLAG_REPORTED(p->fflags);
2268 CLEAR_SH_FFLAG_VISITED(p->fflags);
2269 SET_SH_FFLAG_CHECKED(p->fflags);
2270 }
2271 else
2272 {
2273 SET_SH_FFLAG_VISITED(p->fflags);
2274 CLEAR_SH_FFLAG_CHECKED(p->fflags);
2275 if (flag == SH_FFLAG_REPORTED)
2276 SET_SH_FFLAG_REPORTED(p->fflags);
2277 else
2278 CLEAR_SH_FFLAG_REPORTED(p->fflags);
2279 }
2280 retval = 0;
2281 }
2282 else
2283 retval = -1;
2284
2285 SH_MUTEX_UNLOCK(mutex_hash);
2286 SL_RETURN((retval), _("sh_hash_set_visited_int"));
2287}
2288
2289
2290/* cause the record to be deleted without a 'missing' message
2291 */
2292int sh_hash_set_missing (char * newname)
2293{
2294 int i;
2295 SL_ENTER(_("sh_hash_set_missing"));
2296
2297 i = sh_hash_set_visited_int(newname, SH_FFLAG_CHECKED);
2298
2299 if (sh.flag.checkSum != SH_CHECK_INIT) {
2300 sh_hash_remove(newname);
2301 }
2302
2303 SL_RETURN(i, _("sh_hash_set_missing"));
2304}
2305
2306/* mark the file as visited and reported
2307 */
2308int sh_hash_set_visited (char * newname)
2309{
2310 int i;
2311 SL_ENTER(_("sh_hash_set_visited"));
2312 i = sh_hash_set_visited_int(newname, SH_FFLAG_REPORTED);
2313 SL_RETURN(i, _("sh_hash_set_visited"));
2314}
2315
2316/* mark the file as visited and NOT reported
2317 * used to avoid deletion of file from internal database
2318 */
2319int sh_hash_set_visited_true (char * newname)
2320{
2321 int i;
2322 SL_ENTER(_("sh_hash_set_visited_true"));
2323 i = sh_hash_set_visited_int(newname, 0);
2324 SL_RETURN(i, _("sh_hash_set_visited_true"));
2325}
2326
2327
2328/******************************************************************
2329 *
2330 * Data entry for arbitrary data into database
2331 *
2332 ******************************************************************/
2333
2334void sh_hash_push2db (const char * key, struct store2db * save)
2335{
2336 int i = 0;
2337 char * p;
2338 char i2h[2];
2339 file_type * tmpFile = SH_ALLOC(sizeof(file_type));
2340
2341 int size = save->size;
2342 unsigned char * str = save->str;
2343
2344
2345 tmpFile->attr_string = NULL;
2346 tmpFile->link_path = NULL;
2347
2348 sl_strlcpy(tmpFile->fullpath, key, PATH_MAX);
2349 tmpFile->size = save->val0;
2350 tmpFile->mtime = save->val1;
2351 tmpFile->ctime = save->val2;
2352 tmpFile->atime = save->val3;
2353
2354 tmpFile->mode = 0;
2355 tmpFile->owner = 0;
2356 tmpFile->group = 0;
2357 sl_strlcpy(tmpFile->c_owner, _("root"), 5);
2358 sl_strlcpy(tmpFile->c_group, _("root"), 5);
2359
2360 if ((str != NULL) && (size < (PATH_MAX/2)-1))
2361 {
2362 tmpFile->c_mode[0] = 'l';
2363 tmpFile->c_mode[1] = 'r'; tmpFile->c_mode[2] = 'w';
2364 tmpFile->c_mode[3] = 'x'; tmpFile->c_mode[4] = 'r';
2365 tmpFile->c_mode[5] = 'w'; tmpFile->c_mode[6] = 'x';
2366 tmpFile->c_mode[7] = 'r'; tmpFile->c_mode[8] = 'w';
2367 tmpFile->c_mode[9] = 'x'; tmpFile->c_mode[10] = '\0';
2368 tmpFile->link_path = SH_ALLOC((size * 2) + 2);
2369 for (i = 0; i < size; ++i)
2370 {
2371 p = sh_util_charhex (str[i],i2h);
2372 tmpFile->link_path[2*i] = p[0];
2373 tmpFile->link_path[2*i+1] = p[1];
2374 tmpFile->link_path[2*i+2] = '\0';
2375 }
2376 }
2377 else
2378 {
2379 for (i = 0; i < 10; ++i)
2380 tmpFile->c_mode[i] = '-';
2381 tmpFile->c_mode[10] = '\0';
2382 tmpFile->link_path = sh_util_strdup("-");
2383 }
2384
2385 if (sh.flag.checkSum == SH_CHECK_INIT)
2386 sh_hash_pushdata (tmpFile,
2387 (save->checksum[0] == '\0') ? SH_KEY_NULL : save->checksum);
2388 else
2389 sh_hash_pushdata_memory (tmpFile,
2390 (save->checksum[0] == '\0') ? SH_KEY_NULL : save->checksum);
2391
2392 if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
2393 SH_FREE(tmpFile);
2394 return;
2395}
2396
2397extern int sh_util_hextobinary (char * binary, char * hex, int bytes);
2398
2399char * sh_hash_db2pop (const char * key, struct store2db * save)
2400{
2401 size_t len;
2402 char * p;
2403 int i;
2404 char * retval = NULL;
2405 char fileHash[KEY_LEN+1];
2406 file_type * tmpFile = SH_ALLOC(sizeof(file_type));
2407
2408 save->size = 0;
2409
2410 if (0 == sh_hash_get_it (key, tmpFile, fileHash))
2411 {
2412 save->val0 = tmpFile->size;
2413 save->val1 = tmpFile->mtime;
2414 save->val2 = tmpFile->ctime;
2415 save->val3 = tmpFile->atime;
2416
2417 sl_strlcpy(save->checksum, fileHash, KEY_LEN+1);
2418
2419 if (tmpFile->link_path && tmpFile->link_path[0] != '-')
2420 {
2421 len = strlen(tmpFile->link_path);
2422
2423 p = SH_ALLOC((len/2)+1);
2424 i = sh_util_hextobinary (p, tmpFile->link_path, len);
2425
2426 if (i == 0)
2427 {
2428 save->size = (len/2);
2429 p[save->size] = '\0';
2430 retval = p;
2431 }
2432 else
2433 {
2434 SH_FREE(p);
2435 save->size = 0;
2436 }
2437 }
2438 else
2439 {
2440 save->size = 0;
2441 }
2442 }
2443 else
2444 {
2445 save->size = -1;
2446 save->val0 = 0;
2447 save->val1 = 0;
2448 save->val2 = 0;
2449 save->val3 = 0;
2450 }
2451 if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
2452 SH_FREE(tmpFile);
2453 return retval;
2454}
2455
2456
2457
2458
2459/******************************************************************
2460 *
2461 * Data entry in hash table
2462 *
2463 ******************************************************************/
2464sh_file_t * sh_hash_push_int (file_type * buf, char * fileHash)
2465{
2466 sh_file_t * fp;
2467 sh_filestore_t p;
2468
2469 size_t len;
2470 char * fullpath;
2471 char * linkpath;
2472 char * attr_string = NULL;
2473 char hashbuf[KEYBUF_SIZE];
2474
2475 SL_ENTER(_("sh_hash_push_int"));
2476
2477 fp = SH_ALLOC(sizeof(sh_file_t));
2478
2479 p.mark = REC_MAGIC;
2480 if (buf->attr_string)
2481 p.mark |= REC_FLAGS_ATTR;
2482 sl_strlcpy(p.c_mode, buf->c_mode, 11);
2483 sl_strlcpy(p.c_group, buf->c_group, GROUP_MAX+1);
2484 sl_strlcpy(p.c_owner, buf->c_owner, USER_MAX+1);
2485 sl_strlcpy(p.checksum, fileHash, KEY_LEN+1);
2486#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2487 sl_strlcpy(p.c_attributes, buf->c_attributes, 13);
2488#endif
2489
2490#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2491 p.attributes = (UINT32) buf->attributes;
2492#endif
2493 p.linkmode = (UINT32) buf->linkmode;
2494 p.hardlinks = (UINT32) buf->hardlinks;
2495 p.dev = (UINT64) buf->dev;
2496 p.rdev = (UINT64) buf->rdev;
2497 p.mode = (UINT32) buf->mode;
2498 p.ino = (UINT32) buf->ino;
2499 p.size = (UINT64) buf->size;
2500 p.mtime = (UINT64) buf->mtime;
2501 p.atime = (UINT64) buf->atime;
2502 p.ctime = (UINT64) buf->ctime;
2503 p.owner = (UINT32) buf->owner;
2504 p.group = (UINT32) buf->group;
2505
2506 memcpy( &(*fp).theFile, &p, sizeof(sh_filestore_t) );
2507 fp->fflags = 0; /* init fflags */
2508 fp->modi_mask = 0L;
2509
2510 if (buf->attr_string)
2511 attr_string = sh_util_strdup(buf->attr_string);
2512 fp->attr_string = attr_string;
2513
2514 len = sl_strlen(buf->fullpath);
2515 if (len <= MAX_PATH_STORE)
2516 {
2517 fullpath = SH_ALLOC(len+1);
2518 sl_strlcpy(fullpath, buf->fullpath, len+1);
2519 }
2520 else
2521 {
2522 fullpath = SH_ALLOC(KEY_LEN + 1);
2523 sl_strlcpy(fullpath,
2524 sh_tiger_hash (buf->fullpath, TIGER_DATA, len,
2525 hashbuf, sizeof(hashbuf)),
2526 KEY_LEN+1);
2527 }
2528 fp->fullpath = fullpath;
2529
2530 if (buf->link_path)
2531 {
2532 len = sl_strlen(buf->link_path);
2533 if (len <= MAX_PATH_STORE)
2534 {
2535 linkpath = SH_ALLOC(len+1);
2536 sl_strlcpy(linkpath, buf->link_path, len+1);
2537 }
2538 else
2539 {
2540 linkpath = SH_ALLOC(KEY_LEN + 1);
2541 sl_strlcpy(linkpath,
2542 sh_tiger_hash (buf->link_path, TIGER_DATA, len,
2543 hashbuf, sizeof(hashbuf)),
2544 KEY_LEN+1);
2545 }
2546 fp->linkpath = linkpath;
2547 }
2548 else
2549 fp->linkpath = NULL;
2550
2551 SL_RETURN( fp, _("sh_hash_push_int"));
2552}
2553
2554#ifdef HAVE_INTTYPES_H
2555#include <inttypes.h>
2556#else
2557#ifdef HAVE_STDINT_H
2558#include <stdint.h>
2559#endif
2560#endif
2561
2562#ifndef PRIu64
2563#ifdef HAVE_LONG_32
2564#define PRIu64 "llu"
2565#else
2566#define PRIu64 "lu"
2567#endif
2568#endif
2569
2570char * sh_hash_size_format()
2571{
2572 static char form_rval[81];
2573
2574 SL_ENTER(_("sh_hash_size_format"));
2575
2576
2577#ifdef SH_USE_XML
2578 sl_snprintf(form_rval, 80, _("%s%s%s%s%s"),
2579 _("size_old=\"%"), PRIu64, _("\" size_new=\"%"), PRIu64, "\" ");
2580#else
2581 sl_snprintf(form_rval, 80, _("%s%s%s%s%s"),
2582 _("size_old=<%"), PRIu64, _(">, size_new=<%"), PRIu64, ">, ");
2583#endif
2584
2585 SL_RETURN( form_rval, _("sh_hash_size_format"));
2586}
2587
2588
2589#ifdef SH_USE_XML
2590static char * all_items (file_type * theFile, char * fileHash, int is_new)
2591{
2592 char timstr1c[32];
2593 char timstr1a[32];
2594 char timstr1m[32];
2595
2596 char * tmp_lnk;
2597 char * format;
2598
2599 char * tmp = SH_ALLOC(SH_MSG_BUF);
2600 char * msg = SH_ALLOC(SH_MSG_BUF);
2601
2602 tmp[0] = '\0';
2603 msg[0] = '\0';
2604
2605
2606#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2607 if (is_new)
2608 format = _("mode_new=\"%s\" attr_new=\"%s\" imode_new=\"%ld\" iattr_new=\"%ld\" ");
2609 else
2610 format = _("mode_old=\"%s\" attr_old=\"%s\" imode_old=\"%ld\" iattr_old=\"%ld\" ");
2611 sl_snprintf(tmp, SH_MSG_BUF, format,
2612 theFile->c_mode,
2613 theFile->c_attributes,
2614 (long) theFile->mode,
2615 (long) theFile->attributes
2616 );
2617#else
2618 if (is_new)
2619 format = _("mode_new=\"%s\" imode_new=\"%ld\" ");
2620 else
2621 format = _("mode_old=\"%s\" imode_old=\"%ld\" ");
2622
2623 sl_snprintf(tmp, SH_MSG_BUF, format,
2624 theFile->c_mode,
2625 (long) theFile->mode
2626 );
2627#endif
2628 sl_strlcat(msg, tmp, SH_MSG_BUF);
2629
2630 if (is_new)
2631 format = _("hardlinks_new=\"%lu\" ");
2632 else
2633 format = _("hardlinks_old=\"%lu\" ");
2634 sl_snprintf(tmp, SH_MSG_BUF, format,
2635 (unsigned long) theFile->hardlinks);
2636 sl_strlcat(msg, tmp, SH_MSG_BUF);
2637
2638
2639 if (is_new)
2640 format = _("idevice_new=\"%lu\" ");
2641 else
2642 format = _("idevice_old=\"%lu\" ");
2643 sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->rdev);
2644 sl_strlcat(msg, tmp, SH_MSG_BUF);
2645
2646
2647 if (is_new)
2648 format = _("inode_new=\"%lu\" ");
2649 else
2650 format = _("inode_old=\"%lu\" ");
2651 sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->ino);
2652 sl_strlcat(msg, tmp, SH_MSG_BUF);
2653
2654 /*
2655 * also report device for prelude
2656 */
2657#if defined(HAVE_LIBPRELUDE)
2658 if (is_new)
2659 format = _("dev_new=\"%lu,%lu\" ");
2660 else
2661 format = _("dev_old=\"%lu,%lu\" ");
2662 sl_snprintf(tmp, SH_MSG_BUF, format,
2663 (unsigned long) major(theFile->dev),
2664 (unsigned long) minor(theFile->dev));
2665 sl_strlcat(msg, tmp, SH_MSG_BUF);
2666#endif
2667
2668
2669 if (is_new)
2670 format = _("owner_new=\"%s\" iowner_new=\"%ld\" ");
2671 else
2672 format = _("owner_old=\"%s\" iowner_old=\"%ld\" ");
2673 sl_snprintf(tmp, SH_MSG_BUF, format,
2674 theFile->c_owner, (long) theFile->owner);
2675 sl_strlcat(msg, tmp, SH_MSG_BUF);
2676
2677
2678 if (is_new)
2679 format = _("group_new=\"%s\" igroup_new=\"%ld\" ");
2680 else
2681 format = _("group_old=\"%s\" igroup_old=\"%ld\" ");
2682 sl_snprintf(tmp, SH_MSG_BUF, format,
2683 theFile->c_group, (long) theFile->group);
2684 sl_strlcat(msg, tmp, SH_MSG_BUF);
2685
2686
2687 if (is_new)
2688 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
2689 (UINT64) 0, (UINT64) theFile->size);
2690 else
2691 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
2692 (UINT64) theFile->size, (UINT64) 0);
2693 sl_strlcat(msg, tmp, SH_MSG_BUF);
2694
2695
2696 (void) sh_unix_gmttime (theFile->ctime, timstr1c, sizeof(timstr1c));
2697 if (is_new)
2698 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_new=\"%s\" "), timstr1c);
2699 else
2700 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=\"%s\" "), timstr1c);
2701 sl_strlcat(msg, tmp, SH_MSG_BUF);
2702
2703 (void) sh_unix_gmttime (theFile->atime, timstr1a, sizeof(timstr1a));
2704 if (is_new)
2705 sl_snprintf(tmp, SH_MSG_BUF, _("atime_new=\"%s\" "), timstr1a);
2706 else
2707 sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=\"%s\" "), timstr1a);
2708 sl_strlcat(msg, tmp, SH_MSG_BUF);
2709
2710 (void) sh_unix_gmttime (theFile->mtime, timstr1m, sizeof(timstr1m));
2711 if (is_new)
2712 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_new=\"%s\" "), timstr1m);
2713 else
2714 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=\"%s\" "), timstr1m);
2715 sl_strlcat(msg, tmp, SH_MSG_BUF);
2716
2717 if (is_new)
2718 sl_snprintf(tmp, SH_MSG_BUF, _("chksum_new=\"%s\" "), fileHash);
2719 else
2720 sl_snprintf(tmp, SH_MSG_BUF, _("chksum_old=\"%s\" "), fileHash);
2721 sl_strlcat(msg, tmp, SH_MSG_BUF);
2722
2723 if (theFile->c_mode[0] == 'l' ||
2724 (theFile->link_path != NULL && theFile->link_path[0] != '-'))
2725 {
2726 tmp_lnk = sh_util_safe_name(theFile->link_path);
2727 if (tmp_lnk)
2728 {
2729 if (is_new)
2730 sl_snprintf(tmp, SH_MSG_BUF, _("link_new=\"%s\" "), tmp_lnk);
2731 else
2732 sl_snprintf(tmp, SH_MSG_BUF, _("link_old=\"%s\" "), tmp_lnk);
2733 SH_FREE(tmp_lnk);
2734 sl_strlcat(msg, tmp, SH_MSG_BUF);
2735 }
2736 }
2737
2738 if (theFile->attr_string)
2739 {
2740 tmp_lnk = sh_util_safe_name(theFile->attr_string);
2741 if (tmp_lnk)
2742 {
2743 if (is_new)
2744 sl_snprintf(tmp, SH_MSG_BUF, _("acl_new=\"%s\" "), tmp_lnk);
2745 else
2746 sl_snprintf(tmp, SH_MSG_BUF, _("acl_old=\"%s\" "), tmp_lnk);
2747 SH_FREE(tmp_lnk);
2748 sl_strlcat(msg, tmp, SH_MSG_BUF);
2749 }
2750 }
2751
2752
2753 SH_FREE(tmp);
2754 return (msg);
2755}
2756#else
2757static char * all_items (file_type * theFile, char * fileHash, int is_new)
2758{
2759 char timstr1c[32];
2760 char timstr1a[32];
2761 char timstr1m[32];
2762
2763 char * tmp_lnk;
2764 char * format;
2765
2766 char * tmp = SH_ALLOC(SH_MSG_BUF);
2767 char * msg = SH_ALLOC(SH_MSG_BUF);
2768
2769 tmp[0] = '\0';
2770 msg[0] = '\0';
2771
2772
2773#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2774 if (is_new)
2775 format = _("mode_new=<%s>, attr_new=<%s>, imode_new=<%ld>, iattr_new=<%ld>, ");
2776 else
2777 format = _("mode_old=<%s>, attr_old=<%s>, imode_old=<%ld>, iattr_old=<%ld>, ");
2778 sl_snprintf(tmp, SH_MSG_BUF, format,
2779 theFile->c_mode,
2780 theFile->c_attributes,
2781 (long) theFile->mode,
2782 (long) theFile->attributes
2783 );
2784#else
2785 if (is_new)
2786 format = _("mode_new=<%s>, imode_new=<%ld>, ");
2787 else
2788 format = _("mode_old=<%s>, imode_old=<%ld>, ");
2789
2790 sl_snprintf(tmp, SH_MSG_BUF, format,
2791 theFile->c_mode,
2792 (long) theFile->mode
2793 );
2794#endif
2795 sl_strlcat(msg, tmp, SH_MSG_BUF);
2796
2797 if (is_new)
2798 format = _("hardlinks_new=<%lu>, ");
2799 else
2800 format = _("hardlinks_old=<%lu>, ");
2801 sl_snprintf(tmp, SH_MSG_BUF, format,
2802 (unsigned long) theFile->hardlinks);
2803 sl_strlcat(msg, tmp, SH_MSG_BUF);
2804
2805
2806 if (is_new)
2807 format = _("idevice_new=<%lu>, ");
2808 else
2809 format = _("idevice_old=<%lu>, ");
2810 sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->rdev);
2811 sl_strlcat(msg, tmp, SH_MSG_BUF);
2812
2813
2814 if (is_new)
2815 format = _("inode_new=<%lu>, ");
2816 else
2817 format = _("inode_old=<%lu>, ");
2818 sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->ino);
2819 sl_strlcat(msg, tmp, SH_MSG_BUF);
2820
2821
2822 /*
2823 * also report device for prelude
2824 */
2825#if defined(HAVE_LIBPRELUDE)
2826 if (is_new)
2827 format = _("dev_new=<%lu,%lu>, ");
2828 else
2829 format = _("dev_old=<%lu,%lu>, ");
2830 sl_snprintf(tmp, SH_MSG_BUF, format,
2831 (unsigned long) major(theFile->dev),
2832 (unsigned long) minor(theFile->dev));
2833 sl_strlcat(msg, tmp, SH_MSG_BUF);
2834#endif
2835
2836 if (is_new)
2837 format = _("owner_new=<%s>, iowner_new=<%ld>, ");
2838 else
2839 format = _("owner_old=<%s>, iowner_old=<%ld>, ");
2840 sl_snprintf(tmp, SH_MSG_BUF, format,
2841 theFile->c_owner, (long) theFile->owner);
2842 sl_strlcat(msg, tmp, SH_MSG_BUF);
2843
2844
2845 if (is_new)
2846 format = _("group_new=<%s>, igroup_new=<%ld>, ");
2847 else
2848 format = _("group_old=<%s>, igroup_old=<%ld>, ");
2849 sl_snprintf(tmp, SH_MSG_BUF, format,
2850 theFile->c_group, (long) theFile->group);
2851 sl_strlcat(msg, tmp, SH_MSG_BUF);
2852
2853
2854 if (is_new)
2855 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
2856 (UINT64) 0, (UINT64) theFile->size);
2857 else
2858 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
2859 (UINT64) theFile->size, (UINT64) 0);
2860 sl_strlcat(msg, tmp, SH_MSG_BUF);
2861
2862
2863 (void) sh_unix_gmttime (theFile->ctime, timstr1c, sizeof(timstr1c));
2864 if (is_new)
2865 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_new=<%s>, "), timstr1c);
2866 else
2867 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=<%s>, "), timstr1c);
2868 sl_strlcat(msg, tmp, SH_MSG_BUF);
2869
2870 (void) sh_unix_gmttime (theFile->atime, timstr1a, sizeof(timstr1a));
2871 if (is_new)
2872 sl_snprintf(tmp, SH_MSG_BUF, _("atime_new=<%s>, "), timstr1a);
2873 else
2874 sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=<%s>, "), timstr1a);
2875 sl_strlcat(msg, tmp, SH_MSG_BUF);
2876
2877 (void) sh_unix_gmttime (theFile->mtime, timstr1m, sizeof(timstr1m));
2878 if (is_new)
2879 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_new=<%s>, "), timstr1m);
2880 else
2881 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=<%s>, "), timstr1m);
2882 sl_strlcat(msg, tmp, SH_MSG_BUF);
2883
2884 if (is_new)
2885 sl_snprintf(tmp, SH_MSG_BUF, _("chksum_new=<%s>"), fileHash);
2886 else
2887 sl_snprintf(tmp, SH_MSG_BUF, _("chksum_old=<%s>"), fileHash);
2888 sl_strlcat(msg, tmp, SH_MSG_BUF);
2889
2890 if (theFile->c_mode[0] == 'l' ||
2891 (theFile->link_path != NULL && theFile->link_path[0] != '-'))
2892 {
2893 tmp_lnk = sh_util_safe_name(theFile->link_path);
2894 if (tmp_lnk)
2895 {
2896 if (is_new)
2897 sl_snprintf(tmp, SH_MSG_BUF, _(", link_new=<%s> "), tmp_lnk);
2898 else
2899 sl_snprintf(tmp, SH_MSG_BUF, _(", link_old=<%s> "), tmp_lnk);
2900 SH_FREE(tmp_lnk);
2901 sl_strlcat(msg, tmp, SH_MSG_BUF);
2902 }
2903 }
2904
2905 if (theFile->attr_string)
2906 {
2907 tmp_lnk = sh_util_safe_name(theFile->attr_string);
2908 if (tmp_lnk)
2909 {
2910 if (is_new)
2911 sl_snprintf(tmp, SH_MSG_BUF, _(", acl_new=<%s> "), tmp_lnk);
2912 else
2913 sl_snprintf(tmp, SH_MSG_BUF, _(", acl_old=<%s> "), tmp_lnk);
2914 SH_FREE(tmp_lnk);
2915 sl_strlcat(msg, tmp, SH_MSG_BUF);
2916 }
2917 }
2918
2919 SH_FREE(tmp);
2920 return (msg);
2921}
2922#endif
2923
2924void sh_hash_pushdata_memory (file_type * theFile, char * fileHash)
2925{
2926 sh_file_t * p;
2927
2928 SL_ENTER(_("sh_hash_pushdata_memory"));
2929
2930 p = sh_hash_push_int(theFile, fileHash);
2931 if (p)
2932 {
2933 SH_MUTEX_LOCK(mutex_hash);
2934 hashinsert (p);
2935 p->modi_mask = theFile->check_mask;
2936 SH_MUTEX_UNLOCK(mutex_hash);
2937 }
2938
2939 SL_RET0(_("sh_hash_pushdata_memory"));
2940}
2941
2942
2943/*****************************************************************
2944 *
2945 * Compare a file with the database status.
2946 *
2947 *****************************************************************/
2948int sh_hash_compdata (int class, file_type * theFile, char * fileHash,
2949 char * policy_override, int severity_override)
2950{
2951 char * msg;
2952 sh_file_t * p;
2953 char * tmp;
2954 char * tmp_path;
2955 char * tmp_lnk;
2956 char * tmp_lnk_old;
2957
2958 char * str;
2959
2960 char timstr1c[32];
2961 char timstr2c[32];
2962 char timstr1a[32];
2963 char timstr2a[32];
2964 char timstr1m[32];
2965 char timstr2m[32];
2966 char linkHash[KEY_LEN+1];
2967 char * linkComp;
2968 int maxcomp;
2969
2970 char change_code[16];
2971 int i;
2972
2973 unsigned long modi_mask;
2974
2975 char log_policy[32];
2976 volatile int log_severity;
2977 char hashbuf[KEYBUF_SIZE];
2978
2979 int retval;
2980
2981 SL_ENTER(_("sh_hash_compdata"));
2982
2983 if (IsInit != 1) sh_hash_init();
2984
2985 if (severity_override < 0)
2986 log_severity = ShDFLevel[class];
2987 else
2988 log_severity = severity_override;
2989
2990 if (policy_override != NULL)
2991 sl_strlcpy (log_policy, policy_override, 32);
2992
2993 /* -------- find the entry for the file ---------------- */
2994
2995 SH_MUTEX_LOCK(mutex_hash);
2996
2997 modi_mask = 0;
2998 retval = 0;
2999
3000 if (sl_strlen(theFile->fullpath) <= MAX_PATH_STORE)
3001 p = hashsearch(theFile->fullpath);
3002 else
3003 p = hashsearch( sh_tiger_hash(theFile->fullpath,
3004 TIGER_DATA,
3005 sl_strlen(theFile->fullpath),
3006 hashbuf, sizeof(hashbuf))
3007 );
3008
3009
3010 /* --------- Not found in database. ------------
3011 */
3012
3013 if (p == NULL)
3014 {
3015 if (S_FALSE == sh_ignore_chk_new(theFile->fullpath))
3016 {
3017 tmp = sh_util_safe_name(theFile->fullpath);
3018
3019 str = all_items (theFile, fileHash, 1);
3020 sh_error_handle (log_severity, FIL__, __LINE__, 0,
3021 MSG_FI_ADD2,
3022 tmp, str);
3023 ++sh.statistics.files_report;
3024 SH_FREE(str);
3025
3026 SH_FREE(tmp);
3027 }
3028
3029 if (sh.flag.reportonce == S_TRUE)
3030 SET_SH_FFLAG_REPORTED(theFile->file_reported);
3031
3032 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3033 {
3034 p = sh_hash_push_int(theFile, fileHash);
3035 if (p)
3036 {
3037 hashinsert (p);
3038 p->modi_mask = theFile->check_mask;
3039 }
3040 }
3041
3042 else if (S_TRUE == sh.flag.update)
3043 {
3044 if (S_TRUE == sh_util_ask_update (theFile->fullpath))
3045 {
3046 p = sh_hash_push_int(theFile, fileHash);
3047 if (p)
3048 {
3049 hashinsert (p);
3050 p->modi_mask = theFile->check_mask;
3051 }
3052 }
3053 else
3054 {
3055 retval = 1;
3056 goto unlock_and_return;
3057 }
3058 }
3059
3060 goto unlock_and_return;
3061 }
3062
3063 /* --------- Skip if we don't want to report changes. ------------
3064 */
3065
3066 if (S_TRUE == sh_ignore_chk_mod(theFile->fullpath))
3067 {
3068 goto unlock_and_return;
3069 }
3070
3071 p->modi_mask = theFile->check_mask;
3072
3073 /* initialize change_code */
3074 for (i = 0; i < 15; ++i)
3075 change_code[i] = '-';
3076 change_code[15] = '\0';
3077
3078 TPT ((0, FIL__, __LINE__, _("file=<%s>, cs_old=<%s>, cs_new=<%s>\n"),
3079 theFile->fullpath, fileHash, p->theFile.checksum));
3080
3081 if ( (fileHash != NULL) && (p->theFile.checksum != NULL) &&
3082 (strncmp (fileHash, p->theFile.checksum, KEY_LEN) != 0) &&
3083 (theFile->check_mask & MODI_CHK) != 0)
3084 {
3085 if ((theFile->check_mask & MODI_SGROW) == 0)
3086 {
3087 modi_mask |= MODI_CHK;
3088 change_code[0] = 'C';
3089 TPT ((0, FIL__, __LINE__, _("mod=<checksum>")));
3090 }
3091 else
3092 {
3093 if (0 != strncmp (&fileHash[KEY_LEN + 1], p->theFile.checksum, KEY_LEN))
3094 {
3095 if (S_FALSE == sh_check_rotated_log (theFile->fullpath, (UINT64) p->theFile.size,
3096 (UINT64) p->theFile.ino, p->theFile.checksum))
3097 {
3098 modi_mask |= MODI_CHK;
3099 change_code[0] = 'C';
3100 TPT ((0, FIL__, __LINE__, _("mod=<checksum>")));
3101 }
3102 else
3103 {
3104 /* logfile has been rotated */
3105 p->theFile.size = theFile->size;
3106 p->theFile.ino = theFile->ino;
3107 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
3108 }
3109 }
3110 else
3111 {
3112 p->theFile.size = theFile->size;
3113 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
3114 }
3115 }
3116 }
3117
3118 if (p->theFile.c_mode[0] == 'l')
3119 {
3120 if (!(theFile->link_path) &&
3121 (theFile->check_mask & MODI_LNK) != 0)
3122 {
3123 linkComp = NULL;
3124 modi_mask |= MODI_LNK;
3125 change_code[1] = 'L';
3126 TPT ((0, FIL__, __LINE__, _("mod=<link>")));
3127 }
3128 else
3129 {
3130 if (sl_strlen(theFile->link_path) >= MAX_PATH_STORE)
3131 {
3132 sl_strlcpy(linkHash,
3133 sh_tiger_hash(theFile->link_path,
3134 TIGER_DATA,
3135 sl_strlen(theFile->link_path),
3136 hashbuf, sizeof(hashbuf)),
3137 MAX_PATH_STORE+1);
3138 linkComp = linkHash;
3139 maxcomp = KEY_LEN;
3140 }
3141 else
3142 {
3143 linkComp = theFile->link_path;
3144 maxcomp = MAX_PATH_STORE;
3145 }
3146
3147 if ( sl_strncmp (linkComp, p->linkpath, maxcomp) != 0 &&
3148 (theFile->check_mask & MODI_LNK) != 0)
3149 {
3150 modi_mask |= MODI_LNK;
3151 change_code[1] = 'L';
3152 TPT ((0, FIL__, __LINE__, _("mod=<link>")));
3153 }
3154 }
3155 }
3156
3157 if (p->theFile.c_mode[0] == 'c' || p->theFile.c_mode[0] == 'b')
3158 {
3159 if ( ( major(theFile->rdev) != major((dev_t)p->theFile.rdev) ||
3160 minor(theFile->rdev) != minor((dev_t)p->theFile.rdev) ) &&
3161 (theFile->check_mask & MODI_RDEV) != 0)
3162 {
3163 modi_mask |= MODI_RDEV;
3164 change_code[2] = 'D';
3165 TPT ((0, FIL__, __LINE__, _("mod=<rdev>")));
3166 }
3167 }
3168
3169 /* cast to UINT32 in case ino_t is not 32bit
3170 */
3171 if ( (UINT32) theFile->ino != (UINT32) p->theFile.ino &&
3172 (theFile->check_mask & MODI_INO) != 0)
3173 {
3174 modi_mask |= MODI_INO;
3175 change_code[3] = 'I';
3176 TPT ((0, FIL__, __LINE__, _("mod=<inode>")));
3177 }
3178
3179 if ( theFile->hardlinks != (nlink_t) p->theFile.hardlinks &&
3180 (theFile->check_mask & MODI_HLN) != 0)
3181 {
3182 modi_mask |= MODI_HLN;
3183 change_code[4] = 'H';
3184 TPT ((0, FIL__, __LINE__, _("mod=<hardlink>")));
3185 }
3186
3187
3188 if ( ( (theFile->mode != p->theFile.mode)
3189#if defined(USE_ACL) || defined(USE_XATTR)
3190 || ( (sh_unix_check_selinux|sh_unix_check_acl) &&
3191 (
3192 (theFile->attr_string == NULL && p->attr_string != NULL) ||
3193 (theFile->attr_string != NULL && p->attr_string == NULL) ||
3194 (theFile->attr_string != NULL && 0 != strcmp(theFile->attr_string, p->attr_string))
3195 )
3196 )
3197#endif
3198#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
3199 || (theFile->attributes != p->theFile.attributes)
3200#endif
3201 )
3202 && (theFile->check_mask & MODI_MOD) != 0)
3203 {
3204 modi_mask |= MODI_MOD;
3205 change_code[5] = 'M';
3206 TPT ((0, FIL__, __LINE__, _("mod=<mode>")));
3207 /*
3208 * report link path if switch link/no link
3209 */
3210 if ((theFile->check_mask & MODI_LNK) != 0 &&
3211 (theFile->c_mode[0] != p->theFile.c_mode[0]) &&
3212 (theFile->c_mode[0] == 'l' || p->theFile.c_mode[0] == 'l'))
3213 {
3214 modi_mask |= MODI_LNK;
3215 change_code[1] = 'L';
3216 TPT ((0, FIL__, __LINE__, _("mod=<link>")));
3217 }
3218 }
3219
3220 if ( theFile->owner != (uid_t) p->theFile.owner &&
3221 (theFile->check_mask & MODI_USR) != 0)
3222 {
3223 modi_mask |= MODI_USR;
3224 change_code[6] = 'U';
3225 TPT ((0, FIL__, __LINE__, _("mod=<user>")));
3226 }
3227
3228 if ( theFile->group != (gid_t) p->theFile.group &&
3229 (theFile->check_mask & MODI_GRP) != 0)
3230 {
3231 modi_mask |= MODI_GRP;
3232 change_code[7] = 'G';
3233 TPT ((0, FIL__, __LINE__, _("mod=<group>")));
3234 }
3235
3236
3237 if ( theFile->mtime != (time_t) p->theFile.mtime &&
3238 (theFile->check_mask & MODI_MTM) != 0)
3239 {
3240 modi_mask |= MODI_MTM;
3241 change_code[8] = 'T';
3242 TPT ((0, FIL__, __LINE__, _("mod=<mtime>")));
3243 }
3244
3245 if ( (theFile->check_mask & MODI_ATM) != 0 &&
3246 theFile->atime != (time_t) p->theFile.atime)
3247 {
3248 modi_mask |= MODI_ATM;
3249 change_code[8] = 'T';
3250 TPT ((0, FIL__, __LINE__, _("mod=<atime>")));
3251 }
3252
3253
3254 /* Resetting the access time will set a new ctime. Thus, either we ignore
3255 * the access time or the ctime for NOIGNORE
3256 */
3257 if ( theFile->ctime != (time_t) p->theFile.ctime &&
3258 (theFile->check_mask & MODI_CTM) != 0)
3259 {
3260 modi_mask |= MODI_CTM;
3261 change_code[8] = 'T';
3262 TPT ((0, FIL__, __LINE__, _("mod=<ctime>")));
3263 }
3264
3265 if ( theFile->size != (off_t) p->theFile.size &&
3266 (theFile->check_mask & MODI_SIZ) != 0)
3267 {
3268 if ((theFile->check_mask & MODI_SGROW) == 0 ||
3269 theFile->size < (off_t) p->theFile.size)
3270 {
3271 modi_mask |= MODI_SIZ;
3272 change_code[9] = 'S';
3273 TPT ((0, FIL__, __LINE__, _("mod=<size>")));
3274 }
3275 }
3276 change_code[10] = '\0';
3277
3278 /* --- Directories special case ---
3279 */
3280 if (p->theFile.c_mode[0] == 'd' &&
3281 0 == (modi_mask & ~(MODI_SIZ|MODI_ATM|MODI_CTM|MODI_MTM)) &&
3282 sh_loosedircheck == S_TRUE)
3283 {
3284 modi_mask = 0;
3285 }
3286
3287 /* --- Report full details. ---
3288 */
3289 if (modi_mask != 0 && sh.flag.fulldetail == S_TRUE)
3290 {
3291 if ((theFile->check_mask & MODI_ATM) == 0)
3292 modi_mask = MASK_READONLY_;
3293 else
3294 modi_mask = MASK_NOIGNORE_;
3295 }
3296
3297 /* --- Report on modified files. ---
3298 */
3299 if (modi_mask != 0 && (!SH_FFLAG_REPORTED_SET(p->fflags)))
3300 {
3301 tmp = SH_ALLOC(SH_MSG_BUF);
3302 msg = SH_ALLOC(SH_MSG_BUF);
3303 msg[0] = '\0';
3304
3305 if ( ((modi_mask & MODI_MOD) != 0)
3306#if defined(HAVE_LIBPRELUDE)
3307 || ((modi_mask & MODI_USR) != 0)
3308 || ((modi_mask & MODI_GRP) != 0)
3309#endif
3310 )
3311 {
3312#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
3313 sl_snprintf(tmp, SH_MSG_BUF,
3314#ifdef SH_USE_XML
3315 _("mode_old=\"%s\" mode_new=\"%s\" attr_old=\"%s\" attr_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" iattr_old=\"%ld\" iattr_new=\"%ld\" "),
3316#else
3317 _("mode_old=<%s>, mode_new=<%s>, attr_old=<%s>, attr_new=<%s>, "),
3318#endif
3319 p->theFile.c_mode, theFile->c_mode,
3320 p->theFile.c_attributes, theFile->c_attributes
3321#ifdef SH_USE_XML
3322 , (long) p->theFile.mode, (long) theFile->mode,
3323 (long) p->theFile.attributes,
3324 (long) theFile->attributes
3325#endif
3326 );
3327#else
3328#ifdef SH_USE_XML
3329 sl_snprintf(tmp, SH_MSG_BUF,
3330 _("mode_old=\"%s\" mode_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" "),
3331 p->theFile.c_mode, theFile->c_mode,
3332 (long) p->theFile.mode, (long) theFile->mode);
3333#else
3334 sl_snprintf(tmp, SH_MSG_BUF, _("mode_old=<%s>, mode_new=<%s>, "),
3335 p->theFile.c_mode, theFile->c_mode);
3336#endif
3337#endif
3338 sl_strlcat(msg, tmp, SH_MSG_BUF);
3339
3340#if defined(USE_ACL) || defined(USE_XATTR)
3341 if (theFile->attr_string != NULL || p->attr_string != NULL)
3342 {
3343 sl_snprintf(tmp, SH_MSG_BUF,
3344#ifdef SH_USE_XML
3345 _("acl_old=\"%s\" acl_new=\"%s\" "),
3346#else
3347 _("acl_old=<%s>, acl_new=<%s>, "),
3348#endif
3349 (p->attr_string) ? p->attr_string : _("none"),
3350 (theFile->attr_string) ? theFile->attr_string : _("none"));
3351
3352 sl_strlcat(msg, tmp, SH_MSG_BUF);
3353 }
3354#endif
3355
3356#ifdef REPLACE_OLD
3357 if ((modi_mask & MODI_MOD) != 0)
3358 {
3359 /*
3360 * We postpone update if sh.flag.update == S_TRUE because
3361 * in interactive mode the user may not accept the change.
3362 */
3363 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3364 {
3365 sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11);
3366 p->theFile.mode = theFile->mode;
3367#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
3368 sl_strlcpy(p->theFile.c_attributes,theFile->c_attributes,16);
3369 p->theFile.attributes = theFile->attributes;
3370#endif
3371#if defined(USE_ACL) || defined(USE_XATTR)
3372 if (p->attr_string == NULL && theFile->attr_string != NULL)
3373 { p->attr_string = sh_util_strdup (theFile->attr_string); }
3374 else if (p->attr_string != NULL && theFile->attr_string == NULL)
3375 { SH_FREE(p->attr_string); p->attr_string = NULL; }
3376 else if (theFile->attr_string != NULL && p->attr_string != NULL)
3377 {
3378 if (0 != strcmp(theFile->attr_string, p->attr_string))
3379 {
3380 SH_FREE(p->attr_string);
3381 p->attr_string = sh_util_strdup (theFile->attr_string);
3382 }
3383 }
3384#endif
3385 }
3386 }
3387#endif
3388 }
3389
3390 if ((modi_mask & MODI_HLN) != 0)
3391 {
3392 sl_snprintf(tmp, SH_MSG_BUF,
3393#ifdef SH_USE_XML
3394 _("hardlinks_old=\"%lu\" hardlinks_new=\"%lu\" "),
3395#else
3396 _("hardlinks_old=<%lu>, hardlinks_new=<%lu>, "),
3397#endif
3398 (unsigned long) p->theFile.hardlinks,
3399 (unsigned long) theFile->hardlinks);
3400 sl_strlcat(msg, tmp, SH_MSG_BUF);
3401#ifdef REPLACE_OLD
3402 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3403 p->theFile.hardlinks = theFile->hardlinks;
3404#endif
3405 }
3406
3407 if ((modi_mask & MODI_RDEV) != 0)
3408 {
3409 sl_snprintf(tmp, SH_MSG_BUF,
3410#ifdef SH_USE_XML
3411 _("device_old=\"%lu,%lu\" device_new=\"%lu,%lu\" idevice_old=\"%lu\" idevice_new=\"%lu\" "),
3412#else
3413 _("device_old=<%lu,%lu>, device_new=<%lu,%lu>, "),
3414#endif
3415 (unsigned long) major(p->theFile.rdev),
3416 (unsigned long) minor(p->theFile.rdev),
3417 (unsigned long) major(theFile->rdev),
3418 (unsigned long) minor(theFile->rdev)
3419#ifdef SH_USE_XML
3420 , (unsigned long) p->theFile.rdev,
3421 (unsigned long) theFile->rdev
3422#endif
3423 );
3424 sl_strlcat(msg, tmp, SH_MSG_BUF);
3425#ifdef REPLACE_OLD
3426 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3427 p->theFile.rdev = theFile->rdev;
3428#endif
3429 }
3430
3431 if ((modi_mask & MODI_INO) != 0)
3432 {
3433 sl_snprintf(tmp, SH_MSG_BUF,
3434#ifdef SH_USE_XML
3435 _("inode_old=\"%lu\" inode_new=\"%lu\" "),
3436#else
3437 _("inode_old=<%lu>, inode_new=<%lu>, "),
3438#endif
3439 (unsigned long) p->theFile.ino,
3440 (unsigned long) theFile->ino);
3441 sl_strlcat(msg, tmp, SH_MSG_BUF);
3442#ifdef REPLACE_OLD
3443 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3444 {
3445 p->theFile.ino = theFile->ino;
3446 p->theFile.dev = theFile->dev;
3447 }
3448#endif
3449 }
3450
3451
3452 /*
3453 * also report device for prelude
3454 */
3455#if defined(HAVE_LIBPRELUDE)
3456 if ((modi_mask & MODI_INO) != 0)
3457 {
3458 sl_snprintf(tmp, SH_MSG_BUF,
3459#ifdef SH_USE_XML
3460 _("dev_old=\"%lu,%lu\" dev_new=\"%lu,%lu\" "),
3461#else
3462 _("dev_old=<%lu,%lu>, dev_new=<%lu,%lu>, "),
3463#endif
3464 (unsigned long) major(p->theFile.dev),
3465 (unsigned long) minor(p->theFile.dev),
3466 (unsigned long) major(theFile->dev),
3467 (unsigned long) minor(theFile->dev)
3468 );
3469 sl_strlcat(msg, tmp, SH_MSG_BUF);
3470#ifdef REPLACE_OLD
3471 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3472 p->theFile.dev = theFile->dev;
3473#endif
3474 }
3475#endif
3476
3477 if ( ((modi_mask & MODI_USR) != 0)
3478#if defined(HAVE_LIBPRELUDE)
3479 || ((modi_mask & MODI_MOD) != 0)
3480#endif
3481 )
3482 {
3483#ifdef SH_USE_XML
3484 sl_snprintf(tmp, SH_MSG_BUF,
3485 _("owner_old=\"%s\" owner_new=\"%s\" iowner_old=\"%ld\" iowner_new=\"%ld\" "),
3486#else
3487 sl_snprintf(tmp, SH_MSG_BUF,
3488 _("owner_old=<%s>, owner_new=<%s>, iowner_old=<%ld>, iowner_new=<%ld>, "),
3489#endif
3490 p->theFile.c_owner, theFile->c_owner,
3491 (long) p->theFile.owner, (long) theFile->owner
3492 );
3493 sl_strlcat(msg, tmp, SH_MSG_BUF);
3494#ifdef REPLACE_OLD
3495 if ((modi_mask & MODI_USR) != 0) {
3496 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3497 {
3498 sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2);
3499 p->theFile.owner = theFile->owner;
3500 }
3501 }
3502#endif
3503 }
3504
3505 if ( ((modi_mask & MODI_GRP) != 0)
3506#if defined(HAVE_LIBPRELUDE)
3507 || ((modi_mask & MODI_MOD) != 0)
3508#endif
3509 )
3510 {
3511#ifdef SH_USE_XML
3512 sl_snprintf(tmp, SH_MSG_BUF,
3513 _("group_old=\"%s\" group_new=\"%s\" igroup_old=\"%ld\" igroup_new=\"%ld\" "),
3514 p->theFile.c_group, theFile->c_group,
3515 (long) p->theFile.group, (long) theFile->group);
3516#else
3517 sl_snprintf(tmp, SH_MSG_BUF,
3518 _("group_old=<%s>, group_new=<%s>, igroup_old=<%ld>, igroup_new=<%ld>, "),
3519 p->theFile.c_group, theFile->c_group,
3520 (long) p->theFile.group, (long) theFile->group);
3521#endif
3522
3523 sl_strlcat(msg, tmp, SH_MSG_BUF);
3524#ifdef REPLACE_OLD
3525 if ((modi_mask & MODI_GRP) != 0) {
3526 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3527 {
3528 sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2);
3529 p->theFile.group = theFile->group;
3530 }
3531 }
3532#endif
3533 }
3534
3535 if ((modi_mask & MODI_SIZ) != 0)
3536 {
3537 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
3538 (UINT64) p->theFile.size,
3539 (UINT64) theFile->size);
3540 sl_strlcat(msg, tmp, SH_MSG_BUF);
3541#ifdef REPLACE_OLD
3542 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3543 p->theFile.size = theFile->size;
3544#endif
3545 }
3546
3547 if ((modi_mask & MODI_CTM) != 0)
3548 {
3549 (void) sh_unix_gmttime (p->theFile.ctime, timstr1c, sizeof(timstr1c));
3550 (void) sh_unix_gmttime (theFile->ctime, timstr2c, sizeof(timstr2c));
3551#ifdef SH_USE_XML
3552 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=\"%s\" ctime_new=\"%s\" "),
3553 timstr1c, timstr2c);
3554#else
3555 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=<%s>, ctime_new=<%s>, "),
3556 timstr1c, timstr2c);
3557#endif
3558 sl_strlcat(msg, tmp, SH_MSG_BUF);
3559#ifdef REPLACE_OLD
3560 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3561 p->theFile.ctime = theFile->ctime;
3562#endif
3563 }
3564
3565 if ((modi_mask & MODI_ATM) != 0)
3566 {
3567 (void) sh_unix_gmttime (p->theFile.atime, timstr1a, sizeof(timstr1a));
3568 (void) sh_unix_gmttime (theFile->atime, timstr2a, sizeof(timstr2a));
3569#ifdef SH_USE_XML
3570 sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=\"%s\" atime_new=\"%s\" "),
3571 timstr1a, timstr2a);
3572#else
3573 sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=<%s>, atime_new=<%s>, "),
3574 timstr1a, timstr2a);
3575#endif
3576 sl_strlcat(msg, tmp, SH_MSG_BUF);
3577#ifdef REPLACE_OLD
3578 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3579 p->theFile.atime = theFile->atime;
3580#endif
3581 }
3582
3583 if ((modi_mask & MODI_MTM) != 0)
3584 {
3585 (void) sh_unix_gmttime (p->theFile.mtime, timstr1m, sizeof(timstr1m));
3586 (void) sh_unix_gmttime (theFile->mtime, timstr2m, sizeof(timstr2m));
3587#ifdef SH_USE_XML
3588 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=\"%s\" mtime_new=\"%s\" "),
3589 timstr1m, timstr2m);
3590#else
3591 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=<%s>, mtime_new=<%s>, "),
3592 timstr1m, timstr2m);
3593#endif
3594 sl_strlcat(msg, tmp, SH_MSG_BUF);
3595#ifdef REPLACE_OLD
3596 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3597 p->theFile.mtime = theFile->mtime;
3598#endif
3599 }
3600
3601
3602 if ((modi_mask & MODI_CHK) != 0)
3603 {
3604 sl_snprintf(tmp, SH_MSG_BUF,
3605#ifdef SH_USE_XML
3606 _("chksum_old=\"%s\" chksum_new=\"%s\" "),
3607#else
3608 _("chksum_old=<%s>, chksum_new=<%s>, "),
3609#endif
3610 p->theFile.checksum, fileHash);
3611 sl_strlcat(msg, tmp, SH_MSG_BUF);
3612#ifdef REPLACE_OLD
3613 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3614 {
3615 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
3616 if ((theFile->check_mask & MODI_SGROW) != 0)
3617 p->theFile.size = theFile->size;
3618 }
3619#endif
3620 /* FIXME is this correct? */
3621 if (theFile->c_mode[0] != 'l' && theFile->link_path &&
3622 strlen(theFile->link_path) > 2)
3623 modi_mask |= MODI_LNK;
3624 }
3625
3626
3627 if ((modi_mask & MODI_LNK) != 0 /* && theFile->c_mode[0] == 'l' */)
3628 {
3629 if (theFile->link_path)
3630 tmp_lnk = sh_util_safe_name(theFile->link_path);
3631 else
3632 tmp_lnk = sh_util_strdup("-");
3633 if (p->linkpath)
3634 tmp_lnk_old = sh_util_safe_name(p->linkpath);
3635 else
3636 tmp_lnk_old = sh_util_strdup("-");
3637#ifdef SH_USE_XML
3638 sl_snprintf(tmp, SH_MSG_BUF, _("link_old=\"%s\" link_new=\"%s\" "),
3639 tmp_lnk_old, tmp_lnk);
3640#else
3641 sl_snprintf(tmp, SH_MSG_BUF, _("link_old=<%s>, link_new=<%s>, "),
3642 tmp_lnk_old, tmp_lnk);
3643#endif
3644 SH_FREE(tmp_lnk);
3645 SH_FREE(tmp_lnk_old);
3646 sl_strlcat(msg, tmp, SH_MSG_BUF);
3647#ifdef REPLACE_OLD
3648 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3649 {
3650 if (p->linkpath != NULL && p->linkpath != notalink)
3651 SH_FREE(p->linkpath);
3652 if (!(theFile->link_path) ||
3653 (theFile->link_path[0] == '-' && theFile->link_path[1] == '\0'))
3654 p->linkpath = (char *)notalink;
3655 else
3656 p->linkpath = sh_util_strdup(theFile->link_path);
3657 }
3658#endif
3659 }
3660
3661 if (MODI_AUDIT_ENABLED(theFile->check_mask))
3662 {
3663 char result[256];
3664
3665 if (NULL != sh_audit_fetch (theFile->fullpath, theFile->mtime, result, sizeof(result)))
3666 {
3667#ifdef SH_USE_XML
3668 sl_strlcat(msg, _("obj=\""), SH_MSG_BUF);
3669#else
3670 sl_strlcat(msg, _("obj=<"), SH_MSG_BUF);
3671#endif
3672
3673 sl_strlcat(msg, result, SH_MSG_BUF);
3674
3675#ifdef SH_USE_XML
3676 sl_strlcat(msg, _("\" "), SH_MSG_BUF);
3677#else
3678 sl_strlcat(msg, _(">"), SH_MSG_BUF);
3679#endif
3680 }
3681 }
3682
3683 tmp_path = sh_util_safe_name(theFile->fullpath);
3684 sh_error_handle(log_severity, FIL__, __LINE__,
3685 (long) modi_mask, MSG_FI_CHAN,
3686 (policy_override == NULL) ? _(policy[class]):log_policy,
3687 change_code, tmp_path, msg);
3688 ++sh.statistics.files_report;
3689
3690 SH_FREE(tmp_path);
3691 SH_FREE(tmp);
3692 SH_FREE(msg);
3693
3694#ifndef REPLACE_OLD
3695 SET_SH_FFLAG_REPORTED(p->fflags);
3696#endif
3697
3698 if (S_TRUE == sh.flag.update)
3699 {
3700 if (S_FALSE == sh_util_ask_update(theFile->fullpath))
3701 {
3702 /* user does not want to update, thus we replace
3703 * with data from the baseline database
3704 */
3705 sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11);
3706 theFile->mode = p->theFile.mode;
3707#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
3708 sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, 16);
3709 theFile->attributes = p->theFile.attributes;
3710#endif
3711#if defined(USE_ACL) || defined(USE_XATTR)
3712 if (theFile->attr_string == NULL && p->attr_string != NULL)
3713 { theFile->attr_string = sh_util_strdup (p->attr_string); }
3714 else if (theFile->attr_string != NULL && p->attr_string == NULL)
3715 { SH_FREE(theFile->attr_string); theFile->attr_string = NULL; }
3716 else if (theFile->attr_string != NULL && p->attr_string != NULL)
3717 {
3718 if (0 != strcmp(theFile->attr_string, p->attr_string))
3719 {
3720 SH_FREE(theFile->attr_string);
3721 theFile->attr_string = sh_util_strdup (p->attr_string);
3722 }
3723 }
3724#endif
3725
3726 if (theFile->c_mode[0] == 'l') /* c_mode is already copied */
3727 {
3728 if (theFile->link_path)
3729 SH_FREE(theFile->link_path);
3730 if (p->linkpath)
3731 theFile->link_path = sh_util_strdup(p->linkpath);
3732 else
3733 theFile->link_path = sh_util_strdup("-");
3734 }
3735 else
3736 {
3737 if (theFile->link_path)
3738 SH_FREE(theFile->link_path);
3739 if (p->linkpath && p->linkpath != notalink)
3740 theFile->link_path = sh_util_strdup(p->linkpath);
3741 else
3742 theFile->link_path = NULL;
3743 }
3744
3745 sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
3746
3747 theFile->mtime = p->theFile.mtime;
3748 theFile->ctime = p->theFile.ctime;
3749 theFile->atime = p->theFile.atime;
3750
3751 theFile->size = p->theFile.size;
3752
3753 sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2);
3754 theFile->group = p->theFile.group;
3755 sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2);
3756 theFile->owner = p->theFile.owner;
3757
3758 theFile->ino = p->theFile.ino;
3759 theFile->rdev = p->theFile.rdev;
3760 theFile->dev = p->theFile.dev;
3761 theFile->hardlinks = p->theFile.hardlinks;
3762
3763 SET_SH_FFLAG_VISITED(p->fflags);
3764 CLEAR_SH_FFLAG_CHECKED(p->fflags);
3765 retval = 1;
3766 goto unlock_and_return;
3767 }
3768 else /* if (sh.flag.reportonce == S_TRUE) */
3769 {
3770 /* we replace the data in the in-memory copy of the
3771 * baseline database, because otherwise we would get
3772 * another warning if the suidcheck runs
3773 */
3774 sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11);
3775 p->theFile.mode = theFile->mode;
3776#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
3777 sl_strlcpy(p->theFile.c_attributes, theFile->c_attributes, 16);
3778 p->theFile.attributes = theFile->attributes;
3779#endif
3780#if defined(USE_ACL) || defined(USE_XATTR)
3781 if (p->attr_string == NULL && theFile->attr_string != NULL)
3782 { p->attr_string = sh_util_strdup (theFile->attr_string); }
3783 else if (p->attr_string != NULL && theFile->attr_string == NULL)
3784 { SH_FREE(p->attr_string); p->attr_string = NULL; }
3785 else if (theFile->attr_string != NULL && p->attr_string != NULL)
3786 {
3787 if (0 != strcmp(theFile->attr_string, p->attr_string))
3788 {
3789 SH_FREE(p->attr_string);
3790 p->attr_string = sh_util_strdup (theFile->attr_string);
3791 }
3792 }
3793#endif
3794
3795 if (theFile->c_mode[0] == 'l' || theFile->link_path)
3796 {
3797 if (p->linkpath != NULL && p->linkpath != notalink)
3798 SH_FREE(p->linkpath);
3799 p->linkpath = sh_util_strdup(theFile->link_path);
3800 }
3801 else
3802 {
3803 if (p->linkpath != NULL && p->linkpath != notalink) {
3804 SH_FREE(p->linkpath);
3805 }
3806 p->linkpath = (char *)notalink;
3807 }
3808
3809 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
3810
3811 p->theFile.mtime = theFile->mtime;
3812 p->theFile.ctime = theFile->ctime;
3813 p->theFile.atime = theFile->atime;
3814
3815 p->theFile.size = theFile->size;
3816
3817 sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2);
3818 p->theFile.group = theFile->group;
3819 sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2);
3820 p->theFile.owner = theFile->owner;
3821
3822 p->theFile.ino = theFile->ino;
3823 p->theFile.rdev = theFile->rdev;
3824 p->theFile.dev = theFile->dev;
3825 p->theFile.hardlinks = theFile->hardlinks;
3826 }
3827 }
3828 }
3829
3830 SET_SH_FFLAG_VISITED(p->fflags);
3831 CLEAR_SH_FFLAG_CHECKED(p->fflags);
3832
3833 unlock_and_return:
3834 ; /* 'label at end of compound statement */
3835 SH_MUTEX_UNLOCK(mutex_hash);
3836 SL_RETURN(retval, _("sh_hash_compdata"));
3837}
3838
3839int hash_full_tree ()
3840{
3841 sh_file_t * p;
3842 int i;
3843
3844 SL_ENTER(_("hash_full_tree"));
3845
3846 if (IsInit != 1)
3847 SL_RETURN(0, _("hash_full_tree"));
3848
3849 SH_MUTEX_LOCK_UNSAFE(mutex_hash);
3850 for (i = 0; i < TABSIZE; ++i)
3851 {
3852 for (p = tab[i]; p; p = p->next)
3853 CLEAR_SH_FFLAG_ALLIGNORE(p->fflags);
3854 }
3855 SH_MUTEX_UNLOCK_UNSAFE(mutex_hash);
3856 SL_RETURN (0, _("hash_full_tree"));
3857}
3858
3859#if !defined(SH_CUTEST)
3860static
3861#endif
3862int hash_remove_tree_test(char * s, char * fullpath, size_t len_s)
3863{
3864 size_t len_p;
3865 char * test;
3866
3867 len_p = strlen(fullpath);
3868
3869 if (len_p >= len_s)
3870 {
3871 if (0 == strncmp(s, fullpath, len_s))
3872 {
3873 if (len_p > len_s)
3874 {
3875 /* continue if not inside directory;
3876 * len_s > 1 because everything is inside '/'
3877 */
3878 if ((len_s > 1) && (fullpath[len_s] != '/'))
3879 return S_FALSE;
3880
3881 test = sh_files_find_mostspecific_dir(fullpath);
3882
3883 if (test && 0 != strcmp(test, s)) {
3884 /* There is a more specific directory, continue */
3885 return S_FALSE;
3886 }
3887
3888 if (NULL == sh_files_findfile(fullpath)) {
3889 /* SET_SH_FFLAG_ALLIGNORE(p->fflags); */
3890 return S_TRUE;
3891 }
3892 }
3893 else /* len_p == len */
3894 {
3895 /* it is 's' itself, mark and continue
3896 * unless there is a policy for the inode itself
3897 */
3898 if (NULL == sh_files_findfile(fullpath)) {
3899 /* SET_SH_FFLAG_ALLIGNORE(p->fflags); */
3900 return S_TRUE;
3901 }
3902 else {
3903 return S_FALSE;
3904 }
3905 }
3906
3907 } /* if path is in tree */
3908 } /* if path is possibly in tree */
3909 return S_FALSE;
3910}
3911
3912
3913int hash_remove_tree (char * s)
3914{
3915 sh_file_t * p;
3916 size_t len_s;
3917 unsigned int i;
3918
3919 SL_ENTER(_("hash_remove_tree"));
3920
3921 if (!s || *s == '\0')
3922 SL_RETURN ((-1), _("hash_remove_tree"));
3923
3924 len_s = sl_strlen(s);
3925
3926 if (IsInit != 1)
3927 sh_hash_init();
3928
3929 SH_MUTEX_LOCK_UNSAFE(mutex_hash);
3930 for (i = 0; i < TABSIZE; ++i)
3931 {
3932 for (p = tab[i]; p; p = p->next)
3933 {
3934 if (p->fullpath)
3935 {
3936 /* if (0 == strncmp(s, p->fullpath, len_s)) *//* old */
3937 if (S_TRUE == hash_remove_tree_test(s, p->fullpath, len_s))
3938 SET_SH_FFLAG_ALLIGNORE(p->fflags);
3939 } /* if path is not null */
3940
3941 }
3942 }
3943 SH_MUTEX_UNLOCK_UNSAFE(mutex_hash);
3944 SL_RETURN ((0), _("hash_remove_tree"));
3945}
3946
3947#if TIME_WITH_SYS_TIME
3948#include <sys/time.h>
3949#include <time.h>
3950#else
3951#if HAVE_SYS_TIME_H
3952#include <sys/time.h>
3953#else
3954#include <time.h>
3955#endif
3956#endif
3957
3958static int ListFullDetail = S_FALSE;
3959static int ListWithDelimiter = S_FALSE;
3960static char * ListFile = NULL;
3961
3962int set_list_file (const char * c)
3963{
3964 ListFile = sh_util_strdup(c);
3965 return 0;
3966}
3967
3968int set_full_detail (const char * c)
3969{
3970 (void) c;
3971 ListFullDetail = S_TRUE;
3972 return 0;
3973}
3974
3975int set_list_delimited (const char * c)
3976{
3977 (void) c;
3978 ListFullDetail = S_TRUE;
3979 ListWithDelimiter = S_TRUE;
3980 return 0;
3981}
3982
3983/* Always quote the string, except if it is empty. Quote quotes by
3984 * doubling them.
3985 */
3986char * csv_escape(const char * str)
3987{
3988 const char * p = str;
3989 const char * q;
3990
3991 size_t size = 0;
3992 size_t flag_quote = 0;
3993
3994 char * new;
3995 char * pnew;
3996
3997 if (p)
3998 {
3999
4000 while (*p)
4001 {
4002 if (*p == '"')
4003 ++flag_quote;
4004
4005 ++size; ++p;
4006 }
4007
4008 if (sl_ok_adds(size, flag_quote))
4009 size += flag_quote; /* double each quote */
4010 else
4011 return NULL;
4012
4013 if (sl_ok_adds(size, 3))
4014 size += 3; /* two quotes and terminating null */
4015 else
4016 return NULL;
4017
4018 new = SH_ALLOC(size);
4019
4020 if (flag_quote != 0)
4021 {
4022 new[0] = '"';
4023 pnew = &new[1];
4024 q = str;
4025 while (*q)
4026 {
4027 *pnew = *q;
4028 if (*pnew == '"')
4029 {
4030 ++pnew; *pnew = '"';
4031 }
4032 ++pnew; ++q;
4033 }
4034 *pnew = '"'; ++pnew;
4035 *pnew = '\0';
4036 }
4037 else
4038 {
4039 if (size > 3)
4040 {
4041 new[0] = '"';
4042 sl_strlcpy (&new[1], str, size-1);
4043 new[size-2] = '"';
4044 new[size-1] = '\0';
4045 }
4046 else
4047 {
4048 new[0] = '\0';
4049 }
4050 }
4051
4052 return new;
4053 }
4054 return NULL;
4055}
4056
4057int isHexKey(char * s)
4058{
4059 int i;
4060
4061 for (i = 0; i < KEY_LEN; ++i)
4062 {
4063 if (*s)
4064 {
4065 if ((*s >= '0' && *s <= '9') ||
4066 (*s >= 'A' && *s <= 'F') ||
4067 (*s >= 'a' && *s <= 'f'))
4068 {
4069 ++s;
4070 continue;
4071 }
4072 }
4073 return S_FALSE;
4074 }
4075 return S_TRUE;
4076}
4077
4078#include "sh_checksum.h"
4079
4080static char * KEYBUFtolower (char * s, char * result)
4081{
4082 char * r = result;
4083 if (s)
4084 {
4085 for (; *s; ++s)
4086 {
4087 *r = tolower((unsigned char) *s); ++r;
4088 }
4089 *r = '\0';
4090 }
4091 return result;
4092}
4093
4094void sh_hash_list_db_entry_full_detail (sh_file_t * p)
4095{
4096 char * tmp;
4097 char * esc;
4098 char str[81];
4099 char hexdigest[SHA256_DIGEST_STRING_LENGTH];
4100 char keybuffer[KEYBUF_SIZE];
4101
4102 if (ListWithDelimiter == S_TRUE)
4103 {
4104 printf(_("%7ld, %7ld, %10s, %5d, %12s, %5d, %3d, %-8s, %5d, %-8s, %5d, "),
4105 (unsigned long) p->theFile.ino, (unsigned long) p->theFile.dev,
4106 p->theFile.c_mode, (int) p->theFile.mode,
4107 p->theFile.c_attributes, (int) p->theFile.attributes,
4108 (int) p->theFile.hardlinks,
4109 p->theFile.c_owner, (int) p->theFile.owner,
4110 p->theFile.c_group, (int) p->theFile.group);
4111 }
4112 else
4113 {
4114 printf(_("%7ld %7ld %10s %5d %12s %5d %3d %-8s %5d %-8s %5d "),
4115 (unsigned long) p->theFile.ino, (unsigned long) p->theFile.dev,
4116 p->theFile.c_mode, (int) p->theFile.mode,
4117 p->theFile.c_attributes, (int) p->theFile.attributes,
4118 (int) p->theFile.hardlinks,
4119 p->theFile.c_owner, (int) p->theFile.owner,
4120 p->theFile.c_group, (int) p->theFile.group);
4121 }
4122
4123 if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0])
4124 sl_snprintf(str, sizeof(str), "%"PRIu64, p->theFile.rdev);
4125 else
4126 sl_snprintf(str, sizeof(str), "%"PRIu64, p->theFile.size);
4127
4128 printf( _(" %8s"), str);
4129 if (ListWithDelimiter == S_TRUE)
4130 putchar(',');
4131
4132 printf( _(" %s"), sh_unix_gmttime (p->theFile.ctime, str, sizeof(str)));
4133 if (ListWithDelimiter == S_TRUE)
4134 putchar(',');
4135 printf( _(" %s"), sh_unix_gmttime (p->theFile.mtime, str, sizeof(str)));
4136 if (ListWithDelimiter == S_TRUE)
4137 putchar(',');
4138 printf( _(" %s"), sh_unix_gmttime (p->theFile.atime, str, sizeof(str)));
4139 if (ListWithDelimiter == S_TRUE)
4140 putchar(',');
4141
4142 if (isHexKey(p->theFile.checksum))
4143 printf( _(" %s"), KEYBUFtolower(p->theFile.checksum, keybuffer));
4144 else
4145 printf( _(" %s"), SHA256_Base2Hex(p->theFile.checksum, hexdigest));
4146 if (ListWithDelimiter == S_TRUE)
4147 putchar(',');
4148
4149 tmp = sh_util_safe_name(p->fullpath);
4150 if (ListWithDelimiter != S_TRUE)
4151 {
4152 printf( _(" %s"), tmp);
4153 }
4154 else
4155 {
4156 esc = csv_escape(tmp);
4157 printf( _(" %s,"), (esc != NULL) ? esc : _("(null)"));
4158 if (esc)
4159 SH_FREE(esc);
4160 }
4161 SH_FREE(tmp);
4162
4163 if ('l' == p->theFile.c_mode[0])
4164 {
4165 tmp = sh_util_safe_name(p->linkpath);
4166 if (ListWithDelimiter != S_TRUE)
4167 {
4168 printf(_(" -> %s"), tmp);
4169 }
4170 else
4171 {
4172 esc = csv_escape(tmp);
4173 printf( _(" %s,"), (esc != NULL) ? esc : _("(null)"));
4174 if (esc)
4175 SH_FREE(esc);
4176 }
4177 SH_FREE(tmp);
4178 }
4179
4180 if (p->attr_string)
4181 {
4182 tmp = sh_util_safe_name(p->attr_string);
4183 if (ListWithDelimiter != S_TRUE)
4184 {
4185 printf(_(" %s"), tmp);
4186 }
4187 else
4188 {
4189 esc = csv_escape(tmp);
4190 printf( _(" %s"), (esc != NULL) ? esc : _("(null)"));
4191 if (esc)
4192 SH_FREE(esc);
4193 }
4194 SH_FREE(tmp);
4195 }
4196 else
4197 {
4198 if (ListWithDelimiter == S_TRUE)
4199 printf("%s",_(" no_attr"));
4200 }
4201 putchar('\n');
4202
4203 return;
4204}
4205
4206void sh_hash_list_db_entry (sh_file_t * p)
4207{
4208 char nowtime[128];
4209 char thetime[128];
4210 char * tmp;
4211 time_t now = time(NULL);
4212 time_t then = (time_t) p->theFile.mtime;
4213
4214#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
4215 struct tm * time_ptr;
4216 struct tm time_tm;
4217
4218 time_ptr = gmtime_r(&then, &time_tm);
4219 strftime(thetime, 127, _("%b %d %Y"), time_ptr);
4220 time_ptr = gmtime_r(&now, &time_tm);
4221 strftime(nowtime, 127, _("%b %d %Y"), time_ptr);
4222 if (0 == strncmp(&nowtime[7], &thetime[7], 4))
4223 {
4224 time_ptr = gmtime_r(&then, &time_tm);
4225 strftime(thetime, 127, _("%b %d %H:%M"), time_ptr);
4226 }
4227#else
4228 strftime(thetime, 127, _("%b %d %Y"), gmtime(&then));
4229 strftime(nowtime, 127, _("%b %d %Y"), gmtime(&now));
4230 if (0 == strncmp(&nowtime[7], &thetime[7], 4))
4231 strftime(thetime, 127, _("%b %d %H:%M"), gmtime(&then));
4232#endif
4233
4234 tmp = sh_util_safe_name(p->fullpath);
4235 if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0])
4236 printf(_("%10s %3d %-8s %-8s %3d,%4d %s %s"),
4237 p->theFile.c_mode, (int) p->theFile.hardlinks,
4238 p->theFile.c_owner, p->theFile.c_group,
4239 (int) major((dev_t)p->theFile.rdev),
4240 (int) minor((dev_t)p->theFile.rdev),
4241 thetime,
4242 tmp);
4243 else
4244 printf(_("%10s %3d %-8s %-8s %8ld %s %s"),
4245 p->theFile.c_mode, (int) p->theFile.hardlinks,
4246 p->theFile.c_owner, p->theFile.c_group, (long) p->theFile.size,
4247 thetime,
4248 tmp);
4249 SH_FREE(tmp);
4250
4251 if ('l' == p->theFile.c_mode[0])
4252 {
4253 tmp = sh_util_safe_name(p->linkpath);
4254 printf(_(" -> %s\n"), tmp);
4255 SH_FREE(tmp);
4256 }
4257 else
4258 printf("\n");
4259
4260 return;
4261}
4262
4263#ifdef HAVE_LIBZ
4264#include <zlib.h>
4265#endif
4266
4267int sh_hash_printcontent(char * linkpath)
4268{
4269#ifdef HAVE_LIBZ
4270 unsigned char * decoded;
4271 unsigned char * decompressed = NULL;
4272 size_t dlen;
4273 unsigned long clen;
4274 unsigned long clen_o;
4275 int res;
4276
4277 if (linkpath && *linkpath != '-')
4278 {
4279 dlen = sh_util_base64_dec_alloc (&decoded,
4280 (unsigned char *)linkpath,
4281 strlen(linkpath));
4282
4283 clen = dlen * 2 + 1;
4284
4285 do {
4286 if (decompressed)
4287 SH_FREE(decompressed);
4288 clen += dlen; clen_o = clen;
4289 decompressed = SH_ALLOC(clen);
4290 res = uncompress(decompressed, &clen, decoded, dlen);
4291 if (res == Z_MEM_ERROR)
4292 { fprintf(stderr, "%s",_("Error: Not enough memory\n")); return -1; }
4293 if (res == Z_DATA_ERROR)
4294 { fprintf(stderr, "%s",_("Error: Data corrupt or incomplete\n")); return -1; }
4295 } while (res == Z_BUF_ERROR || clen == clen_o);
4296
4297 decompressed[clen] = '\0';
4298 fputs( (char*) decompressed, stdout);
4299 SH_FREE(decompressed);
4300 return 0;
4301 }
4302#else
4303 (void) linkpath;
4304#endif
4305 fprintf(stderr, "%s",_("Error: No data available\n"));
4306 return -1;
4307}
4308
4309int sh_hash_list_db (const char * db_file)
4310{
4311 sh_file_t * p;
4312 SL_TICKET fd;
4313 char * line;
4314 int flag = 0;
4315
4316 if (!db_file)
4317 {
4318 _exit(EXIT_FAILURE);
4319 return -1;
4320 }
4321 if (sl_is_suid())
4322 {
4323 fprintf(stderr, "%s",_("ERROR: insufficient privilege\n"));
4324 _exit (EXIT_FAILURE);
4325 return -1; /* for Mac OSX compiler */
4326 }
4327 if (0 == strcmp(db_file, _("default")))
4328 db_file = file_path('D', 'W');
4329 if (!db_file)
4330 {
4331 _exit(EXIT_FAILURE);
4332 return -1;
4333 }
4334
4335 line = SH_ALLOC(MAX_PATH_STORE+2);
4336
4337 if ( SL_ISERROR(fd = sl_open_read(FIL__, __LINE__, db_file, SL_YESPRIV)))
4338 {
4339 fprintf(stderr, _("ERROR: can't open %s for read (errnum = %ld)\n"),
4340 db_file, fd);
4341 _exit(EXIT_FAILURE);
4342 return -1;
4343 }
4344
4345 /* fast forward to start of data
4346 */
4347 sh_hash_setdataent(fd, line, MAX_PATH_STORE+1, db_file);
4348
4349 while (1)
4350 {
4351 p = sh_hash_getdataent (fd, line, MAX_PATH_STORE+1);
4352 if ((p != NULL) && (p->fullpath[0] == '/'))
4353 {
4354 if (!ListFile)
4355 {
4356 flag = 1;
4357 if (ListFullDetail == S_FALSE)
4358 sh_hash_list_db_entry (p);
4359 else
4360 sh_hash_list_db_entry_full_detail (p);
4361 }
4362 else
4363 {
4364 if (0 != sl_strcmp(ListFile, p->fullpath))
4365 {
4366 continue;
4367 }
4368 flag = 1;
4369 if ('l' != p->theFile.c_mode[0])
4370 {
4371 if (sh_hash_printcontent(p->linkpath) < 0)
4372 {
4373 _exit(EXIT_FAILURE);
4374 return -1;
4375 }
4376 }
4377 else
4378 {
4379 fprintf(stderr, "%s",_("File is a link\n"));
4380 _exit(EXIT_FAILURE);
4381 return -1;
4382 }
4383 break;
4384 }
4385 }
4386 else if (p == NULL)
4387 {
4388 break;
4389 }
4390 }
4391
4392 if (line != NULL)
4393 SH_FREE(line);
4394 sl_close (fd);
4395
4396 fflush(NULL);
4397
4398 if (flag == 0)
4399 {
4400 fprintf(stderr, "%s",_("File not found\n"));
4401 _exit(EXIT_FAILURE);
4402 }
4403 _exit(EXIT_SUCCESS);
4404 return 0;
4405}
4406
4407/* if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
4408#endif
Note: See TracBrowser for help on using the repository browser.