source: trunk/src/sh_hash.c@ 214

Last change on this file since 214 was 212, checked in by katerina, 16 years ago

Lock baseline database (ticket #139) and allow list as input for PortCheckInterface (ticket #140).

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