source: branches/samhain_3_1/src/sh_hash.c@ 576

Last change on this file since 576 was 474, checked in by katerina, 10 years ago

Fix for ticket #372 (Replace obsolete smatch by clang in test suite).

File size: 106.4 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 1999, 2000, 2001, 2002 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22/* 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 if ( sh.flag.checkSum == SH_CHECK_INIT )
1329 {
1330 dlog(1, FIL__, __LINE__,
1331 _("Attempt to load the baseline database during initialisation. This is an internal error, please report it to the developer.\n"));
1332 SH_ABORT;
1333 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1334 }
1335
1336 SH_MUTEX_LOCK(mutex_hash);
1337
1338 if (IsInit == 1)
1339 {
1340 goto unlock_and_return;
1341 }
1342
1343 fd = (-1);
1344
1345#if defined(SH_WITH_CLIENT)
1346
1347 /* Data file from Server
1348 */
1349
1350 if (fd == (-1) && 0 == sl_strcmp(file_path('D', 'R'), _("REQ_FROM_SERVER")))
1351 {
1352 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_D_DSTART);
1353 fd = sh_forward_req_file(_("DATA"));
1354 if (SL_ISERROR(fd))
1355 {
1356 dlog(1, FIL__, __LINE__,
1357 _("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);
1358 sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_EXIT_ABORT1,
1359 sh.prg_name);
1360 retval = 1; exitval = EXIT_FAILURE;
1361 goto unlock_and_return;
1362 }
1363 sl_rewind (fd);
1364
1365 sl_strlcpy (sh.data.hash,
1366 sh_tiger_hash (file_path('D', 'R'),
1367 fd, TIGER_NOLIM, hashbuf, sizeof(hashbuf)),
1368 KEY_LEN+1);
1369 sl_rewind (fd);
1370 }
1371 else
1372#endif
1373 /* Local data file
1374 */
1375
1376 if (fd == (-1))
1377 {
1378 if ( SL_ISERROR(fd = sl_open_read(FIL__, __LINE__,
1379 file_path('D', 'R'), SL_YESPRIV)))
1380 {
1381 TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s>\n"),
1382 file_path('D', 'R')));
1383 dlog(1, FIL__, __LINE__,
1384 _("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"),
1385 sl_get_errmsg(), fd, (int) sl_ret_euid());
1386 sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_EXIT_ABORT1,
1387 sh.prg_name);
1388 retval = 1; exitval = EXIT_FAILURE;
1389 goto unlock_and_return;
1390 }
1391
1392 TPT(( 0, FIL__, __LINE__, _("msg=<Opened database: %s>\n"),
1393 file_path('D', 'R')));
1394
1395 if (0 != sl_strncmp(sh.data.hash,
1396 sh_tiger_hash (file_path('D', 'R'), fd, TIGER_NOLIM,
1397 hashbuf, sizeof(hashbuf)),
1398 KEY_LEN)
1399 && sh.flag.checkSum != SH_CHECK_INIT)
1400 {
1401 dlog(1, FIL__, __LINE__,
1402 _("The checksum of the file signature database has changed since startup: %s -> %s\n"),
1403 sh.data.hash, sh_tiger_hash (file_path('D', 'R'), fd, TIGER_NOLIM,
1404 hashbuf, sizeof(hashbuf)));
1405 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_AUTH,
1406 ( (NULL == file_path('D', 'R')) ? _("(null)") :
1407 file_path('D', 'R') )
1408 );
1409 retval = 1; exitval = EXIT_FAILURE;
1410 goto unlock_and_return;
1411 }
1412 sl_rewind (fd);
1413
1414 } /* new 1.4.8 */
1415
1416 if (sig_termfast == 1) /* SIGTERM */
1417 {
1418 TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
1419 --sig_raised; --sig_urgent;
1420 retval = 1; exitval = EXIT_SUCCESS;
1421 goto unlock_and_return;
1422 }
1423
1424#if defined(WITH_GPG) || defined(WITH_PGP)
1425
1426 /* extract the data and copy to temporary file
1427 */
1428 fdTmp = sh_gpg_extract_signed(fd);
1429
1430 if (sig_termfast == 1) /* SIGTERM */
1431 {
1432 TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
1433 --sig_raised; --sig_urgent;
1434 retval = 1; exitval = EXIT_SUCCESS;
1435 goto unlock_and_return;
1436 }
1437
1438 sl_close(fd);
1439 fd = fdTmp;
1440
1441 /* Validate signature of open file.
1442 */
1443 if (0 != sh_gpg_check_sign (0, fd, 2))
1444 {
1445 retval = 1; exitval = EXIT_FAILURE;
1446 goto unlock_and_return;
1447 }
1448 sl_rewind (fd);
1449#endif
1450
1451 line = SH_ALLOC(MAX_PATH_STORE+2);
1452
1453 /* fast forward to start of data
1454 */
1455 sh_hash_setdataent(fd, line, MAX_PATH_STORE+1, file_path('D', 'R'));
1456
1457 for (i = 0; i < TABSIZE; ++i)
1458 tab[i] = NULL;
1459
1460 while (1)
1461 {
1462 if (sig_termfast == 1) /* SIGTERM */
1463 {
1464 TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
1465 --sig_raised; --sig_urgent;
1466 retval = 1; exitval = EXIT_SUCCESS;
1467 SH_FREE(line);
1468 line = NULL;
1469 goto unlock_and_return;
1470 }
1471
1472 p = sh_hash_getdataent (fd, line, MAX_PATH_STORE+1);
1473 if (p != NULL)
1474 {
1475 hashinsert (p);
1476 ++count;
1477 }
1478 else
1479 break;
1480 }
1481
1482 /* Initialization completed.
1483 */
1484 IsInit = 1;
1485
1486 if (line != NULL)
1487 SH_FREE(line);
1488
1489 /* Always keep db in memory, so we have no open file
1490 */
1491 sl_close (fd);
1492 sh_hash_getline_end();
1493 /* fd = -1; */
1494
1495 unlock_and_return:
1496 ; /* 'label at end of compound statement */
1497 SH_MUTEX_UNLOCK(mutex_hash);
1498 if (retval == 0)
1499 {
1500 SL_RET0(_("sh_hash_init"));
1501 }
1502 aud_exit (FIL__, __LINE__, exitval);
1503}
1504
1505/*****************************************************************
1506 *
1507 * delete hash array
1508 *
1509 *****************************************************************/
1510void sh_hash_hashdelete ()
1511{
1512 int i;
1513
1514 SL_ENTER(_("sh_hash_hashdelete"));
1515
1516 /* need deadlock detection here if called from exit handler
1517 */
1518 SH_MUTEX_TRYLOCK(mutex_hash);
1519
1520 if (IsInit == 0)
1521 goto unlock_and_exit;
1522
1523 for (i = 0; i < TABSIZE; ++i)
1524 if (tab[i] != NULL)
1525 {
1526 hash_kill (tab[i]);
1527 tab[i] = NULL;
1528 }
1529 IsInit = 0;
1530
1531 unlock_and_exit:
1532 ; /* 'label at end of compound statement */
1533 SH_MUTEX_TRYLOCK_UNLOCK(mutex_hash);
1534
1535 SL_RET0(_("sh_hash_hashdelete"));
1536}
1537
1538/******************************************************************
1539 *
1540 * Insert a file into the database.
1541 *
1542 ******************************************************************/
1543static int pushdata_isfirst = 1;
1544static SL_TICKET pushdata_fd = -1;
1545
1546static int pushdata_stdout = S_FALSE;
1547
1548static char * sh_db_version_string = NULL;
1549
1550int sh_hash_pushdata_stdout (const char * str)
1551{
1552 if (!str)
1553 { pushdata_stdout = S_TRUE; return 0; }
1554 return -1;
1555}
1556
1557int sh_hash_version_string(const char * str)
1558{
1559 if (str)
1560 {
1561 if (sh_db_version_string != NULL) {
1562 SH_FREE(sh_db_version_string);
1563 }
1564 if (0 == sl_strncmp(str, _("NULL"), 4))
1565 {
1566 sh_db_version_string = NULL;
1567 return 0;
1568 }
1569 sh_db_version_string = sh_util_strdup(str);
1570 return 0;
1571 }
1572 return -1;
1573}
1574
1575static int sh_loosedircheck = S_FALSE;
1576
1577int sh_hash_loosedircheck(const char * str)
1578{
1579 return sh_util_flagval(str, &sh_loosedircheck);
1580}
1581
1582
1583static void sh_hash_pushdata_int (file_type * buf, char * fileHash)
1584{
1585 static long p_count = 0;
1586
1587 int status = 0;
1588
1589 char * tmp;
1590 size_t tmp_len = 0;
1591 size_t old_len = 0;
1592 size_t path_len = 0;
1593
1594 sh_filestore_t p;
1595
1596 struct stat sbuf;
1597
1598 char * fullpath = NULL;
1599 char * linkpath = NULL;
1600 char * attr_string = NULL;
1601
1602 char * line = NULL;
1603
1604 char timestring[81];
1605
1606#if !defined(__linux__) && !defined(HAVE_STAT_FLAGS)
1607 int i;
1608#endif
1609
1610 SL_ENTER(_("sh_hash_pushdata_int"));
1611
1612 fullpath = SH_ALLOC(MAX_PATH_STORE+1);
1613 linkpath = SH_ALLOC(MAX_PATH_STORE+1);
1614
1615 linkpath[0] = '-';
1616 linkpath[1] = '\0';
1617 fullpath[0] = '-';
1618 fullpath[1] = '\0';
1619
1620 if (!buf) {
1621 memset(&p, '\0', sizeof(sh_filestore_t));
1622 }
1623
1624 if ((pushdata_stdout == S_TRUE) && (sh.flag.update == S_TRUE))
1625 {
1626 dlog(1, FIL__, __LINE__,
1627 _("You cannot write the database to stdout when you use update rather than init.\n"));
1628 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
1629 _("Writing database to stdout with update"),
1630 sh.prg_name,
1631 _("sh_hash_pushdata_int"));
1632 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1633 }
1634
1635 if ((pushdata_stdout == S_TRUE) && (sl_is_suid()))
1636 {
1637 dlog(1, FIL__, __LINE__,
1638 _("You cannot write the database to stdout when running with suid privileges.\n"));
1639 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
1640 _("Writing database to stdout when suid"),
1641 sh.prg_name,
1642 _("sh_hash_pushdata_int"));
1643 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1644 }
1645
1646
1647 if ((pushdata_isfirst == 1) && (pushdata_stdout == S_FALSE) &&
1648 ( (NULL == file_path('D', 'W')) ||
1649 (0 == sl_strcmp(file_path('D', 'W'), _("REQ_FROM_SERVER"))) ))
1650 {
1651 dlog(1, FIL__, __LINE__,
1652 _("You need to configure a local path for initializing the database\nlike ./configure --with-data-file=REQ_FROM_SERVER/some/local/path\n"));
1653 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
1654 _("No local path for database specified"),
1655 sh.prg_name,
1656 _("sh_hash_pushdata_int"));
1657 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1658 }
1659
1660
1661 if ((pushdata_isfirst == 1) && (pushdata_stdout == S_FALSE))
1662 {
1663 /* Warn that file already exists; file_path != NULL here because
1664 * checked above
1665 */
1666 if (0 == retry_lstat(FIL__, __LINE__, file_path('D', 'W'), &sbuf))
1667 {
1668 if (sh.flag.update == S_FALSE)
1669 {
1670 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_FI_DBEX,
1671 file_path('D', 'W'));
1672 }
1673 }
1674 }
1675
1676
1677 if (sh.flag.update == S_FALSE)
1678 {
1679 if (pushdata_stdout == S_FALSE && pushdata_fd == -1)
1680 {
1681 if ( SL_ISERROR(pushdata_fd = sl_open_write(FIL__, __LINE__,
1682 file_path('D', 'W'),
1683 SL_YESPRIV)))
1684 {
1685 SH_FREE(fullpath);
1686 SH_FREE(linkpath);
1687 sh_error_handle((-1), FIL__, __LINE__, pushdata_fd, MSG_E_ACCESS,
1688 geteuid(), file_path('D', 'W'));
1689 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1690 }
1691
1692 if (SL_ISERROR(status = sl_lock (pushdata_fd)))
1693 {
1694 SH_FREE(fullpath);
1695 SH_FREE(linkpath);
1696 sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
1697 _("Failed to lock baseline database"), _("sh_hash_pushdata_int"),
1698 file_path('D', 'W'));
1699 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1700 }
1701
1702 if ( SL_ISERROR(status = sl_forward(pushdata_fd)))
1703 {
1704 SH_FREE(fullpath);
1705 SH_FREE(linkpath);
1706 sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
1707 _("Failed to seek to end of baseline database"),
1708 _("sh_hash_pushdata_int"),
1709 file_path('D', 'W'));
1710 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1711 }
1712 }
1713 }
1714 else /* update == TRUE */
1715 {
1716 if (pushdata_isfirst == 1)
1717 {
1718 TPT((0, FIL__, __LINE__, _("msg=<Update.>\n")))
1719 if ( SL_ISERROR(pushdata_fd = sl_open_rdwr(FIL__, __LINE__,
1720 file_path('D', 'W'),
1721 SL_YESPRIV))){
1722 SH_FREE(fullpath);
1723 SH_FREE(linkpath);
1724 sh_error_handle((-1), FIL__, __LINE__, pushdata_fd, MSG_E_ACCESS,
1725 geteuid(), file_path('D', 'W'));
1726 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1727 }
1728
1729 if (SL_ISERROR(status = sl_lock (pushdata_fd)))
1730 {
1731 SH_FREE(fullpath);
1732 SH_FREE(linkpath);
1733 sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
1734 _("Failed to lock baseline database"), _("sh_hash_pushdata_int"),
1735 file_path('D', 'W'));
1736 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1737 }
1738
1739 line = SH_ALLOC(MAX_PATH_STORE+1);
1740 if (SL_ISERROR(sh_hash_setdataent_old (pushdata_fd, line,
1741 MAX_PATH_STORE,
1742 file_path('D', 'W'))))
1743 {
1744 SH_FREE(fullpath);
1745 SH_FREE(linkpath);
1746 SH_FREE(line);
1747 aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1748 }
1749 SH_FREE(line);
1750 }
1751 }
1752
1753 if (buf != NULL) {
1754
1755 old_len = sl_strlen(buf->fullpath);
1756#if defined(SH_STEALTH)
1757 sh_do_encode(buf->fullpath, old_len);
1758#endif
1759 tmp = quote_string(buf->fullpath, old_len);
1760 tmp_len = sl_strlen(tmp);
1761#if defined(SH_STEALTH)
1762 sh_do_decode(buf->fullpath, old_len);
1763#endif
1764
1765 if (tmp && tmp_len <= MAX_PATH_STORE)
1766 {
1767 sl_strlcpy(fullpath, buf->fullpath, MAX_PATH_STORE+1);
1768 }
1769 else
1770 {
1771 char hashbuf[KEYBUF_SIZE];
1772
1773 sl_strlcpy(fullpath,
1774 sh_tiger_hash (buf->fullpath,
1775 TIGER_DATA, old_len,
1776 hashbuf, sizeof(hashbuf)),
1777 KEY_LEN+1);
1778 }
1779 if (tmp) SH_FREE(tmp);
1780 }
1781
1782 path_len = sl_strlen(fullpath);
1783#if defined(SH_STEALTH)
1784 sh_do_encode(fullpath, path_len);
1785#endif
1786
1787 tmp = quote_string(fullpath, path_len);
1788 if (tmp) {
1789 sl_strlcpy(fullpath, tmp, MAX_PATH_STORE+1);
1790 SH_FREE(tmp);
1791 }
1792
1793 /* NOTE: TXT entries are c_mode[0] != 'l' and do not get decoded
1794 */
1795 if (buf != NULL /* && buf->c_mode[0] == 'l' */ && buf->link_path != NULL)
1796 {
1797
1798 old_len = sl_strlen(buf->link_path);
1799#if defined(SH_STEALTH)
1800 if (buf->c_mode[0] == 'l')
1801 sh_do_encode(buf->link_path, old_len);
1802#endif
1803 tmp = quote_string(buf->link_path, old_len);
1804 tmp_len = sl_strlen(tmp);
1805#if defined(SH_STEALTH)
1806 if (buf->c_mode[0] == 'l')
1807 sh_do_decode(buf->link_path, old_len);
1808#endif
1809
1810 if (tmp && tmp_len <= MAX_PATH_STORE)
1811 {
1812 sl_strlcpy(linkpath, buf->link_path, MAX_PATH_STORE+1);
1813 }
1814 else
1815 {
1816 char hashbuf[KEYBUF_SIZE];
1817 sl_strlcpy(linkpath,
1818 sh_tiger_hash (buf->link_path,
1819 TIGER_DATA, old_len,
1820 hashbuf, sizeof(hashbuf)),
1821 KEY_LEN+1);
1822 }
1823 if (tmp) SH_FREE(tmp);
1824
1825 path_len = sl_strlen(linkpath);
1826#if defined(SH_STEALTH)
1827 if (buf->c_mode[0] == 'l')
1828 sh_do_encode(linkpath, path_len);
1829#endif
1830 tmp = quote_string(linkpath, path_len);
1831 if (tmp)
1832 {
1833 sl_strlcpy(linkpath, tmp, MAX_PATH_STORE+1);
1834 SH_FREE(tmp);
1835 }
1836 }
1837
1838 if (buf != NULL && buf->attr_string != NULL)
1839 {
1840 old_len = sl_strlen(buf->attr_string);
1841#if defined(SH_STEALTH)
1842 sh_do_encode(buf->attr_string, old_len);
1843#endif
1844 tmp = quote_string(buf->attr_string, old_len);
1845 if (tmp)
1846 {
1847 attr_string = tmp;
1848 tmp = NULL;
1849 }
1850#if defined(SH_STEALTH)
1851 sh_do_decode(buf->attr_string, old_len);
1852#endif
1853 }
1854
1855
1856 if (buf != NULL) {
1857 p.mark = REC_MAGIC;
1858 if (attr_string)
1859 p.mark |= REC_FLAGS_ATTR;
1860 sl_strlcpy(p.c_mode, buf->c_mode, CMODE_SIZE);
1861 sl_strlcpy(p.c_group, buf->c_group, GROUP_MAX+1);
1862 sl_strlcpy(p.c_owner, buf->c_owner, USER_MAX+1);
1863 if (fileHash) {
1864 sl_strlcpy(p.checksum, fileHash, KEY_LEN+1);
1865 }
1866#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1867 sl_strlcpy(p.c_attributes, buf->c_attributes, ATTRBUF_SIZE);
1868#else
1869 for (i = 0; i < ATTRBUF_USED; ++i) p.c_attributes[i] = '-';
1870 p.c_attributes[ATTRBUF_USED] = '\0';
1871#endif
1872
1873#if defined(SH_STEALTH)
1874 sh_do_encode(p.c_mode, sl_strlen(p.c_mode));
1875 sh_do_encode(p.c_owner, sl_strlen(p.c_owner));
1876 sh_do_encode(p.c_group, sl_strlen(p.c_group));
1877 sh_do_encode(p.checksum, sl_strlen(p.checksum));
1878
1879 sh_do_encode(p.c_attributes, sl_strlen(p.c_attributes));
1880#endif
1881
1882#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1883 p.attributes = (UINT32) buf->attributes;
1884#else
1885 p.attributes = 0;
1886#endif
1887 p.linkmode = (UINT32) buf->linkmode;
1888 p.hardlinks = (UINT32) buf->hardlinks;
1889 p.dev = (UINT64) buf->dev;
1890 p.rdev = (UINT64) buf->rdev;
1891 p.mode = (UINT32) buf->mode;
1892 p.ino = (UINT32) buf->ino;
1893 p.size = (UINT64) buf->size;
1894 p.mtime = (UINT64) buf->mtime;
1895 p.atime = (UINT64) buf->atime;
1896 p.ctime = (UINT64) buf->ctime;
1897 p.owner = (UINT32) buf->owner;
1898 p.group = (UINT32) buf->group;
1899
1900 swap_32(&(p.mode));
1901 swap_32(&(p.linkmode));
1902 swap_64(&(p.dev));
1903 swap_64(&(p.rdev));
1904 swap_32(&(p.hardlinks));
1905 swap_32(&(p.ino));
1906 swap_64(&(p.size));
1907 swap_64(&(p.atime));
1908 swap_64(&(p.mtime));
1909 swap_64(&(p.ctime));
1910 swap_32(&(p.owner));
1911 swap_32(&(p.group));
1912 swap_32(&(p.attributes));
1913
1914#ifdef OLD_BUG
1915 swap_short(&(p.mark));
1916#else
1917 p.mark = *(swap_short(&(p.mark)));
1918#endif
1919 }
1920
1921 /* write the start marker
1922 */
1923 if (pushdata_isfirst == 1)
1924 {
1925 if (sh.flag.update == S_FALSE)
1926 {
1927 if (sh_db_version_string != NULL)
1928 {
1929 if (pushdata_stdout == S_FALSE)
1930 {
1931 sl_write (pushdata_fd, _("\n#Host "), 7);
1932 sl_write (pushdata_fd, sh.host.name,
1933 sl_strlen(sh.host.name));
1934 sl_write (pushdata_fd, _(" Version "), 9);
1935 sl_write (pushdata_fd, sh_db_version_string,
1936 sl_strlen(sh_db_version_string));
1937 sl_write (pushdata_fd, _(" Date "), 6);
1938 (void) sh_unix_time(0, timestring, sizeof(timestring));
1939 sl_write (pushdata_fd, timestring, strlen(timestring));
1940 sl_write (pushdata_fd, "\n", 1);
1941 } else {
1942 printf ("%s",_("\n#Host "));
1943 printf ("%s", sh.host.name);
1944 printf ("%s",_(" Version "));
1945 printf ("%s", sh_db_version_string);
1946 printf ("%s",_(" Date "));
1947 (void) sh_unix_time(0, timestring, sizeof(timestring));
1948 printf ("%s\n", timestring);
1949 }
1950 }
1951
1952 if (pushdata_stdout == S_FALSE)
1953 {
1954#if defined(SH_STEALTH)
1955 sl_write (pushdata_fd, "\n", 1);
1956 sl_write_line (pushdata_fd, N_("[SOF]"), 5);
1957#else
1958 sl_write_line (pushdata_fd, _("\n[SOF]"), 6);
1959#endif
1960 }
1961 else
1962 {
1963#if defined(SH_STEALTH)
1964 printf ("\n%s\n", N_("[SOF]"));
1965#else
1966 printf ("%s\n", _("\n[SOF]"));
1967#endif
1968 }
1969 }
1970 pushdata_isfirst = 0;
1971 }
1972
1973 if (pushdata_stdout == S_FALSE)
1974 {
1975 sl_write (pushdata_fd, &p, sizeof(sh_filestore_t));
1976 sl_write_line_fast (pushdata_fd, fullpath, sl_strlen(fullpath));
1977 sl_write_line_fast (pushdata_fd, linkpath, sl_strlen(linkpath));
1978 if (attr_string)
1979 sl_write_line_fast (pushdata_fd, attr_string, sl_strlen(attr_string));
1980 } else {
1981 if (fwrite (&p, sizeof(sh_filestore_t), 1, stdout))
1982 {
1983 printf ("%s\n", fullpath);
1984 printf ("%s\n", linkpath);
1985 if (attr_string)
1986 printf ("%s\n", attr_string);
1987 }
1988 else
1989 {
1990 perror(_("Error writing database"));
1991 aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1992 }
1993 }
1994
1995 ++p_count;
1996
1997 if ((sh.flag.update != S_TRUE) && (pushdata_stdout == S_FALSE))
1998 {
1999 if (sh.flag.checkSum != SH_CHECK_INIT || (buf == NULL && fileHash == NULL))
2000 {
2001 sl_close (pushdata_fd);
2002 pushdata_fd = -1;
2003 }
2004 }
2005
2006 SH_FREE(fullpath);
2007 SH_FREE(linkpath);
2008 if (attr_string)
2009 SH_FREE(attr_string);
2010
2011 SL_RET0(_("sh_hash_pushdata_int"));
2012}
2013
2014SH_MUTEX_STATIC(mutex_writeout,PTHREAD_MUTEX_INITIALIZER);
2015
2016void sh_hash_pushdata (file_type * buf, char * fileHash)
2017{
2018 SH_MUTEX_LOCK(mutex_writeout);
2019 sh_hash_pushdata_int (buf, fileHash);
2020 SH_MUTEX_UNLOCK(mutex_writeout);
2021 return;
2022}
2023
2024
2025int sh_hash_writeout()
2026{
2027 sh_file_t * p;
2028 int i;
2029 file_type * f;
2030 char fileHash[KEY_LEN + 1];
2031
2032 SL_ENTER(_("sh_hash_writeout"));
2033
2034 if (S_TRUE == file_is_remote())
2035 {
2036 sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGEN,
2037 _("Baseline database is remote"), _("sh_hash_writeout"));
2038 SL_RETURN (1, _("sh_hash_writeout"));
2039 }
2040
2041 SH_MUTEX_LOCK(mutex_writeout);
2042 if (!SL_ISERROR(pushdata_fd))
2043 {
2044 sl_close(pushdata_fd);
2045 pushdata_fd = -1;
2046 }
2047 pushdata_isfirst = 1;
2048
2049
2050 SH_MUTEX_LOCK(mutex_hash);
2051 for (i = 0; i < TABSIZE; ++i)
2052 {
2053 for (p = tab[i]; p; p = p->next)
2054 {
2055 f = sh_hash_create_ft (p, fileHash);
2056 sh_hash_pushdata_int (f, fileHash);
2057 if (f->attr_string) SH_FREE(f->attr_string);
2058 if (f->link_path) SH_FREE(f->link_path);
2059 SH_FREE(f);
2060 }
2061 }
2062 SH_MUTEX_UNLOCK(mutex_hash);
2063
2064 if (!SL_ISERROR(pushdata_fd))
2065 {
2066 sl_close(pushdata_fd);
2067 pushdata_fd = -1;
2068 }
2069 pushdata_isfirst = 1;
2070 SH_MUTEX_UNLOCK(mutex_writeout);
2071
2072 SL_RETURN (0, _("sh_hash_writeout"));
2073}
2074
2075
2076/*********************************************************************
2077 *
2078 * Check whether a file is present in the database.
2079 *
2080 *********************************************************************/
2081static sh_file_t * sh_hash_have_it_int (const char * newname)
2082{
2083 sh_file_t * p;
2084 char hashbuf[KEYBUF_SIZE];
2085
2086 SL_ENTER(_("sh_hash_have_it_int"));
2087
2088 if (newname == NULL)
2089 SL_RETURN( (NULL), _("sh_hash_have_it_int"));
2090
2091 if (sl_strlen(newname) <= MAX_PATH_STORE)
2092 p = hashsearch(newname);
2093 else
2094 p = hashsearch ( sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname),
2095 hashbuf, sizeof(hashbuf)) );
2096 if (p == NULL)
2097 SL_RETURN( (NULL), _("sh_hash_have_it_int"));
2098
2099 SL_RETURN( (p), _("sh_hash_have_it_int"));
2100}
2101
2102int sh_hash_have_it (const char * newname)
2103{
2104 sh_file_t * p;
2105 int retval;
2106
2107 if (IsInit != 1)
2108 sh_hash_init();
2109
2110 SH_MUTEX_LOCK(mutex_hash);
2111
2112 retval = 0;
2113
2114 p = sh_hash_have_it_int (newname);
2115
2116 if (!p)
2117 retval = (-1);
2118 else if ((!SH_FFLAG_ALLIGNORE_SET(p->fflags)) &&
2119 (p->modi_mask & MODI_CHK) != 0 &&
2120 (p->modi_mask & MODI_MOD) != 0)
2121 retval = 1;
2122 SH_MUTEX_UNLOCK(mutex_hash);
2123
2124 return retval;
2125}
2126
2127int sh_hash_get_it (const char * newname, file_type * tmpFile, char * fileHash)
2128{
2129 sh_file_t * p;
2130 int retval;
2131
2132 if (IsInit != 1)
2133 sh_hash_init();
2134
2135 tmpFile->link_path = NULL;
2136 tmpFile->attr_string = NULL;
2137
2138 SH_MUTEX_LOCK(mutex_hash);
2139
2140 retval = (-1);
2141
2142 p = sh_hash_have_it_int (newname);
2143 if (p)
2144 {
2145 sl_strlcpy(tmpFile->fullpath, p->fullpath, PATH_MAX);
2146 if (p->linkpath)
2147 tmpFile->link_path = sh_util_strdup (p->linkpath);
2148 tmpFile->size = p->theFile.size;
2149 tmpFile->mtime = p->theFile.mtime;
2150 tmpFile->ctime = p->theFile.ctime;
2151 tmpFile->atime = p->theFile.atime;
2152
2153 if (NULL != fileHash)
2154 sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
2155
2156 tmpFile->attr_string = NULL;
2157 retval = 0;
2158 }
2159 SH_MUTEX_UNLOCK(mutex_hash);
2160
2161 return retval;
2162}
2163
2164int sh_hash_getflags (char * filename)
2165{
2166 sh_file_t * p;
2167 int retval = 0;
2168
2169 if ( sh.flag.checkSum != SH_CHECK_INIT )
2170 {
2171 if (IsInit != 1)
2172 sh_hash_init();
2173
2174 SH_MUTEX_LOCK(mutex_hash);
2175 p = sh_hash_have_it_int (filename);
2176 if (p)
2177 retval = p->fflags;
2178 else
2179 retval = -1;
2180 SH_MUTEX_UNLOCK(mutex_hash);
2181 }
2182 return retval;
2183}
2184
2185int sh_hash_setflags (char * filename, int flags)
2186{
2187 sh_file_t * p;
2188 int retval = 0;
2189
2190 if ( sh.flag.checkSum != SH_CHECK_INIT )
2191 {
2192 if (IsInit != 1)
2193 sh_hash_init();
2194
2195 SH_MUTEX_LOCK(mutex_hash);
2196 p = sh_hash_have_it_int (filename);
2197 if (p)
2198 {
2199 p->fflags = flags;
2200 retval = 0;
2201 }
2202 else
2203 retval = -1;
2204 SH_MUTEX_UNLOCK(mutex_hash);
2205 }
2206 return retval;
2207}
2208
2209/* needs lock to be threadsafe
2210 */
2211void sh_hash_set_flag (char * filename, int flag_to_set)
2212{
2213 sh_file_t * p;
2214
2215 if ( sh.flag.checkSum != SH_CHECK_INIT )
2216 {
2217 if (IsInit != 1)
2218 sh_hash_init();
2219
2220 SH_MUTEX_LOCK(mutex_hash);
2221 p = sh_hash_have_it_int (filename);
2222 if (p)
2223 {
2224 p->fflags |= flag_to_set;
2225 }
2226 SH_MUTEX_UNLOCK(mutex_hash);
2227 }
2228 return;
2229}
2230
2231/* needs lock to be threadsafe
2232 */
2233void sh_hash_clear_flag (char * filename, int flag_to_clear)
2234{
2235 sh_file_t * p;
2236
2237 if ( sh.flag.checkSum != SH_CHECK_INIT )
2238 {
2239 if (IsInit != 1)
2240 sh_hash_init();
2241
2242 SH_MUTEX_LOCK(mutex_hash);
2243 p = sh_hash_have_it_int (filename);
2244 if (p)
2245 {
2246 p->fflags &= ~flag_to_clear;
2247 }
2248 SH_MUTEX_UNLOCK(mutex_hash);
2249 }
2250 return;
2251}
2252
2253
2254/*****************************************************************
2255 *
2256 * Set a file's status to 'visited'. This is required for
2257 * files that should be ignored, and may be present in the
2258 * database, but not on disk.
2259 *
2260 *****************************************************************/
2261static int sh_hash_set_visited_int (char * newname, int flag)
2262{
2263 sh_file_t * p;
2264 char hashbuf[KEYBUF_SIZE];
2265 int retval;
2266
2267 SL_ENTER(_("sh_hash_set_visited_int"));
2268
2269 if (newname == NULL)
2270 SL_RETURN((-1), _("sh_hash_set_visited_int"));
2271
2272 if (IsInit != 1)
2273 sh_hash_init();
2274
2275 SH_MUTEX_LOCK(mutex_hash);
2276
2277 if (sl_strlen(newname) <= MAX_PATH_STORE)
2278 p = hashsearch(newname);
2279 else
2280 p = hashsearch (sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname),
2281 hashbuf, sizeof(hashbuf)));
2282
2283 if (p)
2284 {
2285 if (flag == SH_FFLAG_CHECKED)
2286 {
2287 CLEAR_SH_FFLAG_REPORTED(p->fflags);
2288 CLEAR_SH_FFLAG_VISITED(p->fflags);
2289 SET_SH_FFLAG_CHECKED(p->fflags);
2290 }
2291 else
2292 {
2293 SET_SH_FFLAG_VISITED(p->fflags);
2294 CLEAR_SH_FFLAG_CHECKED(p->fflags);
2295 if (flag == SH_FFLAG_REPORTED)
2296 SET_SH_FFLAG_REPORTED(p->fflags);
2297 else
2298 CLEAR_SH_FFLAG_REPORTED(p->fflags);
2299 }
2300 retval = 0;
2301 }
2302 else
2303 retval = -1;
2304
2305 SH_MUTEX_UNLOCK(mutex_hash);
2306 SL_RETURN((retval), _("sh_hash_set_visited_int"));
2307}
2308
2309
2310/* cause the record to be deleted without a 'missing' message
2311 */
2312int sh_hash_set_missing (char * newname)
2313{
2314 int i;
2315 SL_ENTER(_("sh_hash_set_missing"));
2316
2317 i = sh_hash_set_visited_int(newname, SH_FFLAG_CHECKED);
2318
2319 if (sh.flag.checkSum != SH_CHECK_INIT) {
2320 sh_hash_remove(newname);
2321 }
2322
2323 SL_RETURN(i, _("sh_hash_set_missing"));
2324}
2325
2326/* mark the file as visited and reported
2327 */
2328int sh_hash_set_visited (char * newname)
2329{
2330 int i;
2331 SL_ENTER(_("sh_hash_set_visited"));
2332 i = sh_hash_set_visited_int(newname, SH_FFLAG_REPORTED);
2333 SL_RETURN(i, _("sh_hash_set_visited"));
2334}
2335
2336/* mark the file as visited and NOT reported
2337 * used to avoid deletion of file from internal database
2338 */
2339int sh_hash_set_visited_true (char * newname)
2340{
2341 int i;
2342 SL_ENTER(_("sh_hash_set_visited_true"));
2343 i = sh_hash_set_visited_int(newname, 0);
2344 SL_RETURN(i, _("sh_hash_set_visited_true"));
2345}
2346
2347
2348/******************************************************************
2349 *
2350 * Data entry for arbitrary data into database
2351 *
2352 ******************************************************************/
2353
2354void sh_hash_push2db (const char * key, struct store2db * save)
2355{
2356 int i = 0;
2357 char * p;
2358 char i2h[2];
2359 file_type * tmpFile = SH_ALLOC(sizeof(file_type));
2360
2361 int size = save->size;
2362 unsigned char * str = save->str;
2363
2364
2365 tmpFile->attr_string = NULL;
2366 tmpFile->link_path = NULL;
2367
2368 sl_strlcpy(tmpFile->fullpath, key, PATH_MAX);
2369 tmpFile->size = save->val0;
2370 tmpFile->mtime = save->val1;
2371 tmpFile->ctime = save->val2;
2372 tmpFile->atime = save->val3;
2373
2374 tmpFile->mode = 0;
2375 tmpFile->owner = 0;
2376 tmpFile->group = 0;
2377 sl_strlcpy(tmpFile->c_owner, _("root"), 5);
2378 sl_strlcpy(tmpFile->c_group, _("root"), 5);
2379
2380 if ((str != NULL) && (size < (PATH_MAX/2)-1))
2381 {
2382 tmpFile->c_mode[0] = 'l';
2383 tmpFile->c_mode[1] = 'r'; tmpFile->c_mode[2] = 'w';
2384 tmpFile->c_mode[3] = 'x'; tmpFile->c_mode[4] = 'r';
2385 tmpFile->c_mode[5] = 'w'; tmpFile->c_mode[6] = 'x';
2386 tmpFile->c_mode[7] = 'r'; tmpFile->c_mode[8] = 'w';
2387 tmpFile->c_mode[9] = 'x'; tmpFile->c_mode[10] = '\0';
2388 tmpFile->link_path = SH_ALLOC((size * 2) + 2);
2389 for (i = 0; i < size; ++i)
2390 {
2391 p = sh_util_charhex (str[i],i2h);
2392 tmpFile->link_path[2*i] = p[0];
2393 tmpFile->link_path[2*i+1] = p[1];
2394 tmpFile->link_path[2*i+2] = '\0';
2395 }
2396 }
2397 else
2398 {
2399 for (i = 0; i < 10; ++i)
2400 tmpFile->c_mode[i] = '-';
2401 tmpFile->c_mode[10] = '\0';
2402 tmpFile->link_path = sh_util_strdup("-");
2403 }
2404
2405 if (sh.flag.checkSum == SH_CHECK_INIT)
2406 sh_hash_pushdata (tmpFile,
2407 (save->checksum[0] == '\0') ? SH_KEY_NULL : save->checksum);
2408 else
2409 sh_hash_pushdata_memory (tmpFile,
2410 (save->checksum[0] == '\0') ? SH_KEY_NULL : save->checksum);
2411
2412 if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
2413 SH_FREE(tmpFile);
2414 return;
2415}
2416
2417extern int sh_util_hextobinary (char * binary, char * hex, int bytes);
2418
2419char * sh_hash_db2pop (const char * key, struct store2db * save)
2420{
2421 size_t len;
2422 char * p;
2423 int i;
2424 char * retval = NULL;
2425 char fileHash[KEY_LEN+1];
2426 file_type * tmpFile = SH_ALLOC(sizeof(file_type));
2427
2428 save->size = 0;
2429
2430 if (0 == sh_hash_get_it (key, tmpFile, fileHash))
2431 {
2432 save->val0 = tmpFile->size;
2433 save->val1 = tmpFile->mtime;
2434 save->val2 = tmpFile->ctime;
2435 save->val3 = tmpFile->atime;
2436
2437 sl_strlcpy(save->checksum, fileHash, KEY_LEN+1);
2438
2439 if (tmpFile->link_path && tmpFile->link_path[0] != '-')
2440 {
2441 len = strlen(tmpFile->link_path);
2442
2443 p = SH_ALLOC((len/2)+1);
2444 i = sh_util_hextobinary (p, tmpFile->link_path, len);
2445
2446 if (i == 0)
2447 {
2448 save->size = (len/2);
2449 p[save->size] = '\0';
2450 retval = p;
2451 }
2452 else
2453 {
2454 SH_FREE(p);
2455 save->size = 0;
2456 }
2457 }
2458 else
2459 {
2460 save->size = 0;
2461 }
2462 }
2463 else
2464 {
2465 save->size = -1;
2466 save->val0 = 0;
2467 save->val1 = 0;
2468 save->val2 = 0;
2469 save->val3 = 0;
2470 }
2471 if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
2472 SH_FREE(tmpFile);
2473 return retval;
2474}
2475
2476
2477
2478
2479/******************************************************************
2480 *
2481 * Data entry in hash table
2482 *
2483 ******************************************************************/
2484sh_file_t * sh_hash_push_int (file_type * buf, char * fileHash)
2485{
2486 sh_file_t * fp;
2487 sh_filestore_t p;
2488
2489 size_t len;
2490 char * fullpath;
2491 char * linkpath;
2492 char * attr_string = NULL;
2493 char hashbuf[KEYBUF_SIZE];
2494
2495 SL_ENTER(_("sh_hash_push_int"));
2496
2497 fp = SH_ALLOC(sizeof(sh_file_t));
2498
2499 p.mark = REC_MAGIC;
2500 if (buf->attr_string)
2501 p.mark |= REC_FLAGS_ATTR;
2502 sl_strlcpy(p.c_mode, buf->c_mode, 11);
2503 sl_strlcpy(p.c_group, buf->c_group, GROUP_MAX+1);
2504 sl_strlcpy(p.c_owner, buf->c_owner, USER_MAX+1);
2505 sl_strlcpy(p.checksum, fileHash, KEY_LEN+1);
2506#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2507 sl_strlcpy(p.c_attributes, buf->c_attributes, 13);
2508#endif
2509
2510#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2511 p.attributes = (UINT32) buf->attributes;
2512#endif
2513 p.linkmode = (UINT32) buf->linkmode;
2514 p.hardlinks = (UINT32) buf->hardlinks;
2515 p.dev = (UINT64) buf->dev;
2516 p.rdev = (UINT64) buf->rdev;
2517 p.mode = (UINT32) buf->mode;
2518 p.ino = (UINT32) buf->ino;
2519 p.size = (UINT64) buf->size;
2520 p.mtime = (UINT64) buf->mtime;
2521 p.atime = (UINT64) buf->atime;
2522 p.ctime = (UINT64) buf->ctime;
2523 p.owner = (UINT32) buf->owner;
2524 p.group = (UINT32) buf->group;
2525
2526 memcpy( &(*fp).theFile, &p, sizeof(sh_filestore_t) );
2527 fp->fflags = 0; /* init fflags */
2528 fp->modi_mask = 0L;
2529
2530 if (buf->attr_string)
2531 attr_string = sh_util_strdup(buf->attr_string);
2532 fp->attr_string = attr_string;
2533
2534 len = sl_strlen(buf->fullpath);
2535 if (len <= MAX_PATH_STORE)
2536 {
2537 fullpath = SH_ALLOC(len+1);
2538 sl_strlcpy(fullpath, buf->fullpath, len+1);
2539 }
2540 else
2541 {
2542 fullpath = SH_ALLOC(KEY_LEN + 1);
2543 sl_strlcpy(fullpath,
2544 sh_tiger_hash (buf->fullpath, TIGER_DATA, len,
2545 hashbuf, sizeof(hashbuf)),
2546 KEY_LEN+1);
2547 }
2548 fp->fullpath = fullpath;
2549
2550 if (buf->link_path)
2551 {
2552 len = sl_strlen(buf->link_path);
2553 if (len <= MAX_PATH_STORE)
2554 {
2555 linkpath = SH_ALLOC(len+1);
2556 sl_strlcpy(linkpath, buf->link_path, len+1);
2557 }
2558 else
2559 {
2560 linkpath = SH_ALLOC(KEY_LEN + 1);
2561 sl_strlcpy(linkpath,
2562 sh_tiger_hash (buf->link_path, TIGER_DATA, len,
2563 hashbuf, sizeof(hashbuf)),
2564 KEY_LEN+1);
2565 }
2566 fp->linkpath = linkpath;
2567 }
2568 else
2569 fp->linkpath = NULL;
2570
2571 SL_RETURN( fp, _("sh_hash_push_int"));
2572}
2573
2574#ifdef HAVE_INTTYPES_H
2575#include <inttypes.h>
2576#else
2577#ifdef HAVE_STDINT_H
2578#include <stdint.h>
2579#endif
2580#endif
2581
2582#ifndef PRIu64
2583#ifdef HAVE_LONG_32
2584#define PRIu64 "llu"
2585#else
2586#define PRIu64 "lu"
2587#endif
2588#endif
2589
2590char * sh_hash_size_format()
2591{
2592 static char form_rval[81];
2593
2594 SL_ENTER(_("sh_hash_size_format"));
2595
2596
2597#ifdef SH_USE_XML
2598 sl_snprintf(form_rval, 80, _("%s%s%s%s%s"),
2599 _("size_old=\"%"), PRIu64, _("\" size_new=\"%"), PRIu64, "\" ");
2600#else
2601 sl_snprintf(form_rval, 80, _("%s%s%s%s%s"),
2602 _("size_old=<%"), PRIu64, _(">, size_new=<%"), PRIu64, ">, ");
2603#endif
2604
2605 SL_RETURN( form_rval, _("sh_hash_size_format"));
2606}
2607
2608
2609#ifdef SH_USE_XML
2610static char * all_items (file_type * theFile, char * fileHash, int is_new)
2611{
2612 char timstr1c[32];
2613 char timstr1a[32];
2614 char timstr1m[32];
2615
2616 char * tmp_lnk;
2617 char * format;
2618
2619 char * tmp = SH_ALLOC(SH_MSG_BUF);
2620 char * msg = SH_ALLOC(SH_MSG_BUF);
2621
2622 tmp[0] = '\0';
2623 msg[0] = '\0';
2624
2625
2626#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2627 if (is_new)
2628 format = _("mode_new=\"%s\" attr_new=\"%s\" imode_new=\"%ld\" iattr_new=\"%ld\" ");
2629 else
2630 format = _("mode_old=\"%s\" attr_old=\"%s\" imode_old=\"%ld\" iattr_old=\"%ld\" ");
2631 sl_snprintf(tmp, SH_MSG_BUF, format,
2632 theFile->c_mode,
2633 theFile->c_attributes,
2634 (long) theFile->mode,
2635 (long) theFile->attributes
2636 );
2637#else
2638 if (is_new)
2639 format = _("mode_new=\"%s\" imode_new=\"%ld\" ");
2640 else
2641 format = _("mode_old=\"%s\" imode_old=\"%ld\" ");
2642
2643 sl_snprintf(tmp, SH_MSG_BUF, format,
2644 theFile->c_mode,
2645 (long) theFile->mode
2646 );
2647#endif
2648 sl_strlcat(msg, tmp, SH_MSG_BUF);
2649
2650 if (is_new)
2651 format = _("hardlinks_new=\"%lu\" ");
2652 else
2653 format = _("hardlinks_old=\"%lu\" ");
2654 sl_snprintf(tmp, SH_MSG_BUF, format,
2655 (unsigned long) theFile->hardlinks);
2656 sl_strlcat(msg, tmp, SH_MSG_BUF);
2657
2658
2659 if (is_new)
2660 format = _("idevice_new=\"%lu\" ");
2661 else
2662 format = _("idevice_old=\"%lu\" ");
2663 sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->rdev);
2664 sl_strlcat(msg, tmp, SH_MSG_BUF);
2665
2666
2667 if (is_new)
2668 format = _("inode_new=\"%lu\" ");
2669 else
2670 format = _("inode_old=\"%lu\" ");
2671 sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->ino);
2672 sl_strlcat(msg, tmp, SH_MSG_BUF);
2673
2674 /*
2675 * also report device for prelude
2676 */
2677#if defined(HAVE_LIBPRELUDE)
2678 if (is_new)
2679 format = _("dev_new=\"%lu,%lu\" ");
2680 else
2681 format = _("dev_old=\"%lu,%lu\" ");
2682 sl_snprintf(tmp, SH_MSG_BUF, format,
2683 (unsigned long) major(theFile->dev),
2684 (unsigned long) minor(theFile->dev));
2685 sl_strlcat(msg, tmp, SH_MSG_BUF);
2686#endif
2687
2688
2689 if (is_new)
2690 format = _("owner_new=\"%s\" iowner_new=\"%ld\" ");
2691 else
2692 format = _("owner_old=\"%s\" iowner_old=\"%ld\" ");
2693 sl_snprintf(tmp, SH_MSG_BUF, format,
2694 theFile->c_owner, (long) theFile->owner);
2695 sl_strlcat(msg, tmp, SH_MSG_BUF);
2696
2697
2698 if (is_new)
2699 format = _("group_new=\"%s\" igroup_new=\"%ld\" ");
2700 else
2701 format = _("group_old=\"%s\" igroup_old=\"%ld\" ");
2702 sl_snprintf(tmp, SH_MSG_BUF, format,
2703 theFile->c_group, (long) theFile->group);
2704 sl_strlcat(msg, tmp, SH_MSG_BUF);
2705
2706
2707 if (is_new)
2708 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
2709 (UINT64) 0, (UINT64) theFile->size);
2710 else
2711 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
2712 (UINT64) theFile->size, (UINT64) 0);
2713 sl_strlcat(msg, tmp, SH_MSG_BUF);
2714
2715
2716 (void) sh_unix_gmttime (theFile->ctime, timstr1c, sizeof(timstr1c));
2717 if (is_new)
2718 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_new=\"%s\" "), timstr1c);
2719 else
2720 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=\"%s\" "), timstr1c);
2721 sl_strlcat(msg, tmp, SH_MSG_BUF);
2722
2723 (void) sh_unix_gmttime (theFile->atime, timstr1a, sizeof(timstr1a));
2724 if (is_new)
2725 sl_snprintf(tmp, SH_MSG_BUF, _("atime_new=\"%s\" "), timstr1a);
2726 else
2727 sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=\"%s\" "), timstr1a);
2728 sl_strlcat(msg, tmp, SH_MSG_BUF);
2729
2730 (void) sh_unix_gmttime (theFile->mtime, timstr1m, sizeof(timstr1m));
2731 if (is_new)
2732 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_new=\"%s\" "), timstr1m);
2733 else
2734 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=\"%s\" "), timstr1m);
2735 sl_strlcat(msg, tmp, SH_MSG_BUF);
2736
2737 if (is_new)
2738 sl_snprintf(tmp, SH_MSG_BUF, _("chksum_new=\"%s\" "), fileHash);
2739 else
2740 sl_snprintf(tmp, SH_MSG_BUF, _("chksum_old=\"%s\" "), fileHash);
2741 sl_strlcat(msg, tmp, SH_MSG_BUF);
2742
2743 if (theFile->c_mode[0] == 'l' ||
2744 (theFile->link_path != NULL && theFile->link_path[0] != '-'))
2745 {
2746 tmp_lnk = sh_util_safe_name(theFile->link_path);
2747 if (tmp_lnk)
2748 {
2749 if (is_new)
2750 sl_snprintf(tmp, SH_MSG_BUF, _("link_new=\"%s\" "), tmp_lnk);
2751 else
2752 sl_snprintf(tmp, SH_MSG_BUF, _("link_old=\"%s\" "), tmp_lnk);
2753 SH_FREE(tmp_lnk);
2754 sl_strlcat(msg, tmp, SH_MSG_BUF);
2755 }
2756 }
2757
2758 if (theFile->attr_string)
2759 {
2760 tmp_lnk = sh_util_safe_name(theFile->attr_string);
2761 if (tmp_lnk)
2762 {
2763 if (is_new)
2764 sl_snprintf(tmp, SH_MSG_BUF, _("acl_new=\"%s\" "), tmp_lnk);
2765 else
2766 sl_snprintf(tmp, SH_MSG_BUF, _("acl_old=\"%s\" "), tmp_lnk);
2767 SH_FREE(tmp_lnk);
2768 sl_strlcat(msg, tmp, SH_MSG_BUF);
2769 }
2770 }
2771
2772
2773 SH_FREE(tmp);
2774 return (msg);
2775}
2776#else
2777static char * all_items (file_type * theFile, char * fileHash, int is_new)
2778{
2779 char timstr1c[32];
2780 char timstr1a[32];
2781 char timstr1m[32];
2782
2783 char * tmp_lnk;
2784 char * format;
2785
2786 char * tmp = SH_ALLOC(SH_MSG_BUF);
2787 char * msg = SH_ALLOC(SH_MSG_BUF);
2788
2789 tmp[0] = '\0';
2790 msg[0] = '\0';
2791
2792
2793#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
2794 if (is_new)
2795 format = _("mode_new=<%s>, attr_new=<%s>, imode_new=<%ld>, iattr_new=<%ld>, ");
2796 else
2797 format = _("mode_old=<%s>, attr_old=<%s>, imode_old=<%ld>, iattr_old=<%ld>, ");
2798 sl_snprintf(tmp, SH_MSG_BUF, format,
2799 theFile->c_mode,
2800 theFile->c_attributes,
2801 (long) theFile->mode,
2802 (long) theFile->attributes
2803 );
2804#else
2805 if (is_new)
2806 format = _("mode_new=<%s>, imode_new=<%ld>, ");
2807 else
2808 format = _("mode_old=<%s>, imode_old=<%ld>, ");
2809
2810 sl_snprintf(tmp, SH_MSG_BUF, format,
2811 theFile->c_mode,
2812 (long) theFile->mode
2813 );
2814#endif
2815 sl_strlcat(msg, tmp, SH_MSG_BUF);
2816
2817 if (is_new)
2818 format = _("hardlinks_new=<%lu>, ");
2819 else
2820 format = _("hardlinks_old=<%lu>, ");
2821 sl_snprintf(tmp, SH_MSG_BUF, format,
2822 (unsigned long) theFile->hardlinks);
2823 sl_strlcat(msg, tmp, SH_MSG_BUF);
2824
2825
2826 if (is_new)
2827 format = _("idevice_new=<%lu>, ");
2828 else
2829 format = _("idevice_old=<%lu>, ");
2830 sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->rdev);
2831 sl_strlcat(msg, tmp, SH_MSG_BUF);
2832
2833
2834 if (is_new)
2835 format = _("inode_new=<%lu>, ");
2836 else
2837 format = _("inode_old=<%lu>, ");
2838 sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->ino);
2839 sl_strlcat(msg, tmp, SH_MSG_BUF);
2840
2841
2842 /*
2843 * also report device for prelude
2844 */
2845#if defined(HAVE_LIBPRELUDE)
2846 if (is_new)
2847 format = _("dev_new=<%lu,%lu>, ");
2848 else
2849 format = _("dev_old=<%lu,%lu>, ");
2850 sl_snprintf(tmp, SH_MSG_BUF, format,
2851 (unsigned long) major(theFile->dev),
2852 (unsigned long) minor(theFile->dev));
2853 sl_strlcat(msg, tmp, SH_MSG_BUF);
2854#endif
2855
2856 if (is_new)
2857 format = _("owner_new=<%s>, iowner_new=<%ld>, ");
2858 else
2859 format = _("owner_old=<%s>, iowner_old=<%ld>, ");
2860 sl_snprintf(tmp, SH_MSG_BUF, format,
2861 theFile->c_owner, (long) theFile->owner);
2862 sl_strlcat(msg, tmp, SH_MSG_BUF);
2863
2864
2865 if (is_new)
2866 format = _("group_new=<%s>, igroup_new=<%ld>, ");
2867 else
2868 format = _("group_old=<%s>, igroup_old=<%ld>, ");
2869 sl_snprintf(tmp, SH_MSG_BUF, format,
2870 theFile->c_group, (long) theFile->group);
2871 sl_strlcat(msg, tmp, SH_MSG_BUF);
2872
2873
2874 if (is_new)
2875 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
2876 (UINT64) 0, (UINT64) theFile->size);
2877 else
2878 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
2879 (UINT64) theFile->size, (UINT64) 0);
2880 sl_strlcat(msg, tmp, SH_MSG_BUF);
2881
2882
2883 (void) sh_unix_gmttime (theFile->ctime, timstr1c, sizeof(timstr1c));
2884 if (is_new)
2885 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_new=<%s>, "), timstr1c);
2886 else
2887 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=<%s>, "), timstr1c);
2888 sl_strlcat(msg, tmp, SH_MSG_BUF);
2889
2890 (void) sh_unix_gmttime (theFile->atime, timstr1a, sizeof(timstr1a));
2891 if (is_new)
2892 sl_snprintf(tmp, SH_MSG_BUF, _("atime_new=<%s>, "), timstr1a);
2893 else
2894 sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=<%s>, "), timstr1a);
2895 sl_strlcat(msg, tmp, SH_MSG_BUF);
2896
2897 (void) sh_unix_gmttime (theFile->mtime, timstr1m, sizeof(timstr1m));
2898 if (is_new)
2899 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_new=<%s>, "), timstr1m);
2900 else
2901 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=<%s>, "), timstr1m);
2902 sl_strlcat(msg, tmp, SH_MSG_BUF);
2903
2904 if (is_new)
2905 sl_snprintf(tmp, SH_MSG_BUF, _("chksum_new=<%s>"), fileHash);
2906 else
2907 sl_snprintf(tmp, SH_MSG_BUF, _("chksum_old=<%s>"), fileHash);
2908 sl_strlcat(msg, tmp, SH_MSG_BUF);
2909
2910 if (theFile->c_mode[0] == 'l' ||
2911 (theFile->link_path != NULL && theFile->link_path[0] != '-'))
2912 {
2913 tmp_lnk = sh_util_safe_name(theFile->link_path);
2914 if (tmp_lnk)
2915 {
2916 if (is_new)
2917 sl_snprintf(tmp, SH_MSG_BUF, _(", link_new=<%s> "), tmp_lnk);
2918 else
2919 sl_snprintf(tmp, SH_MSG_BUF, _(", link_old=<%s> "), tmp_lnk);
2920 SH_FREE(tmp_lnk);
2921 sl_strlcat(msg, tmp, SH_MSG_BUF);
2922 }
2923 }
2924
2925 if (theFile->attr_string)
2926 {
2927 tmp_lnk = sh_util_safe_name(theFile->attr_string);
2928 if (tmp_lnk)
2929 {
2930 if (is_new)
2931 sl_snprintf(tmp, SH_MSG_BUF, _(", acl_new=<%s> "), tmp_lnk);
2932 else
2933 sl_snprintf(tmp, SH_MSG_BUF, _(", acl_old=<%s> "), tmp_lnk);
2934 SH_FREE(tmp_lnk);
2935 sl_strlcat(msg, tmp, SH_MSG_BUF);
2936 }
2937 }
2938
2939 SH_FREE(tmp);
2940 return (msg);
2941}
2942#endif
2943
2944void sh_hash_pushdata_memory (file_type * theFile, char * fileHash)
2945{
2946 sh_file_t * p;
2947
2948 SL_ENTER(_("sh_hash_pushdata_memory"));
2949
2950 p = sh_hash_push_int(theFile, fileHash);
2951 if (p)
2952 {
2953 SH_MUTEX_LOCK(mutex_hash);
2954 hashinsert (p);
2955 p->modi_mask = theFile->check_mask;
2956 SH_MUTEX_UNLOCK(mutex_hash);
2957 }
2958
2959 SL_RET0(_("sh_hash_pushdata_memory"));
2960}
2961
2962
2963/*****************************************************************
2964 *
2965 * Compare a file with the database status.
2966 *
2967 *****************************************************************/
2968int sh_hash_compdata (int class, file_type * theFile, char * fileHash,
2969 char * policy_override, int severity_override)
2970{
2971 char * msg;
2972 sh_file_t * p;
2973 char * tmp;
2974 char * tmp_path;
2975 char * tmp_lnk;
2976 char * tmp_lnk_old;
2977
2978 char * str;
2979
2980 char timstr1c[32];
2981 char timstr2c[32];
2982 char timstr1a[32];
2983 char timstr2a[32];
2984 char timstr1m[32];
2985 char timstr2m[32];
2986 char linkHash[KEY_LEN+1];
2987 char * linkComp;
2988 int maxcomp;
2989
2990 char change_code[16];
2991 int i;
2992
2993 unsigned long modi_mask;
2994
2995 char log_policy[32];
2996 volatile int log_severity;
2997 char hashbuf[KEYBUF_SIZE];
2998
2999 int retval;
3000
3001 SL_ENTER(_("sh_hash_compdata"));
3002
3003 if (IsInit != 1) sh_hash_init();
3004
3005 if (severity_override < 0)
3006 log_severity = ShDFLevel[class];
3007 else
3008 log_severity = severity_override;
3009
3010 if (policy_override != NULL)
3011 sl_strlcpy (log_policy, policy_override, 32);
3012
3013 /* -------- find the entry for the file ---------------- */
3014
3015 SH_MUTEX_LOCK(mutex_hash);
3016
3017 modi_mask = 0;
3018 retval = 0;
3019
3020 if (sl_strlen(theFile->fullpath) <= MAX_PATH_STORE)
3021 p = hashsearch(theFile->fullpath);
3022 else
3023 p = hashsearch( sh_tiger_hash(theFile->fullpath,
3024 TIGER_DATA,
3025 sl_strlen(theFile->fullpath),
3026 hashbuf, sizeof(hashbuf))
3027 );
3028
3029
3030 /* --------- Not found in database. ------------
3031 */
3032
3033 if (p == NULL)
3034 {
3035 if (S_FALSE == sh_ignore_chk_new(theFile->fullpath))
3036 {
3037 tmp = sh_util_safe_name(theFile->fullpath);
3038
3039 str = all_items (theFile, fileHash, 1);
3040 sh_error_handle (log_severity, FIL__, __LINE__, 0,
3041 MSG_FI_ADD2,
3042 tmp, str);
3043 ++sh.statistics.files_report;
3044 SH_FREE(str);
3045
3046 SH_FREE(tmp);
3047 }
3048
3049 if (sh.flag.reportonce == S_TRUE)
3050 SET_SH_FFLAG_REPORTED(theFile->file_reported);
3051
3052 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3053 {
3054 p = sh_hash_push_int(theFile, fileHash);
3055 if (p)
3056 {
3057 hashinsert (p);
3058 p->modi_mask = theFile->check_mask;
3059 }
3060 }
3061
3062 else if (S_TRUE == sh.flag.update)
3063 {
3064 if (S_TRUE == sh_util_ask_update (theFile->fullpath))
3065 {
3066 p = sh_hash_push_int(theFile, fileHash);
3067 if (p)
3068 {
3069 hashinsert (p);
3070 p->modi_mask = theFile->check_mask;
3071 }
3072 }
3073 else
3074 {
3075 retval = 1;
3076 goto unlock_and_return;
3077 }
3078 }
3079
3080 goto unlock_and_return;
3081 }
3082
3083 /* --------- Skip if we don't want to report changes. ------------
3084 */
3085
3086 if (S_TRUE == sh_ignore_chk_mod(theFile->fullpath))
3087 {
3088 goto unlock_and_return;
3089 }
3090
3091 p->modi_mask = theFile->check_mask;
3092
3093 /* initialize change_code */
3094 for (i = 0; i < 15; ++i)
3095 change_code[i] = '-';
3096 change_code[15] = '\0';
3097
3098 TPT ((0, FIL__, __LINE__, _("file=<%s>, cs_old=<%s>, cs_new=<%s>\n"),
3099 theFile->fullpath, fileHash, p->theFile.checksum));
3100
3101 if ( (fileHash != NULL) &&
3102 (strncmp (fileHash, p->theFile.checksum, KEY_LEN) != 0) &&
3103 (theFile->check_mask & MODI_CHK) != 0)
3104 {
3105 if ((theFile->check_mask & MODI_SGROW) == 0)
3106 {
3107 modi_mask |= MODI_CHK;
3108 change_code[0] = 'C';
3109 TPT ((0, FIL__, __LINE__, _("mod=<checksum>")));
3110 }
3111 else
3112 {
3113 if (0 != strncmp (&fileHash[KEY_LEN + 1], p->theFile.checksum, KEY_LEN))
3114 {
3115 if (S_FALSE == sh_check_rotated_log (theFile->fullpath, (UINT64) p->theFile.size,
3116 (UINT64) p->theFile.ino, p->theFile.checksum))
3117 {
3118 modi_mask |= MODI_CHK;
3119 change_code[0] = 'C';
3120 TPT ((0, FIL__, __LINE__, _("mod=<checksum>")));
3121 }
3122 else
3123 {
3124 /* logfile has been rotated */
3125 p->theFile.size = theFile->size;
3126 p->theFile.ino = theFile->ino;
3127 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
3128 }
3129 }
3130 else
3131 {
3132 p->theFile.size = theFile->size;
3133 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
3134 }
3135 }
3136 }
3137
3138 if (p->theFile.c_mode[0] == 'l')
3139 {
3140 if (!(theFile->link_path) &&
3141 (theFile->check_mask & MODI_LNK) != 0)
3142 {
3143 linkComp = NULL;
3144 modi_mask |= MODI_LNK;
3145 change_code[1] = 'L';
3146 TPT ((0, FIL__, __LINE__, _("mod=<link>")));
3147 }
3148 else
3149 {
3150 if (sl_strlen(theFile->link_path) >= MAX_PATH_STORE)
3151 {
3152 sl_strlcpy(linkHash,
3153 sh_tiger_hash(theFile->link_path,
3154 TIGER_DATA,
3155 sl_strlen(theFile->link_path),
3156 hashbuf, sizeof(hashbuf)),
3157 MAX_PATH_STORE+1);
3158 linkComp = linkHash;
3159 maxcomp = KEY_LEN;
3160 }
3161 else
3162 {
3163 linkComp = theFile->link_path;
3164 maxcomp = MAX_PATH_STORE;
3165 }
3166
3167 if ( sl_strncmp (linkComp, p->linkpath, maxcomp) != 0 &&
3168 (theFile->check_mask & MODI_LNK) != 0)
3169 {
3170 modi_mask |= MODI_LNK;
3171 change_code[1] = 'L';
3172 TPT ((0, FIL__, __LINE__, _("mod=<link>")));
3173 }
3174 }
3175 }
3176
3177 if (p->theFile.c_mode[0] == 'c' || p->theFile.c_mode[0] == 'b')
3178 {
3179 if ( ( major(theFile->rdev) != major((dev_t)p->theFile.rdev) ||
3180 minor(theFile->rdev) != minor((dev_t)p->theFile.rdev) ) &&
3181 (theFile->check_mask & MODI_RDEV) != 0)
3182 {
3183 modi_mask |= MODI_RDEV;
3184 change_code[2] = 'D';
3185 TPT ((0, FIL__, __LINE__, _("mod=<rdev>")));
3186 }
3187 }
3188
3189 /* cast to UINT32 in case ino_t is not 32bit
3190 */
3191 if ( (UINT32) theFile->ino != (UINT32) p->theFile.ino &&
3192 (theFile->check_mask & MODI_INO) != 0)
3193 {
3194 modi_mask |= MODI_INO;
3195 change_code[3] = 'I';
3196 TPT ((0, FIL__, __LINE__, _("mod=<inode>")));
3197 }
3198
3199 if ( theFile->hardlinks != (nlink_t) p->theFile.hardlinks &&
3200 (theFile->check_mask & MODI_HLN) != 0)
3201 {
3202 modi_mask |= MODI_HLN;
3203 change_code[4] = 'H';
3204 TPT ((0, FIL__, __LINE__, _("mod=<hardlink>")));
3205 }
3206
3207
3208 if ( ( (theFile->mode != p->theFile.mode)
3209#if defined(USE_ACL) || defined(USE_XATTR)
3210 || ( (sh_unix_check_selinux|sh_unix_check_acl) &&
3211 (
3212 (theFile->attr_string == NULL && p->attr_string != NULL) ||
3213 (theFile->attr_string != NULL && p->attr_string == NULL) ||
3214 (theFile->attr_string != NULL && 0 != strcmp(theFile->attr_string, p->attr_string))
3215 )
3216 )
3217#endif
3218#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
3219 || (theFile->attributes != p->theFile.attributes)
3220#endif
3221 )
3222 && (theFile->check_mask & MODI_MOD) != 0)
3223 {
3224 modi_mask |= MODI_MOD;
3225 change_code[5] = 'M';
3226 TPT ((0, FIL__, __LINE__, _("mod=<mode>")));
3227 /*
3228 * report link path if switch link/no link
3229 */
3230 if ((theFile->check_mask & MODI_LNK) != 0 &&
3231 (theFile->c_mode[0] != p->theFile.c_mode[0]) &&
3232 (theFile->c_mode[0] == 'l' || p->theFile.c_mode[0] == 'l'))
3233 {
3234 modi_mask |= MODI_LNK;
3235 change_code[1] = 'L';
3236 TPT ((0, FIL__, __LINE__, _("mod=<link>")));
3237 }
3238 }
3239
3240 if ( theFile->owner != (uid_t) p->theFile.owner &&
3241 (theFile->check_mask & MODI_USR) != 0)
3242 {
3243 modi_mask |= MODI_USR;
3244 change_code[6] = 'U';
3245 TPT ((0, FIL__, __LINE__, _("mod=<user>")));
3246 }
3247
3248 if ( theFile->group != (gid_t) p->theFile.group &&
3249 (theFile->check_mask & MODI_GRP) != 0)
3250 {
3251 modi_mask |= MODI_GRP;
3252 change_code[7] = 'G';
3253 TPT ((0, FIL__, __LINE__, _("mod=<group>")));
3254 }
3255
3256
3257 if ( theFile->mtime != (time_t) p->theFile.mtime &&
3258 (theFile->check_mask & MODI_MTM) != 0)
3259 {
3260 modi_mask |= MODI_MTM;
3261 change_code[8] = 'T';
3262 TPT ((0, FIL__, __LINE__, _("mod=<mtime>")));
3263 }
3264
3265 if ( (theFile->check_mask & MODI_ATM) != 0 &&
3266 theFile->atime != (time_t) p->theFile.atime)
3267 {
3268 modi_mask |= MODI_ATM;
3269 change_code[8] = 'T';
3270 TPT ((0, FIL__, __LINE__, _("mod=<atime>")));
3271 }
3272
3273
3274 /* Resetting the access time will set a new ctime. Thus, either we ignore
3275 * the access time or the ctime for NOIGNORE
3276 */
3277 if ( theFile->ctime != (time_t) p->theFile.ctime &&
3278 (theFile->check_mask & MODI_CTM) != 0)
3279 {
3280 modi_mask |= MODI_CTM;
3281 change_code[8] = 'T';
3282 TPT ((0, FIL__, __LINE__, _("mod=<ctime>")));
3283 }
3284
3285 if ( theFile->size != (off_t) p->theFile.size &&
3286 (theFile->check_mask & MODI_SIZ) != 0)
3287 {
3288 if ((theFile->check_mask & MODI_SGROW) == 0 ||
3289 theFile->size < (off_t) p->theFile.size)
3290 {
3291 modi_mask |= MODI_SIZ;
3292 change_code[9] = 'S';
3293 TPT ((0, FIL__, __LINE__, _("mod=<size>")));
3294 }
3295 }
3296 change_code[10] = '\0';
3297
3298 /* --- Directories special case ---
3299 */
3300 if (p->theFile.c_mode[0] == 'd' &&
3301 0 == (modi_mask & ~(MODI_SIZ|MODI_ATM|MODI_CTM|MODI_MTM)) &&
3302 sh_loosedircheck == S_TRUE)
3303 {
3304 modi_mask = 0;
3305 }
3306
3307 /* --- Report full details. ---
3308 */
3309 if (modi_mask != 0 && sh.flag.fulldetail == S_TRUE)
3310 {
3311 if ((theFile->check_mask & MODI_ATM) == 0)
3312 modi_mask = MASK_READONLY_;
3313 else
3314 modi_mask = MASK_NOIGNORE_;
3315 }
3316
3317 /* --- Report on modified files. ---
3318 */
3319 if (modi_mask != 0 && (!SH_FFLAG_REPORTED_SET(p->fflags)))
3320 {
3321 tmp = SH_ALLOC(SH_MSG_BUF);
3322 msg = SH_ALLOC(SH_MSG_BUF);
3323 msg[0] = '\0';
3324
3325 if ( ((modi_mask & MODI_MOD) != 0)
3326#if defined(HAVE_LIBPRELUDE)
3327 || ((modi_mask & MODI_USR) != 0)
3328 || ((modi_mask & MODI_GRP) != 0)
3329#endif
3330 )
3331 {
3332#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
3333 sl_snprintf(tmp, SH_MSG_BUF,
3334#ifdef SH_USE_XML
3335 _("mode_old=\"%s\" mode_new=\"%s\" attr_old=\"%s\" attr_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" iattr_old=\"%ld\" iattr_new=\"%ld\" "),
3336#else
3337 _("mode_old=<%s>, mode_new=<%s>, attr_old=<%s>, attr_new=<%s>, "),
3338#endif
3339 p->theFile.c_mode, theFile->c_mode,
3340 p->theFile.c_attributes, theFile->c_attributes
3341#ifdef SH_USE_XML
3342 , (long) p->theFile.mode, (long) theFile->mode,
3343 (long) p->theFile.attributes,
3344 (long) theFile->attributes
3345#endif
3346 );
3347#else
3348#ifdef SH_USE_XML
3349 sl_snprintf(tmp, SH_MSG_BUF,
3350 _("mode_old=\"%s\" mode_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" "),
3351 p->theFile.c_mode, theFile->c_mode,
3352 (long) p->theFile.mode, (long) theFile->mode);
3353#else
3354 sl_snprintf(tmp, SH_MSG_BUF, _("mode_old=<%s>, mode_new=<%s>, "),
3355 p->theFile.c_mode, theFile->c_mode);
3356#endif
3357#endif
3358 sl_strlcat(msg, tmp, SH_MSG_BUF);
3359
3360#if defined(USE_ACL) || defined(USE_XATTR)
3361 if (theFile->attr_string != NULL || p->attr_string != NULL)
3362 {
3363 sl_snprintf(tmp, SH_MSG_BUF,
3364#ifdef SH_USE_XML
3365 _("acl_old=\"%s\" acl_new=\"%s\" "),
3366#else
3367 _("acl_old=<%s>, acl_new=<%s>, "),
3368#endif
3369 (p->attr_string) ? p->attr_string : _("none"),
3370 (theFile->attr_string) ? theFile->attr_string : _("none"));
3371
3372 sl_strlcat(msg, tmp, SH_MSG_BUF);
3373 }
3374#endif
3375
3376#ifdef REPLACE_OLD
3377 if ((modi_mask & MODI_MOD) != 0)
3378 {
3379 /*
3380 * We postpone update if sh.flag.update == S_TRUE because
3381 * in interactive mode the user may not accept the change.
3382 */
3383 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3384 {
3385 sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11);
3386 p->theFile.mode = theFile->mode;
3387#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
3388 sl_strlcpy(p->theFile.c_attributes,theFile->c_attributes,16);
3389 p->theFile.attributes = theFile->attributes;
3390#endif
3391#if defined(USE_ACL) || defined(USE_XATTR)
3392 if (p->attr_string == NULL && theFile->attr_string != NULL)
3393 { p->attr_string = sh_util_strdup (theFile->attr_string); }
3394 else if (p->attr_string != NULL && theFile->attr_string == NULL)
3395 { SH_FREE(p->attr_string); p->attr_string = NULL; }
3396 else if (theFile->attr_string != NULL && p->attr_string != NULL)
3397 {
3398 if (0 != strcmp(theFile->attr_string, p->attr_string))
3399 {
3400 SH_FREE(p->attr_string);
3401 p->attr_string = sh_util_strdup (theFile->attr_string);
3402 }
3403 }
3404#endif
3405 }
3406 }
3407#endif
3408 }
3409
3410 if ((modi_mask & MODI_HLN) != 0)
3411 {
3412 sl_snprintf(tmp, SH_MSG_BUF,
3413#ifdef SH_USE_XML
3414 _("hardlinks_old=\"%lu\" hardlinks_new=\"%lu\" "),
3415#else
3416 _("hardlinks_old=<%lu>, hardlinks_new=<%lu>, "),
3417#endif
3418 (unsigned long) p->theFile.hardlinks,
3419 (unsigned long) theFile->hardlinks);
3420 sl_strlcat(msg, tmp, SH_MSG_BUF);
3421#ifdef REPLACE_OLD
3422 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3423 p->theFile.hardlinks = theFile->hardlinks;
3424#endif
3425 }
3426
3427 if ((modi_mask & MODI_RDEV) != 0)
3428 {
3429 sl_snprintf(tmp, SH_MSG_BUF,
3430#ifdef SH_USE_XML
3431 _("device_old=\"%lu,%lu\" device_new=\"%lu,%lu\" idevice_old=\"%lu\" idevice_new=\"%lu\" "),
3432#else
3433 _("device_old=<%lu,%lu>, device_new=<%lu,%lu>, "),
3434#endif
3435 (unsigned long) major(p->theFile.rdev),
3436 (unsigned long) minor(p->theFile.rdev),
3437 (unsigned long) major(theFile->rdev),
3438 (unsigned long) minor(theFile->rdev)
3439#ifdef SH_USE_XML
3440 , (unsigned long) p->theFile.rdev,
3441 (unsigned long) theFile->rdev
3442#endif
3443 );
3444 sl_strlcat(msg, tmp, SH_MSG_BUF);
3445#ifdef REPLACE_OLD
3446 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3447 p->theFile.rdev = theFile->rdev;
3448#endif
3449 }
3450
3451 if ((modi_mask & MODI_INO) != 0)
3452 {
3453 sl_snprintf(tmp, SH_MSG_BUF,
3454#ifdef SH_USE_XML
3455 _("inode_old=\"%lu\" inode_new=\"%lu\" "),
3456#else
3457 _("inode_old=<%lu>, inode_new=<%lu>, "),
3458#endif
3459 (unsigned long) p->theFile.ino,
3460 (unsigned long) theFile->ino);
3461 sl_strlcat(msg, tmp, SH_MSG_BUF);
3462#ifdef REPLACE_OLD
3463 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3464 {
3465 p->theFile.ino = theFile->ino;
3466 p->theFile.dev = theFile->dev;
3467 }
3468#endif
3469 }
3470
3471
3472 /*
3473 * also report device for prelude
3474 */
3475#if defined(HAVE_LIBPRELUDE)
3476 if ((modi_mask & MODI_INO) != 0)
3477 {
3478 sl_snprintf(tmp, SH_MSG_BUF,
3479#ifdef SH_USE_XML
3480 _("dev_old=\"%lu,%lu\" dev_new=\"%lu,%lu\" "),
3481#else
3482 _("dev_old=<%lu,%lu>, dev_new=<%lu,%lu>, "),
3483#endif
3484 (unsigned long) major(p->theFile.dev),
3485 (unsigned long) minor(p->theFile.dev),
3486 (unsigned long) major(theFile->dev),
3487 (unsigned long) minor(theFile->dev)
3488 );
3489 sl_strlcat(msg, tmp, SH_MSG_BUF);
3490#ifdef REPLACE_OLD
3491 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3492 p->theFile.dev = theFile->dev;
3493#endif
3494 }
3495#endif
3496
3497 if ( ((modi_mask & MODI_USR) != 0)
3498#if defined(HAVE_LIBPRELUDE)
3499 || ((modi_mask & MODI_MOD) != 0)
3500#endif
3501 )
3502 {
3503#ifdef SH_USE_XML
3504 sl_snprintf(tmp, SH_MSG_BUF,
3505 _("owner_old=\"%s\" owner_new=\"%s\" iowner_old=\"%ld\" iowner_new=\"%ld\" "),
3506#else
3507 sl_snprintf(tmp, SH_MSG_BUF,
3508 _("owner_old=<%s>, owner_new=<%s>, iowner_old=<%ld>, iowner_new=<%ld>, "),
3509#endif
3510 p->theFile.c_owner, theFile->c_owner,
3511 (long) p->theFile.owner, (long) theFile->owner
3512 );
3513 sl_strlcat(msg, tmp, SH_MSG_BUF);
3514#ifdef REPLACE_OLD
3515 if ((modi_mask & MODI_USR) != 0) {
3516 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3517 {
3518 sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2);
3519 p->theFile.owner = theFile->owner;
3520 }
3521 }
3522#endif
3523 }
3524
3525 if ( ((modi_mask & MODI_GRP) != 0)
3526#if defined(HAVE_LIBPRELUDE)
3527 || ((modi_mask & MODI_MOD) != 0)
3528#endif
3529 )
3530 {
3531#ifdef SH_USE_XML
3532 sl_snprintf(tmp, SH_MSG_BUF,
3533 _("group_old=\"%s\" group_new=\"%s\" igroup_old=\"%ld\" igroup_new=\"%ld\" "),
3534 p->theFile.c_group, theFile->c_group,
3535 (long) p->theFile.group, (long) theFile->group);
3536#else
3537 sl_snprintf(tmp, SH_MSG_BUF,
3538 _("group_old=<%s>, group_new=<%s>, igroup_old=<%ld>, igroup_new=<%ld>, "),
3539 p->theFile.c_group, theFile->c_group,
3540 (long) p->theFile.group, (long) theFile->group);
3541#endif
3542
3543 sl_strlcat(msg, tmp, SH_MSG_BUF);
3544#ifdef REPLACE_OLD
3545 if ((modi_mask & MODI_GRP) != 0) {
3546 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3547 {
3548 sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2);
3549 p->theFile.group = theFile->group;
3550 }
3551 }
3552#endif
3553 }
3554
3555 if ((modi_mask & MODI_SIZ) != 0)
3556 {
3557 sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
3558 (UINT64) p->theFile.size,
3559 (UINT64) theFile->size);
3560 sl_strlcat(msg, tmp, SH_MSG_BUF);
3561#ifdef REPLACE_OLD
3562 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3563 p->theFile.size = theFile->size;
3564#endif
3565 }
3566
3567 if ((modi_mask & MODI_CTM) != 0)
3568 {
3569 (void) sh_unix_gmttime (p->theFile.ctime, timstr1c, sizeof(timstr1c));
3570 (void) sh_unix_gmttime (theFile->ctime, timstr2c, sizeof(timstr2c));
3571#ifdef SH_USE_XML
3572 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=\"%s\" ctime_new=\"%s\" "),
3573 timstr1c, timstr2c);
3574#else
3575 sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=<%s>, ctime_new=<%s>, "),
3576 timstr1c, timstr2c);
3577#endif
3578 sl_strlcat(msg, tmp, SH_MSG_BUF);
3579#ifdef REPLACE_OLD
3580 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3581 p->theFile.ctime = theFile->ctime;
3582#endif
3583 }
3584
3585 if ((modi_mask & MODI_ATM) != 0)
3586 {
3587 (void) sh_unix_gmttime (p->theFile.atime, timstr1a, sizeof(timstr1a));
3588 (void) sh_unix_gmttime (theFile->atime, timstr2a, sizeof(timstr2a));
3589#ifdef SH_USE_XML
3590 sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=\"%s\" atime_new=\"%s\" "),
3591 timstr1a, timstr2a);
3592#else
3593 sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=<%s>, atime_new=<%s>, "),
3594 timstr1a, timstr2a);
3595#endif
3596 sl_strlcat(msg, tmp, SH_MSG_BUF);
3597#ifdef REPLACE_OLD
3598 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3599 p->theFile.atime = theFile->atime;
3600#endif
3601 }
3602
3603 if ((modi_mask & MODI_MTM) != 0)
3604 {
3605 (void) sh_unix_gmttime (p->theFile.mtime, timstr1m, sizeof(timstr1m));
3606 (void) sh_unix_gmttime (theFile->mtime, timstr2m, sizeof(timstr2m));
3607#ifdef SH_USE_XML
3608 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=\"%s\" mtime_new=\"%s\" "),
3609 timstr1m, timstr2m);
3610#else
3611 sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=<%s>, mtime_new=<%s>, "),
3612 timstr1m, timstr2m);
3613#endif
3614 sl_strlcat(msg, tmp, SH_MSG_BUF);
3615#ifdef REPLACE_OLD
3616 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3617 p->theFile.mtime = theFile->mtime;
3618#endif
3619 }
3620
3621
3622 if ((modi_mask & MODI_CHK) != 0)
3623 {
3624 sl_snprintf(tmp, SH_MSG_BUF,
3625#ifdef SH_USE_XML
3626 _("chksum_old=\"%s\" chksum_new=\"%s\" "),
3627#else
3628 _("chksum_old=<%s>, chksum_new=<%s>, "),
3629#endif
3630 p->theFile.checksum, fileHash);
3631 sl_strlcat(msg, tmp, SH_MSG_BUF);
3632#ifdef REPLACE_OLD
3633 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3634 {
3635 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
3636 if ((theFile->check_mask & MODI_SGROW) != 0)
3637 p->theFile.size = theFile->size;
3638 }
3639#endif
3640 /* FIXME is this correct? */
3641 if (theFile->c_mode[0] != 'l' && theFile->link_path &&
3642 strlen(theFile->link_path) > 2)
3643 modi_mask |= MODI_LNK;
3644 }
3645
3646
3647 if ((modi_mask & MODI_LNK) != 0 /* && theFile->c_mode[0] == 'l' */)
3648 {
3649 if (theFile->link_path)
3650 tmp_lnk = sh_util_safe_name(theFile->link_path);
3651 else
3652 tmp_lnk = sh_util_strdup("-");
3653 if (p->linkpath)
3654 tmp_lnk_old = sh_util_safe_name(p->linkpath);
3655 else
3656 tmp_lnk_old = sh_util_strdup("-");
3657#ifdef SH_USE_XML
3658 sl_snprintf(tmp, SH_MSG_BUF, _("link_old=\"%s\" link_new=\"%s\" "),
3659 tmp_lnk_old, tmp_lnk);
3660#else
3661 sl_snprintf(tmp, SH_MSG_BUF, _("link_old=<%s>, link_new=<%s>, "),
3662 tmp_lnk_old, tmp_lnk);
3663#endif
3664 SH_FREE(tmp_lnk);
3665 SH_FREE(tmp_lnk_old);
3666 sl_strlcat(msg, tmp, SH_MSG_BUF);
3667#ifdef REPLACE_OLD
3668 if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
3669 {
3670 if (p->linkpath != NULL && p->linkpath != notalink)
3671 SH_FREE(p->linkpath);
3672 if (!(theFile->link_path) ||
3673 (theFile->link_path[0] == '-' && theFile->link_path[1] == '\0'))
3674 p->linkpath = (char *)notalink;
3675 else
3676 p->linkpath = sh_util_strdup(theFile->link_path);
3677 }
3678#endif
3679 }
3680
3681 if (MODI_AUDIT_ENABLED(theFile->check_mask))
3682 {
3683 char result[256];
3684
3685 if (NULL != sh_audit_fetch (theFile->fullpath, theFile->mtime, result, sizeof(result)))
3686 {
3687#ifdef SH_USE_XML
3688 sl_strlcat(msg, _("obj=\""), SH_MSG_BUF);
3689#else
3690 sl_strlcat(msg, _("obj=<"), SH_MSG_BUF);
3691#endif
3692
3693 sl_strlcat(msg, result, SH_MSG_BUF);
3694
3695#ifdef SH_USE_XML
3696 sl_strlcat(msg, _("\" "), SH_MSG_BUF);
3697#else
3698 sl_strlcat(msg, _(">"), SH_MSG_BUF);
3699#endif
3700 }
3701 }
3702
3703 tmp_path = sh_util_safe_name(theFile->fullpath);
3704 sh_error_handle(log_severity, FIL__, __LINE__,
3705 (long) modi_mask, MSG_FI_CHAN,
3706 (policy_override == NULL) ? _(policy[class]):log_policy,
3707 change_code, tmp_path, msg);
3708 ++sh.statistics.files_report;
3709
3710 SH_FREE(tmp_path);
3711 SH_FREE(tmp);
3712 SH_FREE(msg);
3713
3714#ifndef REPLACE_OLD
3715 SET_SH_FFLAG_REPORTED(p->fflags);
3716#endif
3717
3718 if (S_TRUE == sh.flag.update)
3719 {
3720 if (S_FALSE == sh_util_ask_update(theFile->fullpath))
3721 {
3722 /* user does not want to update, thus we replace
3723 * with data from the baseline database
3724 */
3725 sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11);
3726 theFile->mode = p->theFile.mode;
3727#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
3728 sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, 16);
3729 theFile->attributes = p->theFile.attributes;
3730#endif
3731#if defined(USE_ACL) || defined(USE_XATTR)
3732 if (theFile->attr_string == NULL && p->attr_string != NULL)
3733 { theFile->attr_string = sh_util_strdup (p->attr_string); }
3734 else if (theFile->attr_string != NULL && p->attr_string == NULL)
3735 { SH_FREE(theFile->attr_string); theFile->attr_string = NULL; }
3736 else if (theFile->attr_string != NULL && p->attr_string != NULL)
3737 {
3738 if (0 != strcmp(theFile->attr_string, p->attr_string))
3739 {
3740 SH_FREE(theFile->attr_string);
3741 theFile->attr_string = sh_util_strdup (p->attr_string);
3742 }
3743 }
3744#endif
3745
3746 if (theFile->c_mode[0] == 'l') /* c_mode is already copied */
3747 {
3748 if (theFile->link_path)
3749 SH_FREE(theFile->link_path);
3750 if (p->linkpath)
3751 theFile->link_path = sh_util_strdup(p->linkpath);
3752 else
3753 theFile->link_path = sh_util_strdup("-");
3754 }
3755 else
3756 {
3757 if (theFile->link_path)
3758 SH_FREE(theFile->link_path);
3759 if (p->linkpath && p->linkpath != notalink)
3760 theFile->link_path = sh_util_strdup(p->linkpath);
3761 else
3762 theFile->link_path = NULL;
3763 }
3764
3765 sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
3766
3767 theFile->mtime = p->theFile.mtime;
3768 theFile->ctime = p->theFile.ctime;
3769 theFile->atime = p->theFile.atime;
3770
3771 theFile->size = p->theFile.size;
3772
3773 sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2);
3774 theFile->group = p->theFile.group;
3775 sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2);
3776 theFile->owner = p->theFile.owner;
3777
3778 theFile->ino = p->theFile.ino;
3779 theFile->rdev = p->theFile.rdev;
3780 theFile->dev = p->theFile.dev;
3781 theFile->hardlinks = p->theFile.hardlinks;
3782
3783 SET_SH_FFLAG_VISITED(p->fflags);
3784 CLEAR_SH_FFLAG_CHECKED(p->fflags);
3785 retval = 1;
3786 goto unlock_and_return;
3787 }
3788 else /* if (sh.flag.reportonce == S_TRUE) */
3789 {
3790 /* we replace the data in the in-memory copy of the
3791 * baseline database, because otherwise we would get
3792 * another warning if the suidcheck runs
3793 */
3794 sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11);
3795 p->theFile.mode = theFile->mode;
3796#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
3797 sl_strlcpy(p->theFile.c_attributes, theFile->c_attributes, 16);
3798 p->theFile.attributes = theFile->attributes;
3799#endif
3800#if defined(USE_ACL) || defined(USE_XATTR)
3801 if (p->attr_string == NULL && theFile->attr_string != NULL)
3802 { p->attr_string = sh_util_strdup (theFile->attr_string); }
3803 else if (p->attr_string != NULL && theFile->attr_string == NULL)
3804 { SH_FREE(p->attr_string); p->attr_string = NULL; }
3805 else if (theFile->attr_string != NULL && p->attr_string != NULL)
3806 {
3807 if (0 != strcmp(theFile->attr_string, p->attr_string))
3808 {
3809 SH_FREE(p->attr_string);
3810 p->attr_string = sh_util_strdup (theFile->attr_string);
3811 }
3812 }
3813#endif
3814
3815 if (theFile->c_mode[0] == 'l' || theFile->link_path)
3816 {
3817 if (p->linkpath != NULL && p->linkpath != notalink)
3818 SH_FREE(p->linkpath);
3819 p->linkpath = sh_util_strdup(theFile->link_path);
3820 }
3821 else
3822 {
3823 if (p->linkpath != NULL && p->linkpath != notalink) {
3824 SH_FREE(p->linkpath);
3825 }
3826 p->linkpath = (char *)notalink;
3827 }
3828
3829 sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
3830
3831 p->theFile.mtime = theFile->mtime;
3832 p->theFile.ctime = theFile->ctime;
3833 p->theFile.atime = theFile->atime;
3834
3835 p->theFile.size = theFile->size;
3836
3837 sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2);
3838 p->theFile.group = theFile->group;
3839 sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2);
3840 p->theFile.owner = theFile->owner;
3841
3842 p->theFile.ino = theFile->ino;
3843 p->theFile.rdev = theFile->rdev;
3844 p->theFile.dev = theFile->dev;
3845 p->theFile.hardlinks = theFile->hardlinks;
3846 }
3847 }
3848 }
3849
3850 SET_SH_FFLAG_VISITED(p->fflags);
3851 CLEAR_SH_FFLAG_CHECKED(p->fflags);
3852
3853 unlock_and_return:
3854 ; /* 'label at end of compound statement */
3855 SH_MUTEX_UNLOCK(mutex_hash);
3856 SL_RETURN(retval, _("sh_hash_compdata"));
3857}
3858
3859int hash_full_tree ()
3860{
3861 sh_file_t * p;
3862 int i;
3863
3864 SL_ENTER(_("hash_full_tree"));
3865
3866 if (IsInit != 1)
3867 SL_RETURN(0, _("hash_full_tree"));
3868
3869 SH_MUTEX_LOCK_UNSAFE(mutex_hash);
3870 for (i = 0; i < TABSIZE; ++i)
3871 {
3872 for (p = tab[i]; p; p = p->next)
3873 CLEAR_SH_FFLAG_ALLIGNORE(p->fflags);
3874 }
3875 SH_MUTEX_UNLOCK_UNSAFE(mutex_hash);
3876 SL_RETURN (0, _("hash_full_tree"));
3877}
3878
3879#if !defined(SH_CUTEST)
3880static
3881#endif
3882int hash_remove_tree_test(char * s, char * fullpath, size_t len_s)
3883{
3884 size_t len_p;
3885 char * test;
3886
3887 len_p = strlen(fullpath);
3888
3889 if (len_p >= len_s)
3890 {
3891 if (0 == strncmp(s, fullpath, len_s))
3892 {
3893 if (len_p > len_s)
3894 {
3895 /* continue if not inside directory;
3896 * len_s > 1 because everything is inside '/'
3897 */
3898 if ((len_s > 1) && (fullpath[len_s] != '/'))
3899 return S_FALSE;
3900
3901 test = sh_files_find_mostspecific_dir(fullpath);
3902
3903 if (test && 0 != strcmp(test, s)) {
3904 /* There is a more specific directory, continue */
3905 return S_FALSE;
3906 }
3907
3908 if (NULL == sh_files_findfile(fullpath)) {
3909 /* SET_SH_FFLAG_ALLIGNORE(p->fflags); */
3910 return S_TRUE;
3911 }
3912 }
3913 else /* len_p == len */
3914 {
3915 /* it is 's' itself, mark and continue
3916 * unless there is a policy for the inode itself
3917 */
3918 if (NULL == sh_files_findfile(fullpath)) {
3919 /* SET_SH_FFLAG_ALLIGNORE(p->fflags); */
3920 return S_TRUE;
3921 }
3922 else {
3923 return S_FALSE;
3924 }
3925 }
3926
3927 } /* if path is in tree */
3928 } /* if path is possibly in tree */
3929 return S_FALSE;
3930}
3931
3932
3933int hash_remove_tree (char * s)
3934{
3935 sh_file_t * p;
3936 size_t len_s;
3937 unsigned int i;
3938
3939 SL_ENTER(_("hash_remove_tree"));
3940
3941 if (!s || *s == '\0')
3942 SL_RETURN ((-1), _("hash_remove_tree"));
3943
3944 len_s = sl_strlen(s);
3945
3946 if (IsInit != 1)
3947 sh_hash_init();
3948
3949 SH_MUTEX_LOCK_UNSAFE(mutex_hash);
3950 for (i = 0; i < TABSIZE; ++i)
3951 {
3952 for (p = tab[i]; p; p = p->next)
3953 {
3954 if (p->fullpath)
3955 {
3956 /* if (0 == strncmp(s, p->fullpath, len_s)) *//* old */
3957 if (S_TRUE == hash_remove_tree_test(s, p->fullpath, len_s))
3958 SET_SH_FFLAG_ALLIGNORE(p->fflags);
3959 } /* if path is not null */
3960
3961 }
3962 }
3963 SH_MUTEX_UNLOCK_UNSAFE(mutex_hash);
3964 SL_RETURN ((0), _("hash_remove_tree"));
3965}
3966
3967#if TIME_WITH_SYS_TIME
3968#include <sys/time.h>
3969#include <time.h>
3970#else
3971#if HAVE_SYS_TIME_H
3972#include <sys/time.h>
3973#else
3974#include <time.h>
3975#endif
3976#endif
3977
3978static int ListFullDetail = S_FALSE;
3979static int ListWithDelimiter = S_FALSE;
3980static char * ListFile = NULL;
3981
3982int set_list_file (const char * c)
3983{
3984 ListFile = sh_util_strdup(c);
3985 return 0;
3986}
3987
3988int set_full_detail (const char * c)
3989{
3990 (void) c;
3991 ListFullDetail = S_TRUE;
3992 return 0;
3993}
3994
3995int set_list_delimited (const char * c)
3996{
3997 (void) c;
3998 ListFullDetail = S_TRUE;
3999 ListWithDelimiter = S_TRUE;
4000 return 0;
4001}
4002
4003/* Always quote the string, except if it is empty. Quote quotes by
4004 * doubling them.
4005 */
4006char * csv_escape(const char * str)
4007{
4008 const char * p = str;
4009 const char * q;
4010
4011 size_t size = 0;
4012 size_t flag_quote = 0;
4013
4014 char * new;
4015 char * pnew;
4016
4017 if (p)
4018 {
4019
4020 while (*p)
4021 {
4022 if (*p == '"')
4023 ++flag_quote;
4024
4025 ++size; ++p;
4026 }
4027
4028 if (sl_ok_adds(size, flag_quote))
4029 size += flag_quote; /* double each quote */
4030 else
4031 return NULL;
4032
4033 if (sl_ok_adds(size, 3))
4034 size += 3; /* two quotes and terminating null */
4035 else
4036 return NULL;
4037
4038 new = SH_ALLOC(size);
4039
4040 if (flag_quote != 0)
4041 {
4042 new[0] = '"';
4043 pnew = &new[1];
4044 q = str;
4045 while (*q)
4046 {
4047 *pnew = *q;
4048 if (*pnew == '"')
4049 {
4050 ++pnew; *pnew = '"';
4051 }
4052 ++pnew; ++q;
4053 }
4054 *pnew = '"'; ++pnew;
4055 *pnew = '\0';
4056 }
4057 else
4058 {
4059 if (size > 3)
4060 {
4061 new[0] = '"';
4062 sl_strlcpy (&new[1], str, size-1);
4063 new[size-2] = '"';
4064 new[size-1] = '\0';
4065 }
4066 else
4067 {
4068 new[0] = '\0';
4069 }
4070 }
4071
4072 return new;
4073 }
4074 return NULL;
4075}
4076
4077int isHexKey(char * s)
4078{
4079 int i;
4080
4081 for (i = 0; i < KEY_LEN; ++i)
4082 {
4083 if (*s)
4084 {
4085 if ((*s >= '0' && *s <= '9') ||
4086 (*s >= 'A' && *s <= 'F') ||
4087 (*s >= 'a' && *s <= 'f'))
4088 {
4089 ++s;
4090 continue;
4091 }
4092 }
4093 return S_FALSE;
4094 }
4095 return S_TRUE;
4096}
4097
4098#include "sh_checksum.h"
4099
4100static char * KEYBUFtolower (char * s, char * result)
4101{
4102 char * r = result;
4103 if (s)
4104 {
4105 for (; *s; ++s)
4106 {
4107 *r = tolower((unsigned char) *s); ++r;
4108 }
4109 *r = '\0';
4110 }
4111 return result;
4112}
4113
4114void sh_hash_list_db_entry_full_detail (sh_file_t * p)
4115{
4116 char * tmp;
4117 char * esc;
4118 char str[81];
4119 char hexdigest[SHA256_DIGEST_STRING_LENGTH];
4120 char keybuffer[KEYBUF_SIZE];
4121
4122 if (ListWithDelimiter == S_TRUE)
4123 {
4124 printf(_("%7ld, %7ld, %10s, %5d, %12s, %5d, %3d, %-8s, %5d, %-8s, %5d, "),
4125 (unsigned long) p->theFile.ino, (unsigned long) p->theFile.dev,
4126 p->theFile.c_mode, (int) p->theFile.mode,
4127 p->theFile.c_attributes, (int) p->theFile.attributes,
4128 (int) p->theFile.hardlinks,
4129 p->theFile.c_owner, (int) p->theFile.owner,
4130 p->theFile.c_group, (int) p->theFile.group);
4131 }
4132 else
4133 {
4134 printf(_("%7ld %7ld %10s %5d %12s %5d %3d %-8s %5d %-8s %5d "),
4135 (unsigned long) p->theFile.ino, (unsigned long) p->theFile.dev,
4136 p->theFile.c_mode, (int) p->theFile.mode,
4137 p->theFile.c_attributes, (int) p->theFile.attributes,
4138 (int) p->theFile.hardlinks,
4139 p->theFile.c_owner, (int) p->theFile.owner,
4140 p->theFile.c_group, (int) p->theFile.group);
4141 }
4142
4143 if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0])
4144 sl_snprintf(str, sizeof(str), "%"PRIu64, p->theFile.rdev);
4145 else
4146 sl_snprintf(str, sizeof(str), "%"PRIu64, p->theFile.size);
4147
4148 printf( _(" %8s"), str);
4149 if (ListWithDelimiter == S_TRUE)
4150 putchar(',');
4151
4152 printf( _(" %s"), sh_unix_gmttime (p->theFile.ctime, str, sizeof(str)));
4153 if (ListWithDelimiter == S_TRUE)
4154 putchar(',');
4155 printf( _(" %s"), sh_unix_gmttime (p->theFile.mtime, str, sizeof(str)));
4156 if (ListWithDelimiter == S_TRUE)
4157 putchar(',');
4158 printf( _(" %s"), sh_unix_gmttime (p->theFile.atime, str, sizeof(str)));
4159 if (ListWithDelimiter == S_TRUE)
4160 putchar(',');
4161
4162 if (isHexKey(p->theFile.checksum))
4163 printf( _(" %s"), KEYBUFtolower(p->theFile.checksum, keybuffer));
4164 else
4165 printf( _(" %s"), SHA256_Base2Hex(p->theFile.checksum, hexdigest));
4166 if (ListWithDelimiter == S_TRUE)
4167 putchar(',');
4168
4169 tmp = sh_util_safe_name(p->fullpath);
4170 if (ListWithDelimiter != S_TRUE)
4171 {
4172 printf( _(" %s"), tmp);
4173 }
4174 else
4175 {
4176 esc = csv_escape(tmp);
4177 printf( _(" %s,"), (esc != NULL) ? esc : _("(null)"));
4178 if (esc)
4179 SH_FREE(esc);
4180 }
4181 SH_FREE(tmp);
4182
4183 if ('l' == p->theFile.c_mode[0])
4184 {
4185 tmp = sh_util_safe_name(p->linkpath);
4186 if (ListWithDelimiter != S_TRUE)
4187 {
4188 printf(_(" -> %s"), tmp);
4189 }
4190 else
4191 {
4192 esc = csv_escape(tmp);
4193 printf( _(" %s,"), (esc != NULL) ? esc : _("(null)"));
4194 if (esc)
4195 SH_FREE(esc);
4196 }
4197 SH_FREE(tmp);
4198 }
4199
4200 if (p->attr_string)
4201 {
4202 tmp = sh_util_safe_name(p->attr_string);
4203 if (ListWithDelimiter != S_TRUE)
4204 {
4205 printf(_(" %s"), tmp);
4206 }
4207 else
4208 {
4209 esc = csv_escape(tmp);
4210 printf( _(" %s"), (esc != NULL) ? esc : _("(null)"));
4211 if (esc)
4212 SH_FREE(esc);
4213 }
4214 SH_FREE(tmp);
4215 }
4216 else
4217 {
4218 if (ListWithDelimiter == S_TRUE)
4219 printf("%s",_(" no_attr"));
4220 }
4221 putchar('\n');
4222
4223 return;
4224}
4225
4226void sh_hash_list_db_entry (sh_file_t * p)
4227{
4228 char nowtime[128];
4229 char thetime[128];
4230 char * tmp;
4231 time_t now = time(NULL);
4232 time_t then = (time_t) p->theFile.mtime;
4233
4234#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
4235 struct tm * time_ptr;
4236 struct tm time_tm;
4237
4238 time_ptr = gmtime_r(&then, &time_tm);
4239 strftime(thetime, 127, _("%b %d %Y"), time_ptr);
4240 time_ptr = gmtime_r(&now, &time_tm);
4241 strftime(nowtime, 127, _("%b %d %Y"), time_ptr);
4242 if (0 == strncmp(&nowtime[7], &thetime[7], 4))
4243 {
4244 time_ptr = gmtime_r(&then, &time_tm);
4245 strftime(thetime, 127, _("%b %d %H:%M"), time_ptr);
4246 }
4247#else
4248 strftime(thetime, 127, _("%b %d %Y"), gmtime(&then));
4249 strftime(nowtime, 127, _("%b %d %Y"), gmtime(&now));
4250 if (0 == strncmp(&nowtime[7], &thetime[7], 4))
4251 strftime(thetime, 127, _("%b %d %H:%M"), gmtime(&then));
4252#endif
4253
4254 tmp = sh_util_safe_name(p->fullpath);
4255 if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0])
4256 printf(_("%10s %3d %-8s %-8s %3d,%4d %s %s"),
4257 p->theFile.c_mode, (int) p->theFile.hardlinks,
4258 p->theFile.c_owner, p->theFile.c_group,
4259 (int) major((dev_t)p->theFile.rdev),
4260 (int) minor((dev_t)p->theFile.rdev),
4261 thetime,
4262 tmp);
4263 else
4264 printf(_("%10s %3d %-8s %-8s %8ld %s %s"),
4265 p->theFile.c_mode, (int) p->theFile.hardlinks,
4266 p->theFile.c_owner, p->theFile.c_group, (long) p->theFile.size,
4267 thetime,
4268 tmp);
4269 SH_FREE(tmp);
4270
4271 if ('l' == p->theFile.c_mode[0])
4272 {
4273 tmp = sh_util_safe_name(p->linkpath);
4274 printf(_(" -> %s\n"), tmp);
4275 SH_FREE(tmp);
4276 }
4277 else
4278 printf("\n");
4279
4280 return;
4281}
4282
4283#ifdef HAVE_LIBZ
4284#include <zlib.h>
4285#endif
4286
4287int sh_hash_printcontent(char * linkpath)
4288{
4289#ifdef HAVE_LIBZ
4290 unsigned char * decoded;
4291 unsigned char * decompressed = NULL;
4292 size_t dlen;
4293 unsigned long clen;
4294 unsigned long clen_o;
4295 int res;
4296
4297 if (linkpath && *linkpath != '-')
4298 {
4299 dlen = sh_util_base64_dec_alloc (&decoded,
4300 (unsigned char *)linkpath,
4301 strlen(linkpath));
4302
4303 clen = dlen * 2 + 1;
4304
4305 do {
4306 if (decompressed)
4307 SH_FREE(decompressed);
4308 clen += dlen; clen_o = clen;
4309 decompressed = SH_ALLOC(clen);
4310 res = uncompress(decompressed, &clen, decoded, dlen);
4311 if (res == Z_MEM_ERROR)
4312 { fprintf(stderr, "%s",_("Error: Not enough memory\n")); return -1; }
4313 if (res == Z_DATA_ERROR)
4314 { fprintf(stderr, "%s",_("Error: Data corrupt or incomplete\n")); return -1; }
4315 } while (res == Z_BUF_ERROR || clen == clen_o);
4316
4317 decompressed[clen] = '\0';
4318 fputs( (char*) decompressed, stdout);
4319 SH_FREE(decompressed);
4320 return 0;
4321 }
4322#else
4323 (void) linkpath;
4324#endif
4325 fprintf(stderr, "%s",_("Error: No data available\n"));
4326 return -1;
4327}
4328
4329int sh_hash_list_db (const char * db_file)
4330{
4331 sh_file_t * p;
4332 SL_TICKET fd;
4333 char * line;
4334 int flag = 0;
4335
4336 if (!db_file)
4337 {
4338 _exit(EXIT_FAILURE);
4339 return -1;
4340 }
4341 if (sl_is_suid())
4342 {
4343 fprintf(stderr, "%s",_("ERROR: insufficient privilege\n"));
4344 _exit (EXIT_FAILURE);
4345 return -1; /* for Mac OSX compiler */
4346 }
4347 if (0 == strcmp(db_file, _("default")))
4348 db_file = file_path('D', 'W');
4349 if (!db_file)
4350 {
4351 _exit(EXIT_FAILURE);
4352 return -1;
4353 }
4354
4355 line = SH_ALLOC(MAX_PATH_STORE+2);
4356
4357 if ( SL_ISERROR(fd = sl_open_read(FIL__, __LINE__, db_file, SL_YESPRIV)))
4358 {
4359 fprintf(stderr, _("ERROR: can't open %s for read (errnum = %ld)\n"),
4360 db_file, fd);
4361 _exit(EXIT_FAILURE);
4362 return -1;
4363 }
4364
4365 /* fast forward to start of data
4366 */
4367 sh_hash_setdataent(fd, line, MAX_PATH_STORE+1, db_file);
4368
4369 while (1)
4370 {
4371 p = sh_hash_getdataent (fd, line, MAX_PATH_STORE+1);
4372 if ((p != NULL) && (p->fullpath[0] == '/'))
4373 {
4374 if (!ListFile)
4375 {
4376 flag = 1;
4377 if (ListFullDetail == S_FALSE)
4378 sh_hash_list_db_entry (p);
4379 else
4380 sh_hash_list_db_entry_full_detail (p);
4381 }
4382 else
4383 {
4384 if (0 != sl_strcmp(ListFile, p->fullpath))
4385 {
4386 continue;
4387 }
4388 flag = 1;
4389 if ('l' != p->theFile.c_mode[0])
4390 {
4391 if (sh_hash_printcontent(p->linkpath) < 0)
4392 {
4393 _exit(EXIT_FAILURE);
4394 return -1;
4395 }
4396 }
4397 else
4398 {
4399 fprintf(stderr, "%s",_("File is a link\n"));
4400 _exit(EXIT_FAILURE);
4401 return -1;
4402 }
4403 break;
4404 }
4405 }
4406 else if (p == NULL)
4407 {
4408 break;
4409 }
4410 }
4411
4412 if (line != NULL)
4413 SH_FREE(line);
4414 sl_close (fd);
4415
4416 fflush(NULL);
4417
4418 if (flag == 0)
4419 {
4420 fprintf(stderr, "%s",_("File not found\n"));
4421 _exit(EXIT_FAILURE);
4422 }
4423 _exit(EXIT_SUCCESS);
4424 return 0;
4425}
4426
4427/* if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
4428#endif
Note: See TracBrowser for help on using the repository browser.